[JavaSE series] Java object-oriented composition polymorphism and interface

Keywords: Java interface Polymorphism JavaSE abstract class

⭐ ♪ previous words ⭐ ️

This article introduces you to the basic knowledge of Java - composition, polymorphism and interface, friends, long time no see, question A left to readers in the previous blog post package and inheritance. This article will introduce polymorphism and interfaces in detail. The inheritance introduced last time is the basis for reading this article. Let's review inheritance first. Inheritance is equivalent to multiple drawing instances of an object. We might as well divide drawings into two categories. One category has commonalities, and the other category has characteristics. Drawings (classes) with commonalities are called parent classes (base classes, superclasses) and drawings with characteristics (class) is called A subclass. The relationship between the two is that the subclass inherits the parent class. Then, start the body!

📒 Blog home page: Blog home page without flower smell
🎉 Welcome to pay attention 🔎 give the thumbs-up 👍 Collection ⭐ Leave a message 📝
📌 This article is original by Huawen, CSDN first!
📆 Starting time: 🌴 November 23, 2021 🌴
✉️ Persistence and hard work will surely bring poetry and distance!
💭 Reference books: 📚 Java core technology, 📚 Java programming ideas, 📚 <Effective Java>
💬 Refer to the online programming website: 🌐 Niuke network🌐Force buckle
The blogger's code cloud gitee, usually the program code written by the blogger is in it.
The github of the blogger is usually the program code written by the blogger.
🙏 The author's level is very limited. If you find an error, you must inform the author in time! Thank you!

1. Combination

In the inheritance relationship, the relationship between the subclass (derived class) and the parent class (base class, superclass) is an is - a relationship. For example, if a bird (subclass) inherits an animal (parent class), it can be said that a bird is an animal.
For the combination, we use one or more classes in a new class. For example, we want to create a school class. We all know that the school has teachers and students, and there must be more than one in general. Therefore, the school class will use the student class and the teacher class, that is, the combination is the relationship of hava, that is, there are teachers and students in the school.

class Student {
    public String name;
    public double score;
    public int age;
    public int classNo;

}
class Teacher {
    public String name;
    public int age;
    public int classNo;
    public String subject;

}

public class School {
    public Student[] stu;
    public Teacher[] tec;
}

2. Polymorphism

2.1 upward transformation

The premise of upward transformation is that there is an inheritance relationship between classes. Using parent class references to point to child class objects is called upward transformation.

For example, the Bird class inherits the animal class, and then uses the parent class animal reference to point to the child class Bird object. In Java, the parent class reference is allowed to point to the child class object. In the process of upward transformation, but note that after upward transformation, the parent class reference can only access the member variables and methods of the parent class (if the child class does not override the parent class method) , for chestnuts, Animal animal = new Bird("Bird", 2); this animal reference can only access the eat method, not the fly method of the subclass Bird.

class Animal {
    public String name;
    public int age;
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "I am eating!");
    }
}
class Bird extends Animal{

    public Bird(String name, int age) {
        super(name, age);
    }
    public void fly() {
        System.out.println(this.name + "Flying!");
    }
}

public class UpClass {
    public static void main(String[] args) {
        Animal animal = new Bird("Bird", 2);
        animal.eat();
    }
}


⭐ There are three common cases of upward Transformation:

  1. Pass the address of the child class object to the parent class reference.
  2. Pass the address of the subclass object as a parameter to the formal parameter of the parent type.
  3. In the method whose return value is the parent class reference type, the address of the child class object is taken as the return value.
class Animal {
    public String name;
    public int age;
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "I am eating!");
    }
}
class Bird extends Animal{

    public Bird(String name, int age) {
        super(name, age);
    }
    public void fly() {
        System.out.println(this.name + "Flying!");
    }
}

public class UpClass {
    public static void func1(Animal an) {
        an.eat();
    }
    public static Animal func2() {
        return new Bird("Bird", 2);
    }
    public static void main(String[] args) {
        Animal animal1 = new Bird("Bird", 2);
        animal1.eat();
        func1(new Bird("Bird", 2));
        Animal animal2 = func2();
        animal2.eat();
    }
}

2.2 runtime binding

2.2.1 concept

Runtime binding, also known as dynamic binding, is a behavior that occurs when a program is running. Runtime binding is based on upward transformation. The so-called runtime binding is to call the override (override / overwrite) of the same name of the parent and child classes through the parent class reference Method. Why is it called runtime binding? Because when the program runs, the rewrite of the method takes place. Let's look at a compiled disassembler containing rewritten code, which will find that what is compiled is called the parent class.

class Animal {
    public String name;
    public int age;
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "I am eating!");
    }
}
class Bird extends Animal{

    public Bird(String name, int age) {
        super(name, age);
    }
    public void fly() {
        System.out.println(this.name + "Flying!");
    }

    @Override
    public void eat() {
        System.out.println(this.age + this.name + "Eating slowly!");
    }
}
class Cat extends Animal{
    public Cat(String name, int age) {
        super(name, age);
    }
    public void cute() {
        System.out.println(name + "Busy, cute!");
    }

    @Override
    public void eat() {
        System.out.println(this.age + this.name + "Eating quietly!");
    }
}
public class OverFunc {
    public static void main(String[] args) {
        Animal animal1 = new Bird("Bird", 2);
        animal1.eat();
        Animal animal2 = new Cat("kitten", 1);
        animal2.eat();
    }
}

2.2.2 rewrite method

Rewriting is also called overwriting, overwriting. As the name suggests, a method is used to overwrite / overwrite / rewrite a method, but not any two methods can be rewritten. Rewriting is required. Like method overloading, there are specific provisions. Rewriting methods are in subclasses, and methods in parent classes are rewritten methods.

⭐  conditions for method Rewriting:

  1. Same method name
  2. The parameter list is the same (including the number and type of formal parameters)
  3. The return value types are the same (except covariant return types)

Covariant return type refers to the return value type of the member function in the subclass. It does not have to be strictly equal to the return value type of the overridden member function in the parent class, but can be a more "narrow" type. For example, there is such a relationship between the return value of the subclass and the parent type.

⭐ ⅸ precautions for method Rewriting:

  1. static modified methods cannot be overridden.
  2. final decorated methods cannot be overridden.
  3. Methods with private permission cannot be overridden.
  4. When a subclass overrides a parent class method, the access rights of the overridden method in the subclass must be greater than or equal to the overridden method in the parent class.

Knowing the method rewriting, let's see if the previous program is rewritten at runtime as we said.

The result is that the eat of the subclass is called, indicating that the rewriting occurs when the program is running, and the rewriting does not occur when the program is compiled.

2.3 compile time binding

Just introduced runtime binding, now let's talk about compile time binding. The so-called compile time binding is that the program has method overloading, which will occur at compile time, unlike rewriting at run time. Let's take a look at the disassembly of a code containing overloading.

public class Func {
    public static int add(int a, int b) {
        return a + b;
    }
    public static int add(int a, int b, int c) {
        return a + b + c;
    }
    public static int add(int a, int b, int c, int d) {
        return a + b + c +d;
    }
    public static void main(String[] args) {
        int x = add(1,2);
        int y = add(1, 2, 3);
        int z = add(1, 2, 3 ,4);
        System.out.println(x);
        System.out.println(y);
        System.out.println(z);
    }
}


⭐ ⅸ rules for method overloading (review):

  1. Same method name.
  2. The parameter list is different (including the type and number of formal parameters).
  3. The return value is not required.

Compile time binding, also known as static binding, is a behavior during program compilation.

⭐ The difference between rewriting and overloading:

differencerewriteheavy load
conceptThe method name is the same, the parameter list is the same, and the return value is the same (except covariant return type)The method name is the same, the parameter list is different, and the return value is not required
RangeInheritance relationship (parent-child relationship)A class
limitThe permission of the overridden method of the subclass is greater than the access permission of the overridden parent class. The access permission cannot be private or modified by final and staticThere is no permission requirement. final and static modifications can also be overloaded

2.4 downward transformation

Downward transformation is rarely used and unsafe. The so-called downward transformation is to use the value referenced by the child class to be equal to the value referenced by the parent class on the basis of upward transformation. This process requires forced conversion.

Or look at an old chestnut:

class Animal {
    public String name;
    public int age;
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println(this.name + "I am eating!");
    }
}
class Cat extends Animal {
    public Cat(String name, int age) {
        super(name, age);
    }
    public void cute() {
        System.out.println(name + "Busy, cute!");
    }

    @Override
    public void eat() {
        System.out.println(this.age + this.name + "Eating quietly!");
    }
}
class Bird extends Animal {

    public Bird(String name, int age) {
        super(name, age);
    }
    public void fly() {
        System.out.println(this.name + "Flying!");
    }

    @Override
    public void eat() {
        System.out.println(this.age + this.name + "Eating slowly!");
    }
}

If the type matches after downward Transformation:

public class Instancesof {
    public static void main(String[] args) {
        Animal animal = new Cat("kitten", 1);
        Cat cat = (Cat)animal;//Downward transformation
        cat.eat();
    }
}


Type mismatch after downward Transformation:

public class Instancesof {
    public static void main(String[] args) {
        Animal animal = new Cat("kitten", 1);
        Bird Bird = (Bird) animal;
        bird.eat();
    }
}

Why is it unsafe? Because a parent class may have multiple subclasses, and downward transformation may cause type mismatch. Therefore, in order to avoid this exception, we often need to judge whether the types match when using downward transformation. Here, we can use the keyword instanceof to check whether the subclass references after downward transformation match the types.

public class Instancesof {
    public static void main(String[] args) {
        Animal animal = new Cat("kitten", 1);
        if (animal instanceof Bird) {
            Bird bird = (Bird) animal;
            bird.eat();
        }
        if (animal instanceof Cat) {
          Cat cat = (Cat)animal;
          cat.eat();
        }
    }
}

2.5 polymorphism

2.5.1 understanding polymorphism

When we understand the upward transformation, we can try to understand polymorphism. Let's not talk about the concept of polymorphism, because it is very abstract. Let's give an example first. There are many shapes in our life, such as circle, square, diamond, pentagram, triangle and so on. We use the method of inheritance and rewriting to realize a class Shape and output a variety of shapes.

First define the Shape class, create a draw method in this class, and then create other specific Shape classes to inherit Shape.

public class Shape {
    public void draw() {
        System.out.println("I want to print a shape!");
    }
}

class Circle extends Shape{
    @Override
    public void draw() {
        System.out.println("○");
    }
}
class Triangle extends Shape{
    @Override
    public void draw() {
        System.out.println("△");
    }
}
class Rhombus extends Shape{
    @Override
    public void draw() {
        System.out.println("◇");
    }
}
class Flower extends Shape{
    @Override
    public void draw() {
        System.out.println("❀");
    }
}
class Star extends Shape{
    @Override
    public void draw() {
        System.out.println("☆");
    }
}
class Square extends Shape{
    @Override
    public void draw() {
        System.out.println("□");
    }
}

Method 1: use the parent class array to store the objects of the subclass, and then call the draw override method of the subclass circularly.

public class Test {
    public static void main(String[] args) {
        Flower flower = new Flower();
        Square square = new Square();
        Star star = new Star();
        Rhombus rhombus = new Rhombus();
        Circle circle = new Circle();
        Triangle triangle = new Triangle();

        Shape[] shapes = {flower, square, star, rhombus, circle, triangle};
        for (Shape shape :shapes) {
            shape.draw();
        }
    }
}


Method 2: create a method whose formal parameter is Shape type. The specific content of the method is to call the draw method.

public class Test2 {
    public static void drawMap(Shape shape) {
        shape.draw();
    }
    public static void main(String[] args) {
        Flower flower = new Flower();
        Square square = new Square();
        Star star = new Star();
        Rhombus rhombus = new Rhombus();
        Circle circle = new Circle();
        Triangle triangle = new Triangle();

        drawMap(flower);
        drawMap(square);
        drawMap(star);
        drawMap(rhombus);
        drawMap(circle);
        drawMap(triangle);
    }
}


Using mode 2 to output various shapes is called polymorphism. When the caller of a class writes the drawMap method, the parameter type is shape (parent class). At this time, he does not know or pay attention to the instance of which type (subclass) the current shape reference points to. At this time, the reference of shape may call the draw method in many different ways This behavior is called polymorphism.

The so-called polymorphism is that a reference can show many different forms, which is polymorphism. Polymorphism can make you forget the type of object. For example, this chestnut, you don't need to care which subclass shape refers to. It will execute different methods or produce different behaviors according to different subclass objects.

2.5.2 advantages of polymorphism

✨ 1. It can reduce the cost of using the class by the class caller.
Encapsulation means that the caller of a class does not need to know the implementation details of the class
Polymorphism allows the caller of a class not to know the type of the class, but to know that the object has a method
Therefore, polymorphism can be understood as a further encapsulation, which further reduces the cost of class callers
✨ 2. Reduce the "cycle complexity" of the program and the use of branch statements.
If there is no polymorphism, when outputting different kinds of shapes, you need to judge which class draw method to call first. It is bound to use a lot of if else branch statements. With more branch statements, the "cycle complexity" becomes more complex
Circle complexity is a way to describe the complexity of a piece of code. If a piece of code is flat and straightforward, it is relatively simple and easy to understand. If there are many conditional branches or loop statements, it is considered more complex to understand
Therefore, we can simply and roughly calculate the number of conditional statements and circular statements in a piece of code, which is called "cycle complexity". If the cycle complexity of a method is too high, refactoring needs to be considered. Generally, the company requires that the cycle complexity is no more than 10

3. Abstract class

3.1abstract

In the previous implementation of polymorphism, the draw method of the parent Shape is not called at runtime because it is rewritten and calls the draw method of the child class, so there is no need to implement the draw method of the parent class. However, there is no declaration in C language in Java. If the method is declared in the form of C, an error will be reported in Java.

Therefore, abstract method is introduced into Java. Abstract method is a method without concrete implementation. It is modified by the keyword abstract. The function of abstract method is to be rewritten.
A class containing abstract methods must be an abstract class. In other words, if a class contains one or more abstract methods, the class must be limited to an abstract class, that is, use the keyword abstract to modify the class.

In an abstract class, you can define member variables and member methods. For the properties and methods in the class, the difference from ordinary classes is that abstract classes contain abstract methods, and everything else is the same. In addition, abstract classes are further abstractions of ordinary classes. Abstract classes cannot be instantiated into objects, and the greatest function of abstract classes is to be inherited.

3.2 characteristics of abstract classes

  1. Classes that contain abstract methods are called abstract classes.
  2. Abstract method is a method without concrete implementation, which is similar to the declaration of C language.
  3. Abstract classes cannot be instantiated as objects.
  4. The greatest function of abstract classes is to be inherited, and the greatest function of abstract methods is to be rewritten.
  5. If an ordinary class inherits an abstract class, the ordinary class needs to override all abstract methods in the abstract class.
  6. If an abstract class B inherits from abstract class A and ordinary class C inherits from abstract class B, ordinary class C should override all abstract methods in abstract class A and abstract class B.
  7. If an abstract class B inherits another abstract class A, then abstract class B does not need to override the methods of abstract class A.
  8. Abstract classes can contain the same member methods and member fields as ordinary classes.
  9. Abstract classes and methods cannot be final decorated.
abstract public class Shape {
    abstract public void draw();
}

class Circle extends Shape{
    @Override
    public void draw() {
        System.out.println("○");
    }
}
class Triangle extends Shape{
    @Override
    public void draw() {
        System.out.println("△");
    }
}
class Rhombus extends Shape{
    @Override
    public void draw() {
        System.out.println("◇");
    }
}
class Flower extends Shape{
    @Override
    public void draw() {
        System.out.println("❀");
    }
}
class Star extends Shape{
    @Override
    public void draw() {
        System.out.println("☆");
    }
}
class Square extends Shape{
    @Override
    public void draw() {
        System.out.println("□");
    }
}
public class Test2 {
    public static void drawMap(Shape shape) {
        shape.draw();
    }
    public static void main(String[] args) {
        Flower flower = new Flower();
        Square square = new Square();
        Star star = new Star();
        Rhombus rhombus = new Rhombus();
        Circle circle = new Circle();
        Triangle triangle = new Triangle();

        drawMap(flower);
        drawMap(square);
        drawMap(star);
        drawMap(rhombus);
        drawMap(circle);
        drawMap(triangle);
    }
}

4. Interface

4.1 initial interface

An interface is a further abstraction of an abstract class. To create an interface, you need to use the keyword instead of the interface instead of the keyword class. Just like a class, you can use the public modifier in front of the interface (which needs to be the same as the file name). If you don't add the keyword public, it is the default package access permission. Like interfaces and classes, you can't use the protected private modifier.
The interface name generally starts with capital I. ordinary methods in the interface cannot have specific implementation. If they have to be implemented, they need to be decorated with default.

public interface Shape {
    public void draw();
    default public void print() {
        System.out.println("I have to implement the methods in the interface!");//public after default can be omitted
    }
}

4.2 characteristics of interface

  1. Interfaces are further abstractions of abstract classes, using keywords i n t e r f a c e interface Interface defines an interface, which can only be modified by public or not by access permission keywords.
  2. An interface cannot instantiate an object using new because it is extremely abstract.
  3. The common methods in the interface cannot be implemented concretely. If you want to implement them, please use d e f a u l t default default modifier.
  4. There can be static methods in the interface.
  5. All abstract methods in the interface are public abstract modified by default, and all methods in the interface are public modified.
  6. Class can be defined by keyword i m p l e m e n t s implements implements to implement the interface.
  7. A class can only inherit one class or abstract class at most, and can implement multiple interfaces at the same time. Class inheritance is written in the front and interface implementation is written in the back, separated by commas.
  8. When an ordinary class implements an interface, it must override the abstraction of all parties of the interface and its extension interface.
  9. All member variables in the interface are p u b l i c   s t a t i c   f i n a l public\ static\ final public   static   final modified.
  10. There is an extended relationship between interfaces. Use keywords e x t e n d s extends extends represents an extension relationship.
  11. When a class implements an interface, the overridden method access permission must be p u b l i c public public.

Use the interface to realize graphic output:

public interface Shape {
    public void draw();
    default public void print() {
        System.out.println("I have to implement the methods in the interface!");//public after default can be omitted
    }
}

class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("○");
    }
}
class Triangle implements Shape {
    @Override
    public void draw() {
        System.out.println("△");
    }
}
class Rhombus implements Shape {
    @Override
    public void draw() {
        System.out.println("◇");
    }
}
class Flower implements Shape {
    @Override
    public void draw() {
        System.out.println("❀");
    }
}
class Star implements Shape {
    @Override
    public void draw() {
        System.out.println("☆");
    }
}
class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("□");
    }
}
public class Test {
    public static void drawMap(Shape shape) {
        shape.draw();
    }
    public static void main(String[] args) {
        Flower flower = new Flower();
        Square square = new Square();
        Star star = new Star();
        Rhombus rhombus = new Rhombus();
        Circle circle = new Circle();
        Triangle triangle = new Triangle();

        drawMap(flower);
        drawMap(square);
        drawMap(star);
        drawMap(rhombus);
        drawMap(circle);
        drawMap(triangle);
    }
}


Use interfaces to describe animal behavior:

public class Animal {
    public String name;
    public Animal(String name) {
        this.name = name;
    }
    public void eat() {
        System.out.println(this.name + "I am eating");
    }
}
interface IRun{
    void running();
}
interface ISwim{
    void swimming();
}
interface IFly{
    void flying();
}
interface ISkip{
    void skipping();
}
class Frog extends Animal implements ISkip, ISwim{
    public Frog(String name) {
        super(name);
    }
    @Override
    public void swimming() {
        System.out.println(name + "Good at breaststroke!");
    }
    @Override
    public void skipping() {
        System.out.println(name + "Jump up!");
    }
}
class Bird extends Animal implements IFly{
    public Bird(String name) {
        super(name);
    }

    @Override
    public void flying() {
        System.out.println(name + "Flying freely!");
    }
}

class Cat extends Animal implements IRun,ISkip{
    public Cat(String name) {
        super(name);
    }

    @Override
    public void running() {
        System.out.println(name + "Run!");
    }

    @Override
    public void skipping() {
        System.out.println(name + "Can jump, too!");
    }
}
class Duck extends Animal implements ISwim, IRun{
    public Duck(String name) {
        super(name);
    }

    @Override
    public void running() {
        System.out.println(name + "Will also try to run!");
    }

    @Override
    public void swimming() {
        System.out.println(name + "Can swim, too!");
    }
}
public class TestDemo {
    public static void running(IRun iRun) {
        iRun.running();
    }
    public static void swimming(ISwim iSwim) {
        iSwim.swimming();
    }
    public static void skipping(ISkip iSkip) {
        iSkip.skipping();
    }
    public static void flying(IFly iFly) {
        iFly.flying();
    }
    public static void main(String[] args) {
        Bird bird = new Bird("Bird");
        Cat cat = new Cat("little cat");
        Frog frog = new Frog("Little frog");
        Duck duck = new Duck("Duckling");

        flying(bird);
        running(cat);
        running(duck);
        skipping(frog);
        skipping(cat);
        swimming(frog);
        swimming(duck);
    }
}

That's all for this blog post. I think we must give it to the blogger for three consecutive times!

Posted by LucienFB on Tue, 23 Nov 2021 10:30:33 -0800