?表示不确定的 java 类型
T (type) 表示具体的一个java类型
K V (key value) 分别代表java键值中的Key Value
E (element) 代表Element
一个简单的泛型类
GenericsTest类引入了一个类型变量T,它指定了方法的返回类型以及域和局部变量的类型
可以看到不指定类型时需要强转、指定类型时就不需要了
public class GenericsTest<T> {
private T t;
public void set(T t){
this.t=t;
}
public T get(){
return this.t;
}
@Test
void test(){
GenericsTest number=new GenericsTest();
number.set(13);
//不指定类型时需要强转
Integer num =(Integer) number.get();
System.out.println(num);
GenericsTest<String>name=new GenericsTest<>();
name.set("liuyuan");
//指定类型就不需要强转了
String getName = name.get();
System.out.println(getName);
}
}
泛型方法
泛型方法可以在普通类中定义也可以在泛型类中定义,调用泛型方法时可以在方法名前的尖括号中放入具体的类型
public class GenericsTest<T> {
private T t;
public void set(T t){
this.t=t;
}
public T get(){
return this.t;
}
/**
* 类型变量放在修饰符public static后面,返回类型的前面
* @param a
* @param <T>
* @return
*/
public static <T> T getMiddle(T ...a){
return a[a.length/2];
}
@Test
void testGetMiddle(){
//大多情况可以直接省略<String>不写,编译器能够推断出类型
String middle = GenericsTest.getMiddle("left", "middle","middle2", "right");
System.out.println(middle);
// 可以指定类型
Integer middle1 = GenericsTest.<Integer>getMiddle(123, 22, 56);
System.out.println(middle1);
}
}
类型变量的限定
场景:对数组排序想要最小值,但是必须下面的smallest实现了Comparable接口我们才能使用其compareTo方法对其进行判断,此时通过对类型变量T设置限定实现<T extends Comparable>
此时确定了T所属的类有了compareTo方法就能实现我们想要的结果
public static <T extends Comparable> T getMinNum(T arr[]){
if(arr == null || arr.length== 0 ) return null;
T smallest=arr[0];
for (int i = 0; i < arr.length; i++) {
if(smallest.compareTo(arr[i])>0){
smallest=arr[i];
}
}
return smallest;
}
@Test
void getMinNumTest(){
String arr []=new String[]{"b","a","d"};
String minNum = getMinNum(arr);
System.out.println(minNum);
Integer arr1 []=new Integer[]{6,4,1};
System.out.println(getMinNum(arr1));
}
提一嘴:这里的关键词为什么用extends去限定,T应该是绑定的类型的子类,而T和绑定类型可以是接口或类,选择extends更接近子类概念 所以不用implements
另外:一个类型变量或通配符可以有多个限定T extends Comparable & Seralizable
,限定类型用&分割,而逗号用来分割类型变量
最大值和最小值案例
1、<T extends Comparable>
限定类型变量
2、参数返回Pair
public static <T extends Comparable> Pair<T> getMAxAndMin(T arr[]){
if(arr == null || arr.length == 0)return null;
T min=arr[0];
T max=arr[0];
for (int i = 0; i < arr.length; i++) {
if(min.compareTo(arr[i])>0){
min=arr[i];
}
if(max.compareTo(arr[i])<0){
max=arr[i];
}
}
return new Pair(min,max);
}
@AllArgsConstructor
public class Pair<T>{
@Getter
@Setter
T first;
@Getter
@Setter
T second;
}
泛型类型的继承规则
使用泛型类型时,比如List<Animal.Dog>
是List<Animal>
的子类吗???肯定不是
通配符类型
通配符解决什么问题???:
比如想要打印动物的信息:
public void printAnimal2(List<Animal> animals){
for (int i = 0; i < animals.size(); i++) {
System.out.println(animals.get(i));
}
但是你不能把List<Animal.Dog>也就是狗的集合传进去,这点是受限制的,解决办法就是使用通配符类型。
1、public void printAnimal3(List<? extends Animal>animals)
类型List<Animal.Dog>
是List<Animal>
的子类型
2、换种姿势实现上述需求public <T extends Animal> void printAnimal(List<T> animals)
指定了List<T> animals
只能够是Animal的子类
两种方式实现代码如下:
@AllArgsConstructor
@Data
public class Animal {
private String name;
private String sex;
private Integer age;
public static class Dog extends Animal{
public Dog(String name, String sex, Integer age) {
super(name, sex, age);
}
}
public static class Cat extends Animal{
public Cat(String name, String sex, Integer age) {
super(name, sex, age);
}
}
}
想把List<Animal.Dog>打印出来报错
@Test
void testPrintAnimal(){
List<Animal.Dog> dogs=new ArrayList<>();
dogs.add(new Animal.Dog("dog","1",18));
// error
printAnimal2(dogs);
}
public void printAnimal2(List<Animal> animals){
for (int i = 0; i < animals.size(); i++) {
System.out.println(animals.get(i));
}
}
而这样就可以两种方式都可以实现
//<T extends Animal> 对T进行了限制 只能是Animal子类
public <T extends Animal> void printAnimal(List<T> animals){
for (int i = 0; i < animals.size(); i++) {
System.out.println(animals.get(i));
}
}
//? extends Animal 标示任何泛型List类型,类型参数是Animal子类即可
public void printAnimal3(List<? extends Animal>animals){
for (int i = 0; i < animals.size(); i++) {
System.out.println(animals.get(i));
}
}
@Test
void testPrintAnimal(){
List<Animal.Dog> dogs=new ArrayList<>();
dogs.add(new Animal.Dog("dog","1",18));
printAnimal(dogs);
printAnimal3(dogs);
}