JAVA 类总结

最近看了遍java内部类相关的一些内容,做一些总结。与个人博客 zhiheng.me 同步发布,标题: JAVA 类总结

顶级类与嵌套类

定义在某个类(或接口,下同)内部的类,称为嵌套类(nested class),相应的,其所在的类称之为该类的外围类(enclosing class)或包裹类。

非嵌套类称为顶级类(top-level class),一个 .java 文件中可以有若干个顶级类(含抽象类和接口),但只能有一个被 public 修饰的类,且该类必须和 .java 文件同名。

顶级类的访问修饰符只能是 public 和包访问权限(默认权限,无修饰符)。

嵌套类可看作是外围类的一个成员,因此其修饰符可以是 public 、protected 、包访问权限和 private 。

嵌套类没有层次限制,可以在嵌套类里面在定义类,成为嵌套类中的嵌套类。

嵌套类分为两种,一种是静态的(用 static 关键字修饰)称为静态嵌套类(static nested class);一种是非静态的,称为内部类(inner class)。

注:在《Think in Java》一书中,作者将内部类定义为“将一个类定义在另一个类的定义内部,则这个类就是内部类”,因此,他将静态嵌套类视为内部类的一种。而本文使用了 java 官方文档中的定义。

内部类一般直接定义在外部类(outer class)中,就像该类的一个成员一样,我们把这样的内部类称为成员内部类(member inner class)。即不在构造器、方法、语句块中定义的内部类为成员内部类。

除成员内部类外还有另外两种较特殊的内部类:局部内部类(local class)和匿名内部类(anonymous class)。

嵌套类字节码文件命名

嵌套类经编译后会自动生成独立的字节码文件(.class),其命名格式:

外部类名称+\$+[该种类同名类中该类顺序]+[内部类名称]

以下代码(文件名:Outer.java)中含有静态类 Static 、成员内部类 Inner 、局部类 Local 、实现 Anonymous 接口的匿名类以及定义在该源文件中的接口 Anonymous 。

package thinkinjava;

public class Outer {

    public static class Static{}

    public class Inner {}

    {
class Local{};
} Anonymous anonymous = new Anonymous(){};
} interface Anonymous {}

编译后形成了如下6个 .class 字节码文件。顶级类 Outer 和 Anonymous 都被编译成同名的 class 文件,静态嵌套类 Static 和成员内部类 Inner 被编译成了 Outer\$Static.class 和 Outer\$Inner.class ,因为成员类不能同名,所以也就没有同名类顺序。局部类 Local 编译后的文件名是 Outer\$1Local.class ,因为 Outer 类中只有一个名为 Local 的局部类,因此,其顺序是1。匿名类没有名称,所以编译后的文件名是 Outer\$1.class ,1表示该类是 Outer 类中第一个匿名类。

Anonymous.class
Outer$1.class
Outer$1Local.class
Outer$Inner.class
Outer$Static.class
Outer.class

静态嵌套类

public class OuterClass{
public static class NestClass{}
}

静态嵌套类因为是静态的,因此从本质上来说它和外部类的关系更像是类与包(package)的关系。在其他类中引用使用的时候需要加上外部类限定: OuterClass.NestClass 。

  1. 与静态方法一样,静态嵌套类中不能访问外部类的非静态成员和非静态方法(不管是public还是private的);
  2. 静态嵌套类的实例化(instantiate)无需事先实例化外部类,因为静态嵌套类是与外部类直接相关联的,而非与外部类的实例(instance)相关联。

内部类

内部类是非静态的,因此内部类是与外部类的实例相关联的。在实例化内部类时,必须先行实例化外部类,再通过外部类的实例来创建内部类的实例:

OuterClass outObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
  1. 内部类中不能有 static 关键字修饰的静态成员(块、字段、方法、接口等),除非该成员是静态常量。所以,内部类中的静态成员必须是同时使用 final 关键字修饰的字段。
  2. 内部类可以访问外部类的任何成员(包括构造器),不管是公有的还是私有的,静态的还是非静态的。同样,外部类也可以访问到内部类的所有成员。

遮蔽(Shadowing)

定义在内部类或成员方法内的字段或参数,如果和外部作用域内的某个成员变量定义同名,那么外部的定义将被遮蔽,此时无法在内部作用域内仅通过名字访问到外部的成员。以下是摘自 Java Tutorial 中的一个例子:

public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
System.out.println("x = " + x);
System.out.println("this.x = " + this.x);
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
}
} public static void main(String... args) {
ShadowTest st = new ShadowTest();
ShadowTest.FirstLevel fl = st.new FirstLevel();
fl.methodInFirstLevel(23);
}
}
// 输出如下
// x = 23
// this.x = 1
// ShadowTest.this.x = 0

局部内部类

局部类是定义在某个块(block)中的类。即定义在构造器、方法、循环体、分支结构(if 子句)中的类。

  1. 同局部变量,局部类不能用public,private,protected,static修饰,但可以被final或者abstract修饰。
  2. 局部类是内部类,因此可以访问其外部类的成员。但局部类的作用域在块内,所以外部类无法访问到局部内部类。

局部类属于块的作用域,因此可以访问局部变量(包括形参),但是只能访问用 final 修饰的局部变量。

在 Java SE 8 之后,局部类可以访问 effectively final 的局部变量和非 final 的形参了,effectively final 的变量没有 final 修饰但在初始化后从未改变过值。 “A variable or parameter whose value is never changed after it is initialized is effectively final” 。

匿名类

匿名类,顾名思义就是没有名称的类,没有名称也就无法在其他地方引用和实例化,当然也就没有构造器。匿名类在定义的同时会实例化本身(匿名类只实例化这一次)。

匿名类的定义从形式上看更像是一种表达式,也就是类的定义出现在一个表达式中。从语法形式上看,匿名类的定义像是调用了一个构造器。以下是几种匿名类的例子:

public class Test {
InterfaceA a = new InterfaceA() {};//成员匿名类
public static void main(String[] args){
InterfaceA a = new InterfaceA() {};//局部匿名类
//以上两种是通过实现接口实现匿名类,称为接口式匿名类,也可以通过继承类实现
Test test = new Test(){};//继承式匿名类
//还可以是位于参数上
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();//属于局部匿名类一种
}
private interface InterfaceA{}

匿名类不能使用任何关键字和访问控制符,匿名类和局部类访问规则一样,只不过内部类显式的定义了一个类,然后通过new的方式创建这个局部类实例,而匿名类直接new一个类实例。

JAVA 类总结的更多相关文章

  1. 如何用Java类配置Spring MVC(不通过web.xml和XML方式)

    DispatcherServlet是Spring MVC的核心,按照传统方式, 需要把它配置到web.xml中. 我个人比较不喜欢XML配置方式, XML看起来太累, 冗长繁琐. 还好借助于Servl ...

  2. jvm系列(一):java类的加载机制

    java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装 ...

  3. java类与实例

    最近在看设计模式,感觉自己对java的三大特性的理解不够清晰,搞不清楚抽象类.接口.泛型的用处和优缺点.设计模式学了一半,想着还是停下来脑补一下java的基础,就从java对象开始吧. 一.java对 ...

  4. oracle调用JAVA类的方法

    导入jar包 在oracle中导入需要的jar包,我们把编辑好的java类打成jar包,直接在oarcle里面写简单的调用就可以了,  1.操作系统需要拥有支持loadjava命令的jdk.  2.加 ...

  5. Java 类的实例变量初始化的过程 静态块、非静态块、构造函数的加载顺序

    先看一道Java面试题: public class Baset { private String baseName = "base"; // 构造方法 public Baset() ...

  6. hibernate中java类的成员变量类型如何映射到SQL中的数据类型变化

    hibernate映射文件??.hbm.xml配置映射元素详解--Hibernate映射类型 在从Hibernate的java的成员类型映射到SQL中的数据类型,其内映射方式它满足,SQL可以自己调制 ...

  7. kettle系列-[KettleUtil]kettle插件,类似kettle的自定义java类控件

    该kettle插件功能类似kettle现有的定义java类插件,自定java类插件主要是支持在kettle中直接编写java代码实现自定特殊功能,而本控件主要是将自定义代码转移到jar包,就是说自定义 ...

  8. Myeclipse中导入项目后java类中汉字注释出现乱码问题(已解决)

    今天重装系统,安装了新的Myeclipse后,导入之前的项目后,,出现了乱码问题.乱码问题主要是java类中的注释,而jsp页面中汉字却完好如初: 右键项目,查看项目的编码格式,UTF-8,把java ...

  9. Java类初始化

    Java类初始化 成员变量的初始化和构造器 如果类的成员变量在定义时没有进行显示的初始化赋值,Java会给每个成员变量一个默认值 对于  char.short.byte.int.long.float. ...

  10. 深入研究Java类装载机制

    目录 1.为什么要研究java类装在机制? 2.了解类装载机制,对于我们在项目开发中有什么作用? 3.装载实现细节. 4.总结 一.为什么药研究Java类装载机制 java类加载机制,便于我们使用自定 ...

随机推荐

  1. css3 3d小demo

    css3 3d案例总结 最近入坑 Web 动画,所以把自己的学习过程记录一下分享给大家.就把最近做的比较好的给大家分享下 1.旋转拼图 首先看下效果 代码主要由HTML和CSS3组成,应该说还是比较简 ...

  2. PHP 数组处理

    一:PHP 定义数组: PHP 代码  不能再 空的位置 打字  会报错 定义数组  方式1 $cars=array("Volvo","BMW","T ...

  3. Java数据类型转换浅析

    Java数据类型转换分为两种:自动类型转换和强制类型转换. 数据类型转换的关键是数据类型相应的表数范围大小 1.自动类型转换: 概念:小范围数据类型会自动转化成大范围数据类型 实例: int a=10 ...

  4. EF操作扩展之async

    EF的操作类网上很多类,我只是把我在平时项目中的类进行一些改进和扩展,扩展了部分同步和异步的EF操作 接口 /// <summary> /// 接口数据操作基础类 /// </sum ...

  5. plupload插件的错误SCRIPT601

    在网上copy 别人的demo来用结果发生这个问题.浪费半天时间才找到问题. 在IE8下下提示这个异常. SCRIPT601: 未知的运行时错误plupload.full.min.js, 行15 字符 ...

  6. [Spark] - Spark部署安装

    环境:centos6.0 虚拟机 搭建单机版本的spark 前提条件:搭建好hadoop环境 1. 下载scala进行安装 只需要设置环境变量SCALA_HOME和PATH即可 export SCAL ...

  7. ReactJS的开发日常

    在用React框架开发的日子里,踩的坑真不少!今天就来说说这个关于组件的周期,说的可能不是很清楚,但是也给自己留下一个踩坑的纪念,如有不妥 还望大家指点一二 Warning: setState(... ...

  8. Javascript定时器中的this指向

    使用js中的定时器(setInterval,setTimeout),很容易会遇到this指向的问题. 直接上例子: var name = 'my name is window'; var obj = ...

  9. rem与em

    最近有朋友在进行rem布局的时候总搞不懂rem  em  px  与百分比布局的区别在哪里  这里简单给大家介绍一下 Em为单位: 这种技术需要一个参考点,一般都是以<body>的&quo ...

  10. SSIS 数据流的连接和查找转换

    在SSIS的数据流组件中,SSIS引擎使用Merge Join组件和 Lookup组件实现TSQL语句中的inner join 和 outer join 功能,Lookup查找组件的功能更类似TSQL ...