Java study notes: polymorphism & virtual methods, inner classes & anonymous classes

1. Polymorphism & Virtual Method

1.1. What is polymorphism?

Polymorphism means that in the program, a name represents many different meanings.
Polymorphism is divided into two situations: (Why are they divided into different periods? Think first!)

First: compile-time polymorphism

Typical way to achieve compile-time polymorphism:
Why is there compile-time polymorphism in Overload ? Why overloading is a typical implementation of compile-time polymorphism?
In the program, that is, when writing the program, maybe we use the same name for a certain method, but we want to achieve polymorphism, we will inevitably make some methods of the same name be different, and it is impossible to achieve more. State! When is the difference? The program execution has a compile period and a run period, and each of these two stages has a means of distinguishing the method of the same name when encoding. During the compilation period, our overloaded functions are compiled, assembled, linked, and finally executed (Java should generate bytecode files). And this overload, it is in the compilation stage to complete the distinction of the method of the same name. How to distinguish it?
For example: sample program & disassembly code (disassembly command: javap -c file name)
Insert picture description here
Insert picture description here
can be seen from here, after compilation, our three overloaded functions are completely different, so we can know that this is in The compiler has completed the distinction!

Second: runtime polymorphism

A typical way to achieve runtime polymorphism: Override Override
must exist in the inheritance relationship. Without inheritance, there is no override! Because it is in the inheritance relationship, our subclass rewrites the method of the parent class. At this time, when the object of the subclass calls this method, it will not call the method of the parent class, but call the rewrite of the subclass Later method! Isn't this that the method of the same name has different effects in different application scenarios? So rewriting is a typical polymorphism. So why is rewriting a runtime polymorphism? How do you distinguish when the method with the same name calls the subclass and when the parent class is called?

This is determined by the system, which has a mechanism: dynamic binding! It is also called virtual method call, why is it called virtual method? It's imaginary? ? ? In fact, it is not, but when you are coding, you rewrite the method of the parent class, and then after compilation, the system does not know what the method you use is, who owns it, and what the method body is! At this time it is a dynamic relationship, only know that each method belongs to each class, and then compile it into a bytecode file according to the class!
According to our above example, you can see the disassembled code, each method has such a logo:
invokevirtual This is handled in accordance with the virtual method! But there is a different method, it is invokespecial ! That is the construction method, it is real! And why are these methods virtual? Because these methods are at the object level, and the object may or may not be called! So there is no binding with the instance yet! Need dynamic binding! (The static method at the class level is not a virtual method, and it is understandable from here!)

This kind of runtime polymorphism is to complete the dynamic binding when the method is called. At this time, the system runs it, which is the runtime polymorphism!

1.2. Upward modeling (further understanding of compile time and runtime)

Suppose there is a parent class: Person
Person has a subclass: Student
such a line of code: Person p = new Student();
or call it in function parameters:

Person p = new Student();

void fun(Person p){
    
    }

At this point, let's interpret the above two codes!
We call this method of declaring a variable of a base class type and referencing it with a subclass object, which is called uptracking modeling. During compilation, it is a variable of Person (base class), but during runtime, this reference variable will point to Object of subclass. So actually the object of p is subclass Student! Then in the function, if the passed parameter is an object of Student, it can also be passed to the function that requires the passing of the Person class, because the student is also a person, which is not contradictory (the subclass is a special embodiment of the parent class). But when it is used in the method body, it is the runtime. At this time, it will be dynamically bound according to the actual situation, and the methods and properties of the specific object will be used!
Insert picture description here

1.3. Demo of virtual method & polymorphism


public class VirtualMethod {
    
    
	
	static void GetDarw(Shape s) {
    
    
		s.darw();
	}
	
	static void GetSay(Shape s) {
    
    
		Shape.Say();
		// 写成 s.Say();会报警告!
	}
	
	public static void main(String[] args) {
    
    
		
		// 运行时多态:用重写来实现,调用的是虚方法!
		// 虚方法是除了static、private、final的方法,因为父类的这些修饰符的方法都是不可Override的!
		Circle c = new Circle();
		GetDarw(c);
		
		Triangle t = new Triangle();
		GetDarw(t);
		
		Line l = new Line();
		GetDarw(l);
		
//		Shape shape = new Circle();
//		shape.darw();  result: Circle is darwed! 因为实际shape是Circle的对象,这个是运行期决定的!
		
		
		// static修饰的方法,不算虚方法,是类级别的,是取决于类的声明的(在编译器)
		
		Circle StaticC = new Circle();
		GetSay(StaticC);// 无论传入的对象是什么,static的方法,只取决于类的声明,而与实例无关!
		
		
	}
}

class Shape {
    
    
	void darw() {
    
    
		System.out.println("Shape is darwed!");
	}
	
	static void Say() {
    
    
		System.out.println("Hello, i am Shape!");
	}
}

class Circle extends Shape {
    
    
	void darw() {
    
    
		System.out.println("Circle is darwed!");
	}
	
	static void Say() {
    
    
		System.out.println("Hello, i am Circle");
	}// 注意:Override不能重写父类的静态方法,这里不算重写!
}

class Triangle extends Shape {
    
    
	void darw() {
    
    
		System.out.println("Triangle is darwed!");
	}
	
	static void Say() {
    
    
		System.out.println("Hello, i am Triangle!");
	}
}

class Line extends Shape {
    
    
	void darw() {
    
    
		System.out.println("Line is darwed!");
	}
	
	static void Say() {
    
    
		System.out.println("Hello, i am Line!");
	}
}

Look at the running effect:
Insert picture description here

Analysis and summary of sample Demo:

The first point: First, let's look at the Darw method:

static void GetDarw(Shape s) {
    
    
		s.darw();
	}

The variable passed in this method is of the Shape type, but because the up-tracing modeling is allowed, we can pass in the object of its type (that is, the Shape type) when passing the parameter, or pass the subclass of the Shape type Objects (that is, the Circle, Triangle, and Line objects of this Demo), and in these objects, we have rewritten the methods of the parent class Shape, so it is impossible to determine whose method is called at compile time, and how to implement it , These are not known, so it is a virtual method at this time! Then at runtime, we will clarify who the parameter refers to, and then we will be specific to the instance and call the method belonging to the specific instance! So at runtime, we will be specific to the incoming instance objects to call, that is, they override the method implementation of the parent class!

The second point: Let's take a look at the GetSay method:

static void GetSay(Shape s) {
    
    
		Shape.Say();
		// 写成 s.Say();会报警告!
	}

This method we traced back to the Say method of the parent class:

static void Say() {
    
    
		System.out.println("Hello, i am Shape!");
	}

This is a method that does not support dynamic binding (static, private, and final methods are not allowed to be dynamically bound, because they can't be overridden! There is no need for dynamic binding, but an error will occur if it is bound! Be careful !!!)
For this kind of method that does not support dynamic binding, it will only belong to the declared class. We declare the Shape class, so this static method will call the Shape method! That is to say: For methods that cannot be dynamically bound, we only care about the declaration. What kind of declaration is immediately what kind of class, and will not be dynamically bound!

Final summary:

Insert picture description here

Two, inner class & anonymous class

2.1, internal class

What is an inner class?
The internal class is to put the definition of a class in another class. This internal class and other methods of the external class are at the same level, but the compiler will still generate related class files, named: external class name $ internal class name The format of .class Use of
internal classes?
Insert picture description here
The most special thing about inner classes is that they are used in other places. The first is instantiation: the
format is: 外部类名.内部类名 in(对象名) = 外部对象.new 内部类名(构造函数的参数列表);
and then the use: the used is actually quite normal, and there is no need to name the outer class.

2.2. Examples of internal classes:


public class InnerClass {
    
    
	public static void main(String[] args) {
    
    
		Parcel p = new Parcel();
		
		p.getInfo();
		
		Parcel.Content c = p.new Content(20);
		Parcel.Destination d = p.new Destination("QingHai");
		p.getInfo(c, d);
		
		System.out.println(c.Val() + " " + d.getDes());
	}
	
}


class Parcel {
    
    
	
	public Parcel() {
    
    
		
	}
	
	public void getInfo() {
    
    
		Content cc = new Content(10);
		Destination dd = new Destination("Hunan");
		System.out.println("包裹送到 " + dd.getDes() + " ,里面装的内容是: " + cc.Val());
	}
	
	public void getInfo(Content c, Destination d) {
    
    
		System.out.println("包裹送到 " + d.getDes() + " ,里面装的内容是: " + c.Val());
	}
	
	protected class Content {
    
    
		private int c;
		public Content(int c){
    
    
			this.c = c;
		}
		public int Val() {
    
    
			return this.c;
		}
	}
	
	protected class Destination {
    
    
		private String des;
		public Destination(String des) {
    
    
			this.des = des;
		}
		public String getDes() {
    
    
			return this.des;
		}
	}
	
}

The result of the operation is:
Insert picture description here

Example interpretation:

I believe this example is quite clear!
Insert picture description here
When the inner class is defined, written, and used in the class, there is no big difference from other ordinary classes. The only difference is that it can add modifiers. Only public, protected, private, abstract, and final can be added, because inner classes are also classes. The members of, so there is no big difference from the method!

Note: You cannot use static to decorate inner classes, because this is not an inner class, it is at the class level, not the object level!

Insert picture description here
Why is the second point like this?
Because the inner class is a member of the instance of the outer class, when calling the field or method of the outer class with the same name, you need to use the outer class name.this, this function is to tell the system that we are calling the method of the outer class! The reason is that the method (general method) of the external class is at the object level. We first pull to the related object (that is, the this pointer), and then use the object instance to access it!

How to understand the instantiation of inner classes?
Because the system does not generate internal classes, we have also seen that it will only generate bytecode files of external class name $ internal class name.class! So when we want to declare the internal class instance, we must get it through the external class, and then instantiate it, because the internal class is generated by the instance object of the external class, so we need the instance object to be new, which is the external class instance. new ( This is just a personal guess, easy to remember, whether it is correct, welcome to discuss!)

2.2, anonymous class

Anonymous class is a special internal class. It has no name and is a one-time-use thing. It is often used in the actual situation of function parameters to implement interfaces!
An anonymous class generates an object instance at the same time it is defined, ready to use!
Regarding the use of
Insert picture description here
anonymous classes : anonymous classes have no names, so there is no construction method! Then the commonly used format is:

new 接口名(参数){
    
    实现、Overwrite父类/接口方法}

Often used as a method parameter!

Guess you like

Origin blog.csdn.net/qq_44274276/article/details/105396301