2013-07-03 25 views
6

Mam następujące klasy Generic:Dlaczego typy ogólne mają ten sam podpis?

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

Dlaczego otrzymuję następujący błąd, gdy próbuję go skompilować:

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

Wydaje mi się, że te dwa konstruktory mają tę samą sygnaturę chociaż mają różne argumenty typu ogólnego. Czemu? A jak obejść ten problem?

Aktualizacja

zrozumiałem problem teraz. Kompilator potrzebuje sposobu na rozróżnienie dwóch typów. Dodanie takiego ograniczenia byłoby w porządku dla mojego przypadku użycia. Chciałbym dodać kolejne pytanie:

Jak określić, że dwa typy A i B mogą być inne niż różne?

+2

Legacy [* typ wymazywania *] (http://en.wikipedia.org/wiki/Generics_in_Java # Problems_with_type_erasure). – Paul

+0

@ johnchen902, czy możesz dodać ten komentarz jako odpowiedź? Byłoby wspaniale –

+0

@PrasadKharkar Ponieważ to pytanie jest oczywiście duplikatem. Nie chcę być pierwszym odbierającym, zanim zobaczę, że ktoś odpowie na 10 000 lub więcej. – johnchen902

Odpowiedz

8

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

Robią to. Podpis jest

Or(Object o); 

Why?

powodu type erasure realizacji rodzajowych w Javie: odniesienia do typów generycznych są konwertowane do System.Object we wszystkich kontekstach, w których są one stosowane; typ ogólny jest znany tylko kompilatorowi.

And how to work around this problem?

Niestety, nie można łatwo obejść tego problemu w konstruktorze. Można wymienić przeciążonych konstruktorów z metod fabrycznych i dać różne nazwy, np OrWithA i 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(...); 
} 
+0

upvote dla jasnych opracowań i metod fabrycznych. –

+0

Nie działa, ponieważ 'niestatyczna klasa A nie może być odwołana ze statycznego kontekstu'. – ceving

+0

@ceving Dzięki, zapomniałem o pewnych ograniczeniach generycznych Java po kilku latach pracy z C#. Możesz uczynić swoje metody fabryczne generycznymi na jakimś innym typie (zobacz edycję), chociaż z pewnością nie jest tak elegancka, jak gdybyś użył "A" i "B". – dasblinkenlight

0

To nie jest legalne, ponieważ leki generyczne są wyrzucane w czasie wykonywania (jest to wymazywanie typu). Obie metody będą miały prototyp Or(Object).

Jedynym rozwiązaniem może być metoda OrA() i OrB() - lub całkowicie przejrzeć swoją klasę.

2

Po prostu to robią. Taka jest natura leków generycznych; dostarczają cukru syntetycznego używanego tylko w czasie kompilacji. Nie ma możliwości obejścia tego.

(Potwierdzenie komentarzy pytanie) To się nazywa typ wymazywania: patrz http://en.wikipedia.org/wiki/Type_erasure

2

To dlatego, A lub B może być cokolwiek, mogą być takie same, jak również generycznych jest tylko dla kompilacji. W czasie wykonywania są one utracone z powodu wymazania typu:

+0

Nie ma to nic wspólnego z typami uruchomieniowymi. –

1

Mówiąc inaczej: masz 2 typy A i B, i nic nie wiadomo o nich obu. Tak więc jeden zupełnie nieznany typ jest równie dobry jak inny. W jaki sposób wywoływać wywołania konstruktora?

0

To z powodu type erasure: generics są zastępowane typem obiektu w kompilacji, więc twoje metody mają ten sam podpis.Jako workaound można wybrać, aby ograniczyć typy A i B:

public class Test<A extends String, B extends Number> { 

public Test(A arg){ 

} 

public Test(B arg){ 

} 
} 
0

Te konstruktorzy będą postrzegane jako posiadające te same podpisy, ponieważ ich typy nie mogą być zidentyfikowane przy starcie.

Spróbuj określić ograniczenia co najmniej jednego z parametrów, jeśli to możliwe.

class Or<A extends Number,B> 
{ 
    Or (A a) {} 
    Or (B b) {} 
} 
0
  1. Rozważ to, co konstruktor zadzwonić?

    Or<Integer,Integer> o = new Or<>(5); 
    
  2. Twój problem rzeczywiście pochodzi z Rodzaj skasowaniem, to uczynić swój kod wygląda jak to po kompilacji:

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

Jak określić, że typy mogą być inne niż różne? Byłoby dobrze dla mojego przypadku użycia i powinno wystarczyć kompilatorowi. – ceving

+0

@ceving Nie, nie można, obawiam się. Być może jednak możesz użyć [metody fabrycznej] (http://stackoverflow.com/a/929273/2040040) – johnchen902

2

Wynika to type erasure. Eclipse kompilator daje dokładniejszy błąd: Method Or(A) has the same erasure Or(Object) as another method in type Or

Jeśli stosuje się ograniczenia do generyków kompiluje dobrze:

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

    Or(B b) {} 
}
+0

Potrzebowałbym ograniczenia: A rozciąga się tylko na klasę B. Typy powinny być różne. Jak to określić? – ceving

+0

@ceving Nie można określić czegoś tak ogólnego jak "coś oprócz B". Potrzebujesz dwóch konkretnych klas lub interfejsów, które są różne. – joe776

Powiązane problemy