一.对泛型的理解:
1.泛型,从字面意思上来说指的是广泛的类型,很多的类型。同时也是它的设计理念,
设计者希望创造容器,可以存放各种基类或者自定义类的对象的容器。
下面通过一些简单的代码来理解泛型:
public class Robot{
private int a;
public Robot(int a) {
this.a = a;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
如上,Robot这个类只能持有整型对象a,而没有办法持有其他对象,这样的代码重用性就很不好,举个例子:在不添加其他属性的前提下,假如我们既需要整形对象1314,又需要字符串对象"一生一世",再编写新的类会增加工作量,并且我们不能为每个类型都 编写一个类,(像这样的例子有很多,比如地球的经度和纬度,根据需求不同,简单一点描述可以用int,要精确一点可以用float,甚至可以加上语言描述用字符串,同样是经纬度这个属性,我们不能再定义其它变量吧)在使用泛型之前,我们一般用Object类来解决这个问题:
public class Robot{
private Object a;
public Robot(Object a) {
this.a = a;
}
public Object getA() {
return a;
}
public void setA(Object a) {
this.a = a;
}
public static void main(String[] args) {
Robot r1=new Robot(1314);
int number=(Integer)r1.getA();//需要向上转型
Robot r2=new Robot("一生一世");
String str= (String) r2.getA();//转型
System.out.println(number+str);
}
}
使用Object需要转型,并且也容易出现一些转型错误,比如把
int number=(Integer)r1.getA();//需要向上转型
改为:
String number=(String)r1.getA();
这个代码写好后也是可以运行的,不会提示错误,但在运行的时候会提示类型转换错误
因此,使用Object安全性不高,使用泛型可以很好的解决这一问题:
public class Robot<T>{
private T a;
public Robot(T a) {
this.a = a;
}
public T getA() {
return a;
}
public void setA(T a) {
this.a = a;
}
public static void main(String[] args) {
Robot<Integer> r1=new Robot<Integer>(1314);
Integer a1 = r1.getA();//不需要转型了
Robot<String> r2=new Robot<String>("一生一世");
String a2 = r2.getA();//不需要转型了
System.out.println(a1+a2);
}
}
在我们创建类的时候,往往不能够确定要具体使用哪一个类或者使用几种类,而是要到使用的时候才知道,这个时候就很适合使用泛型,使用时:只需要在尖括号中存入该类型。以上内容,概述了我们使用泛型的原因以及泛型类的简单使用。
二.泛型接口
泛型不止可以用于类,也可以用于接口,用法类似
interface 接口名称<泛型标识>{}//泛型接口格式
interface Usb<T>{//声明接口
public void read();
}
public class Robot<T> implements Usb<T>{//实现接口
private T a;
public Robot(T a) {
this.a = a;
}
public T getA() {
return a;
}
public void setA(T a) {
this.a = a;
}
public void read() {
}
public static void main(String[] args) {
Robot<String> r=new Robot("T45");
System.out.println(r.getA());
Robot<Integer> r1=new Robot<Integer>(1949);
System.out.println(r1.getA());
}
}
三.泛型方法:
访问权限<泛型标识>泛型标识 方法名(泛型标识 方法名称 )//泛型方法格式
class Method{
public <T>T read(T t){
return t;
}
}
public class Robot{
public static void main(String[] args) {
Method method=new Method();
String t = method.read("T60型");
System.out.println(t);
}
}
四.元组
return语句只允许返回单个对象,而我们通常需要一次方法返回多个对象,这个时候我们可以使用对象容器,元组。
元组:指的是把一组可以是任意类型的对象存储在一个容器中。
public class Robot<K,T>{
publicfinal K first;
public final T second;
public Robot(K first, T second) {
this.first = first;
this.second = second;
}
@Override
public String toString() {
return first+","+second;
}
public static void main(String[] args) {
Robot<Integer,String> robot=new Robot<Integer, String>(2039,"T60");
System.out.println(robot);
}
}
通过继承来实现长度更长的元组,元组可以有任意长度
class MoreRobot<K,T,E>extends Robot<K,T>{
public final E third;
public MoreRobot(K first, T second, E third) {
super(first, second);
this.third = third;
}
}
五.通配符:
来看一个使用通配符的例子:
class Root<T>{
private T red;
public Root(T red) {
this.red = red;
}
public T getRed() {
return red;
}
public void setRed(T red) {
this.red = red;
}
@Override
public String toString() {
return this.getRed().toString();
}
}
public class Robot{
public static void main(String[] args) {
Root<String> root=new Root<String>("红色T60系列");
System.out.println(root);
paint(root);
}
public static void paint(Root<?> root){//使用通配符
System.out.println("上色:"+root);
}
}
方法被创建时不能确定使用什么类型,使用通配符
六.擦除
java泛型是通过擦除来实现的,当使用泛型的时候,任何具体的类型都被擦除了,唯一知道的是在使用一个对象,通过下面的例子来理解:
public class Robot{
public static void main(String[] args) {
Class c1=new ArrayList<String>().getClass();
Class c2=new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
}
}
输出为true,程序会认为Arraylist和Arraylist是相同的类型,在运行时两种类型都被擦除成原生类型,Arraylist。擦除会删去类型参数后的泛型类型名,并且替换为限定类型,无限定则用Object,与之前直接用Object不同,泛型擦除后会自动进行类型转换。
擦除实现了泛型,同时也带来了很多限制和问题,如:不能实例化变量,不能构造泛型数组,不能用基本类型实例化类型参数,这些内容后续更新。