内部匿名类无法访问外面的非 final 的变量的问题

这个题目有点拗口,其实我更多的是想说 Java 内部类的一些特性。

之所以会想起这个题目只要是最近在阅读 JDK 源码中关于 HTTP keepalive 的代码时,其中一个源文件 sun.net.www.protocol.http.HttpURLConnection.java 无意中看到下面这段代码。(注意高亮部分的代码)

final boolean result[] = {false};
java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {
    public Object run() {
        try {
            InetAddress a1 = InetAddress.getByName(h1);
            InetAddress a2 = InetAddress.getByName(h2);
            result[0] = a1.equals(a2);
        } catch (UnknownHostException e) {
        } catch (SecurityException e) {
        }
        return null;
    }
});

return result[0];


Java 的匿名内部类无法访问对应的函数的非 final 变量。要想访问外部的 local variable, 这个variable 又必须要先定义成 fianl, 但是一定义成 final 就不能在匿名内部类中修改这个变量的值,所以要想匿名内部类返回一些有用的值时不是那么的容易。这段代码使用了一个非常巧妙的方法,这里使用数组的方式绕过这个限制,虽然我们无法修改 result 这个变量的引用,但是我们可以修改 result 指向的那个数组的内容。

这篇文章只是想记录一下内部匿名类修改外部变量的一个小技巧。不过既然已经到了这里,不妨继续的看看内部类都有哪些特性或者限制吧。

在继续本文前,我觉得非常有必要的明确下本文中涉及的一些 Java 术语,这些术语不太好翻译成中文,所以我们还是用英文来描述。

// This is class
public class JavaTerm {

    //  field or member variable
    private int field;

    // constructor
    public JavaTerm() {
    }

    // method
    public void method() {

        // local variable
        int localVariable = 0;

        // local class
        class LocalClass {
            public LocalClass() {
            }
        }
        // anonymous class
        new Runnable() {
            public void run() {
            }
        };
    }
}

我们今天更多的将关注于 local class 和 anonymous class,它们都属于 inner class。

Java 允许我们在一个 class 里面再定义一个 class, 称为嵌套类(nested class), nested class 又可以分为两类,一类是 static nested class, 另外一个是 non-static nested class, 又称为 inner class。inner class 又可以分为 local class 和 anonymous class。

anonymous class 的一些限制
  • 一个 anonymous class 可以访问包含它的类的类变量(field/member variable)
  • 一个 anonymous class 不能访问包含它的作用于中的不是 final 的本地变量(local variable)
  • 和 nested class 一样,anonymous class 中定义的 variable 会覆盖包含这个内部类的作用域中的同名的 variable
  • 你不能定义静态的初始化方法
  • 一个 anonymous class 可以有静态的成员变量。这个成员变量必须是常量(用 final 修饰)。
  • 一个 anonymous class 不可以有构造函数

更多的一些特性还是参考 Java 官方的教程吧。那里更权威,更详细。

  1. Nested calsses http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
  2. Local classes http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
  3. Anonymous classes http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注