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

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

限定必需继承自某个类

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


例如以下代码:

public interface MyInterface {
    void run();
}

public class MainTest {

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

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

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

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

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

public static  void fun2(T obj, U obj1)

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

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

问号通配符及其由来

通配符由来

考虑下面一段程序:

public class MainTest {

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

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

    public static void fun1(Map map) {
        System.out.println(map);
    }
}

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

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

问号通配符

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

public class MainTest {

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

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

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

    public static void fun2(Map map) {
        // 只做限定使用
        //Map是Map的父类型
        System.out.println(map);
    }

    public static void fun3(Map map) {
        // 不限定
        System.out.println(map);
    }
}

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

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

public class MainTest {
    static Pair p;

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

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

这里一定要注意!!!

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

public class MainTest {
    static Pair p;

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

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

其中:

表示MyInterface的所有超类型,所以,PairPair的子类型

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

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

你可能感兴趣的:(【Java高级】有界泛型及使用注意事项)