什么是内部类
概念:在一个类的内部再定义一个完整的类
public class Outer {
class Inner {
}
}
特点:
- 编译之后可生成独立的字节码文件
- 内部类可直接访问外部类的私有属性,而不破坏封装
- 可为外部类提供必要的内部功能组件
一、成员内部类
概念:在类的内部定义,与实例变量、实例方法同级别的类
特点:
- 成员内部类可以使用任意访问修饰符(外部类的访问修饰符只能是 public 或 默认)
- 成员内部类可以直接访问外部类的属性和方法
- 如果内部类中的属性名和外部类中属性名重名时,使用
外部类名.this.属性名
访问 - 成员内部类中不能包含静态成员(但是可以包含静态常量)
成员内部类的使用
/**
* 成员内部类。
*
* @author 张宝旭
*/
public class Outer {
// 实例属性
private String name = "zbx";
private int age = 21;
// 实例方法
public void show() {
System.out.println("name:" + name + " age:" + age);
}
// 成员内部类
class Inner {
private String name1 = "j";
private int age1 = 21;
public void show() {
System.out.println("name:" + name1 + " age:" + age1);
// 内部类访问外部类属性
System.out.println(Outer.this.name);
}
}
}
/**
* 测试内部类。
*
* @author 张宝旭
*/
public class OuterTest {
public static void main(String[] args) {
// 创建外部类对象
Outer outer = new Outer();
outer.show();
// 创建内部类对象
Outer.Inner inner1 = outer.new Inner();
inner1.show();
// 两步合成一步
Outer.Inner inner2 = new Outer().new Inner();
inner2.show();
}
}
二、静态内部类
概念:不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员
作用:为外部类提供功能
特点:
- 静态内部类可以使用任意访问修饰符
- 静态内部类不能直接访问外部内部类的实例属性和方法,可以直接访问静态属性和方法
- 静态内部类可以包含静态成员
静态内部类的使用
/**
* 静态内部类。
*
* @author 张宝旭
*/
public class Outer {
// 实例属性
private String name = "zbx";
private int age = 21;
// 实例方法
public void show() {
System.out.println("name:" + name + " age:" + age);
}
// 静态内部类,级别和外部类一样
// 作用:为外部类提供功能
static class StaticInner {
// 成员属性
private String name = "t";
// 静态属性
private static int count = 12;
// 成员方法
public void show() {
System.out.println("show");
}
// 静态成员方法
public static int sum() {
return ++count;
}
}
}
/**
* 测试静态内部类。
*
* @author 张宝旭
*/
public class OuterTest {
public static void main(String[] args) {
// 测试静态内部类
Outer.StaticInner staticInner = new Outer.StaticInner();
staticInner.show();
Outer.StaticInner.sum();
}
}
三、局部内部类
概念:定义在外部类方法中,作用范围仅限于当前方法(和局部变量级别一样)
特点:
- 不能使用任何访问修饰符
- 如果局部内部类所在的方法是非静态方法,则可以直接访问外部类的属性和方法
- 如果局部内部类所在的方法是静态方法,则只能访问外部类的静态属性和方法
- 局部内部可以访问外部类的局部变量,但是局部变量必须是 final 类型 (JDK1.8后final可以省略)
- 局部内部类也不能声明静态成员,但是可以使用静态常量
为什么局部变量必须是final类型?
因为对象的生命周期比局部变量的声明周期长
在方法中创建内部对象后,当方法结束后,局部变量的生命周期就结束了,但是局部内部类创建的对象还没有立即销毁,需要等待GC去回收后才会销毁,但是在局部内部类中还需要访问局部变量,而局部变量已经销毁了,所以才规定,这个局部变量必须声明为final类型
局部内部类的使用
/**
* 局部内部类。
*
* @author 张宝旭
*/
public class Outer {
// 实例属性
private String name = "zbx";
private int age = 21;
private static int myCount = 12;
// 外部类方法
public void print() {
String gender = "MM";
// 局部内部类
class LocalInner {
private String name = "tt";
public void run() {
System.out.println("local Inner Class");
}
}
// 创建对象
LocalInner localInner = new LocalInner();
localInner.run();
}
}
四、匿名内部类
概念:没有类名的内部类
特点:
- 必须继承一个父类或实现一个接口
- 不能手动添加构造方法
- 不能添加静态成员
- 一般不包含特有的方法,因为不能直接访问,但是可以通过内部对象访问
- 匿名内部类生成的class文件:
类名$编号.class
优点:减少代码量
缺点:可读性差
匿名内部类的使用
public interface USB {
void print();
}
/**
* @author 张宝旭
*/
public class Anonymity {
public static void main(String[] args) {
// 第一种方法
USB usb1 = new USB() {
@Override
public void print() {
System.out.println("usb1");
}
};
usb1.print();
// 第二种方法 lambda表达式
USB usb2 = ()->{
System.out.println("usb2");
};
// 第三种方法 lambda表达式
USB usb3 = ()-> System.out.println("usb3");
}
}
如果需要重写多个方法,则不可使用lambda表达式