Java语言程序设计(原书第8版)--进阶篇 注意(一)

掌握Java语言基本且必备的知识点,在实践中运用并总结!

1.有时候,泛型类可能会有多个参数。在这种情况下,应将所有参数一起放在尖括号中,并用逗号隔开,比如<E1, E2, E3>。

2.可以定义一个类或一个接口作为泛型或者接口的子类型。例如,在Java API中,java.lang.String 类被定义为实现Comparable接口,如下所示:

public class String implement Comparable<String>

3.非受限泛型类型<E>和<E exxtends Object>是一样的。

4.为了定义一个类为泛型类型,需要将泛型类型放在类名之后,例如,GenericStack<E>。为了定义一个方法为泛型类型,需要将泛型类型放在方法返回类型之前,例如<E> void max(E o1, E o2)。

5.在Java集合框架中定义的所有接口和类都存储在java.util包中。

6.Java集合框架中的所有具体类都实现了java.lang.Cloneable和java.io.Serializable接口。所以,它们的实例都是可复制且可序列化的。

7.方法addAll、removeAll、retainAll类似于规则集上的并、差、交运算。

8.Java集合框架中的所有具体类(参见图22-1)都至少有两个构造方法:一个是创建空集合的无参构造方法,另一个是用某个集合来创建实例的构造方法。这样,TreeSet类中就含有从集合c创建TreeSet对象的构造方法TreeSet(Collection c)。在这个例子中,new TreeSet(hashSet)方法从集合hashset创建了TreeSet的一个实例。

9.Comparable用于比较实现Comparable的类的对象;Comparator用于比较没有实现Comparable的类的对象。

10.方法elements()返回一个Enumeration对象(枚举型对象)。Enumeration接口是在Java2之前引入的,已经被Iterator接口所取代。

11.在Java2之前,Vector类被广泛应用于Java程序设计中,因为它可以实现Java可变大小的数组。大多数Swing数据模型使用的都是Vector。

12.在Java2以前,一般使用java.util.Hashtable来映射键值和元素。为了适应Java集合框架,Java对Hashtable进行了重新设计,但是,为了向后兼容保留了所有的方法。Hashtable实现了Map接口,除了Hashtable具有同步功能之外,它与HashMap的用法是一样的。

13. 符号O提供了对算法效率的一个很好的理论上的估计。但是,两个算法即使有相同的时间复杂度,他们的效率也不一定相同。如前面的例子所示,程序清单4.8和23.2中的两个算法具有相同的复杂度,但实际上,程序清单23.2中的算法显然会更好些。

14.不一定要归并两个相邻分段。例如,在第一步归并中,可以归并S1和S5,S2和S6,S3和S7,S4和S8。这种思路在高效实现第II步时很有用。

15.f1.dat可能会比f3.dat多一个分段。这样的话,在归并后将最后一个分段一道f3.dat中。

16.该数组类型是E[]类型,所以,数组中每个元素实际存储的是对象的引用。

17.如果当前节点是叶子结点,这就是第一种情况。例如,为了删除图26-11a中的元素16,将节点16的右孩子和它的父节点相连。在这种情况下,节点16的右孩是null。

18.如果current的左孩子没有右孩子,那么current.left指向current左孩子的大元素。在这种情况下,rightMost是current.left,而parentOfRightMost是current。必须考虑这种特殊情况,重新链接rightMost的右孩子和parentOfRightMost。

19.中序遍历、前序遍历和后序遍历的时间复杂度很明显都是O(n),因为每个结点只遍历一次。查找、插入和删除的时间复杂度是树的高度。在最差的情况下,树的高度为O(n)。

20.java.util.Iterator定义一个前向迭代器,它以前向的方向遍历迭代器中的元素,每个元素只能遍历一次。Java API还提供java.util.ListIterator,它支持前向遍历和后向遍历。如果你的数据结构要保证遍历的灵活性,可以将迭代器类定义为java.util.ListIterator的一个子类。

21.定点可以是任意类型的对象。例如,可以将会曾是考虑为包含名字、人口和市长等信息的实体。于是可以将顶点定义为:

City city0 = new City(“Seattle”, 563374, “Greg Nickels”);

City city11 = new City(“Houston”, 1000203, “Bill White”);

Object[] vretices = {city0, city1, …, city11};

22.可以通过顶点的名字或者索引来引用顶点,就看哪一种方式使用起来更方便。很显然,在程序中通过索引访问顶点是很容易的。

23.由于对于无向图来说,矩阵是对称的,因此可以用锯齿矩阵来存储它。

24.可以使用邻接矩阵或者邻接线性表来表示一个图。哪种方法更好呢?如果很密(也就是说,存在大量的边),那么建议使用邻接矩阵。如果图很稀疏(也就是说,存在很少的边),由于使用邻接矩阵会浪费大量的存储空间,因此最好使用邻接线性表。邻接矩阵和邻接线性表都可以用在程序中,以使算法的效率更高。例如,使用邻接矩阵来检查两个顶点是否相连只需要O(1)常量时间,而使用邻接线性表来打印图中所有的边需要线性时间O(m),这里的m标识变得条数。

25.邻接矩阵和邻接线性表是两种常用的表示图的方法,但是它们不是表示图的唯一方法。例如,可以将定义顶点为一个对象,其中方法getNeighbors()返回顶点所有的邻居。为简单起见,本书将用邻接线性表来表示图。其他的表示方法将在编程练习题中探讨。

26.可以使用任意类型的顶点来创建图。每个顶点与一个下标相关联,这同链表中的顶点与顶点下标之间的关系一样。如果创建图时没有指定顶点,顶点和它们的索引一样。

27.AbstractGraph类实现了Graph接口的所有方法,那么,为什么将它定义为抽象的?今后,我们可能需要给Graph接口添加AbstractGraph不能实现的新方法。为了使类易于维护,有必要将AbstractGraph定义为抽象类。

28.为了简单起见,假设权值为一个整数。权值可以 为任何类型。在这种情况下,可能需要一个如下所示的Object类型的二维数组:

Object[ ][ ] edges = {

    {new Integer(0), new Integer(1), new SomeTypeForWeight(2)},

    {new Integer(0), new Integer(3), new SomeTypeForWeight(8)},

    …

};

29.每个顶点的邻接边都存储在一个优先队列中。如果要从队列中移除一条边,那么总是具有最小权值的边被删除。然而,如果遍历队列中的边,边就没必要以权值递增的顺序排列。

30.最小生成树不是唯一的。例如,图28-5c和图28-5d都是图28-5a中图的最小生成树。然而,如果权值是不同的,那么图就只有唯一的最小生成树。

31.假设图是连通且无向的。如果一个图不是连通或者有向的,算法是不起作用的。可以修改算法,为任何无向图找出生成森林。

32.如果看不到并发运行三个线程的效果,那么就要增加打印字符的个数。例如,将第4行改为

Runnable printA = new PrintChar(‘a’, 10000);

33.重要的注意事项 任务中的run( )方法指明如何完成这个任务。Java虚拟机会自动调用该方法,无需特意调用它。直接调用run( )只是在同一个线程中执行该方法,而没有新线程被启动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值