简体   繁体   中英

Why does this cast to a generic type parameter work?

Having some idea of type erasure, I would think this cast would not compile or work at runtime:

public class GenericDatumReader<D> implements DatumReader<D> {
    ...
    @SuppressWarnings("unchecked")
    public D read(D reuse, Decoder in) throws IOException {
      return (D) read(reuse, actual, expected != null ? expected : actual, in);
    }

However, it works!

How does the program know at runtime what D is?

EDIT

I wrote a simple test:

  1 public class Main {                                                                                                                                                           
  2                                                                                                                                                                               
  3     public static class Something<D> {                                                                                                                                        
  4                                                                                                                                                                               
  5         private Object getObj() { return new Object(); }                                                                                                                      
  6         private String getStr() { return new String("hello"); }                                                                                                               
  7                                                                                                                                                                               
  8         public <D> D get(boolean str) {                                                                                                                                       
  9            return (D) (str ? getStr() : getObj());                                                                                                                            
 10         }                                                                                                                                                                     
 11     }                                                                                                                                                                         
 12                                                                                                                                                                               
 13     public static void main(String[] args) {                                                                                                                                  
 14         Something<String> something = new Something<>();                                                                                                                      
 15         String str = something.get(true);                                                                                                                                     
 16         String notStr = something.get(false);                                                                                                                                 
 17     }                                                                                                                                                                         
 18 } 

Without the (D) cast, this doesn't compile:

Main.java:9: error: incompatible types: bad type in conditional expression
           return (str ? getStr() : getObj());
                               ^
    String cannot be converted to D
  where D is a type-variable:
    D extends Object declared in method <D>get(boolean)
Main.java:9: error: incompatible types: bad type in conditional expression
           return (str ? getStr() : getObj());
                                          ^
    Object cannot be converted to D
  where D is a type-variable:
    D extends Object declared in method <D>get(boolean)
2 errors

With the (D) cast I get just an unchecked warning but it compiles. However, at runtime:

$ java Main
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
        at Main.main(Main.java:16)

There are two aspects here:

  1. Compile-time: This works because the only thing you know about D at compile-time is that it's an Object , so it's perfectly possible that the returned value is actually going to be a D --the compiler can't determine otherwise.
  2. Run-time: Because Java implements generics via erasure, generic types are almost entirely a compile-time concept. This method actually has no idea what D is at run-time, so the cast doesn't do anything at all. If a non-generic method assigned the result to some type that was known at runtime (ie non-generic), then it could create a cast exception if the object was not of the right type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM