Java之泛型
1. 概述
在引入泛型之前,Java类型分为原始类型、复杂类型,其中复杂类型分为数组和类。引入泛型后,一个复杂类型就可以在细分成更多的类型。
例如原先的类型List,现在在细分成List<Object>, List<String>等更多的类型。
注意,现在List<Object>, List<String>是两种不同的类型,他们之间没有继承关系,即使String继承了Object。下面的代码是非法的:
1 List<String> ls = new ArrayList<String>(); 2 List<Object> lo = ls;
这样设计的原因在于,根据lo的声明,编译器允许你向lo中添加任意对象(例如Integer),但是此对象是List<String>,破坏了数据类型的完整性。
在引入范型之前,要在类中的方法支持多个数据类型,就需要对方法进行重载,在引入范型后,可以解决此问题(多态),更进一步可以定义多个参数以及返回值之间的关系。例如:
1 public void write(Integer i, Integer[] ia); 2 public void write(Double d, Double[] da);
的范型版本为:
1 public <T> void write(T t, T[] ta);
在看下面代码:
1 public class GenericTest { 2 3 public static void main(String[] args) { 4 List list = new ArrayList(); 5 list.add("qqyumidi"); 6 list.add("corn"); 7 list.add(100); 8 9 for (int i = 0; i < list.size(); i++) { 10 String name = (String) list.get(i); // 1 11 System.out.println("name:" + name); 12 } 13 } 14 }
定义了一个List类型的集合,先向其中加入了两个字符串类型的值,随后加入一个Integer类型的值。这是完全允许的,因为此时list默认的类型为Object类型。在之后的循环中,由于忘记了之前在list中也加入了Integer类型的值或其他编码原因,很容易出现类似于//1中的错误。因为编译阶段正常,而运行时会出现“java.lang.ClassCastException”异常。因此,导致此类错误编码过程中不易发现。
通过使用泛型,解决上面异常,修改代码如下:
1 public class GenericTest { 2 3 public static void main(String[] args) { 4 /* 5 List list = new ArrayList(); 6 list.add("qqyumidi"); 7 list.add("corn"); 8 list.add(100); 9 */ 10 11 List<String> list = new ArrayList<String>(); 12 list.add("qqyumidi"); 13 list.add("corn"); 14 //list.add(100); // 1 提示编译错误 15 16 for (int i = 0; i < list.size(); i++) { 17 String name = list.get(i); // 2 18 System.out.println("name:" + name); 19 } 20 } 21 }
总结: 使用泛型可以指代任意对象类型,定义的容器所放的内容是一个统一的类型;
java中泛型的引入主要是为了解决两个方面的问题:
1. 集合类型元素在运行期出现类型装换异常,引入泛型增加编译时类型的检查;(即:消除强制类型转换,提高 Java 程序的类型安全)
2. 解决开发时重复代码的编写,能够复用算法。(比如:在类中的方法支持多个数据类型,就需要对方法进行重载)
2. 定义泛型类
我们直接上代码:
1 package com.learn.chap06.sec01; 2 3 public class Fdemo<T> { // 泛型类 4 private T a; 5 6 public Fdemo(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("Obeject类型为:"+a.getClass().getName()); 21 } 22 23 24 }
1 package com.learn.chap06.sec01; 2 /** 3 * 定义泛型类 (使用泛型可以指代任意对象类型) 4 * @author Administrator 5 * 6 */ 7 public class Fdemotest { 8 9 public static void main(String[] args) { 10 Fdemo<Integer> test = new Fdemo<Integer>(12); 11 test.print(); 12 System.out.println("test="+test.getA()); 13 14 Fdemo<String> strFdemo = new Fdemo<String>("我是中国人"); 15 strFdemo.print(); 16 System.out.println("strFdemo="+strFdemo.getA()); 17 } 18 }
运行结果:
Obeject类型为:java.lang.Integer
test=12
Obeject类型为:java.lang.String
strFdemo=我是中国人
3. 限制泛型:
我们直接上代码:
1 package com.learn.chap06.sec02; 2 3 public class Animal { 4 public void say() { 5 System.out.println("它是动物"); 6 } 7 }
1 package com.learn.chap06.sec02; 2 3 public class Dog extends Animal{ 4 5 @Override 6 public void say() { 7 // TODO Auto-generated method stub 8 System.out.println("它是一只狗"); 9 } 10 11 12 }
1 package com.learn.chap06.sec02; 2 3 public class Cat extends Animal{ 4 5 @Override 6 public void say() { 7 // TODO Auto-generated method stub 8 System.out.println("它是一只猫"); 9 } 10 11 12 }
1 package com.learn.chap06.sec02; 2 3 public class Demo<T extends Animal>{ 4 private T ob; 5 6 public Demo(T ob) { 7 super(); 8 this.ob = ob; 9 } 10 11 public T getOb() { 12 return ob; 13 } 14 15 public void setOb(T ob) { 16 this.ob = ob; 17 } 18 19 public void print(){ 20 System.out.println("T的类型是:"+ob.getClass().getName()); 21 } 22 }
1 package com.learn.chap06.sec02; 2 /** 3 * 限制泛型 4 * @author Administrator 5 * 6 */ 7 public class Test { 8 public static void main(String[] args) { 9 Demo<Dog> demo = new Demo<Dog>(new Dog()); 10 //demo.say(); 11 demo.print(); 12 13 //Demo<Integer> demo = new Demo<Integer>(new Dog()); // 由于泛型定义Demo类的类型必须为Animal或其子类Dog和Cat,而Integer不是Animal的子类,所以类型被限制,即:限制泛型,导致编译报错 14 Demo<Animal> demo2 = new Demo<Animal>(new Cat()); 15 demo2.print(); 16 17 Demo<Cat> demo3 = new Demo<Cat>(new Cat()); 18 demo3.print(); 19 20 } 21 }
运行结果:
T的类型是:com.learn.chap06.sec02.Dog
T的类型是:com.learn.chap06.sec02.Cat
T的类型是:com.learn.chap06.sec02.Cat
4. 通配符泛型:
我们直接上代码:
1 package com.learn.chap06.sec03; 2 3 import com.learn.chap06.sec02.Animal; 4 import com.learn.chap06.sec02.Cat; 5 import com.learn.chap06.sec02.Demo; 6 import com.learn.chap06.sec02.Dog; 7 8 public class Test1 { 9 /** 10 * 通配符泛型 11 * @param demo 12 */ 13 public static void take(Demo<?> demo){ // <?> 即为:通配符泛型 14 demo.print(); 15 } 16 17 public static void main(String[] args) { 18 Demo<Dog> demo1 = new Demo<Dog>(new Dog()); 19 take(demo1); 20 21 Demo<Cat> demo2 = new Demo<Cat>(new Cat()); 22 take(demo2); 23 24 Demo<Animal> demo3 = new Demo<Animal>(new Animal()); 25 take(demo3); 26 } 27 }
运行结果:
T的类型是:com.learn.chap06.sec02.Dog
T的类型是:com.learn.chap06.sec02.Cat
T的类型是:com.learn.chap06.sec02.Animal
5. 泛型方法:
1 package com.learn.chap06.sec04; 2 3 public class Test { 4 5 /** 6 * 泛型方法 7 * @param t 8 */ 9 public static <T> void f(T t) { 10 System.out.println("T的类型是:"+t.getClass().getName()); 11 } 12 13 public static void main(String[] args) { 14 f(1); 15 f("hello"); 16 f(1.0f); 17 f(new Object()); 18 } 19 }
运行结果:
T的类型是:java.lang.Integer
T的类型是:java.lang.String
T的类型是:java.lang.Float
T的类型是:java.lang.Object
现在使用泛型没问题了吧!呵呵