看看下面程序例子(不使用泛型):java
public static void main(String[] args) { List list = new ArrayList(); list.add("zhangsan"); list.add("lisi"); list.add(102);//没有使用泛型,代码出现黄色警告 for(int i= 0; i < list.size();i++){ //list装载默认是Object类型,因为第三项装载Integer类型,因此在取对象时强制转换报错。 String name = (String) list.get(i); System.out.println(name); } }
出现以下错误:安全
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.java.test.genericity.GenericityMain.main(GenericityMain.java:40)架构因为list没有使用泛型,代码出现黄色警告,list装载默认是Object类型,因为第三项装载Integer类型,因此在取对象时强制转换报错。ide
List使用泛型带有String形参:this
public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("zhangsan"); list.add("lisi"); // list.add(102); 类型已经限定编译直接报错通不过,默认是String类型 for(int i= 0; i < list.size();i++){ String name = list.get(i); System.out.println(name); } }
此时list添加第三项数据直接编译报错,类型已经限定编译直接报错通不过,默认是String类型code
1:经过结合代码继承封装,减小Java代码重复冗余,使得代码的结构和架构更合理。
2:消除了强制类型转换 使得代码可读性好,减小了不少出错的机会。
3:Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,而且全部的强制转换都是自动和隐式的,这样编译器就能够在一个高的程度上验证这个类型。对象
- 自定义泛型类
- 自定义泛型接口
- 自定义泛型方法
- 了解泛型参数继承关系
/*** * @ClassName Car * @Description 定义泛型类 * * ***/ public class Car<M> { private M m; public void openCar(M m){ System.out.println("开车"); }; public M endCar(){ System.out.println("关车"); return m; } }
这里的M表示泛型形参,因为接收来自外部使用时候传入的类型实参。那么对于不一样传入的类型实参,生成的相应对象实例的类型是否是同样的呢?看以下例子:继承
Car<Person> pCar = new Car<Person>(); Car<Animal> aCar = new Car<Animal>(); System.out.println(pCar.getClass());//class com.java.test.genericity.Car System.out.println(aCar.getClass());//class com.java.test.genericity.Car System.out.println(aCar.getClass()== pCar.getClass());//true
看了以上例子,咱们能够发现,在使用泛型类时,虽然传入了不一样的泛型实参,但并无真正意义上生成不一样的类型,传入不一样泛型实参的泛型类在内存上只有一个,即仍是原来的最基本的类型(本实例中为Car),固然,在逻辑上咱们能够理解成多个不一样的泛型类型,在于Java中的泛型这一律念提出的目的,致使其只是做用于代码编译阶段,在编译过程当中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译事后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。接口
2:泛型接口,泛型接口和泛型类的使用差很少,其中T表示泛型参数:ip
public interface Map<T> { public void load(T t); }
实现泛型接口类的写法,传参形式以下:(在实现类实现泛型接口时,如已将泛型类型传入实参类型,则全部使用泛型的地方都要替换成传入的实参类型)
public class BaiduMap implements Map<String>{ @Override public void load(String t) { // TODO Auto-generated method stub } }
实现泛型接口类,不传形参写法以下:(不传形参,与泛型类的定义相同,在声明类的同时,须要将泛型的形参也一块儿加进去)
public class BaiduMap<T> implements Map<T>{ @Override public void load(T t) { // TODO Auto-generated method stub } }
3:泛型方法使用:(若是当前方法所在的Java类中没有定义T泛型参数,则在方法的前面声明泛型形参<T>)
public class BaiduMap implements Map<String>{ @Override public void load(String t) { } //若是当前方法所在的Java类中没有定义T泛型参数,则在方法的前面声明泛型形参<T> public <T> T getMethod(Class<T> czz) throws InstantiationException, IllegalAccessException{ T t = czz.newInstance(); return t; } }
区别泛型方法和泛型类方法:
//咱们在当前类中已经定义了T类型,下面load含有泛型参数,因此泛型T不是泛型方法 @Override public void load(T t) { } //咱们在当前方法中getMethod已经定义了M类型,下面getMethod含有泛型参数,全部getMethod是泛型方法 public <M> M getMethod(Class<M> czz) throws InstantiationException, IllegalAccessException{ M m = czz.newInstance(); return m; }
4:了解泛型的继承关系以及泛型参数的上下行边界:
//当前定义了一个类Car 约定了M形参继承Person类。 public class Car<M extends Person> { private M m; public void openCar(M m){ System.out.println("开车"); }; public M endCar(){ System.out.println("关车"); return m; } } public class Person { private String name; private String age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } } public class Man extends Person{ } public class Sedan extends Car<Man>{ @Override public void openCar(Man m) { // TODO Auto-generated method stub super.openCar(m); } @Override public Man endCar() { // TODO Auto-generated method stub return super.endCar(); } }
我定义了一个Car类,约束当前的形参M继承Person,此时我定义一个Man的类做为形参,继承了Person,Sedan类继承Car在Sedan类中我传递形参Man,正由于形参Man,重写方法openCar,endCar的参数才会显示Man参数,这样就约定了泛型的边界,使得子类传递的参数必须是泛型约定的参数。