Introduction to inheritance, polymorphism, overloading, and overriding in Java _java

Source: Internet
Author: User
Tags call back constant function prototype inheritance modifier advantage

What is polymorphism? What is its implementation mechanism? What is the difference between overloading and overriding? This is the four very important concepts that we want to review this time: inheritance, polymorphism, overloading, and rewriting.

Inheritance (inheritance)

Simply put, inheritance is based on an existing type, creating a new type by adding new methods or redefining existing methods (which is called rewriting in the following way). Inheritance is an object-oriented three basic features-encapsulation, one of the inheritance, polymorphism, and every class we write when using Java is inherited, because in the Java language, the Java.lang.Object class is the most fundamental base class (or parent class, superclass) of all classes. If one of our newly defined classes does not explicitly specify which base class to inherit from, then Java defaults to that it inherits from the object class.

We can divide the classes in Java into the following three kinds:

Class: A class that uses class definitions and does not contain abstract methods.
Abstract class: A class defined with the abstract class that can contain or contain no abstract methods.
Interfaces: Classes that are defined using interface.

The following inheritance laws exist between these three types:

Classes can inherit (extends) classes, can inherit (extends) abstract classes, and can inherit (implements) interfaces.
Abstract classes can inherit (extends) classes, can inherit (extends) abstract classes, and can inherit (implements) interfaces.
Interfaces can only inherit (extends) interfaces.

Note that the different keyword extends and implements used in each of the three rules above are not replaceable at will. As you know, a generic class that inherits an interface must implement all the methods defined in this interface, otherwise it can only be defined as an abstract class. I'm not using the word "implementation" for the Implements keyword here because conceptually it also represents an inheritance relationship, and for an abstract class implements interface, it does not necessarily implement any of the methods defined by this interface. Therefore, it is more reasonable to use the argument of inheritance.

The above three rules also adhere to the following constraints:

Both classes and abstract classes can inherit up to one class, or up to one abstract class, and both are mutually exclusive, meaning that they either inherit a class or inherit an abstract class.
Classes, abstract classes, and interfaces, when inheriting interfaces, are not constrained by numbers and can theoretically inherit infinitely many interfaces. Of course, for a class, it must implement all the methods defined in all the interfaces that it inherits.
Abstract classes inherit abstract classes, or when implementing an interface, you can partially, wholly or completely implement abstract (abstract) methods of the parent abstract class, or interfaces defined in the parent class interface.
class, or when implementing an interface, you must implement all abstract (abstract) methods of the parent abstract class, or all interfaces defined in the parent class interface.

The benefit of inheriting to our programming is the reuse of the original class (reuse). Like the reuse of modules, the reuse of classes can improve the efficiency of our development, in fact, the reuse of modules is a large number of classes in the reuse of the effect of superposition. In addition to inheritance, we can use a combination of the way to use the class. The so-called combination is to define the original class as a property of the new class, and reuse it by invoking the original class in the new class. If there is no relationship between the newly defined type and the original type, that is to say, the object represented by the new defined type is not one of the things that the original type represents, for example, the yellow race is one of the human beings, and there is a relationship between them that contains and is contained. Then the combination is a better choice to achieve reuse. The following example is a simple example of a combinatorial approach:


public class Sub { 
  private parent P = new parent (); 
 
  public void DoSomething () { 
    //Multiplexing Parent class method 
    P.method (); 
    ' Other code 
  } 
' 
 
class Parent {public 
  void method () { 
    //does something here 
  } 

Of course, in order for the code to be more efficient, we can initialize it when we need to use the original type (such as parent p).

Use inheritance and combine to reuse the original class, is an incremental development pattern, which has the advantage of not having to modify the original code, so that it does not bring new bugs to the original code, nor does it need to be tested again because of changes to the original code, which is obviously beneficial for our development. Therefore, if we are in the maintenance or transformation of an existing system or modules, especially their understanding is not very thorough, we can choose the mode of incremental development, this can not only greatly improve our development efficiency, but also to avoid the original code changes caused by the risk.

Polymorphism (polymorphism)

Polymorphism is another important basic concept, as mentioned above, it is one of the three basic features of object-oriented. What is polymorphism? Let's take a look at the following examples to help understand:

//Auto Interface interface Car {//Auto name String getName (); 
Get car price int getprice (); 
  //BMW class BMW implements car {public String getName () {return "BMW"; 
  public int GetPrice () {return 300000; 
  }//Chery QQ class CHERYQQ implements car {public String getName () {return "CHERYQQ"; 
  public int GetPrice () {return 20000; 
 
  }//car dealership public class Carshop {//Car sales private int money = 0; 
    Sell a car. public void Sellcar (cars car) {System.out.println ("model:" + car.getname () + "unit Price:" + car.getprice ()); 
  Increase the selling price of the car revenue money + = Car.getprice (); 
  ///Sales total revenue public int Getmoney () {return money; 
    public static void Main (string[] args) {Carshop ashop = new Carshop (); 
    Sell a BMW Ashop.sellcar (new BMW ()); 
    Sell a Chery QQ Ashop.sellcar (New Cheryqq ()); 
  System.out.println ("gross income:" + Ashop.getmoney ()); } 
} 


Run Result:

Model: BMW Price: 300000
Model: CHERYQQ Price: 20000
Total Revenue: 320000

Inheritance is the basis for the realization of polymorphism. In a literal sense, polymorphism is a type (all car type) showing a variety of states (BMW's name is BMW, the price is 300000; Chery's name is CHERYQQ and the price is 2000). Associating a method call with the body (that is, an object or Class) to which this method belongs is called binding, divided into early binding and late binding. Let's explain their definition:

Pre-binding: Binding before the program is run, implemented by compilers and linker, also called static binding. such as the static method and final method, note that this also includes the private method, because it is implicitly final.
Late binding: Binding at run time based on the type of the object, implemented by the method invocation mechanism, and therefore called dynamic binding, or run-time binding. All methods except early binding belong to late binding.

Polymorphism is implemented on the mechanism of late binding. The advantage of polymorphism is that it eliminates the coupling between classes and makes programs easier to extend. For example, in the above example, a new type of car sales, just want to let the new defined class and implement all of its methods, and do not need to make any changes to the original code, the Carshop class Sellcar (Cars car) method can handle the new model. The new code is as follows:

Santana 
class Santana implements car {public 
  String GetName () {return 
    "Santana"; 
  } 
 
  public int GetPrice () {return 
    80000; 
  } 

Overloads (overloading) and overrides (overriding)

Both overloads and overrides are concepts of methods, and before we figure out the two concepts, let's take a look at what the method is called (the English name is signature, and some of the translations are "signed", although it is widely used, but this translation is inaccurate). A type structure is the composition of a method, including the name and parameters of the method, the number and type of parameters, and the order in which they appear, but does not include the return value type of the method, the access modifier, and the abstract, static, final modifier. For example, the following two methods have the same type of structure:

public void method (int i, string s) { 
  //does something 
} public 
 
String method (int i, string s) { 
  //do some Thing 
} 


And these two are different types of methods:

public void method (int i, String s) { 
  //does something 
} public 
 
void method (String s, int i) { 
  //do some Thing 
} 

After understanding the concept of the form, let's look at the overloads and overrides, see their definitions:

Rewrite, the English name is overriding, means that in the case of inheritance, a subclass defines a new method with the same type as the method in its base class, which is called a subclass that overrides the method of the base class. This is the necessary step to implement polymorphism.
Overload, the English name is overloading, is defined in the same class with more than one with the same name, but a different type of method. In the same class, it is not allowed to define more than one method with the same type of structure.

Let's consider an interesting question: can constructors be overloaded? The answer, of course, is yes, and we often do that in actual programming. In fact, the constructor is also a method, the constructor name is the method name, the constructor parameter is the method parameter, and its return value is an instance of the newly created class. However, the constructor cannot be overridden by the quilt class because subclasses cannot define constructors with the same type as the base class.

Overload, overlay, polymorphism, and function concealment

Often see some beginners in C + + for overload, overlay, polymorphism and function hidden fuzzy understanding. Write a bit of your own opinion here, hope to be able to C + + Beginners FAQ.

To understand the complex and subtle relationship between overload, overlay, polymorphism, and function concealment, let us first review the basic concepts of overload coverage.

First, let's take a look at a very simple example of what is called a function hidden hide.

#include <iostream>
using namespace std;
Class base{public
:
  void Fun () {cout << "base::fun ()" << Endl;}
};
Class Derive:public base{public
:
  void Fun (int i) {cout << "derive::fun ()" << Endl;}
};
int main ()
{
  derive D;
     The following is a mistake, so shielding off the
  //d.fun (); Error C2660: ' Fun ': function does not take 0 parameters D.fun
  (1);
     Derive *pd =new derive ();
     The following is a mistake, so shielding off the
     //pd->fun (); Error C2660: ' Fun ': function does not take 0 parameters Pd->fun
     (1);
     Delete PD;
  return 0;
}

/* Functions in different namespaces scopes do not form overloads, and subclass and parent classes are two different scopes.
In this case, two functions are not overloaded in different scopes, unless this scope is a namespace scope. */
In this example, the function is not overloaded overload, nor does it overwrite override, but hides the hide.

The next 5 examples specify what is hidden

Example 1

#include <iostream>
using namespace std;
Class basic{public
:
     void Fun () {cout << "base::fun ()" << Endl;} Overload
     void Fun (int i) {cout << "base::fun (int i)" << Endl;} Overload
};
Class derive:p ublic basic{public
:
     void Fun2 () {cout << "derive::fun2 ()" << Endl;}
};
int main ()
{
     derive D;
     D.fun ()//correct, the derived class does not declare a function with the same name as the base class, all overloaded functions with the same name in the base class are candidates.
     D.fun (1);/correct, the derived class does not declare a function with the same name as the base class, all overloaded functions with the same name in the base class are candidates. return
     0;
}

Example 2

#include <iostream>
using namespace std;
Class basic{public
:
     void Fun () {cout << "base::fun ()" << Endl;} Overload
     void Fun (int i) {cout << "base::fun (int i)" << Endl;} Overload
};
Class derive:p ublic basic{public
:
     //new version of the function, all overloaded versions of the base class are masked, and here we call it a function
  to hide the declaration of a function with the same name as a base class in a derived class. A function with the same name in the base class is not a candidate function, even though the base class has overloaded functions with multiple versions of the parameter table.
     void Fun (int i,int j) {cout << "derive::fun (int i,int j)" << Endl;}
     void Fun2 () {cout << "derive::fun2 ()" << Endl;}
;
int main ()
{
     derive D;
     D.fun (1,2);
     The following is a mistake, so shielding off
     //d.fun (); Error C2660: ' Fun ': function does not take 0 parameters return
     0;
}

Example 3

#include <iostream>
using namespace std;
Class basic{public
:
     void Fun () {cout << "base::fun ()" << Endl;} Overload
     void Fun (int i) {cout << "base::fun (int i)" << Endl;} Overload
};
Class derive:p ublic basic{public
:
     /Covers one of the function versions of the override base class, and all overloaded versions of the base class are hidden from the
  declaration of a function with the same name as the base class in a derived class. A function with the same name in the base class is not a candidate function, even though the base class has overloaded functions with multiple versions of the parameter table.
     void Fun () {cout << "derive::fun ()" << Endl;}
     void Fun2 () {cout << "derive::fun2 ()" << Endl;}
;
int main ()
{
     derive D;
     D.fun ();
     The following is a mistake, so shielding off
     //d.fun (1); Error C2660: ' Fun ': function does not take 1 parameters return
     0;
}

Example 4

#include <iostream>
using namespace std;
Class basic{public
:
     void Fun () {cout << "base::fun ()" << Endl;} Overload
     void Fun (int i) {cout << "base::fun (int i)" << Endl;} Overload
};
Class derive:p ublic basic{public
:
     using Basic::fun;
     void Fun () {cout << "derive::fun ()" << Endl;}
     void Fun2 () {cout << "derive::fun2 ()" << Endl;}
;
int main ()
{
     derive D;
     D.fun ()//Correct
     d.fun (1);//correct return
     0;
}
/*
Output Results
derive::fun ()
base::fun (int i) Press any key to
continue
* *

Example 5

#include <iostream>
using namespace std;
Class basic{public
:
     void Fun () {cout << "base::fun ()" << Endl;} Overload
     void Fun (int i) {cout << "base::fun (int i)" << Endl;} Overload
};
Class derive:p ublic basic{public
:
     using Basic::fun;
     void Fun (int i,int j) {cout << "derive::fun (int i,int j)" << Endl;}
     void Fun2 () {cout << "derive::fun2 ()" << Endl;}
;
int main ()
{
     derive D;
     D.fun ()//Correct
     d.fun (1);//correct
     d.fun (1,2)//correct return
     0;
}
/*
output result
base::fun ()
base::fun (int i)
derive::fun (int i,int j)
Press any key to continue
*/ 

All right, let's start with a little summary. Characteristics between overload and overlay

Features of overloaded Overload:

n the same range (in the same class);
n function names are different with same parameters;
n virtual keyword is optional.

Overlay override refers to a derived class function that overrides a base class function, covering the following characteristics:

n different ranges (in derived classes and base classes, respectively);
n function names and parameters are the same;
n the base class function must have the virtual keyword. (if no virtual keyword is called hidden hide)

If the base class has multiple overloaded (overload) versions of a function, and you override (override) The version of one or more functions in the base class in a derived class, or add a new version of the function in a derived class (with the same number of functions and different arguments), the overloaded versions of all base classes are masked. This is what we call hidden hide. So, in general, when you want to use a new version of a function in a derived class and want to use a version of the base class, you should override all overloaded versions of the base class in the derived class. If you do not want to rewrite the overloaded version of the function of the base class, you should explicitly declare the base class namespace scope by using example 4 or example 5.
In fact, the C + + compiler thinks that functions with different parameters of the same function name have no relationship at all, they are basically two unrelated functions. Just C + + language in order to simulate the real world, in order to let programmers more intuitive thinking to deal with the problems in the real world, the introduction of the concept of overload and coverage. Overloads are under the same namespace scope, while overrides are under different namespace scopes, such as base classes and derived classes, which are two different namespace scopes. In the inheritance process, the base class function is hidden if the derived class has the same name as the base class function. Of course, the situation discussed here is that there is no virtual keyword in front of the base class function. In the case of the virtual keyword keyword, we have another discussion.
An inheriting class overrides a version of a function of the base class to produce an interface of its own functionality. At this point, C + + compiler thinks, now that you want to use the derived class's own rewritten interface, then my base class interface is not available to you (you can, of course, explicitly declare the namespace scope of the method, see [C + + base] overload, overlay, polymorphism and function hidden (1)). And it doesn't bother you. The interfaces of the base class have overloaded attributes. If you want to keep the overloaded feature in a derived class, then you can give the feature of the interface overload yourself. So in a derived class, as long as the function name, the function version of the base class will be ruthlessly blocked. In the compiler, the mask is implemented through the namespace scope.

Therefore, to keep the overloaded version of the base class in a derived class, you should override the overloaded versions of all base classes. Overloading is only valid in the current class, and inheritance loses the attributes of the function overload. In other words, to put overloaded functions of a base class in an inherited derived class, you must override it.

Here "hidden" means that the function of the derived class masks the base class function with the same name, and we also make a summary of the rules:

n if the function of the derived class has the same name as the function of the base class, but the arguments are different. At this point, the Jocky class has no virtual keyword and the function of the base class is hidden. (Note that you are not confused with overloading, although the function name is different from the same argument should be called overloading, but this is not understood as overloading, because derived classes and base classes are not within the same namespace scope.) understood here as hidden)
n if the function of the derived class has the same name as the function of the base class, but the arguments are different. At this point, the Jocky class has the virtual keyword, and the function of the base class is implicitly inherited into the vtable of the derived class. The functions in the derived class vtable point to the function address of the base class version. The new version of the function is added to the derived class as an overloaded version of the derived class. However, when the base class pointer implements the Polymorphic call function method, the new derived class function version will be hidden.
n if the function of the derived class has the same name as the function of the base class, and the parameters are the same, the base class function does not have the virtual keyword. At this point, the function of the base class is hidden. (Note that it is not confused with the overlay, which is understood as hidden).
n if the function of the derived class has the same name as the function of the base class, and the parameters are the same, the base class function has a virtual keyword. At this point, the functions of the base class are not "hidden." (Here, you have to understand to cover oh ^_^).

Episode: The base class function does not have the virtual keyword before, we want to rewrite more easily, in the virtual keyword, we call coverage more reasonable, quit this, I also hope that we can better understand C + + some subtle things. Crap, let's illustrate.

Example 6

#include <iostream>
using namespace std;
 
Class base{public
:
     virtual void fun () {cout << "base::fun ()" << Endl;} Overload
  virtual void Fun (int i) {cout << "base::fun (int i)" << Endl;} Overload
};
 
Class Derive:public base{public
:
     void Fun () {cout << "derive::fun ()" << Endl;} Override
  void Fun (int i) {cout << "derive::fun (int i)" << Endl;} Override
     void Fun (int i,int j) {cout<< "derive::fun (int i,int j)" <<endl;} Overload
};
 
int main ()
{
 Base *PB = new Derive ();
 Pb->fun ();
 Pb->fun (1);
 The following is a mistake, so shielding off
 //pb->fun (1,2); virtual function cannot be overload,error C2661: ' fun ': no overloaded function takes 2 Parameters
 
 cout << Endl;
 Derive *pd = new derive ();
 Pd->fun ();
 Pd->fun (1);
 Pd->fun (1,2);//overload
 
 delete pb;
 Delete PD;
 return 0;
}
/*

Output results


Derive::fun ()
Derive::fun (int i)

Derive::fun ()
Derive::fun (int i)
Derive::fun (int i,int j)
Press any key to continue
*/

Example 7-1

#include <iostream> 
using namespace std;
 
Class base{public
:
     virtual void fun (int i) {cout << "base::fun (int i)" << Endl;}
;
 
Class Derive:public base{};
 
int main ()
{
     Base *PB = new Derive ();
     Pb->fun (1);//base::fun (int i)
     delete pb;
     return 0;
}

Example 7-2

#include <iostream> 
using namespace std;
 
Class base{public
:
     virtual void fun (int i) {cout << "base::fun (int i)" << Endl;}
;
 
Class Derive:public base{public
:
  void Fun (double d) {cout << "derive::fun (double D)" << Endl; 
};
 
int main ()
{
     Base *PB = new Derive ();
     Pb->fun (1);//base::fun (int i)
     pb->fun ((double) 0.01);//base::fun (int i)
     delete pb;
     return 0;
}

Example 8-1

#include <iostream> 
using namespace std;
 
Class base{public
:
     virtual void fun (int i) {cout << "base::fun (int i)" << Endl;}
;
 
Class Derive:public base{public
:
     void Fun (int i) {cout << "derive::fun (int i)" << Endl;}
;
 
int main ()
{
     Base *PB = new Derive ();
     Pb->fun (1);//derive::fun (int i)
     delete pb;
     return 0;
}


Example 8-2

#include <iostream> 
using namespace std;
 
Class base{public
:
     virtual void fun (int i) {cout << "base::fun (int i)" << Endl;}
;
 
Class Derive:public base{public
:
     void Fun (int i) {cout << "derive::fun (int i)" << Endl;}
     void Fun (double d) {cout << "derive::fun (double D)" << Endl;}     
;
 
int main ()
{
     Base *PB = new Derive ();
     Pb->fun (1);//derive::fun (int i)
     pb->fun ((double) 0.01);//derive::fun (int i)
     delete pb;
     return 0;
}


Example 9

 #include <iostream> using namespace std;

Class base{public:virtual void fun (int i) {cout << "base::fun (int i)" << Endl;}
};
    Class Derive:public base{public:void fun (int i) {cout << "derive::fun (int i)" << Endl;} 
    void Fun (char c) {cout << "derive::fun (char c)" << Endl;}     
void Fun (double d) {cout << derive::fun (double D) << Endl;}
};
     int main () {Base *PB = new Derive (); Pb->fun (1);//derive::fun (int i) Pb->fun (' a ');//derive::fun (int i) Pb->fun (double) 0.01);//derive::fun (i
     NT i) derive *pd =new derive (); Pd->fun (1);//derive::fun (int i)//overload pd->fun (' a ');//derive::fun (char c)//overload PD
     ->fun (0.01);//derive::fun (double D) Delete PB;
     Delete PD;
return 0; }

&NBSP
Example 7-1 and 8-1 very well understood, I put these two examples here, is lets everybody make a comparison pendulum, is also in order to help everybody better understanding:
n       In     example 7-1, a derived class does not have a virtual function that overrides the base class, where the function pointer in the vtable of the derived class points to an address that is a virtual function of the base class. In
n          example 8-1, the derived class overrides the virtual function of the base class. The address that the function pointer in the vtable of the derived class points to is the overridden virtual function address of the derived class itself.
In example 7-2 and 8-2 looks a bit strange, in fact, you follow the principle of the above comparison, the answer is clear:
n          example 7-2, We overloaded a function version for a derived class: void Fun (double D)   In fact, it's just a decoy. We specifically analyze, the base class has several functions, derived classes have several functions:
type
  base class
  derived class
 
vtable part
 void Fun (int i)
& nbsp to the base class version of virtual function void Fun (int i)
 
Static section
 
 void fun (double D)
 

&NBSP
Let's analyze the following three lines of code
Base *PB = new Derive ();
Pb->fun (1);//base::fun (int i)
Pb->fun (double) 0.01);//base::fun (int i)
 
The first sentence is the key, and the base class pointer points to the object of the derived class, which we know is a polymorphic call; In the next sentence, the Run-time base class pointer is found to be a derived class object based on the type of the Run-time object. So first you go to the vtable of the derived class to find the virtual function version of the derived class, and you find that the derived class does not have a virtual function that overrides the base class, and that the vtable of the derived class simply makes a point pointing to the address of the base class virtual function, so it's natural to call The last sentence, the program is still immersed in the operation to find derived classes of vtable, found no this version of the virtual function, had to call back to their own only a virtual function.
&NBSP
It is also worth mentioning that if the base class has more than one virtual function at this time, the program will prompt for "ambiguous call" when it is compiled. Examples include the following

#include <iostream> 
using namespace std;
 
Class base{public
:
     virtual void fun (int i) {cout << "base::fun (int i)" << Endl;}
          virtual void Fun (char c) {cout << "base::fun (char c)" << Endl;}
;
 
Class Derive:public base{public
:
  void Fun (double d) {cout << "derive::fun (double D)" << Endl; 
};
 
int main ()
{
     Base *PB = new Derive ();
          Pb->fun (0.01);//error C2668: ' fun ': ambiguous call to overloaded function
     Delete pb;
     return 0;
}

OK, let's analyze the example 8-2.

In n example 8-2, we also overload a version of a function for a derived class: void Fun (Double D), which overrides the virtual function of the base class, and let's analyze it to see that there are several functions in the base class, and a derived class has several functions:

Type


Base class


Derived classes





vtable part


void Fun (int i)


void Fun (int i)





Static part





void Fun (double D)


From the table we can see that the function pointer in the vtable of the derived class points to its own overridden virtual function address.





Let's analyze the following three lines again.





Base *PB = new Derive ();


Pb-&gt;fun (1);//derive::fun (int i)


Pb-&gt;fun (double) 0.01);//derive::fun (int i)





The first sentence is needless to say, the second sentence, of course, invokes the virtual function version of the derived class, the third sentence, hey, feel strange, in fact, the C + + program is very stupid, in the run, immersed into the vtable of the derived class table, only a look, rely on, the competition is not the version of the want, really think impassability, Base class pointers why not turn around and look for it? Oh, the original is the eyesight is limited, base class age so old, must certainly be the elder, it that pair of eyes to see only is own vtable part (namely static part) and own to manage vtable part, the derived class void fun (double D) So far, can not see Ah! Besides, the derived class has nothing to do with it, does it not have a little power of its own? Hey, no quarrel, their own bar ^_^





Oh, are you going to sigh? The base class pointer can make polymorphic calls, but it is never possible to make overloaded calls to derived classes (reference example 6) ~ ~ ~





Take another look at example 9,


The effect of this example is similar to that of example 6. Presumably you understand the above examples, this is also a small kiss.


Summary:





Overloaded overload is based on the function's argument list to select the version of the function to invoke, and polymorphism is based on the actual type of the runtime object to select the version of Virtual virtual function to invoke, the implementation of the polymorphism is derived class to cover the virtual virtual function of the base class override to achieve, If the derived class does not overwrite the virtual virtual function of the base class override, then the derived class automatically inherits the virtual virtual function version of the base class, and the virtual virtual function of the base class version is invoked whenever the base class pointer points to an object that is a base type or a derived type If the derived class overrides the virtual virtual function of the base class override, the version of the virtual virtual function to invoke is selected at run time based on the actual type of the object, for example, if the base class pointer points to an object type that is a derived type, the virtual virtual function version of the derived class is invoked. In order to realize polymorphism.





The intention of using polymorphism is to declare the function as virtual in the base class, and to overwrite the virtual virtual function version of the override base class in a derived class, note that the function prototype at this time is consistent with the base class, which is the same as the parameter type; If you add a new version of the function in a derived class, You cannot dynamically invoke a new function version of a derived class through a base class pointer, which is only an overloaded version of a derived class. In the same sentence, overloading is only valid in the current class, regardless of whether you overload it in the base class or in a derived class. If you understand this, in example 6, example 9, we will also have a smooth understanding of its output results.





Overloading is statically linked, and polymorphism is dynamically linked. Further, the overload is independent of the type of object that the pointer actually points to, and polymorphism is related to the type of object the pointer actually points to. A pointer to a Jocky class calls an overloaded version of a derived class, and C + + editing is considered illegal, and the C + + compiler only thinks that the base class pointer can only invoke overloaded versions of the base class, overloading is only valid within the namespace scope of the current class, and inheritance loses the overloaded attribute, of course If the base-class pointer at this point calls a virtual virtual function, it will also dynamically select the virtual virtual function version of the base class or the virtual virtual version of the derived class to perform the specific operation, which is determined by the type of object that the base class pointer actually points to. So the overload is independent of the type of object the pointer actually points to, and polymorphism is related to the type of object the pointer actually points to.





Finally, it is clear that virtual virtual functions can also be overloaded, but overloads can only be valid within the scope of their current namespace.





How many string objects were created?


Let's start by looking at a piece of code:


Java code


String Str=new string ("abc");


This is often followed by this code, and that is, how many string objects did this line of code create? I believe you are not unfamiliar with this problem, the answer is also known, 2. Let's start with this question and review some of the Java knowledge associated with creating string objects.


We can look at the above line of code as String str, =, "abc", and new String () four. String Str simply defines a variant of type string named Str. So it doesn't create an object; = It initializes the variable str, assigns a reference (or a handle) of an object to it, and obviously does not create an object; now only the new String ("abc") Out. So why is the new string ("abc") considered "ABC" and new String ()? Let's take a look at the constructor of the string we called:


Java code


public string (string original) {


Other code ...


}


As we all know, the methods we use to create an instance of a class (object) have the following two kinds:


Create an object using new.


Call the Class class's Newinstance method and create the object using the reflection mechanism.


We created an object by invoking the above constructor method of the string class using new, and assigned its reference to the STR variable. At the same time, we notice that the invoked constructor method accepts an argument that is also a string object, which is "ABC". This brings us to another discussion of how to create a string object--quotation marks contain text.


This is a string-specific, and it differs greatly from the way new is.


Java code


String str= "ABC";


There is no doubt that this line of code creates a string object.


Java code


String a= "ABC";


String b= "ABC";


What about here? The answer is still one.


Java code


String a= "AB" + "CD";


And look at this? The answer is still one. Is it a little strange? Here, we need to introduce a review of the knowledge about string pooling.


There is a string pool in the Java Virtual Machine (JVM) that holds many string objects and can be shared for use, so it improves efficiency. Because the string class is final, its value cannot be changed once it is created, so we do not have to worry about the confusion of the program as a result of string object sharing. The string pool is maintained by the string class, and we can call The Intern () method to access the string pool.


Let's look back at string a= "abc"; When this line of code is executed, the Java Virtual machine first looks in the string pool for an object that has a value of "ABC", which is judged by the return value of the String class equals (Object obj) method. If it does, it will no longer create a new object, directly return a reference to an existing object, or, if not, create the object and then add it to the string pool and return its reference. Therefore, it is not difficult to understand why the first two examples in the preceding three examples are the answer.


For a third example:


Java code


String a= "AB" + "CD";


Because the value of a constant is determined at compile time. Here, both "AB" and "CD" are constants, so the value of variable a can be determined at compile time. The result of this line of code is equivalent to the following:


Java code


String a= "ABCD";


So only one object "ABCD" was created here, and it was saved in a string pool.


Now the question is, are all the strings added to the string pool after the "+" connection? We all know that "= =" can be used to compare two variables, it has the following two kinds of situations:


If you are comparing two basic types (Char,byte,short,int,long,float,double,boolean), you are determining whether their values are equal.


If the table is more than two object variables, it's about whether their references point to the same object.


Below we will use "= =" To do a few tests. For illustration purposes, we refer to an object that already exists in the string pool as the object is added to the string pool:


Java code


public class Stringtest {public static void main (string[] args) {string a = ' ab ';//created an object and added to the string pool Syste 
    M.out.println ("String a = \" ab\; "); 
    String b = "CD";//Creates an object and adds System.out.println ("string b = \" cd\ ";") to the string pool; 
    String c = "ABCD";//Creates an object and adds string d = "AB" + "CD" to the Pool of strings; 
    If D and C point to the same object, then D is also added to the string pool if (d = = c) {System.out.println ("\" ab\ "+\" cd\ "created object \" joined \ "string Pool"); 
    //If D and C do not point to the same object, then D is not added to the string pool else {System.out.println ("\" ab\ "+\" cd\ "created object \" is not joined \ "string Pool"); 
    String e = a + "CD"; 
    If E and C point to the same object, then E is also added to the string pool if (e = = c) {System.out.println ("a +\" cd\ "created object \" joined \ "string Pool"); 
    //If E and C do not point to the same object, then E is not added to the string pool else {System.out.println ("a +\" cd\ "created object \" is not joined \ "string Pool"); 
    String f = "AB" + B; 
    If f and C point to the same object, then F is also added to the string pool if (f = = c) {System.out.println ("\" ab\ "+ B created object \" joined \ "string Pool"); }//If F andC does not point to the same object, then the F is not joined to the string pool else {System.out.println ("\" ab\ "+ B created object \" is not joined \ "string Pool"); 
    } String g = a + B; 
    If G and C point to the same object, then G is also added to the string pool if (g = = c) {System.out.println ("A + B created object \" joined \ "string Pool"); 
    //If G and C do not point to the same object, then G is not added to the string pool else {System.out.println ("A + B created object \" is not joined \ "string Pool"); 
 } 
  } 
}

The results of the operation are as follows:
String a = "AB";
String B = "CD";
"AB" + "CD" created Object "joined" String pool
A + "CD" created object "not joined" string pool
"AB" + B created object "not joined" string pool
A + B created object "not joined" string pool
From the results above, it is not hard to see that only new objects created using a "+" connection between string objects that you create with quotes containing text are added to the string pool. For all the "+" join expressions that contain new, new objects (including null), the resulting object will not be added to the string pool, so we don't go into the details.
But there is one situation that needs to be brought to our attention. Take a look at the following code:
Java code

public class Stringstatictest { 
  //constant A public 
  static final String a = "AB"; 
 
  Constant b public 
  static final String b = "CD"; 
 
  public static void Main (string[] args) { 
    ///Two constants are initialized with a + join 
    String s = A + B; 
    String t = "ABCD"; 
    if (s = = t) { 
      System.out.println ("s equals T, they are the same object"); 
    } else { 
      System.out.println ("s not equal to T, they are not the same object"); 
    } 
  } 


The results of this code run as follows:
S equals T, they are the same object
Why is that? The reason is that, for a constant, its value is fixed, so it can be determined at compile time, and the value of the variable can be determined only when it is run, because the variable may be invoked by different methods, which may cause a change in value. In the example above, both A and B are constants, the values are fixed, so the value of S is fixed, and it is determined when the class is compiled. Other words:
Java code
String s=a+b;
Equivalent to:
Java code
String s= "AB" + "CD";
I'll change the example above to see what happens:
Java code

public class Stringstatictest { 
  //constant A public 
  static final String A; 
 
  Constant b public 
  static final String B; 
 
  static { 
    A = "AB"; 
    B = "CD"; 
  } 
 
  public static void Main (string[] args) { 
    ///Two constants are initialized with a + join 
    String s = A + B; 
    String t = "ABCD"; 
    if (s = = t) { 
      System.out.println ("s equals T, they are the same object"); 
    } else { 
      System.out.println ("s not equal to T, they are not the same object"); 
    } 
  } 
} 

The result of its operation is this:
S is not equal to T, they are not the same object
Just a little change, and the result is just the opposite of what happened. Let's analyze it again. A and B are defined as constants (they can only be assigned once), but they are not immediately assigned. When they are assigned, and what values are assigned, before the value of S is calculated, it is a variable. So A and B are similar in nature to a variable before being assigned a value. Then s cannot be determined at compile time, and can only be created at run time.
Because the sharing of objects in the string pool can improve efficiency, we encourage you to create string objects in quotes that contain text, which is what we often use in programming.
Next we'll look at the Intern () method, which is defined as follows:
Java code
Public native String intern ();
This is a local method. When this method is invoked, the the Java Virtual machine first checks if there is already an object value equality object exists in the string pool, returns a reference to the object in the string pool, or, if not, creates a string object with the same value in the string pool before returning its reference.
Let's take a look at this piece of code:
Java code

public class Stringinterntest {public 
  static void Main (string[] args) { 
    //use a char array to initialize a to avoid the existence of a value in the string pool before a is created "ABCD" Object 
    String A = new string (new char[] {' A ', ' B ', ' C ', ' d '}); 
    String B = A.intern (); 
    if (b = = = a) { 
      System.out.println ("B is joined in a string pool, no new object"); 
    } else { 
      System.out.println ("B is not added to the string pool, new object"); 
    } 
  } 
} 

Run Result:
B not included in the string pool, new object
if the Intern () method of the string class does not find an object of the same value, it adds the current object to the string pool, and then returns its reference, then B and a point to the same object or b points to a Java virtual machine that is new in the string pool, except that its value is the same as a. The result of this code is exactly what this is.
Finally, let's talk about the storage of the string object in the Java Virtual Machine (JVM) and the relationship of the string pool to the heap (heap) and stack (stack). Let's look at the difference between stacks and stacks:
Stacks: The main type of storage (or built-in type) (char, Byte, short, int, long, float, double, Boolean) and object references, data can be shared, The speed is second to the Register (register), faster than the heap.
Heap (heap): Used to store objects.
When we look at the source code of the string class, we find that it has a value property that holds the values of the string object, the type is char[], which also illustrates that the string is a sequence of characters.
When executing string a= "abc";, the Java Virtual opportunity creates three char values ' a ', ' B ' and ' C ' in the stack, and then creates a string object in the heap, whose value (value) is an array of three char values created just on the stack {' A ', ' B ', ' C '}, and finally this newly created string object is added to the string pool. If we then execute string b=new string ("abc"); code, because "ABC" has been created and saved in a string pool, the Java Virtual machine will only create a new string object in the heap. But its value (value) is the three char value ' a ', ' B ' and ' C ' that were created on the stack when the previous line of code was executed.
Here, the question of why the string Str=new string ("ABC") presented in the first chapter creates two objects is quite clear.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.