第11章持有对象 _11.1泛型和类型安全的容器

来源:互联网 发布:java判断字符串不相等 编辑:程序博客网 时间:2024/04/30 12:07

第11章持有对象
若一个程序只包含固定数量的且其生命周期都是已知对象,那么这是一个非常简单的程序。
通常程序不是这个样子,程序总是根据运行时才知道的某些条件去创建新对象。在此之前不会知道所需对象的数量,甚至不知道所需的确切类型。为解决这个问题,需要在任意时刻在任意位置创建任意数量的对象。所以就不能依靠创建命名的引用来持有每一个对象:
mytype a reference
因为不知道实际上会需要多少个这样的引用。
java有多种方式保存对象的引用,有数组,它是编译器支持的类型。是保存一组对象最有效的方式,如果你想保存一组基本类型数据,推荐使用数组。但,数组有固定的大小,在不一般的情况下,写程序时并不知道需要多少个对象,或者是不是需要更复杂的方式来存储对象,数组的大小固定就受限了。
java api 类库提供了一套相当完整的容器类来解决这个问题,基本的类型是List、Set、Queue和Map。这些对象类型也称为集合类,因为java类库中使用Collection来指代该类库的一个特殊子集,术语“容器”称呼它们。容器提供了完善的方法来保存对象,可以使用这些工具来解决数量惊人的问题。
容器的其他特性:Set对于每个值都保存一个对象,Map是允许你将某些对象其他对象关联起来的”关联数组”,java 容器类都能自动调整自己的大小。与数组不同,可以将任意数量的对象放置到容器中,不需要担心容器设置为多大。

11.1泛型和类型安全的容器
ArrayList是 可以自动扩充自身尺寸的数组。创建一个实例,用add()插入对象;用get()访问这些对象,此时需要使用引用,就像数组一样,但是不需要[],ArrayList还有一个size(),可以知道有多少个元素添加了进来,从而不会不小心因索引越界而引发错误。
package cn.wangs.c08.$11_1_1;

import java.util.ArrayList;

public class ApplesAndOrangesWithoutGenerics {

public static void main(String[] args) {    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();    }}

}

class Apple {
private static long counter;
private final long id = counter++;

public long id() {    return id;}

}

class Orange {

}
Apple和Orange是有区别的,他们除了都是Object类型之外没有任何共性(如果一个类没有显式地声明继承自哪个类,那么它自动地继承自Object)。因为ArrayList保存的是Object,因为Apple和Orange都可以通过ArrayList.add(Object obj)方法都可以装进这个集合的对象实例。而且无论在编译期还是运行期都没有问题。当你get(index)时取出来的是Object类型,所以要强制转换类型。在运行期时,试图将Orange对象转型为Apple对象时,就会发生异常。
使用java泛型来创建类会很复杂,但,应用预定义的泛型会很简单,如:定义用来保存Apple对象的ArrayList:ArrayList,而不仅仅只是ArrayList,其中<>中是类型参数(可以有多个),它指定了容器实例可以保存的类型,通过使用泛型在编译期防止将错误类型的对象放置到容器中。
package cn.wangs.c08.$11_1_1;

import java.util.ArrayList;

public class ApplesAndOrangesWithGenerics {

public static void main(String[] args) {    ArrayList<Apple> apples = new ArrayList<Apple>();    for (int i = 0; i < 3; i++)        apples.add(new Apple());    //apples.add(new Orange());编译器错误    for (int i = 0; i < apples.size(); i++) {        System.out.println(apples.get(i).id());    }    for(Apple apple : apples){        System.out.println(apple.id());    }}

}

现在,编译器会阻止你将Orange放置到apples中,它变成了一个编译期错误,而不再是运行期错误。
从List中取出时,类型转换也不再是必须的了。因为List知道它保存的是什么类型,在你调用get()时替你自动转型。
如果不使用每个元素的索引,还可以使用foreach语法来选择List中的每个元素。
当你指定了某个类型作为泛型参数时,并不仅限于只能将该类型的对象放置到容器中。向上转型也可以像作用于其他类型一样作用于泛型:
package cn.wangs.c08.$11_1_1;

import java.util.ArrayList;

public class GenericsAndUpcasting {
public static void main(String[] args) {
ArrayList apples = new ArrayList();
apples.add(new GrannySmith());
apples.add(new Gala());
apples.add(new Fuji());
apples.add(new Braeburn());

    for (Apple apple : apples) {        System.out.println(apple);    }}

}

class GrannySmith extends Apple {

}

class Gala extends Apple {

}

class Fuji extends Apple {

}

class Braeburn extends Apple {

}
因此,可以将Apple的子类型添加到被指定为保存Apple对象的容器中。
程序的输出是Object默认的toString()方法产生的,该方法将打印全类名,后面跟随该对象的散列码的无符号十六进制表示(这个散列码是通过hashCode()产生的)
练习1:创建一个新类Gerbil(沙鼠),包含int gerbilNumber,在构造器中初始化它。添加一个方法hop(),用于打印沙鼠的号码以及它正在跳跃的信息。创建一个ArrayList,并向其中添加一串Gerbil对象。使用get()遍历List,并且对每个Gerbil调用hop();
package cn.wangs.c08.$11_1_1;

import java.util.ArrayList;

/**
*
* @ClassName: GerbilTest 练习1:创建一个新类Gerbil(沙鼠),包含int
* gerbilNumber,在构造器中初始化它。添加一个方法hop(),用于打印沙鼠的号码以及它正在跳跃的信息。
* 创建一个ArrayList,并向其中添加一串Gerbil对象。使用get()遍历List,并且对每个Gerbil调用hop();
*/
public class GerbilTest {

public static void main(String[] args) {    ArrayList<Gerbil> list = new ArrayList<Gerbil>();    list.add(new Gerbil(1));    list.add(new Gerbil(2));    list.add(new Gerbil(3));    list.add(new Gerbil(4));    for (int i = 0; i < list.size(); i++) {        Gerbil gerbil = list.get(i);        if (gerbil == null) {            continue;        }        gerbil.hop();    }}

}

class Gerbil {
private int gerbilNumber;

public int getGerbilNumber() {    return gerbilNumber;}public void setGerbilNumber(int gerbilNumber) {    this.gerbilNumber = gerbilNumber;}public Gerbil(int gerbilNumber) {    setGerbilNumber(gerbilNumber);}public void hop() {    System.out.println("gerbilNumber#" + gerbilNumber);    System.out.println("跳跃了:" + gerbilNumber + "次");}

}

0 0