关于java泛型的一些概念

本文详细解析了Java泛型的核心概念,包括类型参数、泛型子类型、通配符、边界通配符、泛型方法等,并通过实例展示了它们在实际编程中的应用。此外,文章还讨论了泛型的命名约定、遗留代码的泛型化、通配符捕获、多边界、协变与逆变等高级特性。

关于java泛型其实挺复杂的,之前看文档的时候做过一些泛型名词摘记,今天把这这个笔记放到博客上来,以后抽空完善这篇关于泛型的文章  

一  类型参数(Type parameters)

二  泛型子类型(Subtyping)  
    有点违反OOP的直觉
  List<String>  listStr = new ArrayList<String>();
  List<Object> listObj = listStr;  不允许

三 泛型通配符(Wildcards):
     Collection<?> 和Collection<Object>区别
     type parameter is ?, it stands for some unknown type.  ?表示未知类型

四  边界通配符(Bounded Wildcards):
  List<Shape> shapes 与List<? extends Shape> shapes2的区别
List<? extends Shape> shapes2允许接收类型为Shape和Shape的子类型
   Shape是通配符的上界

五  泛型方法(Generic Methods)  
  static void fromArrayToCollection(Object[] a, Collection<?> c) {
for (Object o : a) { 
        c.add(o); // compile-time error
    }
}
  编译错误,正确的写法是static后面void的前面加上泛型声明
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) {
        c.add(o); // Correct
    }
}

六  泛型方法和通配符使用区别  


七  泛型参数命名约定:
E: element
T: Type
K: Key
V;Value

八  遗留代码 
  raw type :像Collection这样的泛型类型,不使用类型参数(type paramter)被称为raw type 
遗留代码API操作集合未使用泛型,新代码调用的集合可以使用泛型参数。  遗留代码修改 支持泛型 修改过后的API二进制兼容老的客户端

九  未检查警告(unchecked warning):


十  上边界  下边界(lower bound)
  下边界通配符  ? super T 

   上边界通配符 ? extend T

十一  上下边界泛型使用区别
In general, if you have an API that only uses a type parameter T as 
an argument, its uses should take advantage of lower bounded wildcards (? 
super T). Conversely, if the API only returns T, 
you'll give your clients more flexibility by using upper bounded wildcards 
(? extends T).

十二  通配符捕获(wildcard Capture)


十三 Multiple bounds 多边界
   

十四  协变(convariant)  逆变(contravariant)  可变(variance)  不变(invariant)


2 协变(convariant):String是Object的子类,如果List<String>是List<Object>的子类 则称为协变
3 逆变(contravariant):String是Object的子类,如果List<String>是List<Object>的父类 则称为逆变
4 可变(variance):如果带类型参数的类型支持协变或逆变,这称为可变
5 不变(invariant):即不支持协变也不支持逆变,则称为不变

十五  通配符类型(Wildcard types):如果类型参数未知,使用?表示,比如List<?> list = new ArrayList<>(); 由于List的泛型参数E具体类型未知,不能像list写入任何对象。
list.add("ONE")  提示The method add(capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (String)


十六  类型擦除(Erasure):支持泛型的类或方法,泛型信息只在编译阶段起作用,运行时泛型的类型信息已经被擦除,
比如list 在运行时不能感知到底是List<String> 还是List<Object>

十七  PECS原则(producer-extends, comsumer-super)
  指导如何使用上边界和下边界原则

十八  递归类型

  比如Integer类的,Integer extends Number implements Comparable<Integer>

十九  类型推导(type inference)

  从java7开始,编译器可以自动推到泛型类型参数比如

Map<String, List<String>> myMap = new HashMap<String, List<String>>();

  可以将HashMap后面的泛型参数省略,只用<>

Map<String, List<String>> myMap = new HashMap<>(); 

### Java 概念详解 Java (Generics)是 Java SE 5 引入的一项重要特性,旨在提高代码的类安全性和可重用性。通过,开发者可以编写一个通用的类、接口或方法,使其能够处理多种数据类,而无需为每种类分别编写代码[^2]。 #### 的核心概念 1. **类** 类是在类定义时声明一个或多个类参数的类。这些类参数可以在类的成员变量、方法参数以及方法返回值等位置使用。例如: ```java public class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } } ``` 在上述示例中,`Box<T>` 是一个类,`T` 是类参数。可以通过指定不同的类来实例化该类,如 `Box<Integer>` 或 `Box<String>`[^5]。 2. **方法** 方法允许方法独立于类具有自己的类参数。这意味着即使类本身不是类,也可以在方法中使用。例如: ```java public class Util { public static <T> void printArray(T[] array) { for (T element : array) { System.out.println(element); } } } ``` 在此示例中,`printArray` 方法是一个方法,可以接受任意类的数组并打印其内容[^5]。 3. **接口** 接口与类类似,允许在接口定义时声明类参数。例如: ```java public interface Generator<T> { T next(); } ``` #### 的意义 - **类安全性**:提供了一种编译时的安全机制,避免了运行时的类转换错误。例如,在非集合中,可能将不同类的数据存储到同一集合中,导致运行时异常。而使用后,编译器会在编译阶段检查类是否匹配[^3]。 - **代码复用性**:通过,可以编写适用于多种数据类的通用代码,减少了重复代码的编写。 #### 类擦除 需要注意的是,信息仅存在于编译阶段。在编译完成后,所有的信息会被擦除,这一过程称为类擦除。例如: ```java ArrayList<Integer> list1 = new ArrayList<>(); ArrayList<String> list2 = new ArrayList<>(); System.out.println(list1.getClass() == list2.getClass()); // 输出 true ``` 上述代码表明,尽管 `list1` 和 `list2` 的参数不同,但它们的实际类均为 `ArrayList`,即信息在运行时已被擦除[^4]。 ### 示例代码 以下是一个完整的类和方法的示例: ```java public class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } public static <T> void swap(Box<T> box1, Box<T> box2) { T temp = box1.get(); box1.set(box2.get()); box2.set(temp); } public static void main(String[] args) { Box<Integer> integerBox = new Box<>(); integerBox.set(10); Box<String> stringBox = new Box<>(); stringBox.set("Hello"); System.out.println(integerBox.get()); // 输出 10 System.out.println(stringBox.get()); // 输出 Hello Box<Integer> box1 = new Box<>(); box1.set(1); Box<Integer> box2 = new Box<>(); box2.set(2); swap(box1, box2); System.out.println(box1.get()); // 输出 2 System.out.println(box2.get()); // 输出 1 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值