1. 回调是一种双向调用模式,就是说,被调用方 在被调用时也会调用对方,这就叫回调。“If you call me,i will call back”。:
- class A实现接口InA ——背景1
- class A中包含一个class B的引用b ——背景2
- class B有一个参数为InA的方法test(InA a) ——背景3
- A的对象a调用B的方法传入自己,test(a) ——这一步相当于you call me
- 然后b就可以在test方法中调用InA的方法 ——这一步相当于i call you back
形象举例:你有一个复杂的问题解决不了,打电话给我,我可以解决这个问题,但是需要一些时间,那么你不可能一直拿着电话在那里等,你会把你的电话号码告诉我(注册),让我解决之后打电话通知你。回调就是体现在我又反过来给电话。
结合到前面所分析的,你打电话给我就是【you call me】,我解决完之后打电话给你就是【i call you back】。
//相当于接口InA
publicinterface
IBoomWTC
{
//
执行轰炸世贸
publicvoidboom();
}
//相当于class A
publicclass BenLaDeng
implements IBoomWTC
// 相当于【背景1】
{
private Terrorists
ta;//
相当于【背景2】
//
获得拉登的决定
BenLaDeng()
{
//
TODO Auto-generated method stub
ta =
newTerrorists();
//
人员就位,时机成熟
}
//
执行轰炸世贸
@Override
publicvoidboom()
{
//
TODO Auto-generated method stub
System.out.println("BenLaDeng:
启动任务!");
}
publicvoidexcute()
{
// class A调用class B的方法传入自己的对象,相当于【you
call me】
ta.attack(newBenLaDeng());//
}
}
//相当于class B
publicclass Terrorists
{
publicvoidattack(IBoomWTC
bwtc)// ——这相当于【背景3】
{
{// class B在方法中回调class A的方法,相当于【i
call you back】
bwtc.boom();
System.out.println("Terrorists:
轰炸!");
}
}
publicstaticvoidmain(String
args[])
{
BenLaDeng
benLaDeng = newBenLaDeng();
benLaDeng.excute();
}
};
2. 在串行化对象时,不会将对象的静态成员写入到输出流,因为静态成员不只属于某一个对象,而是类的属性。在串行化对象时,也不会将使用保留字transient
声明的成员写入到输出流,因为这样的成员被程序员制定为瞬时的,无需持久化。
3. 主要有四个因素影响对象容器存放的对象所形成的结构:一是是否允许存放重复的对象,这里所谓存放重复的对象,是指容器中包含有多个使用深比较相等的对象;二是存放的对象之间是否有序,如果要求存放的对象有序,则所存放对象之间在某种意义下必须是可比较的;三是如何访问所存放的对象,这通常有两种方式,顺序访问和随机访问,随机访问就是指能用常数时间访问容器内任意位置的对象,而顺序访问只能从存放对象的起始或者末尾位置开始访问,如果只能从某一位置顺序访问下一个,是单向顺序访问,如果还能从该位置访问上一个就是双向顺序访问;四是存放对象的数目是否有限制,如果存放对象的数目没有限制,则容器总是可以自动扩展以存放更多的对象。
4. ava API
按对象容器能存放的对象将容器分为两种:一种称为类集(collection)
容器,用接口Collection描述这种容器的基本操作,其中存放的基本单位是单个对象;一种称为映射(map) 容器,用接口Map 描述这种容器的基本操作,其中存放的基本单位是对象对(object pairs),其中一个对象称为键(key)对象,另一个对象称为值(value) 对象。
5. 根据是否能存放重复的对象,类集容器又可进一步分为列表容器(List)与集合容器(Set)。
6. 集合容器只能单向顺序遍历存放的对象,不能双向遍历,也不能随机访问.
7. 接口Map
内部定义了一个嵌套接口Entry表示映射容器中存放的对象对,该接口定义了取键对象和值对象的方法,也定义了修改值对象的方法,但没有定义修改键对象的方法。
8. 接口Map
不能返回用于遍历映射容器的迭代器,但可根据键对象直接访问其对应的值对象,也可将整个映射容器转换为集合容器(其中存放的对象具有类型Map.Entry),或者分别将映射容器中存放的所有键对象转换为一个集合容器,将所有值对象转换为一个(一般的)类集容器。
9. 各种对象容器的主要特点
容器种类 |
对于所存放对象的约束 |
访问容器内对象的方式 |
|||||
存放对象 |
是否允许重复对象 |
对象之间是否有序 |
顺序访问的形式 |
是否允许随机访问 |
|||
类集容器 |
列表容器 |
单个对象 |
允许 |
无序 |
双向 |
允许 |
|
集合容器 |
普通集合容器 |
不允许 |
无序 |
单向 |
不允许 |
||
有序集合容器 |
有序 |
||||||
映射容器 |
普通映射容器 |
键-值对象对 |
键对象不允许重 |
无序 |
转换为类集容器后访问 |
||
有序映射容器 |
有序 |
10.Java API
提供的列表容器具体类主要包括类LinkedList、ArrayList、Vector 和Stack.。类 LinkedList 内部使用双向链接表实现;类ArrayList 创建的列表容器的特点是相当于是一个可变长的数组。
11.类Vector
和Stack是JDK 1.2 版以前提供的对象容器类,些类的方法都是同步实现的,效率比较低已不推荐使用这两个容器类,同步实现就是指在多线程情况下要保证只有一个线程在访问容器内的对象。
12.类Vector
是类ArrayList 的同步实现版本,类Stack是Vector的子类,它提供操作允许将类Stack的对象用作堆栈,即按先进后出方式使用它存放的对象。
13.Java API
提供的集合容器具体类主要包括类HashSet和TreeSet,其中类HashSet实现普通集合容器接口Set,而类 TreeSet实现有序集合容器接口 SortedSet。类HashSet使用散列表,而类TreeSet使用红黑树。
14.Java
语言的每一个类都从根类Object 继承了方法hashCode()。
15.Java API
提供的映射容器具体类主要包括类HashMap、Weak Hash Map、TreeMap 和HashTable。前面三个类都是骨架类AbstractMap的子类,但类HashTable不是它的子类。类HashTable同样是JDK 1.2 版以前提供的容器类。
16.Java API提供的对象容器类
容器种类 |
实现的接口 |
容器类名 |
实现方面的特点 |
JDK版本 |
||
类集容器 |
列表容器 |
List |
LinkedList |
内部使用双向链表 |
>=1.2 |
|
List |
ArrayList |
相当于可变长数组 |
>=1.2 |
|||
List |
Vector |
同步实现的可变长数组 |
<1.2 |
|||
List |
Stack类 |
Vector的子类实现堆栈先进后出的特征 |
<1.2 |
|||
集合容器
|
Set |
HashSet |
内部使用散列表 |
>=1.2 |
|
|
SortedList |
TreeSet |
内部使用红黑树 |
>=1.2 |
|
||
映射容器 |
普通映射容器 |
Map |
HashMap |
内部使用散列表 |
>=1.2 |
|
Map |
WeakHashMap |
与HashMap十分类似但自动删除不用的元素 |
>=1.2 |
|||
Map |
HashTable |
与HashMap十分类似相当于其同步实现的版本 |
<1.2 |
|||
有序映射容器 |
SortedMap |
TreeMap |
内部使用红黑树 |
>=1.2 |
17.Java API
用于辅助对象容器的接口包括Iterator、Comparable 和Comparator 。
18.接口Comparable和Comparator 用于对象之间的比较,使得对象可以放入有序的对象容器。
19.当容器要求存放的对象之间有序时,有两种方法满足这种要求:第一种方法是声明要存入容器的对象实现接口Comparable,这时它必须实现方法compareTo(),以比较两个具有相同类型的对象;第二种方法是在创建对象容器的同时提供一个实现接口Comparator的对象(这种对象称为比较子),该对象实现方法
compare(),它应能够比较要放入容器的任意两个对象。这两种方法到底采用哪种方法在创建容器时决定:如果创建容器时提供比较子则采用第二种方法,否则采用第一种方法。
20.Java API用于辅助对象容器的类包括类Arrays 和Collections。类Arrays 用于辅助操纵最基本的对象容器——数组,它提供了对各种基本数据类型及Object
类型的数组进行二分查找(binary search)、排序(sort)、填充(fill) 以及判断两个数组相等(equals)等一系列的公有静态方法。 类Collections 用于辅助操纵除数组以外的对象容器,它提供的功能包括:对列表容器内的对象进行二分查找和排序、对类集容器内的对象进行统计(主要是求最大值和最小值)、将各种容器(包括类集容器和映射容器)包装成不可修改的容器(即不可对容器进行添加和删除等操作)、将各种容器包装成同步的容器(即保证在多线程情况下同一时刻只有一个线程访问该容器)以及其它一些辅助功能。
21.迭代器是对象容器的遍历行为的一种抽象。迭代器模式的设计目标是将遍历行为与组织数据的对象容器的其它行为(如插入、删除元素等)分离开。采用迭代器模式的优点是对象容器对使用者隐藏了遍历行为的内部实现,使用者可使用统一的接口方法遍历任意的对象容器。
22.对象容器存放的总是对象引用而非对象实例。对象容器添加、删除的都是对象引用,这些操作不会影响该引用指向的对象实例。
23.使用对象容器时,尽量使用接口类型的变量而非具体容器类的变量完成对容器的操作。
多线程
24.线程的状态转换图
25.锁的典型用法是控制临界区(critical section)的访问,从而保证特定代码段之间的互斥。
26.如果一个方法的方法体全部都是由 this
对象的锁提供保护的代码临界区, 则可采用一种更简便的写法,即将以下代码:
public void push(char element) {
synchronized(this) {
...
}
}
简单地表示为:
public synchronized voidpush(char element) {
...
}
27.共享数据的多线程设计基本原则是将所有访问敏感数据的代码都安放在synchronized标识的同步代码段中,并且将一个类中那些敏感数据的访问控制方式定义为非公有的(通常为定义 private) ,从而这些数据只能通过该类提供的公有方法进行访问,我们只需对该类的公有方法设计一种同步机制即可。
28.调用 join()方法的功能是让当前正在执行的线程进入阻塞状态,等待指定的线程(即用于调用 join()方法的线程实例)运行结束后再重新投入运行。
29.线程间通信的一种常用技巧是让一个线程持有另一线程对象的引用。
30.Java的线程机制建立在宿主操作系统的线程基础上,它将宿主操作系统提供的线程机制包装为语言一级的机制提供给程序员使用,一方面为程序员提供了简单一致、独立于平台的多线程编程接口,另一方面也为程序员屏蔽了宿主操作系统的线程技术细节,使得Java程序员不必关心如何将Java
语言的线程机制映射到宿主操作系统的线程库,这一任务完全交由JVM 供应商完成。
31.JVM
是一个进程,并且无论你编写的是否一个多线程应用程序,JVM
本身总是以多线程方式执行。
32.创建线程
(1) 自定义的线程类要么实现Runnable 接口,要么继承 Thread类。无论采用何种方式编写线程类,线程类中均须重定义方法run(),该方法负责完成线程所需执行的任务。Thread 类本身实现了 Runnable 接口,并且在该类中还包装了一个 Runnable 类型的对象实例target。
(2) 完成一个实现了Runnable接口的线程类后,可创建该线程类的一个实例,然后再以该实例为参数创建Thread 类的一个实例,最后调用该Thread实例的start()方法,从而创建了一个新线程。继承 Thread 类的线程类创建一个新线程时,可直接创建该线程类的一个实例。
(3) 当Java程序启动时,一个主线程自动地被创建并运行。
33.JVM
并不保证这一假设总会成立,因为调度程序有时可能选择低优先级线程投入运行以避免饥饿(starvation
)现象。优先级设置仅用于表达程序员的一种愿望,JVM 线程调度程序尽量照顾这种愿望而已。故设计线程优先级时,应从效率出发设计优先级以影响线程调度,
34.每一个线程都隶属于某一线程组,这种隶属关系在创建新线程时指定,并且在线程的整个生存期内无法改变。
35.主线程隶属于一个名为main的预设线程组。创建的线程组将形成一个类似文件系统的树层次结构,预设的线程组main 是该树层次的根。
36.守护线程(daemonthread)是一类特殊的线程,它与普通线程的惟一区别在于JVM 不将守护线程视作应用程序的核心部分。当所有非守护线程都执行完毕时,整个Java 应用程序将终止运行,即使此时仍有某些守护线程正在运行。
37.为保证多个并发线程可互斥地使用共享资源,Java
语言参考操作系统的管程(monitor)机制,为每一对象实例都引入一个管程,并称之为“锁”。不仅每一对象实例都具有惟一的锁,每一类对象也有一个惟一的锁。Synchronized锁定的是对象而不是函数代码。
38.由于wait()和notify()/notifyAll() 方法需在持有对象实例的锁时方可调用,故这些方法的调用必须放在以synchronized 标识的同步代码段中,否则运行时将抛出一个java.lang.IllegalMonitorStateException异常,wait()产生的阻塞状态可由interrupt()方法中断。
39.线程对象执行wait()之后会释放锁,而sleep()不会释放锁。
40.典型的wait()方法调用模式如下:
...
// 假设两个相互通信的线程约定使用对象obj 实现同步
synchronized (obj)
{
while ( 条件condition 不成立)
{
Try
{
obj.wait();
}
catch(InterruptedException exc)
{
处理在等待期间被异常中断的情况;
}
}
执行条件condition 成立时方可执行的操作;
}
...
而典型的notify()/ notifyAll() 方法调用模式如下:
...
// 假设两个相互通信的线程约定使用对象obj 实现同步
synchronized (obj)
{
执行某些操作以改变条件condition ;
obj.notify();
}
...