为什么阴影会影响“最终”行为?

时间:2015-02-13 00:46:31

标签: java final

以下是三个SSCCE,我相信它应该编译并且行为相同。我唯一要改变的是第一行“跑”。

图1

public class FinalExperiment {
    private TinyThing thing;

    public static void main(String[] args) {
        FinalExperiment instance = new FinalExperiment();
        instance.run();
    }

    public void run() {
        final TinyThing thing = new TinyThing();
        System.out.println("Got a thing here: " + thing);
    }

    private static class TinyThing {
        public TinyThing() {}
        public String toString() { return "Hello!"; }
    }
}

这有效;它成功编译,并打印:“有一件事:你好!”

图表2

public class FinalExperiment {
    private TinyThing thing;

    public static void main(String[] args) {
        FinalExperiment instance = new FinalExperiment();
        instance.run();
    }

    public void run() {
        final TinyThing otherThing = thing;
        System.out.println("Got a thing here: " + otherThing);
    }

    private static class TinyThing {
        public TinyThing() {}
        public String toString() { return "Hello!"; }
    }
}

这有效;它编译成功,并打印:“有一件事:null”

图3

public class FinalExperiment {
    private TinyThing thing;

    public static void main(String[] args) {
        FinalExperiment instance = new FinalExperiment();
        instance.run();
    }

    public void run() {
        final TinyThing thing = thing;
        System.out.println("Got a thing here: " + thing);
    }

    private static class TinyThing {
        public TinyThing() {}
        public String toString() { return "Hello!"; }
    }
}

使用此消息无法编译:

FinalExperiment.java:10: error: variable thing might not have been initialized
            final TinyThing thing = thing;
                                    ^
1 error

为什么呢?图表2和图3之间的唯一区别是我在thing方法中隐藏了run。似乎编译器不应该更简单地关注,因为正在发生阴影。

3 个答案:

答案 0 :(得分:5)

是的,图3中出现了阴影,但实际上您正在尝试声明final变量,然后将其分配给自身。

final TinyThing thing = thing;  // Assign to self!

尚未为其分配值,因此您会收到编译器错误,表明它未初始化。无论局部变量thing是否为final,都会发生这种情况。

要引用实例变量,请使用this

对其进行限定
final TinyThing thing = this.thing;  // Bypass shadowing.

这会编译并产生与图表2相同的输出:

Got a thing here: null

此示例无法以相同方式编译,例如:

public class SelfDefineExample {
    public static void main(String[] args) {
        int i = i;
    }
}

答案 1 :(得分:1)

执行final TinyThing thing = thing时,您会引用尚未初始化的自变量。

您可以通过final TinyThing thing = this.thing;

解决此问题

哪个会输出

  

在这里有一件事:null

请注意,final关键字不会改变此处的行为。

这与阴影无关,您可以使用任何其他值进行测试。

例如:Object a = a会出现同样的错误。

答案 2 :(得分:1)

变量属于他们自己定义的范围。这样:

int i = i;

尝试使用自己的值初始化变量。但它没有价值,因为它尚未初始化!因此错误。