Java中泛型的基本使用总结

本文详细解析了Java泛型的概念,包括泛型类、泛型接口和泛型方法的使用,以及泛型在编译过程中的擦除特性。通过具体示例展示了泛型如何提升代码的复用性和安全性。

一、什么是泛型

泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

例子:

public static void main(String[] args) {
        List a = new ArrayList<String>();
        a.add("hello");
        a.add(10);
        for(int i=0;i<a.size();i++){
            String str = (String) a.get(i);
            System.out.println(str);
        }
    }

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

arrayList可以存任意的类型,存入一个String和一个Integer,再取出来当String类型使用时就会报强制类型转换异常。

如果我们把第一行变成

List<String> a = new ArrayList<String>();

a.add(10); 在编译阶段,编译器发现错误。

        List<String> a = new ArrayList<>();
        List<Integer> b =new ArrayList<>();
        Class classA = a.getClass();
        Class classB = b.getClass();
        System.out.println(classA.equals(classB));
        

结果为true。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。泛型的信息不会进入运行期。

二、泛型的使用

泛型类:

/**
 * 1、T可以是任意标识,常用的有以下几种
 * E - Element (在集合中使用,因为集合中存放的是元素)
 * T - Type(Java 类)
 * K - Key(键)
 * V - Value(值)
 * N - Number(数值类型)
 * ? -  表示不确定的java类型
 * S、U、V  - 2nd、3rd、4th types
 * 2、实例化泛型类时,必须指定T的类型
 */
public class Person<T> {
    //T由外部的T指定
    private T key;

    public Person(T key) {
        this.key = key;
    }

    public T getKey() {
        return key;
    }
    @Override
    public String toString() {
        return "key=" + key;
    }
}
        Person<String> p1 = new Person<>("hello");
        Person<Integer> p2 = new Person<>(10);

1、泛型的类型参数只能是引用类型,不能是基本类型。

2、不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。

3、不能对确切的泛型类型使用instanceof操作,例如X instanceof Person<Integer>不行。

泛型接口: 


public interface Student<T> {
    public T fun();
}
public class Demo implements Student<String> {
    @Override
    public String fun() {
        String str = new String("hello");
        return str;
    }
}

如果未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中。

public class Demo<T> implements Student<T>{
}

1、T传入无数个实参,就形成无数种类型的接口。

2、 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型。

泛型方法:

class X {
    public <T> T fun(T t){
        return t;
    }
};
public class Test{
    public static void main(String args[]){
        X c = new X(); //实例化X对象
        String str = c.fun("hello"); //传递字符串
        Integer i = c.fun(10); //传递数字
        System.out.println(str); // 通过泛型方法返回泛型类型实例
        System.out.println(i);  // 通过泛型方法返回泛型类型实例
    }
}

1、只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法,<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。

2、如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法。静态方法无法访问类上定义的泛型。

public class Person<T> {
public <T> void show(T t){ // T 和类上的T不是一个T
    }
}

 

待续。。。

### Java 使用指南 #### 什么是Java 是一种允许在类、接口和方法中使用参数的技术。它提供了更强的类安全性和更高的代码重用性,减少了运行时错误并简化了调试过程。 --- #### 基本语法 通过引入类参数 `<T>` 或其他占位符(如 `E` 表示元素,`K` 表示键,`V` 表示值),可以在定义类或方法时不指定具体的数据类型,在实际使用时再传入具体的类。 ```java // 定义一个简单的类 public class Box<T> { private T content; public void setContent(T content) { this.content = content; } public T getContent() { return content; } } ``` 在这个例子中,`Box<T>` 是一个通用容器类,可以存储任意类的对象[^1]。 --- #### 类推断与菱形操作符 自 Java SE 7 开始,编译器可以通过菱形操作符 (`<>`) 自动推断的实际类参数,从而减少冗余代码: ```java MyClass<Integer> myObject = new MyClass<>("example"); // 使用菱形操作符 ``` 这使得代码更加简洁明了[^1]。 --- #### 方法 即使在一个非类中,也可以定义方法。这些方法独立于类本身是否具有类参数工作: ```java public class Util { // 静态方法 public static <T> void printArray(T[] array) { for (T element : array) { System.out.println(element); } } } String[] strings = {"a", "b", "c"}; Util.printArray(strings); Integer[] integers = {1, 2, 3}; Util.printArray(integers); ``` 此方法接受不同类的数组作为输入,并打印其内容[^2]。 --- #### 通配符及其用途 通配符 `?` 可用于表示未知类,通常分为三种形式:无界通配符、上限通配符和下限通配符。 ##### 1. **无界通配符** 当只需要访问集合的内容而不需要修改时,可使用无界通配符: ```java public static void printList(List<?> list) { for (Object elem : list) { System.out.println(elem); } } ``` 这里 `list` 的确切类被隐藏,但仍能遍历其中的元素[^4]。 ##### 2. **上限通配符** 限定某个类及其子类可用作参数: ```java public static double sumOfList(List<? extends Number> list) { double s = 0.0; for (Number n : list) { s += n.doubleValue(); } return s; } ``` 这段代码计算了一个包含数值类(如 `Integer`, `Double` 等)列表的总和。 ##### 3. **下限通配符** 允许向特定超类及其子类赋值的操作场景: ```java public static void addNumbers(List<? super Integer> list) { for (int i = 1; i <= 10; i++) { list.add(i); } } ``` 这种方法支持将整数添加到能够容纳 `Integer` 或更广的列表中[^4]。 --- #### 方法签名中的类捕获限制 需要注意的是,某些情况下无法直接捕获类参数实例。例如下面的例子会引发编译错误,因为异常类 `T` 不可能被捕获为局部变量的一部分: ```java public static <T extends Exception, J> void execute(List<J> jobs) throws T { try { for (J job : jobs) {} } catch (T e) { // 错误:不能捕获类参数 throw e; } } ``` 这种设计是为了防止潜在的安全隐患以及保持 JVM 的一致性[^3]。 --- #### 总结 Java 提供了一种强大的机制来增强程序的功能性和安全性。无论是创建灵活的容器结构还是实现复杂的算法逻辑,合理运用都能带来显著的好处。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值