内部类
内部类
局部内部类
- 存在于外部类的方法体,代码块中
- 可以访问外部类所有成员
- 外部类访问局部内部类成员要实例化对象
- 调用变量时遵循就近原则,如果要调用外部类的同名变量, 通常这么访问:
外部类.this.变量 - 外部其他类不能访问局部内部类,因为局部内部类地位相当于局部变量
匿名内部类(重点)
情景需求:假设我有一个接口A,然后有一个抽象方法f(),要实现这个方法,该怎么做?
常规的思路就是建一个类去实现它,重写方法,然后创建对象再去调用
interface A{
void f();
}
class B implements A{
@override
public void f(){
//方法体...
}
}
public static void main(String[] args) {
B b = new B;
B.f();
}
大致就是这么个流程,但有一个问题,如果我们仅仅是实现一次接口里的方法,又要建类重写方法又要实例化对象再去调用,如果是多次调用还好,但只用一次就会很繁琐,这样,匿名内部类就拯救我们了。
下面是匿名内部类的实现方式
interface A{
void f();
}
public static void main(String[] args) {
A a = new A(){
@override
public void f(){
//方法体...
}.f();
}
在main方法直接新建一个接口引用指向实现接口A的匿名内部类
花括号内的就是匿名内部类了。
通过匿名内部类来实现接口方法,在仅调用一次的情况下,比传统方法(写类实现接口)明显清爽很多。
说明
- 匿名内部类本质还是一个类,有属性有方法
- 定义在方法体和代码块中 (外部类的局部位置)
- 该类没有名字 (实际上jdk底层自动分配类名 我们不用写)
- 是一个对象
基本语法
new 类或接口(参数列表){
//类体
}
使用
假设有一个类Person,在main方法去用匿名内部类
public static void main(String[] args) {
Person people = new Person();//1
Person people1 = new Person(){//2
public void hi(){};
};
people1.hi();
}
句1和句2是完全不一样的,句1是Person的对象创建
来详细分析一下句2
people1的编译类型是Person,运行类型是继承Person的匿名内部类
Person people1 = new Person() { } ;下划线部分就是匿名内部类
它干的是就是 class XXXX$1 extends Person{ },同时返回XXXX$1的对象给people1,
XXXX$1就是jdk给匿名内部类分配的类名。匿名内部类使用一次就没了,但people1对象还在,可以调匿名内部类中的方法,想用几次用几次。
细节
-
匿名内部类的语法比较奇特,它既是一个类的定义,同时本身也是一个对象,因此也可以调用匿名内部类中的方法,从上面的代码也可以看出。
-
匿名内部类可以访问外部类的所有成员
-
不能添加访问修饰符
-
调用变量时遵循就近原则,如果要调用外部类的同名变量, 通常这么访问:
外部类.this.变量 -
外部其他类不能访问局部内部类,因为局部内部类地位相当于局部变量
和局部内部类差不多
匿名内部类的最佳实践
当作实参传递,简介高效
案例:
有一个铃声接口Bell,里面有ring方法
有一个手机类CellPhone,有一个闹钟功能alarmClock参数是Bell类型
测试闹钟功能通过匿名内部类作为参数,打印懒狗起床了
再传入另一个匿名内部类打印 懒狗上课了
interface Bell{
void ring();
}
class CellPhone{
public void alarmClock(Bell bell){
bell.ring();
}
}
public static void main(String[] args) {
//先创建一个手机对象
CellPhone cellPhone = new CellPhone();
//调用手机的alarmClock方法,
cellPhone.alarmClock(new Bell() {//这边返回给形参bell的是 //实现接口Bell匿名内部类对象
@Override //重写了ring方法
public void ring() {
System.out.println("懒狗起床了");
}//这里通过动态绑定机制,实现的是重写后的ring()方法,完成打印
});
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("懒狗上课了");
}
});
}
成员内部类
-
定义在外部类的成员位置,没有static修饰
-
可以访问外部类的所有成员
-
可以添加访问修饰符,因为成员内部类相当于一个成员
-
作用域再整个类体中
-
外部类访问成员内部类先创建成员内部类对象然后调用
-
外部其他类使用成员内部类方式
-
先创建外部类对象然后 Outer.Inner inner = outer.new Inner();
Outer外部类 Inner内部类 inner内部类对象 outer外部类对象这里的语法就是把new Inner()当成outer 的成员来使用
-
在外部类编写一个返回成员内部类的方法
-
-
调用变量时遵循就近原则,如果要调用外部类的同名变量, 通常这么访问:
外部类.this.变量
静态内部类
- 放在外部类的成员位置
- static修饰
- 可以添加访问修饰符,因为静态内部类相当于一个成员
- 可以访问外部类的静态成员
- 作用域 整个类体
- 外部类访问静态内部类先创建成员内部类对象然后调用
- 外部其他类使用静态内部类
- 通过类名直接访问,注意符合访问权限
- 编写放回静态内部类的方法
- 调用变量时遵循就近原则,如果要调用外部类的同名变量, 通常这么访问:
外部类.变量
小结
-
内部类有四种 局部,匿名 成员 静态内部类
-
重点是匿名内部类使用
new 类/接口(参数列表){
//...
}; -
成员/静态内部类是在外部类的成员位置,本质就是一个成员