junhong

Thinking in java review 2

 

1.      The only place a label is useful in Java is right before an iteration

statement. And that means right before—it does no good to put any other

statement between the label and the iteration. And the sole reason to put

a label before an iteration is if you’re going to nest another iteration or a

switch inside it. That’s because the break and continue keywords will

normally interrupt only the current loop, but when used with a label

they’ll interrupt the loops up to where the label exists:

label1:

outer-iteration {

inner-iteration {

//…

break ; // 1

//…

continue ; // 2

//…

continue label1; // 3

//…

break label1; // 4

}

}

In case 1, the break breaks out of the inner iteration and you end up in

the outer iteration. In case 2, the continue moves back to the beginning

of the inner iteration. But in case 3, the continue label1 breaks out of

the inner iteration and the outer iteration, all the way back to label1.

Then it does in fact continue the iteration, but starting at the outer

iteration. In case 4, the break label1 also breaks all the way out to

label1 , but it does not re-enter the iteration. It actually does break out of

both iterations.

 

2.       

It’s important to remember that the only reason to use labels in Java is

when you have nested loops and you want to break or continue through

more than one nested level

 3.       

switch( integral-selector) {

case integral-value1 : statement; break;

case integral-value2 : statement; break;

case integral-value3 : statement; break;

case integral-value4 : statement; break;

case integral-value5 : statement; break;

// ...

default: statement;

}

Integral-selector is an expression that produces an integral value.
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

4. Suppose you’re inside a method and you’d like to get the reference to the

current object. Since that reference is passed secretly by the compiler,

there’s no identifier for it. However, for this purpose there’s a keyword:

this . The this keyword—which can be used only inside a method—

produces the reference to the object the method has been called for. You

can treat this reference just like any other object reference

 4.       
Normally, when you say this, it is in the sense of “this object” or “the

current object,” and by itself it produces the reference to the current

object. In a constructor, the this keyword takes on a different meaning

when you give it an argument list: it makes an explicit call to the

constructor that matches that argument list Thus you have a

straightforward way to call other constructors

 

 5.      垃圾回收器并不一定会回收未用的对象(因为垃圾回收器只有在内存不够用时才启动,所以如果未用对象已经产生了,但是内存还有很多,这时垃圾回收器就不会执行,垃圾对象就不会被回收了)。
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

When the garbage collector is ready to release the storage used for your object, it will first call finalize( ), and only on the next garbage-collection pass will it reclaim the object’s memory. So if you choose to use finalize( ), it gives you the ability to perform some important cleanup at the time of garbage collection.

当你调用, System.gc() 时,这时虚拟机会尽最大可能去回收内存,但是它也不能保证100%的去掉用垃圾回收器去收集垃圾对象,如果调用了垃圾回收器 ,他的 finalize() 函数也会被调用,但是如果是系统运行完了以后也没有濒临内存用完时,这是 garbage collector 就不会被调用来回收内存的。这样对象也就没有被回收。

 

<!--[if !supportLists]--> 6.      <!--[endif]-->
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

If you remember this, you will stay out of trouble. What it means is that if

there is some activity that must be performed before you no longer need

an object, you must perform that activity yourself. Java has no destructor

or similar concept, so you must create an ordinary method to perform this

cleanup

<!--[if !supportLists]--> 7.      <!--[endif]--> 一个文件可以没有public class,如果有public class,则必须要与文件名同名

<!--[if !supportLists]--> 8.      <!--[endif]--> class 不能是private ,protected,但是inner class 是特例
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

chapter 6 reuse class
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

<!--[if !supportLists]--> 9.      <!--[endif]-->
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

You can create a main( ) for each one of your classes, and it’s often recommended to code this way so that your test code is wrapped in with the class. Even if you have a lot of classes in a program, only the main( ) for the class invoked on the command line will be called. (As long as main( ) is public, it doesn’t matter whether the class that it’s part of is public.)

<!--[if !supportLists]--> 10.  <!--[endif]--> 调用同一个class内的构造函数用this(参数),调用base class 的函数用super.函数(参数)就可以了。调用base class 的构造函数用super(parameter)
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

<!--[if !supportLists]--> 11.  <!--[endif]-->  

When you create an object of the derived class, it contains within it a subobject of the base class. This subobject is the same as if you had created an object of the base class by itself. It’s just that, from the outside, the subobject of the base class is wrapped within

the derived-class object. baseclass 对象是包含在 subclass 的对象内的)

 

<!--[if !supportLists]--> 12.     <!--[endif]-->
Java automatically inserts calls to the base-class constructor in the derived-class constructor

 

<!--[if !supportLists]--> 13.  <!--[endif]--> 总结(personal):默认情况下,derived class的默认构造函数会在其第一条语句加入super()来调用base class 的默认构造函数。如果base class 没有默认构造函数就会报错。但是如果要在derived class中调用非默认的base class 构造函数,则必须手工调用super(parameter),且这句必须在derived class 构造函数的第一句。如果你在derived class中没有调用base class 的构造函数,则derived class 构造函数会调用base class 的默认构造函数
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

<!--[if !supportLists]--> 14.  <!--[endif]--> 不能在继承过程中降低权限。

<!--[if !supportLists]--> 15.  <!--[endif]-->

Base class

Other part of subclass except the part in base class

Subclass object

对于一个derived class 对象而言,他已经包含base class对象,如上图所示,可以用测试内存地址验证

Class A

{A(){System.out.println(this);

}

Class B extends A

{B(){System.out.println(this);}

}

 

<!--[if !vml]--> 15.bmp<!--[endif]-->


<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

<!--[if !supportLists]--> 16.  <!--[endif]-->
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

Composition is generally used when you want the features of an existing class inside your new class, but not its interface. That is, you embed an object so that you can use it to implement functionality in your new class, but the user of your new class sees the interface you’ve defined for the new class rather than the interface from the embedded object. For this effect, you embed private objects of existing classes inside your new class.

<!--[if !supportLists]--> 17.  <!--[endif]-->
That is, protected in Java is automatically “friendly.

<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

<!--[if !supportLists]--> 18.  <!--[endif]-->
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

you should use inheritance sparingly,( 只有在明显能够产生实用价值时,才使用继承,还有要考虑 polymorphism),One of the clearest ways to determine whether you

should use composition or inheritance is to ask whether you’ll ever need

to upcast from your new class to the base class. If you must upcast, then

inheritance is necessary, but if you don’t need to upcast, then you should

look closely at whether you need inheritance.

 

<!--[if !supportLists]--> 19.  <!--[endif]--> java 没有提供任何的机制可以保持对象的内容不变。对array也是这样的

<!--[if !supportLists]--> 20.  <!--[endif]--> 初始化的顺序
base class
装载-base class中的static 变量初始化->derived class static变量初始化-base class 对象的初始化(1,数据成员初始化为默认值,for reference ,it is null. 2, 构造函数执行)-> derived class 对象初始化
注:当你在derived class 中时,base class 应该已经可以初始化完毕,可以使用了。

<!--[if !supportLists]--> 21.  <!--[endif]--> java 中的所有函数,除了被声明为final,皆使用后期绑定。

<!--[if !supportLists]--> 22.    <!--[endif]--> Inheritance vs composition
A better approach is to choose composition first, when it’s not obvious which one you should use. Composition does not force a design into an inheritance hierarchy. But composition is also more flexible since it’s possible to dynamically choose a type (and thus behavior) when using composition, whereas inheritance requires an exact type to be known at compile-time.(当你不知道该选择“继承“,或“组合“是,最好先选择组合,组合不会强迫你的设计出现一大串继承阶层架构。组合手法弹性比较大)

<!--[if !supportLists]--> 23.    <!--[endif]-->
a good guideline for constructors is, “Do as little as possible to set the object into a good state, and if you can possibly avoid it, don’t call any methods.”

<!--[if !supportLists]--> 24.  <!--[endif]-->
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

import java.util.*;

class Useful {

public void f() {}

Chapter 7: Polymorphism 345

public void g() {}

}

class MoreUseful extends Useful {

public void f() {}

public void g() {}

public void u() {}

public void v() {}

public void w() {}

}

public class RTTI {

public static void main(String[] args) {

Useful[] x = {

new Useful(),

new MoreUseful()

};

x[0].f();

x[1].g();

// Compile-time: method not found in Useful:

/* x[1] 在执行时期才可以知道其类型是 MoreUseful, 所以这里编译不了

//! x[1].u();

((MoreUseful)x[1]).u(); // Downcast/RTTI

((MoreUseful)x[0]).u(); // Exception thrown

}

}

<!--[if !supportLists]--> 25.  <!--[endif]--> interface 中的data 默认是public static final.函数为public .
请千万记住,interface 存在的根本理由是: 能够被向上转型至多个基本型别。
如果你的base class 可以不带任何函数定义或任何成员变量,应优先使用interface
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

<!--[if !supportLists]--> 26.  <!--[endif]--> 所有的class的定义,无论是在函数内,或任意{}语句内,该class的定义都会和其他class一起被编译出来
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

<!--[if !supportLists]--> 27.    <!--[endif]-->
If you’re defining an anonymous inner class and want to use an object

that’s defined outside the anonymous inner class, the compiler requires

that the outside object be final

<!--[if !supportLists]--> 28.  <!--[endif]--> 总结(personal):non-static inner class 不能包含任何static 数据method
static inner class
却可以包含static data,or static methond,当然也可以包含non-static 成员。
static inner class
就说明它与外围class没有联系,和一个单独的class 一样。
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

    E.g non-static inner class can not have static data.bmp

<!--[if !supportLists]--> 29.    <!--[endif]-->
So one way to look at the inner class is as the completion of the solution of the multiple-inheritance problem. Interfaces solve part of the problem, but inner classes effectively allow “multiple implementation inheritance.” That is, inner classes effectively allow you to inherit from more than one non-interface.

<!--[if !supportLists]--> 30.<!--[endif]-->
chapter 9

<!--[if !supportLists]--> 31.     <!--[endif]-->
Arrays provides the overloaded method equals( ) to compare entire arrays for equality. Again, these are overloaded for all the primitives, and for Object. To be equal, the arrays must have the same number of elements and each element must be equivalent to each corresponding element in the other array, using the equals( ) for each element. (For primitives, that primitive’s wrapper class equals( ) is used; Integer.equals( ) for int.

<!--[if !supportLists]--> 32.    <!--[endif]--> 使某个class具有比较能力有两种方法,1、可以实现java.lang.Comparable interface,只有一个函数compareTo()在这个interface,接受另外一个Object做为parameter.2、实现Comparator interface, 两个函数在这个interface 内,: compare() equal().
by creating a separateclass that implements an interface called Comparator. This has two methods, compare( ) and equals( ). However, you don’t have to implement equals( ) except for special performance needs, because anytime you create a class it is implicitly inherited from Object, which has an equals( ). So you can just use the default Object equals( ) and satisfy the contract imposed by the interface.

 

<!--[if !supportLists]--> 33.    <!--[endif]-->
Unlike arrays, the containers print nicely without any help

<!--[if !supportLists]--> 34.  <!--[endif]--> remember the following diagram

<!--[if !vml]--><!--[endif]-->34.bmp
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

<!--[if !supportLists]--> 35.    <!--[endif]-->
Notice that there’s no get( ) function for random-access element selection. That’s because Collection also includes Set, which maintains its own internal ordering (and thus makes random-access lookup meaningless). Thus, if you want to examine all the elements of a Collection you must use an iterator; that’s the only way to fetch things back

<!--[if !supportLists]--> 36.    <!--[endif]-->
The form for the definitions for equals( ) and hashCode( ) will be described later in this chapter. You must define an equals( ) in both cases, but the hashCode( ) is absolutely necessary only if the class will be placed in a HashSet (which is likely, since that should generally be your first choice as a Set implementation). However, as a programming style you should always override hashCode( ) when you override equals( ). This process will be fully detailed later in this chapter.

 

<!--[if !supportLists]--> 37.    <!--[endif]-->
In the previous example, a standard library class (Integer) was used as a

key for the HashMap. It worked fine as a key, because it has all the necessary wiring to make it work correctly as a key. But a common pitfall occurs with HashMaps when you create your own classes to be used as keys. For example, consider a weather predicting system that matches Groundhog objects to Prediction objects. It seems fairly

straightforward—you create the two classes, and use Groundhog as the

key and Prediction as the value:

//: c09:SpringDetector.java

// Looks plausible, but doesn't work.

import java.util.*;

class Groundhog {

int ghNumber;

Groundhog(int n) { ghNumber = n; }

}

class Prediction {

boolean shadow = Math.random() > 0.5;

public String toString() {

if(shadow)

return "Six more weeks of Winter!";

else

return "Early Spring!";

}

}

public class SpringDetector {

public static void main(String[] args) {

HashMap hm = new HashMap();

for(int i = 0; i < 10; i++)

hm.put(new Groundhog(i), new Prediction());

System.out.println("hm = " + hm + "\n");

System.out.println(

"Looking up prediction for Groundhog #3:");

Groundhog gh = new Groundhog(3);

if(hm.containsKey(gh))

System.out.println((Prediction)hm.get(gh));

else

System.out.println("Key not found: " + gh);

}

} ///:~

Each Groundhog is given an identity number, so you can look up a

Prediction in the HashMap by saying, “Give me the Prediction

associated with Groundhog number 3.” The Prediction class contains

a boolean that is initialized using Math.random( ), and a toString( )

that interprets the result for you. In main( ), a HashMap is filled with

Groundhog s and their associated Predictions. The HashMap is

printed so you can see that it has been filled. Then a Groundhog with an

identity number of 3 is used as a key to look up the prediction for

Groundhog #3 (which you can see must be in the Map).

It seems simple enough, but it doesn’t work. The problem is that

Groundhog is inherited from the common root class Object (which is

what happens if you don’t specify a base class, thus all classes are

ultimately inherited from Object)  It is Object’s hashCode( ) method

that is used to generate the hash code for each object, and by default it

just uses the address of its object. Thus, the first instance of Groundhog(3) does not produce a hash code equal to the hash code forthe second instance of Groundhog(3) that we tried to use as a lookup.

You might think that all you need to do is write an appropriate override

for hashCode( ). But it still won’t work until you’ve done one more

thing: override the equals( ) that is also part of Object. This method is

used by the HashMap when trying to determine if your key is equal to

any of the keys in the table. Again, the default Object.equals( ) simply

compares object addresses, so one Groundhog(3) is not equal to

another Groundhog(3).

Thus, to use your own classes as keys in a HashMap, you must override

both hashCode( ) and equals( )

 

<!--[if !supportLists]--> 38.    <!--[endif]-->

in hashset or hashmap ,first of all you  produce the hashcode, then,use hashcode /capacity(number of buckets) to get the index of the array,A[index]refer to a array of elements  with the same hashcode value

Slot or bucket

EntrySet

HashSet or HashMap 的内部表示

<!--[if !vml]--> 39.bmp<!--[endif]-->

The most important factor in creating a hashCode( ) is that, regardless

of when hashCode( ) is called, it produces the same value for a

particular object every time it is called.

So if your hashCode( ) depends on mutable data in the object the user must

be made aware that changing the data will effectively produce a different

key by generating a different hashCode( ).

 

<!--[if !supportLists]--> 39.    <!--[endif]-->
Strings have the special characteristic that if a program has several String objects that contain identical character sequences, then those String objects all map to the

same memory

chapter 10 Exception

<!--[if !supportLists]--> 40.   <!--[endif]-->
When you throw an exception, several things happen. First, the exception

object is created in the same way that any Java object is created: on the

heap, with new. Then the current path of execution (the one you couldn’t

continue) is stopped and the reference for the exception object is ejected

from the current context. At this point the exception handling mechanism

takes over and begins to look for an appropriate place to continue

executing the program

<!--[if !supportLists]--> 41.    <!--[endif]-->
Like any object in Java, you always create exceptions on the heap using

new , which allocates storage and calls a constructor. There are two constructors in all standard exceptions: the first is the default constructor,

and the second takes a string argument so you can place pertinent

information in the exception:

 

<!--[if !supportLists]--> 42.  <!--[endif]--> 总结(personal: 1override 函数只能掷出base class 明确列出的异常,当interface 中的某个函数也存在base class中时,interface 中的函数异常是不能在实现类中改变在实现类中这个函数的异常。2、在derived class中的函数可以不掷出base class规定的异常,但是如果要throws exception,则,这个exception 必须是base class中明确列出来的。
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

<!--[if !supportLists]--> 43.    <!--[endif]-->
The restriction on exceptions does not apply to constructors. You can see in StormyInning that a constructor can throw anything it wants, regardless of what the base-class constructor throws. However, since a base-class constructor must always be called one way or another (here, the default constructor is called automatically), the derived-class constructor must declare any base-class constructor exceptions in its exception specification. Note that a derived-class constructor cannot catch exceptions thrown by its base-class constructor.

chapter 11 : java i/o

<!--[if !supportLists]--> 44.   <!--[endif]-->
Serializing an object is quite simple, as long as the object implements the

Serializable interface (this interface is just a flag and has no methods).

When serialization was added to the language, many standard library

classes were changed to make them serializable, including all of the

wrappers for the primitive types, all of the container classes, and many

others. Even Class objects can be serialized.

<!--[if !supportLists]--> 45.  <!--[endif]-->
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

To serialize an object, you create some sort of OutputStream object and

then wrap it inside an ObjectOutputStream object. At this point you

need only call writeObject( ) and your object is serialized and sent to

the OutputStream. To reverse the process, you wrap an InputStream

inside an ObjectInputStream and call readObject( ). What comes

back is, as usual, a reference to an upcast Object, so you must downcast

to set things straight.

A particularly clever aspect of object serialization is that it not only saves

an image of your object but it also follows all the references contained in

your object and saves those objects, and follows all the references in each

of those objects

 

<!--[if !supportLists]--> 46.    <!--[endif]-->
Note that no constructor, not even the default constructor, is called in the

process of deserializing a Serializable object. The entire object is

restored by recovering data from the InputStream.

Object serialization is byte-oriented (not Unicode -oriented), and thus uses the InputStream and OutputStream hierarchies.

 

<!--[if !supportLists]--> 47.             <!--[endif]--> 使用Externalizable

//: c11:Blip3.java

// Reconstructing an externalizable object.

import java.io.*;

import java.util.*;

class Blip3 implements Externalizable {

int i;

String s; // No initialization

public Blip3() {

System.out.println("Blip3 Constructor");

// s, i not initialized

}

public Blip3(String x, int a) {

System.out.println("Blip3(String x, int a)");

s = x;

i = a;

// s & i initialized only in nondefault

// constructor.

}

public String toString() { return s + i; }

public void writeExternal(ObjectOutput out)

throws IOException {

System.out.println("Blip3.writeExternal");

// You must do this:

out.writeObject(s);

out.writeInt(i);

}

public void readExternal(ObjectInput in)

throws IOException, ClassNotFoundException {

System.out.println("Blip3.readExternal");

// You must do this:

s = (String)in.readObject();

i =in.readInt();

}

public static void main(String[] args)

throws IOException, ClassNotFoundException {

System.out.println("Constructing objects:");

Blip3 b3 = new Blip3("A String ", 47);

System.out.println(b3);

ObjectOutputStream o =

new ObjectOutputStream(

new FileOutputStream("Blip3.out"));

System.out.println("Saving object:");

o.writeObject(b3);

o.close();

// Now get it back:

ObjectInputStream in =

new ObjectInputStream(

new FileInputStream("Blip3.out"));

System.out.println("Recovering b3:");

b3 = (Blip3)in.readObject();

System.out.println(b3);

}

} ///:~

You can control the process of serialization by implementing the

Externalizable interface instead of the Serializable interface. The

Externalizable interface extends the Serializable interface and adds

two methods, writeExternal( ) and readExternal( ), that are

automatically called for your object during serialization and

deserialization so that you can perform your special operations.

 

When b1 is recovered, the Blip1 default constructor is called. This is

different from recovering a Serializable object, in which the object is

constructed entirely from its stored bits, with no constructor calls. With

an Externalizable object, all the normal default construction behavior

occurs (including the initializations at the point of field definition), and

then readExternal( ) is called. You need to be aware of this—in

particular, the fact that all the default construction always takes place—to

produce the correct behavior in your Externalizable objects.

If you are inheriting from an Externalizable object, you’ll typically call

the base-class versions of writeExternal( ) and readExternal( ) to

provide proper storage and retrieval of the base-class components.

 

So to make things work correctly you must not only write the important

data from the object during the writeExternal( ) method (there is no

default behavior that writes any of the member objects for an

Externalizable object), but you must also recover that data in the

readExternal( ) method. This can be a bit confusing at first because the

default construction behavior for an Externalizable object can make it

seem like some kind of storage and retrieval takes place automatically. It

does not.

 

 

<!--[if !supportLists]--> 48.    <!--[endif]-->
One way to prevent sensitive parts of your object from being serialized is

to implement your class as Externalizable, as shown previously. Then

nothing is automatically serialized and you can explicitly serialize only the

necessary parts inside writeExternal( ).

If you’re working with a Serializable object, however, all serialization

happens automatically. To control this, you can turn off serialization on a

field-by-field basis using the transient keyword, which says “Don’t

bother saving or restoring this—I’ll take care of it.

<!--[if !supportLists]--> 49.    <!--[endif]-->
Since Externalizable objects do not store any of their fields by default,

the transient keyword is for use with Serializable objects only.

<!--[if !supportLists]--> 50.  <!--[endif]--> Externalizable 的替代写法

        If you’re not keen on implementing the Externalizable interface, there’s

another approach. You can implement the Serializable interface and

add (notice I say “add” and not “override” or “implement”) methods

called writeObject( ) and readObject( ) that will automatically be

called when the object is serialized and deserialized, respectively. That is,

if you provide these two methods they will be used instead of the default

serialization.

The methods must have these exact signatures:

private void

writeObject(ObjectOutputStream stream)

throws IOException;

private void

readObject(ObjectInputStream stream)

throws IOException, ClassNotFoundException

 

It would appear that when you call

ObjectOutputStream.writeObject( ) , the Serializable object that

you pass it to is interrogated (using reflection, no doubt) to see if it

implements its own writeObject( ). If so, the normal serialization

process is skipped and the writeObject( ) is called. The same sort of

situation exists for readObject( ).

 

There’s one other twist. Inside your writeObject( ), you can choose to

perform the default writeObject( ) action by calling

defaultWriteObject( ) . Likewise, inside readObject( ) you can call

defaultReadObject( )


If you are going to use the default mechanism to write the non-transient

parts of your object, you must call defaultWriteObject( ) as the first

operation in writeObject( ) and defaultReadObject( ) as the first

operation in readObject( ).

 

<!--[if !supportLists]--> 51.  <!--[endif]-->
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

animals: [Bosco the dog[Animal@1cc76c], House@1cc769

, Ralph the hamster[Animal@1cc76d], House@1cc769

, Fronk the cat[Animal@1cc76e], House@1cc769

]

animals1: [Bosco the dog[Animal@1cca0c], House@1cca16

, Ralph the hamster[Animal@1cca17], House@1cca16

, Fronk the cat[Animal@1cca1b], House@1cca16

]

animals2: [Bosco the dog[Animal@1cca0c], House@1cca16

, Ralph the hamster[Animal@1cca17], House@1cca16

, Fronk the cat[Animal@1cca1b], House@1cca16

]

animals3: [Bosco the dog[Animal@1cca52], House@1cca5c

, Ralph the hamster[Animal@1cca5d], House@1cca5c

, Fronk the cat[Animal@1cca61], House@1cca5c

]

 

As long as you’re serializing everything to a single stream, you’ll be able to

recover the same web of objects that you wrote, with no accidental

duplication of objects. Of course, you can change the state of your objects

in between the time you write the first and the last, but that’s your

responsibility—the objects will be written in whatever state they are in

(and with whatever connections they have to other objects) at the time

you serialize them.

 

Chapter 12 RTTI

<!--[if !supportLists]--> 52.    <!--[endif]-->
There’s a Class object for each class that is part of your program. That is,

each time you write and compile a new class, a single Class object is also

created (and stored, appropriately enough, in an identically named .class

file). At run-time, when you want to make an object of that class, the Java

Virtual Machine (JVM) that’s executing your program first checks to see if

the Class object for that type is loaded. If not, the JVM loads it by finding

the .class file with that name. Thus, a Java program isn’t completely

loaded before it begins, which is different from many traditional

languages.

Once the Class object for that type is in memory, it is used to create all

objects of that type.

 

<!--[if !supportLists]--> 53.  <!--[endif]-->
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

Java provides a second way to produce the reference to the Class object,

using a class literal. In the above program this would look like:

 

Gum.class;

 

which is not only simpler, but also safer since it’s checked at compiletime

<!--[if !vml]--> 54.bmp<!--[endif]-->

<!--[if !supportLists]--> 54.    <!--[endif]-->
instanceof says “are you this class, or a class derived from this class?” On the other hand, if you compare the actual Class objects using ==, there is no concern with

inheritance—it’s either the exact type or it isn’

 

<!--[if !supportLists]--> 1.         <!--[endif]--> chapter 14 multithread

<!--[if !supportLists]--> 2.        <!--[endif]-->  

regardless of whether you’re explicitly using threads, you can produce the current

thread used by your program with Thread and the static sleep( ) method.

<!--[if !supportLists]--> 3.        <!--[endif]-->
The simplest way to create a thread is to inherit from class Thread, which has all the wiring necessary to create and run threads. The most important method for Thread is run( ), which you must override to make the thread do your bidding. Thus, run( ) is the code that will be executed “simultaneously” with the other threads in a program.

<!--[if !supportLists]--> 4.        <!--[endif]-->
When main( ) creates the Thread objects it isn’t capturing the

references for any of them. An ordinary object would be fair game for

garbage collection, but not a Thread. Each Thread “registers” itself so

there is actually a reference to it someplace and the garbage collector can’t

clean it up.

<!--[if !supportLists]--> 5.        <!--[endif]-->
.
A “daemon” thread is one that is supposed to provide a general service in

the background as long as the program is running, but is not part of the

essence of the program. Thus, when all of the non-daemon threads

complete, the program is terminated. Conversely, if there are any nondaemon

threads still running, the program doesn’t terminate. (There is,

for instance, a thread that runs main( ).)

<!--[if !supportLists]--> 6.        <!--[endif]-->
Java has built-in support to prevent collisions over one kind of resource:

the memory in an object. Since you typically make the data elements of a

class private and access that memory only through methods, you can

prevent collisions by making a particular method synchronized. Only

one thread at a time can call a synchronized method for a particular

object (although that thread can call more than one of the object’s

synchronized methods). Here are simple synchronized methods:

synchronized void f() { /* ... */ }

synchronized void g(){ /* ... */ }

Each object contains a single lock (also called a monitor) that is

automatically part of the object (you don’t have to write any special code).

When you call any synchronized method, that object is locked and no

other synchronized method of that object can be called until the first

one finishes and releases the lock. In the example above, if f( ) is called

for an object, g( ) cannot be called for the same object until f( ) is

completed and releases the lock. Thus, there’s a single lock that’s shared

by all the synchronized methods of a particular object, and this lock

prevents common memory from being written by more than one method

at a time (i.e., more than one thread at a time).

There’s also a single lock per class (as part of the Class object for the

class), so that synchronized static methods can lock each other out

from simultaneous access of static data on a class-wide basis.

<!--[if !supportLists]--> 7.        <!--[endif]-->
You’ll notice that both run( ) and synchTest( ) are synchronized. If

you synchronize only one of the methods, then the other is free to ignore

the object lock and can be called with impunity. This is an important

point: Every method that accesses a critical shared resource must be

synchronized or it won’t work right

<!--[if !supportLists]--> 8.        <!--[endif]-->
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

What we’d like for this example is a way to isolate only part of the code

inside run( ). The section of code you want to isolate this way is called a

critical section and you use the synchronized keyword in a different

way to set up a critical section. Java supports critical sections with the

synchronized block; this time synchronized is used to specify the object

whose lock is being used to synchronize the enclosed code:

synchronized(syncObject) {

// This code can be accessed

// by only one thread at a time

}

Before the synchronized block can be entered, the lock must be acquired

on syncObject. If some other thread already has this lock, then the block

cannot be entered until the lock is given up.

<!--[if !supportLists]--> 9.        <!--[endif]-->
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

Blocking

A thread can be in any one of four states:

1. New : The thread object has been created but it hasn’t been started

yet so it cannot run.

2. Runnable : This means that a thread can be run when the timeslicing

mechanism has CPU cycles available for the thread. Thus,

the thread might or might not be running, but there’s nothing to

prevent it from being run if the scheduler can arrange it; it’s not

dead or blocked.

3. Dead : The normal way for a thread to die is by returning from its

run( ) method. You can also call stop( ), but this throws an

exception that’s a subclass of Error (which means you aren’t

forced to put the call in a try block). Remember that throwing an

exception should be a special event and not part of normal program

execution; thus the use of stop( ) is deprecated in Java 2. There’s

also a destroy( ) method (which has never been implemented)

that you should never call if you can avoid it since it’s drastic and

doesn’t release object locks.

4. Blocked : The thread could be run but there’s something that

prevents it. While a thread is in the blocked state the scheduler will

simply skip over it and not give it any CPU time. Until a thread

reenters the runnable state it won’t perform any operations.

Becoming blocked

The blocked state is the most interesting one, and is worth further

examination. A thread can become blocked for five reasons:

1. You’ve put the thread to sleep by calling sleep(milliseconds), in

which case it will not be run for the specified time.

2. You’ve suspended the execution of the thread with suspend( ). It

will not become runnable again until the thread gets the

resume( ) message (these are deprecated in Java 2, and will be

examined further).

3. You’ve suspended the execution of the thread with wait( ). It will

not become runnable again until the thread gets the notify( ) or

notifyAll( ) message. (Yes, this looks just like number 2, but

there’s a distinct difference that will be revealed.)

4. The thread is waiting for some I/O to complete.

5. The thread is trying to call a synchronized method on another

object, and that object’s lock is not available.

You can also call yield( ) (a method of the Thread class) to voluntarily

give up the CPU so that other threads can run. However, the same thing

happens if the scheduler decides that your thread has had enough time

and jumps to another thread. That is, nothing prevents the scheduler

from moving your thread and giving time to some other thread. When a

thread is blocked, there’s some reason that it cannot continue running.

<!--[if !supportLists]--> 10.   <!--[endif]-->
it’s important to understand that both sleep( )

and suspend( ) do not release the lock as they are called. You must be

aware of this when working with locks. On the other hand, the method

wait( ) does release the lock when it is called, which means that other

synchronized methods in the thread object could be called during a

wait( ) .

 

<!--[if !supportLists]--> 11.     <!--[endif]-->  

One fairly unique aspect of wait( ) and notify( ) is that both methods are

part of the base class Object and not part of Thread as are sleep( ),

suspend( ) , and resume( ). Although this seems a bit strange at first—

to have something that’s exclusively for threading as part of the universal

base class—it’s essential because they manipulate the lock that’s also part

of every object. As a result, you can put a wait( ) inside any

synchronized method, regardless of whether there’s any threading

going on inside that particular class. In fact, the only place you can call

wait( ) is within a synchronized method or block. If you call wait( ) or

notify( ) within a method that’s not synchronized, the program will

compile, but when you run it you’ll get an

IllegalMonitorStateException with the somewhat nonintuitive

message “current thread not owner.” Note that sleep( ), suspend( ),

and resume( ) can all be called within non-synchronized methods

since they don’t manipulate the lock.

 

 

 

 

posted on 2006-06-28 17:46 junhong 阅读(1761) 评论(0)  编辑  收藏 所属分类: java技术


只有注册用户登录后才能发表评论。


网站导航: