There are two types of regeneration:
Synthesize and create objects of the original class in the new class.
It creates a new class and treats it as a "type" of the existing class. We can take the form of the existing class as is and add new code to it, does not affect existing classes.
Because there are two classes-the base class and the category class, instead of the previous one, you may be confused when imagining the result object of the category class. From the external perspective, it seems that the new class has the same interface as the basic class, and can contain some additional methods and fields. However, inheritance is not just about copying basic class interfaces. When creating an object of the category class, it contains a "sub-object" of the base class ". This sub-object is like an object of the base class itself. Externally, the sub-objects of the base class have been encapsulated into objects of the category class.
Of course, basic class sub-objects should be correctly initialized, and there is only one way to ensure this: Execute initialization in the builder, by calling
With the base class builder, the latter has sufficient capabilities and permissions to perform initialization of the base class. Java will automatically insert
The call to the base class builder. The following example shows the application of Level 3 inheritance:
Java code
Public class Art {
Art (){
System. out. println ("art ");
}
}
Public class Drawing extends Art {
Drawing (){
System. out. println ("drawing ");
}
Public static void main (String [] args ){
Drawing drawing = new Drawing ();
}
}
Output result:
Art
Drawing
The above example has its own default builder; that is, they do not contain any independent variables. The compiler can easily call them because they are not stored.
The question of which independent variables are passed. If the class does not have the default independent variable, or you want to call a base class that contains the independent variable to build
You must explicitly write the calling code for the basic class. This is implemented using the super keyword and the appropriate list of independent variables, as shown below:
Java code
Class Game {
Game (int I ){
System. out. println ("Game constructor ");
}
}
Class BoardGame extends Game {
BoardGame (int I ){
Super (I );
System. out. println ("BoardGame constructor ");
}
}
Class Chess extends BoardGame {
Chess (){
Super (11 );
System. out. println ("Chess constructor ");
}
Public static void main (String [] args ){
Chess x = new Chess ();
}
}
Output result:
Game constructor
BoardGame constructor
Chess constructor
Although the compiler forces us to initialize the base class and requires us to do this at the beginning of the builder, it does not monitor us
Whether the member object is correctly initialized. Pay special attention to this.
One benefit of inheritance is that it supports "accumulative development", allowing us to introduce new code without causing errors to existing code. In this way
New errors are isolated from new code. By inheriting from a ready-made, functional class, and adding new data members and methods (and re-
Define existing methods), we can keep the existing code intact (and someone may still use it), without introducing their own programming errors.
Error. Once an error occurs, it must be caused by your new code. In this way, compared with modifying the subject of the existing code
The time and effort required for a positive error can be much less.
The most noteworthy part of inheritance is that it does not provide a method for the new class. Inheritance is an expression of the relationship between the new class and the basic class. Yes.
To sum up the relationship, "the new class belongs to one of the existing classes ".
This expression is not only a visual interpretation of inheritance, but also directly supported by languages. As an example, you can consider
One basic class named Instrument is used to represent an Instrument, and the other category is called Wind. Because inheritance means that all of the basic classes
Methods can also be used in Derived classes, so any messages we send to the basic class can also be sent to the messages class. If the Instrument class has one
The play () method is used by the Wind device. This means that we can definitely think that a Wind object is also one of the instruments.
Type. The following example shows how the compiler supports this concept:
Java code
Public class Instrument {
Public void play (){
System. out. println ("hello ");
}
Static void tune (Instrument I ){
I. play ();
}
}
Public class Wind extends Instrument {
Public static void main (String [] args ){
Wind wind = new Wind ();
Instrument. tune (wind );
}
}
Running result:
Hello
The most interesting in this example is the tune () method, which can accept an Instrument handle. However, in Wind. main (), the tune () method
It is called by assigning a Wind handle to it. Java is especially strict with the type check, so you may be surprised that
What kind of method can receive another type? However, we must realize that a Wind object is also
Instrument object. In addition, there is no way for an Instrument (Instrument) that is not in the Wind to be called by tune. In
In tune (), the Code applies to instruments and anything derived from instruments. Here we will begin with a Wind sentence
The act of converting a handle into an Instrument handle is called "upstream Styling ".
Because the direction of the shape is from the category class to the base class, the arrow is facing up, so it is usually called "upstream shape", that is, Upcasting. Upstream
Type is certainly safe, because we are from a more special type to a more general type. In other words, the category class is a super
Set. It can contain more methods than the base class, but it contains at least the methods of the base class. The class interface may output
The only problem is that it may lose methods, rather than winning them. This is when there is no clear shape or other special logo
Note: The reason why the compiler allows the shape extension is true.
Description of final keywords in inheritance:
Final data
(1) compile-time constant, which will never change
(2) A value initialized at runtime. We do not want it to change.
Java code
Final int s = 1; // s is a constant
Final Object obj = new Object (); // obj is an unchangeable handle, but the internal variable of obj can be changed.
Final int s; // s is a constant, but must be initialized before use
Void method (final int s) {}// when calling a method, s gets a value, but this value is read-only in the method.
Final Method
The final method may be used for two reasons. The first is to lock the method to prevent any inheritance class from changing its original meaning. When designing a program, you can do this if you want the behavior of a method to remain unchanged during the inheritance period and cannot be overwritten or rewritten.
The second reason for using the final method is the efficiency of program execution. After a method is set to final, the compiler can put all calls to that method into "embedded" calls. As long as the compiler finds a final method call, it will (based on its own judgment) Ignore the General Code insertion method used to execute the method call mechanism (push the independent variables into the stack; jump to the method code and execute it; jump back; clear the stack independent variable; and finally process the returned value ). Instead, it replaces the method call with a copy of the actual code in the method body. This avoids system overhead during method calls. Of course, if the method size is too large, the program will become swollen and may not be able to achieve any performance improvement caused by embedded code. Because any improvement is offset by the time spent in the method. The Java compiler can automatically detect these situations and "wisely" decide whether to embed a final method. However, it is best not to fully trust the compiler to make all the judgments correctly. Generally, you should consider setting a method as final only when the amount of code for the method is very small or you want to explicitly prohibit the method from being overwritten.
All private methods in the class are automatically final. Since we cannot access a private method, it will never be overwritten by other methods (if forced to do so, the compiler will give an error message ). You can add a final indicator for a private method, but cannot provide any additional meaning for that method.
Final class
After a class is defined as final, the result is that inheritance is not allowed-there are no more restrictions. However, because it prohibits inheritance, all methods in a final class are final by default. Because they cannot be overwritten at this time. Therefore, the compiler has the same efficiency choice as we explicitly declare a method as final. You can add a final indicator to a method in the final class, but this does not make any sense.
Class loading sequence:
If the base class contains another base class, the other base class is loaded immediately, and so on. Next, perform static initialization in the root base class, and then in the next category class, and so on. It is critical to ensure this order, because the initialization of the category class may depend on the correct initialization of the base class members.
Summary:
Whether inherited or merged, we can create a new type based on the existing type. However, in typical cases, we synthesize existing types of "regeneration" or "reuse" to use them as part of the basic implementation process of new types. However, if you want to implement "regeneration" of interfaces, you should use inheritance. Because the derived or derived classes have interfaces of the basic classes, they can be "uplinked" as the basic classes. This is vital to the problem of the polymorphism that will be discussed in the next chapter.
Although inheritance has been particularly emphasized in object-oriented programming, it is best to consider the adoption of synthesis technology when starting a design. Inheritance technology should be considered only when necessary (this issue will be discussed in the next chapter ). Merging is more flexible. However, by applying inheritance techniques to your member types, you can accurately change the types of member objects at runtime, thereby changing their behavior.
Although it is of great help for rapid project development to achieve code regeneration through synthesis and inheritance. However, before allowing other programmers to fully rely on it, they generally want to redesign their class structure. Our ideal class structure should be that each class has its own specific purpose. They cannot be too large (for example, if there are too many integrated functions, it is difficult to achieve its regeneration), and cannot be too small (as a result, they cannot be used by themselves, or new features cannot be added ). The final implemented classes should be able to be easily regenerated.