内部类

内部类

局部内部类

  • 存在于外部类的方法体,代码块中
  • 可以访问外部类所有成员
  • 外部类访问局部内部类成员要实例化对象
  • 调用变量时遵循就近原则,如果要调用外部类的同名变量, 通常这么访问:
    外部类.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修饰
  • 可以添加访问修饰符,因为静态内部类相当于一个成员
  • 可以访问外部类的静态成员
  • 作用域 整个类体
  • 外部类访问静态内部类先创建成员内部类对象然后调用
  • 外部其他类使用静态内部类
    • 通过类名直接访问,注意符合访问权限
    • 编写放回静态内部类的方法
  • 调用变量时遵循就近原则,如果要调用外部类的同名变量, 通常这么访问:
    外部类.变量

小结

  1. 内部类有四种 局部,匿名 成员 静态内部类

  2. 重点是匿名内部类使用

    new 类/接口(参数列表){
    //...
    };

  3. 成员/静态内部类是在外部类的成员位置,本质就是一个成员

posted @ 2021-11-12 17:20  独高的浮云  阅读(58)  评论(0)    收藏  举报