<T extends Serializable>这是什么意思呢?看明白这个,你的问题就自然而然的明白了!

本文深入浅出地介绍了Java泛型的概念及其重要性。通过对比泛型与非泛型的示例,展示了泛型如何提高代码的安全性和重用率。文章还概述了泛型的基本规则与限制,帮助读者更好地理解和应用这一特性。

 

 


泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

  Java语言引入泛型的好处是安全简单。

  在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,

而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常

,这是一个安全隐患。

  泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

  泛型在使用中还有一些规则和限制:

  1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。

  2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。

  3、泛型的类型参数可以有多个。

  4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上成为“有界类型”。

  5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(java.lang.String);

  泛型还有接口、方法等等,内容很多,需要花费一番功夫才能理解掌握并熟练应用。在此给出我曾经了解泛型时候写出的两个例子(根据看的印象写的),

实现同样的功能,一个使用了泛型,一个没有使用,通过对比,可以很快学会泛型的应用,学会这个基本上学会了泛型70%的内容。

  例子一:使用了泛型

Java code

public class Gen<T> {
    private T ob; //定义泛型成员变量  

    public Gen(T ob) {
        this.ob = ob;
    }

    public T getOb() {
        return ob;
    }

    public void setOb(T ob) {
        this.ob = ob;
    }

    public void showTyep() {
        System.out.println("T的实际类型是: " + ob.getClass().getName());
    }
}


public class GenDemo {
    public static void main(String[] args) {
        //定义泛型类Gen的一个Integer版本 
        Gen<Integer> intOb = new Gen<Integer>(88);
        intOb.showTyep();
        int i = intOb.getOb();
        System.out.println("value= " + i);
        System.out.println("----------------------------------");
        //定义泛型类Gen的一个String版本 
        Gen<String> strOb = new Gen<String>("Hello Gen!");
        strOb.showTyep();
        String s = strOb.getOb();
        System.out.println("value= " + s);
    }
}


运行结果:

 

 


例子二:没有使用泛型

 

 

Java code

public class Gen2 {
    private Object ob;

    //定义一个通用类型成员 
    public Gen2(Object ob) {
        this.ob = ob;
    }

    public Object getOb() {
        return ob;
    }

    public void setOb(Object ob) {
        this.ob = ob;
    }

    public void showTyep() {
        System.out.println("T的实际类型是: " + ob.getClass().getName());
    }
} 


public class GenDemo2 {
    public static void main(String[] args) {
        //定义类Gen2的一个Integer版本 
        Gen2 intOb = new Gen2(new Integer(88));
        intOb.showTyep();
        int i = (Integer) intOb.getOb();
        System.out.println("value= " + i);
        System.out.println("----------------------------------");
        //定义类Gen2的一个String版本 
        Gen2 strOb = new Gen2("Hello Gen!");
        strOb.showTyep();
        String s = (String) strOb.getOb();
        System.out.println("value= " + s);
    }
}


运行结果:




  看明白这个,你的三个问题就自然而然的明白了

 

 

 

### Java 通配符 `<? extends T>` 和 `<? super T>` 的区别及使用场景 #### 1. 基本概念 - **`<? extends T>`** 表示上界限定通配符,表示参数化类型可能是 `T` 或其子类[^2]。这种通配符通常用于从集合中读取数据的场景。 - **`<? super T>`** 表示下界限定通配符,表示参数化类型是 `T` 或其父类[^3]。这种通配符通常用于向集合中写入数据的场景。 #### 2. 使用场景 根据 PECS(Producer Extends, Consumer Super)原则: - 如果需要从集合中读取类型为 `T` 的数据,并且不需要写入,则使用 `<? extends T>`[^3]。 - 如果需要向集合中写入类型为 `T` 的数据,并且不需要读取,则使用 `<? super T>`[^3]。 - 如果既需要读取又需要写入,则不建议使用通配符,直接指定具体类型即可。 #### 3. 示例代码 ##### (1) `<? extends T>` 示例 以下代码展示了如何使用 `<? extends T>` 从集合中读取数据: ```java import java.util.ArrayList; import java.util.List; public class ExtendsExample { public static void printNumbers(List<? extends Number> numbers) { for (Number number : numbers) { System.out.println(number); } } public static void main(String[] args) { List<Integer> integers = new ArrayList<>(); integers.add(1); integers.add(2); List<Double> doubles = new ArrayList<>(); doubles.add(1.1); doubles.add(2.2); printNumbers(integers); // 输出:1, 2 printNumbers(doubles); // 输出:1.1, 2.2 } } ``` 在上述代码中,`printNumbers` 方法可以接受 `List<Integer>` 或 `List<Double>`,因为它们都是 `Number` 的子类[^2]。 ##### (2) `<? super T>` 示例 以下代码展示了如何使用 `<? super T>` 向集合中写入数据: ```java import java.util.ArrayList; import java.util.List; public class SuperExample { public static void addNumbers(List<? super Integer> numbers) { numbers.add(1); numbers.add(2); } public static void main(String[] args) { List<Object> objects = new ArrayList<>(); addNumbers(objects); // 可以添加 Integer 类型的对象 for (Object obj : objects) { System.out.println(obj); } } } ``` 在上述代码中,`addNumbers` 方法可以接受 `List<Object>` 或 `List<Number>`,因为 `Integer` 是它们的子类或本身[^3]。 #### 4. 区别总结 | 特性 | `<? extends T>` | `<? super T>` | |---------------------|------------------------------------|------------------------------------| | **含义** | 上界限定通配符 | 下界限定通配符 | | **读取/写入** | 只能读取 | 只能写入 | | **适用场景** | 从集合中读取类型为 `T` 的数据 | 向集合中写入类型为 `T` 的数据 | | **类型范围** | `T` 或其子类 | `T` 或其父类 | #### 5. 注意事项 - 使用 `<? extends T>` 时,无法向集合中添加元素(除了 `null`),因为编译器无法确定实际类型[^2]。 - 使用 `<? super T>` 时,可以从集合中读取元素,但读取到的类型会被视为通配符的上界类型(如 `Object`),需要进行显式类型转换[^3]。 ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值