day12_ Interface and polymorphism

Interface Overview

Interface is a reference type in the Java language and a "collection" of methods. Therefore, the interior of the interface is mainly to define methods, including constants, abstract methods (JDK 7 and before), default methods and static methods (JDK 8), and private methods (jdk9). There can be no other members in the interface, no constructor and no initialization block, because there are no member variables to initialize in the interface. The definition of interface, which is similar to the way of defining classes, but uses the interface keyword. It will also be compiled into Class file, but it must be clear that it is not a class, but another reference data type. Interface, which cannot create objects, but can be implemented (similar to being inherited). A class that implements an interface (which can be regarded as a subclass of the interface) needs to implement all the abstract methods in the interface. After creating this class object, you can call the method, otherwise it must be an abstract class.

Declaration format of interface

An interface is a specification, which defines a set of rules, reflecting the real world "if you are / want to..., you must be able to..." My thoughts. Inheritance is a yes / no is-a relationship, while interface implementation is a yes / no has-a relationship.  

Code example

public interface IA {
    // Constants (jdk7 and before) are decorated with the public static final keyword, which can be omitted
    public static final int A = 18;
    int B = 20;

    // Abstract methods (jdk7 and before) are decorated with the public abstract keyword. Both keywords can be omitted
    public abstract void method1();

    void method2();

    // The default method (jdk8) is decorated with the keyword public default. Public can be omitted and default cannot be omitted
    public default void method3() {
        System.out.println("I am the default method 1");
    }

    default void method4() {
        System.out.println("I am the default method 2");
    }

    // The static method (jdk8) is decorated with the keyword public static. Public can be omitted and static cannot be omitted
    public static void method5() {
        System.out.println("I am static method 1");
    }

    static void method6() {
        System.out.println("I am static method 2");
    }

    // The private method (jdk9) is decorated with the private keyword. Private cannot be omitted
    private static void method7() {//Private static method
        System.out.println("Private static method  method5");
    }

    private void method8() {//Common private method
        System.out.println("Private non static method  method6");
    }

}

Implementation interface

Interface, which cannot create objects, but can be implemented (similar to being inherited). The relationship between class and interface is implementation relationship, that is, class implements interface. This class can be called implementation class of interface or subclass of interface. The actions implemented are similar to inheritance and the format is similar, but the keywords are different. The implementation uses the implements keyword. If a function is added by a class, you can define the additional function in the interface and implement it by this class

Implementation interface syntax format

be careful:

  • If the implementation class of the interface is a non abstract class, you must override all abstract methods in the interface.
  • The default method can be retained or overridden. When rewriting, do not write the word default. It is only used to represent the default method in the interface, and there is no concept of default method in the class
  • Static methods cannot be overridden

Code example

Define interface

public interface IA {
    //static const 
    long MAX_SPEED = 500*1024*1024;//500MB/s

    //Abstract method
    void read();
    void write();

    //Default method
    public default void start(){
        System.out.println("start");
    }
    public default void stop(){
        System.out.println("end");
    }

    //Static method
    public static void show(){
        System.out.println("USB 3.0 It can read and write at full speed synchronously");
    }
}

Define implementation classes

public class IAimp implements IA {
    //Rewrite / implement the abstract method of the interface, [required]
    @Override
    public void read() {
        System.out.println("Read data");
    }
    @Override
    public void write() {
        System.out.println("Write data");
    }

    //Override the default method of the interface, [optional]
    //When overriding the default method, the default word is removed
    @Override
    public void stop() {
        System.out.println("Clean up the hidden recycle bin in the hard disk, and then finish");
    }
}

Access characteristics of members in interface

Constants in the interface: mainly for direct use of the interface. We can access through interface name, implementation class object and implementation class. It is recommended to use interface name to access

interface A {
    public static final double PI = 3.1415926;
}

class Aimp implements A {
    //The constants in the interface are inherited by the implementation class
}

public class Test {
    public static void main(String[] args) {
        // It is recommended to access by interface name
        System.out.println(A.PI);
        System.out.println(Aimp.PI);
        System.out.println(new Aimp().PI);
    }
}

Why can it be accessed through the implementation class and implementation class object? Because the constants in the interface are modified by static and inherited by the implementation class.

Abstract method in interface: it is rewritten by implementation class and can only be called through implementation class object

interface A{
    void eat();
}

class Aimp implements A{

    @Override
    public void eat() {//Abstract methods in rewriting interfaces
        System.out.println("Eat something");
    }
}

public class Test {
    public static void main(String[] args) {
        //Create an implementation class object and call the rewritten abstract method
        new Aimp().eat();
    }
}

Default method in the interface: it is inherited by the implementation class. It can be called directly in the implementation class, and the implementation class object can also be called directly. If the implementation class is overridden, the overridden default method will be executed. If it is not overridden, the default method in the interface will be executed

interface A{
    default void eat(){
        System.out.println("Parents eat Wowotou");
    }
    default void sleep(){
        System.out.println("sleep");
    }
}

class Aimp implements A{

    @Override
    public void eat() {//Override the default method in the interface
        sleep();//Directly call the default method in the parent class
        System.out.println("Subclasses eat white rice");
    }
}

public class Test {
    public static void main(String[] args) {
        //Create an implementation class object and call the overridden default method
        new Aimp().eat();
    }
}

Static method in interface: it can only be called with "interface name". It cannot be called through the object implementing the class

interface A {
    static void sleep() {//Static method
        System.out.println("sleep");
    }
}

class Aimp implements A {

}

public class Test {
    public static void main(String[] args) {
        //Use "interface name" directly Just call
        A.sleep();
        // new Aimp().sleep(); Cannot be called through an object that implements a class
    }
}

Private methods in the interface: they can only be called directly in the interface and cannot be inherited by the implementation class. Because there are specific implementation methods such as default methods and static methods, multiple methods may be extracted by common code, and the methods extracted from these common code only want to be used inside the interface, so private methods are added.

Multiple implementation of interface

In the inheritance system, a class can inherit only one parent class. For interfaces, a class can implement multiple interfaces, which is called multiple implementation of interfaces. Moreover, a class can inherit a parent class and implement multiple interfaces at the same time.

What if multiple parent interfaces have the same constants or methods in conflict during multiple implementations?

Conflict of public static constants: if multiple parent interfaces have the same constants, the implementation class cannot inherit. In short: you cannot call the same constant through an implementation class or an implementation class object because the reference is ambiguous.

interface A {
    public static final int NUM1 = 10;
}

interface B {
    public static final int NUM1 = 20;
    public static final int NUM2 = 30;
}

class ABimp implements A, B {

}

public class Test {
    public static void main(String[] args) {
        System.out.println(A.NUM1); //10
        System.out.println(B.NUM1);//20
        System.out.println(B.NUM2);//30
        //System.out.println(ABimp.NUM1); error
        System.out.println(ABimp.NUM2);//30
    }
}

In general, constants in the parent interface will be inherited by subclasses unless there is a constant conflict problem.

Conflict of public abstract methods: when there are multiple abstract methods in the interface, the implementation class must override all abstract methods. If the abstract method in multiple parent interfaces has the same name, it only needs to be rewritten once.

interface A{
    public abstract void method();
}
interface B{
    public abstract void method();
}
class Imp implements A,B{
    @Override
    public void method() {
        System.out.println("Implement class overrides");
    }
}
public class Test {
    public static void main(String[] args) {
        /*
            Conflict of public abstract methods: the implementation class only needs to rewrite one 
         */
    }
}

Conflict of public default methods: when a class implements multiple interfaces at the same time and multiple interfaces contain default methods with the same method signature, the implementation class must rewrite the final version once

interface A{
    public default void method(){
        System.out.println("A Default method of interface method");
    }
}
interface B{
    public default void method(){
        System.out.println("B Default method of interface method");
    }
}
class Imp implements A,B{
    @Override
    public void method() {
        System.out.println("Default method to implement class overrides");
    }
}
public class Test {
    public static void main(String[] args) {
        /*
            Conflict of public default methods: the implementation class must rewrite the final version once 
         */
        Imp imp = new Imp();
        imp.method();
    }
}

Conflict of public static methods: static methods directly belong to the interface and cannot be inherited, so there is no conflict

Conflict of private methods: private methods can only be used directly in this interface without conflict

Interface and interface relationship

Relationship between interfaces: interfaces can be "inherited" from another "interface", and can be "multi inherited".

interface A {
}

interface B {
}

interface C1 extends A {
}   // Single inheritance

interface C2 extends A, B {
} // Multiple inheritance

interface C3 extends C2 {
}  // Multilayer inheritance

public class Test {
    public static void main(String[] args) {
        /*
            - Relationship between interfaces: inheritance relationship
                    Single inheritance: interface A inherits interface B
                    Multiple inheritance: interface A inherits interface B, interface C
                    Multi layer inheritance: interface A inherits interface B, interface B, and interface C      
         */
    }
}

When an interface inherits an interface, what happens if there are multiple parent interfaces with the same constants or methods in conflict?

  • Conflict of public static constants: the child interface cannot inherit the conflicting constants in the parent interface
  • Conflict of public abstract methods: the sub interface will inherit only one conflicting abstract method
  • Conflict of public default methods: the conflicting default methods must be rewritten once in the sub interface. The implementation class rewrites the default methods in the interface without adding default. If the sub interface rewrites the default methods in the parent interface, it must add default.
  • Public static methods and private methods: no conflict, because static methods directly belong to the interface and can only be accessed directly using this interface, while private methods can only be accessed in the interface without conflict

When the implementation class inherits the parent class and implements the interface, what if there is a conflict between the same constant or method in the parent interface and the parent class?

  • Conflict between public static constants of parent class and interface: subclasses cannot inherit conflicting constants
class Fu{
    public static final int NUM1 = 10;
    public static final int NUM2 = 100;
}
interface A{
    public static final int NUM1 = 20;

}
class Zi extends Fu implements A{

}
public class Test {
    public static void main(String[] args) {
        /*
            Conflict of public static constants: subclasses cannot inherit conflicting constants
         */
        //System.out.println(Zi.NUM1);//  Compilation error
        System.out.println(Zi.NUM2);

    }
}
  • Abstract method conflict between parent class and interface: subclass must override the conflicting abstract method once
abstract class Fu{
    public abstract void method();
}
interface A{
    public abstract void method();
}
class Zi extends Fu implements A{
    @Override
    public void method() {
        System.out.println("Zi Override conflicting abstract methods");
    }
}
public class Test {
    public static void main(String[] args) {
        /*
            Conflict of public abstract methods: subclasses must override conflicting abstract methods once
         */
        Zi zi = new Zi();
        zi.method();
    }
}
  • Conflict between the public default methods of the parent class and the interface: the member method in the parent class has the same name as the default method in the interface, and the child class selects the member method of the parent class nearby.
  • Public static methods of parent class and interface: subclasses can only access the static methods of the parent class
  • Private methods of parent class and interface: subclasses cannot be accessed, and there is no conflict

Application scenario:

  • Additional functions: defined in the interface and implemented by the implementation class. If a function is added by a class, the additional function can be defined in the interface and implemented by this class
  • Common functions: define in the parent class and let the subclasses inherit. If a method in a parent class has different implementations for all subclasses, the method should be defined as an abstract method, so the parent class is an abstract class (the parent class is generally an abstract class)

polymorphic

Polymorphism is the third feature of object-oriented after encapsulation and inheritance. In life, such as the function of seeking area, the realization of circle, rectangle and triangle is different. The action of running is different for kittens, dogs and elephants. Another example is the action of flying, insects, birds and aircraft are also different. It can be seen that the same behavior can reflect different forms through different things. Then the types of each seed class will appear.

definition

  • Polymorphism: refers to the same behavior, which has multiple different manifestations for different objects.
  • Polymorphism in program: it refers to that the same method has different implementations for different objects

Origin of polymorphism:

Java is a strongly typed static language, that is, each variable must declare its exact type before use, and then the subsequent assignment and operation are handled in strict accordance with this data type. For example:

int num = 10;

However, sometimes, when designing an array, or the formal parameter and return value type of a method, we cannot determine its specific type, but can only determine that it is the type of a series. For example, if you want to design an array to store the objects of various graphics and sort them according to the area of various graphics, but the specific stored objects may be circles, rectangles, triangles, etc., then the area calculation methods of various graphics are different. For example, if you want to design a method, its function is to compare the area of two graphics and return the graphic object with larger area. At this time, the formal parameter and return value types are graphic types, but we don't know which graphic type it is. At this time, Java introduced polymorphism.

At the same time, the application of polymorphism in the program can be realized by meeting the following conditions

  • Inherit or implement [one of two]
  • The parent class reference points to the child class object or the interface reference points to the implementation class object [format embodiment]
  • Rewriting of methods [meaning embodiment: no rewriting, meaningless]

Code example

abstract class Animal {//Parent class
    public abstract void eat();
}
//Subclass
class Dog extends Animal{

    @Override
    public void eat() {//Method rewriting
        System.out.println("Dogs eat bones");
    }
}
//Subclass
class Cat extends Animal{
    @Override
    public void eat() {//Method rewriting
        System.out.println("Cats eat fish");
    }
}
public class Test {
    public static void main(String[] args) {
        //A parent class reference points to a child class object
        Animal dog = new Dog();
        dog.eat(); //Dogs eat bones
        //A parent class reference points to a child class object
        Animal cat = new Cat();
        cat.eat();//Cats eat fish
    }
}

Characteristics of accessing members in polymorphism

If you directly access member variables, you can only look at the compile time type, that is, look at the left when compiling and look at the left when running. In short: in the case of polymorphism, the member variables of the parent class are accessed. If there is no member variable to be accessed in the parent class, an error will be reported

class Animal {
    int age = 18;
}

class Dog extends Animal {
    int age = 20;
    String name = "Golden hair";
}

public class Test {
    public static void main(String[] args) {
        Animal dog = new Dog();
        System.out.println(dog.age);//18
        //System.out.println(dog.name);  Compilation error
    }
}

Access characteristics of member methods in polymorphism

In Java, virtual method refers to the method whose calling entry address can not be determined in the compilation stage and class loading stage, but can only be determined in the running stage, that is, the method that may be rewritten. When we call a virtual method in the form of "object. Method", how do we determine which method it executes?

  • Static dispatch: first look at the compile time type of the object. Find the most matching method in the compile time type of the object. The most matching means that the compile time type of the argument matches the type of the formal parameter best. If not found, the compilation fails
  • Dynamic binding: look at the runtime type of this object. If the runtime class of this object overrides the most matching method just found, the overridden method will be executed. Otherwise, the method in the compile time type just now will still be executed

In short: when compiling, look for methods in the parent class, and when running, look for methods in the child class to execute

class Animal {
   public void eat(){
       System.out.println("Eat something");
   }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("Dogs eat bones");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal dog = new Dog();
        dog.eat();//Dogs eat bones
    }
}

The following methods are implemented by finding methods in the parent class when compiling and by finding methods in the parent class when running.

  • static method, which determines at compile time that it will not change at run time.
  • Methods called by invokespecial instruction, including private methods, instance construction methods and parent class methods. These methods are also determined at compile time and will not be changed at run time
  • A method modified by the final keyword. Although the final method is called by the invokevirtual instruction, the final modified method cannot be overridden in the subclass, so the final modified method cannot be changed dynamically at run time.

Several forms of polymorphism

Common parent polymorphism:

class Fu{}
class Zi extends Fu{}
public class Demo{
    public static void main(String[] args){
        Fu f = new Zi();//On the left is a "normal parent class"
    }
}

Abstract parent polymorphism

abstract class Fu{}
class Zi extends Fu{}
public class Demo{
    public static void main(String[] args){
        Fu f = new Zi();//The parent class on the left is an abstract class
    }
}

Parent interface polymorphism

interface A{}
class AImp implements A{}
public class Demo{
    public static void main(String[] args){
        A a = new AImp();//On the left is a parent interface
    }
}

Several application scenarios of polymorphism:

Scenario 1: the variable is polymorphic. If the type of the variable is the parent type, the variable can receive the object of the parent type or all its subclass objects

class Animal{
    public void eat(){
        System.out.println("Eat something...");
    }
}

class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("Cats eat fish");
    }
}
public class Test {
    public static void main(String[] args) {
        // Variable polymorphism: variables of the parent type point to objects of the child type
        // If the type of a variable is a parent type, the variable can receive objects of the parent type or all its subclass objects
        anl = new Cat();
        anl.eat();
    }
}

Scenario 2: the formal parameters are polymorphic, the parent type is used as the formal parameter of the method, and the subclass object is the argument.

class Animal {
    public void eat() {
        System.out.println("Eat something");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("Dogs eat bones");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal dog = new Dog();
        //When assigning an argument to a formal parameter = = > animal anl = new dog();
        method(dog);
    }

    //Define a method with a parameter that can receive Animal class objects and all subclass objects of Animal class
    public static void method(Animal animal) {
        animal.eat();//Dogs eat bones
    }
}

Scenario 3: the return value is polymorphic. If the return value type is the parent type, you can return the object of the parent type or all its subclass objects

//Parent class
abstract class Animal {
    abstract void eat();
}
//Subclass Dog
class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("Dogs eat bones");
    }
}
//Subclass Cat
class Cat extends Animal{
    @Override
    void eat() {
        System.out.println("Cats eat fish");
    }
}
public class Test {
    public static void main(String[] args) {
        buy("Kitty").eat();//Cats eat fish

    }
    /*
     * Design a method that can buy the objects of various animals. At this time, it is not sure what kind of specific animals it is
     *
     * The return value type is the object of the parent class
     *
     * Polymorphism is reflected in the return value type Animal. The actual returned object is new Cat() or new Dog() of the subclass
     */
    public static Animal buy(String name){
        if("Kitty".equals(name)){
            return new Cat();
        }else if("puppy".equals(name)){
            return new Dog();
        }
        return null;
    }
}

Scenario 4: polymorphism is applied to arrays. Array element types are declared as parent types, which can actually store their parent and child objects

	    /*
		 * Declare an array that can hold objects of various animals,
		 */
		Animal[] arr = new Animal[2]; //At this time, it is not the object of new Animal, but the array object of new Animal []
									//An array space of length 2 is opened up in the heap to hold the address of Animal or its subclass objects
		arr[0] = new Cat();//On the left arr[0] of the polymorphic reference is the Animal type, and on the right is the new Cat()
							//Assign a Cat object to a variable of type Animal
		arr[1] = new Dog();

Advantages and disadvantages of polymorphism

In the actual development process, the parent type is used as the formal parameter of the method, passing the subclass object to the method and calling the method, which can better reflect the expansibility and convenience of polymorphism. However, after using the parent variable to receive the subclass object, we can't call the methods owned by the subclass but not by the parent. This is also a little "trouble" brought by polymorphism. Disadvantages: in the case of polymorphism, you can only call the common content of the parent class, not the unique content of the child class. Therefore, if you want to call subclass specific methods, you must do type conversion. Whether the transformation is upward or downward, it must meet the parent-child relationship or implementation relationship

Upward Transformation: when the type (parent class) of the variable on the left > the type (subclass) of the object / variable on the right, we call it upward transformation

  • At this time, when compiling, you can only call the variables and methods in the parent class according to the type of variables on the left, and you can't call the variables and methods unique to the child class
  • However, at runtime, it is still the type of the object itself. At this time, it must be safe and automatic

Downward Transformation: when the type (subclass) of the variable on the left < the type (parent) of the object / variable on the right, we call it downward transformation

  • Format: subclass type object name = (subclass type) variable of parent type;
  • At this time, the variables and methods unique to the subclass can be called when the compilation is processed according to the type of the variables on the left
  • However, at runtime, it is still the type of the object itself. At this time, it is not necessarily safe. You need to use (type) to force type conversion. This process is manual.
  • Not all downward transformations through compilation are correct, and classcastexceptions may occur. For safety, you can judge through the isInstanceof keyword

Code example

//Parent class
abstract class Animal {
    abstract void eat();
}
//Subclass Dog
class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("Dogs eat bones");
    }
    public void lookHome(){
        System.out.println("Dog watch");
    }
}
//Subclass Cat
class Cat extends Animal{
    @Override
    void eat() {
        System.out.println("Cats eat fish");
    }
    public void grabMouse(){
        System.out.println("Cat catches mouse");
    }
}
public class Test {
    public static void main(String[] args) {
        method(new Cat());//The Dog object is passed in
    }
    public static void method(Animal animal){
        Dog dog = (Dog) animal;//This code can be compiled, but ClassCastException is reported at runtime
        //This is because the Cat type object is clearly created. Of course, it cannot be converted into a Dog object at run time. These two types do not have any inheritance relationship,
    }
}

The results after running are shown in the following figure:

In order to avoid the occurrence of ClassCastException, Java provides the instanceof keyword to verify the type of reference variables. As long as instanceof is used to judge whether it returns true, it must be safe to forcibly convert to this type and ClassCastException exception will not be reported.

effect:

  • Judge whether the object type pointed to by the previous variable is the following data type:
  • If the object type pointed to by the preceding variable belongs to the following data type, it returns true
  • If the object type pointed to by the preceding variable does not belong to the following data type, false is returned

Therefore, we'd better make a judgment before conversion. The code is as follows:

public static void method(Animal animal) {
        if (animal instanceof Cat) {
            // Downward transformation
            Cat cat = (Cat) animal;
            cat.eat();//Cats eat fish
            // Cat's unique grabMouse method is called
            cat.grabMouse();//Cat catches mouse
        } else if (animal instanceof Dog) {
            Dog dog = (Dog) animal;
            dog.eat();//Dogs eat bones
            // Dog's unique lookHome method is called
            dog.lookHome();//Dog watch
        }
    }

To summarize the disadvantages of polymorphism: you can't access the unique methods or member variables of subclasses, because the characteristic of polymorphic member access is to compile and see the parent class. Solution type conversion.

Keywords: Java Back-end

Added by vocoder on Sun, 27 Feb 2022 07:21:24 +0200