Java疯狂讲义笔记——内部类
【定义】
内部类:定义在其它类内部的类。
外部类:包含内部类的类,也称 宿主类。
局部内部类:定义在方法里的内部类。
【接口内部类】
接口中也可以定义内部类,必须为public static修饰(自动添加),接口内部类只能时静态内部类。
【接口的内部接口】
接口的内部接口为接口成员,必须为public static(自动)。
【与外部类关系】
1,成员内部类是类成员。
成员内部类:静态内部类、非静态内部类
2,局部内部类和匿名内部类不是类成员。
【内部类的作用】
1,内部类提供了更好的封装,其隐藏在外部类之内,不允许同一个包中的其他类访问该类。
2,内部类成员可以直接访问外部类的私有数据,因为内部类被当成为外部类的成员,同一个类的成员间可以相互访问。
但外部类不能访问内部类的实现细节,例如内部类的成员变量。
3,匿名内部类适合用于创建那些仅需要一次使用的类。
【内部类与外部类定义时的区别】
1,内部类比外部类可以多使用三个修饰符:private、protected、static ——外部类不可以使用这三个修饰符。
2,为外部类定义子类,子类创建一个与父类的内部类同名的内部类不是重写,而是重新创建了一个新的属于子类的内部类。因为它们的命名空间不同。
内部类的类名不是简单地由内部类的类名组成,而是还把外部类的类名作为一个命名空间,作为内部类类名的限制。
【内部类和外部类的作用域】
1,外部类:
同一个包内----默认(default)
任何位置------public
2,内部类:
同一个类----private
同一个包----default
同一个包的其他类和外部类的子类------protected
任何位置----public
【非静态内部类】
1,非静态内部类对象里,保存了一个它所寄生的外部类对象的引用,即
当调用非静态内部类的实例方法时,必须有一个非静态内部类实例,非静态内部类实例必须寄生在外部类实例中。
2,外部类实例:OutterClass.this.
内部类实例:this.
3,如果外部类要访问非静态内部类的成员,必须显示创建非静态内部类对象来调用访问其实例成员。
4,非静态内部类不能拥有静态成员。
5,不能在外部类的静态成员中直接使用非静态内部类。
6,非静态内部类的子类不一定是内部类,它可以是一个外部类。
但对于非静态内部类的子类实例一样保留了一个引用,该引用指向其父类所在外部类的对象。
如果有一个内部类的子类存在,则一定存在与之对应的外部类对象。
【静态内部类】
1,静态内部类属于外部类本身,不属于外部类的某个对象。也称 类内部类。
2,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。
3,静态内部类的实例方法也不能访问外部类的是实例成员,只能访问外部类的静态成员。
4,外部类不可直接访问静态内部类成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,
使用静态内部类的对象作为调用者来访问静态内部类的实例成员。
【局部内部类】
【匿名内部类】
定义:
new 实现接口() | 父类构造器(实参列表)
{
//匿名内部类的类体部分
}
特点:
1,适用于创建只需要一次使用的类。
2,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。
3,匿名内部类必须继承一个父类或实现一个接口,但最多只能继承一个父类,实现一个接口。
4,匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象。
5,匿名内部类不能定义构造器。由于匿名内部类没有类名,所以无法定义构造器。
匿名内部类可以定义初始化块,通过实例初始化块来完成构造器完成的事情。
匿名内部类的实现:
1,通过实现接口
匿名内部类不能显式创建构造器,因此匿名内部类只有一个隐式的无参数构造器,故new接口名后的括号里不能传入参数值。
2,通过继承父类
匿名内部类将拥有和父类相似的构造器,此处的相似指拥有相同的形参列表。
【Java8增强的匿名内部类】
1,从Java8以前,匿名内部类、局部内部类访问的局部变量必须用final修饰。
从Java8开始,匿名内部类、局部内部类允许访问非final的局部变量。
2,如果局部变量被匿名内部类访问,那么该局部变量相当于自动使用了final修饰。
3,Java8将这个功能称为"effectively final",它的意思是对于被匿名内部类访问的局部变量,可以用final修饰,也可以不用final修饰,
但必按照有final修饰的方法来用——也就是一次赋值后,以后不能重新赋值。
例子:
class Demo
{
public static void main(String[] args) {
int age = 8;
/*
age = 2; //报错
Demo.java:11: 错误: 从内部类引用的本地变量必须是最终变量或实际上的最终变量
System.out.println(age);
^
1 个错误
定义age时指定了初值,后又对其赋值,导致Java8无法自动使用final修饰age局部变量,因此编译器会报错。
(被匿名内部类访问的局部变量必须被final修饰)
*/
A a = new A() {
public void test() {
//在Java8以前下面语句将提示错误:age必须使用final修饰
//从Java8开始,匿名内部类、局部内部类允许访问非final的局部变量
System.out.println(age);
}
};
a.test(); //输出:8
}
}
interface A
{
void test();
}