Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Generics: Klassen die Interface implementieren, aber selbst nicht das Interface sind
bekomme ich ein L, das von Label abgeleitet ist oder das Label selbst. Was muss ich schreiben, dass ich nur die Klassen bekomme, die Label implementieren, aber nicht das Label selbst sind, also so nach dem Motto <L (L != Label) extends Label>? Danke!
Okay das ist doof, aber vlt kann mir anders geholfen werden.
Also ich habe folgende Struktur:
Ein interface Label:
Java:
public interface Label {
String toString();
double toDouble();
/**
* Separates numeric values from Label in String Array and returns a
* {@link Sample} with the data from the array
*
* @param data the array containing the data that has not been separated yet
* @return the {@link Sample} containing the data from the array
* @throws IllegalArgumentException if there is not at least one numeric value
* and one Label in the array
*/
<L extends Label> Sample<L> arrayToSample(String[] data) throws IllegalArgumentException;
/**
* returns a Label with value l
*
* @param l
* @return Label
*/
<L extends Label> L parseLabel(String l);
static <L extends Label> L random() throws IllegalAccessException {
throw new IllegalAccessException("May not call random() from super class");
}
}
Und verschiedene Enums die Label implementieren, da alle gleich aufgebaut sind hier mal eines als Beispiel:
Java:
public enum BinaryLabel implements Label {
POSITIVE, NEGATIVE;
@Override
public String toString() {
switch (this) {
case POSITIVE:
return "POSITIVE";
default:
return "NEGATIVE";
}
}
@Override
public double toDouble() {
switch (this) {
case NEGATIVE:
return 0d;
default:
return 1d;
}
}
static BinaryLabel random() {
return POSITIVE;
}
/**
* returns a {@link BinaryLabel} with value l
*
* @param l
* @return {@link BinaryLabel}
*/
@Override
@SuppressWarnings("unchecked")
public BinaryLabel parseLabel(String l) {
BinaryLabel label = BinaryLabel.POSITIVE;
return (l.equals(label.toString()) ? BinaryLabel.POSITIVE : BinaryLabel.NEGATIVE);
}
/**
* Separates numeric values from {@link BinaryLabel} in String Array and returns
* a {@link Sample} with the data from the array
*
* @param data the array containing the data that has not been separated yet
* @return the {@link Sample} containing the data from the array
* @throws IllegalArgumentException if there is not at least one numeric value
* and one {@link BinaryLabel} in the array
*/
@SuppressWarnings("unchecked")
@Override
public Sample<BinaryLabel> arrayToSample(String[] data) throws IllegalArgumentException {
double[] values;
BinaryLabel[] labelArr;
for (int i = 0; i < data.length; i++) {
try {
Double.parseDouble(data[i]);
} catch (Exception e) {
if (i > 1) {
values = new double[i];
for (int j = 0; j < values.length; j++)
values[j] = Double.parseDouble(data[j]);
} else
throw new IllegalArgumentException("Expected at least one numeric value.");
labelArr = new BinaryLabel[data.length - values.length];
if (labelArr.length > 0)
for (int j = 0; j < labelArr.length; j++)
labelArr[j] = parseLabel(data[j + values.length]);
else
throw new IllegalArgumentException("Expected at least one label.");
return new Sample<BinaryLabel>(labelArr, values);
}
}
throw new IllegalArgumentException("Expected at least one label.");
}
}
Und nun stehe ich vor folgendem Sachverhalt: Ich habe einen CSVReader, der wie der Name schon sagt, daten aus einer CSV-Datei einlesen soll.
[CODE lang="java" highlight="9"]public class CSVReader<L extends Label> {
...
public SampleSet<L> read() throws IOException {
SampleSet<L> data = new SampleSet<L>();
String line = "";
In dem Code habe ich die Stelle, an der es scheitert hervorgehoben. Wie mache ich es, dass immer die arrayToSample-Methode des jeweils übergebenen L aufgerufen wird?
Da sagt der mir, "Cannot instantiate type L" was ja auch Sinn macht, da man ja kein objekt von einem Enum erstellen kann. Meine Frage ist also, wie kann ich die Methode arrayToSample des jeweiligen L aufrufen?
Dein L ist kein enum sondern ein generischer Typparameter, von denen kannst du auch kein Objekt erstellen. Deine Klasse braucht irgendwo her den Typ. Zb im Konstruktor
Java:
private T t;
public CSVReader(T obj){
t = obj;
}
Du kannst das T natürlich auch bei Methoden als Parameter setzen.
So hättest du eine Instanz von T , aber ob das Sinn in deinem Code macht weiss ich nicht. Ich tue mich sehr schwer den zu verstehen
Vlt ist der Code auch schlecht geschrieben....
Ich versuche mal zu beschreiben, was der tun soll:
Ich habe den CSVReader, der liest eine CSV-Datei ein, die wie folgt aussieht:
Jede Zeile besteht aus mindestens einem numerischen Wert und mindestens einem String, der später in ein Label umgewandelt wird
Jetzt lese ich diese Datei Zeile für Zeile aus, wobei jede Zeile als String-Array ausgegeben wird. Jede Zeile soll nun zu einem Sample<L extends Label> gemacht werden, wobei dieses Sample im Konstruktor einen Vektor mit den Zahlen und ein Array mit Labels bekommt. Der Konstruktor von Vector sieht so aus: public Vector(double... data) Für diesen Vorgang, also StringArray -> Sample habe ich die Methode arrayToSample die in der Datei des jeweiligen Label-Enums zu finden ist. Da ich verschiedene Enums habe die Labels repräsentieren stellt sich mir die Frage, wie ich am Ende ein Label-Array vom richtigen Typ in mein Sample bekomme.
Der üblichste Weg dafür wäre, eine Factory für die konkrete Label-Klasse zu übergeben.
Also das arrayToSample nicht in der Label-Klasse zu haben, sondern in einer LabelFactory, von der es dann für jede Art Label eine Subklasse gibt. Eine Instanz der Factory kannst du dann dem CsvReader übergeben.