Gemeinsame Oberklasse zweier Generics

CSHW89

Bekanntes Mitglied
Hallo zusammen,

ich habe mal wieder eine etwas speziellere Frage zu Generics. Folgender Code ist nur ein minimales Beispiel, um hoffentlich einfach zeigen zu können, was ich will:
Java:
public class GenericTest {
  
  public static void main(String[] args) {
    new MyList<A>().concat(new MyList<A>()).getFirst().aMethod();
    new MyList<B>().concat(new MyList<B>()).getFirst().bMethod();
    new MyList<A>().concat(new MyList<B>()).getFirst().superMethod();
    new MyList<A>().concat(new MyList<Superclass>()).getFirst().superMethod();
    new MyList<Superclass>().concat(new MyList<B>()).getFirst().superMethod();
  }
  
  
  static class Superclass {
    public void superMethod() {
    }
  }
  static class A extends Superclass {
    public void aMethod() {
    }
  }
  static class B extends Superclass {
    public void bMethod() {
    }
  }
  
  
  static class MyList<E> {
  
    public E getFirst() {
      // some stuff
      return null;
    }
    
    public <S,F> MyList<S> concat(MyList<F> other) {
      // some stuff
      return null;
    }
  
  }
  
}
Es geht mir um die Methode concat in der Klasse MyList. Diese Methode soll die "this"-Liste mit einer übergebenen Liste verknüpfen (wie gesagt, ist nur ein konstruiertes Beispiel). Nun soll der Generic-Typ der zurückgegebenen Liste die Superklasse der beiden Listentypen sein. Also "E extends S" sowie "F extends S" sollen gelten. Meine Idee war folgende:
Java:
public <S super E,F extends S> MyList<S> concat(MyList<F> other)
Dies geht aber nicht, da ein 'super'-bound nicht zulässig ist. Hat jemand eine Idee zu diesem Problem?

lg Kevin
 
So etwas?
Java:
public <S,F> MyList<? extends Superclass> concat(MyList<F> other) {
   // some stuff
   return null;
}

Damit solltest du eine Liste zurückgeben können welche Objekte enthalten kann von allen Typen die von "Superclass" ableiten
 
Ich hätte sagen sollen, dass Superclass,A,B zum Beispiel dazugehört. 'concat' soll mit allen Klassen funktionieren, und wie gesagt, die gemeinsame Oberklasse von E und F zurückgeben.
 
Ich hätte sagen sollen, dass Superclass,A,B zum Beispiel dazugehört. 'concat' soll mit allen Klassen funktionieren, und wie gesagt, die gemeinsame Oberklasse von E und F zurückgeben.

Diese Aussage widerspricht aber etwas deiner Angabe.

Java:
public class GenericTest {
   public static void main(String[] args) {
     new MyList<A>().concat(new MyList<A>()).getFirst().aMethod();
     new MyList<B>().concat(new MyList<B>()).getFirst().bMethod();
     new MyList<A>().concat(new MyList<B>()).getFirst().superMethod();
     new MyList<A>().concat(new MyList<Superclass>()).getFirst().superMethod();
     new MyList<Superclass>().concat(new MyList<B>()).getFirst().superMethod();
   }
}

Laut deiner Aussage sollte der Aufruf von "concat" immer ein MyList<Superclass> Objekt zurückliefern (auf dein Beispiel bezogen).
Von diesem Objekt kannst du aber kein "getFirst().aMethod()" bzw. "getFirst().bMethod()" aufrufen.

Also entweder man setzt es um das der Code stimmt oder das deine Aussage zutrifft. Beide würde meiner Meinung nach nicht gehen!
 
Der Name 'Superclass' war vielleicht schlecht gewählt. Ich sagte, es soll ein MyList<S> zurückgeben, wobei S Oberklasse bzw. Superklasse (nicht 'Superclass') von E und F ist. Demendsprechend würde beim Aufruf...
Java:
new MyList<A>().concat(new MyList<A>())
S = A sein, da die Oberklasse von A und A eben A ist, und daher der Aufruf aMethod() möglich wäre.
Aber eigentlich dachte ich mir schon, dass das nicht möglich ist.

PS: mit einer static-Methode ist das ja möglich. Aber eine instance-Methode wäre schon schöner:
Java:
public static <S> MyList<S> concat(MyList<? extends S> a, MyList<? extends S> b)
Vielleicht ist das auch der Grund, warum die concat-Methode in Stream static ist.
 
Der Name 'Superclass' war vielleicht schlecht gewählt.
Ich sagte, es soll ein MyList<S> zurückgeben, wobei S Oberklasse bzw. Superklasse (nicht 'Superclass') von E und F ist.

Soweit bin ich schon mitgekommen.
Wenn E und F die gleiche Klasse sind wird eben auch das zurückgegeben Objekt von der gleichen Klasse sein.
Wenn E bzw. F die Ober-/Superklasse vom der jeweiligen anderen Klasse ist, wird ein Objekt dieser Ober-/Superklasse zurückgeliefert
Wenn E und F unterschiedlichen Subklassen sind, soll eine Objekt der Ober-/Superklasse zurückgeliefert werden.

Bei der von mir zitierten Aussage aber hast du gemeint es soll eben die Oberklasse zurückgeliefert werden (verstand ich soweit: Wenn A und A kommt auch S zurück.)

Ich bin mir ehrlich gesagt nicht sicher ob es vielleicht mit ein paar Tricks und Kniffen gehen würde, müsste man probieren. Ich kenne mich zwar mit Generics grundlegend aus, aber ab einen gewissen Grad bzw. einer gewissen Komplexibilität tu auch ich mir schwer 😉
 
Wenn ich das richtig verstanden habe sucht ihr so etwas:
Java:
public class Sub1 extends Super{

}
Java:
public class Sub2 extends Super{

}

Java:
import java.util.ArrayList;
import java.util.List;

public class Super {

    public <S, F extends S, E extends S> List<S> returnSuperClass(List<F> list1, List<E> list2) {
        List<S> concat = new ArrayList<S>(list1);
        concat.addAll(list2);

        return concat;
    }

    public void test() {
       
        List<Sub1> sub1List = new ArrayList<Sub1>();
        List<Sub2> sub2List = new ArrayList<Sub2>();
        List<Super> superList = new ArrayList<Super>();
       
        //beide Listen sind vom Typ Sub1" -> Rückgabe von Sub1 Liste
        List<Sub1> sub1Concat = returnSuperClass(sub1List, sub1List);
       
        //Listen von unterschiedlichen Subklassen -> Rückgabe von Superklasse Liste
        List<Super> superConcat = returnSuperClass(sub1List, sub2List);
       
        //Sub1 Klasse + Super-Klasse -> List<Super> wird returned
        List<Super> sub1SuperConcat = returnSuperClass(sub1List, superList);
       

    }

}

Die Methode returnSuperClass gibt immer eine Liste von der ersten gemeinsamen Oberklasse zurück. Ich glaube das war gewollt.
 
Nein nicht ganz. Diese Methode ist ja quasi die static-Lösung. Es ging darum, eine Instanz-Methode zu schreiben, also statt den ersten Parameter this benutzen.
 
Ja in deinem Beispiel nimmst du einfach den generischen Parameter deiner Klasse "MyList":

Java:
public class GenericTest {
 
  public static void main(String[] args) {
    new MyList<A>().concat(new MyList<A>()).getFirst().aMethod();
    new MyList<B>().concat(new MyList<B>()).getFirst().bMethod();
    new MyList<A>().concat(new MyList<B>()).getFirst().superMethod();
    new MyList<A>().concat(new MyList<Superclass>()).getFirst().superMethod();
    new MyList<Superclass>().concat(new MyList<B>()).getFirst().superMethod();
  }
 
 
  static class Superclass {
    public void superMethod() {
    }
  }
  static class A extends Superclass {
    public void aMethod() {
    }
  }
  static class B extends Superclass {
    public void bMethod() {
    }
  }
 
 
  static class MyList<E> {
 
    public E getFirst() {
      // some stuff
      return null;
    }
   
    public <S,F extends S, E extends S> MyList<S> concat(MyList<F> other) {
      // some stuff
      return null;
    }
 
  }
 
}
 
Nein das funktioniert nicht. Du überschreibst den Generic-Typ E von MyList<E> mit dem lokalen Generic-Typ der Methode. Somit ist folgendes nicht möglich:
Java:
public <S,F extends S, E extends S> MyList<S> concat(MyList<F> other) {
    // some stuff
    S a = other.getFirst();
    a = this.getFirst(); // compiler-error
    return null;
}
 

Zurück
Oben