Java泛型与类型擦除

Java泛型与类型擦除

一、Java泛型

1.1 泛型的概念

泛型是 Java 5 引入的一个重要特性,它允许在定义类、接口和方法时使用类型参数。通过使用泛型,我们可以编写更通用、类型安全的代码,避免了在使用集合等数据结构时进行强制类型转换,同时在编译阶段就能发现类型不匹配的错误。

1.2 泛型的作用

  • 类型安全:泛型能够在编译时检查类型,确保只有正确类型的对象才能放入集合或作为参数传递,减少运行时的类型转换异常。
  • 代码复用:编写一次代码,可以用于多种不同类型的数据,提高了代码的复用性。
  • 消除强制类型转换:使用泛型后,无需手动进行强制类型转换,使代码更加简洁和易读。

1.3 泛型的使用场景

泛型类
// 定义一个泛型类
class Box<T> {
    private T item;

    public Box(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }
}

// 使用泛型类
public class GenericClassExample {
    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<>(10);
        Integer num = integerBox.getItem();
        System.out.println(num);

        Box<String> stringBox = new Box<>("Hello");
        String str = stringBox.getItem();
        System.out.println(str);
    }
}
泛型接口
// 定义一个泛型接口
interface Generator<T> {
    T generate();
}

// 实现泛型接口
class IntegerGenerator implements Generator<Integer> {
    @Override
    public Integer generate() {
        return (int) (Math.random() * 100);
    }
}

// 使用泛型接口
public class GenericInterfaceExample {
    public static void main(String[] args) {
        Generator<Integer> generator = new IntegerGenerator();
        Integer num = generator.generate();
        System.out.println(num);
    }
}
泛型方法
public class GenericMethodExample {
    // 定义一个泛型方法
    public static <T> T getFirstElement(T[] array) {
        if (array != null && array.length > 0) {
            return array[0];
        }
        return null;
    }

    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3};
        Integer firstInt = getFirstElement(intArray);
        System.out.println(firstInt);

        String[] strArray = {"Hello", "World"};
        String firstStr = getFirstElement(strArray);
        System.out.println(firstStr);
    }
}

1.4 泛型通配符

  • ? extends T:上界通配符,表示该类型必须是 T 或者 T 的子类。
  • ? super T:下界通配符,表示该类型必须是 T 或者 T 的父类。
  • ?:无界通配符,表示可以是任意类型。
import java.util.ArrayList;
import java.util.List;

class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

public class WildcardExample {
    // 上界通配符示例
    public static void printAnimals(List<? extends Animal> animals) {
        for (Animal animal : animals) {
            System.out.println(animal);
        }
    }

    // 下界通配符示例
    public static void addDog(List<? super Dog> dogs) {
        dogs.add(new Dog());
    }

    public static void main(String[] args) {
        List<Dog> dogList = new ArrayList<>();
        dogList.add(new Dog());
        printAnimals(dogList);

        List<Animal> animalList = new ArrayList<>();
        addDog(animalList);
    }
}

二、Java类型擦除

2.1 类型擦除的概念

类型擦除是 Java 泛型实现的一种机制。在 Java 编译过程中,泛型类型信息会被擦除,即泛型类型参数在编译后会被替换为其原始类型(通常是 Object 或者边界类型)。这意味着在运行时,泛型类型的具体信息是不可用的。

2.2 类型擦除的规则

  • 无边界的类型参数:如果泛型类型参数没有指定边界,会被擦除为 Object 类型。
class GenericClass<T> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}
// 编译后,T 会被擦除为 Object
class GenericClass {
    private Object value;

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }
}
  • 有边界的类型参数:如果泛型类型参数指定了边界,会被擦除为其边界类型。
class GenericClass<T extends Number> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}
// 编译后,T 会被擦除为 Number
class GenericClass {
    private Number value;

    public Number getValue() {
        return value;
    }

    public void setValue(Number value) {
        this.value = value;
    }
}

2.3 类型擦除带来的影响

  • 无法在运行时获取泛型的具体类型:由于类型擦除,在运行时无法通过反射获取泛型的具体类型信息。
import java.util.ArrayList;
import java.util.List;

public class TypeErasureExample {
    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        List<String> strList = new ArrayList<>();

        // 输出 true,因为类型擦除后,它们的运行时类型都是 ArrayList
        System.out.println(intList.getClass() == strList.getClass()); 
    }
}
  • 不能创建泛型数组:由于类型擦除,无法直接创建泛型数组。可以使用 ArrayList 等集合来替代。
// 以下代码会编译错误
// T[] array = new T[10]; 

2.4 类型擦除的好处

  • 兼容性:类型擦除使得 Java 泛型能够与旧的非泛型代码兼容,在引入泛型时不需要对现有的代码进行大规模修改。
  • 性能:避免了为每个泛型类型创建新的类,减少了内存开销。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值