[Thinking in Java] Chapter 7th-reuse classes and reuse of thinking
[Code reuse is one of the many notable functions of Java. But to become a revolutionary language, it is not enough to simply copy and change the code. It must be able to do more .]
7.1 combined syntax
The combination is to put the object in the new class and make the members of the new class, such
class A {}class B { private String value1, value2, value3; private A a = new A(); private int integer; private double d;}
As shown above, Class A objects become one of class B. In addition, Class B also has three objects of the class string, and has the basic data types integer and d.
If you want to initialize a class, you can perform this operation in four locations in the code.
1. Define the object;
2. In the constructor of the class;
3. Use instance initialization, that is, the initialization Block
4. before using this object, this method is also called inertia initialization, which can reduce the extra burden.
Class A {} class B {// 1. private String name = new String ("James"); private String sex; // private int id not initialized; // private A a is not initialized; // not initialized {// 4. use instance initialization id = 13;} public B () {// 2. initialize a = new A ();} public void f () {// 4 in the constructor. initialize if (sex = null) sex = "boy"; System. out. println ("I am a" + sex );}}
7.2 inheritance syntax
When a class is created, it is always inherited. Therefore, unless it is explicitly stated that it is to be inherited from other classes, it is always implicitly inherited from the standard Java root class Object.
class A { private int a; private double b; private String name; public void f1() {} public void f2() {}}class B extends A { private int c; public void f3() {}}
As shown in the code above, with the keyword extends, Class B inherits Class A and obtains all attributes and methods of the parent class, including the private attributes of the parent class.
Class Person {public String toString () {return "I am a person" ;}} class Father extends Person {private String name = "James"; public Father (String name) {this. name = name;} public String toString () {return "I am a father";} public String getName () {return name ;}} class Son extends Father {public Son (String name) {super (name);} public String toString () {return "I am a son ";}} public class PersonTest {public static void main (String [] args) {Father father = new Father ("Xiaotian"); Son = new son ("Xiaoqiang"); father. say ("My name is" + father. getName (); son. say ("I am" + son. getName ());}}
As shown in the code above, the class Father defines the private modified attribute name, which is inherited by the class Son and initialized in the constructor. Meanwhile, the class Father defines the accessors getName (), because it is modified using public, Son-like objects can be directly used. We can also note that class Person defines the public method toString (), in fact, the root class Object also defines toString (), but the toString () of the class Person is overloaded. Because the method signature is different, the class Father also defines the toString () of the same method signature (), this overwrites the toString () of the Person class. Similarly, the toString () of Son class overwrites the toString () of the Father class ().
Note the super (name) sentence of the Son-like constructor. If you comment out this sentence or change it to super (), the compiler can only report an error, this is because the inheritance mechanism requires that the parent class be initialized:
In fact, inheritance is not just a copy of the parent class interface. When a subclass object is created, the object contains a child object of the parent class, this sub-object is the same as directly creating an object with the parent class, but the latter comes from the external, and the sub-object of the parent class is encapsulated inside the sub-class object. Correct initialization of parent sub-objects is also crucial, and there is only one method, that is, the early constructor calls the constructor of the parent class to execute initialization.
Class Art {Art () {System. out. print ("Art constructor") ;}} class Drawing extends Art {Drawing () {System. out. print ("Drawing constructor");} class Cartoon extends Drawing {Cartoon () {System. out. print ("Cartoon constructor ");}}
As shown in the code above, a parent class Drawing is found during Cartoon initialization, so the compiler will add a super () statement in the first sentence of the constructor by default, and then initialize the parent class Drawing first, the parent class Art is also found, so a super () is added in the first sentence of the constructor by default; then the parent class Art is initialized, and the root class Object will not be mentioned, the output result is as follows:
Art constructor Drawing constructor Cartoon Constructor
Can the super of the first line of the constructor (the super of the initialization parent class must be the first line) contain parameters? Of course, as in the preceding example, super (name) in the Son-like constructor carries parameters. However, if the parameter name is removed or is not written, the compiler will complain that initialization cannot be performed, because the parent Father class does not have a no-argument constructor. What if we encounter the following example?
Class A {A () {System. out. println ("A No parameter");} class B extends A {B () {System. out. println ("B No parameter");} B (int a) {this (); System. out. println ("B has Parameters");} class C extends B {C () {super (1); System. out. println ("C No parameter") ;}} public class Inheritance {public static void main (String [] args) {new C ();}}
Because the constructor chain starts from the initialization Object to the end of the root class Object. Therefore, when the execution of this (); program jumps to the constructor B (), but the chain of the constructor has already been completed, it will not be super to parent class, therefore, the program output is
A has no parameters.
B without Parameters
B has Parameters
C No Parameter
7.3 proxy
The relationships between classes are composite, inherited, and the third type of relationships become proxies. Java does not provide direct support for them. It is the moderate way of combination and inheritance.
Because we place a member object in the class to be constructed (like a combination), but at the same time, we expose all methods of this member object in the new class (like inheritance ), proxy solves this problem
class A { f1(int i) {} f2(int i) {}}class B { A a = new A(); f1(int i) { a.f1(i); } f2(int i) { a.f2(i); }}
As shown in the code above, we want to use the f1 and f2 methods of B during design, instead of directly using the f1 and f2 methods of A. For example, we want to move a car forward, not the control engine of the car.
7.4 heavy load and coverage
Overload means that the method name is the same, while the parameter list is different, and the type of the returned value is allowed to be different. The parameter list is different in that the number and type of parameters are different;
Override means that the subclass overrides the method of the parent class. The method name of a method of the subclass must be the same as that of the parent class in the return value type and parameter list.
1 class A { 2 int method(int i) { 3 return i; 4 } 5 } 6 7 public class B extends A { 8 public int method(int i) { 9 return ++i;10 }11 12 double method(double d) {13 return d;14 }15 16 double method(int a, double b) {17 return a + b;18 }19 20 public static void main(String[] args) {21 B c = new B();22 System.out.println(c.method(1));23 System.out.println(c.method(5.6));
24 System.out.println(c.method(5, 5.5));25 }26 }
It should be noted that if the modifier of the 8th-line code is changed to private, the compiler will complain that the modifier has lower visibility than the method of the parent class, therefore, when overwriting, you must ensure that the modifier visibility is not lower than the method of the parent class. Rows 12th to 14 reload the method of the parent class, where the return value type can be different, the method is also overloaded in rows 16th to 18, where the number of parameter lists is different
7.5 initialization and class loading
The compilation code of each class exists in its own independent files, although a java file can have multiple classes. This file is loaded only when the program code is required. Generally, the class code is loaded only when used for the first time. This usually means loading occurs when the first object of the class is created, but loading also occurs when the static domain or static method is accessed.
Static Initialization is also used for the first time. All static objects and static code segments are initialized sequentially during loading. Of course, things defined as static will only be initialized once.
The following is an example of Java programming ideas.
1 import static java.lang.System.*; 2 3 class Insect { 4 private int i = 9; 5 protected int j; 6 Insect() { 7 out.println("i = " + i + ", j = " + j); 8 j = 39; 9 }10 11 private static int x1 = 12 printInit("static Insect.x1 initialized");13 14 static int printInit(String s) {15 out.println(s);16 return 47;17 }18 }19 20 public class Beetle extends Insect {21 private int k = printInit("Beetle.k initialized");22 public Beetle() {23 out.println("k = " + k);24 out.println("j = " + j);25 }26 27 private static int x2 = 28 printInit("static Beetle.x2 initialized");29 30 public static void main(String[] args) {31 out.println("Beetle constructor");32 Beetle b = new Beetle();33 }34 }
When running Java on Beetle, the first thing that happens is to try to access Beetle. main () (a static method), so the loader starts to start and find the compilation code of the Beetle class (in the name of Beetle. class file ). During its loading process, the compiler notices that it has a parent class (known by the keyword extends), so it continues to load, whether or not you intend to create an object for this parent class, this will happen.
If the parent class has its own parent class, the second parent class will be loaded, and so on. Next, static initialization in the root parent class (Insect in this example) will be executed, followed by the next subclass, and so on.
So far, all necessary classes have been loaded, and the object can be created. First, all basic types of the object are set to the default value, and the object reference is set to null. Then, the constructor of the parent class is called. In this example, it is automatically called. However, you can also use super to specify the call to the parent class Constructor (just as the first step in the Beetle () constructor ). The parent class constructor is the same as the sub-class constructor, and goes through the same process in the same order. After the parent class constructor is complete, the instance variables are initialized in order. The rest of the constructor is executed.
As in this example, when trying to access Beetle. when main () is used, the Beetle class will be loaded first, but the Beetle parent class Insect will be found, so Insect will be loaded first, and the first static Statement of Insect will be 11th rows, the second line calls printInit (String s) of the second line, prints s and returns 47, so x1 = 47; then loads Beetle. The first static statement is the second line, row 3 calls the printInit (String s) of the parent class, prints s and returns 47. Therefore, x2 = 47. So far, all classes have been loaded, and return to Beetle. main (), execute the statement of 31st rows, then execute 32nd rows, create the Beetle object, then try to execute the constructor of 22nd rows, but find that there is a parent class Insect, therefore, first initialize the parent class, the program jumps to the 6th line, and calls the constructor of the parent class. After the parent class is initialized, the Child class is initialized, and so on, the Beetle object is created successfully.