英文:
Generics - Why are Class type variables not valid in static contexts?
问题
我正在从一本书中学习Java泛型。该书指出:“类类型变量在静态上下文中无效”,并通过以下示例进行了解释。
考虑一个带有类型变量的泛型类,例如Entry<K,V>。您不能在静态变量或方法中使用类型变量K和V。例如,以下代码无法正常工作:
public class Entry<K, V> {
// 编译错误 - 静态上下文中的V(无法从静态上下文中引用“Entry.this”)
private static V defaultValue;
// 编译错误 - 静态上下文中的V(无法从静态上下文中引用“Entry.this”)
public static void setDefault(V value) {
defaultValue = value;
}
}
毕竟,类型擦除意味着在被擦除的Entry类中只有一个这样的变量或方法,而不是每个K和V都有一个。
我不理解上述解释。我尝试创建了与K相同的代码,但我得到了相同的编译错误。为什么上述代码是非法的?
英文:
I am learning Java generics from a book. The book says that "Class Type Variables Are Not Valid in Static Contexts" and explains it with the following example.
Consider a generic class with type variables, such as Entry<K, V>. You cannot use the type variables K and V with static variables or methods. For example, the following does not work:
public class Entry<K, V> {
// Compiler error - V in static context ("Entry.this' cannot be referenced from a static context")
private static V defaultValue;
// Compiler error - V in static context ("Entry.this' cannot be referenced from a static context")
public static void setDefault(V value) {
defaultValue = value;
}
}
After all, type erasure means there is only one such variable or method in the erased Entry class, and not one for each K and V.
I don't understand the above explanation. I tried to create the same code for K also and I got the same compile errors. Why is the above code illegal ?
答案1
得分: 5
假设static
变量按照您描述的方式工作...
我本应该能够这样做:
Entry<String, Integer>.defaultValue = 1;
Entry<String, String>.defaultValue = "Hello";
System.out.println(Entry<String, Integer>.defaultValue); // 1
System.out.println(Entry<String, String>.defaultValue); // Hello
这正是您期望的,不是吗?
但请记住,static
变量是“每个类一个”。由于类型擦除,Entry<String, Integer>
和Entry<String, String>
被视为同一类。对于上述代码工作,1
和"Hello"
需要存储在_两个_不同的位置(两个变量)!
英文:
Let's suppose static
variables did work the way you described...
I would've been able to do:
Entry<String, Integer>.defaultValue = 1;
Entry<String, String>.defaultValue = "Hello";
System.out.println(Entry<String, Integer>.defaultValue); // 1
System.out.println(Entry<String, String>.defaultValue); // Hello
That's what you'd expect, isn't it?
But remember that static
variables are one per class. Because of type erasure, Entry<String, Integer>
and Entry<String, String>
are considered the same class. And for the above code the work, 1
and "Hello"
would need to be stored at two different places (two variables)!
答案2
得分: 3
V
将是实例化类的类型。如果两个类实例化的时候,使用不同的类型来实例化V
,那么用于访问在类级别上由所有类共享的静态字段的类型会是哪种类型?
private static V defaultValue;
现在,一个被实例化的类将V
设置为String
,另一个类将V
设置为Long
。
但静态字段可供所有类使用,因此在访问时会使用哪种类型?
这与为什么不能从静态上下文引用实例字段有关。一旦进入静态上下文,将访问哪个“实例”字段的实例?无法确定,因此这是不合法的(也没有意义)。
英文:
V
will be the type of the instantiating class. If two classes instantiate with different types for V
, which type would be used to access the static field which is shared by all classes at the class level?
private static V defaultValue;
Now one instantiated class has V
as String
and another has V
as Long
.
But static is available to all classes so which one would it be when accessed?
It's related as to why you can't reference an instance field from a static context. Once inside a static context, which "instance" of the instance field would be accessed? It can't be determined so it isn't legal (and doesn't make sense).
答案3
得分: 2
Java泛型的设计者选择使用一种称为“类型擦除”的机制来实现它。这意味着像Entry<String,Integer>
和Entry<Integer,String>
这样的泛型特化并不存在于单独的类中。类型参数被擦除。
在从Entry<String,Integer>
和Entry<Integer,String>
中擦除类型参数之后,你只剩下了Entry
类。
如果有可能像defaultValue
这样的静态变量,你会期望Entry<String,Integer>.defaultValue
是一个整数。并且你会期望Entry<Integer,String>.defaultValue
是一个字符串。但是在类型擦除之后,只剩下一个Entry
类,其中只有一个defaultValue
变量,现在必须既是整数又是字符串。这是不可能的。这就是为什么你不能有一个泛型类型的静态变量。
英文:
Designers of Java generics chose to implement it using a mechanism called "type erasure". It means that generic specializations like Entry<String,Integer>
and Entry<Integer,String>
do not exist as separate classes. The type parameters are erased.
After you erase the type parameters from Entry<String,Integer>
and Entry<Integer,String>
you're left with just the Entry
class.
If it were possible to have a static variable like defaultValue
you would expect Entry<String,Integer>.defaultValue
to be a Integer. And you would expect Entry<Integer,String>.defaultValue
to be a String. But after type erasure only one Entry
class with only one defaultValue
variable, which now has to be both Integer and String. That's impossible. That's why you can't have a static variable of the generic type.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论