0

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. 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 ?

Java Impatient
  • 159
  • 1
  • 2
  • 13
  • 2
    An interesting note. You can pass the method `V` by adding it to the head. `public static void setDefault(V value) { ... }`. Can't do it with the class variable, but the method will take a generic reference then. – Tim Hunter Apr 03 '20 at 18:29
  • This question is not a duplicate of the question which the moderator has mentioned. – Java Impatient Apr 03 '20 at 18:58
  • @JavaImpatient If you can explain why not, feel free to [edit] your question. If you can convince me, I can reopen the question for you. – Sweeper Apr 03 '20 at 19:00

3 Answers3

5

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)!

Sweeper
  • 213,210
  • 22
  • 193
  • 313
3

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).

WJS
  • 36,363
  • 4
  • 24
  • 39
2

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.

Joni
  • 108,737
  • 14
  • 143
  • 193