简体   繁体   中英

Java generics — looking for a method to tell me the supertype of a generic type

the supertype of

SomeClass <Double>  

is

Someclass <T extends Numbers>

and is not

SomeClass <Numbers> 

i'm looking for a method returning the supertype of an instance of a generic class. Something like getGenericSuperclass() of the of Class ( although can't be exactly like it-- getGenericSuperclass() returns only one class while a generic can extend and be bounded by multiple as in:

Eg.:

Someclass <T extends aConcreteClass && anInterface && anotherInterface>

When i run getGenericSuperclass() on an instance of a generic class, i'm getting Object in return.

Is there such a method anywhere in Java, telling me the supertype of the generic type on which i instantiated an object on?

//===================

EDIT: lengthy comment to @jwa's answer below:

i understand the generics are type-checked at compile time. however, JVM could still bind the types in run-time, as specifically as possible using the outcome of type inference , and return at least the definition of the supertype rather than merely returning Object as the supertype. This info is clearly available in runtime. but i gather it's not doing this.

NOTE: haven't yet looked deep into type erasure.

//=================================

EDIT2:

referring to the term "bounded type parameter" in this page, i've been looking for a method to return the object's "bound class(es)",

which is Comparable in the example

public class Node<T extends Comparable<T>> {

private T data;
private Node<T> next;

public Node(T data, Node<T> next) {
    this.data = data;
    this.next = next;
}

public T getData() { return data; }
// ...
}

on the same page .

no trace of it in those pages or anywhere else-- i guess Java not doing it.

You need to take a look into "type erasure". Essentially, when your java code is compiled into bytecode the generic information is lost (or "erased"). This is why you cannot find any methods for querying the generic typing via the reflection classes.

I couldn't find a good answer regarding type erasure here on SO, but Wikiepdia seems to have a reasonable description .

It's worth noting that type erasure was chosen to give backward-compatability between java 1.5 and 1.4. Other languages have implemented this differently. For example, .NET has full support for generics in byte code - and does permit such methods as part of its reflection API.


Consider this class, which uses typed and non-typed lists:

import java.util.List;

public class CastExample <T extends Object> {
    public List<T> typedList;
    public List<?> untypedList;

    public T getFirstElement() {
        return typedList.get(0);
    }


    public T getFromUntypedArray() {
        return (T) untypedList.get(0);
    }
}

There is no difference between the way that the two methods are encoded in byte code. We can see this using javap , specifically javap -c CastExample :

/var/tmp-> javap -c CastExample

Compiled from "CastExample.java"
public class CastExample<T> {
  public java.util.List<T> typedList;

  public java.util.List<?> untypedList;

  public CastExample();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public T getFirstElement();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field typedList:Ljava/util/List;
       4: iconst_0      
       5: invokeinterface #3,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      10: areturn       

  public T getFromUntypedArray();
    Code:
       0: aload_0       
       1: getfield      #4                  // Field untypedList:Ljava/util/List;
       4: iconst_0      
       5: invokeinterface #3,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      10: areturn       
}

The exact meaning of each of these operations is not overly important. The important thing is that it is calling the exact same operations, there's no distinction between the two.

the supertype of

SomeClass <Double> is

Someclass <T extends Numbers>

The premise of the question is wrong. First of all, Someclass <T extends Numbers> is not syntactically correct as a type in Java.

And second, there is no single generic "supertype" of a type. The following is a list of some (but not all) supertypes of SomeClass <Double> :

SomeClass<? extends Number>
SomeClass<? extends Serializable>
SomeClass<? extends Comparable<Double>>
SomeClass<? extends Comparable<? extends Number>>
SomeClass<? extends Comparable<? extends Serializable>>
SomeClass<? extends Comparable<? extends Comparable<Double>>>
SomeClass<? extends Comparable<?>>
SomeClass<? extends Object>
SomeClass<?>
SomeClass<? super Double>
Object
(and if SomeClass has a superclass or interface SuperclassOfSomeClass:)
SuperclassOfSomeClass<Double>
SuperclassOfSomeClass<? extends Number>
... (all of the above for SomeClass repeated for SuperclassOfSomeClass, etc.)

Yeap, generics aren't covariant in Java, ie List< Number > is not a superclass of List< Double > . You should read some info on it, heres a link .

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