Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics. Why does it compile?

Tags:

java

generics

abstract class Type<K extends Number> {
    abstract <K> void use1(Type<K> k);           // Compiler error (Type parameter K is not within its bounds)
    abstract <K> void use2(Type<? extends K> k); // fine
    abstract <K> void use3(Type<? super K> k);   // fine
}

The method generic type K shadows the class generic type K, so <K> doesn't match <K extends Number> in use1().The compiler doesn't know anything usefull about new generic type <K> in use2() and use3() but it is still legal to compile . Why <? extends K> (or <? super K>) match <K extends Number>?

like image 577
Groxel Avatar asked Sep 26 '11 13:09

Groxel


1 Answers

The problem you have is that There are two K types. It may be clearer if you rename one.

abstract class Type<N extends Number> {
    abstract <K extends Number> void use1(Type<K> k); // fine
    abstract <K> void use2(Type<? extends K> k); // fine
    abstract <K> void use3(Type<? super K> k);   // fine
}

There are cases where you have to provide duplicate information the compiler can infer, and other places where you don't. In Java 7 it has added a <> diamond notation to tell the compiler to infer types it didn't previously.


To illustrate what I mean. Here is different ways to create an instance of a generic class. Some requires the type be given twice, others only once. The compiler can infer the type.

In general, Java doesn't infer types when it might do in most other languages.

class Type<N extends Number> {
    private final Class<N> nClass;

    Type(Class<N> nClass) {
        this.nClass = nClass;
    }

    static <N extends Number> Type<N> create(Class<N> nClass) {
        return new Type<N>(nClass);
    }

    static void main(String... args) {
      // N type is required.
      Type<Integer> t1 = new Type<Integer>(Integer.class);

      // N type inferred in Java 7.
      Type<Integer> t2 = new Type<>(Integer.class); 

      // type is optional
      Type<Integer> t3 = Type.<Integer>create(Integer.class); 

      // type is inferred
      Type<Integer> t4 = create(Integer.class);
    }
like image 69
Peter Lawrey Avatar answered Oct 01 '22 11:10

Peter Lawrey