美文网首页Java
【Java高级】有界泛型及使用注意事项

【Java高级】有界泛型及使用注意事项

作者: 大栗几 | 来源:发表于2020-05-26 22:27 被阅读0次

本文为原创文章,转载请注明出处
查看[Java]系列内容请点击:https://www.jianshu.com/nb/45938443

限定必需继承自某个类

当我们需要限定泛型对象必需是继承自某一个类或者接口的时候,我们使用:

<T extends MyInterface>

例如以下代码:

public interface MyInterface {
    void run();
}

public class MainTest {

    public static void main(String[] args) {
    }

    // 不限定类型,需要强制转换
    public static <T> void fun1(T obj) {
        MyInterface myInterface = (MyInterface) obj;
        myInterface.run();
    }

    // 限定类型,不需要强制转换
    public static <T extends MyInterface> void fun2(T obj) {
        obj.run();
    }
}

对比fun1fun2方法,可以看到,fun2限定了T必需是MyInterface的子类型,从而可以直接调用MyInterface接口中的方法,而不需要强制转换。

可以定义多个复杂的限定类型:

public static <T extends MyInterface & MyInterface1, U extends MyInterface> void fun2(T obj, U obj1)

那么所传的obj参数必需同时继承自MyInterfaceMyInterface1两个父接口,obj1必需继承自MyInterface接口。

我们称MyInterfaceMyInterface1T的超类型,T可以有多个超类型,超类型最多只允许有一个是类,且类必需是限定列表中的第一个,其余都是接口(与Java的继承机制保持一致)。

问号通配符及其由来

通配符由来

考虑下面一段程序:

public class MainTest {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>() {{
            put("1", "1");
        }};

        /*
        * 这里出错,因为 Map<String, String> 不是 Map<String, Object> 类型的子类型,
        * 所以参数类型不匹配
        * */
        fun1(map);
    }

    public static void fun1(Map<String, Object> map) {
        System.out.println(map);
    }
}

在调用fun1方法的时候,实际需要的参数类型是Map<String, Object>类型,而实际传参是Map<String, String>类型,所以这里就会报错:参数类型不匹配。

那么,怎么解决这个问题?可以考虑由通配符来解决问题。

问号通配符

下面列出使用继承等方式分三种方式解决问题:

public class MainTest {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>() {{
            put("1", "1");
        }};

        // 正确
        fun1(map);
        fun2(map);
        fun3(map);
    }

    public static <T extends Object> void fun1(Map<String, T> map) {
        T a = null; // 可以使用变量类型T
        System.out.println(map);
    }

    public static void fun2(Map<String, ? extends Object> map) {
        // 只做限定使用
        //Map<String, ? extends Object>是Map<String, String>的父类型
        System.out.println(map);
    }

    public static void fun3(Map<String, ?> map) {
        // 不限定
        System.out.println(map);
    }
}

就像注释中说到的一样,使用?来作为通配符,在程序里面不能声明一样类型的变量。

一个限制:
当我们进行赋值时,看下面代码:

public class MainTest {
    static Pair<MyInterface> p;

    public static void main(String[] args) {
    }

    public static void fun1(Pair<? extends MyInterface> pair) {
        /*
        * 报错,这是因为 Pair<? extends MyInterface>是父类型 
        * Pair<MyInterface> 是子类型,子类型可以赋值给父类型
         * */
        p = pair;
        pair = p; // 正确
    }
}

这里一定要注意!!!

与之相反,还有一个super关键字:

public class MainTest {
    static Pair<? super MyInterface> p;

    public static void main(String[] args) {
    }

    public static void fun1(Pair<MyInterface> pair) {
        /*
        * 正确,Pair<? super MyInterface>是父类型
        * Pair<MyInterface> 是子类型,子类型可以赋值给父类型
        * */
        p = pair;
    }
}

其中:

<? super MyInterface> 表示MyInterface的所有超类型,所以,Pair<MyInterface>Pair<? super MyInterface>的子类型

  • 这里其实不是很好理解,<? super MyInterface>其实更应该写成<MyInterface extends ?>,只不过Java不支持这种写法,意思是一样的,便于理解。

super关键字表示的方式叫做通配符的超类型限定,与extends正好相反。

相关文章

  • 【Java高级】有界泛型及使用注意事项

    本文为原创文章,转载请注明出处查看[Java]系列内容请点击:https://www.jianshu.com/nb...

  • 泛型介绍

    各种泛型定义及使用 1、泛型类定义及使用 我们先看看泛型的类是怎么定义的: [java]view plaincop...

  • Java 泛型

    01.泛型 泛型的本质是参数化类型,使用泛型可以获得更高级的抽象。 Java泛型(generics)是JDK 5 ...

  • Kotlin-泛型和委托

    泛型 泛型的使用是为了程序有更好的扩展性。泛型类和泛型方法 泛型的高级特性java的泛型是通过类型擦除机制来实现的...

  • 泛型接口,类和通配符

    java零基础入门-高级特性篇(六) 泛型 中 泛型的使用位置,除了最常见的约束集合元素,还可以使用在接口,类,方...

  • Java基础(一)

    Java要点1 JAVA基础 1.对抽象、继承、多态的理解 2.泛型的作用及使用场景 1.Java泛型是JDK1....

  • Java高级语言特性之泛型

    Java高级语言特性之泛型 Java泛型(generics)是JDK 5中引入的一个新特性,泛型提供了编译时类型安...

  • Kotlin泛型的高级特性(六)

    泛型的高级特性1、泛型实化2、泛型协变3、泛型逆变 泛型实化 在Java中(JDK1.5之后),泛型功能是通过泛型...

  • Java 泛型

    泛型概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。什么是泛型?为什么要使用...

  • FastJson解析封装

    导包 方法 注意事项 使用时涉及到泛型相关,泛型 T 要转的类必须要有无参构造方法,一般 Java 默认就有,如果...

网友评论

    本文标题:【Java高级】有界泛型及使用注意事项

    本文链接:https://www.haomeiwen.com/subject/tqkbahtx.html