泛型
泛型
参考视频: BV1xJ411n77R
应用场景
- 同一方法可以:
- 产生不同类型的实例对象(返回对象引用)
- 书写不同类型的泛型方法
- 接收不同类型的传入参数(输入对象引用)
- 抽象(字面意义的)地继承
- 同一接口可以:
- 产生不同类型的方法实现
上面是我自己总结的,描述的范围肯定有问题,不要拿去当做参考
格式
为了代码简洁,统一使用无参构造
常用的泛型缩写
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(表示Java 类,包括基本的类和我们自定义的类)
- K - Key(表示键,比如Map中的key)
- V - Value(表示值)
- N - Number(表示数值类型)
- ? - (表示不确定的java类型)本文后面提到的通配
- S、U、V - 2nd、3rd、4th types
案例
类:
public class GenericTest<T> {
private T t;
public T getT(){
return t;
}
}
类继承:
- 非泛型类(必须要指明继承的父类的明确类型)
class GenericChild extends GenericTest<String> {
}
- 泛型类(声明时泛型名与父类一样就行)
- 当然子类也可以拓展泛型列表
class GenericAnotherChild<E, K> extends GenericTest<E>{
private K k;
public K getK() {
return k;
}
public void setK(K k) {
this.k = k;
}
}
接口
public interface GenericInterface<T> {
T printSomething();
}
类实现泛型接口:
- 泛型类实现泛型接口
- 泛型类也可以扩充泛型列表,这里为了保持间接不做赘述
- 必须保证泛型类包括接口的泛型
public class GenericTest<T> implements GenericInterface<T>{
private T t;
@Override
public T printSomething() {
return (t);
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
实例化
GenericTest<Integer> stringGenericTest = new GenericTest<>()
左右两侧类名后紧跟<> 并且右侧的不需要写
测试案例
上述代码的分别实例化:
public class Application {
public static void main(String[] args) {
// 继承泛型接口的泛型类
GenericTest<Integer> stringGenericTest = new GenericTest<>();
stringGenericTest.setT(1);
Integer s = stringGenericTest.printSomething();
System.out.println(s + "\t"+ s.getClass().getSimpleName());
System.out.println("--------------------");
// 继承泛型类的子类
GenericChild genericChild = new GenericChild();
genericChild.setT("Child");
String s1 = genericChild.printSomething();
System.out.println(s1 + "\t" + s1.getClass().getSimpleName());
System.out.println("--------------------");
// 继承泛型类的泛型子类
GenericAnotherChild<String, Integer> stringIntegerGenericAnotherChild = new GenericAnotherChild<>();
stringIntegerGenericAnotherChild.setK(10);
stringIntegerGenericAnotherChild.setT("Number");
String t = stringIntegerGenericAnotherChild.getT();
Integer k = stringIntegerGenericAnotherChild.getK();
System.out.println("t=" + t + "\t" + "K=" + k);
}
}
STDOUT
1 Integer
--------------------
Child String
--------------------
t=Number K=10
类型通配符
是什么
用?问号代替具体的类型实参
能够代表任一类型
(目前来看用于创建方法时,面对泛型对象时出现的无法重载方法的问题)
案例
第一种使用类型通配符,第二种不使用通配符
- 使用类型通配符
- 此时IDEA不会标黄,推测是正式的写法
- 注意此时接收或者处理传递的对象 genericTest时,应该按照Object来处理
public static void showData2nd(GenericTest<?> genericTest) {
Object data = genericTest.getT();
System.out.println(data);
}
- 不适用通配符
- 和上面一样,IDEA没有报错但是传递类型
GenericTest
标黄 - 提示
Raw use of parameterized class 'GenericTest'
- 推测是不规范的写法,但是也依旧可以用
- 和上面一样,IDEA没有报错但是传递类型
public static void showData(GenericTest generictest){
Object data = generictest.getT();
System.out.println(data);
}
类型通配符的上下限
这里为便于理解通配符,所以建立一个不含泛型的继承树
为了方便查阅,这里只列出继承关系和类内实例变量,构造器和get/set/toString方法均取IDEA默认。
/** 类继承树
* Object
* - Animal {private String species;}
* - Cat {private String speciesOfCat;}
* - MiniCat {private String name; private int age;}
*/
Animal.java
public class Animal {
private String species;
public Animal() {
}
public Animal(String species) {
this.species = species;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
@Override
public String toString() {
return "Animal{" +
"species='" + species + '\'' +
'}';
}
}
Cat.java
public class Cat extends Animal{
private String speciesOfCat;
public Cat() {
}
public Cat(String speciesOfCat) {
this.speciesOfCat = speciesOfCat;
}
public String getSpeciesOfCat() {
return speciesOfCat;
}
public void setSpeciesOfCat(String speciesOfCat) {
this.speciesOfCat = speciesOfCat;
}
@Override
public String toString() {
return "Cat{" +
"speciesOfCat='" + speciesOfCat + '\'' +
'}';
}
}
MiniCat.java
public class MiniCat extends Cat{
private String name;
private int age;
public MiniCat() {
}
public MiniCat(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "MiniCat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
创建对象
ArrayList<Animal> animals = new ArrayList<>();
ArrayList<Cat> cats = new ArrayList<>();
ArrayList<MiniCat> miniCats = new ArrayList<>();
// 填充 animals
animals.add(new Animal("猫"));
animals.add(new Animal("狗"));
animals.add(new Animal("鼠"));
// 填充 cats
cats.add(new Cat("暹罗"));
cats.add(new Cat("中华田园猫"));
cats.add(new Cat("金渐层"));
// 填充 miniCats、
miniCats.add(new MiniCat("汤姆",2));
miniCats.add(new MiniCat("老汤姆",7));
miniCats.add(new MiniCat("汤姆妈",4));
上限之于方法
类/接口<? extends 实参类型>
限定泛型的类型只能是传入的 实参类型 本身或者是其子类型
也就是截断了继承树,只保留其及之下的继承树
可见其遍历时的枚举对象类型是传入的上限 Cat
public static void showAnimalExtends(ArrayList<? extends Cat> arrayList) {
for (Cat cat : arrayList) {
System.out.println(cat.toString());
}
}
上限测试方法
// extends
showAnimalExtends(animals);// 编译报错
showAnimalExtends(cats);
showAnimalExtends(miniCats);
下限之于方法
类/接口<? super 实参类型>
截断了继承树,只保留其及之上的继承树
可见其遍历时的枚举对象类型是Object, 毕竟每一个类都继承自Object
public static void showAnimalSuper(ArrayList<? super Cat> arrayList) {
for (Object o : arrayList) {
System.out.println(o);
}
下限测试方法
// super
showAnimalSuper(animals);
showAnimalSuper(cats);
showAnimalSuper(miniCats);// 编译报错
完整测试用例
(去掉编译错误行后)
public static void main(String[] args) {
ArrayList<Animal> animals = new ArrayList<>();
ArrayList<Cat> cats = new ArrayList<>();
ArrayList<MiniCat> miniCats = new ArrayList<>();
// 填充 animals
animals.add(new Animal("猫"));
animals.add(new Animal("狗"));
animals.add(new Animal("鼠"));
// 填充 cats
cats.add(new Cat("暹罗"));
cats.add(new Cat("中华田园猫"));
cats.add(new Cat("金渐层"));
// 填充 miniCats、
miniCats.add(new MiniCat("汤姆",2));
miniCats.add(new MiniCat("老汤姆",7));
miniCats.add(new MiniCat("汤姆妈",4));
// extends
// showAnimalExtends(animals);
showAnimalExtends(cats);
showAnimalExtends(miniCats);
// super
showAnimalSuper(animals);
showAnimalSuper(cats);
// showAnimalSuper(miniCats);
}
STDOUT:
extends
showAnimalExtends(cats)
Cat{speciesOfCat='暹罗'}
Cat{speciesOfCat='中华田园猫'}
Cat{speciesOfCat='金渐层'}
showAnimalExtends(miniCats)
MiniCat{name='汤姆', age=2}
MiniCat{name='老汤姆', age=7}
MiniCat{name='汤姆妈', age=4}
super
showAnimalSuper(animals)
Animal{species='猫'}
Animal{species='狗'}
Animal{species='鼠'}
showAnimalSuper(cats)
Cat{speciesOfCat='暹罗'}
Cat{speciesOfCat='中华田园猫'}
Cat{speciesOfCat='金渐层'}
Process finished with exit code 0
泛型通配上下限案例
继承树
/**
* Object
* - Animal<T> {private T theAnimal;}
* - Cat<T> extends Animal<T> {private T theCat;
* - MiniCat<T> extends Cat<T> {private T theMiniCat;}
*/
使用时先把类当成非泛型类,有了整体结构之后将泛型再放进去
Animal.java
package pair.generic;
public class Animal<T> {
private T theAnimal;
public Animal() {
}
public Animal(T theAnimal) {
this.theAnimal = theAnimal;
}
public T getTheAnimal() {
return theAnimal;
}
public void setTheAnimal(T theAnimal) {
this.theAnimal = theAnimal;
}
@Override
public String toString() {
return "Animal{" +
"theAnimal=" + theAnimal +
'}';
}
}
Cat.java
package pair.generic;
public class Cat<T> extends Animal<T>{
private T theCat;
public Cat() {
}
public Cat(T theCat) {
this.theCat = theCat;
}
public T getTheCat() {
return theCat;
}
public void setTheCat(T theCat) {
this.theCat = theCat;
}
@Override
public String toString() {
return "Cat{" +
"theCat=" + theCat +
'}';
}
}
MiniCat.java
package pair.generic;
public class MiniCat<T> extends Cat<T>{
private T theMiniCat;
public MiniCat() {
}
public MiniCat(T theMiniCat) {
this.theMiniCat = theMiniCat;
}
public T getTheMiniCat() {
return theMiniCat;
}
public void setTheMiniCat(T theMiniCat) {
this.theMiniCat = theMiniCat;
}
@Override
public String toString() {
return "MiniCat{" +
"theMiniCat=" + theMiniCat +
'}';
}
}
上限测试方法
public static void showItExtends(ArrayList<? extends Cat<?>> arrayList) {
for (Cat<?> cat : arrayList) {
System.out.println(cat);
}
}
// extends
showItExtends(animals);// 编译错误
showItExtends(cats);
showItExtends(miniCats);
下限测试方法
public static void showItSuper(ArrayList<? super Cat<?>> arrayList) {
for (Object o : arrayList) {
System.out.println(o);
}
}
// super
showItSuper(animals);
showItSuper(cats);
showItSuper(miniCats);// 编译错误
测试用例
public static void main(String[] args) {
ArrayList<Animal<?>> animals = new ArrayList<>();
ArrayList<Cat<?>> cats = new ArrayList<>();
ArrayList<MiniCat<?>> miniCats = new ArrayList<>();
// animals
animals.add(new Animal<>("猫"));
animals.add(new Animal<>("狗"));
animals.add(new Animal<>("鼠"));
// cats
cats.add(new Cat<>("暹罗"));
cats.add(new Cat<>("中华田园猫"));
cats.add(new Cat<>("金渐层"));
// miniCats
miniCats.add(new MiniCat<>("汤姆"));
miniCats.add(new MiniCat<>("老汤姆"));
miniCats.add(new MiniCat<>("汤姆妈"));
// extends
System.out.println("\n\textends");
// showItExtends(animals);// 编译错误
System.out.println("showItExtends(cats)");
showItExtends(cats);
System.out.println("showItExtends(miniCats)");
showItExtends(miniCats);
// super
System.out.println("\n\tsuper");
System.out.println("showItSuper(animals)");
showItSuper(animals);
System.out.println("showItSuper(cats)");
showItSuper(cats);
// showItSuper(miniCats);// 编译错误
}
STDOUT
extends
showItExtends(cats)
Cat{theCat=暹罗}
Cat{theCat=中华田园猫}
Cat{theCat=金渐层}
showItExtends(miniCats)
MiniCat{theMiniCat=汤姆}
MiniCat{theMiniCat=老汤姆}
MiniCat{theMiniCat=汤姆妈}
super
showItSuper(animals)
Animal{theAnimal=猫}
Animal{theAnimal=狗}
Animal{theAnimal=鼠}
showItSuper(cats)
Cat{theCat=暹罗}
Cat{theCat=中华田园猫}
Cat{theCat=金渐层}
Process finished with exit code 0
*暂时写到这了,学到更多的继续往后补充 2021年12月19日