Java泛型

泛型是什么

泛型是Java1.5的特性,是为了规范数据标准化的一种手段。例如一个list集合如果不设定泛型就可以随意放入任何类型的元素,从而导致类型转换异常。本文主要讲解自定义泛型。

泛型的使用

泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法
泛型类

//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T>{ 
    //key这个成员变量的类型为T,T的类型由外部指定  
    private T key;

    public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
        this.key = key;
    }

    public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
        return key;
    }
    public static void main(String []args) {
		//泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
		//传入的实参类型需与泛型的类型参数类型相同,即为Integer.
		Generic<Integer> genericInteger = new Generic<Integer>(123456);
		
		//传入的实参类型需与泛型的类型参数类型相同,即为String.
		Generic<String> genericString = new Generic<String>("key_vlaue");
		Log.d("泛型测试","key is " + genericInteger.getKey());
		Log.d("泛型测试","key is " + genericString.getKey());
	}
}

泛型接口

//定义一个泛型接口
public interface Generator<T> {
    public T next();
}

泛型方法

/**
 * 泛型方法的基本介绍
 * @param tClass 传入的泛型实参
 * @return T 返回值为T类型
 * 说明:
 *     1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
 *     2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
 *     3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
 *     4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
 */
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,IllegalAccessException{
        T instance = tClass.newInstance();
        return instance;
}

泛型通配符?? extends T? super T

我们知道Ingeter是Number的一个子类,同时在特性章节中我们也验证过Generic与Generic实际上是相同的一种基本类型。那么问题来了,在使用Generic作为形参的方法中,能否使用Generic的实例传入呢?在逻辑上类似于Generic和Generic是否可以看成具有父子关系的泛型类型呢?

为了弄清楚这个问题,我们使用Generic这个泛型类继续看下面的例子:

public void showKeyValue1(Generic<Number> obj){
    Log.d("泛型测试","key value is " + obj.getKey());
}
Generic<Integer> gInteger = new Generic<Integer>(123);
Generic<Number> gNumber = new Generic<Number>(456);

showKeyValue(gNumber);
// showKeyValue这个方法编译器会为我们报错:Generic<java.lang.Integer> 
// cannot be applied to Generic<java.lang.Number>
// showKeyValue(gInteger);

通过提示信息我们可以看到Generic不能被看作为Generic的子类。由此可以看出:同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。

回到上面的例子,如何解决上面的问题?总不能为了定义一个新的方法来处理Generic类型的类,这显然与java中的多台理念相违背。因此我们需要一个在逻辑上可以表示同时是Generic和Generic父类的引用类型。由此类型通配符应运而生。

我们可以将上面的方法改一下:

public void showKeyValue1(Generic<?> obj){
    Log.d("泛型测试","key value is " + obj.getKey());
}

类型通配符一般是使用?代替具体的类型实参,注意了,此处’?’是类型实参,而不是类型形参 。重要说三遍!此处’?’是类型实参,而不是类型形参 ! 此处’?’是类型实参,而不是类型形参 !再直白点的意思就是,此处的?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型。

可以解决当具体类型不确定的时候,这个通配符就是 ? ;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用 ? 通配符来表未知类型。

?T的区别

T(Type Parameter): T 是一种表示未知类型的通用标识符,通常用于类、接口或方法的定义中。使用 T 可以创建一个在实例化时指定具体类型的泛型类、接口或方法。

public class Box<T> {
    private T value;

    public void setValue(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

在这个例子中,T 是一个类型参数,可以在实例化 Box 类时指定具体的类型。
通配符表示未知类型,但它通常用于泛型的边界、通配符类型和方法参数。有两种主要的通配符使用方式:

? extends T: 表示通配符可以是 T 或 T 的子类。这用于表示上界通配符,允许读取泛型类型的值,但不允许修改。

? super T: 表示通配符可以是 T 或 T 的超类。这用于表示下界通配符,允许修改泛型类型的值,但只能安全地添加 T 类型的元素。

例如:

public static <T> void printList(List<? extends T> list) {
    for (T element : list) {
        System.out.println(element);
    }
}

总的来说,T 是用于定义泛型类型的参数,而 ? 是用于表示未知类型的通配符,通常与边界一起使用以提供更多的灵活性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值