【JavaEE】匿名内部类的隐式继承和实现、为何只能访问局部final变量?

匿名内部类

定义: 匿名内部类是指在使用某个类的时候,临时创建一个继承于该类的子类对象,并对该对象进行重写或扩展操作,但是不拥有具体的类名,而是直接使用匿名的方式进行定义和实例化。

语法:new 构造器(实参列表) {// 匿名内部类的类体部分}

匿名内部类通常用于一次性的需求,不需要单独创建一个新的类或者接口来实现某个功能。它主要用于简化代码的编写,减少类的定义和对象实例化的步骤。


隐式继承/实现

匿名内部类可以重写父类的方法、实现接口的方法。由此,通常会使用一种可拓展性更强的写法:
new 父类构造器(实参列表)/接口() { // 匿名内部类的类体部分 }
此处,类体部分实质上是外部父类/接口的子类/实现类,在内部直接实现某个功能。

例如,在创建对象时,直接重写父类的抽象方法:

public class Main {
    public static void main(String[] args) {
        // 创建一个匿名内部类对象,并继承自父类Animal
        Animal animal = new Animal() {
            @Override
            public void makeSound() {
                System.out.println("Meow"); // 实现了父类的抽象方法
            }
        };
        
        // 调用匿名内部类对象的方法
        animal.makeSound(); // 输出:Meow
    }
}

// 父类Animal
abstract class Animal {
    abstract void makeSound();
}

还有一种常见的方式,创建线程时,直接重写run方法:

Thread thread = new Thread(new Runnable() {
    public void run() {
        // 线程执行的任务
    }
});

此处,new Runnable(){}作为实现Runnable接口的匿名实现类充当new Thread()的实参列表,在创建线程时定义好了run方法。

tips:

  • 通常情况下,匿名内部类是一次性使用的,因为它没有类名,无法复用;
  • 匿名内部类访问外部变量时,需要外部变量声明为final (JDK8之后,要求使用过程不修改即可)

为何只能访问局部final变量?

首先,回顾以下final的作用:

final的作用

  • 修饰:表示类不可被继承
  • 修饰方法:表示方法不可被子类重写覆盖,但可以重载
  • 修饰变量:表示变量一旦被赋值就不可更改
    • 修饰成员变量:在声明的时候就需要赋值或者在代码块中赋值
    • 修饰局部变量:系统不会为局部变量初始化,可以在用的时候赋值(使用之前一定要赋值且只能赋值一次)
    • 修饰基本类型变量:其数值一旦初始化后不能更改
    • 修饰引用类型变量:其初始化后不可在让其指向另一对象(地址不变),但引用值可变

重载和重写的区别:

  • 重载:发生在同一个类中,方法名相同,参数列表不同(个数,顺序也算),和方法返回值没有关系
  • 重写:子类重写父类方法,方法名相同,参数列表相同返回值范围小于等于父类,抛出异常范围小于等于父类,修饰符范围大于等于父类(如果父类方法为private,那么子类不可重写)

为什么局部内部类和匿名内部类只能访问局部final变量

局部内部类匿名内部类编译之后会生产单独的class文件,实际上是同一个级别。里面的class文件不会随着外部方法执行结束而回收。

这里产生一个问题:外部类的方法结束时,局部变量就会被销毁,但是内部类对象可能还存在。为了解决这个问题,JVM将局部变量复制了一份作为内部类的成员变量。因此,就将局部变量设为final,必须保证内部类和外部的变量是一样的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值