Why do generic types have the same signature?

I have the following general class:

class Or<A,B> { Or (A a) {} Or (B b) {} } 

Why am I getting the following error when trying to compile it:

  Or (A) is already defined in Or
     Or (B b)
     ^

It seems to me that the two constructors have the same signature, although they have different common type arguments. What for? And how to get around this problem?

Update

Now I understand the problem. The compiler needs a way to distinguish between two types. Adding such a restriction would be good for my use case. So I would like to add one more question:

How to indicate that two types A and B can be something else?

+6
source share
9 answers

It seems to me that the two constructors have the same signature, although they have different common type arguments.

They make. Signature

 Or(Object o); 

Why?

Due to type erasure, the implementation of generics in Java: references to generic types are converted to System.Object in all contexts where they are used; the generic type is known only to the compiler.

And how to get around this problem?

Unfortunately, you cannot easily get around this problem in the constructor. You can replace overloaded constructors with factory methods and give different names, for example OrWithA and OrWithB :

 // Hide the constructor private Or(...) { ... } // Publish factory methods public static <X> Or OrWithA(X a) { return new Or(...); } public static <X> Or OrWithB(X a) { return new Or(...); } 
+8
source

They just do. What is the nature of generics; they provide syntactic sugar used only at compile time. There is no way around this.

(Confirmation of question comments) This is called type erasure: see http://en.wikipedia.org/wiki/Type_erasure

+2
source

This is because A or B can be any, they can be the same as generics, only for compilation time. At runtime, they get lost due to type erasure

+2
source

This is due to type erasure . The Eclipse compiler gives a more detailed error: Method Or(A) has the same erasure Or(Object) as another method in type Or

If you apply generic restrictions, it compiles just fine:

  class Or <A extends String, B extends Integer>
 {
     Or (A a) {}

     Or (B b) {}
 } 
+2
source

To put it another way: you have 2 types, A and B, and nothing is known about either of them. Thus, one completely unknown type is as good as another. How should constructor calls be sent?

+1
source

This is not legal, since generics are discarded at runtime (this is type erasure). Both methods will have a prototype of Or(Object) .

The only solution is to have the OrA() and OrB() method - or fully explore your class.

0
source

This is due to the erasure : generics type being replaced with the Object type at compilation time, so your methods have the same signature. As an example, you can narrow the types A and B:

 public class Test<A extends String, B extends Number> { public Test(A arg){ } public Test(B arg){ } } 
0
source

These constructors will be considered as having the same signatures, because their types cannot be identified at runtime.

Try to specify boundaries for at least one of the type parameters, if possible.

 class Or<A extends Number,B> { Or (A a) {} Or (B b) {} } 
0
source
  • Consider this, which constructor to call?

     Or<Integer,Integer> o = new Or<>(5); 
  • Your problem really comes from erasing styles , so after compiling your code looks like this:

     class Or { Or (Object a) {} Or (Object b) {} } 
0
source

Source: https://habr.com/ru/post/948613/


All Articles