1 初识泛型
泛型是一种模板,它可以动态的基于类型上的更改。当我们需要重复的使用某一个类对象,但是我们使用的数据类型不同时,我们需要定义多个不同的类。这个时候我们希望有一个模板,它可以动态的基于不同的数据类型来生成不同的类,我们可以使用泛型来实现这一功能。
在没有泛型的概念时,我们可以想象ArrayList是这样工作的
class ObjectArrayLsit{
private Object[] array;
private int size;
public void add(Object e) {...}
public void remove(int index) {...}
public Object get(int index) {...}
}
当我们需要在数组传入不同参数时,使用强转强制转换成我们传入参数的类型。
但是这样会带来数据不安全的问题,所以我们需要为每一种类型来设置一种集合类型来保证数据安全。所以java有了泛型的概念。
public class ArrayLsit<T>{
private T[] array;
private int size;
public void add(T e) {...}
public void remove(int index) {...}
public T get(int index) {...}
}
这样我们只需要在传入参数时声明具体类型,那么这个类就只能传入指定的数据类型了。
ArrayList<String> list = new ArrayList<String>();
对于泛型的简单理解:
- 泛型是一种模板。
- 既然是模板,这个模板被指定类型使用并编译时,被编译的只是指定的类型。
- 它不存在虚拟机层次,而存在编译器层次,类似重载,编译器将它进行进一步的修饰,使之成为不同的对象类型。
- 在集合中ArrayList 和ArrayList没有任何关系。不再有父子关系。
- Java语言的泛型实现方式是擦拭法(Type Erasure)。
- 所谓擦拭法是指,虚拟机对泛型其实一无所知,所有的工作都是编译器做的。
2 自定义泛型
我们有这么一个普通类,它的属性和返回值都是String类型的。
public class Page{
private String size;
public Page(String szie){
this.size = size;
}
private void setName(String size){
this size = size;
}
private String getName(){
return this.size
}
}
可以将它改造成泛型,是任何类型的参数它都可以传入
public class Page<T>{
private T size;
public Page(T szie){
this.size = size;
}
private void setName(T size){
this size = size;
}
private T getName(){
return this.size
}
}
注意
- 静态方法不能使用泛型。
3 多种类型泛型
我们有时候希望能够实现传入多个不同类型的参数,就像map一样,泛型也提供了这样的方法供我们使用。
class Page<T, K>{
private T fist;
private K last;
Page(T fist, K last){
this.fist = fist;
this.last = last;
}
public T getFist() {...}
public void setFist(T fist) {...}
public K getLast() {...}
public void setLast(K last) {...}
}
使用的时候定义它的类型即可使用
Page<Integer, String> page = new Page<>(18,"张三");
System.out.println(page.getFist()+"---"+page.getLast());
4 集合中的泛型
在集合中,一般不使用来表示泛型,而是使用的标识,因为Eelement代表集合元素。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
5 extends通配符
在之前中,我们说ArrayList与ArrayList不再有父子关系,但是继承时Java的三大特性之一,所以泛型也提供了一种方法来实现伪继承。即使用extends通配符。
Page<? extends Object> page = new Page<>(12,"hello");
System.out.println(page.getFist()+"---"+page.getLast());
- 这样的一个方式,使得我们可以传入所有Object的子类对象,并且可以使用它的get方法获得它的属性值。
- 但是我们无法调用它的set方法完成属性值的修改。
6 super通配符
通过extends通配符声明的类型虽然可以完成不同属性值的设置以及获取,但是无法完成属性值的修改,泛型提供了另一种通配符来为我们提供属性值的修改功能。
Page<? super Object> page = new Page<>(12,"hello");
System.out.println(page.getFist()+"---"+page.getLast());
page.setFist(10000);
System.out.println(page.getFist()+"---"+page.getLast());
- 和extends相对应的是,我们只能用super之后的类型来接受get参数。
- super和extends这两个通配符应该根据不同情况来使用。
很多东西都是看了学习网站的教程之后理解的,讲的真的是太好了廖雪峰学泛型