Java 常数和内部类
Java 常数和内部类,java,constants,inner-classes,Java,Constants,Inner Classes,static内部类中的变量: 内部类不能包含静态字段。它不能包含静态成员,因为在哪里分配静态成员会有问题。内部类与外部类相连接。我理解为什么它不包含static成员,但内部类可以包含static常量。为什么?它经过特殊处理吗?它在特殊的堆上吗?它仍然是静态成员,但是是常量,所以它被特殊处理了吗 它可以包含:“最终静态int x”,但不能包含“静态int x” 我想知道为什么本地类中使用的方法变量应该是final。我的意思是: public void function1() { final i
static
内部类中的变量:
内部类不能包含静态
字段。它不能包含静态
成员,因为在哪里分配静态
成员会有问题。内部类与外部类相连接。我理解为什么它不包含static
成员,但内部类可以包含static
常量。为什么?它经过特殊处理吗?它在特殊的堆上吗?它仍然是静态成员,但是是常量,所以它被特殊处理了吗
它可以包含:“最终静态int x”,但不能包含“静态int x”
final
。我的意思是:
public void function1() {
final int x; // value of x, which is used in class A have to be final
class A {
void function2() {
//body of function
}
}
}
答案是:变量x id复制到类A。它不能更改,因为当时出现了不一致。那么,为什么Java架构师没有创建不复制变量x的语言呢?变量的地址将被传递,然后变量x将被更改而不会出现不一致。有人能给我举个例子解释一下吗
或与同步相关的问题。这两个变量应该是相同的,但是如果我们超出了范围呢?其中一个变量不存在,那么同步又如何呢interface In
{
void f1();
}
class A
{
int variable = 3;
In g()
{
return new In()
{
@Override
public void f1()
{
variable = 6;
System.out.println(variable);
}
};
}
}
public static void main(String[] args)
{
In in1;
{
A a = new A();
in1 = a.g();
}
in1.f1(); //class A does not exists any more, field 'variable' is changed, despite it does not exist
}
为什么没有同步问题?要回答第一个问题: 就我个人而言,我还不明白为什么它不接受内部类中的非最终静态成员。但是,我可以告诉您编译时会发生什么。当您声明
静态final
基元成员时,可以将其编译为使用此成员的代码。但是,当您尝试创建静态最终对象o=new Object()时代码>,它无法在编译时知道o
将指向什么。显然,如果您在内部类中创建一个静态int
(非final),则会产生相同的编译器错误
回答第二个问题,原因如下:
x
是一个局部变量,它被推送到堆栈上。当您在内部类中使用对x
的引用时,您将遇到问题。因为内部类很可能比该函数的作用域活得更长。函数一结束,x
就超出范围并从堆栈中删除。所以,现在,您的内部类仍然有一个对不再存在的变量的引用。因此,这是在编译器中实现的一个小技巧:如果您将x
声明为final
,编译器知道它不会更改,因此没有必要保留对它的引用。这允许编译器将x
作为新成员复制到内部类的实例中。因此,x
将被复制到堆中。如果不将堆栈标记为final(当然不会编译,因为编译器会保护您避免犯此错误),请将其与对堆栈的无效引用进行比较。在我看来,没有无法解决的问题,因为内部类不能有静态成员,匿名类中使用的变量只能是final。我认为这只是语言设计师的决定
在complilation之后,内部类和顶级类并没有什么不同,只有它的所有构造函数获得额外的参数——对外部类的引用
X类{
Y类{
}
}
编译器将其转换为
class X {
}
class X$Y {
private final X x;
X$Y(X x) {
this.x = x;
}
}
没有理由说明X$Y不能有静态成员。语法也不是问题
class X {
class Y {
static int x = 1;
}
void x() {
Y.x = 2;
}
}
至于如何static final int x=1代码>不同于静态int x=1代码>-区别在于前者不需要初始化—它是一个常量,而后者需要一个隐式静态初始化块来放置将分配1到x的代码
最后一个变量作为构造函数参数访问匿名类
X类{
void x(){
最终整数x=1;
新的Runnable(){
公开募捐{
int y=x;
}
};
}
}
实际匿名类
class X$1 {
private final Integer x;
X$1(Integer x) {
this.x = x;
}
...
外部变量必须是final的唯一原因是,否则看起来我们可以从内部类代码更改它
void x() {
Integer x = 1;
new Runnable() {
public void run() {
x = 2;
}
...
但事实并非如此,因为内部类与副本一起工作
内部类背后的思想是它们属于包含类的实例。因此,如果我们忽略作用域和类似的细节,内部类的静态成员将等同于包含类的非静态成员
然而,使用内部类的实现方式,这是不可能实现的:内部类被编译成一个独立的类,如果它有静态成员,它们将在包含类的所有实例之间共享。这打破了语言试图创造的错觉。因此,完全禁止使用静态成员
此规则的唯一例外是声明为static final
并使用编译时常量(如整数或字符串文本)初始化的字段。这是允许的,因为编译时常量无论如何都会在包含类的所有实例之间共享
一旦变量超出范围,局部变量的地址就毫无用处,例如当方法返回时。如果读取或写入变量,会发生什么情况?该地址现在指向一个非法的内存位置,甚至更糟的是:指向一个完全不相关的变量
所以,若我把变量标记为final,这个变量用另一种方式处理?内存中的不同位置?关于第二个问题,是的:它被复制到内部类的实例中(不是类,而是真实对象本身!)。常量被复制到实例中。如果我们有一个对象数组,每个对象都有常数?我们使用了这么大的内存?是的,每个内存都保持不变。每个实例占用4个额外字节,这不是