java的“?”通配符

通配符

通配符解决的是:一个方法可以接收所有的泛型类型,但是又不能够让用户随意修改。

?通配符:作用于方法参数声明:

​​​​​​​public static void print(MyClass<?> myClass){
}

为什么 有通配符?

在类中追加了泛型的定义后,避免了ClassCastException的问题,但是又会产生新的情况:参数的统一问题

什么 意思???看一段代码解释:

这段代码用泛型定义了一个Message类,在主类里写了个方法打印Message创建的对象的message属性

class Message<T> {
    private T message;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }
}


public class 通配符 {
    public static void main(String[] args) {
        Message<String> message = new Message<>();
        message.setMessage("hello");
        method(message);
    }
    
    public static void method(Message<String> str){
        System.out.println(str);
    }
}

看上去没有问题,那么void main里new了一个Integer类型的message怎么办?调用method方法就会报错

public class 通配符 {
    public static void main(String[] args) {
        Message<Integer> message = new Message<>();
        message.setMessage(123);
        method(message);//这里就会报错
    }

    public static void method(Message<String> str){
        System.out.println(str);
    }
}

那么改一下,使用通配符就可以解决问题

public class 通配符 {
    public static void main(String[] args) {
        Message<Integer> message = new Message<>();
        message.setMessage(123);
        method(message);
    }

    public static void method(Message<?> str){
        System.out.println(str);
    }
}

此时方法参数表示可以接受任意类型的Message对象。


使用通配符之后无法设置值

由于无法确定入参的类型,因此“?”通配符下的泛型参数,只能取得类中的属性值,无法进行属性值的设置。

public class 通配符 {
    public static void main(String[] args) {
        Message<Integer> message = new Message<>();
        message.setMessage(123);
        method(message);
    }

    public static void method(Message<?> str){
        str.setMessage("232");//由于不知道str的具体类型,所以不能修改,会报错
        System.out.println(str);
    }
}

无法设置值的解决方案——上下限概念

在"?"的基础上又产生了两个子通配符:
? extends class:设置泛型上限:
例如:? extends Number,表示只能够设置Number或其子类,例如:Integer、Double等;
? super class:设置泛型下限:
例如:? super String,表示只能够设置String及其父类Object。

设置泛型上限——可以用于泛型类的声明,也可用于方法参数。

泛型类上限声明:(T必须是Number类的子类)

//设置上限
class Message<T extends Number>  {
    private T message;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }
}

方法参数声明上限:表示方法入参只能接受Num以及他的子类对象。

public static void method(Message<? extends Number> str){
    str.setMessage("232");//此时仍然无法确定str的具体类型,所以不能修改,会报错
    System.out.println(str);
}

方法参数设置泛型上限仍然只能取得类中属性值,而无法设置,因为父类的值子类不一定能使用(父类不一定能发生向下转型变为子类)。

设置泛型下限——只能用于方法参数

下限声明:? Super 类(>=类):都表示方法入参只能接受类及其父类对象

    public static void method(Message<? super Integer> str){
        str.setMessage(256);//现在可以设置了,因为子类可以天然向上转型
        System.out.println(str);
    }

方法参数设置泛型下限不仅可以取得类中属性值,还可以设置属性值。因为子类可以天然向上转型变成父类。

### Java 通配符类型及其用法 Java 中的通配符(Wildcard)用于泛型编程,提供了一种灵活的方式来处理不同类型的对象。以下是关于通配符的主要类型和用法的详细说明。 #### 1. 无界通配符 无界通配符使用 `?` 表示未知类型。它允许将任何类型的对象传递给泛型类或方法,但不能对其中的对象进行修改[^2]。 ```java public void printList(List<?> list) { for (Object elem : list) { System.out.println(elem); } } ``` 上述代码中,`List<?>` 表示可以接受任意类型的列表,但无法向列表中添加新元素(除了 `null`),因为编译器不知道具体的类型[^3]。 #### 2. 上限通配符 上限通配符使用 `? extends Type` 表示未知类型是 `Type` 或其子类。这种通配符主要用于读取操作,因为它确保了从集合中获取的对象一定是 `Type` 或其子类的实例。 ```java public double sumNumbers(List<? extends Number> numbers) { double sum = 0.0; for (Number number : numbers) { sum += number.doubleValue(); } return sum; } ``` 在上面的例子中,`List<? extends Number>` 表示可以传递 `Number` 或其子类(如 `Integer`、`Double` 等)的列表。由于所有可能的类型都继承自 `Number`,因此可以安全地调用 `doubleValue()` 方法[^3]。 #### 3. 下限通配符 下限通配符使用 `? super Type` 表示未知类型是 `Type` 或其父类。这种通配符主要用于写入操作,因为它允许向集合中添加 `Type` 类型的对象[^2]。 ```java public void addNumbers(List<? super Integer> list) { for (int i = 1; i <= 5; i++) { list.add(i); } } ``` 在上面的例子中,`List<? super Integer>` 表示可以传递 `Integer` 或其父类(如 `Number` 或 `Object`)的列表。由于所有可能的类型都可以接受 `Integer` 对象,因此可以安全地向列表中添加 `Integer` 类型的值[^3]。 #### 4. 通配符的限制 - **不能实例化通配符类型的对象**:例如,`new ArrayList<?>()` 是非法的。 - **无界通配符的限制**:对于 `List<?>`,只能读取对象,但不能添加新对象(除了 `null`)。 - **有界通配符的限制**:`? extends Type` 和 `? super Type` 的具体限制取决于上下文。例如,`? extends Type` 适合读取操作,而 `? super Type` 适合写入操作。 #### 5. 通配符好处 - 提高 API 的灵活性,使得代码能够处理更广泛的数据类型[^2]。 - 减少强制类型转换的需求,从而提高代码的安全性和可读性[^3]。 ### 示例代码 以下是一个综合示例,展示如何使用不同类型通配符: ```java import java.util.ArrayList; import java.util.List; public class WildcardExample { public static void main(String[] args) { List<Integer> intList = new ArrayList<>(); intList.add(1); List<Number> numList = new ArrayList<>(); numList.add(1.0); // 使用无界通配符 printList(intList); // 输出: 1 printList(numList); // 输出: 1.0 // 使用上限通配符 System.out.println(sumNumbers(intList)); // 输出: 1.0 System.out.println(sumNumbers(numList)); // 输出: 1.0 // 使用下限通配符 List<Object> objList = new ArrayList<>(); addNumbers(objList); // 添加 1, 2, 3, 4, 5 } public static void printList(List<?> list) { for (Object elem : list) { System.out.println(elem); } } public static double sumNumbers(List<? extends Number> numbers) { double sum = 0.0; for (Number number : numbers) { sum += number.doubleValue(); } return sum; } public static void addNumbers(List<? super Integer> list) { for (int i = 1; i <= 5; i++) { list.add(i); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值