Generisches generve...

S

Spacerat

Gast
Folgendes Beispiel:
Java:
import java.util.ArrayList;
import java.util.List;

public class GenerischesGenerve {
	public static void main(String[] args) {
		List<PolygonV> polygons = new ArrayList<>();
		Triangulator.triangulate(polygons);
		/*           ^^^^^^^^^^^
		 * Bound mismatch: The generic method triangulate(List<Polygon<P>>)
		 * of type Triangulator is not applicable for the arguments
		 * (List<PolygonV>). The inferred type Vertex is not a valid substitute
		 * for the bounded parameter <P extends Point<P>>
		 * 
		 * WAS SOLL DAS?
		 */
	}
}

class Polygon<T extends Point<?>> {
		// Wenn hier das ? ein T wird, kann
		// ich PolygonV nicht mehr erstellen.
}

class Point<T extends Point<T>> {
	
}

class Point3 extends Point<Point3> {
	
}

class Vertex extends Point3 {
}

class PolygonV extends Polygon<Vertex> {
	
}

class Triangulator {
	public static <P extends Point<P>> List<Polygon<P>> triangulate(List<Polygon<P>> polygons) {
		// Wenn ich hier mit Wildcards arbeite habe ich keinen
		// Zugriff auf die Methoden der Klasse Point.

		// doWork();
		return polygons;
	}
}
Ich hab' schon viel versucht, aber ich dreh' mich im Kreis. Ich wollte es so haben, dass der Triangulator mit jeder Art Polygonen ob 2D, 3D, Vertex oder sonst was klar kommt. Solange ich Polygone verwende, die direkt aus abgeleiteten Klassen der Klasse Point<> (also P2D und P3D). Sobald ich aber höhere Klassen (z.B. Vertex) verwende, erhalte ich obigen Fehler. Hat dafür jemand evtl. einen Vorschlag?
Diverse Interfaces usw. habe ich im übrigen auch schon ausprobiert. Ich bin mit meinem Latein am Ende. Ich versteh' einfach nicht, wieso Vertex kein Point<P> mehr ist, obwohl es Point3 direkt erweitert.
 

JCODA

Top Contributor
Java:
import java.util.ArrayList;
import java.util.List;
 
public class GenerischesGenerve {
    public static void main(String[] args) {
        List<Polygon<Vertex>> polygons = new ArrayList<>();
        polygons.add(new PolygonV());
        Triangulator.triangulate(polygons);

        List<PolygonV> polygons0 = new ArrayList<>();
        polygons0.add(new PolygonV());
        Triangulator.triangulate(polygons0);
    }
}
 
class Polygon<T extends Point<?>> {
       
}
 
class Point<T extends Point<T>> {
    
}
 
class Point3 extends Point<Point3> {
    
}
 
class Vertex extends Point3 {
}
 
class PolygonV extends Polygon<Vertex> {
    
}
 
class Triangulator {
    public static <P extends Point<?>,T extends Polygon<P>> List<T> triangulate(List<T> polygons) {
       System.out.println(polygons);
        return polygons;
    }
}

So vielleicht?
Warum ist eigentlich Point selbst generisch?

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

public class GenerischesGenerve {
	public static void main(String[] args) {
		List<PolygonV> polygons = new ArrayList<>();
		polygons.add(new PolygonV(new Vertex()));
		Triangulator.triangulate(polygons);

	}
}

class Polygon<T extends Point<?>> {
	private T t;
	public Polygon(T t){
		this.t=t;
	}
	public T getT(){
		return t;
	}
	
}

class Point<T extends Point<T>> {

	public void sayHello(){
		System.out.println("Hello!");
		System.out.println(this.getClass().getSuperclass());
	}
	
}

class Point3 extends Point<Point3> {

}

class Vertex extends Point3 {
}

class PolygonV extends Polygon<Vertex> {
	public PolygonV(Vertex v){
		super(v);
	}	
}

class Triangulator {
	public static <P extends Point<?>, T extends Polygon<P>> List<T> triangulate(
			List<T> polygons) {
			polygons.get(0).getT().sayHello();
		return polygons;
	}
}

Mhh, okay, klar, wenn Point generische Methoden abietet, dann ists immernoch falsch :/
 
Zuletzt bearbeitet:
S

Spacerat

Gast
Mhh, okay, klar, wenn Point generische Methoden abietet, dann ists immernoch falsch :/
Tja, Point ist generisch, weil es generische Methoden (add, substract, multiply, divide usw.) anbietet, passend zu Point2 und Point3, Point4. Vertices haben darüber hinaus nuch eine Farbe und mit PolygonV können nun Normalen und Texturkoordinanten per Vertex oder per Polygon definiert werden. Zuletzt bekommt PolygonV noch Meterialien für Vorder- und Rückseite. Alles in allem also Daten, die für die Triangulation nicht wichtig sind.
Wenn ich's ein bissl' umschreibe kommt schon ein ganz anderer Fehler:
Java:
public class GenerischesGenerve {
	public static void main(String[] args) {
		List<PolygonV> polygons = new ArrayList<>();
		Triangulator.triangulate(polygons);
		/*           ^^^^^^^^^^^
		 * The method triangulate(List<? super Polygon<P>>)
		 * in the type Triangulator is not applicable for
		 * the arguments (List<PolygonV>)
		 */
	}
}

class Polygon<T extends Point<? super T>> {

}

class Point<T extends Point<? super T>> {
	
}

class Triangulator {
	public static <P extends Point<? super P>> List<? super Polygon<P>> triangulate(List<? super Polygon<P>> polygons) {
		// doWork();
		return polygons;
	}
}
...aber ich hätt's nach wie vor schon lieber ganz ohne Fehler.
Beim Zugriff ging es im übrigen um die Methoden der Klasse Point. Die der Klasse PolygonV sind kein Problem. Der Triangulator kann nicht auf die erforderlichen Methoden ([c]getX()[/c] usw) oder Variablen (x usw) zugreifen. Für mich, wie gesagt, völlig unverständlich, weil die Klassen alle nur erweitert wurden.
Mit einer weiteren Änderung bekomme ich wieder ein "Bound mismatch" ([c]Bound mismatch: The generic method triangulate(List<L>) of type Triangulator is not applicable for the arguments (List<PolygonV>). The inferred type PolygonV is not a valid substitute for the bounded parameter <L extends List<? super Polygon<P>>>[/c])
Java:
class Triangulator {
	public static <P extends Point<? super P>, L extends List<? super Polygon<P>>> List<L> triangulate(List<L> polygons) {
		// doWork();
		return polygons;
	}
}
Ich bin vom Verhalten der Generics inzwischen echt angepieeet (Schreibfehler dienen der Verharmlosung ;)). Bei dem Ganzen "das und das und das geht nicht" ist's wohl sinnvoller wieder zum guten alten Typecasting zurück zu kehren und bei falscher Parameterübergabe schlicht mit Exceptions um sich zu schmeissen. Das wollte ich eigentlich vermeiden, aber die Generics sind (für mich völlig unverständlich) irgendwie dagegen.
[EDIT]Oh... Pardon... Hab' deine Zeile ein wenig falsch gelesen, aber wenn ich nun
Java:
	public static <P extends Point<? super P>, L extends Polygon<P>> List<L> triangulate(List<L> polygons) {
		return new Triangulator().doWork(polygons);
	}
draus mache, kann ich der "List<L>" keine "Polygon<P>" mehr hinzufügen... ist für Triangulation aber essentiell. Okay, zumindest ist man schon mal 'nen Schritt weiter.[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:

JCODA

Top Contributor
Gefallen tuts mir nicht und es sieht auch n bisschen redundant aus

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

public class GenerischesGenerve {
	public static void main(String[] args) {
		List<PolygonV> polygons = new ArrayList<>();
		polygons.add(new PolygonV());
		Triangulator.triangulate(polygons);

		List<Polygon2D> polygons0 = new ArrayList<>();
		polygons0.add(new Polygon2D());
		Triangulator.triangulate(polygons0);

		List<Polygon<Point2,Point2>> polygons1 = new ArrayList<>();
		polygons1.add(new Polygon<Point2,Point2>());
		Triangulator.triangulate(polygons1);
		
		List<Polygon<Point3,ExtendedVertex>> polygons2 = new ArrayList<>();
		polygons2.add(new Polygon<Point3,ExtendedVertex>());
		Triangulator.triangulate(polygons2);
	}
}

class Polygon<Q extends Point<Q>,T extends Point<Q>> {}

class Point<T extends Point<T>> {}

class Point3 extends Point<Point3> {}

class Point2 extends Point<Point2> {}

class Vertex extends Point3 {}

class ExtendedVertex extends Vertex {}

class PolygonV extends Polygon<Point3,Vertex> {}

class Polygon2D extends Polygon<Point2,Point2> {}

class Triangulator {
	public static <Q extends Point<Q>,P extends Point<Q>,T extends Polygon<Q,P>> List<T> triangulate(List<T> polygons) {
		
		
		
		return polygons;
	}	

}
 
S

Spacerat

Gast
Gefallen tuts mir nicht und es sieht auch n bisschen redundant aus...
Dem stimme ich zu...
Das das adden ausserhalb der Triangulationsroutine klappt, dürfte klar sein. Es sollte aber logischerweise innerhalb dieser klappen, nämlich genau dann, wenn ein Dreieck vom Polygon abgeschnitten und der Liste hinzugefügt werden muss.
Hier mal der komplette Triangulator... evtl. geht's ja noch anders, aber im Moment ist der Typecast beim Hinzufügen des Dreiecks eine funktionierende alternatieve, zumindest, solange wie keine ClassCastException kommt.
Java:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Triangulator {
	private static final Comparator<Polygon<?>> TRIA = new Comparator<Polygon<?>>() {
		@Override
		public int compare(Polygon<?> o1, Polygon<?> o2) {
			return Integer.valueOf(o2.numPoints()).compareTo(o1.numPoints());
		}
	};

	private Triangulator() {
	}

	private <P extends Point<? super P>, L extends Polygon<P>> List<L> doWork(List<L> polygons) {
		Collections.sort(polygons, TRIA);
		Polygon<P> p = polygons.get(0);
		AxisAlignedBounds<P> box = new AxisAlignedBounds<>(p.iterator().next());
		while(p.numPoints() > 3) {
			List<P> tmp = new ArrayList<>(p.getPoints());
			box.addAll(tmp);
			Collections.sort(tmp, ElementComparator.fromCache(box.maxDimension()));
			polygons.add((L) p.removeEar(tmp.get(0)));
			Collections.sort(polygons, TRIA);
			p = polygons.get(0);
			box.invalidate();
		}
		return polygons;
	}

	public static <P extends Point<? super P>, L extends Polygon<P>> List<L> triangulate(List<L> polygons) {
		return new Triangulator().doWork(polygons);
	}
}
Das Thema ist bis auf weiteres erst mal durch, danke für die Hilfe.
 

Landei

Top Contributor
[c]P extends Point<? super P>[/c] sieht einfach falsch aus, diese Varianz macht hier keinen Sinn. Würde mich nicht wundern, wenn dich das nochmal in den Hintern beißt.
 
S

Spacerat

Gast
[c]P extends Point<? super P>[/c] sieht einfach falsch aus, diese Varianz macht hier keinen Sinn. Würde mich nicht wundern, wenn dich das nochmal in den Hintern beißt.
Wer sagt das? Irgendwelche Bücher? Das ist die einzige Varianz, die funktioniert. Anderes mag zwar richtig aussehen, ist aber genau dass, was mich letztendlich in den Hintern beisst. Solange "richtig aussehen" nicht funktioniert, hat man davon nicht allzuviel. So was steht aber leider nicht in Büchern.
 

Marco13

Top Contributor
Ich muß es mir wohl noch genauer ansehen (und an ein paar Stellen "raten", warum dort was wie gemacht ist). Aber das scheint eine Wand zu sein, gegen die ich auch schon gelegentlich gelaufen bin: Man muss (soweit ich das sehe und verstehe und auf ähnliche Fälle, die ich schon hatte, übertragen kann) leider diese lästige Information über das "selbstreferentielle" bis zum bitteren Ende durchschleifen - GROB so ähnlich wie JCODA angedeutet hat (ob man da an der einen oder anderen Stelle noch was "schön-tweaken" kann müßte ich auch erst schauen). Diese "typedefs", wie du sie mit "Vertex" versucht hast, um den lästig-verbosen [c]T extends Point<T>[/c] loszuweden, funktionieren einfach nicht :( Etwas vereinfachend-suggestiv gesagt:
Vertex ist ein Point<Point3>, aber es müßte ein Vertex<Vertex<Vertex<...>>> sein.

Ich habe mir auch schon gelegentlich gedacht: Man bräuchte irgendein Konstrukt, damit man statt
Java:
class Point<T extends Point<T>> 
{
    void add(T other) { ... }
}
einfach schreiben könnte
Java:
class Point
{
    void add("ThisType" other) { ... }
}
oder so, weil das mit dem 'T', das eigentlich nur "sich selbst" beschreibt so schrecklich unübersichtlich ist, und auf der x-ten Verschachtelungsebene dann DOCH wieder irgendwelche Bounds-Fehler verursacht.

Etwas, was mit "wenigen Änderungen" compilert, und ggf. deiner Intention recht nahe kommt, aber eben OHNE diesen "Typedef" von Point3 arbeitet, und bei dem bestimmte Sachen die du vielleicht noch willst vielleicht auch nicht gehen, könnte grob sowas sein wie
Java:
package javaforum.generics;
import java.util.ArrayList;
import java.util.List;
 
public class GenerischesGenerve {
    public static void main(String[] args) {
        List<PolygonV> polygons = new ArrayList<PolygonV>();
        Triangulator.triangulate(polygons);
    }
}
 
class Polygon<T extends Point<?>> {
        // Wenn hier das ? ein T wird, kann
        // ich PolygonV nicht mehr erstellen.
}
 
class Point<T extends Point<T>> 
{
    void add(T other)
    {
    }
}
 
class Vertex extends Point<Vertex> 
{
    @Override
    void add(Vertex other)
    {
    }
}
 
class PolygonV extends Polygon<Vertex> {
    
}
 
class Triangulator {
    public static <P extends Point<P>> List<? extends Polygon<P>> triangulate(List<? extends Polygon<P>> polygons) {
        // Wenn ich hier mit Wildcards arbeite habe ich keinen
        // Zugriff auf die Methoden der Klasse Point.
 
        // doWork();
        return polygons;
    }
}
 

Landei

Top Contributor
Ich habe mir auch schon gelegentlich gedacht: Man bräuchte irgendein Konstrukt, damit man statt
Java:
class Point<T extends Point<T>> 
{
    void add(T other) { ... }
}
einfach schreiben könnte
Java:
class Point
{
    void add("ThisType" other) { ... }
}
oder so, weil das mit dem 'T', das eigentlich nur "sich selbst" beschreibt so schrecklich unübersichtlich ist, und auf der x-ten Verschachtelungsebene dann DOCH wieder irgendwelche Bounds-Fehler verursacht.

Lustigerweise hat Scala genau das, was du beschreibst (sogenannt "self-types"):

Code:
trait Point[T]{ 
  self:T =>  
  def add(that:T):T 
}

case class Point2D(x:Int, y:Int) extends Point[Point2D] {
  def add(that:Point2D) = Point2D(this.x+that.x, this.y+that.y)
}
 
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben