Ich habe eine Methode fetchObjects(String)
, von der erwartet wird, dass sie ein Array von Contract
Geschäftsobjekten zurückgibt. Der Parameter className
sagt mir, welche Art von Geschäftsobjekten ich zurückgeben sollte (natürlich ergibt das in diesem konstruierten Fall keinen Sinn, weil ich bereits gesagt habe, dass ich 0 zurücksenden werde, aber es ist im Grunde die Situation, die ich in meinem realen Szenario habe). So bekomme ich die Menge der Einträge von irgendwo und lade die Klasse der Einträge der Sammlung (deren Typ von className
angegeben wird).Umwandlung in eine Klasse, die zur Laufzeit bestimmt wird
Jetzt muss ich das Array erstellen, um zurückzukehren, so dass ich Set
's toArray(T[])
Methode verwenden. Mit Reflektion baue ich mir ein leeres Contracts-Array. Aber, das gibt mir einen Wert von statischen Typ Object
! Als nächstes muss ich es auf den passenden Typ umwandeln, der in diesem Fall Contract[]
ist (siehe "asterisk-unterstrichen" Teil in der Liste unten).
Meine Frage ist: Gibt es eine Möglichkeit, und wie man Contract[]
werfen, wie ich in der Liste zu tun, aber die Art der Array-Elemente (Contract
) nur durch className
(oder entriesType
) Bestimmung? Mit anderen Worten, was ich tun möchte, ist im Grunde Casting wie folgt: (entriesType[]) valueWithStaticTypeObject
, wo EinträgeTyp durch die Klasse ersetzt werden, die durch den classname
Parameter, d. H. Contract
spezifiziert wird.
Ist das irgendwie von Natur aus unmöglich oder kann es irgendwie gemacht werden? Vielleicht mit Generika?
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
}
}
Danke.
Update: Mit der typsichere Methode
toArray
, genommen von
CodeIdol, ich aktualisierte meine
fetchObjects
Methode so:
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;
}
Was ich von dem Compiler-Fehler tun, tun müssen, um loszuwerden, zitiert im Kommentar? Muss ich unbedingt Set<Contract>
im Rückgabetyp meiner getEntrySet
Methode angeben, damit das funktioniert? Danke für irgendwelche Hinweise.
Wie behandeln Sie, wenn die Klasse entriesType keine Unterklasse von Contract ist? –
entriesType ist * not * notwendigerweise ein Subtyp des Vertrags. Es könnte Haustier, Freund, Hobby sein - alles, was Sie vielleicht eine Sammlung von haben. In meinem Beispielfall würde ein Kunde eine Sammlung von Verträgen haben. –