内部类的分类
局部位置
调用:如果要调用,创建类对象,对象调用方法即可(方法内有内部类)
作用域:方法或者代码块内
定义在外部类局部位置上(比如方法内,和局部变量一个层级):
1)局部内部类(有类名)
2)匿名内部类(没有类名,重点)(JDK底层还是有名字的)
成员位置
作用域:整个类体
定义在外部类的成员位置上(和属性,方法一个层级):
1)成员内部类(没用static修饰)
2)静态内部类(使用static修饰)
1)局部内部类
1.可以直接访问外部类所有成员,包括私有。
2.局部变量是不能添加访问修饰符的,只能添加final。
3.外部类想访问内部类需要创建一个外部类对象来创建内部类对象,再由内部类对象来访问。
4.外部类和局部内部类的成员重名,默认就近原则,内部类想访问外部类重名成员,则用外部类名.this.成员,因为不是静态所以要加this(哪个对象调用方法,this则指向哪个对象)(所有内部类共享这条规则,除了静态内部类)
2)匿名内部类(是一个类同时是一个对象)
底层创建一个只能使用一次的类继承该类
格式:new类/接口(参数列表){类体}
(1)基于接口
传统
一般是写一个类,实现该接口,并向上转型为接口创建对象,调用接口方法。
,就会动态绑定子类的方法。
因为接口类型可以指向实现了该接口的类的对象实例。
简化开发
编译类型是接口类型,而运行类型是匿名内部类(底层系统会分配,用外部类的名称加上$1)
如果实在想看,变量名.getClass()就看到了。
接口名 变量名=new 接口名(){
@Override
接口方法();
};
变量名.重写后的接口方法();。
并且创建了一个实例,并把实例地址赋给变量名。
匿名内部类创建一次就不能使用了销毁了,但是那个变量地址还是可以反复使用。
(2)基于类(普通类,抽象类....)
创建对象:Person p=new Person();
编译类型:Person
运行类型:Person
创建匿名内部类:Person p=new Person(){};
编译类型:Person
运行类型:(外部类名)$(创建匿名内部类的次数)
就是一个匿名类继承Person,所以运行类型是那个匿名类
第一种调用方式(要多次调用匿名类方法,用一个p变量接收):
Person p=new Person(){
@Override
类的方法(){
}
};
p.类的方法();
第二种调用方式(只调用一次匿名内部类方法,则不需要变量接收):
new Person(){
@Override
类的方法(){
super.xxx();(调用父类方法)
}
}.类的方法();
如果一个类的构造器里面有参数,那当你基于这个类使用匿名内部类并传入参数时,会调用此类的构造器。
匿名内部类当实参传递(本质也是一个对象)
//接口 interface PP{ //动态绑定机制 void show(); } //有个方法用接口类型作为参数 public static void LL(PP p){ p.show(); } //(1)在主方法中,用匿名内部类做一个对象,这个对象重写了show方法并传入参数 LL(new PP(){ @Override //在这里改动show(),不影响其他实例 public void show(){ System.out.println("999999999"); } }); //(2)传统方法(硬编码) LL(new Car()); //在这里改动方法show(),会影响所有Car实例 class Car implements PP{ @Override public void show(){ System.out.println("999999999"); } }
3)成员内部类
没有写在方法中,也不在代码块中,且没有static修饰。
和上面两个相同的是,可以访问外部类的所有成员,包含私有的,
和上面两个不同的是,它可以添加任意的访问修饰符,因为地位不再是一个局部变量,而是成员变量。
外部其他类想访问成员内部类的方法
第一个方法:
则先创建一个外部类对象,再用这个对象创建一个内部类对象,再用这个内部类对象去调用方法。
第二个方法:
在外部类中定义一个方法,该方法返回一个内部类对象实例。则直接在外部类对象调用此方法即可得到一个内部类对象。。
4)静态内部类
类被声明为静态类时,必须为内部类!
反之:静态类一定是内部类!
定义在成员变量的位置,且有static修饰。
可以直接访问外部类所有静态成员(包括私有),但是不可以访问非静态成员。
可以添加任意的访问修饰符,因为地位是成员变量。
重点!!!
静态类不可以实例化!但是静态内部类可以实例化!!
外部类和局部内部类的成员重名,默认就近原则,内部类想访问外部类重名成员,则用外部类名.成员(因为你只能访问外部类静态成员,静态成员是属于类的,不需要加this)