junhong

          My Links

          Blog Stats

          News

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          文章檔案

          相冊

          收藏夾

          common component

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          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 閱讀(1783) 評論(0)  編輯  收藏 所屬分類: java技術

          主站蜘蛛池模板: 龙门县| 西青区| 泊头市| 花莲县| 青海省| 东宁县| 安岳县| 凯里市| 平湖市| 浪卡子县| 文成县| 南宁市| 南阳市| 连平县| 文昌市| 裕民县| 合川市| 伊吾县| 邯郸市| 深泽县| 曲沃县| 乌兰浩特市| 平度市| 浮梁县| 海阳市| 略阳县| 改则县| 龙海市| 子洲县| 全州县| 布尔津县| 祁连县| 克山县| 云梦县| 梨树县| 古田县| 北海市| 新兴县| 宁明县| 塘沽区| 屯留县|