1.什么是泛型
Java中的参数化类型被称为泛型。也就是在类定义的时候不会设置类中的属性或方法中的参数的具体类型,而是在使用时再进行定义。
- 泛型:标签
- 举例:中药店每个抽屉外面贴着标签;垃圾分类的垃圾桶
2.为什么要有泛型呢,直接Object不也是可以存储数据么?
- 解决元素存储安全性问题,好比商品、药品标签,不会弄错
- 解决获取数据元素时,需要类型强制转换的问题,好比每回不用拿商品、药品都要辨别
public class GenericTest {
@Test
//在集合中使用泛型之前的情况
public void test1() {
ArrayList list = new ArrayList();
//需求:存放学生的成绩
list.add(88);
list.add(78);
//问题一:类型不安全
list.add("Tom");
for (Object score : list) {
//问题二:强转时,可能会出现ClassCastException
int stuScore = (int) score;
System.out.println(stuScore);
}
}
@Test
//在集合中使用泛型的情况
public void test2() {
ArrayList<Integer> list = new ArrayList<>();
//需求:存放学生的成绩
list.add(88);
list.add(78);
//解决一:编译时进行类型检查
//list.add("Tom");
for (Integer score : list) {
//解决二:避免强转,进而不会出现类型转换异常
int stuScore = score;
System.out.println(stuScore);
}
}
}
总结:
- 集合接口或集合类在jdk5.0时都修改为带泛型的结构
- 在实例化集合时,可以指明具体的泛型类型
- 在指明完以后,在集合类或接口中凡是定义类或接口时,内部结构使用到类的泛型的位置都指定为实例化的泛型类型,比如:add(E e)----->实例化以后:add(Integer e)
- 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
- 如果实例化时,没有指明泛型的类型为java.lang.Object类型
3.如何自定义泛型结构:泛型类、泛型接口、泛型方法
/**
*定义泛型类
*/
class MyClass<T>{
T value;
}
/**
*使用泛型类
*/
MyClass<String> myclass = new MyClass<String>();
泛型只能接受类,所有的基本数据类型必须使用包装类。
/**
*定义泛型方法
*/
class MyClass{
public <T> void testMethod(T t){
System.out.println(t);
}
}
//第一个T:类型参数
//第二个T:参数化类型
泛型类与泛型方法是可以共存的,泛型类中的类型参数与泛型方法中的类型参数是没有相应的联系的,泛型方法始终以自己定义的类型参数为准。
4.增强for
import java.util.ArrayList;
import java.util.Collection;
public class Test {
public static void main(String[] args) {
//创建集合对象
Collection<String> c = new ArrayList<String>();
//添加元素
c.add("hello");
c.add("world");
c.add("java");
//遍历集合对象
for (String s : c) {
c.add("android");//在遍历中修改元素
System.out.println(s);
}
}
}
增强for循环是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。
格式:
for(元素的数据类型 变量 : Collection集合or数组){
}
5.通配符
作用:解决参数的统一问题
- ?extends 类:设置泛型上限,唯一能作用到类上。
例如:?extends Number,表示只能够设置Number或其子类,例如Integer、Double等。 - ?super String:设置泛型下限。
例如:?super String,表示只能够设置String及其父类Object
上限可以用在声明,不能修改;而下限只能用在方法参数,可以修改内容
6.泛型接口
interface IMessage<T>{
public void print(T,t);
}
实现子类:
①在子类定义时继续使用泛型
class MessageImpl<T> implements IMessage<T>{}
②在子类实现接口的时候明确给出具体类型
class MessageImpl implements IMessage<String>{}
7.类型擦出
泛型信息只存在于代码编译阶段,在进入JVM前,与泛型相关的信息会被擦出掉,专业术语叫做类型擦出。也就是说泛型类和普通类在JVM中没有什么特别的地方。
在泛型类被类型擦出的时候,之前泛型类中的类型参数部分如果没有指定上限,如则会被转译成普通的Object类型,如果指定了上限如则类型参数就会被替换成类型上限。