public class Pair<T> { private T first; private T second; public Pair(T first, T second){ this.first = first; this.second = second; } public void setFirst(T first){ this.first = first; } public T getFirst(){ return first; } public void setSecond(T second){ this.second = second; } // public void setSecond(Object second){ // this.second = (T) second; // } public T getSecond(){ return second; } }使用类分析器对其进行分析,结果:
public class Pair extends java.lang.Object{ //域 private java.lang.Object first; private java.lang.Object second; //构造器 public Pair(java.lang.Object, java.lang.Object); //方法 public void setFirst(java.lang.Object); public void setSecond(java.lang.Object); public java.lang.Object getSecond( ); public java.lang.Object getFirst( ); }如果将泛型类Pair的类型参数加上限定,比如Pair<T extends Comparable>,再使用 类分析器对其进行分析,结果:
public class Pair extends java.lang.Object{ //域 private java.lang.Comparable first; private java.lang.Comparable second; //构造器 public Pair(java.lang.Comparable, java.lang.Comparable); //方法 public void setFirst(java.lang.Comparable); public void setSecond(java.lang.Comparable); public java.lang.Comparable getSecond( ); public java.lang.Comparable getFirst( ); }使用类型参数的限定进行了替换,这与预计的相同。
Pair<GregorianCalendar> birthdays = ...; GregorianCalendar first = birthdays.getFirst();
public class ArrayAlg { public static <T> T getMiddle(T[] t){ System.out.println("泛型方法"); return t[t.length/2]; } // public static Object getMiddle(Object[] o){ // return o[o.length/2]; // } public static <T extends Comparable> T min(T[] a){ if(a == null || a.length == 0){ return null; } T smallest = a[0]; for(int i = 1;i < a.length;i++){ if(smallest.compareTo(a[i]) > 0){ smallest = a[i]; } } return smallest; } public static <T extends Comparable> Pair<T> minmax(T[] ts){ if(ts == null || ts.length == 0){ return null; } T min = ts[0]; T max = ts[0]; for(int i = 0;i < ts.length;i++){ if(min.compareTo(ts[i]) > 0){ min = ts[i]; } if(max.compareTo(ts[i]) < 0){ max = ts[i]; } } return new Pair<T>(min, max); } // public static Pair<Comparable> minmax(Comparable[] ca){ // return null; // } public static void main(String[] args) { String[] s = {"AAA","BBB","CCC"}; System.out.println(ArrayAlg.<String>getMiddle(s));//在方法名前指定类型 // System.out.println(<String>getMiddle(s));//不能这样用,虽然调用的是处在同一个类中静态方法,语法问题,<>不能加在方法名前 Date[] d = {new Date(),new Date(),new Date()}; System.out.println(getMiddle(d));//其实可以不指定参数,编译器有足够的信息推断出要调用的方法 int[] is = {100,200,300}; System.out.println(getMiddle(is)); } } 使用类分析器对其进行分析,结果: public class ArrayAlg extends java.lang.Object{ //方法 public static int getMiddle(int[]); public static java.lang.Object getMiddle(java.lang.Object[]); public static Pair minmax(java.lang.Comparable[]); public static void main(java.lang.String[]); public static java.lang.Comparable min(java.lang.Comparable[]); } 泛型方法的类型擦除会带来两个问题1.类型擦除与多态的冲突;2.方法签名冲突。 我们来看一个结构相对繁杂一些的类,类DateInterval继承前面定义的泛型类Pair<T>: public class DateInterval extends Pair<Date> { public DateInterval(Date first, Date second){ super(first, second); } @Override public void setSecond(Date second) { super.setSecond(second); } @Override public Date getSecond(){ return super.getSecond(); } public static void main(String[] args) { DateInterval interval = new DateInterval(new Date(), new Date()); Pair<Date> pair = interval;//超类,多态 Date date = new Date(2000, 1, 1); System.out.println("原来的日期:"+pair.getSecond()); System.out.println("set进新日期:"+date); pair.setSecond(date); System.out.println("执行pair.setSecond(date)后的日期:"+pair.getSecond()); } }
我们知道Java中的方法调用采用的是动态绑定的方式,应该呈现出多态的特性。子类覆写超类中的方法,如果将子类向下转型成超类后,仍然可以调用覆写后的方法。但是泛型类的类型擦除造成了一个问题,Pair的原始类型中存在方法
public void setSecond(Object second);
DateInterval中的方法
public void setSecond(Date second);
我们的本意是想覆写Pair中的setSecond方法,但是从方法签名上看,这完全是两个不同的方法,类型擦除与多态产生了冲突。而实际情况那?运行DateInterval的main方法,我们看到
public void setSecond(Date second)的确覆写了public void setSecond(Object second)方法。这是如何做到的那?
使用Java类分析器对其进行分析,结果:
public class DateInterval extends Pair{ //构造器 public DateInterval(java.util.Date, java.util.Date); //方法 public void setSecond(java.util.Date); public volatile void setSecond(java.lang.Object);//方法1 public java.util.Date getSecond( );//方法2 public volatile java.lang.Object getSecond( );//方法3,它难道不会和方法1冲突? public static void main(java.lang.String[]); }
方法1和方法3是我们在源码中不曾定义的,它肯定是由编译器生成的。这个方法称为桥方法(bridge method),真正覆写超类方法的是它。语句pair.setSecond(date)实际上调用的是方法1,public volatile void setSecond(Object),通过这个方法再去调用public void setSecond(Date)。这个桥方法的实际内容是:
public void setSecond(Object second){ this.setSecond( (java.util.Date) second ); }
这样的结果就符合面向对象中多态的特性了,实现了方法的动态绑定。但是,这样的做法给我们带来了一种错觉,就认为public void setSecond(Date)覆写了泛型类的public void setSecond(Object),如果我们在DateInterval中增加一个方法:
public void setSecond(Object obj){ System.out.println("覆写超类方法!"); }
public class A { public List getList(){ return null; } } public class ASub extends A{ @Override public ArrayList getList(){ return null; } } 分析ASub类,结果: public class ASub extends A{ //域 //构造器 public ASub( ); //方法 public java.util.ArrayList getList( ); public volatile java.util.List getList( ); }