链接: 原文链接
一.泛型的定义
泛型,即“参数化类型”。就是将类型由原来的具体类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(类型形参),然后再使用/调用时传入具体的类型
常用的泛型变量
Element(E):元素,多用于java框架集合
Key(K) :关键字
Number(N) : 数字
Type(T) : 类型
Value(V) : 值
如果没有泛型会怎么样?
如果要实现不同类型的加法,每种类型都需要重载一个add方法
package com.company;
public class GenericityTest {
public static int add(int a ,int b){
return a+b;
}
public static float add(float a,float b){
return a+b;
}
public static void main(String[] args) {
GenericityTest.add(1, 2);
GenericityTest.add(1f, 2f);
}
}
如果我们利用泛型,只需要定义一个方法
package com.company;
public class GenericityTest {
public static <T extends Number> int add(T a, T b) {
System.out.println(a + "+" + b + "=" + (a.intValue() + b.intValue()));
return a.intValue() + b.intValue();
}
public static void main(String[] args) {
GenericityTest.add(1, 2);
GenericityTest.add(1f, 2f);
}
}
所以泛型的意义在于
1.适用于多种数据类型执行相同的代码
2.泛型中的类型在使用时指定,不需要强制转换类型(类型安全,编译器会检查类型)
二.泛型的使用
1.泛型类的使用
package com.company;
public class GenericityTest<T> {
public T data;
public void setData(T data){
this.data=data;
}
public T getData(){
return data;
}
public static void main(String[] args) {
GenericityTest genericityTest=new GenericityTest();
genericityTest.setData(1245.1323f);
System.out.println(genericityTest.getData());
}
}
2.泛型接口的使用
package com.company;
public interface GenericityInter <T>{
public T getData();
}
3.泛型方法的使用
如果没有使用泛型类,定义泛型方法时,需要加<T>
定义该方法所拥有的泛型标识符
package com.company;
public class GenericityTest{
public <T> T setData(T data){
return data;
}
public static void main(String[] args) {
GenericityTest genericityTest=new GenericityTest();
System.out.println(genericityTest.setData("abc"));
}
}
4.限定泛型类型变量
对方法的限定: public T setData(T data){}
package com.company;
public class GenericityTest{
public <T extends Number> T setData(T data){
return data;
}
public static void main(String[] args) {
GenericityTest genericityTest=new GenericityTest();
System.out.println(genericityTest.setData("abc"));//如果传入String类型,则报错
System.out.println(genericityTest.setData(123));
}
}
对类的限定:public class GenericityTest{}
package com.company;
public class GenericityTest<T extends Number>{
public T name;
public void setName(T name){
this.name=name;
}
public T getName(){
return name;
}
public static void main(String[] args) {
GenericityTest genericityTest=new GenericityTest();
genericityTest.setName(1212);
genericityTest.setName("abc");//如果传入字符串则报错
System.out.println(genericityTest.getName());
}
}
5.通配符类型
? - 表示不确定的java类型
1.<? extends Parent> 指定了泛型类型的上届
2.<? super Child> 指定了泛型类型的下届
3. <?> 指定了没有限制的泛型类型
/**
* Author:Jay On 2019/5/10 19:51
* <p>
* Description: 泛型通配符测试类
*/
public class GenericByWildcard {
private static void print(GenericClass<Fruit> fruitGenericClass) {
System.out.println(fruitGenericClass.getData().getColor());
}
private static void use() {
GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
print(fruitGenericClass);
GenericClass<Orange> orangeGenericClass = new GenericClass<>();
//类型不匹配,可以使用<? extends Parent> 来解决
// print(orangeGenericClass);
}
/**
* <? extends Parent> 指定了泛型类型的上届
*/
private static void printExtends(GenericClass<? extends Fruit> genericClass) {
System.out.println(genericClass.getData().getColor());
}
public static void useExtend() {
GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
printExtends(fruitGenericClass);
GenericClass<Orange> orangeGenericClass = new GenericClass<>();
printExtends(orangeGenericClass);
GenericClass<Food> foodGenericClass = new GenericClass<>();
//Food是Fruit的父类,超过了泛型上届范围,类型不匹配
// printExtends(foodGenericClass);
//表示GenericClass的类型参数的上届是Fruit
GenericClass<? extends Fruit> extendFruitGenericClass = new GenericClass<>();
Apple apple = new Apple();
Fruit fruit = new Fruit();
/*
* 道理很简单,? extends X 表示类型的上界,类型参数是X的子类,那么可以肯定的说,
* get方法返回的一定是个X(不管是X或者X的子类)编译器是可以确定知道的。
* 但是set方法只知道传入的是个X,至于具体是X的那个子类,不知道。
* 总结:主要用于安全地访问数据,可以访问X及其子类型,并且不能写入非null的数据。
*/
// extendFruitGenericClass.setData(apple);
// extendFruitGenericClass.setData(fruit);
fruit = extendFruitGenericClass.getData();
}
/**
* <? super Child> 指定了泛型类型的下届
*/
public static void printSuper(GenericClass<? super Apple> genericClass) {
System.out.println(genericClass.getData());
}
public static void useSuper() {
GenericClass<Food> foodGenericClass = new GenericClass<>();
printSuper(foodGenericClass);
GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
printSuper(fruitGenericClass);
GenericClass<Apple> appleGenericClass = new GenericClass<>();
printSuper(appleGenericClass);
GenericClass<HongFuShiApple> hongFuShiAppleGenericClass = new GenericClass<>();
// HongFuShiApple 是Apple的子类,达不到泛型下届,类型不匹配
// printSuper(hongFuShiAppleGenericClass);
GenericClass<Orange> orangeGenericClass = new GenericClass<>();
// Orange和Apple是兄弟关系,没有继承关系,类型不匹配
// printSuper(orangeGenericClass);
//表示GenericClass的类型参数的下界是Apple
GenericClass<? super Apple> supperAppleGenericClass = new GenericClass<>();
supperAppleGenericClass.setData(new Apple());
supperAppleGenericClass.setData(new HongFuShiApple());
/*
* ? super X 表示类型的下界,类型参数是X的超类(包括X本身),
* 那么可以肯定的说,get方法返回的一定是个X的超类,那么到底是哪个超类?不知道,
* 但是可以肯定的说,Object一定是它的超类,所以get方法返回Object。
* 编译器是可以确定知道的。对于set方法来说,编译器不知道它需要的确切类型,但是X和X的子类可以安全的转型为X。
* 总结:主要用于安全地写入数据,可以写入X及其子类型。
*/
// supperAppleGenericClass.setData(new Fruit());
//get方法只会返回一个Object类型的值。
Object data = supperAppleGenericClass.getData();
}
/**
* <?> 指定了没有限定的通配符
*/
public static void printNonLimit(GenericClass<?> genericClass) {
System.out.println(genericClass.getData());
}
public static void useNonLimit() {
GenericClass<Food> foodGenericClass = new GenericClass<>();
printNonLimit(foodGenericClass);
GenericClass<Fruit> fruitGenericClass = new GenericClass<>();
printNonLimit(fruitGenericClass);
GenericClass<Apple> appleGenericClass = new GenericClass<>();
printNonLimit(appleGenericClass);
GenericClass<?> genericClass = new GenericClass<>();
//setData 方法不能被调用, 甚至不能用 Object 调用;
// genericClass.setData(foodGenericClass);
// genericClass.setData(new Object());
//返回值只能赋给 Object
Object object = genericClass.getData();
}
}