1-泛型的介绍
1.1 泛型的介绍
-
泛型是一种类型参数,专门用来保存类型用的
-
最早接触泛型是在ArrayList<E>,这个E就是所谓的泛型了。使用ArrayList时,只要给E指定某一个类型,里面所有用到泛型的地方都会被指定对应的类型
-
1.2 使用泛型的好处
-
不用泛型带来的问题
-
集合若不指定泛型,默认就是Object。存储的元素类型自动提升为Object类型。获取元素时得到的都是Object,若要调用特有方法需要转型,给我们编程带来麻烦.
-
-
使用泛型带来的好处
-
可以在编译时就对类型做判断,避免不必要的类型转换操作,精简代码,也避免了因为类型转换导致的代码异常
-
//泛型没有指定类型,默认就是Object
ArrayList list = new ArrayList();
list.add("Hello");
list.add("World");
list.add(100);
list.add(false);
//集合中的数据就比较混乱,会给获取数据带来麻烦
for (Object obj : list) {
String str = (String) obj;
//当遍历到非String类型数据,就会报异常出错
System.out.println(str + "长度为:" + str.length());
}
1.3 泛型的注意事项
-
泛型在代码运行时,泛型会被擦除。
- 泛型只在编译时期限定数据的类型 , 在运行时期会被擦除
1.4 自定义泛型类
-
当一个类定义其属性的时候,不确定具体是什么类型时,就可以使用泛型表示该属性的类型
-
定义的格式
-
在类型名后面加上一对尖括号,里面定义泛型。一般使用一个英文大写字母表示,如果有多个泛型使用逗号分隔
-
public class 类名<泛型名>{ ... }
-
-
泛型的确定
-
当创建此泛型类是 , 确定泛型类中泛型的具体数据类型
-
-
练习
import java.time.Period; /* 需求 : 定义一个人类,定义一个属性表示爱好,但是具体爱好是什么不清楚,可能是游泳,乒乓,篮球。 */ public class GenericityDemo { public static void main(String[] args) { Person<BasketBall> person = new Person<>(); person.setHobby(new BasketBall()); Person<Swim> person2 = new Person<>(); person2.setHobby(new Swim()); Person person3 = new Person<>();// 如果没有指定泛型 , 那么默认使用Object数据类型 } } class Person<H> { // 定义属性表达爱好 private H hobby; public H getHobby() { return hobby; } public void setHobby(H hobby) { this.hobby = hobby; } } class Swim { } class PingPang { } class BasketBall { }
1.5自定义泛型接口
-
当定义接口时,内部方法中其参数类型,返回值类型不确定时,就可以使用泛型替代了。
-
定义泛型接口
-
在接口后面加一对尖括号 , 尖括号中定义泛型 , 一般使用大写字母表示, 多个泛型用逗号分隔
-
public interface<泛型名> { ... }
-
举例 :
public interface Collection<E>{ public boolean add(E e); } //,表示这是一个向集合中添加元素的方法。 参数:E e,表示这个方法接受一个类型为 E 的参数 e,即要添加到集合中的元素。
-
泛型的确定
-
实现类去指定泛型接口的泛型
-
实现了不去指定泛型接口的泛型 , 进行延续泛型 , 回到泛型类的使用
-
-
举例
-
/*
需求:
模拟一个Collection接口,表示集合,集合操作的数据不确定。
定义一个接口MyCollection具体表示。
*/
// 泛型接口
public interface MyCollection<E> {
// 添加功能
public abstract void add(E e);
// 删除功能
public abstract void remove(E e);
}
// 指定泛型的第一种方式 : 让实现类去指定接口的泛型
class MyCollectionImpl1 implements MyCollection<String>{
@Override
public void add(String s) {
}
@Override
public void remove(String s) {
}
}
// 指定泛型的第二种方式 : 实现类不确定泛型,延续泛型,回到泛型类的使用
class MyCollectionImpl2<E> implements MyCollection<E>{
@Override
public void add(E a) {
}
@Override
public void remove(E a) {
}
}
1.6 自定义泛型方法
-
当定义方法时,方法中参数类型,返回值类型不确定时,就可以使用泛型替代了
-
泛型方法的定义
-
可以在方法的返回值类型前定义泛型
-
格式 : public <泛型名> 返回值类型 方法名(参数列表){ ... }
-
举例 : public <T> void show(T t) { ... }
-
-
泛型的确定
-
当调用一个泛型方法 , 传入的参数是什么类型, 那么泛型就会被确定
-
-
举例
-
package com.lizhiwei.fangfa; import java.util.ArrayList; public class Test { public static void main(String[] args) { // 创建一个 ArrayList 对象,指定泛型类型为 String ArrayList<String> stringList = new ArrayList<>(); // 使用 addElement 方法向 stringList 中添加三个字符串元素 addElement(stringList, "Hello", "World", "Java"); // 打印 stringList 内容 System.out.println("String List: " + stringList); // 创建一个 ArrayList 对象,指定泛型类型为 Integer ArrayList<Integer> intList = new ArrayList<>(); // 使用 addElement 方法向 intList 中添加三个整数元素 addElement(intList, 1, 2, 3); // 打印 intList 内容 System.out.println("Integer List: " + intList); } // 定义一个泛型方法,向 ArrayList 中添加三个元素 public static <X> void addElement(ArrayList<X> list, X x1, X x2, X x3) { list.add(x1); list.add(x2); list.add(x3); } }
1.7 通配符
-
当我们对泛型的类型确定不了,而是表达的可以是任意类型,可以使用泛型通配符给定
符号就是一个问号:? 表示任意类型,用来给泛型指定的一种通配值。如下
public static void shuffle(List<?> list){ //… } 说明:该方法时来自工具类Collections中的一个方法,用来对存储任意类型数据的List集合进行乱序
-
泛型通配符结合集合使用
-
泛型通配符搭配集合使用一般在方法的参数中比较常见。在集合中泛型是不支持多态的,如果为了匹配任意类型,我们就会使用泛型通配符了。
-
方法中的参数是一个集合,集合如果携带了通配符,要特别注意如下
-
集合的类型会提升为Object类型
-
方法中的参数是一个集合,集合如果携带了通配符,那么此集合不能进行添加和修改操作 , 可以删除和获取
-
-
1.8 受限泛型
-
受限泛型是指,在使用通配符的过程中 , 对泛型做了约束,给泛型指定类型时,只能是某个类型父类型或者子类型
-
分类 :
-
泛型的下限 :
-
<? super 类型> //只能是某一类型,及其父类型,其他类型不支持
-
-
泛型的上限 :
-
<? extends 类型> //只能是某一个类型,及其子类型,其他类型不支持
-
-