赞
踩
泛型就是类型的参数化,就是可以把类型像方法的参数那样传递。泛型使编译器可以在编译期间对类型进行检查以提高类型安全,减少运行时由于对象类型不匹配引发的异常。在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型。
也就是说在泛型的使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
当我们使用泛型来约束集合、方法、类、接口时,如果直接指定类型的话,那么在使用泛型约束的集合、方法、类、接口时便只能操作与泛型类型相同的数据。(强制绑定数据类型,比如给List集合定义上String类型的泛型,那么只能存储String类型的数据)
如果不定义泛型的类型而是使用类型变量的话,那么此时的泛型便可以认为是 Object 类型,可以对所有类型的数据进行操作。
注:泛型所指定的类型都是引用类型
众所周知,如果不定义集合的存储类型,那么集合的默认类型便是 Object 类型。这样的好处便是在创建集合对象,并向集合中存储元素时,不会有类型的限制,可以存储所有的数据类型。
我们平时在使用集合时,往往涉及到元素类型的转换。当集合中存在多种数据类型的元素时,我们便无法对集合整体做出类型转换的操作。虽然代码在编译期不会显示出异常,但是当对集合进行强制转换时,会将集合中的所有元素都进行类型转换,这时候如果其中某些元素与强转类型不符合,比如:不含数字的字符串类型元素转换成数字类型。对于这种不合理的类型转换,系统便会报出元素类型转换异常。
为了避免这种类型转换的异常,Java提供了一种数据类型定义规范 — 泛型。使用泛型可以在定义集合对象时候指定集合的类型,这样在向集合中存储元素时便只能存储泛型指定类型的元素数据。有效的避免了集合元素的类型转换出现异常的问题。
泛型应用在集合上的好处:
泛型应用在集合上的弊端:
集合转换异常, Demo 代码示例:
public class GenericDemo { public static void main(String[] args) { // 创建 List list = new ArrayList(); // 添加元素 //添加int类型的元素 list.add(10); // JDK5以后的自动装箱 // 等价于:array.add(Integer.valueOf(10)); list.add("String"); list.add(2.14); list.add('i'); list.add(true); list.add("hello"); // 遍历 Iterator it = list.iterator(); while (it.hasNext()) { Integer integer =(Integer) it.next(); System.out.println(integer); } } }
运行结果:
从运行结果可以看出,使用强制类型转换时,转换类型为 Integer ,只有第一个元素遍历出来了,因为第一个元素是整数类型,可以与 Integer 之间相互转换,其他的都不可以转换,所以报出类型转换异常。
使用泛型定义集合类型, Demo 代码示例:
public class GenericDemo { public static void main(String[] args) { // 创建 List<String> list = new ArrayList<String>(); //非字符串类型不可存储 //list.add(12.12); list.add("String"); list.add("java"); /*list.add(2.14); list.add('i'); list.add(true); */ // 遍历 Iterator it = list.iterator(); while (it.hasNext()) { // Integer integer =(Integer) it.next();//字符串类型不可转换成数字类型 System.out.println(it.next()); } } }
运行结果:
修饰符 <泛型变量> 返回值的类型 方法名称(形参列表){
//方法体
}
Demo代码示例:
public class ObjectTool {
public static void main(String[] args) {
ObjectTool tool = new ObjectTool();
tool.information("姓名","姚青");
tool.information("年龄",22);
tool.information("性别","男");
tool.information("头发是否浓密?",true);
tool.information("是否是个憨批?",false);
}
public <M> void information(M m1,M m2){
System.out.println(m1+":"+m2);
}
运行结果:
当我们将方法定义成泛型方法,我们就可以向该方法中传递任意类型的参数了。
类结构是面向对象中最基本的元素,如果我们的类需要有很好的扩展性,那么我们可以将其设置成泛型类。
泛型类Demo代码示例:
定义泛型实体类:
//定义泛型实体类,泛型中所指定的内容需要是引用类型 //此处O可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型 //在实例化泛型类时,必须指定O的具体类型 public class ObjectTool <O>{ //这个name成员变量的类型为O,O的类型由外部调用指定 private O name; private O age; //泛型方法getObj的返回值类型为O,O的类型由外部调用指定 public O getName() { return name; } //泛型构造方法形参obj的类型也为O,O的类型由外部调用指定 public void setName(O name) { this.name = name; } //泛型方法getObj的返回值类型为O,O的类型由外部调用指定 public O getAge() { return age; } //泛型构造方法形参obj的类型也为O,O的类型由外部调用指定 public void setAge(O age) { this.age = age; } }
实现测试类:
public class ObjectToolText { public static void main(String[] args) { ObjectTool<String> objectTool = new ObjectTool<String>(); objectTool.setName("李磊"); ObjectTool<Integer> objectTool1 = new ObjectTool<Integer>(); objectTool1.setAge(23); System.out.println("姓名:"+objectTool.getName()+","+"年龄:"+objectTool1.getAge()); //可以看出实例化泛型类之后,会根据给对象定义的泛型来定义调用方法时参数的类型 } }
运行结果:
我们使用泛型接口定义接口实现类时,通常会出现两个状况
Demo代码示例:
/* * 定义泛型接口:把泛型定义在接口上 */ public interface Inter<T> { public abstract void show(T t); } -------------------------------------------------- //实现类在实现接口的时候,我们会遇到两种情况 //第一种情况:已经知道是什么类型的了 public class InterImpl implements Inter<String> { @Override public void show(String t) { System.out.println(t); } } //第二种情况:还不知道是什么类型的 //这里需要注意,当实现泛型接口时,需要在类名和实现的接口名后面将泛型添上, //实现类中添加的泛型不需要和接口的泛型一样,可以是自定义的随便搞,但是这两个泛型名需要是相同的 public class InterImpl<T> implements Inter<T> { @Override public void show(T t) { System.out.println(t); } } ------------------------------------------ public class InterDemo { public static void main(String[] args) { // 第一种情况的测试 Inter<String> i = new InterImpl(); i.show("hello"); // 第二种情况的测试 Inter<String> i = new InterImpl<String>(); i.show("hello"); Inter<Integer> ii = new InterImpl<Integer>(); ii.show(100); } }
常用的通配符有: T,E,K,V,?
T,E,K,V,? 的约定如下:
T:(type) 表示具体的一个java类型。
E:代表Element。
K、V :分别代表java键值中的Key Value。
? :无界通配符,表示不确定的 java 类型
Demo代码示例:
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>();//报错 // ?表示任意的类型都是可以的,变相的等于 Object 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 { }
通过代码可知:
集合前面的泛型类型指定为无界通配符时,后面的泛型指定可以为任意类型。
当在集合前面使用下边界限定通配符时,后面的泛型指定就只能是父类本身和继承该类的向下子类。
当在集合前面使用上边界限定通配符时,后面的泛型指定就只能是当前指定类本身和其父类,直至向上祖类。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。