您的位置:首页 > 编程语言 > Java开发

JAVA中泛型和类型安全的容器

2017-07-27 09:46 417 查看
在JAVA中,同样具备同C++那样方便的容器,比如ArrayList,它可以被当做“可以自动扩充自身尺寸的数组”来使用。看一段代码:

package access;
import java.util.*;
class Apple{
private static long counter;
private final long id = counter++;
public long id(){
return id;
}
}
class Orange{}

public class ApplesAndOrangesWithoutGenerics {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList apples = new ArrayList();
for(int i =0;i < 3; i++)
apples.add(new Apple());
apples.add(new Orange());
for(int i = 0 ; i < apples.size(); i++)
((Apple)apples.get(i)).id();
}

}
上述例子并未使用泛型,Apple和Orange类是有区别的,它们都继承自Object,由于ArrayList保存的是Object,因此我们不仅可以添加Apple对象,还可以添加Orange对象,但是当我们从ArrayList中取出来我们认为的Apple对象时,我们得到的仅仅是Object的引用,必须将其转换为Apple,所以最后需要一对()来括起来,另外在Orange进行强制转换时会发生错误,所以我们应当使用泛型,修改上述代码:
package access;
import java.util.*;
class Apple{
private static long counter;
private final long id = counter++;
public long id(){
return id;
}
}
class Orange{}
public class ApplesAndOrangesWithGenerics {

public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<Apple> apples = new ArrayList<Apple>();
for(int i = 0; i < 3; i++ )
apples.add(new Apple());
for(int i = 0; i < apples.size(); i++)
System.out.println(apples.get(i).id());
for(Apple c : apples)
System.out.println(c.id());
}

}
此程序运行结果为:



现在,编译器将阻止我们将Orange放入ArrayList中,并且在元素从ArrayList中取出时,类型转换也不再需要,因为ArrayList知道保存的类型,它会在调用get()时自动为我们转型。

而当我们指定了某个类型作为泛型参数时,并不仅限于只能将确切的此类型的对象放置到容器中,向上转型也同样可以像作用于其他类型一样作用于泛型,看如下一段代码:

package access;
import java.util.*;
class Apple{
private static long counter;
private final long id = counter++;
public long id(){
return id;
}
}
class GrannySmith extends Apple{}
class Gala extends Apple{}
class Fuji extends Apple{}
class Braeburn extends Apple{}
public class GenericsAndUpcasting {

public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<Apple> apples = new ArrayList<Apple>();
apples.add(new GrannySmith());
apples.add(new Gala());
apples.add(new Fuji());
apples.add(new Braeburn());
for(Apple c : apples)
System.out.println(c);
}

}
此程序的输出结果为:



该程序的输出是从Object默认的toString方法产生的,该方法会打印类名,后跟该对象的散列码的无符号十六进制表示,其中散列码通过hashCode方法产生。

JAVA容器类类库的作用是“保存对象”,并将其划分为两个概念:

1.Collection:一个独立元素的序列,这些元素服从一条或多条规则。List必须按照插入的顺序保存元素;Set不能有重复的元素。Quene按照排队规则确定对象产生的顺序,通常情况下与它们被插入的顺序相同。

2.Map:一组成对的“键值对”对象,允许我们按照键来查找值。ArrayList允许我们使用数字来查找值,它将数字与对象关联在一起。映射表允许我们使用另一个对象查找某个对象,被称作关联数组,将某些对象与另一些对象关联在了一起,Map的运用范围非常广泛。

在理想情况下,我们编写的大部分代码都是与这些接口打交道,并且我们唯一需要指定所使用的精确类型的地方在创建的时候:

List<Apple> apples = new ArrayList<Apple>();

此时ArrayList被上转型为List,使用接口的目的在于如果我们决定去修改我们的实现,我们只需在创建出修改它:

List<Apple> apples = new linkedList<Apple>();

因此我们应该创建一个具体类的对象,将其转型为对应的接口,然后在其余的代码中使用此接口。

但由于某些类有特定的方法和功能,比如LinkedList有在List中未包含的额外方法,而TreeMap也有在Map接口中未包含的额外方法,如果我们需要使用到这些方法,就不能上转为通用接口。

Collection接口概况了序列的概念:一种存放一组对象的方式。看下面一段代码:

package access;
import java.util.*;
public class SimpleCollection {

public static void main(String[] args) {
// TODO Auto-generated method stub
Collection<Integer> c = new ArrayList<Integer>();
for(int i = 0; i < 10; i++){
c.add(i);
}
for(Integer i : c)
System.out.print(i + ", ");
}

}
此程序的输出结果为:



任何继承自Collection的类的对象均可正常工作,ArrayList是最基本的的序列类型。所有的Collection也都可以用foreach语法进行遍历操作。在ArrayList中add方法只是添加,而在Set中需要考虑到元素重复的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 容器
相关文章推荐