内部类
- 类的五大成员
属性、方法、构造方法、代码块、内部类
什么是内部类?
在一个类的里面,再定义一个类
举例:在A类的内部定义B类,B类就被称为内部类
public class Outer { /内部类
public class Inner { /外部类
}
}
public class Test { /外部其他类
public static void main(String[] args) {
}
}
- 内部类表示的事物是外部类的一部分
- 内部类单独出现没有任何意义
- 比如:汽车的发动机,ArrayList的迭代器,人的心脏等
内部类的访问特点
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要访问内部类的成员,必须创建内部类对象
内部类的分类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
成员内部类
- 写在成员位置的,属于外部类的成员
- 成员内部类可以被一些修饰符所修饰,比如:private、默认、protected、public、static等
- 在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量
public class Car { //外部类
String carName;
int carAge;
int carColor;
class engineName { //成员内部类
String engineName;
int enginAge;
}
}
获取成员内部类对象
- 方式一:在外部类中编写方法,对外提供内部类的对象
- 方式二:直接创建格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象
- 范例:
Outer.Inner oi = new Outer().new Inner();
- 范例:
- 当内部类被private所修饰,无法在外部之间获取内部类对象,这时可以通过方式一获取
//在外部类中
public Inner gerInstance() {
return new Inner();
}
//在类外,可以通过多态来获取对象
Outer o = new Outer();
//Outer.Inner inner = o.getInstance(); //错误的,外部无法访问到Inner
Object inner = o.getInstance();
//或者直接使用
sout(o.getInstance());
- 在底层内部类的地址 @ 的左边显示的是 Outer 和 _
成员内部类如何获取外部类成员变量
public class Outer {
private int a = 10;
class Inner {
private int a = 20;
public void show() {
int a = 30;
sout(Outer.this.a); //10
sout(this.a); //20
sout(a); //30
}
}
}
public class Test {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
- 在内部类对象生成时,虚拟机会自动生成一个Outer.this变量,里面存储的是外部类Outer的地址值
静态内部类
静态内部类也是成员内部类中的一种
public class Car { //外部类
String carName;
int carAge;
int carColor;
static class engineName { //静态内部类
String engineName;
int enginAge;
}
}
-
静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建外部类对象
-
创建静态内部类对象的格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
Outer.Inner oi = new Outer.inner();
-
调用非静态方法的格式:先创建对象,用对象调用
-
调用静态方法的格式:外部类名.内部类名.方法名();
局部内部类
- 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量
- 外界无法直接使用局部内部类,需要在方法内部创建对象并使用
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量
匿名内部类
匿名内部类本质上就是隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置
真的没有名字吗?其实并不是,其实是不用我们自己写名字,虚拟机会自动分配名字,格式为 父类或接口名字$序号 ,例如Inter$1
格式
new 类名或者接口名() {
重写方法;
};
举例
new Inter() {
public void show() {
}
};
格式的细节
-
包含继承/实现关系
-
包含方法的重写
包含创建对象
-
整体就是一个类的子类对象或者接口的实现类对象
使用场景
- 当方法的参数是接口或者类时
- 以接口为例,可以传递这个接口的实现类对象,如果这个类只要使用一次,就可以用匿名内部类来简化代码