📄 ch2.htm
字号:
static Hashtable cache = new Hashtable(cacheSize);<BR><BR> // The loader is static and so can be createdonly once<BR> private static MediaLoader loader = new <BR>MediaLoader();<BR><BR> // Private internal constructor<BR> private MediaLoader() {<BR> // ... various initilizationgoes on here...<BR> }<BR><BR> // Return reference to this MediaLoader object<BR> public static MediaLoader getMediaLoader() {<BR> return loader;<BR> }<BR> // ... internal methods..<BR>}</TT></BLOCKQUOTE><P>A lot of interesting things are going on here. A <TT>cache</TT>,which is used to store images, is declared as a class variable.One of the neat things about Java is the flexibility with whichyou can structure your code. Note how this initialization is notwithin a method but is part of the class definition; rememberthat because the <TT>cache</TT> variableis <TT>static</TT>, it is a classvariable and thus is not tied to an object instance.<P>The next step is even more unusual. The loader class initializesitself! The constructor is <TT>private</TT>and not <TT>public</TT>, so no otherobject can create an instance of the loader. Instead, the classcalls the <TT>private</TT> constructorand stores the instantiated loader object into a <I>private classvariable</I>. In effect, the class is saying, "Make onlyone instance of this class, and only I know it!"<P>How do other objects use this MediaLoader object? They do so bycalling the last method listed, <TT>getMediaLoader()</TT>.It is a class method and so is not tied to any instance. The jobof the method is to return a <I>reference</I> to the <TT>private</TT>instance of the object. The other objects can then use this referenceto call the <TT>public</TT> methodsof the loader class. These methods will not be declared as <TT>static</TT>.<P>To keep things simple, suppose that the loader has a <TT>public</TT>method called <TT>getImage()</TT>,with no parameters. Another object calls the method as follows:<BLOCKQUOTE><TT>MediaLoader ref = MediaLoader.getMediaLoader();// Get the reference!<BR>ref.getImage(); // Call the method!</TT></BLOCKQUOTE><P>Note how you call the class method <TT>getMediaLoader()</TT>by prefacing it with the name of the class. Because class methodsare global to the class, you do not need an instance of the class.<P>The preceding call also could have been accomplished in one lineof code:<BLOCKQUOTE><TT>MediaLoader.getMediaLoader().getImage();</TT></BLOCKQUOTE><P>This method-chaining technique prevents you from creating short-livedvariables; you can use the object returned from one method callas the object to be used in the next method call.<P>While class methods are extremely powerful, they have some restrictions.In particular, they can work only on class variables. If you thinkabout it, the reason for this is obvious: They cannot work oninstance variables because there may not be an instance for themto work with!<P>The various techniques you have seen in the MediaLoader classare used throughout the Java Developer's Kit (JDK). You sometimessee classes that you cannot figure out how to use. In this situation,look for methods named something like <TT>getReference</TT>or <TT>getDefault</TT>; these mayreturn a reference to an object instance of that class. You wouldthen employ them in a fashion similar to the MediaLoader class.<H3><A NAME="ThefinalModifier">The <TT><FONT SIZE=4 FACE="Courier">final</TT></FONT><FONT SIZE=4>Modifier</FONT></A></H3><P>You use the <TT>final</TT> modifierto indicate that something cannot be changed or overridden. Ifthe <TT>final</TT> modifier is appliedto a variable, it is effectively made into a <I>constant</I>.In the AddressRecord example, the address flags are set to theirbest form by adding the <TT>final</TT>modifier:<BLOCKQUOTE><TT>class AddressRecord extends SimpleRecord{<BR> public static final int INTERNET_ADDRESS = 0;<BR> public static final int PHYSICAL_ADDRESS = 1;<BR> // ... Constructors and methods...<BR> }<BR>}</TT></BLOCKQUOTE><P>Without the <TT>final</TT> modifier,other classes could change the value of the variable by callingsomething like<BLOCKQUOTE><TT>AddressRecord.INTERNET_ADDRESS = 6;</TT></BLOCKQUOTE><P>With the <TT>final</TT> modifier attachedto <TT>INTERNET_ADDRESS</TT>, however,this line of code would generate a compiler error. This is because<TT>final</TT> variables cannot bemodified.<P>If a method is declared as <TT>final</TT>,it cannot be subclassed. Because <TT>private</TT>methods cannot be subclassed, they are effectively <TT>final</TT>.Note, however, that the converse does not hold. It is useful todeclare methods as <TT>final</TT>whenever it is appropriate. This allows the Java compiler to makesome optimizations, thus improving the performance of your code.If the compiler knows that a method cannot be subclassed, it cando such things as "in-lining" the method wherever itis called. Because a <TT>final</TT>method cannot be subclassed, runtime lookups for matching methodsignatures as part of the subclassing mechanism are not necessary.<P>To declare a method as <TT>final</TT>,place the modifier as follows:<BLOCKQUOTE><TT>public final void list()</TT></BLOCKQUOTE><P>You can also declare classes as <TT>final</TT>.This means that the class cannot be subclassed. The main reasonyou may want to declare a class as <TT>final</TT>is related to security. In the JDK, many classes are <TT>final</TT>.The reason for this is clear if you think about it. For example,suppose that you could subclass the System class! It would thenbe relatively easy to subvert the security of a client. Finalclasses may also be subject to some compiler optimizations, thusproviding an additional reason for declaring a class as <TT>final</TT>.<BR><P><CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%><TR VALIGN=TOP><TD><B>Note</B></TD></TR><TR VALIGN=TOP><TD><BLOCKQUOTE>The term <I>accessor methods</I> refers to methods used to set and retrieve a variable. This is the preferred way of constructing a class rather than declaring everything as <TT>public</TT>. In the SimpleRecord class, the preferred way to set or retrieve the <TT>firstName</TT> variable of an object is to create methods like</BLOCKQUOTE><BLOCKQUOTE><TT>public void setFirstName(String firstName) {<BR> this.firstName = firstName;<BR> }<BR> public String getFirstName() {<BR> return firstName;<BR> }</TT></BLOCKQUOTE><BLOCKQUOTE>where the variable <TT>firstName</TT> is not declared as <TT>public</TT>. While writing a <TT>set</TT> or <TT>get</TT> method for every accessible variable may seem tedious, it is better than declaring everything <TT>public</TT>. If you make instance variables <TT>public</TT>, you're compromising the principle of encapsulation. By exposing <TT>public</TT> instance variables to objects that use your class, you're making the outside world aware of how your class works. You may then lose the freedom to modify the inner workings of your class. For example, if you want to rename or delete a <TT>public</TT> instance variable, you may not be able to do so because all kinds of classes are using this variable! This very bad practice departs from all the good principles of object-oriented programming. So while it may seem painful now to write large numbers of <TT>set</TT> or <TT>get</TT> methods, you're saving yourself time down the road. If you have a good editor, it won't take that much time anyway.</BLOCKQUOTE><BLOCKQUOTE>The term <I>accessor class</I> is sometimes used to refer to classes that do nothing more than hold data reachable through accessor methods; the classes have no behavior per se. For C programmers, you will often want to write an accessor class where you would normally create a structure.</BLOCKQUOTE></TD></TR></TABLE></CENTER><H3><A NAME="ThenullKeywordandMoreaboutGarbage">The <TT><FONT SIZE=4 FACE="Courier">null</TT></FONT><FONT SIZE=4>Keyword and More about Garbage Collection</FONT></A></H3><P>The <TT>null</TT> keyword indicatesthat something has no instance. By default, an uninitialized classvariable is set to <TT>null</TT>.Sometimes you might want to do this explicitly-simply for codereadability-if your variable will not be initialized for a while.<P>The biggest use of <TT>null</TT> occurswhen you no longer need an object. For example, suppose that youcreate a local variable in a long and involved method that refersto an instance of the Integer class. You use the Integer objectfor a while, and then you want to indicate that it is no longerneeded. You can do this with the <TT>null</TT>keyword:<BLOCKQUOTE><TT>Integer I = new Integer(6);<BR>// ... do something with the object...<BR>I = null;</TT></BLOCKQUOTE><P>You can achieve the same result in other ways. You can enclosethe variable in a block statement; when the variable goes outof scope, the object will no longer be referenced. If you reusethe variable for another object reference, the old object willno longer be referenced:<BLOCKQUOTE><TT>Integer I = new Integer(6);<BR>// ... do something with the object...<BR>I = new Integer(9); // Old Integer reference is <BR>gone...</TT></BLOCKQUOTE><P>Why would you want to set something to <TT>null</TT>?Recall that Java's memory management is through a garbage collector.This garbage collector removes objects from memory that are nolonger referenced. If your variable was the only reference tothe object, then after the reference is removed, the object isa candidate for garbage collection. Remember that the garbagecollector is a low-priority thread, so the object may not be cleanedup immediately. If you are really tight on memory, you can callthe garbage collector explicitly via the System class:<BLOCKQUOTE><TT>System.gc();</TT></BLOCKQUOTE><P>Like all methods in the System class, <TT>gc()</TT>is a class method, so you don't have to create any instance touse it. The kind of situations in which you might want to callthe garbage collector explicitly is after involved operationsthat consume a large number of objects and system resources. Donot call the collector in a loop, however. The <TT>gc()</TT>operation runs the full collector, so the collector's executionwill take a moment or so.<H3><A NAME="ScopingRules">Scoping Rules</A></H3><P>When a variable is referenced inside a method, Java first looksin an enclosing block for a declaration. If a declaration is notfound, Java travels up the nested blocks until it reaches themethod definition. If the variable is found anywhere inside amethod, the variable has priority over a similarly named instanceor class variable. This is why you often see code like the following:<BLOCKQUOTE><TT>public SimpleRecord(String firstName,String lastName) {<BR> this.firstName = firstName;<BR> this.lastName = lastName;<BR>}</TT></BLOCKQUOTE><P>The <TT>this</TT> keyword is usedhere to differentiate the instance variable from the local variable.<P>If the referenced variable is not found inside the method, Javasearches the class. If the reference variable still is not found,Java travels up the class hierarchy (until the Object class isreached), inspecting the superclasses for the variable. You haveseen how this works in the "Inheritance in Java" section.<H3><A NAME="CastingRules">Casting Rules</A></H3><P>Use <I>casting</I> when you need to convert an object or primitiveof one type to another type. For example, you may want to converta <TT>double</TT> to an <TT>int</TT>,or a subclass to its superclass. Casting allows you to do this,although the rules of casting can be complicated. The key thingto remember about casting is that it does <I>not</I> affect theobject or value being cast. However, the receiver of the castconstitutes a new object or a new type.<P>Casting primitive data types occurs quite often, such as whenyou are reading in a stream of data. How the cast occurs dependson the precision of the types involved in the cast. Precisionrelates to how much information the type can contain; for example,a floating point type such as <TT>double</TT>or <TT>float</TT> has more precisionthan a simple number like <TT>int</TT>.Likewise, <TT>double</TT> has moreprecision than <TT>float</TT> becauseit is 64-bit as opposed to 32-bit. Whenever you transfer datafrom a less precise type to a more precise type, explicit castingis <I>not</I> required:<BLOCKQUOTE><TT>int i = 3;<BR>double pi = i + .14159;</TT></BLOCKQUOTE><P>On the other hand, transferring data from a more precise typeto a less precise type requires casting. This is because datamay be lost in the casting. Java forces you to explicitly castbecause it wants you to be aware of the possible danger of sucha conversion:<BLOCKQUOTE><TT>double pi = 3.14159;<BR>int i = (int)pi; // This is set to 3 (you lost the <BR>.14159!)</TT></BLOCKQUOTE><P>Casting between objects is a little more complicated. To illustratecasting, look at the Hashtable class of the JDK. This class takesinstances of the Object class and places them into a hash tablevia a method called <TT>put()</TT>,where a String is used as a key. To retrieve them from the table,you invoke <TT>get()</TT>, which takesa String key and returns the corresponding Object.<P>Recall that Object is a superclass of all classes; every classis a subclass of Object. Suppose that you have a class calledMyClass and a String that will be used as a key, placed in a variable<TT>key</TT>. You can place it ina Hashtable object, indicated by the variable <TT>hash</TT>,as follows:<BLOCKQUOTE><TT>MyClass MyObject;<BR>hash.put(key,MyObject);</TT></BLOCKQUOTE><P>Because
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -