泛型
泛型的引出
java
public class pra {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add("java");
arrayList.add("jack");
arrayList.add("jom");
arrayList.add(new a());
for (Object obj :arrayList) {
String str = (String)obj;
System.out.println(str);
}
}
}
class a{
public a() {
}
}由于添加了 a 对象,但是在遍历的时候遍历的是字符串对象,这个时候就会抛出 ClassCastException 异常
问题分析
(1)不能对加入到集合 ArrayList 中的数据类型进行约束(不安全)
(2)遍历的时候需要进行数据类型转换,如果集合的数据量大,对显效率有影响
泛型优势
由于集合中添加的对象,当集合中的对象不为同一类对象时,遍历集合就会出现异常,这个时候可以通过泛型来约束集合存储的对象类型
基本介绍
(1)泛型又称参数化类型,是 Jdk5.0 出现的新特性,解决数据类型的安全性问题
(2)在类声明或实例化时,需要指定好需要的具体的类型
(3)Java 泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生 ClassCastException 异常。同时,代码更加简洁、健壮
(4)泛型的作用:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型
(5)泛型的理解:是一种表示数据类型的数据类型
(6)泛型的优点
1. 编译时,检查添加元素的类型,提高了安全性
2. 减少了类型转换的次数,提高效率
3. 不再提示编译警告
泛型的使用
基本语法
T、K、V 不代表值(可以替换成其他任意字母),而是表示一种数据类型
单例集合
java
ArrayList<T> arrylist = new ArrayList<T>()双例集合
java
HashMap<K,V> arrylist = new HashMap<K,V>()⭐ 推荐写法
java
ArrayList<String> arrylist = new ArrayList<>()应用场景
类
类中可以有多个泛型变量
java
class 类 <K,T....>{
}接口
java
interface 接口名<T>{
}使用细节
(1)泛型变量只能是引用类型
错误案例:List<int> list = new ArrayList<int>()
(2)如果不写泛型默认是 Object 类型,下方的两条语句等价
java
ArrayList list = new ArrayList();
ArrayList<Object> list = new ArrayList<>()(3)泛型指定具体类型后,可以传入该类型或者其子类型
java
public class pra {
public static void main(String[] args) {
animal<a> a = new animal<a>(new a());
animal<a> b = new animal<a>(new b());
}
}
class a{
}
class b extends a{
}
class animal<T>{
T e;
// 构造器
public animal(T e){
this.e = e;
}
public void getclass(){
System.out.println(e.getClass());
}
}代码分析
指定了 animal 类只能存储 a 类对象,但是 b 类是 a 的子类,即 animal 类既可以是 a 对象也可以是 b 对象
代码示例
java
public class pra {
public static void main(String[] args) {
HashMap<String,student> hashMap = new HashMap<>();
hashMap.put("18",new student("jackson"));
hashMap.put("20",new student("jack"));
hashMap.put("23",new student("jom"));
// 先取出entryset
Set<Map.Entry<String, student>> entries = hashMap.entrySet();
// 构建迭代器(指向单例集合)
Iterator<Map.Entry<String, student>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, student> next = iterator.next();
System.out.println("key:" + next.getKey() + " value:" + next.getValue());
}
}
}
class student{
String name;
public student(String name) {
this.name = name;
}
@Override
public String toString() {
return "student{" +
"name='" + name + '\'' +
'}';
}
}自定义泛型类
基本介绍
(1) 普通成员可以使用泛型(属性、方法)
(2) 使用泛型的数组,不能初始化(由于不知道数组的类型,无法在内存开辟空间)
(3) 静态方法中不能使用泛型
因为静态是和类相关的,在类加载时,对象还没有创建
如果静态方法和静态属性使用了泛型,JVM 就无法完成初始化
(4) 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
(5) 如果在创建对象时,没有指定类型,默认为 Object
(6)泛型是标识符,需要大写
类结构
java
class a<T,K,V...>{
T age;
K name;
V phone_number;
...
}自定义泛型接口
基本介绍
(1) 接口中,静态成员也不能使用泛型
(2)在继承接口或者实现接口时确定泛型接口的类型
(3)如果没有指定类型,默认为 Object
(4)如果一个类实现了泛型接口,则类中实现接口的方法需要需要指定接口方法中的泛型类型
可能是返回值类型或者是方法参数类型使用了泛型
代码示例
java
public class pra {
public static void main(String[] args) {
}
}
interface a<T,R>{
// 接口中的变量默认是静态的,需要赋初值
void hi(T t,R r);
void pay(T t,R r);
void run(T t,R r);
}
class b implements a<String,Double>{
@Override
public void hi(String s, Double aDouble) {
}
@Override
public void pay(String s, Double aDouble) {
}
@Override
public void run(String s, Double aDouble) {
}
}代码分析
通过指定泛型的类型来实现接口中的方法
自定义泛型方法
java
public T hi(V a, K b){
// 方法体
}(1)泛型方法可定义在普通类或泛型类中,实体信息为泛型方法的定义位置相关内容
(2)泛型方法在调用时确定类型(通过传入的参数自动判断是什么类型)
(3)若修饰符后无 <T,R...> ,像 public void eat(E e) { } 不是泛型方法,只是方法参数使用了泛型
泛型的继承和通配符
(1)泛型不具备继承性
错误案例:List<Object> list = new ArrayList<String>()
