Java Generics with Class

后端 未结 6 2159
Happy的楠姐
Happy的楠姐 2020-12-31 16:03

So I have a map:

Map format = new HashMap();

And I would add elements to it like this:



        
相关标签:
6条回答
  • 2020-12-31 16:23

    It is because your HashMap returns a

    Class 
    

    object, but the verify function expects a

    Class<T> 
    

    object.

    0 讨论(0)
  • 2020-12-31 16:29

    The reason you get this error is that in the first case the compiler sees that you pass it a Class object and is able to bind T to Integer at compile time, but in the second case the compiler only sees that you are passing it a Class object.

    At the end of the day, you will not be able to do

    Integer i = verifyType("100",format.get("Vendor Number"));
    

    in a type-safe way, since the compiler can't know that you will get an Integer (what if someone does a format.put("Vendor Number", X.class) just before that call?)

    0 讨论(0)
  • 2020-12-31 16:32

    You have to genericize your references to Class. For example:

    Class<Integer> type = Integer.class
    Integer i = verifyType("100",type);
    

    would work fine.

    As would:

    Map<String, Class<?>> format = new HashMap<String, Class<?>>();
    

    However, this will never work:

    Integer i = verifyType("100",format.get("Vendor Number"));
    

    Because format is not defined as:

    Map<String, Class<Integer>>
    

    If it was, the casting would work, but the design would be pointless.

    The closest you can get is:

    Integer i = verifyType("100",(Class<Integer>) format.get("Vendor Number"));
    

    However, you will get a compiler warning doing it, as you must - it is an inherently unsafe cast. The compiler is taking your word for it that that format.get statement will return an integer. If you are sure of that, then that is what unsafe casts are for. If you want to get rid of the compiler warning, you could do this:

        Class<?> type = format.get("Vendor Number");
        Integer i = null;
        if (type == Integer.class) {
            i = verifyType("100", Integer.class);
        } else {
            //What do you want to do?
        }
    
    0 讨论(0)
  • 2020-12-31 16:37

    Change:

    Class type = Integer.class
    Integer i = verifyType("100",type);
    

    to

    Class<Integer> type = Integer.class
    Integer i = verifyType("100",type);
    

    By only declaring the type as 'Class', you're losing the generic parameter and the verifyType() method can't infer the class, thus the unchecked warning.

    This problem:

    Map<String, Class> format = new HashMap<String, Class>();
    format.put("Vendor Number", Integer.class);
    format.put("Vendor Dispatch", Date.class);
    Integer i = verifyType("100",format.get("Vendor Number"));
    

    can't really be solved due to type erasure. The compiler can't infer the type based on a generic parameter that is gone by runtime. This is because Java generics are little more than smoke and mirrors for casting.

    0 讨论(0)
  • 2020-12-31 16:45

    Class Class is a generic class itself. If you try

    Class<Integer> type = Integer.class;
    Integer i = verifyType("100", type);
    

    it should work better. Generification of the input parameter convinces the compiler that you know what you're doing, enough to let your code compile without warning.

    You can also convince the compiler by suppressing the warning using

    @SuppressWarning("unchecked")
    

    before the specific line of code or method.

    0 讨论(0)
  • 2020-12-31 16:49

    It is strange for me, that your compiler on line

    Integer i = verifyType("100",format.get("Vendor Number"));
    

    complains about unchecked invocation but doesn't show an error like "Type mismatch: cannot convert from Object to Integer".

    This line just doesn't make sense to me. What do you expect verifyType to return if it receives Date.class as a second parameter? Also an Integer (then the return type of verifyType is invalid)? Or a Date? If you expect a Date, how is compiler expected to know that

    format.get("Vendor Number");
    

    returns Integer.class, but

    format.get("Vendor Dispatch");
    

    returns Date.class

    Invocation of

    Integer i = verifyType("100",format.get("Vendor Dispatch"));
    

    must fail, as Date is not an Integer. So, in my opinion (and in opinion of my compiler) compilation of

    Integer i = verifyType("100",format.get("Vendor Number"));
    

    must fail.

    0 讨论(0)
提交回复
热议问题