2017-05-10 9 views
18
public class Program { 

    private static <Program> void foo(Program x){ 
     System.out.println(x+"-->1"); 
    } 

    private static void foo(final int i){ 
     System.out.println(i+"-->2"); 
    } 

    public static void main(String[] args) { 
     Integer i = 10; 
     foo(i); 
    } 

} 

a wyjście jest:Jak generics w java działa dla następującego programu?

10-->1 

nie byłem w stanie znaleźć żadnych istotnych dyskusji na ten temat. Jednak odpowiedź na innym temacie mylić mnie trochę: - Return Type of Java Generic Methods

Według nich ogólny <Program> nie ma nic wspólnego z rodzaju powrót, ale w moim przypadku, jeśli zmienię trochę do tego programu, jak poniżej to wyjście jest inny.

public class Program { 

    private static <Integer> void foo(Program x){ 
     System.out.println(x+"-->1"); 
    } 

    private static void foo(final int i){ 
     System.out.println(i+"-->2"); 
    } 

    public static void main(String[] args) { 
     Integer i = 10; 
     foo(i); 
    } 

} 

wyjściowa:

10-->2 

Używam JDK1.7

+0

W twoim drugim przykładzie, tylko druga wersja 'foo()' ma podpis, który można dopasować do tego, co wywołujesz w 'main()'. W pierwszym przykładzie musi istnieć reguła poprzedzająca, która dopasowuje wywołanie "Integer" do funkcji ogólnej przed rozpakowaniem i rozważa alternatywę. –

+10

Definiujesz nowy rodzajowy parametr 'Program' w tym wierszu:' private static void foo (Program x) {'. Ten parametr typu nie ma nic wspólnego z twoją klasą o nazwie 'Program'.Kiedy zmienisz nazwę parametru typu na "Integer", parametr 'Program x' nagle ma typ twojej aktualnej klasy' Program'. Lekcja: nie nadaj nazw parametrom typu istniejącym klasom faktycznym. – marstran

+2

Twój kod będzie łatwiejszy do zrozumienia, jeśli nazwy parametrów generycznych będą zgodne z konwencją literowania jedną wielką literą. Bez względu na to, jest beznadziejnie mylące, gdy nazwiesz je tak samo jak konkretny typ, a tym bardziej taki, który znajduje się w zakresie. Oddzielić nazwy parametrów generycznych od nazw typów! –

Odpowiedz

14

W pierwszym przykładzie, w rzeczywistości nie podajesz argumentu typu Program, jest to rodzajowy. Ten parametr typu nie ma nic wspólnego z klasą o nazwie Program. Dostaniesz sam rezultat poprzez literówkę tak:

public class Program { 

    private static <Programmmm> void foo(Programmmm x){ 
     System.out.println(x+"-->1"); 
    } 

    private static void foo(final int i){ 
     System.out.println(i+"-->2"); 
    } 

    public static void main(String[] args) { 
     Integer i = 10; 
     foo(i); 
    } 

} 

Jednak w drugim przykładzie parametr jest dosłownie typu Program i tak nie pasuje, gdy nazywa się foo(10); i masz wynikiem sekundę metoda.

13

w pierwszym przypadku, Program jest nazwą parametru rodzajowego stosowanych do metody. To może być dowolna nazwa. Ważną rzeczą jest to, że argument metody jest obiektem, więc gdy wywołasz twoją metodę za pomocą argumentu Integer, używa wersji, która przyjmuje Object.

W drugim przypadku parametr ogólny ma nazwę Integer (nie należy tego robić), ale argumentem, który metoda przyjmuje, jest Program. Tak więc, wywołując go z liczbą całkowitą, nie ma poprawnej Object lub wersji integer, więc rozpakowuje wartość.

Pod względem method overloading, który opisuje kolejność, w której zostało usunięte przeładowanie. Dzięki temu dowiesz się, dlaczego w pierwszej wersji użyto metody Object zamiast metody int.

Drugą kwestią jest to, że nazwałeś swoje podstawowe parametry rodzajami betonu, co jest mylące. Łatwiej jest zobaczyć, czy tego nie robisz.

private static <T> void foo(T x){ 
    System.out.println(x+"-->1"); 
} 

Teraz jest jaśniej, T jest sparametryzowanym argumentem. W swojej drugiej wersji,

private static <T> void foo(Program x){ 
    System.out.println(x+"-->1"); 
} 

Teraz jest jasne, twój argumentem ma być przedmiotem programu, a nie tylko dowolny obiekt.

+0

Punkty premiowe, jeśli znajdziesz coś podobnego do odpowiedniej części JLS omawiającej to^^ –

+0

Nie wywołuj też parametru typu 'Program', ponieważ jest to nazwa jego głównej klasy. Kiedy zmienia nazwę parametru na "Integer", typ parametru nagle zmienia się na aktualną klasę "Program". – marstran