1

Let's say I have this generic class A:

public class A<E> {

    public A(E e) {}

}

How can I know if two instances of this class have the same type parameter, <E>?

I tried this:

public static void main(String[] args) {
    A<String> aString = new A<>("a");
    A<Integer> anInt = new A<>(0);
    System.out.println(aString.getClass().isInstance(anInt));
}

Which outputs true. I guess it makes sense because they have the same class. However if you try doing this:

A<String> anotherString = new A<Integer>(-1);

It will not compile because the type parameters are different. How can I know, at runtime, if two type parameters are different/equivalent? In other words, I need a method that can compare both variables and return false based on their type parameters.

Edit: Okay, it seems that it might not be possible. I'll try to explain why I wanted to do this in the first place, perhaps there is another way of achieving it. If you wish that I post a diferent question, please let me know.

I have this method:

public void someMethod(A<String> aString) {
    System.out.println("I got called!");
}

How can I ensure that the parameter given is actually an A<String> via reflection?

If I try this:

A<Integer> anInt = new A<>(0);
Method method = Main.class.getMethod("someMethod", anInt.getClass());
method.invoke(new Main(), anInt);

It will still print the "I got called!" message. How can I ensure this won't happen? (If that is possible of course).

Momo
  • 3,542
  • 4
  • 21
  • 34
  • 3
    It's unclear to me why you need this. It's all verified at compile time, by the compiler. – Sotirios Delimanolis Aug 02 '16 at 15:34
  • @SotiriosDelimanolis Sorry if this wasn't clear from the start. I need to check if two variables from the same type have the same type parameters, using reflection. – Momo Aug 02 '16 at 15:37
  • 2
    If the variables are of parameterized types, then you already know from the source code. If they aren't, you're out of luck. That information is not available at runtime. – Sotirios Delimanolis Aug 02 '16 at 15:38
  • Updated post. If there's really no way of doing this, please let me know. – Momo Aug 02 '16 at 15:49
  • For me this question is _almost_ a dupe of [Get generic type of class at runtime](http://stackoverflow.com/questions/3403909/get-generic-type-of-class-at-runtime). Any answer would be a trivial extension of an answer of that one. – Didier L Aug 02 '16 at 15:57

4 Answers4

1

Type information is just used at compile time. So at runtime the type information will be lost. You can store the class type in a variable if you want to do some comparison at runtime.

Sumit Kumar
  • 375
  • 1
  • 11
0

The whole reason of using generics is to ensure that if the code compiles then it will not cause any runtime problems. You are searching for a problem where there isn't one. The reason why your code fails at compile time is that you are explicitly providing incompatible reference types and it will never occur in runtime as long as those types have common supertype <E>

Lucas
  • 3,181
  • 4
  • 26
  • 45
0

One way that you can capture the type is by making the instances anonymous subclasses of A:

A<String> aString = new A<String>("a") {};
A<Integer> anInt = new A<Integer>(0) {};

Then you can look at e.g. aString.getClass().getGenericSuperclass() to get the generic type at runtime.

Ideone Demo

As noted by @James_D, you can enforce this by making A abstract.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • 1
    And of course, by making `A` abstract you could force all instances to be created as subclasses... – James_D Aug 02 '16 at 15:48
0

As described in other answers, the generic type information is not preserved at runtime. If you need that information, it makes sense (to me) to define a property in the class to represent it:

public class A<E> {
    private final Class<E> type ;

    private E value ;

    public A(E e, Class<E> type) {
        this.type = type ;
        this.value = value ;
    }

    public Class<E> getType() { return type ; }

    // other methods, etc...
}

Then you can do

A<Integer> aInt = new A<>(1, Integer.class);
A<String> aString = new A<>("", String.class);

and you can check

aInt.getType() == aString.getType()
James_D
  • 201,275
  • 16
  • 291
  • 322