JAVA programming ideology (4) and java programming ideology
Share multiple objects
- For example, Frog objects have their own objects and know how long they will survive, because Frog objects know when to call dispose () to release their objects. However, if these Member objects are shared by one or more other objects, the problem is no longer simple and dispose () can no longer be simply called. In this case, we may need to reference the count to track the number of shared objects that are still accessed.
//: polymorphism/ReferenceCounting.java// Cleaning up shared member objects.import static net.mindview.util.Print.*;class Shared { private int refcount = 0; private static long counter = 0; private final long id = counter++; public Shared() { print("Creating " + this); } public void addRef() { refcount++; } protected void dispose() { if(--refcount == 0) print("Disposing " + this); } public String toString() { return "Shared " + id; }}class Composing { private Shared shared; private static long counter = 0; private final long id = counter++; public Composing(Shared shared) { print("Creating " + this); this.shared = shared; this.shared.addRef(); } protected void dispose() { print("disposing " + this); shared.dispose(); } public String toString() { return "Composing " + id; }}public class ReferenceCounting { public static void main(String[] args) { Shared shared = new Shared(); Composing[] composing = { new Composing(shared), new Composing(shared), new Composing(shared), new Composing(shared), new Composing(shared) }; for(Composing c : composing) c.dispose(); }} /* Output:Creating Shared 0Creating Composing 0Creating Composing 1Creating Composing 2Creating Composing 3Creating Composing 4disposing Composing 0disposing Composing 1disposing Composing 2disposing Composing 3disposing Composing 4Disposing Shared 0*///:~
- The number of Shared instances created by the static long counter trail. The id is final, because we do not want its value to be changed in the object lifecycle.
- When attaching a shared object to a class, you must remember to call addRef (), but the dispose () method tracks the number of references and determines when to clean up.
Polymorphism behavior in the constructor
- What happens if a dynamic binding method of an object being constructed is called inside a constructor?
- In a general method, the call of dynamic binding is determined at runtime, because the object cannot know whether it belongs to the class where the method is located or the export class of that class.
- If you want to call a dynamic binding method inside the constructor, you need to use the overwritten definition of that method. However, the calling effect may be quite unpredictable, because the overwritten method is called before the object is fully constructed. This may cause some difficult-to-find errors.
- Simply put, the base class constructor calls the function in the base class. This function is also overwritten in the export class. When the export class calls the base class constructor, therefore, a dynamically bound method call will go deep into the hierarchy, and it can call the methods in the export class. A method may be called, and the member operated by this method may not be initialized.
//: polymorphism/PolyConstructors.java// Constructors and polymorphism// don't produce what you might expect.import static net.mindview.util.Print.*;class Glyph { void draw() { print("Glyph.draw()"); } Glyph() { print("Glyph() before draw()"); draw(); print("Glyph() after draw()"); }} class RoundGlyph extends Glyph { private int radius = 1; RoundGlyph(int r) { radius = r; print("RoundGlyph.RoundGlyph(), radius = " + radius); } void draw() { print("RoundGlyph.draw(), radius = " + radius); }} public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5); }} /* Output:Glyph() before draw()RoundGlyph.draw(), radius = 0Glyph() after draw()RoundGlyph.RoundGlyph(), radius = 5*///:~
- The design of the Glyph. draw () method will be overwritten, which occurs in RoundGlyph. However, the Glyph constructor calls this method, resulting in a response to RoundGlyph. the call of draw () seems to be our purpose, but the output result is not what we expected. We found that when the Glyph () constructor calls the draw () method, radius is not the default value of 1, but 0.
- Let's take a look at the actual initialization process:
- Before any other food occurs, the storage space allocated to the object is initialized to a binary zero.
- As previously mentioned, the base class constructor is called. In this case, the overwritten draw () method is called before the RoundGlyph constructor is called. Because of step 1, the radius value is 0.
- Call the initialization method of the member in the declared order.
- Call the constructor body of the export class.
- One advantage of doing so is that everything is initialized to at least zero. Instead of making garbage. The object reference is usually null, So if you forget to initialize the reference, an exception will occur during the runtime.
- Therefore, when writing the constructor, there is a guideline: "Use the simplest way possible to make the object normal. If possible, avoid calling other methods ." The only method that the constructor can safely call is the final method in the base class.
Design with inheritance
- Polymorphism is not used to make everything inherited, because it will increase our design burden and make things unnecessary.
- A better way is to select a "Combination", especially when you are not sure which method should be used. The combination is more flexible, because it can dynamically select a type (So behavior is selected); on the contrary, Inheritance needs to know the exact type during compilation.
//: polymorphism/Transmogrify.java// Dynamically changing the behavior of an object// via composition (the "State" design pattern).import static net.mindview.util.Print.*;class Actor { public void act() {}}class HappyActor extends Actor { public void act() { print("HappyActor"); }}class SadActor extends Actor { public void act() { print("SadActor"); }}class Stage { private Actor actor = new HappyActor(); public void change() { actor = new SadActor(); } public void performPlay() { actor.act(); }}public class Transmogrify { public static void main(String[] args) { Stage stage = new Stage(); stage.performPlay(); stage.change(); stage.performPlay(); }} /* Output:HappyActorSadActor*///:~
- Here, the Stage object contains a reference to the Actor, and the Actor is initialized as the HappyActor object. This means that mongomplay () will produce some special behavior. When we replace actor's object reference, we can change our behavior.
- One criterion is: "Use inheritance to express differences in behavior and use fields to express changes in status ."
Pure inheritance and Expansion
- It seems the best way to create an inheritance hierarchy in a "pure" way ("is-. That is to say, only methods created by the base class can be overwritten in the export class. It can also be said that the export Class "only" overrides the function of the base class and there are no other functions.
- Because the interface of a class has determined what it should be, inheritance can ensure that all exported classes have interfaces of the base class and will never be less. "Pure" inheritance, the export class will have the same interface as the base class.
- It can also be considered as a pure substitution, because the export class can completely replace the base class, And when using them, you do not need to know any additional information about the subclass. That is to say, the base class can receive any information sent to the export class because the two have identical interfaces. We only need to know the exact type of the object being processed from the export class to the upward transformation. These are all handled through polymorphism.
- However, the export class does not only have interfaces inherited from the base class, but also has its own additional functions. We can call it (is-like-a) (like) because the export class is like a base class-it has the same interface, but it also has other features implemented by additional methods.
- "Like a" link also has shortcomings. The extension of the interface in the export class cannot be accessed by the base class. Therefore, once we make an upward transition, we cannot call those new methods. In this case, we generally re-view the exact type of the object so that we can access the method of expanding the type.
Downward transformation and runtime type identification
- The specific type information is lost in the upward transformation, so we want to obtain the type information through the downward transformation. Then we know that the upward transformation is safe, because the interface of the base class will not be greater than the interface of the export class. Therefore, the information we send through the base class interface can be accepted. However, for a downward transformation, we cannot know which type of transformation we will transform.
- In Java, all transformations will be checked! Therefore, even if we only perform a normal type transformation in the form of adding arc, we will still check it at runtime. If it is not the correct type, a ClassCastException (class transformation exception) will be returned ). This type check behavior during runtime is called "runtime type recognition" (RTTI ).
//: polymorphism/RTTI.java// Downcasting & Runtime type information (RTTI).// {ThrowsException}class Useful { public void f() {} 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].u(); ((MoreUseful)x[1]).u(); // Downcast/RTTI ((MoreUseful)x[0]).u(); // Exception thrown }} ///:~
Java programming ideology version 4
You just need to search in Baidu Library.
This is the result of the search.
Wenku.baidu.com/.?&od=0
Why is the fourth edition of java programming ideology different from that of online e-books?
Because the fourth version of e-books on the Internet's JAVA programming ideology are mostly fake, but the cover of the fourth version adds the third version. Your paper books are correct. Chapter 7 is multiplexing and chapter 8 is polymorphism. My paper books are the same as yours. But I don't understand why the fourth edition has no network programming and what the author thinks. We are willing to spend money to buy books, and the author cannot afford paper? I don't understand.