Detailed explanation of java overloaded method and class initialization

1 overload problem

Let's look at two pieces of code first:

public classTest2 {  
   
    public static void main(String[] args) {  
        f1(null);  
        f2();  
    }  
    public static void f1(String s) {  
        System.out.println("Which method is executed? I am String");  
    }  
   
    public static void f1(Object o) {  
        System.out.println("Which method is executed? I am Object");  
    }  
    public static void f2(){  
        System.out.println("Which method is executed? I have no parameters");  
    }  
    public static void f2(String...strings){  
        System.out.println("Which method is executed? I am an indefinite length parameter");  
    }  
}  

1.1 null and formal parameters in overload

When we call f1(null), the theory calls that both methods can run, but the jvm certainly can't run both methods. It can only choose one of them. Which one will it choose? The jvm will select the method of String parameter, because according to the principle of accuracy in method overloading, from the perspective of hierarchy, Object is at a higher level, String is inherited from Object, and calling String will be more accurate.

1.2 string and stringbuffer in overloading

If I add another method

public static void f1(StringBuffer s) {  
        System.out.println("Which method is executed? I am String");  
    }  

Then call f1(null); You can't compile. Why? Because there is no inheritance relationship between StringBuffer and String, the compiler feels that the methods of StringBuffer and String as parameters are very accurate. It does not know which method to execute. Compilation errors will occur, violating the principle of uniqueness in overloading

1.3 there is no parameter of the variable length in heavy load

And we're calling f2(); Method, which jvm will execute? The answer is no parameter. In fact, after the compiler compiles the variable length parameter, it will compile f2(String...strings) into a method whose parameters are arrays. We can prove through the code:

Class clazz=Test2.class;  
        Method[]methods=clazz.getDeclaredMethods();  
        for (Method method :methods) {  
            System.out.println(method);  
        }      

The result is: public static void Test2.f2(java.lang.String [])

Therefore, directly calling f2() without parameters is the most correct way to call parameterless methods. If there is no f2() {...}; This method can still run when we call f2(). This is because variable length parameters support no parameters, but the support for no parameters here is actually called by the compiler automatically filling in a new String [] {""}. Therefore, in essence, it is a calling method with array as parameters. And if we define a void f2(String[] s) method, we will prompt for repetition

2 initialization problem

2.1 initialization sequence

First, let's talk about the java object initialization steps:

  • This class: static variable - > static initialization block - > variable - > initialization block - > constructor
  • Inherited class: parent static variable - > parent static initialization block - > child static variable - > child static initialization block - > parent variable - > parent initialization block - > parent constructor - > child variable - > child initialization block - > child constructor

2.2 subclass inherits parent class

The problem with the default constructor: if the base class is the parent class and the derived class is the child class, first
Note that since there is a parent class before a child class, there must be a parent class before generating a child class.
Class is generated by the constructor of class. Every class has
Constructor. If you don't write any constructor when writing your class, then
The compiler automatically generates a default constructor for you. This default constructor
It is essentially empty and does not contain any code. But when it comes to inheritance, its problems arise
Yes.

If the parent class base class has only the default constructor, that is, the compiler automatically generates it for you.
And there are only default constructors in subclasses, so it won't cause any problems, because when you try to generate
When an instance of a subclass, the constructor of the subclass must be executed first, but because the subclass inherits the parent class,
Therefore, the default constructor of the subclass automatically calls the default constructor of the parent class. The instance of the parent class is generated first, and then the instance of the child class is generated.

class base{
}
class derived extends base{
public static void main(String[] args){
derived d=new derived();
}
}

Now I explicitly add the default constructor myself:

class base{
base(){
	System.out.println("base constructor");
}
}
class derived extends base{
derived(){
	System.out.println("derived constructor");
}
public static void main(String[] args){
derived d=new derived();
}
}

The execution results are as follows: first generate base class, and then derived class

base constructor
derived constructor

The problem I want to explain is if the base class has multiple constructor s
The derived class also has multiple constructors, and the constructor in the subclass defaults
What about calling the constructor of that parent class? The answer is to call the default constructor of the parent class.
But instead of the default constructor that the compiler automatically generates for you, you explicitly
Write out the default constructor.

class base{
base(){
System.out.println("base constructor");
}
base(int i){
System.out.println("base constructor int i");
}
}
class derived extends base{
derived(){
System.out.println("derived constructor");
}
derived(int i){
System.out.println("derived constructor int i");
}
public static void main(String[] args){
derived d=new derived();
derived t=new derived(9);
}
}

Operation results
base constructor
derived constructor
base constructor
derived constructor int i

If you comment out the constructor of the base class, an error occurs.

class base{
// base(){
// System.out.println("base constructor");
// }
base(int i){
System.out.println("base constructor int i");
}
}
class derived extends base{
derived(){
System.out.println("derived constructor");
}
derived(int i){
System.out.println("derived constructor int i");
}
public static void main(String[] args){
derived d=new derived();
derived t=new derived(9);
}
}

Operation results
derived.java:10: cannot resolve symbol
symbol : constructor base ()
location: class base
derived(){
^
derived.java:13: cannot resolve symbol
symbol : constructor base ()
location: class base
derived(int i){
2 errors

The constructor in the subclass cannot find the default constructor in the explicitly written parent class, so an error occurred.

2.3 protection function

So if you don't want the constructor of the subclass to call the default in the parent class you explicitly write out
What about constructors?
Examples are as follows:

class base{
// base(){
// System.out.println("base constructor");
// }
base(int i){
System.out.println("base constructor int i");
}
}
class derived extends base{
derived(){
super(8);
System.out.println("derived constructor");
}
derived(int i){
super(i);
System.out.println("derived constructor int i");
}
public static void main(String[] args){
derived d=new derived();
derived t=new derived(9);
}
}

Operation results
base constructor int i
derived constructor
base constructor int i
derived constructor int i

super(i) represents the constructor of the parent class. base(i) please pay attention
One is super(i) and the other is super(8)

Conclusion: if a subclass has multiple constructors, the parent class either has no constructor and the compiler generates it automatically, the default constructor of the parent class automatically generated by the compiler shall be executed before the subclass constructor is executed; Or there must be at least one explicit default constructor that can be called by the constructor of a subclass

Tags: Java

Posted on Sat, 02 Oct 2021 15:53:04 -0400 by exnet