2017-02-06 99 views
5

Potrzebuję napisać metodę java, która pobiera klasę (nie obiekt), a następnie tworzy ArrayList z tą klasą jako elementem każdego elementu tablicy. Przykład pseudokodu:Podaj typ klasy jako parametr do użycia w ArrayList?

public void insertData(String className, String fileName) { 
     ArrayList<className> newList = new ArrayList<className>(); 
} 

Jak mogę to zrobić w Javie?

+4

Czy to ma być 'String className'? Byłoby łatwiej, gdybyś mógł przekazać rzeczywisty obiekt 'Class', np.' InsertData (ExampleClass.class, fileName) '. – nickb

+0

Nie wiem, którą klasę przechodzę. – Greymarch

Odpowiedz

4

Można użyć Generic methods

public <T> void insertData(Class<T> clazz, String fileName) { 
    List<T> newList = new ArrayList<>(); 
} 

ale czy należy skorzystać z tej umowy insertData(String className, String fileName), nie można użyć rodzajowych, ponieważ typ elementu listy nie może być rozwiązany w czasie kompilacji przez Java.

W tym przypadku można nie wykorzystać rodzajowych w ogóle i wykorzystać odbicie sprawdzić typ przed umieszczeniem go na liście:

public void insertData(String className, String fileName) { 
    List newList = new ArrayList(); 

    Class clazz; 
    try { 
     clazz = Class.forName(className); 
    } catch (ClassNotFoundException e) { 
     throw new RuntimeException(e); // provide proper handling of ClassNotFoundException 
    } 

    Object a1 = getSomeObjectFromSomewhere(); 

    if (clazz.isInstance(a1)) { 
     newList.add(a1); 
    } 
    // some additional code 
} 

ale bez informacji o klasie jesteś w stanie używać tylko Object bo ciebie nie mogę rzucić obiektu do UnknownClass w twoim kodzie.

+0

Należy zauważyć, że zmienia to sygnaturę metody OP, która może być pożądana lub nie. – nickb

+0

@nickb agree, updated answer –

+0

@VladBochenin Czy możesz podać przykład implementacji powyższego kodu? – Greymarch

2

Vlad Bochenin daje dobrą drogę, ale nie ma sensu dostarczać generycznego T, który pochodzi z niczego w twojej metodzie.
Wprowadza ograniczenia zerowe w kodzie insertData(), które manipulują listą.
Zostaniesz zmuszony do rzucenia kodu i pokonania celu Generics.

Przypuszczam, że chcesz manipulować niektórymi wystąpieniami znanych klas w insertData().
A jeśli użyjesz generycznych w twoim przypadku, miałoby to więcej znaczenia, jeśli masz podtypy klas do manipulowania.

W ten sposób można uzyskać metodę akceptującą typ podstawowy i jego podklasy.

public static <T extends YourClass> void insertData(Class<T> clazz, String fileName) { 
    List<T> newList = new ArrayList<>(); 
    T t = newList.get(0); 
    // here I can manipulate something that derives from YourClass 
} 
+0

@ Dvvvoter Czy możesz wyjaśnić? Jak zwykle przypuszczam, że nie. – davidxxx

+0

Nie jestem downvoter, ale twoje stwierdzenie, że "nie ma sensu dostarczać generycznego T, który wywodzi się z niczego w twojej metodzie" jest złe.Oczywiście, nie możesz wywoływać żadnych metod z elementów na liście z poziomu metody, chyba że użyjesz refleksji, ale możesz zapełnić 'List ' (być może z wartościami deserialized z pliku o podanej nazwie). Zwykle jednak chciałbyś zwrócić tę listę. W miejscu połączenia znasz 'T' w czasie kompilacji i możesz wywoływać dowolne metody. – Hulk

+1

@Hulk W pytaniu nie zwraca listy. Jeśli tak, to rzeczywiście ma to sens. "możesz wypełnić listę (być może z wartościami deserialized z pliku o podanej nazwie)." Wciąż pokonuje cel generyków, ponieważ umieszczasz instancje czegoś pobranego z pliku na liście 'Object'. T wywodzi się z niczego, a więc tylko z "obiektu". Jaka jest zaleta Generics tutaj? W takim przypadku możemy uprościć API, aby usunąć parametr klasy i dodać '@ SuppressWarnings' w metodzie insertData(), ponieważ w końcu Generics nie zapewnia tutaj bezpieczeństwa. – davidxxx

0

Domyślam się, że to, co naprawdę chcesz zrobić, to wrócić wygenerowany List. Jest to co to może wyglądać następująco:

public <T> List<T> loadData(Class<T> clazz, String fileName) { 
    List<T> newList = new ArrayList<>(); 

    //...populate list somehow (e.g. with values deserialized from the file named "filename") 

    return newList; 
} 

W ten sposób może on być wykorzystany:

List<String> names = loadData(String.class, "someFileContainingNameStrings"); 
List<Double> temperatures = loadData(Double.class, "someFileContainingTemperatureData");