Mam metodę fetchObjects(String)
, która ma zwrócić tablicę obiektów biznesowych Contract
. Parametr className
mówi mi, jakie obiekty biznesowe powinienem zwrócić (oczywiście nie ma to sensu w tym skonstruowanym przypadku, ponieważ już powiedziałem, że zwrócę Contract
s, ale to w zasadzie sytuacja, którą mam w moim prawdziwym scenariuszu). Dostaję więc zbiór wpisów skądś i ładuję klasę pozycji kolekcji (której typ jest określony przez className
).Odlewanie do klasy, która jest określana w czasie wykonywania
Teraz potrzebuję skonstruować tablicę, aby wrócić, więc używam metody Set
's toArray(T[])
. Używając refleksji, zbudowałem sobie pustą tablicę kontraktów. Ale, to daje mi wartość statycznego typu Object
! Następnie muszę rzucić go do odpowiedniego typu, który w tym przypadku jest Contract[]
(patrz "gwiazdka podkreślona" część w wykazie poniżej).
Moje pytanie brzmi: Czy jest jakiś sposób, i jak oddać do Contract[]
jak ja w szczegóły, ale ustalaniu rodzaju elementów Array (Contract
) tylko przez className
(lub entriesType
)? Innymi słowy, to, co chciałbym zrobić, to zasadniczo rzutowanie w następujący sposób: (entriesType[]) valueWithStaticTypeObject
, gdzie entriesType należy zastąpić klasą określoną parametrem classname
, tj. Contract
.
Czy jest to w jakiś sposób niemożliwe lub może być zrobione w jakiś sposób? Może używając generycznych?
package xx.testcode;
import java.util.HashSet;
import java.util.Set;
class TypedArrayReflection {
public static void main(String[] args) {
try {
Contract[] contracts = fetchObjects("Contract");
System.out.println(contracts.length);
} catch (ClassNotFoundException e) {}
}
static Contract[] fetchObjects(String className) throws ClassNotFoundException {
Class<?> entriesType = Class.forName("xx.testcode."+className);
Set<?> entries = ObjectManager.getEntrySet(className);
return entries.toArray(
(Contract[]) java.lang.reflect.Array.newInstance(
/********/ entriesType, entries.size()));
}
}
class Contract { } // business object
class ObjectManager {
static Set<?> getEntrySet(String className) {
if (className.equals("Contract"))
return new HashSet<Contract>();
return null; // Error
}
}
Dzięki.
Aktualizacja: Stosując metodę typu bezpieczny
toArray
, wykonane z
CodeIdol, zaktualizowałem moją
fetchObjects
metoda tak:
static Contract[] fetchObjects(String className) throws ClassNotFoundException {
Class<?> entriesType = Class.forName("xx.testcode."+className);
Set<?> entries = ObjectManager.getEntrySet(className);
return toArray(entries, entriesType); // compile error
// -> "method not applicable for (Set<capture#3-of ?>, Class<capture#4-of ?>)"
}
public static <T> T[] toArray(Collection<T> c, Class<T> k) {
T[] a = (T[]) java.lang.reflect.Array.newInstance(k, c.size());
int i = 0;
for (T x : c)
a[i++] = x;
return a;
}
Co muszę zrobić, aby pozbyć się tego błędu kompilatora cytowanego w komentarzu? Czy muszę bezwzględnie określać Set<Contract>
w typie zwrotu mojej metody getEntrySet
, aby mogło to działać? Dzięki za wszelkie wskazówki.
Jak postępować, gdy klasa entriesType nie jest podklasą kontraktu? –
entries entries * nie * koniecznie podtyp kontraktu. Może to być Pet, Friend, Hobby - wszystko, co możesz mieć w kolekcji. W moim przykładowym przypadku klient będzie miał kolekcję umów. –