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

Java编程思想 第11章 持有对象

2017-07-25 23:11 441 查看

Java编程思想 第11章 持有对象

标签(空格分隔): JAVA学习

11.1 泛型和类型安全的容器

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) {
ArrayList apples = new ArrayList();
for (int i = 0; i < 3; i++) {
apples.add(new Apple());
}
// Not prevented from adding an Orange to apples:
apples.add(new Orange());
for (int i = 0; i < apples.size(); i++) {
((Apple)apples.get(i)).id();
// Orange is detected only at run time
}
}
}


Apple和Orange类是有区别的,它们除了都是Object之外没有任何共性(如果一个类没有显式地声明继承自哪个类,那么它自动地继承自Object)。因为ArrayList保存的是Object,因此apples容器不仅可以添加Apple对象,还可以添加Orange对象,而且无论在编译期还是运行时都不会有问题。

但是在运行时,当试图将Orange对象转型为Apple时,就会得到异常:

Exception in thread "main" java.lang.ClassCastException: com.java.chapter11.Orange cannot be cast to com.java.chapter11.Apple
at com.java.chapter11.ApplesAndOrangesWithoutGenerics.main(ApplesAndOrangesWithoutGenerics.java:26)


使用泛型,就可以在编译期防止将错误类型的对象放置到容器中。

public class ApplesAndOrangesWithoutGenerics2 {
public static void main(String[] args) {
ArrayList<Apple> apples = new ArrayList<Apple>();
for (int i = 0; i < 3; i++) {
apples.add(new Apple());
}
// Compile-time error:
//        apples.add(new Orange());
for (int i = 0; i < apples.size(); i++) {
System.out.println(apples.get(i).id());
}
for (Apple c : apples) {
System.out.println(c.id());
}
}
}
/* Output:
0
1
2
0
1
2
*/


现在,编译器可以阻止你将Orange放置到apples中,因此它变成了一个编译期错误,而不再是运行时错误。

向上转型也可以像作用于其他类型一样作用于泛型:

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) {
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);
}
}
}
/* Output:
com.java.chapter11.GrannySmith@325dfb22
com.java.chapter11.Gala@147e8bd9
com.java.chapter11.Fuji@f5e12
com.java.chapter11.Braeburn@70e8efc5
*/


11.2 基本概念

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

* Collection : 一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序。

* Map : 一组成对的“键值对”对象,允许你使用键来查找值。

11.3 添加一组元素

public class AddingGroups {
public static void main(String[] args) {
Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1, 2, 34, 5));
Integer[] moreInts = {6, 7, 8, 9, 10};
collection.addAll(Arrays.asList(moreInts));
// Runs significantly faster, but you can't
// construct a Collection this way:
Collections.addAll(collection, 11, 12, 13, 14, 15);
Collections.addAll(collection, moreInts);
// Produces a list "backed by" an array:
List<Integer> list = Arrays.asList(16, 17, 18, 19, 20);
list.set(1, 99); // OK -- modify an element
//        list.add(21); // Runtime error because the underlying array cannot be resized
}
}


Arrays.asList()方法的限制是它对所产生的List的类型做出了最理想的假设,而并没有注意你对它会赋予什么样的类型。有时这就会引发问题:

class Snow {}
class Powder extends Snow {}
class Light extends Powder {}
class Heavy extends Powder {}
class Crusty extends Snow {}
class Slush extends Snow {}

public class AsListInference {
public static void main(String[] args) {
List<Snow> snow1 = Arrays.asList(new Crusty(), new Slush(), new Powder());
// Won't compile:
// Compiler says:
// found : java.util.List<Powder>
// required : java.util.List<Snow>
//        List<Snow> snow2 = Arrays.asList(new Light(), new Heavy());

List<Snow> snow3 = new ArrayList<Snow>();
Collections.addAll(snow3, new Light(), new Heavy());

// Give a hint using an
// explit type argument specification:
List<Snow> snow4 = Arrays.<Snow>asList(new Light(), new Powder());
}
}


11.4 容器的打印

public class PrintingContainers {
static Collection fill(Collection<String> collection) {
collection.add("rat");
collection.add("cat");
collection.add("dog");
collection.add("dog");
return collection;
}

static Map fill(Map<String, String> map) {
map.put("rat", "Fuzzy");
map.put("cat", "Rags");
map.put("dog", "Bosco");
map.put("dog", "Spot");
return map;
}

public static void main(String[] args) {
System.out.println(fill(new ArrayList<String>()));
System.out.println(fill(new LinkedList<String>()));
System.out.println(fill(new HashSet<String>()));
System.out.println(fill(new TreeSet<String>()));
System.out.println(fill(new LinkedHashSet<String>()));
System.out.println(fill(new HashMap<String, String>()));
System.out.println(fill(new TreeMap<String, String>()));
System.out.println(fill(new LinkedHashMap<String, String>()));
}
}
/* Output:
[rat, cat, dog, dog]
[rat, cat, dog, dog]
[cat, dog, rat]
[cat, dog, rat]
[rat, cat, dog]
{cat=Rags, dog=Spot, rat=Fuzzy}
{cat=Rags, dog=Spot, rat=Fuzzy}
{rat=Fuzzy, cat=Rags, dog=Spot}
*/


ArrayList和LinkedList都是List类型,它们都按照被插入的顺序保存元素。两者的不同之处仅仅在于执行某些类型的操作时的性能,而且LinkedList包含的操作也多于ArrayList。

HashSet、TreeSet和LinkedHashSet都是Set类型,输出显示在Set中。每个相同的项只保存一次,但是存储元素的方式不同。

HashSet:存储的顺序没有意义,是最快的获取元素方式。

TreeSet:按照比较结果的升序保存对象。

LinkedHashSet:按照被添加的顺序保存对象。

11.5 List

List接口在Collection的基础上添加了大量的方法,使得可以在List的中间插入和移除元素。

有两种类型的List:

基本的ArrayList,它长于随机访问元素,但是在List的中间插入和移除元素时较慢。

LinkedList,它随机访问方面相对比较慢,但通过较低的代价在List中间进行插入和删除操作,提供了优化的顺序访问。

11.6 迭代器

List<Pet> pets = Pets.arrayList(12);
Iterator<Pet> it = pets.iterator();
while (it.hasNext()) {
Pet p = it.next();
}


11.6.1 ListIterator

Iterator的子类型

只能用于各种List类的访问

Iterator只能向前移动,ListIterator可以双向移动

11.7 LinkedList

11.8 Stack

11.9 Set

11.10 Map

11.11 Queue

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: