什么是匿名内部类,它有什么特征
匿名内部类的使用主意事项
- 匿名内部类就是没有名字的内部类
- 正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
- 但使用匿名内部类还有个前提条件:必须继承一个父类或者实现一个接口
- 匿名内部类中是不能定义构造函数的
使用的形参为什么要final
- 我们给匿名内部类传递参数的时候,若该形参在内部类中有需要被使用,那么该形参必须要为final。也就是说,当所在的方法的形参需要被内部类里面使用时,该形参必须为final。
- 为什么必须为final呢?
- 首先我们知道在内部类编译成功后,它会产生一个class文件,该class文件与外部文件并不是同一个class文件,仅仅只保留对外部类的引用。当外部类传入参数需要被内部类调用时,从Java程序的角度看是直接被调用
- 但实际上却不是的,它们两者可以任意变化,也就是说在内部类中我对属性的改变并不会影响到外面的形参,所以为了保持参数的一致性,就规定使用final来避免形参的不确定性
- 简单理解来说,拷贝引用,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变
- 故如果定义一个匿名内部类,并且希望它使用一个其外部定义的参数,那么编译器就会要求该参数引用是final的。
匿名内部类初始化
我们一般都是利用构造器来完成某个实例的初始化工作的,但是匿名内部类是没有构造器的!那怎么来初始化内部类呢?使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果
常见的匿名内部类实例
public class Demo{
public static void main(String[] args){
Runnable r = new Runnable(){
public void run(){
for(int i = 1;i<= 5;i++){
System.out.print(i+" ");
}
}
};
Thread t = new Thread(r);
t.start;
}
}
Java内部类小结
成员内部类
也是最常规的内部类。该内部类相当于外部类成员的位置。该内部类可以访问外部类的所有成员和方法,即使是private。
public class Outer{
public class Inner{
public void print(String str){
System.out.println(str);
}
}
public Inner getInner(){
return new Inner();
}
public static void main(String[] args){
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.print("outer.new");
inner = outer.getInner();
inner.print("outer.get");
}
}
静态内部类
- 该方法被修饰为static。同时作为静态内部类,它不能访问外部类非静态的成员和方法。
- 一般书写静态时,不涉及成员变量
class Outer{
public Outter(){
System.out.println("Outter constructor.");
}
static class Inner{
public Inner(){
System.out.println("Inner constructor.");
}
}
}
pulic class Demo{
public static void main(String[] args){
Outter.Inner inner = new Outter.Inner();
}
}
方法内部类
类被创建在外部方法中:
- 可以访问外部类中的成员
- 不能被static private修饰,因为它不再是成员位置,只有成员才能被修饰为static
- 因此内部类中不能有静态成员
- 内部类要访问外部方法中的局部变量时,该局部变量需要被修饰成final
class People{
public People(){
}
}
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{//局部内部类
int age = 0;
}
return new Woman();
}
}
匿名内部类
- 就是一个内部类的简化版
- 定义匿名内部类的前提是,该类必须继承一个外部类或者实现接口。
为什么要有内部类
- 内部类是为了更好的封装,把内部类封装在外部类里,不允许同包其他类访问
- 内部类中的属性和方法即使是外部类也不能直接访问
- 相反内部类可以直接访问外部类的属性和方法,即使private
- 利于回调函数的编写。PS:回调函数是函数的迭代
- 当描述事物,如身体里的大脑时,大脑在身体内部,可以通过内部类直观描述
内部类特点
- 内部类对象不仅指向该内部类,还指向该内部类的外部类对象的内存
- 内部类和普通类一样可以重写Object类的方法,如toString方法;并且有构造函数,执行顺序依旧是先初始化属性,再执行构造函数
- 在编译完之后,会出现(外部类.class)和(内部类.class)两个类文件名
- 内部类可以被修饰为private,只能被外部类所访问,事实上一般也如此书写
- 内部类可以被写在外部类的任意位置,如成员位置,方法内。
内部类对象的建立
-
在同包其他类以及main方法中(前提要内部类没有被修饰成private,所以一般不采用),先创建外部对象,再通过外部类对象创建内部类
Outer outer = new Outer(); Outer.In inner = outer.new In();//第一个outer是为了说明该内部类是属于哪个外部类
-
通过匿名外部类创建内部类
Outer.In inner = new Outer().new In();
-
在外部类里,可以直接创建对象,如I
In inner = new In();
或者直接:
new In();
内部类的访问
- 静态时,静态内部类只能访问外部类静态成员;非静态内部类都可以直接访问。(原因是:内部类有一个外部类名.this的指引)当访问外部类静态成员出现重名时,通过(外部类.静态成员变量名)访问。如:Out.show();
- 重名情况下,非静态时,内部类访问自己内部类通过this.变量名。访问外部类通过(外部类.this.变量名)访问,如: Out.this.show();
- 在没有重名的情况下,无论静态非静态,内部类直接通过变量名访问外部成员变量。
外部类的访问
-
内部类为非静态时,外部类访问内部类,必须建立内部类对象。建立对象方法,如前所述
-
内部类为静态时,外部类访问非静态成员,通过(外部类对象名.内部类名.方法名)
如:new Out().In.function();
-
内部类为静态时,外部类访问静态成员时,直接通过(外部类.内部类名.方法名),如
如: out.In.function();
PS:当内部类中定义了静态成员时,内部类必须是静态的; 当外部静态方法访问内部类时,内部类也必须是静态的才能访问。