十(3)、泛型与数组以及泛型的边界

一、首先要强调,数组不支持泛型

1.数组是编译期间检查并且要求有确定类型存在, 而泛型由于擦除的存在, 类型信息被删除, 所以数组不支持泛型。

见下例:

 1 import java.lang.reflect.Array;
 2 import java.util.Arrays;
 3
 4 /**
 5 * 创建一个类,它支持泛型, 本意是希望提供一个方法,该方法
 6 * 能够根据泛型来返回一个该类型的数组
 7 */
 8 public class ArrayMarker<T> {
 9     private Class<T> kind;
10     public ArrayMarker(Class<T> kind) {
11         this.kind = kind;
12     }
13
14     T[] create(int size) {//创建方法
15         return (T[])Array.newInstance(kind, size);
16     }
17
18     public static void main(String[]args) {
19         ArrayMarker<String> stringMarker =
20             new ArrayMarker<String>(String.class);
21
22         String[] stringArray = stringMarker.create(9);
23         System.out.println(Arrays.toString(stringArray));
24     }
25 }

结果如下:

可以看到, 虽然尝试传递类型, 但是由于泛型的存在将类型信息删除, 最终生成的只是null。

2.泛型删除的只是类型信息,而不是值本身

这点需要注意, 泛型并不会删除传过去的值本身, 只是传过去的值对它来说不再有原来的类型信息, 见下例:

 1 public class ArrayMarker<T> {
 2     private Class<T> kind;
 3     public ArrayMarker(Class<T> kind) {
 4         this.kind = kind;
 5     }
 6
 7     T[] create(int size) {
 8         return (T[])Array.newInstance(kind, size);
 9     }
10
11     T[] create2(T t,int size) {
12         T[] tarr = (T[])Array.newInstance(kind, size);
13         for(int i=0;i<tarr.length;i++) {
14             tarr[i] = t;//值设置
15         }
16         return tarr;
17     }
18
19     public static void main(String[]args) {
20         ArrayMarker<String> stringMarker =
21             new ArrayMarker<String>(String.class);
22
23         String[] stringArray = stringMarker.create2("hello",4);
24         System.out.println(Arrays.toString(stringArray));
25     }
26 }

结果如下:

并不是说由于擦除的存在,导致T本身,就变成Object了, 只是说它的具体类型信息Class里面的东西,被擦除掉, 但是方法指针什么还在,还能够调用a方法, 还能够显示T的值,只是T.t.getClass()的时候,返回的已经不是Weight 的类型信息了,它的类型信息已经被擦除 。

如果要关联上泛型来使用容器, 不要使用数组, 使用Collection,Map。

3.关于泛型和数组,再看两个例子:

 二、泛型的边界

1.extends关键字

前面的博客中,有提到使用<T  extends HasF> 这种形式来确定边界 ,下面是一个更复杂的例子:

  1 import java.awt.Color;
  2 //定义一个颜色接口
  3 interface HasColor {
  4     Color getColor();
  5 }
  6
  7 //定义一个着色类,注意 T这里继承的是接口,说明T也是接口类型
  8 class Colored<T extends HasColor> {
  9     T item;
 10     Colored(T item) {
 11         this.item = item;
 12     }
 13     T getItem() {
 14         return this.item;
 15     }
 16
 17     Color color() {
 18         return item.getColor();
 19     }
 20 }
 21
 22 //定义一个三维类
 23 class Dimension {
 24     public int x,y,z;
 25 }
 26
 27
 28 //这里报错,首先了解到可以用&来这么写, 另一个问题就是如果这么写,必须要先写类,后写接口
 29 //class ColoredDimension<T extends HasColor & Dimension> {
 30 //
 31 //}
 32
 33 class ColoredDimension<T extends Dimension & HasColor > {
 34     T item;
 35     public ColoredDimension(T item) {
 36         this.item = item;
 37     }
 38
 39     T getItem() {
 40         return this.item;
 41     }
 42
 43     Color color() {
 44         return item.getColor();
 45     }
 46
 47     int getX() {
 48         return item.x;
 49     }
 50
 51     int getY() {
 52         return item.y;
 53     }
 54
 55     int getZ() {
 56         return item.z;
 57     }
 58
 59 }
 60
 61 interface Weight {
 62     int weight();
 63 }
 64
 65 /**
 66  * 这里,还能够在泛型中extends关键字后面写多个接口
 67  */
 68 class Solid<T extends Dimension & HasColor & Weight> {
 69     T item;
 70     public Solid(T item) {
 71         this.item = item;
 72     }
 73
 74     T getItem() {
 75         return this.item;
 76     }
 77
 78     Color color() {
 79         return item.getColor();
 80     }
 81
 82     int getX() {
 83         return item.x;
 84     }
 85
 86     int getY() {
 87         return item.y;
 88     }
 89
 90     int getZ() {
 91         return item.z;
 92     }
 93
 94     public int weight() {
 95         return item.weight();
 96     }
 97 }
 98
 99 /**
100  * 这里,继承Dimension ,并且实现HasColor,Weight接口,但是没采用泛型
101  */
102 class Bounded extends Dimension implements HasColor,Weight {
103     public Color getColor() {
104         return null;
105     }
106
107     public int weight() {
108         return 0;
109     }
110 }
111
112 public class BasicBounds {
113     public static void main(String[] agrs) {
114         Solid<Bounded> solid = new Solid<Bounded>(new Bounded());
115
116         System.out.println(solid.color());
117         System.out.println(solid.getY());
118         System.out.println(solid.weight());
119     }
120 }

简单的理解,就是泛型可以用<T extends HasColor & Dimension> 这种形式来确定边界 ,extends哪个,就可以仍然拥有哪个类的方法(可以参考之前博客的例子) ,并且extends后面也可以接接口, 用&来连接。

但是不支持<T  implements  Dimension>这种形式。

2.extends关键字的反面 super关键字 (逆变)

首先看一个例子:

 1 import java.util.ArrayList;
 2 import java.util.List;
 3
 4 public class ConvariantArrays {
 5     public static void main(String[] args) {
 6         List<? extends Father> list = new ArrayList<Son>();
 7         list.add(null);
 8 //        list.add(new Father()); //报错
 9 //        list.add(new Son());    //报错
10 //        list.add(new Object()); //报错
11
12     }
13 }
14
15 class Father {}
16
17 class Son extends Father {}

这里看似是只要extends Father的类都能放入,但是事实上除了放入null, 其他包括放Object都会报错。

但是类似的如果用super关键字

 1 import java.util.ArrayList;
 2 import java.util.List;
 3
 4 public class SuperTypeWildcards {
 5
 6     public static void main(String[] args) {
 7         List<? super Apple> list = new ArrayList<Apple>();
 8         list.add(new Apple());
 9     }
10 }

这里可以成功。如果大神路过,求给个解释一下。

时间: 2024-08-14 04:39:01

十(3)、泛型与数组以及泛型的边界的相关文章

爪哇国新游记之十五----泛型动态数组类

import java.lang.reflect.Array; /** * 泛型动态数组类 * */ public class DynamicArray<T extends Object>{ private T[] arr; private Class<T> type; private int currCount; private static final int InitSize=2; public DynamicArray(Class<T> type){ this.

泛型的其他应用-接口,方法定义使用,泛型数组,泛型的嵌套设置。

掌握泛型的接口的使用: 掌握泛型方法的定义与使用: 掌握泛型数组的使用: 掌握泛型的嵌套设置: 具体内容 1.1泛型接口基本概念 之前所有的操作都是在类中直接使用泛型操作的,那么,对于JAVA来说,也可以在接口中定义及使用泛型. 声明泛型接口: interface 接口名称<接口标示>{} interface Info<T> { public T getInfo(); } 如果现在一个子类实现此接口是没有进行正确的实现,则在编译时候会出现警告, 例子: interface Info

基于泛型的数组列表

在<数组和数组列表>那篇随笔里我们定义了一个int类型的数组列表,但是这样实际上是有问题的,在日后的开发中我们使用的数组列表实际上并不一定是int类型的,甚至于,还不一定会是基本数据类型的.那这个时候,按照原来的方法,我们在开发中每要定义一个数组列表,我们就要重写一遍,这样做实际上是非常不友好的.那么有什么方法来解决这一问题呢,这样我们便引出了泛型这个概念 泛型 什么是泛型?泛型简单来理解实际上就是一个类类型,它是表示一个类的类型,而不具体表示某一个对象.由于在此重点是数组列表,关于泛型的其他

重学《C#高级编程》(泛型与数组)

前段时间工作比较忙,就没有写随笔了,现在继续. 前两天重新看了泛型和数组两章,简单说下我自己的收获吧 泛型 我们知道数组是一种批量的数据格式,而泛型其实就是一种自定义的批量数据格式,当数组和C#现有的泛型类List和Dictionary<K,V>不满足我们的要求时,我们可以自己创建泛型类,具体怎么创建就不在这里一一解释了,要创建时再去找解决方案吧(个人感觉完全没必要去纠结每一个功能如何实现,真要使用时可以去网上搜到大把的实现方式,我们只要知道有这样一种解决方案,可以实现这样一个功能就行). 泛

从头认识java-13.11 对比数组与泛型容器,观察类型擦除给泛型容器带来什么问题?

这一章节我们继续类型擦除的话题,我们将通过对比数组与泛型容器,观察类型擦除给泛型容器带来什么问题? 1.数组 package com.ray.ch13; public class Test { public static void main(String[] args) { Fruit[] fruits = new Apple[5]; fruits[0] = new Apple(); fruits[1] = new Fuji(); fruits[2] = new Fruit(); } } cla

从头认识java-13.11 对照数组与泛型容器,观察类型擦除给泛型容器带来什么问题?

这一章节我们继续类型擦除的话题,我们将通过对照数组与泛型容器,观察类型擦除给泛型容器带来什么问题? 1.数组 package com.ray.ch13; public class Test { public static void main(String[] args) { Fruit[] fruits = new Apple[5]; fruits[0] = new Apple(); fruits[1] = new Fuji(); fruits[2] = new Fruit(); } } cla

Java泛型的其他应用——泛型接口、泛型方法、泛型数组以及泛型的嵌套设置

学习目标 掌握泛型接口的使用 掌握泛型方法的定义的及使用 掌握泛型数组的使用 掌握泛型的嵌套设置 之前所有的操作都是在类中直接使用泛型操作的,那么,对于Java来说,也可以直接在接口中定义及使用泛型. 定义泛型接口 在JDK1.5之后,不仅仅可以声明泛型类,也可以声明泛型接口,声明泛型接口和声明泛型类的语法类似,也是在接口名称后面加上<T>,如下格式所示: [访问权限]  interface 接口名称<泛型标识>{} interface Info<T>{ // 在接口上

自定义泛型_无多态_通配符无泛型数组_jdk7泛型使用

通配符 T, K, V, E 等泛型字母为有类型, 类型参数赋予具体的值 ? 未知类型 类型参数赋予不确定值, 任意类型 只能用在 声明类型上,方法参数上, 不能用在定义泛型类上 上限 extends, 指定类型必须是继承某个子类. 或者实现某个接口 (不是用 implements), 即 <= 如 ? extends Fruit ? extends List 不能添加信息 存在以下规则, 如 List<Fruit> 满足 List<? extends Fruit> List

数组与泛型容器区别

一.基本 class Shape{ void draw(){ System.out.println(this+".draw()"); } } class Circle extends Shape{ @Override public String toString() { return "Circle"; } } class Rect extends Shape{ @Override public String toString() { return "Re