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

在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中需要考虑到元素重复的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值