加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

Java泛型的重要目的:别让猫别站在狗队里

发布时间:2020-12-14 06:17:05 所属栏目:Java 来源:网络整理
导读:span class="hljs-class"gt;span class="hljs-keyword"gt;class span class="hljs-title"gt;Dog {}span class="hljs-class"gt;span class="hljs-keyword"gt;class span class="hljs-title"gt;Cat {}span class="hljs-function"gt;span class="hljs-keyword"g

<span class="hljs-class"&gt;<span class="hljs-keyword"&gt;class <span class="hljs-title"&gt;Dog {
}

<span class="hljs-class"&gt;<span class="hljs-keyword"&gt;class <span class="hljs-title"&gt;Cat {
}

<span class="hljs-function"&gt;<span class="hljs-keyword"&gt;public <span class="hljs-keyword"&gt;static <span class="hljs-keyword"&gt;void <span class="hljs-title"&gt;main<span class="hljs-params"&gt;(String[] args) {
    Cmower cmower = <span class="hljs-keyword"&gt;new Cmower();
    Map map = <span class="hljs-keyword"&gt;new HashMap();
    map.put(<span class="hljs-string"&gt;"dog",cmower.new Dog());
    map.put(<span class="hljs-string"&gt;"cat",cmower.new Cat());

    Cat cat = (Cat) map.get(<span class="hljs-string"&gt;"dog");
    System.out.println(cat);
}

}

<p class="line" data-line="42">这段代码的意思是:我们在map中放了一只狗(Dog),又放了一只猫(Cat),当我们想从map中取出猫的时候,却一不留神把狗取了出来。


<p class="line" data-line="44">这段代码编译是没有问题的,但运行的时候就会报ClassCastException(狗毕竟不是猫啊):

 {
}

 
    ,}

<p class="line" data-line="80">其中的put方法(泛型方法)是这样定义的:

<span class="hljs-class"&gt;<span class="hljs-keyword"&gt;class <span class="hljs-title"&gt;Dog {
}

<span class="hljs-class"&gt;<span class="hljs-keyword"&gt;class <span class="hljs-title"&gt;Cat {
}

<span class="hljs-function"&gt;<span class="hljs-keyword"&gt;public <span class="hljs-keyword"&gt;static <span class="hljs-keyword"&gt;void <span class="hljs-title"&gt;main<span class="hljs-params"&gt;(String[] args) {
    Cmower cmower = <span class="hljs-keyword"&gt;new Cmower();
    Map<String,Cat> map = <span class="hljs-keyword"&gt;new HashMap<>();

<span class="hljs-comment">// map.put("dog",cmower.new Dog()); // 不再允许添加
map.put(<span class="hljs-string">"cat",cmower.new Cat());

    Cat cat = map.get(<span class="hljs-string"&gt;"cat");
    System.out.println(cat);
}

}

<p class="line" data-line="111">当使用泛型定义map(键为String类型,值为Cat类型)后:


<p class="line" data-line="113">1)编译器就不再允许你向map中添加狗的对象了。


<p class="line" data-line="115">2)当你从map中取出猫的时候,也不再需要强制转型了。


<h3 class="line" data-line="117">03、类型擦除


<p class="line" data-line="119">有人说,Java的泛型做的只是表面功夫——泛型信息存在于编译阶段(狗队在编译时不允许站猫),运行阶段就消失了(运行时的队列里没有猫的信息,连狗的信息也没有)——这种现象被称为“类型擦除”。


<p class="line" data-line="121">来,看代码解释一下:

<span class="hljs-class"&gt;<span class="hljs-keyword"&gt;class <span class="hljs-title"&gt;Dog {
}

<span class="hljs-class"&gt;<span class="hljs-keyword"&gt;class <span class="hljs-title"&gt;Cat {
}

<span class="hljs-function"&gt;<span class="hljs-keyword"&gt;public <span class="hljs-keyword"&gt;static <span class="hljs-keyword"&gt;void <span class="hljs-title"&gt;main<span class="hljs-params"&gt;(String[] args) {
    Cmower cmower = <span class="hljs-keyword"&gt;new Cmower();
    Map<String,Cat> map = <span class="hljs-keyword"&gt;new HashMap<>();
    Map<String,Dog> map1 = <span class="hljs-keyword"&gt;new HashMap<>();

    <span class="hljs-comment"&gt;// The method put(String,Cmower.Cat) in the type Map<String,Cmower.Cat> is not applicable for the arguments (String,Cmower.Dog)
    <span class="hljs-comment"&gt;//map.put("dog",cmower.new Dog());

    System.out.println(map.getClass());
    <span class="hljs-comment"&gt;// 输出:class java.util.HashMap
    System.out.println(map1.getClass());
    <span class="hljs-comment"&gt;// 输出:class java.util.HashMap
}

}

<p class="line" data-line="149">map的键位上是Cat,所以不允许put一只Dog;否则编译器会提醒The method put(String,Cmower.Dog)。编译器做得不错,值得点赞。


<p class="line" data-line="151">但是问题就来了,map的Class类型为HashMap,map1的Class类型也为HashMap——也就是说,Java代码在运行的时候并不知道map的键位上放的是Cat,map1的键位上放的是Dog。


<p class="line" data-line="153">那么,试着想一些可怕的事情:既然运行时泛型的信息被擦除了,而反射机制是在运行时确定类型信息的,那么利用反射机制,是不是就能够在键位为Cat的Map上放一只Dog呢?


<p class="line" data-line="155">我们不妨来试一试:

<span class="hljs-class"&gt;<span class="hljs-keyword"&gt;class <span class="hljs-title"&gt;Dog {
}

<span class="hljs-class"&gt;<span class="hljs-keyword"&gt;class <span class="hljs-title"&gt;Cat {
}

<span class="hljs-function"&gt;<span class="hljs-keyword"&gt;public <span class="hljs-keyword"&gt;static <span class="hljs-keyword"&gt;void <span class="hljs-title"&gt;main<span class="hljs-params"&gt;(String[] args) {
    Cmower cmower = <span class="hljs-keyword"&gt;new Cmower();
    Map<String,Cat> map = <span class="hljs-keyword"&gt;new HashMap<>();

    <span class="hljs-keyword"&gt;try {
        Method method = map.getClass().getDeclaredMethod(<span class="hljs-string"&gt;"put",Object.class,Object.class);

        method.invoke(map,<span class="hljs-string"&gt;"dog",cmower.new Dog());

        System.out.println(map);
        <span class="hljs-comment"&gt;// {dog=com.cmower.java_demo.sixteen.Cmower$Dog@55f96302}
    } <span class="hljs-keyword"&gt;catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        e.printStackTrace();
    }
}

}

<p class="line" data-line="185">看到没?我们竟然在键位为Cat的Map上放了一只Dog!


<p class="line" data-line="187">注:Java的设计者在JDK 1.5时才引入了泛型,但为了照顾以前设计上的缺陷,同时兼容非泛型的代码,不得不做出了一个折中的策略:编译时对泛型要求严格,运行时却把泛型擦除了——要兼容以前的版本,还要升级扩展新的功能,真的很不容易!


<h3 class="line" data-line="189">04、泛型通配符
<p class="line" data-line="191">有些时候,你会见到这样一些代码:

 list = ();
List list = ();

?和关键字extends或者super在一起其实就是泛型的高级应用:通配符。

 {
     list;
<span class="hljs-function"&gt;<span class="hljs-keyword"&gt;public <span class="hljs-title"&gt;PetHouse<span class="hljs-params"&gt;() {
}

<span class="hljs-function"&gt;<span class="hljs-keyword"&gt;public <span class="hljs-keyword"&gt;void <span class="hljs-title"&gt;add<span class="hljs-params"&gt;(T item) {
    list.add(item);
}

<span class="hljs-function"&gt;<span class="hljs-keyword"&gt;public T <span class="hljs-title"&gt;get<span class="hljs-params"&gt;() {
    <span class="hljs-keyword"&gt;return list.get(<span class="hljs-number"&gt;0);
}

}


<p class="line" data-line="219">如果我们想要住进去一只宠物,可以这样定义小屋(其泛型为Pet):

 petHouse = ();

 petHouse = ();

 petHouse = ();

extends?通配符),但我们却无法向其中添加任何东西——编译器并不知道宠物小屋里要住的是小猫还是小狗,或者其他宠物,因此干脆什么都不让住。

PetHouse定义的宠物小屋什么也不让住,那为什么还要这样定义呢?


(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读