1. 泛型概述
是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。参数化类型,把类型当作参数一样的传递。
2. 格式:
<数据类型>
注意:该数据类型只能是引用类型。
3. 好处:
A:把运行时期的问题提前到了编译期间
B:避免了强制类型转换
C:优化了程序设计,解决了黄色警告线问题,让程序更安全
/* * ArrayList存储字符串并遍历 * * 不使用泛型,写这个程序, 结果出错了。 * 为什么呢? * 因为我们开始存储的时候,存储了String和Integer两种类型的数据。 * 而在遍历的时候,我们把它们都当作String类型处理的,做了转换,所以就报错了。 * 但是呢,它在编译期间却没有告诉我们。所以,我就觉得这个设计的不好。 * 回想一下,我们的数组 * String[] strArray = new String[3]; * strArray[0] = "hello"; * strArray[1] = "world"; * strArray[2] = 10;// 编译出错 * 集合也模仿着数组的这种做法,在创建对象的时候明确元素的数据类型。这样就不会在有问题了。 * 而这种技术被称为:泛型。 */ public class GenericDemo { public static void main(String[] args) { // 创建 ArrayList<String> array = new ArrayList<String>(); // 添加元素 array.add("hello"); array.add("world"); array.add("java"); // array.add(new Integer(100)); // 定义泛型前,编译没有问题 // array.add(10); // JDK5以后的自动装箱,等价于:array.add(Integer.valueOf(10)); // 遍历 Iterator<String> it = array.iterator(); while (it.hasNext()) { // String s = (String) it.next(); // 定义泛型前:ClassCastException String s = it.next(); // 定义泛型后就不用向下转型了 System.out.println(s); } // 看下面这个代码 // String[] strArray = new String[3]; // strArray[0] = "hello"; // strArray[1] = "world"; // strArray[2] = 10; // 编译出错 } }
/** * 用ArrayList存储字符串元素,并遍历。用泛型改进代码 */ public class GenericDemo { public static void main(String[] args) { ArrayList<String> array = new ArrayList<String>(); array.add("hello"); array.add("world"); array.add("java"); Iterator<String> it = array.iterator(); while (it.hasNext()) { String s = it.next(); // 避免了向下转型 System.out.println(s); } for (int x = 0; x < array.size(); x++) { String s = array.get(x); // 避免了向下转型 System.out.println(s); } } }
/* * 需求:存储自定义对象并遍历。 * A:创建学生类 * B:创建集合对象 * C:创建元素对象 * D:把元素添加到集合 * E:遍历集合 */ public class GenericDemo { public static void main(String[] args) { // 创建集合对象 // ArrayList<Student> array = new ArrayList<>();// JDK7的新特性:泛型推断。但是不建议这样使用。 ArrayList<Student> array = new ArrayList<Student>(); // 创建元素对象 Student s1 = new Student("曹操", 40); // 后知后觉 Student s2 = new Student("蒋干", 30); // 不知不觉 Student s3 = new Student("诸葛亮", 26);// 先知先觉 // 添加元素 array.add(s1); array.add(s2); array.add(s3); // 遍历 Iterator<Student> it = array.iterator(); while (it.hasNext()) { Student s = it.next(); System.out.println(s.getName() + "---" + s.getAge()); } for (int x = 0; x < array.size(); x++) { Student s = array.get(x); System.out.println(s.getName() + "---" + s.getAge()); } } } class Student { private String name; private int age; public Student() { } public Student(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
4. 泛型的前世今生
A:泛型的由来
早期的时候,我们使用Object来代表任意的类型。
向上转型是没有任何问题的,但是在向下转型的时候其实隐含了类型转换的问题。
也就是说这样的程序其实并不是安全的。所以Java在JDK5后引入了泛型,提高程序的安全性。
public class ObjectToolDemo { public static void main(String[] args) { ObjectTool ot = new ObjectTool(); ot.setObj(new Integer(27)); Integer i = (Integer) ot.getObj();// 正常使用 System.out.println("年龄是:" + i); ot.setObj(new String("林青霞")); String s = (String) ot.getObj();// 正常使用 System.out.println("姓名是:" + s); ot.setObj(new Integer(30)); String ss = (String) ot.getObj();// ClassCastException System.out.println("姓名是:" + ss); } } class ObjectTool { private Object obj; public Object getObj() { return obj; } public void setObj(Object obj) { // Object obj = new Integer(30); this.obj = obj; } }
B:泛型类:把泛型定义在类上
/** * 泛型类的测试 */ public class ObjectToolDemo { public static void main(String[] args) { ObjectTool<String> ot = new ObjectTool<String>(); // ot.setObj(new Integer(27)); // 这个时候编译期间就过不去 ot.setObj(new String("林青霞")); String s = ot.getObj(); System.out.println("姓名是:" + s); ObjectTool<Integer> ot2 = new ObjectTool<Integer>(); // ot2.setObj(new String("风清扬")); // 这个时候编译期间就过不去 ot2.setObj(new Integer(27)); Integer i = ot2.getObj(); System.out.println("年龄是:" + i); } } /** * 泛型类:把泛型定义在类上 */ class ObjectTool<T> { private T obj; public T getObj() { return obj; } public void setObj(T obj) { this.obj = obj; } }
C:泛型方法:把泛型定义在方法上
public class ObjectToolDemo { public static void main(String[] args) { ObjectTool ot = new ObjectTool(); ot.show("hello"); ot.show(100); ot.show(true); ObjectTool<String> ot1 = new ObjectTool<String>(); ot1.show("hello"); ObjectTool<Integer> ot2 = new ObjectTool<Integer>(); ot2.show(100); ObjectTool<Boolean> ot3 = new ObjectTool<Boolean>(); ot3.show(true); // 但是呢,谁说了我的方法一定要和类的类型的一致呢? // 我要是类上没有泛型的话,方法还能不能接收任意类型的参数了呢? // 定义泛型方法后 ObjectTool2 ot4 = new ObjectTool2(); ot4.show("hello"); ot4.show(100); ot4.show(true); } } class ObjectTool<T> { // public void show(String s) { // System.out.println(s); // } // // public void show(Integer i) { // System.out.println(i); // } // // public void show(Boolean b) { // System.out.println(b); // } public void show(T t) { System.out.println(t); } } // 泛型方法:把泛型定义在方法上 class ObjectTool2 { public <T> void show(T t) { System.out.println(t); } }
D:泛型接口
// 泛型接口:把泛型定义在接口上 interface Inter<T> { public abstract void show(T t); } // 实现类在实现泛型接口的时候,也需要定义泛型 class InterImpl<T> implements Inter<T> { public void show(T t) { System.out.println(t); } } public class InterDemo { public static void main(String[] args) { Inter<String> i = new InterImpl<String>(); i.show("hello"); Inter<Integer> ii = new InterImpl<Integer>(); ii.show(100); } }
E:泛型高级(通配符)
? :任意类型,如果没有明确,那么就是Object以及任意的Java类了
? extends :向下限定,E及其子类
? super E :向上限定,E极其父类
public class GenericDemo { public static void main(String[] args) { // 泛型如果明确的写的时候,前后必须一致 Collection<Object> c1 = new ArrayList<Object>(); // Collection<Object> c2 = new ArrayList<Animal>(); // 错误形式 // Collection<Object> c3 = new ArrayList<Dog>(); // 错误形式 // Collection<Object> c4 = new ArrayList<Cat>(); // 错误形式 // ?表示任意的类型都是可以的 Collection<?> c5 = new ArrayList<Object>(); Collection<?> c6 = new ArrayList<Animal>(); Collection<?> c7 = new ArrayList<Dog>(); Collection<?> c8 = new ArrayList<Cat>(); // ? extends E:向下限定,E及其子类 // Collection<? extends Animal> c9 = new ArrayList<Object>(); // 错误形式 Collection<? extends Animal> c10 = new ArrayList<Animal>(); Collection<? extends Animal> c11 = new ArrayList<Dog>(); Collection<? extends Animal> c12 = new ArrayList<Cat>(); // ? super E:向上限定,E极其父类 Collection<? super Animal> c13 = new ArrayList<Object>(); Collection<? super Animal> c14 = new ArrayList<Animal>(); // Collection<? super Animal> c15 = new ArrayList<Dog>(); // 错误形式 // Collection<? super Animal> c16 = new ArrayList<Cat>(); // 错误形式 } } class Animal { } class Dog extends Animal { } class Cat extends Animal { }
5. 我们在哪里使用呢?
看API,如果类,接口,抽象类后面跟的有<E>就说明要使用泛型。一般来说就是在集合中使用。