java泛型
来源:互联网 发布:阿里云ecs绑定几个域名 编辑:程序博客网 时间:2024/06/05 09:04
一、泛型的最大价值
经常出现同一个算法适合几种数据类型,为了编写通用的算法,我们使用泛型。
也就是在保证类型安全的前提下,把算法和数据类型解耦。
二、泛型类
public class Person<T> {private T t;public Person(T t){this.t = t;}public String toString(){return "参数的类型是:" + t.getClass().getCanonicalName();}
子类怎么继承父类的T呢
public class Teacher<T,S> extends Person<T> {protected T t;private S s;public Teacher(T t) {super(t);}public void set(V v, S s){this.v = v;this.s = s;}
泛型类怎么调用
public class Generics {public static void main(String[] args){Person<Integer> p = new Person<Integer>(5);System.out.print(p.toString());}}
三、泛型接口
public interface Factory<T> {public T create();}
具体实现:
public class Car {}public class Computer {}public class CarFacotry implements Factory<Car> {@Overridepublic Car create() {System.out.println("装载发动机!");System.out.println("装载座椅!");System.out.println("装载轮子!");return new Car();}}public class ComputerFactory implements Factory<Computer> {@Overridepublic Computer create() {System.out.println("装载主板!");System.out.println("装载CPU!");System.out.println("装载内存");return new Computer();}}
调用:
public class GenericTest {public static void main(String[] args) throws Exception{Factory<Car> carFactory = new CarFacotry();Factory<Computer> computerFactory = new ComputerFactory();System.out.println("======开始生产车子!=======");carFactory.create();System.out.println("=====开始生产电脑!========");computerFactory.create();}}
四、泛型方法
泛型方法是在方法上声明类型参数,该类型参数只可以作用于声明它的方法上
public class Factory {public <T> T generator (Class<T> t) throws Exception{return t.newInstance();}}
调用:
public class Teacher{public static void main(String[] args) throws Exception{Factory factory = new Factory();Date date = factory.generator(Date.class);System.out.print(date.toString());}}
五、泛型边界
1)通配符类型,表示任何类型,符号是“?”
2)<? extends A> ,设定上行边界,限定传入的具体参数类型,只能是A的子类或A
3)<? super A>,设定下行边界,限定传入的具体参数类型,只能是A的父类或A
4)例子:
public class Animal {}public class Bird extends Animal {}public class Fish extends Animal {}public class Zoo<T> {private T t;public Zoo(T t){this.t = t;}public T pop(){return this.t;}}
调用:
public class GenericTest {public static void main(String[] args) throws Exception{Zoo<? extends Animal> zoo = new Zoo<Bird>(new Bird());zoo = new Zoo<Fish>(new Fish());//zoo = new Zoo<Integer>(5); //不合法}Zoo<? super Bird> zoo1 = new Zoo<Bird>(new Bird());zoo1 = new Zoo<Animal>(new Animal());//zoo1 = new Zoo<Fish>(new Fish()); //不合法
5)多边界的泛型
<T extends Speakable&Flyable>,要求T是实现了Speakable和Flyable这两个接口的类
六、泛型擦除
1)泛型只存在语法层次,一旦编译后,就不存在
当泛型存在于编译时,一旦被确认安全使用时,就会将其转换为原生类型也就是擦除成原生类型
2)为什么要擦除
擦除后,泛型变成原生类型,使泛化的代码可以使用非泛化的类库
3)擦除的实质
将原有的类型参数替换成非泛化的上界
例子:
public class Computer<E> { private E e; public Cmputer(E e){ this.e=e;} public E apply(){ return this.e; }}
编译后:
public class Computer { private Object e; public Computer(Object e){ this.e=e;} public Object apply(){ return e; }}因为Computer<E>没有指明上界,所以被擦除成Object类型
4)多边界擦除
<T extends Speakable&Flyable>,选择排在前面的边界进行参数替换,这里是Speakable。。换下位置就是Flyable
七、泛型的限制和问题
1)为了保证类型安全,不能使用泛型类型参数创建实例
/ /不合法 T object=new T();
因为运行时参数类型已经被擦除了,不知道T到底是什么类型,有没有无参构造方法,或者可能是个抽象类,不能实例化2)
不能声明泛型实例数组,这会导致运行错误
//不合法 T[] number= new T[capcity];
但可以通过创建一个Object类型数组然后将它的类型转换E[]来规避这个限制。
E[] number= (E[])new Object[capcity];
4)泛型类对象无法被抛出或捕获,因为泛型类不能继承或实现Throwable接口及其子类
这句话不要理解错了,不要以为不可以try-catch和throws,他们都是可以的,只不过不能下面这样
try{
}catch(T t) // 正常情况下是catch(Exception e)
public class GenericException<T> extends Exception{}
原因是什么,上面说的很清楚了,看加粗字体
5)instanceof 不起作用
Zoo<Fish> birdZoo = new Zoo<Fish>();if(birdZoo instanceof Zoo<Bird>){...} //这个if一定会是true的,原因是擦除了,都是Zoo类型
那有没有能起作用的地方呢?有
Zoo<Bird> birdZoo = new Zoo<Bird>();if(birdZoo instanceof Zoo<?>){...} //这里的if就不会总是true了,因为instanceof判断允许使用参数类型为通配符的泛型
6)多态冲突
例子:
public class Animal<T> {public void set(T t){//泛型擦除后,就变成了 set(Object t)System.out.println("1111");}}public class Bird extends Animal<String>{public void set(String name){//按理来说,这个方法应该是重写,但是由于擦除的原因,父类中此方法的参数是Object,//而这里是String,所以不构成重写,对多态是个影响super.set(name);//但是这句话还是能调用成功的}}
调用:
public class Test {public static void main(String[] args) {Bird bird = new Bird();Animal<String> animal = bird;animal.set("bird");}}
怎么解决多态冲突呢?JVM会自动生成桥方法,不用程序员自己写
public void set(Object obj){//这个例子中,这个桥方法是生成在Bird类里面的。set((String)obj);}
再来个例子
public class Animal<T> {public T get(){System.out.println("Animal get");return null;}}public class Bird extends Animal<String>{public String get(){System.out.println("Bird get");return null;}}
调用:
public class Test {public static void main(String[] args) {Bird bird = new Bird();Animal<String> animal = bird;animal.get();}}输出结果是:Bird get
这里就有个疑问了,Bird的桥方法 Object get()与本来就有的方法 String get(),只是返回值不同,java中不是不准这样的吗?
原因是这是在JVM中,而JVM确定一个方法还要根据返回值
- 【java 2】java泛型
- Java 泛型 Java generic
- Java Tutorials_Generics(java泛型)
- Java基础 Java 泛型
- java 泛型
- java泛型
- Java泛型
- Java泛型
- java泛型
- java泛型
- java泛型
- Java 泛型
- Java泛型
- Java 泛型
- JAVA 泛型
- java 泛型
- java泛型
- Java泛型
- 一台电脑同时运行多个tomcat配置方法
- hibernate-日常小计 原生sql 返回map
- 【SQL】连接(二):左连接
- 遇到request.getParameter()获取空值
- 每日订单号从0001开始
- java泛型
- BMapLib.DrawingManager
- 大型网站架构演化历程
- POJ
- bootscrap+angular+ssm整合(上)
- Python图表绘制:matplotlib绘图库入门
- 下面讲解 padding和margin常用的用法
- Net::ERR_INCOMPLETE_CHUNKED_ENCODING问题跟踪
- C++多线程--2017-7-21