// CSE341, Fall 2011 // Lecture 27: Generics vs. Subtyping; Bounded Polymorphism import java.util.List; import java.util.ArrayList; class Pair { T1 x; T2 y; Pair(T1 _x, T2 _y) { x = _x; y = _y; } Pair swap() { return new Pair(y,x); } } class Pt { double x, y; double distance(Pt pt) { return Math.sqrt((x-pt.x)*(x-pt.x)+(y-pt.y)*(y-pt.y)); } Pt(double _x, double _y) { x = _x; y = _y; } } class ColorPt extends Pt { String color; ColorPt(double _x, double _y, String c) { super(_x,_y); color = c; } } public class Lec27 { // caller can only pass List with an unchecked cast // and has to downcast result again without checking // (neither would work if Java "fully respected" generics) static List inCircle1(List pts, Pt center, double radius) { List result = new ArrayList(); for(Pt pt : pts) if(pt.distance(center) <= radius) result.add(pt); return result; } // in this version the unchecked cast burns us: a Pt // ends up in an alleged List static List inCircle2(List pts, Pt center, double radius) { List result = new ArrayList(); for(Pt pt : pts) if(pt.distance(center) <= radius) result.add(pt); else result.add(center); // weird example, but okay return result; } // bounded polymorphism is exactly what we want static List inCircle3(List pts, Pt center, // could be T if wanted double radius) { List result = new ArrayList(); for(T pt : pts) if(pt.distance(center) <= radius) result.add(pt); return result; } // this version is actually a bit less reusable, but we need this // type since center can end up in the result static List inCircle4(List arr, T center, // must be T double radius) { List result = new ArrayList(); for(T pt : arr) if(pt.distance(center) <= radius) result.add(pt); else result.add(center); // weird example, but okay return result; } public static void main(String[] args) { List cps = new ArrayList(); cps.add(new ColorPt(1.0,0.0,"purple")); cps.add(new ColorPt(0.0,1.0,"red")); cps.add(new ColorPt(3.0,3.0,"green")); cps.add(new ColorPt(-1.0,0.5,"sepia")); // these casts are unchecked -- don't do this!! (use bounds instead) List out1 = (List)(List) inCircle1((List)(List)cps, new Pt(0.0,0.0), // ColorPt okay 1.5); // this is why: this version fails "mysteriously" at run-time // (in an unexpected place: out2 has a Pt object in it!) List out2 = (List)(List) inCircle2((List)(List)cps, new Pt(0.0,0.0), // ColorPt needed (oops!) 1.5); List out3 = inCircle3(cps, new Pt(0.0,0.0), // ColorPt okay 1.5); List out4 = inCircle4(cps, new ColorPt(0.0,0.0,"clear"), // ColorPt needed 1.5); System.out.print("\nout1: "); for(ColorPt cp : out1) System.out.print(cp.color + " "); //System.out.print("\nout2: "); //for(ColorPt cp : out2) // System.out.print(cp.color + " "); System.out.print("\nout3: "); for(ColorPt cp : out3) System.out.print(cp.color + " "); System.out.print("\nout4: "); for(ColorPt cp : out4) System.out.print(cp.color + " "); System.out.println(); } }