文章标题

来源:互联网 发布:怎么修改tomcat的端口 编辑:程序博客网 时间:2024/05/21 11:35

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:012012*/

现在,编译器可以阻止你将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@325dfb22com.java.chapter11.Gala@147e8bd9com.java.chapter11.Fuji@f5e12com.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

  1. Iterator的子类型
  2. 只能用于各种List类的访问
  3. Iterator只能向前移动,ListIterator可以双向移动

11.7 LinkedList

11.8 Stack

11.9 Set

11.10 Map

11.11 Queue

原创粉丝点击