深入理解Java中的泛型(一)什么是泛型,如何理解泛型中的T

什么是泛型

Java 在 1.5 时增加了泛型机制,据说专家们为此花费了 5 年左右的时间(听起来很不容易)。有了泛型之后,尤其是对集合类的使用,就变得更规范了。

看下面这段简单的代码。

ArrayList<String> list = new ArrayList<String>();
list.add("沉默王二");
String str = list.get(0);

你能想象到在没有泛型之前该怎么办吗?
在没有泛型之前,我们可以使用 Object 数组来设计 Arraylist 类

class Arraylist {
    private Object[] objs;
    private int i = 0;
    public void add(Object obj) {
        objs[i++] = obj;
    }
    
    public Object get(int i) {
        return objs[i];
    }
}

然后,我们向 Arraylist 中存取数据。

Arraylist list = new Arraylist();
list.add("沉默王二");
list.add(new Date());
String str = (String)list.get(0);

但是这样有两个问题

  • Arraylist 可以存放任何类型的数据(既可以存字符串,也可以混入日期),因为所有类都继承自 Object 类。
  • 从 Arraylist 取出数据的时候需要强制类型转换,因为编译器并不能确定你取的是字符串还是日期。

对比一下,你就能明显地感受到泛型的优秀之处:使用类型参数解决了元素的不确定性——参数类型为 String 的集合中是不允许存放其他类型元素的,取出数据的时候也不需要强制类型转换了。

泛型类型的创建

public class Wrapper<T> { 
T instance;
public T get() { 
   return instance;
 }
public void set(T newInstance) { instance = newInstance;
  }
}

泛型接口的创建

 
public interface Shop<T> {
 T buy();
 float refund(T item);
}

泛型作用小结

  1. 帮助检查代码中的类型,提前报错;
  2. 自动强制转型。

「创建一个泛型类型」到底是为了什么

  • 本质目标或原因:这个类型的不同实例的具体类型可能会有不同,针对的
    实例
  • 因此,静态字段和静态方法不能使用泛型类型的类型参数(也就是那个T )

继承

 
public class AppleShop extends Shop<Apple> {
  @Override
  Apple buy();

  @Override
  float refund(Apple item);
 }
 
public interface RealShop<T> extends Shop<T> { 
 @Override
 public T buy() {
   return null; 
 }
 @Override
 public float refund(Object item) { 
 return 0;
 } 
}

类型参数 <T> 到底是什么

  • 不是一个类,也不是一个接口。只是一个标记符号,可以用其他字母代替
  • 代表这个类型内部某个通用的类型

但出于规范的目的,Java 还是建议我们用单个大写字母来代表类型参数。常见的如:

T 代表一般的任何类。
E 代表 Element 的意思,或者 Exception 异常的意思。
K 代表 Key 的意思。
V 代表 Value 的意思,通常与 K 一起配合使用。
S 代表 Subtype 的意思,文章后面部分会讲解示意。

多个类型参数

public interface HenCoderMap<K, V> { 
  public void put(K key, V value);
  public V get(K key); 
}
public interface SimShop<T, C> extends Shop<T> { 
 T buy(float money);
 float refund(T item);
 C getSim(String name, String id);
}

泛型类型的实例化

  • 所谓泛型实例化其实就是「确定这个 T 的实际值」的意思
 // 左右两边的尖括号都是 ArrayList 的类型参数的实例化 
ArrayList<Apple> apples = new ArrayList<>();
// 左边的 E 是 Repairable 的类型参数的声明;右边的 E 是 Shop 的类型参数的实例化
interface RepairableShop<E> extends Shop<E>{
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容