嵌套类
第一节 嵌套类入门
嵌套类:定义在另一个类中的类。内部类和嵌套类是不同的
- 静态嵌套类:Static nested classes,类前面有static修饰符
- 非静态嵌套类:Inner classes,内部类
- 普通内部类
- 局部内部类
- 匿名内部类
public class Outer{
String name;
public void f1(){
new Thread(new Runnable(){
public void run(){
System.out.println("hello");
}
}).start();
}
}
接口是不能实例化的,但是能够加上其实现,就可以实现一个匿名类。对程序来说,匿名内部类只需要运行一次就好了,还可以不占用名字。
为啥需要嵌套类呢?
- 不同的访问权限的要求,更细粒度的访问控制。
- 简洁,避免过多的类定义。
- 语言设计过于复杂,较难学习和使用。
第二节 匿名内部类和局部内部类
嵌套类的学习重点:
- 嵌套类的语法
- 嵌套类和其他类的关系
- 嵌套类访问外部包围类
- 外部包围类访问嵌套类
- 第三方类访问嵌套类
匿名内部类:没有名字
- 必须继承一个父类/实现一个父接口。
- 在实例化之后,迅速转型为父类/父接口。
- 只能new出一个对象,之后以对象名字操作(想new第二个都不行)。
- 在普通语句和成员变量赋值时使用内部类。
注意事项:
-
在匿名内部类内部,不能定义静态变量,除非是常量(
public final static int a = 5;
) -
在匿名内部类不能定义静态方法。
-
匿名内部类内部会屏蔽外部方法的临时变量,怎么理解这句话呢?这个例子真棒
- 在匿名内部类中直接写
变量名
或者写this.变量名
表示的是匿名内部类的变量 - 在匿名内部类中想访问外部类中的属性,必须加上
外部类名.this.变量名
- 如果想访问方法中的局部变量,该方法变量必须是
effectively final
就是申明之后不能改变的了。
- 在匿名内部类中直接写
-
如果定义在静态方法中,也只能访问外部包围类中的成员变量和方法(包括private)
-
外部包围类和其他类也无法访问到匿名内部类。
局部内部类:定义在代码块中非静态的类,定以后可以创建对象使用(可以重复的创建对象),代码块(for循环、if语句、方法)结束后外界无法使用该类(只能存活在这个代码块中,代码块结束就无法使用了)。
- 这个类可以继承、可以实现接口、可以由构造函数
- 不能定义普通的静态成员(静态变量和静态方法都不行)
- 同匿名内部类,局部内部类要想访问方法的局部变量,该变量必须是
final
类型的。 - 编译后名称:外部类名+$+序号+内部类名。
第三节 普通内部类和静态嵌套类
普通内部类:
-
非static类,定义在某个类的成员变量位置
-
定义后,在类中所有位置均可使用。可以继承、实现。内部也只能常量,但是不能有静态变量和静态方法。
-
普通内部类与匿名内部类和局部内部类是不同的,可以通过外部类的对象new出来。
-
每一个内部类必须有一个外围的类与其相关联,不允许没有关联的单独的内部类对象。
-
编译后的名称:外部类名+$+内部类名,与匿名内部类和局部内部类还是有点不同
-
与外部包围类的实例相关,一个普通内部类的实例肯定是在一个外部包围类的实例中,且可以访问外部包围类的所有成员。
-
在第三方类中,需要先创建外部包围类实例,才能够创建普通内部类的实例,不允许单独的内部类对象存在。
静态嵌套类:
- 层级和包围类的成员变量/方法一样
- 第三方需要通过外部包围类才能访问到静态嵌套类。可以直接new静态嵌套类对象。静态嵌套类并不是表示其是唯一的,new出来的东西是不同的。
- 在静态嵌套类中可以定义静态和非静态成员。前面的都不行。
- 静态嵌套类只能访问外部包围类的静态成员
- 静态嵌套类中能够定义普通的方法???这个该怎么调用呢?
静态类纯粹的是为了访问的和打包的方便,可以当做正常类来使用。
第四节 嵌套类对比
对比:
变量遮蔽:嵌套类变量和外部包围类变量重名
- 以离得近作为有限原则。
- 优先级高的变量会遮蔽优先级低的变量
- 外部包围类.this.变量名,可以访问到外部包围类的成员变量
- 静态嵌套类不能访问非静态变量
- java7及以前,匿名内部类和局部内部类只能访问外部包围类的fianl成员变量
- java8及以后,匿名内部类和局部内部类可以访问外部包围类的final成员变量和事实意义上的final变量(一个变量赋值之后,再也没有改过值)。
就是,能访问最近的和最远的,中间的就被遮蔽了。
尽量使用不同的变量名字组织遮蔽。