Java se泛型

集合中的泛型是Java等编程语言中一种强大的特性,它允许在编译时期而不是运行时期检查集合中元素的类型。通过使用泛型,可以创建可以工作于任何类型的集合,同时保持类型安全。这意味着,当你尝试向集合中添加不兼容类型的元素时,编译器会报错,而不是在运行时抛出异常。

泛型的好处

  1. 类型安全:泛型集合可以确保你只能插入正确类型的对象,并在编译时检查类型错误。
  2. 消除强制类型转换:使用泛型后,从集合中取出的对象不需要再进行强制类型转换。
  3. 提高代码的重用性:你可以编写与类型无关的通用代码,这些代码可以用于多种数据类型。 

泛型通配符 

泛型通配符(?)用于表示未知的类型。它可以作为类型参数使用,但只能用于读取集合中的元素,不能用于写入。泛型通配符有三种形式:

  • ?:未知类型,只读。
  • ? extends T:未知类型,但它是T或T的子类,表示上限通配符,用于读取。
  • ? super T:未知类型,但它是T或T的父类,表示下限通配符,用于写入。

泛型方法

泛型不仅可以用于类,还可以用于方法。泛型方法允许你定义一个方法,该方法可以操作多种类型的数据。在方法声明时,你可以在返回类型之前指定一个或多个类型参数。

  • 当你不知道该方法要传递什么类型的参数时,可以使用泛型
  • 用T表示一个要出入的未知类型参数
  • 泛型方法有很好的复用性,此时使用不同类型的参数,就不需要再去创建别的方法了
public static <T> void printArray(T[] inputArray) {  
    for (T element : inputArray) {  
        System.out.printf("%s ", element);  
    }  
    System.out.println();  
}  
  
// 使用示例  
Integer[] intArray = { 1, 2, 3, 4, 5 };  
printArray(intArray);  
  
String[] stringArray = { "Hello", "World" };  
printArray(stringArray);

泛型类 

泛型类在类名后紧跟一对尖括号<>,并在尖括号中声明类型参数。类型参数是一种占位符,用于表示在实例化类时将用实际类型替换的类型。

public class Box<T> {  
    //T 代表“类型”——但应该使用有意义的名称,如 E、K、V 等。 
    private T t;  
  
    public void set(T t) {  
        this.t = t;  
    }  
  
    public T get() {  
        return t;  
    }  
}

在这个例子中,Box是一个泛型类,它有一个类型参数T。这意味着Box类可以与任何类型一起工作,具体取决于实例化Box时指定的类型。

泛型类的实例化

Box<Integer> integerBox = new Box<>();  
integerBox.set(123);  
Integer value = integerBox.get();  
  
Box<String> stringBox = new Box<>();  
stringBox.set("Hello");  
String anotherValue = stringBox.get();

在这个例子中,分别实例化了Box的两个对象:integerBoxstringBox

我们指定了Box的类型参数分别为IntegerString

因此,integerBox只能存储Integer类型的对象,而stringBox只能存储String类型的对象。

集合中的泛型 

  1. 假设有一个函数 fun(Animal animal),如果我们传入一个Dog d 对象进去,编译器是不会报错的,这是多态的概念;
  2.  假设有一个函数 fun(Animal[] animals),如果我们传如一个Dog[] dogs数组进去,编译器也不会报错,这就是数组的协变性;
  3. 假设有一个函数 fun(List<Animal>  animal), 如果我们传如一个List <Dog>  dog 集合进去,编译器就会报错了,这就是集合泛型的不变性;

那么该怎么办呢?

我们可以将泛型改成这样 fun (List <? extends Animal> ),这样之后,当我们再 传入一个List <Dog>  dog 集合进去,编译器就就不会报错了。也就是说可以传入包含Animal的子类的List了。

定义三个实体类

// 定义一个Animal类  
class Animal {  
    void eat() {  
        System.out.println(" animal eats food.");  
    }  
}  
  
// 定义一个Dog类,继承自Animal  
class Dog extends Animal {  
    void bark() {  
        System.out.println("Woof!");  
    }  
}  
  
// 定义一个Cat类,也继承自Animal  
class Cat extends Animal {  
    void meow() {  
        System.out.println("Meow!");  
    }  
}  
  

实现集合泛型 

public class Generic {  
  
    // 使用? extends Animal作为类型参数,表示这个方法可以接受任何Animal或Animal子类的List  
    public static void processAnimals(List<? extends Animal> animalList) {  
        for (Animal animal : animalList) {  
            animal.eat(); // 合法,因为所有Animal及其子类都有eat方法  
            // animal.bark(); // 非法,编译器不知道animalList具体是Dog还是其他Animal子类  
        }  
    }  


  
    public static void main(String[] args) {  
        List<Dog> dogs = new ArrayList<>();  
        dogs.add(new Dog());  
          
        List<Cat> cats = new ArrayList<>();  
        cats.add(new Cat());  
          
        // 由于processAnimals方法使用了? extends Animal,它可以接受dogs和cats  
        processAnimals(dogs);  
        processAnimals(cats);  
    }  
}

 在这个例子中,processAnimals方法接受一个List<? extends Animal>类型的参数,这意味着它可以接受任何List<Animal>List<Dog>List<Cat>等列表,只要这些列表中的元素类型是Animal或其子类。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值