杰瑞科技汇

Java匿名内部类中的this指向谁?

核心思想

在匿名内部类中,this 有两个层面的含义:

Java匿名内部类中的this指向谁?-图1
(图片来源网络,侵删)
  1. 指代当前匿名内部类的实例:当你在匿名内部类的方法中直接使用 this 时,它指向的是匿名内部类自己创建的那个对象。
  2. 指代外部类的实例:当你在匿名内部类的方法中,通过 外部类名.this 的形式来访问 this 时,它指向的是包含该匿名内部类的那个外部类的对象。

理解这两者的区别是掌握匿名内部类 this 的关键。


this 指代匿名内部类自身

这是最常见的情况,当你创建一个匿名内部类的实例并调用其方法时,方法内部的 this 就代表这个匿名对象。

示例代码:

public class OuterClass {
    public void display() {
        System.out.println("OuterClass's display() method.");
    }
    public void useAnonymousClass() {
        // 创建一个实现 Runnable 接口的匿名内部类
        Runnable r = new Runnable() {
            @Override
            public void run() {
                // 这里的 this 指的是 new Runnable() {...} 这个匿名对象
                System.out.println("Inside anonymous class. this = " + this);
                System.out.println("The type of 'this' is: " + this.getClass().getName());
            }
        };
        Thread t = new Thread(r);
        t.start();
    }
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        System.out.println("In main method. outer = " + outer);
        outer.useAnonymousClass();
    }
}

输出结果:

Java匿名内部类中的this指向谁?-图2
(图片来源网络,侵删)
In main method. outer = com.example.OuterClass@15db9742
Inside anonymous class. this = com.example.OuterClass$1@6d06d69c
The type of 'this' is: com.example.OuterClass$1

代码分析:

  1. System.out.println("In main method. outer = " + outer);:这里的 outerOuterClass 的一个实例。
  2. Runnable r = new Runnable() { ... };:我们创建了一个匿名对象,这个对象的类型是 OuterClass 的一个自动生成的、未命名的子类(编译器会命名为 OuterClass$1)。
  3. public void run() { ... }:这是匿名内部类的方法。
  4. System.out.println("Inside anonymous class. this = " + this);:在 run 方法内部,this 指的是当前正在执行的匿名对象,即 r 引用的那个对象,从输出可以看到,它的类型是 com.example.OuterClass$1,而不是 OuterClass

外部类名.this 指代外部类实例

有时,匿名内部类需要访问或引用它所嵌入的外部类的实例,这时,就必须使用 外部类名.this 的形式。

示例代码:

public class OuterClass {
    private String outerName = "Outer Instance";
    public void displayOuterName() {
        System.out.println("OuterClass's name is: " + outerName);
    }
    public void createAndUseAnonymous() {
        // 匿名内部类需要访问外部类的 outerName 变量
        // 它还需要一个方法来接收外部类的实例
        new Object() { // 创建一个匿名子类
            public void showOuterReference(OuterClass outer) {
                // 使用 外部类名.this 来明确指代外部类的当前实例
                OuterClass outerThis = OuterClass.this;
                System.out.println("Anonymous class's outer reference: " + outerThis);
                System.out.println("Accessing outer variable via outerThis: " + outerThis.outerName);
                // 直接访问外部类的成员(如果可见)
                // 因为匿名内部类是非静态的,所以可以隐式访问外部类的成员
                System.out.println("Directly accessing outer variable: " + outerName);
            }
        }.showOuterReference(this); // 将当前外部类的实例 (this) 传递过去
    }
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        System.out.println("In main, outer = " + outer);
        outer.createAndUseAnonymous();
    }
}

输出结果:

In main, outer = com.example.OuterClass@15db9742
Anonymous class's outer reference: com.example.OuterClass@15db9742
Accessing outer variable via outerThis: Outer Instance
Directly accessing outer variable: Outer Instance

代码分析:

  1. new Object() { ... }.showOuterReference(this);:我们创建了一个匿名 Object 的子类,并立即调用了它的方法 showOuterReference,同时将当前外部类的实例 (this) 作为参数传递。
  2. public void showOuterReference(OuterClass outer):这是匿名类的方法,它接收一个 OuterClass 类型的参数。
  3. OuterClass outerThis = OuterClass.this;:这是最关键的一行。OuterClass.this 明确地告诉编译器:“我要获取的是 OuterClassthis,而不是我这个匿名类的 this”。outerThis 变量现在就指向了外部类的那个实例。
  4. System.out.println("Accessing outer variable via outerThis: " + outerThis.outerName);:通过 outerThis,我们成功访问了外部类的私有成员 outerName
  5. System.out.println("Directly accessing outer variable: " + outerName);:在非静态的内部类(包括匿名内部类)中,可以隐式地访问外部类的成员,所以即使不写 OuterClass.this,也能直接访问 outerName,但在某些情况下,比如方法参数名与外部成员名冲突,或者为了代码清晰,使用 OuterClass.this 是更好的选择。

常见陷阱与注意事项

在构造器中不能使用 this

匿名内部类没有显式的构造器(只有默认的),它的初始化代码块()可以看作是一个构造器,但在这个初始化块中,你不能调用 this()super()

错误示例:

new Object() {
    {
        // this(); // 编译错误!匿名内部类没有构造器可以调用
        System.out.println("Initialization block");
    }
};

this 的类型决定了可以调用的方法

由于匿名内部类是一个具体的类,它的 this 类型就是这个匿名类本身,你只能调用这个匿名类中定义的方法,或者它所实现的接口/继承的父类中的方法。

示例:

public class Outer {
    public void doSomething() {
        // 匿名内部类实现了 MyInterface
        MyInterface obj = new MyInterface() {
            @Override
            public void methodA() {
                System.out.println("methodA called");
                // this.methodB(); // 编译错误!this 的类型是匿名类,它没有 methodB
            }
        };
        obj.methodA();
    }
    public static void main(String[] args) {
        new Outer().doSomething();
    }
}
interface MyInterface {
    void methodA();
}

匿名内部类中的 final 或 effectively final 变量

匿名内部类访问外部方法的局部变量时,该变量必须是 final 或 effectively final (即只被赋值一次),这是为了避免外部方法执行完毕后,局部变量被销毁,而匿名内部类的对象却持有一个无效的引用。

public class Outer {
    public void myMethod() {
        int count = 10; // effectively final
        new Runnable() {
            @Override
            public void run() {
                // System.out.println(count++); // 编译错误!不能修改 effectively final 变量
                System.out.println("Count is: " + count);
            }
        }.run();
        // count = 20; // 如果取消这行注释,上面的代码就会编译错误,因为 count 不再是 effectively final
    }
}
上下文 this 的含义 示例 类型
匿名内部类内部 指代匿名内部类自身的实例 System.out.println(this); OuterClass$1 (编译器生成的匿名子类)
匿名内部类内部 指代外部类的实例 OuterClass.this OuterClass

记住这个核心区别,你就能轻松应对 Java 匿名内部类中关于 this 的各种问题了。

分享:
扫描分享到社交APP
上一篇
下一篇