泛型基础【介绍泛型、泛型类、泛型方法、通配符、擦除】
什么是泛型?
Java泛型设计原则:只要在编译时期没有出现警告,那么运行时期就不会出现ClassCastException异常
泛型:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型
参数化类型:
- 把类型当作是参数一样传递
- <数据类型> 只能是引用类型
相关术语:
ArrayList<E>
中的E称为类型参数变量ArrayList<Integer>
中的Integer称为实际类型参数- 整个称为
ArrayList<E>
泛型类型 - 整个
ArrayList<Integer>
称为参数化的类型ParameterizedType
为什么需要泛型
早期Java是使用Object来代表任意类型的,但是向下转型有强转的问题,这样程序就不太安全
首先,我们来试想一下:没有泛型,集合会怎么样
- Collection、Map集合对元素的类型是没有任何限制的。本来我的Collection集合装载的是全部的Dog对象,但是外边把Cat对象存储到集合中,是没有任何语法错误的。
- 把对象扔进集合中,集合是不知道元素的类型是什么的,仅仅知道是Object。因此在get()的时候,返回的是Object。外边获取该对象,还需要强制转换
有了泛型以后:
- 代码更加简洁【不用强制转换】
- 程序更加健壮【只要编译时期没有警告,那么运行时期就不会出现ClassCastException异常】
- 可读性和稳定性【在编写集合的时候,就限定了类型】
使用增强for遍历集合
在创建集合的时候,我们明确了集合的类型了,所以我们可以使用增强for来遍历集合!
//创建集合对象
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
//遍历,由于明确了类型.我们可以增强for
for (String s : list) {
System.out.println(s);
}
基础
泛型类
泛型类就是把泛型定义在类上,用户使用该类的时候,才把类型明确下来….这样的话,用户明确了什么类型,该类就代表着什么类型…用户在使用的时候就不用担心强转的问题,运行时转换异常的问题了。
在类上定义的泛型,在类的方法中也可以使用!
/ 1:把泛型定义在类上 2:类型变量定义在类上,方法中也可以使用 /
public class ObjectTool{ private T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
测试代码:
用户想要使用哪种类型,就在创建的时候指定类型。使用的时候,该类就会自动转换成用户想要使用的类型了。
public static void main(String[] args) {
//创建对象并指定元素类型
ObjectTool<String> tool = new ObjectTool<>();
tool.setObj(new String("钟福成"));
String s = tool.getObj();
System.out.println(s);
//创建对象并指定元素类型
ObjectTool<Integer> objectTool = new ObjectTool<>();
/** * 如果我在这个对象里传入的是String类型的,它在编译时期就通过不了了. */
objectTool.setObj(10);
int i = objectTool.getObj();
System.out.println(i);
}
泛型方法
前面已经介绍了泛型类了,在类上定义的泛型,在方法中也可以使用…..
现在呢,我们可能就仅仅在某一个方法上需要使用泛型….外界仅仅是关心该方法,不关心类其他的属性…这样的话,我们在整个类上定义泛型,未免就有些大题小作了。
定义泛型方法….泛型是先定义后使用的
//定义泛型方法..
public <T> void show(T t) {
System.out.println(t);
}
测试代码:
用户传递进来的是什么类型,返回值就是什么类型了
public static void main(String[] args) {
//创建对象
ObjectTool tool = new ObjectTool();
//调用方法,传入的参数是什么类型,返回值就是什么类型
tool.show("hello");
tool.show(12);
tool.show(12.5);
}
泛型类派生出的子类
前面我们已经定义了泛型类,泛型类是拥有泛型这个特性的类,它本质上还是一个Java类,那么它就可以被继承
那它是怎么被继承的呢??这里分两种情况
- 子类明确泛型类的类型参数变量
- 子类不明确泛型类的类型参数变量
子类明确泛型类的类型参数变量
泛型接口
/ 把泛型定义在接口上 /
public interface Inter{ public abstract void show(T t);
}
实现泛型接口的类…..
/* 子类明确泛型类的类型参数变量: */
public class InterImpl implements Inter
{ @Override
public void show(String s) {
System.out.println(s);
}
}
子类不明确泛型类的类型参数变量
当子类不明确泛型类的类型参数变量时,外界使用子类的时候,也需要传递类型参数变量进来,在实现类上需要定义出类型参数变量
/* 子类不明确泛型类的类型参数变量: 实现类也要定义出
类型的 */
public class InterImplimplements Inter { @Override
public void show(T t) {
System.out.println(t);
}
}
测试代码;
public static void main(String[] args) {
//测试第一种情况
//Inter<String> i = new InterImpl();
//i.show("hello");
//第二种情况测试
Inter<String> ii = new InterImpl<>();
ii.show("100");
}
值得注意的是:
- 实现类的要是重写父类的方法,返回值的类型是要和父类一样的!
- 类上声明的泛形只对非静态成员有效
类型通配符
为什么需要类型通配符????我们来看一个需求…….
现在有个需求:方法接收一个集合参数,遍历集合并把集合元素打印出来,怎么办?
按照我们没有学习泛型之前,我们可能会这样做:
public void test(List list){
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
上面的代码是正确的,只不过在编译的时候会出现警告,说没有确定集合元素的类型….这样是不优雅的…
那我们学习了泛型了,现在要怎么做呢??有的人可能会这样做:
public void test(List
还没有评论,来说两句吧...