------- android培训、java培训、期待与您交流! ----------
首先,可以为任何类,接口增加泛型声明,下面自定义一个Apple类,这个Apple类就可以包含一个泛型声明。
1 public class Apple2 { 3 //使用T类型形参定义实例变量 4 private T info; 5 public Apple(){} 6 7 //下面方法中使用T类型形参定义构造器 8 public Apple(T info) 9 { 10 this.info = info; 11 } 12 13 public void setInfo(T info) 14 { 15 this.info = info; 16 } 17 18 public T getInfo() 19 { 20 return this.info; 21 } 22 23 public static void main(String[] args) 24 { 25 //由于传给T形参的是String,所以构造器参数只能是String 26 Apple a1 = new Apple<>("苹果"); 27 System.out.println(a1.getInfo()); 28 29 //由于传给T形参的是Double, 所以构造器参数只能是Double或double 30 Apple a2 = new Apple<>(5.67); 31 System.out.println(a2.getInfo()); 32 } 33 }
上面程序定义了一个带泛型声明的Apple
JDK在定义List ArrayList等接口和类时使用了类型形参,所以在使用这些类时为之传入了实际的类型参数。
问题:我们如何从泛型类派生子类?
当创建了带泛型声明的接口,父类之后,可以为该接口创建实现类,或从该父类派生子类,需要指出的是,当使用这些接口,父类时不能再包含类型形参。例如,下面代码就是错误的。
//定义类A继承Apple类,Apple类不能根类型形参 public class A extends Apple{}
定义方法时可以声明数据形参,调用方法时必须为这些数据形参传入实际的数据:于此类似的是,定义类,接口,方法时可以声明类型形参,使用类,接口,方法时应该为类型形参传入实际的类型
如果想从Apple类派生子类,则可以改为如下代码:
//使用Apple类时,为T形参传入String类型 public class A extends Apple
调用方法时必须为所有的数据形参传入参数值,与调用方法不同的时,使用类,接口时可以不为类型形参传入实际的类型参数,所以下面的代码也是正确的。
//使用Apple类时,没有为T形参传入实际的类型参数 public class A extends Apple
如果Apple
public class A1 extends Apple{ //正确重写了父类的方法,返回值 //与父类Apple 的返回值完全相同 public String getInfo() { return "子类" + super.getInfo(); } //下面方法时错误的,重写父类方法时返回值类型不一致 public Object getInfo() { return "子类"; } }
如果使用Apple类时没有传入实际的类型参数,java编译器可能发出警告:使用了未经坚持或不安全的操作——这就是泛型坚持的警告。
此时,系统会把Apple
1 public class A2 extends Apple 2 { 3 //重写父类方法 4 public String getInfo() 5 { 6 //super.getInfo()方法返回值是Object类型 7 //所以加toString()才返回String类型 8 return super.getInfo().toString(); 9 } 10 }
并不存在泛型类
我们可以把ArrayList
//分别创建List对象和List List对象 l1 = new ArrayList<>(); List l2 = new ArrayList<>(); //调用getClass()方法来比较l1和l2的类是否相等 System.out.println(l1.getClass() == l2.getClass());
运行上面的代码片段实际输出的是true.因为不管泛型的实际类型参数是什么,它们在运行时总有同样的类(class)
不管为泛型的类型形参传入哪一种类型实参,对于java来说,它们已然被当成同一个类处理,在内存中也只占用一块内存空间,因此在静态方法,静态初始化块或者静态变量的声明和初始化中不允许使用类型形参。