Java泛型
一、定义
泛型可以用来指代任意对象类型。
二、泛型和多态
1.引入多态
定义一个C1类:里面有个Integer属性,给出它的构造方法、打印其类型和get\set方法。
1 package com.swu.generics; 2 3 public class C1 { 4 private Integer a; 5 6 public C1(Integer a) { 7 super(); 8 this.a = a; 9 } 10 11 public Integer getA() { 12 return a; 13 } 14 15 public void setA(Integer a) { 16 this.a = a; 17 } 18 19 20 /** 21 * 打印a的类型 22 */ 23 public void print() { 24 System.out.println("a的类型是:" + a.getClass().getName()); 25 } 26 }
同理定义一个C2类,里面定义一个String属性:
1 package com.swu.generics; 2 3 public class C2 { 4 private String a; 5 6 public C2(String a) { 7 super(); 8 this.a = a; 9 } 10 11 public String getA() { 12 return a; 13 } 14 15 public void setA(String a) { 16 this.a = a; 17 } 18 19 /** 20 * 打印a的类型 21 */ 22 public void print() { 23 System.out.println("a的类型是:" + a.getClass().getName()); 24 } 25 }
写个Test1类用于测试:
1 package com.swu.generics; 2 3 public class Test1 { 4 5 public static void main(String[] args) { 6 //begin test C1 7 C1 c1 = new C1(1); 8 c1.print(); 9 int i1 = c1.getA(); 10 System.out.println("i1 = " + i1); 11 //end test C1 12 13 //begin test C2 14 C2 c2 = new C2("I'm C2"); 15 c2.print(); 16 String i2 = c2.getA(); 17 System.out.println(i2); 18 //end test C2 19 20 } 21 22 }
输出结果:
假如有其他类型,我们就要写很多C3、C4......很麻烦,这个时候我们想起用多态。对以上代码进行改写:
2.用多态进行改写
将上述C1、C2用一个类实现,因为所有的类都继承自Object类,所以直接定义Object类型的属性:
1 package com.swu.generics; 2 3 public class C12 { 4 private Object a; 5 6 public C12(Object a) { 7 super(); 8 this.a = a; 9 } 10 11 public Object getA() { 12 return a; 13 } 14 15 public void setA(Object a) { 16 this.a = a; 17 } 18 19 /** 20 * 打印a的类型 21 */ 22 public void print() { 23 System.out.println("a的类型是:" + a.getClass().getName()); 24 } 25 }
写下测试类:
1 package com.swu.generics; 2 3 public class Test1 { 4 5 public static void main(String[] args) { 6 //begin test C1 7 C1 c1 = new C1(1); 8 c1.print(); 9 int i1 = c1.getA(); 10 System.out.println("i1 = " + i1); 11 //end test C1 12 13 //begin test C2 14 C2 c2 = new C2("I'm C2"); 15 c2.print(); 16 String i2 = c2.getA(); 17 System.out.println("i2:" + i2); 18 //end test C2 19 20 //begin test C12 21 C12 c12 = new C12(12);//向上转型 int->Object 不会出错 22 c12.print(); 23 int i3 = (int)c12.getA();//向下转型 Object->int 会出错 24 System.out.println("i3:" + i3); 25 26 C12 c122 = new C12("I am C122"); 27 c122.print(); 28 String i4 = (String)c122.getA(); 29 System.out.println("i4:" + i4); 30 //end test C12 31 } 32 33 }
测试结果:
使用多态我们可以让类简单,但是具体实现仍然没有简化,需要向上向下转型,容易出错。而泛型就是既可以简化类,也可以简化实现的方法。
3.使用泛型
先定义一个泛型类:
1 package com.swu.generics; 2 3 /** 4 * 泛型类 5 * @author 健泽 6 * @param <T> T可以用其他字母代替 7 */ 8 public class CC<T> { 9 private T a; 10 11 public CC(T a) { 12 super(); 13 this.a = a; 14 } 15 16 public T getA() { 17 return a; 18 } 19 20 public void setA(T a) { 21 this.a = a; 22 } 23 24 /** 25 * 打印a的类型 26 */ 27 public void print() { 28 System.out.println("a的类型是:" + a.getClass().getName()); 29 } 30 }
再进行测试:
1 package com.swu.generics; 2 3 public class Test1 { 4 5 public static void main(String[] args) { 6 //begin test C1 7 C1 c1 = new C1(1); 8 c1.print(); 9 int i1 = c1.getA(); 10 System.out.println("i1 = " + i1); 11 //end test C1 12 13 //begin test C2 14 C2 c2 = new C2("I'm C2"); 15 c2.print(); 16 String i2 = c2.getA(); 17 System.out.println("i2:" + i2); 18 //end test C2 19 20 //begin test C12 21 C12 c12 = new C12(12);//向上转型 int->Object 不会出错 22 c12.print(); 23 int i3 = (int)c12.getA();//向下转型 Object->int 会出错 24 System.out.println("i3:" + i3); 25 26 C12 c122 = new C12("I am C122"); 27 c122.print(); 28 String i4 = (String)c122.getA(); 29 System.out.println("i4:" + i4); 30 //end test C12 31 32 //begin test CC 33 CC<Integer> cc = new CC<Integer>(1222);//泛型实例化方式 34 cc.print(); 35 int i5 = cc.getA(); 36 System.out.println("i5:" + i5); 37 38 CC<String> cc1 = new CC<String>("I am generics and I am easy."); 39 cc1.print(); 40 String i6 = cc1.getA(); 41 System.out.println("i6:" + i6); 42 //end test cc 43 } 44 45 }
测试结果:
可以看到,使用泛型在实例化的时候就确定了类型,避免了转型麻烦,更加简单。注意泛型实例化的方式
三、限制泛型类型
前面我们说的泛型,可以是任意类型,但是有时候我们需要限制类型,这样更加安全。
我们通过实例理解,新建一个Animal类,再建两个子类Dog类和Cat类:
1 package com.swu.generics02; 2 3 public class Animal { 4 public void print() { 5 System.out.println("Animal"); 6 } 7 }
1 package com.swu.generics02; 2 3 public class Dog extends Animal { 4 public void print() { 5 System.out.println("Dog"); 6 } 7 }
1 package com.swu.generics02; 2 3 public class Cat extends Animal{ 4 public void print() { 5 System.out.println("Cat"); 6 } 7 }
然后再定义一个泛型类:
1 package com.swu.generics02; 2 3 public class Demo <T extends Animal>{ 4 private T a; 5 6 public Demo(T a) { 7 super(); 8 this.a = a; 9 } 10 11 public T getA() { 12 return a; 13 } 14 15 public void setA(T a) { 16 this.a = a; 17 } 18 19 public void print() { 20 System.out.println("a的类型是:" + a.getClass().getName()); 21 } 22 }
这里对泛型类进行了限制,必须是Animal类或者是Animal的子类。
新建一个测试类:
1 package com.swu.generics02; 2 3 public class Test { 4 public static void main(String[] args) { 5 Demo<Dog> dd = new Demo<Dog>(new Dog()); 6 Dog dog = dd.getA(); 7 dog.print(); 8 9 Demo<Cat> dc = new Demo<Cat>(new Cat()); 10 Cat cat = dc.getA(); 11 cat.print(); 12 13 Demo<Animal> ad = new Demo<Animal>(new Animal()); 14 ad.print(); 15 16 } 17 }
输出如下:
如果Demo<Animal>中将Animal换成其他类就会报错,类型不匹配:
四、通配符泛型
通配符泛型在使用泛型特殊的场景下用到,比如把泛型对象作为方法参数传入方法的时候,就用到通配符泛型。在调用该方法时,要将具体的对象作为参数传入。
1 package com.swu.generics02; 2 3 public class Test { 4 /** 5 * 通配符泛型 具体使用方法时,用具体类型代替? 6 * @param demo 7 */ 8 public static void take(Demo<?> demo) { 9 demo.print(); 10 } 11 12 public static void main(String[] args) { 13 Demo<Dog> dg = new Demo<Dog>(new Dog()); 14 take(dg); 15 16 Demo<Cat> dc = new Demo<Cat>(new Cat()); 17 take(dc); 18 19 Demo<Animal> da = new Demo<Animal>(new Animal()); 20 take(da); 21 } 22 }
输出:
五、泛型方法
泛型方法是指返回值和参数都用泛型表示的方法,其中返回类型可以是int、void、T等。
1 package com.swu.generics02; 2 3 public class Test2 { 4 5 /** 6 * 泛型方法 7 * @param <T> 声明T 否则参数不知道T是什么 8 * @param t 泛型参数 9 */ 10 public static <T> void getClass(T t){ 11 System.out.println("类型是" + t.getClass().getName()); 12 } 13 14 public static void main(String[] args) { 15 getClass(1); 16 getClass("ad"); 17 getClass(1.02); 18 getClass(new Object()); 19 } 20 }
输出: