Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why calling method with generic return on a generic class is considered unsafe by javac?

Consider the following code:

public class Main {
    public static class NormalClass {
        public Class<Integer> method() {
            return Integer.class;
        }
    }

    public static class GenericClass<T> {
        public Class<Integer> method() {
            return Integer.class;
        }
    }

    public static void main(String... args) {
        NormalClass safeInstance = new NormalClass();
        Class<Integer> safeValue = safeInstance.method();

        GenericClass unsafeInstance = new GenericClass();
        Class<Integer> unsafeValue = unsafeInstance.method();
    }
}

If I compile it with:

$ javac -Xlint:unchecked Main.java 

It returns:

Main.java:16: warning: [unchecked] unchecked conversion
        Class<Integer> unsafeValue = unsafeInstance.method();
                                                          ^
  required: Class<Integer>
  found:    Class
1 warning

Please note that only the generic method is considered unsafe, even if no generic type is referenced on the return type.

Is this a javac bug? Or there is a deeper reason for this I'm not taking into account?

like image 610
Juan Lopes Avatar asked May 02 '15 16:05

Juan Lopes


People also ask

What is the purpose of generic class and generic method?

Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.

How do you declare a generic method How do you invoke a generic method?

Generic MethodsAll generic method declarations have a type parameter section delimited by angle brackets (< and >) that precedes the method's return type ( < E > in the next example). Each type parameter section contains one or more type parameters separated by commas.

How does a generic method differ from a generic type?

From the point of view of reflection, the difference between a generic type and an ordinary type is that a generic type has associated with it a set of type parameters (if it is a generic type definition) or type arguments (if it is a constructed type). A generic method differs from an ordinary method in the same way.


2 Answers

Raw types were allowed to ensure compatibility with code written before generics were introduced. Raw types work by simply ignoring all type information from all method arguments and return types, even type information that is not related to the type parameter of the class. This can lead to strange results, as you have found. But it gets even stranger than this. For example, this compiles.

public class Main {

    public static class GenericClass<T> {
        public void foo(Class<Integer> clazz) {
        }
    }

    public static void main(String... args) {
        GenericClass unsafeInstance = new GenericClass();
        unsafeInstance.foo(String.class);
    }
}
like image 99
Paul Boddington Avatar answered Sep 16 '22 12:09

Paul Boddington


The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

Java Language Specification

like image 34
user2418306 Avatar answered Sep 18 '22 12:09

user2418306