2017-07-19 81 views
5

Próbuję dowiedzieć się o używaniu typów ogólnych i zauważyłem coś dziwnego, kiedy eksperymentowałem z pewnymi liniami kodu.Java - typy ogólne i kolekcje

Pierwszy kawałek kodu jest wewnątrz klasy o nazwie "A":

public void func(int k, List list) { 
    list.add(9); 
    list.add(true); 
    list.add("a string"); 
    } 

Drugi fragment kodu jest w innej klasie, wewnątrz funkcji main:

List<Integer> arr = new ArrayList<Integer>(); 
     arr.add(14); 
     System.out.println(arr.toString()); 
     a.func(8, arr); 
     System.out.println(arr.toString()); 

uruchamiając wyniki kodu w tym linie drukowane:

[14]

[14, 9, prawda, ciąg]

To dało mi całkiem zdezorientowany ponieważ arr jest ArrayList typu Integer, w jaki sposób może zawierać obiekty typu boolean i String? Czy istnieje transformacja listy w funkcji func na typ surowy (co oznacza, że ​​staje się ona typem generycznym Object)? A jeśli tak, to jak to jest możliwe, ponieważ nie możesz tego zrobić na przykład: List<Integer> arr = new ArrayList<Object>();?

Chciałbym wyjaśnienia na ten temat, może pomoże mi to lepiej zrozumieć ten przedmiot rodzajów ogólnych. Dzięki!

+0

Należy przeczytać o [RAW] (https://docs.oracle.com/javase/tutorial/ typy java/generics/rawTypes.html), a także [heap pollution] (https://docs.oracle.com/javase/tutorial/java/generics/nonReifiableVarargsType.html#heap_pollution). – Flown

Odpowiedz

1

Java nie pozwala na tworzenie ogólnych tablic. Klasy kolekcji Java są głównie implementowane przy użyciu macierzy Object. Klasa ArrayList może wyglądać następująco

public class ArrayList<T> implements List<T>, Serializable { 
    private transient Object[] data; 
    // more content... 
} 

Podczas tworzenia nowej instancji ArrayList nowy Object[] tablica jest tworzony, które mogą posiadać obiekty dowolnego typu. Bezpieczeństwo typów osiąga się jedynie przy użyciu ogólnego parametru typu.

Ponieważ lista nie zawierała żadnego parametru typu, korzysta z rawtype i wszystko można dodać do listy. Dlatego zawsze upewnij się, że wyprowadzasz argumenty z szablonu, aby zachować typy.

public void func(int k, List<Integer> list) { 
    list.add(9);  // works 
    list.add(true); // compile error 
    list.add("a string"); // compile error 
} 

Nigdy nie należy używać rawtypes. W zależności od ustawień kompilatora ostrzeżenia zostaną pominięte. Lepiej używać symboli (związanych/niezwiązanych).

1

Powodem takiego rodzaju produkcji jest to, że są przechodzącą List jako parametr do func(int k , List list) . I listy w func metody jest nie- rodzajowe, które pozwala na dodawanie znaków, jak również tak, że dostajesz takiego wyjścia.

List<Integer> arr = new ArrayList<Integer>(); 
       arr.add(14); 
       System.out.println(arr.toString()); 
       a.func(8, arr); // here you are passing a list 
       System.out.println(arr.toString()); 

    public void func(List list) { // here List in non-generic 
     list.add(9); 
     list.add(true); 
     list.add("a string"); 
     } 
1

Celem całego kodu generycznego w Javie jest zapewnienie bezpieczeństwa typu przed przystąpieniem do kompilacji kodu. Skompilowany kod nie ma typu, dlatego nie napotykamy żadnego problemu w naszym kodzie, ponieważ w rzeczywistości metoda func() nazywa się, List arr nie ma żadnego typu.

Kiedy dzwonimy pod numer System.out.println(arr.toString()), właśnie drukujemy obiekt.To będzie dobrze na każdym typie (tj. Int, boolean, String itp.). Dlatego nie spotykamy się z żadnym wyjątkiem.

Jednak tylko próbować przypisać wartość z tej listy, a my java.lang.ClassCastException

... 
func(8, arr); 
System.out.println(arr.toString()); 
int a = arr.get(2);