首页 > 为什么java非静态内部类可以有static final的数据成员?

为什么java非静态内部类可以有static final的数据成员?

根据java的语法,非静态内部类不可以有静态成员的声明,如

class Laptop {
    // non-static inner class
    class Battery {
        private static String vendor = "Lenovo";
    }
}

是不能编译通过的。

但是如果声明 Battery 的成员 vendor 为 final, 如:

class Laptop {
    // non-static inner class
    class Battery {
        private static final String vendor = "Lenovo";
    }
}

就可以编译通过,为什么呢?


补充一下, 实际上非static内部类里, static数据成员不是加了final的变量就可以了

比如:

import java.util.Date;
public class Outter {
        class Inner{
                int x;
                final static int i=1;
                final static Date t=new Date();
        }
}

用jdk1.7的javac, 可以看到这个:

Outter.java:7: 错误: 内部类Outter.Inner中的静态声明非法
                final static Date t=new Date();;
                                  ^
  修饰符 'static' 仅允许在常量变量声明中使用

明显是不对的.

java在这上面有bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=343480 如果在新版的eclipse上, 可以看到: The field t cannot be declared static in a non-static inner type, unless initialized with a constant expression

不仅需要final, 还需要初始化为一个常量表达式.

最后补充一下我的理解, 为什么限制 非静态内部类不可以有静态成员的声明

如果我们不从抽象的语义方面去理解, 可以这么想:

public class Outter {
    class Inner{
        static Inner a1=new Inner();
    }
}

如果上面的代码编译无误, 我们可以直接 Outter.Inner.a来拿到Inner类的实例, 而内部类的实例是一定要绑定到一个外部类的实例的. 然后java里试图用final来为上述限制松绑, 以提供更多的灵活性.


每一个非静态内部类,必须维持一个对其外部类实例的应用,这就表明了非静态内部类的作用域是实例级别;而static关键字显式指定某个属性、方法或内部类的作用域是属于类级别。既然二者在语言层面要求的作用域不同,自然无法编译通过。
为什么添加final就可以了呢。final关键字的字面语义就是指明不可变,用在属性上,表示属性一旦赋值后即不可改变。与static关键字合用即表示定义一个常量,从这个角度看有点类似c++中的const。一旦作为常量,其作用域自然不再是实例级别了,而是全局级别了,只是java语言里面没有全局级别的作用域这个概念,类级别作用域其实就只是加了一个访问权限修饰的全局作用域而已。所以编译自然OK。

【热门文章】
【热门文章】