函数对象内部 类 中的 variables/objects 会怎样?
What happens to variables/objects in inner classes of function objects?
我有一个函数 multi2
,其中 returns 内部 class Inner
作为 Object
。
a
发生了什么 - 它保存在哪里,我如何访问它?
public class C {
private static Object multi2(final int a) {
class Inner {
public int hashCode() {
return 2*a;
}
}
return new Inner(); // What happens to a?
// Who allocates a?
// Can I Access a?
}
public static void main(String[] args) {
Object o = multi2(6);
System.out.println("o.hashCode() = " + o.hashCode());
o = multi2(4);
System.out.println("o.hashCode() = " + o.hashCode());
}
}
内部是所谓的本地class。 a
是传递给方法 multi2
的参数,可在该范围内访问。在该方法之外,您无法访问 a
.
在实现级别发生的事情是 a
的值的副本保存在 合成实例变量 中,该变量在 [= 的编译版本中声明11=] class。
a
的值通过一个额外的参数传递给编译后的 Inner
构造函数。
C.Inner.hashCode
方法使用合成变量的值。在Inner.hashCode
的源代码中访问a
,转化为在编译代码中访问相应的合成变量。
外部作用域中的变量必须是final
1。 Inner
class中的合成变量必须是final
2。这维持了 Inner
class 的(可能)多个实例看到相同 a
变量的错觉。 (它们不是,但由于无法更改变量,因此内部 class 的代码无法区分。)
如果您使用 javap
查看编译示例的字节码,您将看到用于在外部和内部 classes 中实现它的机制。
1 - 或者从 Java 8 开始有效。
2 - 如果 a
可以通过 Inner
方法进行变异,那么两个具有相同外部 class 的 Inner
实例需要共享一个可变变量,其生命周期(现在)长于 multi2
调用的堆栈帧。这需要以某种方式将 a
从堆栈变量转换为堆上的东西。这将是昂贵和复杂的。
由于 "a" 是局部参数,您可以使用不同的方法来读取 "a" 值:
public class C {
public static Object multi2(final int a) {
return new Inner(a);
}
public static void main(String[] args) {
Object o = multi2(6);
System.out.println("o.hashCode() = " + o.hashCode());
System.out.println("o.getA() = " + ((Inner) o).getA());
o = multi2(4);
System.out.println("o.hashCode() = " + o.hashCode());
System.out.println("o.getA() = " + ((Inner) o).getA());
}
}
class Inner{
public int valueA;
public Inner(int a)
{
valueA = a;
}
public int getA() {
return valueA;
}
public int hashCode() {
return 2*valueA;
}
}
我想知道到底发生了什么,所以我编译了你的代码并查看了字节码输出。
基本上,编译器会向您的 class 'Inner' 添加一个构造函数。它还向采用 'a' 的构造函数添加了一个参数。如果您的 multi2() 方法不是静态的,那么可能还会有一个参数需要 'this',其中 'this' 是 multi2() 正在执行的 'C' 的实例。但是由于我们处于静态上下文中,因此没有 'this'.
编译器将一个私有最终字段添加到您的 class 'Inner' 并使用通过构造函数传递的值设置该私有字段。编译器还转换
new Inner()
进入
new Inner(a)
Hashcode 然后访问包含 a 值的私有字段。
如果'a'是一个对象而不是一个基本类型,那么它也是一样的,但是会传递一个引用而不是一个实际的数值。
你如何访问这个变量?好吧,你用反射访问它,但是有很多问题:
1) 你不知道编译器做出的字段名称,所以只能通过查看字节码来获取名称。不要相信反编译器,因为它们可能会更改名称。你得自己看看字节码才能知道。
2) 编译器可能将该字段标记为最终字段,这意味着即使您可以获得反射来为您访问该字段,您也无法更新它。
3) 字段名完全由编译器决定。字段名称可能会在构建之间发生变化,具体取决于编译器及其心情。
您已经在函数内部定义了 class Inner
,因此 class 的范围将是
限制在方法中。并且您的 函数是静态的 因此只要加载 class 定义它就会存在。您已经覆盖了 InnerClass 中的 hashCode 函数,因此每次调用 multi2(param)
时,您都在为实例创建 hashCode InnerClass 并返回 InnerClass.
的实例
所以关于大家的问题,如有不妥请指正
a 会怎样?
a
在您的静态方法的范围内,因此只要加载 class 定义,它就会存在。
谁分配一个?
a
的范围被限制在静态方法内部,静态方法不需要实例来访问它,但至于静态 method/variable 分配,我认为这取决于 JVM。
我可以访问吗?
不,您不能从静态方法外部访问 a
,它在您的静态方法中受到限制。
我有一个函数 multi2
,其中 returns 内部 class Inner
作为 Object
。
a
发生了什么 - 它保存在哪里,我如何访问它?
public class C {
private static Object multi2(final int a) {
class Inner {
public int hashCode() {
return 2*a;
}
}
return new Inner(); // What happens to a?
// Who allocates a?
// Can I Access a?
}
public static void main(String[] args) {
Object o = multi2(6);
System.out.println("o.hashCode() = " + o.hashCode());
o = multi2(4);
System.out.println("o.hashCode() = " + o.hashCode());
}
}
内部是所谓的本地class。 a
是传递给方法 multi2
的参数,可在该范围内访问。在该方法之外,您无法访问 a
.
在实现级别发生的事情是 a
的值的副本保存在 合成实例变量 中,该变量在 [= 的编译版本中声明11=] class。
a
的值通过一个额外的参数传递给编译后的 Inner
构造函数。
C.Inner.hashCode
方法使用合成变量的值。在Inner.hashCode
的源代码中访问a
,转化为在编译代码中访问相应的合成变量。
外部作用域中的变量必须是final
1。 Inner
class中的合成变量必须是final
2。这维持了 Inner
class 的(可能)多个实例看到相同 a
变量的错觉。 (它们不是,但由于无法更改变量,因此内部 class 的代码无法区分。)
如果您使用 javap
查看编译示例的字节码,您将看到用于在外部和内部 classes 中实现它的机制。
1 - 或者从 Java 8 开始有效。
2 - 如果 a
可以通过 Inner
方法进行变异,那么两个具有相同外部 class 的 Inner
实例需要共享一个可变变量,其生命周期(现在)长于 multi2
调用的堆栈帧。这需要以某种方式将 a
从堆栈变量转换为堆上的东西。这将是昂贵和复杂的。
由于 "a" 是局部参数,您可以使用不同的方法来读取 "a" 值:
public class C {
public static Object multi2(final int a) {
return new Inner(a);
}
public static void main(String[] args) {
Object o = multi2(6);
System.out.println("o.hashCode() = " + o.hashCode());
System.out.println("o.getA() = " + ((Inner) o).getA());
o = multi2(4);
System.out.println("o.hashCode() = " + o.hashCode());
System.out.println("o.getA() = " + ((Inner) o).getA());
}
}
class Inner{
public int valueA;
public Inner(int a)
{
valueA = a;
}
public int getA() {
return valueA;
}
public int hashCode() {
return 2*valueA;
}
}
我想知道到底发生了什么,所以我编译了你的代码并查看了字节码输出。
基本上,编译器会向您的 class 'Inner' 添加一个构造函数。它还向采用 'a' 的构造函数添加了一个参数。如果您的 multi2() 方法不是静态的,那么可能还会有一个参数需要 'this',其中 'this' 是 multi2() 正在执行的 'C' 的实例。但是由于我们处于静态上下文中,因此没有 'this'.
编译器将一个私有最终字段添加到您的 class 'Inner' 并使用通过构造函数传递的值设置该私有字段。编译器还转换
new Inner()
进入
new Inner(a)
Hashcode 然后访问包含 a 值的私有字段。
如果'a'是一个对象而不是一个基本类型,那么它也是一样的,但是会传递一个引用而不是一个实际的数值。
你如何访问这个变量?好吧,你用反射访问它,但是有很多问题:
1) 你不知道编译器做出的字段名称,所以只能通过查看字节码来获取名称。不要相信反编译器,因为它们可能会更改名称。你得自己看看字节码才能知道。
2) 编译器可能将该字段标记为最终字段,这意味着即使您可以获得反射来为您访问该字段,您也无法更新它。
3) 字段名完全由编译器决定。字段名称可能会在构建之间发生变化,具体取决于编译器及其心情。
您已经在函数内部定义了 class Inner
,因此 class 的范围将是
限制在方法中。并且您的 函数是静态的 因此只要加载 class 定义它就会存在。您已经覆盖了 InnerClass 中的 hashCode 函数,因此每次调用 multi2(param)
时,您都在为实例创建 hashCode InnerClass 并返回 InnerClass.
所以关于大家的问题,如有不妥请指正
a 会怎样?
a
在您的静态方法的范围内,因此只要加载 class 定义,它就会存在。
谁分配一个?
a
的范围被限制在静态方法内部,静态方法不需要实例来访问它,但至于静态 method/variable 分配,我认为这取决于 JVM。
我可以访问吗?
不,您不能从静态方法外部访问 a
,它在您的静态方法中受到限制。