17网站一起做网店广州,网站服务器有什么区别,关于做网站,wordpress官方中文主题下载这是对泛型的介绍性讨论的延续#xff0c; 此处的先前部分可以在此处找到。 在上一篇文章中#xff0c;我们讨论了关于类型参数的递归边界。 我们看到了递归绑定如何帮助我们重用了车辆比较逻辑。 在该文章的结尾#xff0c;我建议当我们不够小心时#xff0c;可能会发生类… 这是对泛型的介绍性讨论的延续 此处的先前部分可以在此处找到。 在上一篇文章中我们讨论了关于类型参数的递归边界。 我们看到了递归绑定如何帮助我们重用了车辆比较逻辑。 在该文章的结尾我建议当我们不够小心时可能会发生类型混合。 今天我们将看到一个例子。 如果有人错误地通过以下方式创建了Vehicle的子类则可能会发生混合 /*** Definition of Vehicle*/
public abstract class VehicleE extends VehicleE implements ComparableE {// other methods and propertiespublic int compareTo(E vehicle) {// method implementation}
}/*** Definition of Bus*/
public class Bus extends VehicleBus {}/*** BiCycle, new subtype of Vehicle*/
public class BiCycle extends VehicleBus {}/*** Now this class’s compareTo method will take a Bus type* as its argument. As a result, you will not be able to compare* a BiCycle with another Bicycle, but with a Bus.*/
cycle.compareTo(anotherCycle); // This will generate a compile time error
cycle.compareTo(bus); // but you will be able to do this without any error 枚举不会发生这种类型的混淆因为JVM负责子类化和为枚举类型创建实例但是如果我们在代码中使用此样式则必须小心。 让我们谈谈递归边界的另一个有趣的应用。 考虑以下类别 public class MyClass {private String attrib1;private String attrib2;private String attrib3;private String attrib4;private String attrib5;public MyClass() {}public String getAttrib1() {return attrib1;}public void setAttrib1(String attrib1) {this.attrib1 attrib1;}public String getAttrib2() {return attrib2;}public void setAttrib2(String attrib2) {this.attrib2 attrib2;}public String getAttrib3() {return attrib3;}public void setAttrib3(String attrib3) {this.attrib3 attrib3;}public String getAttrib4() {return attrib4;}public void setAttrib4(String attrib4) {this.attrib4 attrib4;}public String getAttrib5() {return attrib5;}public void setAttrib5(String attrib5) {this.attrib5 attrib5;}
} 如果我们要创建此类的实例则可以执行以下操作 MyClass mc new MyClass();
mc.setAttrib1(Attribute 1);
mc.setAttrib2(Attribute 2); 上面的代码创建该类的实例并初始化属性。 如果我们可以在此处使用方法链接 那么我们可以编写 MyClass mc new MyClass().setAttrib1(Attribute 1).setAttrib2(Attribute 2); 显然比第一个版本好得多。 但是要启用这种方法链接我们需要通过以下方式修改MyClass public class MyClass {private String attrib1;private String attrib2;private String attrib3;private String attrib4;private String attrib5;public MyClass() {}public String getAttrib1() {return attrib1;}public MyClass setAttrib1(String attrib1) {this.attrib1 attrib1;return this;}public String getAttrib2() {return attrib2;}public MyClass setAttrib2(String attrib2) {this.attrib2 attrib2;return this;}public String getAttrib3() {return attrib3;}public MyClass setAttrib3(String attrib3) {this.attrib3 attrib3;return this;}public String getAttrib4() {return attrib4;}public MyClass setAttrib4(String attrib4) {this.attrib4 attrib4;return this;}public String getAttrib5() {return attrib5;}public MyClass setAttrib5(String attrib5) {this.attrib5 attrib5;return this;}
} 然后我们将可以对此类的实例使用方法链接。 但是如果我们想在涉及继承的地方使用方法链接那么事情就会变得混乱 public abstract class Parent {private String attrib1;private String attrib2;private String attrib3;private String attrib4;private String attrib5;public Parent() {}public String getAttrib1() {return attrib1;}public Parent setAttrib1(String attrib1) {this.attrib1 attrib1;return this;}public String getAttrib2() {return attrib2;}public Parent setAttrib2(String attrib2) {this.attrib2 attrib2;return this;}public String getAttrib3() {return attrib3;}public Parent setAttrib3(String attrib3) {this.attrib3 attrib3;return this;}public String getAttrib4() {return attrib4;}public Parent setAttrib4(String attrib4) {this.attrib4 attrib4;return this;}public String getAttrib5() {return attrib5;}public Parent setAttrib5(String attrib5) {this.attrib5 attrib5;return this;}
}public class Child extends Parent {private String attrib6;private String attrib7;public Child() {}public String getAttrib6() {return attrib6;}public Child setAttrib6(String attrib6) {this.attrib6 attrib6;return this;}public String getAttrib7() {return attrib7;}public Child setAttrib7(String attrib7) {this.attrib7 attrib7;return this;}
}/*** Now try using method chaining for instances of Child* in the following way, you will get compile time errors.*/
Child c new Child().setAttrib1(Attribute 1).setAttrib6(Attribute 6); 这样做的原因是即使Child从其父级继承了所有的setter所有这些setter方法的返回类型也都是Parent类型而不是Child类型。 因此第一个设置器将返回类型为Parent的引用调用setAttrib6会导致编译错误因为它没有任何此类方法。 我们可以通过在Parent上引入通用类型参数并在其上定义递归绑定来解决此问题。 它的所有子项从其扩展时都将自己作为类型参数传递从而确保setter方法将返回其类型的引用 public abstract class ParentT extends ParentT {private String attrib1;private String attrib2;private String attrib3;private String attrib4;private String attrib5;public Parent() {}public String getAttrib1() {return attrib1;}SuppressWarnings(unchecked)public T setAttrib1(String attrib1) {this.attrib1 attrib1;return (T) this;}public String getAttrib2() {return attrib2;}SuppressWarnings(unchecked)public T setAttrib2(String attrib2) {this.attrib2 attrib2;return (T) this;}public String getAttrib3() {return attrib3;}SuppressWarnings(unchecked)public T setAttrib3(String attrib3) {this.attrib3 attrib3;return (T) this;}public String getAttrib4() {return attrib4;}SuppressWarnings(unchecked)public T setAttrib4(String attrib4) {this.attrib4 attrib4;return (T) this;}public String getAttrib5() {return attrib5;}SuppressWarnings(unchecked)public T setAttrib5(String attrib5) {this.attrib5 attrib5;return (T) this;}
}public class Child extends ParentChild {private String attrib6;private String attrib7;public String getAttrib6() {return attrib6;}public Child setAttrib6(String attrib6) {this.attrib6 attrib6;return this;}public String getAttrib7() {return attrib7;}public Child setAttrib7(String attrib7) {this.attrib7 attrib7;return this;}
} 请注意我们已经明确地施放此为T类型因为编译器不知道这种转换是否是可能的即使它是因为牛逼的定义是由父T界。 同样由于我们将对象引用转换为T 因此编译器将发出未经检查的警告。 为了抑制这种情况我们在设置器上方使用了SuppressWarnings“ unchecked” 。 经过上述修改这样做是完全有效的 Child c new Child().setAttrib1(Attribute 1).setAttrib6(Attribute 6); 当以这种方式编写方法设置器时我们应注意不要将递归边界用于任何其他目的例如从父级访问子级状态因为这会使父级暴露其子类的内部细节并最终破坏封装。 通过这篇文章我完成了泛型的基本介绍。 我在本系列中没有讨论太多的事情因为我认为它们已经超出了介绍的范围。 直到下一次。 翻译自: https://www.javacodegeeks.com/2014/07/an-introduction-to-generics-in-java-part-6.html