Java泛型通配符案例如何用

wen java案例 28

本文目录导读:

Java泛型通配符案例如何用

  1. 通配符基础语法
  2. 核心使用场景
  3. 实用案例:动物园管理系统
  4. PECS原则(Producer Extends, Consumer Super)
  5. 实际项目应用
  6. 使用原则总结
  7. 学习建议:

这是Java泛型通配符的完整学习指南,包含核心概念和实用案例:

通配符基础语法

// 无界通配符
List<?> list1 = new ArrayList<String>();
List<?> list2 = new ArrayList<Integer>();
// 上界通配符(只能读)
List<? extends Number> list3 = new ArrayList<Integer>();
// 下界通配符(只能写)
List<? super Integer> list4 = new ArrayList<Number>();

核心使用场景

无界通配符

public class UnboundedWildcard {
    // 打印任意类型列表
    public static void printList(List<?> list) {
        for (Object element : list) {
            System.out.print(element + " ");
        }
        System.out.println();
    }
    public static void main(String[] args) {
        List<Integer> intList = Arrays.asList(1, 2, 3);
        List<String> strList = Arrays.asList("A", "B", "C");
        List<Double> dblList = Arrays.asList(1.1, 2.2);
        printList(intList);
        printList(strList);
        printList(dblList);
    }
}

上界通配符 ? extends T

public class UpperBoundedWildcard {
    // 计算数字列表总和
    public static double sumList(List<? extends Number> list) {
        double sum = 0;
        for (Number num : list) {
            sum += num.doubleValue();
        }
        return sum;
    }
    // 复制列表(只读)
    public static void copyList(List<? extends Number> src, List<? super Number> dest) {
        for (Number num : src) {
            dest.add(num);
        }
    }
    public static void main(String[] args) {
        List<Integer> ints = Arrays.asList(1, 2, 3);
        System.out.println("Sum: " + sumList(ints));
        List<Double> doubles = Arrays.asList(1.1, 2.2);
        System.out.println("Sum: " + sumList(doubles));
    }
}

下界通配符 ? super T

public class LowerBoundedWildcard {
    // 向列表添加整数(只写)
    public static void addIntegers(List<? super Integer> list) {
        for (int i = 1; i <= 5; i++) {
            list.add(i);
        }
    }
    public static void main(String[] args) {
        List<Number> numList = new ArrayList<>();
        List<Object> objList = new ArrayList<>();
        addIntegers(numList);
        addIntegers(objList);
        System.out.println("Number list: " + numList);
        System.out.println("Object list: " + objList);
    }
}

实用案例:动物园管理系统

// 动物类层次
class Animal {
    String name;
    Animal(String name) { this.name = name; }
    public String toString() { return name; }
}
class Dog extends Animal {
    Dog(String name) { super(name); }
    void bark() { System.out.println(name + " 汪汪"); }
}
class Cat extends Animal {
    Cat(String name) { super(name); }
    void meow() { System.out.println(name + " 喵喵"); }
}
// 动物园类
public class Zoo {
    // 1. 无界通配符 - 展示所有动物
    public static void showAllAnimals(List<?> animals) {
        System.out.println("=== 所有动物 ===");
        for (Object animal : animals) {
            System.out.println(animal);
        }
    }
    // 2. 上界通配符 - 让动物表演(只读)
    public static void performTricks(List<? extends Animal> performers) {
        System.out.println("=== 表演开始 ===");
        for (Animal animal : performers) {
            System.out.println(animal + " 表演了一个节目");
        }
    }
    // 3. 下界通配符 - 添加动物(只写)
    public static void addDogToGroup(List<? super Dog> dogGroup) {
        System.out.println("=== 添加狗狗 ===");
        dogGroup.add(new Dog("小黑"));
        dogGroup.add(new Dog("旺财"));
    }
    // 4. 生产者-消费者模式
    public static <T> void copyAnimals(
            List<? extends T> source,  // 生产者
            List<? super T> dest) {    // 消费者
        for (T animal : source) {
            dest.add(animal);
        }
    }
    public static void main(String[] args) {
        // 准备动物列表
        List<Dog> dogs = new ArrayList<>();
        dogs.add(new Dog("小黑"));
        dogs.add(new Dog("旺财"));
        List<Cat> cats = new ArrayList<>();
        cats.add(new Cat("咪咪"));
        cats.add(new Cat("花花"));
        // 1. 无界通配符使用
        List<Animal> allAnimals = new ArrayList<>();
        allAnimals.addAll(dogs);
        allAnimals.addAll(cats);
        showAllAnimals(allAnimals);
        // 2. 上界通配符使用
        performTricks(dogs);  // List<Dog> -> List<? extends Animal>
        performTricks(cats);  // List<Cat> -> List<? extends Animal>
        // 3. 下界通配符使用
        List<Animal> animalGroup = new ArrayList<>();
        addDogToGroup(animalGroup);  // List<Animal> -> List<? super Dog>
        System.out.println("动物组: " + animalGroup);
        // 4. 生产者-消费者模式
        List<Object> zooList = new ArrayList<>();
        copyAnimals(dogs, zooList);  // 复制狗狗到动物园列表
        copyAnimals(cats, zooList);  // 复制猫猫到动物园列表
        System.out.println("Zoo列表: " + zooList);
        // 5. 常见错误示例
        /*
        List<? extends Animal> extAnimal = new ArrayList<Dog>();
        extAnimal.add(new Dog("错误"));  // 编译错误!不能写入
        List<? super Dog> supDog = new ArrayList<Animal>();
        supDog.add(new Dog("正确"));     // 可以!Dog是Dog的子类
        supDog.add(new Animal("错"));   // 编译错误!Animal不是Dog的子类
        */
    }
}

PECS原则(Producer Extends, Consumer Super)

public class PECSExample {
    // 方法1:读取数据(生产者)
    public static <T> void readFrom(List<? extends T> producer) {
        // 只能读取,不能写入
        T item = producer.get(0);
        System.out.println("读取: " + item);
    }
    // 方法2:写入数据(消费者)
    public static <T> void writeTo(List<? super T> consumer, T item) {
        // 只能写入,不能读取(读取为Object类型)
        consumer.add(item);
        Object obj = consumer.get(0);  // 只能读取为Object
    }
    // 方法3:复制数据(同时使用)
    public static <T> void copy(
            List<? extends T> source,   // 只读(生产者)
            List<? super T> dest) {     // 只写(消费者)
        for (T item : source) {
            dest.add(item);
        }
    }
    public static void main(String[] args) {
        List<Integer> ints = Arrays.asList(1, 2, 3);
        List<Number> nums = new ArrayList<>();
        // 正确用法
        copy(ints, nums);  // Integer -> Number
        System.out.println("Copy结果: " + nums);
        // 错误用法示例
        // copy(nums, ints);  // 编译错误!Number不能赋值给Integer
    }
}

实际项目应用

// 比较器工具类
public class WildcardComparator {
    // 比较两个集合的最大值
    public static <T extends Comparable<T>> T max(
            List<? extends T> list) {
        if (list.isEmpty()) return null;
        T max = list.get(0);
        for (T item : list) {
            if (item.compareTo(max) > 0) {
                max = item;
            }
        }
        return max;
    }
    // 排序(使用通配符使方法更灵活)
    public static <T> void sort(List<T> list, 
            Comparator<? super T> comparator) {
        list.sort(comparator);
    }
}
// 使用示例
public class Demo {
    public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(3, 1, 4, 1, 5);
        // 通配符使得Comparator可以接收父类比较器
        WildcardComparator.sort(nums, 
            (Comparator<Number>) (a, b) -> 
                Integer.compare(a.intValue(), b.intValue()));
        System.out.println("排序后: " + nums);
        System.out.println("最大值: " + WildcardComparator.max(nums));
    }
}

使用原则总结

// 通配符使用速查表
public class WildcardSummary {
    /*
     * 1. 只读(获取数据):? extends T
     * 2. 只写(添加数据):? super T
     * 3. 既读又写:不使用通配符
     * 4. 读写都可以但类型不重要:?(无界通配符)
     * 
     * PECS原则:
     * - Producer Extends(生产者使用extends)
     * - Consumer Super(消费者使用super)
     */
    // 只读方法
    public void readOnly(List<? extends Number> list) {
        Number n = list.get(0);  // √ 正确
        // list.add(1);          // × 编译错误
    }
    // 只写方法
    public void writeOnly(List<? super Integer> list) {
        list.add(1);             // √ 正确
        Object o = list.get(0);  // √ 但只能得到Object
    }
    // 既读又写(不使用通配符)
    public <T> void readAndWrite(List<T> list, T item) {
        T t = list.get(0);
        list.add(item);
    }
}

学习建议:

  1. 记住PECS原则 - 这是通配符使用的核心
  2. 理解编译时安全 - 通配符在编译期检查类型安全
  3. 多看源码 - Java集合框架大量使用通配符
  4. 实践验证 - 编写代码测试不同通配符的效果

通配符的主要目的是增加API的灵活性,让方法能接受更多类型的参数,同时保持类型安全。

抱歉,评论功能暂时关闭!