Java object oriented polymorphism

1. Interface

When all methods in a class are abstract methods, we can define them as interfaces.

An interface is also a reference data type, which is more abstract than an abstract class.

There are two important meanings of the interface:

  1. Definition of rules
  2. Program scalability

Interface definition format: public interface interface interface name {}

There is an implementation relationship between interfaces and classes: public class class name implements interface name {}

Interfaces and classes can be implemented alone or in multiple ways: public class class name implements interface name 1, interface name 2 {}

The subclass (implementation class) of the interface either rewrites all abstract methods in the interface or turns itself into an abstract class.

Interface cannot be instantiated.

package com.qdu.test1;

public interface Inter {
    public abstract void study();
}
package com.qdu.test1;

public interface InterA {
    public abstract void print1();
    public abstract void print2();
    public abstract void study();
}
package com.qdu.test1;

public class InterImpl implements Inter, InterA {
    @Override
    public void study() {
        System.out.println("I'm in the implementation class study method");
    }

    @Override
    public void print1() {

    }

    @Override
    public void print2() {

    }
}
package com.qdu.test1;

public class Test1Interface {
    public static void main(String[] args) {
        // Inter i = new Inter();
        InterImpl ii = new InterImpl();
        ii.study();
    }
}

1.1 access characteristics of members in the interface

Member variables in the interface can only be constants. The default modifier is public static final.

Interface has no constructor.

Member methods in an interface can only be abstract methods (JDK7 and before). The default modifier is public abstract.

package com.qdu.test2;

public interface Inter {
    public static final int NUM = 10;

    // public Inter(){}

    public abstract void show();
}
package com.qdu.test2;

public class TestInterface {
    public static void main(String[] args) {
        System.out.println(Inter.NUM);
    }
}

class InterImpl extends Object implements Inter {
    public InterImpl() {
        super();
    }

    public void method() {
        // NUM = 20;
        System.out.println(NUM);
    }

	@Override
    public void show(){

    }
}

1.2 default method

After JDK8, Java only improves the member methods of the interface.

After JDK8, non abstract methods can be defined in the interface, but they need to be modified with the keyword default. These methods are the default methods.

Function: solve the problem of interface upgrade.

Definition format of default method in interface: public default return value type method name (parameter list) {}

Precautions for default methods in the interface:

  • The default method is not an abstract method, so it is not forced to be overridden. But it can be rewritten. When rewriting, remove the default keyword.
  • public can be omitted, but default cannot be omitted.
  • If multiple interfaces are implemented and the same method declaration exists in multiple interfaces, the subclass must override the method.
package com.qdu.test3;

public interface InterA {
    public default void show() {
        System.out.println("I am A In the interface show method");
    }
}
package com.qdu.test3;

public interface InterB {
    public default void show() {
        System.out.println("I am B In the interface show method");
    }
}
package com.qdu.test3;

public class TestInterface {
    public static void main(String[] args) {
        InterAImpl ia = new InterAImpl();
        ia.show(); // I am the show method of the implementation class
    }
}

class InterAImpl implements InterA, InterB {
    @Override
    public void show() {
    	System.out.println("I'm an implementation class show method");
    }
}

1.3 static method

After JDK8, static methods can be defined in the interface.

Definition format of static method in interface: public static return value type method name (parameter list) {}

Precautions for static methods in the interface:

  • Static methods can only be called through the interface name, not through the implementation class name or object name.
  • public can be omitted, but static cannot be omitted.
package com.qdu.test4;

public interface InterA {
    public static void show() {
        System.out.println("InterA...show");
    }
}
package com.qdu.test4;

public interface InterB {
    public static void show() {
        System.out.println("InterB...show");
    }
}
package com.qdu.test4;

public class TestInterface {
    public static void main(String[] args) {
        // InterAImpl ia = new InterAImpl();
        // ia.show();
		
		// InterAImpl.show();

        InterA.show(); // InterA...show

        InterB.show(); // InterB...show
    }
}

class InterAImpl implements InterA , InterB {

}

1.4 private method

Definition format of private method in JDK9 interface:

  • private return value type method name (parameter list) {}

  • private static return value type method name (parameter list) {}

package com.qdu.test5;

public interface Inter {
    public default void start() {
        System.out.println("start Method is executed...");
        log();
    }

    public default void end() {
        System.out.println("end Method is executed...");
        log();
    }

    private void log() {
        System.out.println("Logging ( simulation )");
    }

    private static void check() {
        System.out.println("Permission verification ( simulation )");
    }

    public static void open() {
        check();
        System.out.println("open Method is executed");
    }

    public static void close() {
        check();
        System.out.println("close Method is executed");
    }
}
package com.qdu.test5;

public class TestInterface {
    public static void main(String[] args) {
        InterImpl ii = new InterImpl();
        ii.start();
        ii.end();

        Inter.open();
        Inter.close();
    }
}

class InterImpl implements Inter {

}

1.5 summary

If you find that all the methods in a class are abstract methods, you can improve the class into an interface.

When it comes to updating methods in a large area of the interface, instead of modifying each implementation class, you can define the updated method as the default method with method body.

If you want to make the default method calls more concise, you can consider designing static static methods. (the default keyword needs to be removed)

Duplicate code appears in the default method. Consider extracting a private method. (the default keyword needs to be removed)

(1) Class and class relationship: inheritance relationship. You can only inherit single, but you can inherit multiple layers.

(2) Relationship between class and interface: the implementation relationship can be implemented alone or multiple, and multiple interfaces can be implemented while inheriting a class.

If the same method declaration appears in the direct parent class and the interface, but the code logic is different, the code logic of the direct parent class is preferred.

package com.qdu.test6;

public class Fu {
    public void show() {
        System.out.println("Fu...show");
    }
}
package com.qdu.test6;

public interface Inter {
    public default void show() {
        System.out.println("Inter....show");
    }
}
package com.qdu.test6;

public class TestInterface {
    public static void main(String[] args) {
        InterImpl ii = new InterImpl();
        ii.show(); // Fu...show
    }
}

class InterImpl extends Fu implements Inter {

}

(3) Interface and interface relationship: inheritance relationship, single inheritance or multiple inheritance.

package com.qdu.test7;

public interface InterA {
    public abstract void showA();

    public default void method() {
        System.out.println("InterA...method method");
    }
}
package com.qdu.test7;

public interface InterB {
    public abstract void showB();

    public default void method() {
        System.out.println("InterB...method method");
    }
}
package com.qdu.test7;

public interface InterC extends InterA, InterB {
    @Override
    public default void method() {
        System.out.println("InterC Interface to solve code logic conflict, rewrite method method");
    }
}
package com.qdu.test7;

public class InterImpl implements InterC {
    @Override
    public void showA() {

    }

    @Override
    public void showB() {

    }
}
package com.qdu.test7;

public class TestInterface {
    public static void main(String[] args) {
        InterImpl ii = new InterImpl();
        ii.method(); // The InterC interface solves the problem of code logic conflict and rewrites the method method
    }
}

2. Polymorphism

The same object shows different forms at different times.

We can say that a cat is a cat: cat = new cat ();

We can also say that cats are animals: animal = new cat ();

Here, cats show different forms at different times, which is polymorphism.

The premise and embodiment of polymorphism

  1. Inheritance / implementation relationship
  2. There is a way to rewrite
  3. A parent class reference points to a child class object
package com.qdu.test1;

public class Test1Polymorphic {
    public static void main(String[] args) {
        Cat c = new Cat();
        Animal a = new Cat();
        a.eat(); // Cats eat fish
    }
}

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

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("Cats eat fish");
    }
}

2.1 access characteristics of members in polymorphism

Constructor: like inheritance, subclasses will access the constructor of the parent class through super.

Member variable: compile to the left (parent class), execute to the left (parent class).

Member method: see the left (parent class) for compilation and the right (child class) for execution.

Why are member variables and member methods accessed differently?

Because member methods have overrides and member variables do not.

package com.qdu.test2;

public class Test2Polymorpic {
    public static void main(String[] args) {
        Fu f = new Zi();
        System.out.println(f.num); // 10
        f.method(); // Zi.. method
    }
}

class Fu {
    int num = 10;

    public void method() {
        System.out.println("Fu.. method");
    }
}

class Zi extends Fu {
    int num = 20;

    public void method() {
        System.out.println("Zi.. method");
    }
}

2.2 benefits and disadvantages of polymorphism

The advantage of polymorphism: it improves the scalability of the program. When defining a method, the method can receive any subclass object of the parent class by using the parent type as a parameter.

The disadvantage of polymorphism: you can't use the unique functions of subclasses. At this point, you can either create subclass objects directly or transform down.

package com.qdu.test3;

public class Test3Polymorpic {
    public static void main(String[] args) {
        useAnimal(new Dog()); // Animal a = new Dog(); //  Dogs eat meat
        useAnimal(new Cat()); // Animal a = new Cat(); //  Cats eat fish
    }
    
    public static void useAnimal(Animal a) {
        a.eat();
        //a.watchHome();
    }
}

abstract class Animal {
    public abstract void eat();
}

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

    public void watchHome() {
        System.out.println("Housekeeping");
    }
}

class Cat extends Animal {
    public void eat() {
        System.out.println("Cats eat fish");
    }
}

2.3 transformation in polymorphism

Upward Transformation: from child to parent, that is, the parent class reference points to the child class object.

Downward Transformation: from parent to child, that is, the parent class reference is transformed into a child class object.

package com.qdu.test4;

public class Test4Polymorpic {
    public static void main(String[] args) {
        // 1. Upward Transformation: the parent class reference points to the child class object
        Fu f = new Zi();
        f.show(); // Zi..show...

        // 2. Downward Transformation: convert from parent type to child type
        Zi z = (Zi) f;
        z.method(); // I am a subclass specific method
    }
}

class Fu {
    public void show() {
        System.out.println("Fu..show...");
    }
}

class Zi extends Fu {
    @Override
    public void show() {
        System.out.println("Zi..show...");
    }

    public void method() {
        System.out.println("I am a subclass specific method method");
    }
}

If the actual type and the target type corresponding to the reference type variable to be converted are not the same type, ClassCastException will appear during conversion.

Solution: the variable name is instanceof type, judge whether the variable on the left of the keyword is the type on the right, and return the boolean type result.

package com.qdu.test3;

public class Test3Polymorpic {
    public static void main(String[] args) {
        useAnimal(new Dog());
        useAnimal(new Cat());
    }

    public static void useAnimal(Animal a) {
        a.eat();

        // Judge whether the type of a variable record is Dog
        if(a instanceof Dog) {
            Dog dog = (Dog) a;
            dog.watchHome();
        }
    }
}

abstract class Animal {
    public abstract void eat();
}

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

    public void watchHome(){
        System.out.println("Housekeeping");
    }
}

class Cat extends Animal {
    public void eat() {
        System.out.println("Cats eat fish");
    }
}

3. Internal class

Inner class: defines a class in a class. For example, if a class B is defined inside a Class A, class B is called an inner class.

Access characteristics of internal classes:

  • Internal classes can directly access members of external classes, including private classes.
  • An object must be created for an external class to access members of an internal class.

According to the different positions of the internal class defined in the class, it can be divided into the following two forms:

  • In the member position of the class: the inner class of the member
  • Local position in class: local inner class

3.1 member internal class

For the inner class of a member, how can an object be created and used by the outside world?

Format: external class name. Internal class name object name = new external class object (). New internal class object ();

package com.qdu.test1;

public class Test1Inner {
    public static void main(String[] args) {
        Outer.Inner i = new Outer().new Inner();
        System.out.println(i.num);
        i.show();
    }
}

class Outer {
    private int a = 10;

    class Inner {
        int num = 10;
        public void show() {
            System.out.println("Inner..show");
            // Internal classes can directly access members of external classes, including private classes
            System.out.println(a);
        }
    }
}

The inner class of a member also belongs to a member. Since it is a member, it can be modified by some modifiers.

(1) private

Private member internal class access: create object access in its own external class.

package com.qdu.test2;

public class Test2Innerclass {
    public static void main(String[] args) {
        // Outer.Inner oi = new Outer().new Inner();

        Outer o = new Outer();
        o.method();
    }
}

class Outer {
    private class Inner {
        public void show() {
            System.out.println("inner..show");
        }
    }

    public void method() {
        Inner i = new Inner();
        i.show();
    }
}

(2) static

Static member internal class access format: external class name. Internal class name object name = new external class name. Internal class name ();

Static methods in internal classes of static members: external class name. Internal class name. Method name ();

package com.qdu.test3;

public class Test3Innerclass {
    public static void main(String[] args) {
        Outer.Inner oi = new Outer.Inner();
        oi.show(); // inner..show
        Outer.Inner.method(); // inner..method
    }
}

class Outer {
    static class Inner {
        public void show() {
            System.out.println("inner..show");
        }

        public static void method() {
            System.out.println("inner..method");
        }
    }
}

3.2 local internal class

The local internal class is a class defined in the method, so it cannot be used directly by the outside world. You need to create an object inside the method and use it.

This class can directly access members of external classes or local variables in methods.

package com.qdu.test4;

public class Test4Innerclass {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.method();
    }
}

class Outer {
    int a = 10;

    public void method() {
        int b = 20;

        class Inner {
            public void show() {
                System.out.println("show...");
                System.out.println(a);
                System.out.println(b);
            }
        }

        Inner i = new Inner();
        i.show();
    }
}

3.3 anonymous inner class

Overview: anonymous inner class is essentially a special local inner class (defined inside a method).

Premise: an interface or class is required.

Understanding: anonymous inner classes are three steps: Inheritance / implementation, method rewriting and object creation in one step.

package com.qdu.test5;

public class Test5Innerclass {
    public static void main(String[] args) {
        InterImpl ii = new InterImpl();
        ii.show();
        
        new Inter() {
            @Override
            public void show() {
                System.out.println("Anonymous Inner Class ...show");
            }
        }.show();

        // There are multiple methods in the interface, which are polymorphic
        Inter2 i = new Inter2() {
            @Override
            public void show1() {
                System.out.println("show1...");
            }

            @Override
            public void show2() {
                System.out.println("show2...");
            }
        };

        i.show1();
        i.show2();
    }
}

interface Inter {
    void show();
}

interface Inter2 {
    void show1();
    void show2();
}

class InterImpl implements Inter {
    @Override
    public void show() {
        System.out.println("InterImpl...show");
    }
}

When the formal parameter of a method is an interface or an abstract class, the anonymous inner class can be passed as an actual parameter.

package com.qdu.test6;

public class TestSwimming {
    public static void main(String[] args) {
        goSwimming(new Swimming() {
            @Override
            public void swim() {
                System.out.println("Let's go swimming");
            }
        });
    }
    
    public static void goSwimming(Swimming swimming) {
        swimming.swim();
    }
}

interface Swimming {
    void swim();
}

4.Lambda expression

In mathematics, a function is a set of calculation scheme with input and output, that is, "take data for operation".

Object oriented thought emphasizes that "things must be done in the form of objects".

Functional thinking tries to ignore the complex object-oriented syntax "emphasizing what to do, not what form to do".

Lambda expression is the embodiment of the idea of functional expression.

Format of Lambda expression: (formal parameter) - > {code block}

  • Formal parameters: if there are multiple parameters, the parameters are separated by commas; If there is no parameter, leave it blank.
  • ->: it is composed of a line drawn in English and a greater than symbol. It is written in a fixed way and represents pointing action.
  • Code block: it is the specific thing we need to do, that is, the content of the method body we wrote before.

Premise of Lambda expression:

  • There is an interface
  • There is only one abstract method in the interface

(1) No parameter no return value

package com.qdu.test2;

public class TestLambda {
    public static void main(String[] args) {
        useShowHandler(new ShowHandler() {
            @Override
            public void show() {
                System.out.println("I'm in an anonymous inner class show method");
            }
        });

        // Lambda implementation
        useShowHandler( () -> {System.out.println("I am Lambda Medium show method");} );
    }

    public static void useShowHandler(ShowHandler showHandler){
        showHandler.show();
    }

}

interface ShowHandler {
    void show();
}

(2) No return value with parameter

package com.qdu.test3;

public class StringHandlerDemo {
    public static void main(String[] args) {
        useStringHandler(new StringHandler() {
            @Override
            public void printMessage(String msg) {
                System.out.println("I am an anonymous inner class" + msg);
            }
        });

        // Lambda implementation
        useStringHandler( (String msg) -> {System.out.println("I am Lambda expression" + msg);} );
    }

    public static void useStringHandler(StringHandler stringHandler) {
        stringHandler.printMessage("qdu");
    }
}

interface StringHandler {
    void printMessage(String msg);
}

(3) No parameter has return value

If the method in the interface operated by lambda has a return value, be sure to return the result through the return statement, otherwise a compilation error will occur.

package com.qdu.test4;

import java.util.Random;

public class RandomNumHandlerDemo {
    public static void main(String[] args) {
        useRandomNumHandler(new RandomNumHandler() {
            @Override
            public int getNumber() {
                Random r = new Random();
                int num = r.nextInt(10) + 1;
                return num;
            }
        });

        useRandomNumHandler( () -> {
                Random r = new Random();
                int num = r.nextInt(10) + 1;
                return num;
        } );
    }

    public static void useRandomNumHandler(RandomNumHandler randomNumHandler){
        int result = randomNumHandler.getNumber();
        System.out.println(result);
    }
}

interface RandomNumHandler {
    int getNumber();
}

(4) Return value with parameter

package com.qdu.test5;

public class CalculatorDemo {
    public static void main(String[] args) {
        useCalculator(new Calculator() {
            @Override
            public int calc(int a, int b) {
                return a + b;
            }
        });

        useCalculator( (int a, int b) -> {
             return a + b;
        });
    }

    public static void useCalculator(Calculator calculator) {
        int result = calculator.calc(10,20);
        System.out.println(result);
    }
}

interface Calculator {
    int calc(int a, int b);
}

(5) Ellipsis rule of lambda expression:

  • Parameter types can be omitted, but when there are multiple parameters, only one cannot be omitted.
  • If there is only one parameter, the parentheses can be omitted.
  • If the code block has only one statement, you can omit braces, semicolons, or even return.
package com.qdu.test6;

public class Test6 {
    public static void main(String[] args) {
        useInter((a, b) ->
                a + b
        );
    }

    public static void useInter(Inter i) {
        double result = i.method(12.3, 22.3);
        System.out.println(result);
    }
}

interface Inter {
    // Used to calculate the result of a + b and return
    double method(double a, double b);
}

5. Differences between lambda expressions and anonymous inner classes

(1) Different types required

Anonymous inner class: it can be an interface, an abstract class, or a concrete class.

Lambda expression: can only be an interface.

(2) Different use restrictions

If there is only one abstract method in the interface, you can use Lambda expressions or anonymous inner classes.

If there is more than one abstract method in the interface, only anonymous inner classes can be used, not Lambda expressions.

(3) Different implementation principles

Anonymous inner class: after compilation, a separate. Class bytecode file is generated.

Lambda expression: after compilation, there is no separate. class bytecode file, and the corresponding bytecode will be generated dynamically at run time.

Tags: Java JavaSE

Posted on Mon, 22 Nov 2021 13:01:02 -0500 by work_it_work