深入理解Java 泛型原理和使用场景

泛型是什么

泛型即参数化类型,就是将原来的具体的类型参数化。就像方法变量参数,类型也定义成类型参数,在传入和调用的时候传入具体的类型。看看下面的例子,有没有什么问题?

    List arrayList = new ArrayList();
        arrayList.add("hello");
        arrayList.add(1);
       for (int i = 0; i<arrayList.size();i++) {
           System.out.println((String)arrayList.get(i));
       }

ArrayList 可以存放任意类的值,上面的代码中有Integer、String两种类型,因为没有做参数类型限制,但是取出来当String类型使用的时候就会在运行时报错:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

如果应用泛型,执行ArrayList类型为String,List<String> arrayList = new ArraryList();可以在编译阶段就能发现错误,保证程序的健壮性。

泛型的使用

接下来我们从泛型类、泛型接口、泛型方法、泛型的通配符4个方面的介绍泛型的使用

泛型类

public class DataProcessor<T> {
    T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

泛型类还是很简单的,只要在类名后面加上类型参数即可,类型参数可以用任意的字母代替,常用的可以是T,E,K,V。在使用的时候只要传入想要的具体的参数:

DataProcessor<String> data = new DataProcessor();

泛型接口

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

这里泛型接口有2点需要注意的点;

  • 泛型接口没有传入泛型实参时,泛型接口的实现类也在定义时,也必须也泛型接口一样将类型参数加到类中:
class FruitGenerator<T> implements Generator<T>{
    @Override
    public T next() {
        return null;
    }
}
  • 泛型接口传入具体的泛型实参,泛型接口的实现类也用到泛型的地方需要加上具体的类型如下:
class DataHolder implements Generator<String>{
    @Override
    public String next() {
    	return null;
    }
}

泛型方法

首先泛型的方法是可以存在泛型类中,也是可以存在普通类中的,记住:能用泛型方法可以解决的问题,尽量使用泛型方法,下面用一个例子介绍泛型方法的使用:

class DataHolder<T>{
    T item;
    
    public void setData(T t) {
    	this.item=t;
    }
    
    public T getData() {
    	return this.item;
    }
    
    /**
     * 泛型方法
     * @param e
     */
    public <E> void PrinterInfo(E e) {
    	System.out.println(e);
    }
}

上面的例子中泛型类的类型参数T和泛型方法类型参数E,是没有任何关系的。甚至都可以用T代替。PrinterInfo 的泛型方法的参数可以的String,Integer。泛型方法注意的几点:

  • public与返回值中间的<T>非常重要,可以理解为声明此方法为泛型方法。
  • 与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。

 

泛型上下边界通配符

在使用泛型的时候,我们还可以为传入的泛型类型实参进行上下边界的限制,如:类型实参只准传入某种类型的父类或某种类型的子类

  • 为泛型添加上边界,即传入的类型实参必须是指定类型的子类型
public class DataProcessor<T extends Number> {

    T data;

    public T getData() {
        return data;
    }

    public DataProcessor(T data) {
        this.data = data;
    }

    public void setData(T data) {
        this.data = data;
    }


}

        DataProcessor<Integer> d2 = new DataProcessor<>(12);
        
        //这一行代码编译器会提示错误,因为String类型并不是Number类型的子类
        DataProcessor<String> d1 = new DataProcessor<String>("hello");

在来一个泛型参数的例子:

 private <T extends Number> T show (DataProcessor<T> dataProcessor) {

        System.out.println("container key :" + dataProcessor.getData());
        T test = dataProcessor.data;
        return test;

    }

在泛型方法中添加上下边界限制的时候,必须在权限声明与返回值之间的<T>(或者是其它任意类型)上添加上下边界,即在泛型声明的时候添加.

总结

相信大家日常工作中肯定是经常用到泛型,尤其是集合的使用。有时候也会自定泛型来简化代码,一句话就是能用泛型就尽量用泛型。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值