Java programming (spring 2021) -- Chapter 4 notes and Thoughts on interface and polymorphism

Java programming (spring 2021) -- Chapter 4 notes and Thoughts on interface and polymorphism

Overview of this chapter:

4.1 interface (the concept of interface, the syntax of declaring interface and implementing interface)

4.2 type conversion

4.3 concept of polymorphism

4.4 application of polymorphism

4.5 construction method and polymorphism

4.1 interface

The interface can be regarded as a pure abstract class, which only provides design but not implementation.

  1. The interface can specify the prototype of the method: method name, parameter list and return type, but does not specify the method body (that is, the implementation of the method is not given).
  2. You can also include data members of basic data types, but they are static and final by default.

Function of interface

  1. Inherit multiple designs (you can implement multiple inheritance of the design of a class).

  2. Establish a protocol between classes.

    The classes are grouped according to their functions and represented by interfaces, without worrying about the class inheritance level; This can maximize the use of dynamic binding and hide the implementation details.

Interfaces allow common behaviors to be defined between seemingly unrelated objects, as shown in the following figure.

Interface syntax

The declaration format is

[Interface modifier]interface Interface name [extends Parent interface name]{
	...Prototype or static variable of method
}
  1. Interface indicates that what is being declared is an interface.
  2. The interface can inherit the parent interface (described later).
  3. Method prototypes and static constants can be declared in the interface body.
  4. Since the data member in the interface body is static, it must have an initial value, and this value cannot be changed. You can omit the final keyword (constant by default).
  5. The method in the interface must be an abstract method and cannot have a method body. The public and abstract keywords can be omitted (the default is public because it is an external service interface; the default is abstract because the method is abstract).

Example: interface declaration

Declare an interface Shape2D, including π and a method prototype for calculating area

interface Shape2D{//Declare Shape2D interface
    final double pi = 3.14;//Data members must be initialized
    public abstract double area();//Abstract method
}

In the declaration of the interface, some keywords can be omitted, or the following can be declared:

interface Shape2D{
    double pi = 3.14;
    double area();
}

As above, the final public abstract keyword can be omitted.

There is only the prototype of the method body in the interface, and there is no implementation of the method body. Therefore, like the abstract class, the interface cannot generate an instance (cannot new an interface object).

Implementation interface

Implementing an interface is the process of designing a class using an interface to become the implementation of the interface. Use the implements keyword. The syntax is as follows:

public class Class name implements Interface name{
    //Method of implementing interface in class body
    //More variables and methods declared by this class
}

By, the implementation interface is similar to the inherited superclass in form (using the extends keyword)

be careful:

  1. All methods in the interface must be implemented.
  2. Methods from interfaces must be declared public.

Example: implement interface Shape2D

class Circle implements Shape2D{
    double radius;
    public Circle(double r){
        radius = r;
    }
    public double area(){
        return (pi * radius * radius);
    }
}
class Rectangle implements Shape2D{
    int width,height;
    public Rectangle (int w,int h){
        width = w;
        height = h;
    }
    public double area(){
        return (width * height);
    }
}

Test class

public class InterfaceTester {
	public static void main(String[] args) {
		Rectangle rect = new Rectangle(5, 6);
		System.out.println("Area of rect = " + rect.area());
		Circle cir = new Circle(2.0);
		System.out.println("Area of cir = " + cir.area());
	}
}

output

Area of rect = 30.0
Area of cir = 12.56

It can be seen from the above that although the area() method is called, the correct areas are calculated respectively.

Example: reference variable of interface type

Declare a variable of interface type and use it to access objects:

public class VariableTester {
	public static void main(String[] args) {
		Shape2D var1, var2;//Declare the reference variables VAR1 and VAR1 of two interface types
		var1 = new Rectangle(5, 6);//Assigning the reference of the Rectangle object to the reference of the Shape2D interface type results in an implicit type conversion
		System.out.println("Area of var1 = " + var1.area());
		var2 = new Circle(2.0);//An implicit type conversion occurs when the reference of the Circle object is assigned to the reference of the Shape2D interface type
		System.out.println("Area of var2 = " + var2.area());
	}
}

output

Area of var1 = 30.0
Area of var2 = 12.56

As can be seen from the above, the respective area() methods are still executed accurately.

Syntax for implementing multiple interfaces

A class can implement multiple interfaces, and multiple inheritance of design can be realized through this mechanism (only single inheritance is supported in Java, which is a turning point).

The syntax for implementing multiple interfaces is as follows

[Class modifier] class Class name implements Interface 1,Interface 2,...{
    //Implement the abstract methods in each interface
}

Example: achieve multiple inheritance (to the design) by implementing the interface

Declare the Circle class to implement the interfaces Shape2D and Color

  1. Shape2D has constant pi and area methods to calculate the area.

  2. Color has the setColor method, which can be used to assign colors.

  3. By implementing these two interfaces, the Circle class can have the members of these two interfaces at the same time, so as to achieve the purpose of multiple inheritance of the design.

interface Shape2D{//Declare Shape2D interface
    final double pi = 3.14;//Data members must be initialized
    public abstract double area();//Abstract method
}
interface Color{
    void setColor(String str);//Abstract method
}
class Circle implements Shape2D, Color {
	double radius;
	String color;

	public Circle(double r) {// Construction method
		radius = r;
	}

	public double area() {
		return (pi * radius * radius);
	}

	public void setColor(String str) {// Defines how setColor() is handled
		color = str;
		System.out.println("color = " + color);
	}
}

Test class

public class MultiInterfaceTester {
	public void main() {
		Circle cir;
		cir = new Circle(2.0);
		cir.setColor("blue");
		System.out.println("Area = " + cir.area());
	}
}

Output results

color = blue
Area = 12.56

Interface extension

There can also be inheritance relationship between interfaces, that is, extensions relationship, which can extend more interfaces from an existing interface. The existing interface becomes a super interface, and the extended interface is called a sub interface.

  1. A class that implements an interface must implement its super interface.

  2. Syntax of interface extension

    interface Name of the sub interface extends Hyperinterface name 1, hyperinterface name 2,...{
        //
    }
    

    Examples are as follows:

Example: interface extension

//Declare Shape interface
interface Shape{
    double pi = 3.14;
    void setColor(String str);
}
//Declaring the Shape2D interface extends the Shape interface
interface Shape2D extends Shape{//It inherits the Shape interface and automatically inherits the constant pi and setColor methods
    double area();
}
class Circle implements Shape2D {
	double radius;
	String color;

	public Circle(double r) {// Construction method
		radius = r;
	}

	public double area() {
		return (pi * radius * radius);
	}

	public void setColor(String str) {// Defines how setColor() is handled
		color = str;
		System.out.println("color = " + color);
	}
}
public calss ExtendsInterfaceTester{
    public static void main(String[] args){
        Circle cir;
        cir = new Circle(2.0);
        cir.setColor("blue");
        System.out.println("Area = " + cir.area());
    }
}

Operation results

color = blue
Area = 12.56

explain

  1. First declare the parent interface Shape, and then declare its child interface Shape2D.
  2. Then declare the class Circle to implement the Shape2D sub interface, so the processing methods of setColor() and area() methods must be clearly defined in the class.
  3. Finally, the variable cir of Circle type is declared in the main class and a new object is created. Finally, setColor and area() methods are called through the cir object.

4.2 type conversion

Type conversion

  1. Also known as type casting.
  2. Conversion methods can be divided into implicit type conversion and explicit type conversion.
  3. The transformation direction can be divided into upward transformation and downward transformation.

Type conversion rules

  1. Conversion between basic types: converts values from one type to another.
  2. Type conversion of reference type:
    1. Converting a reference to another type does not change the type of the object itself.
    2. Reference type can only be converted to
      1. The type of any (direct or indirect) superclass (upward transformation).
      2. An excuse for the implementation of the class (or its superclass) to which the object belongs (upward transformation).
      3. Is converted to the type of object pointed to by the reference (the only case that can be converted down).
  3. When a reference is converted to its superclass reference, only the methods declared in the superclass can be accessed through it, that is, they are limited. The same is true for converting to interface reference.

The following is an example of type conversion:

Person inherits or extends the Object class; Employee class and Customer class inherit the person class; The manager class inherits the Employee class.

Person implements the Insurable interface.

  1. Manager object
    1. It can be molded as employee person object or Insurable.
    2. It cannot be typed as Customer, Company or Car because there is no inheritance relationship and it is not a relationship to implement the interface.

Implicit type conversion

Basic data type

  1. Between types that can be converted, those with low storage capacity will automatically convert to those with high storage capacity.

Reference variable

  1. Is converted to a more general class (converting a reference of a subtype to a reference of a supertype), for example:

    Emploee emp;
    emp = new Manager();
    //If you directly assign an object of Manager type to the reference variable of Employee class, the system will automatically shape the Manager object into employee class
    
  2. It is modeled as the interface type implemented by the class to which the object belongs, for example:

    Car jetta = new Car();
    Insurable item = jetta;
    

Explicit type conversion

Basic data type

(int)871.34354;//The result is 871, which is the conversion from high type to low type, which must be explicitly converted. The method is to directly cut off the decimal part, so there is data loss.
(char)65;//The result is' A '
(long)453;//The result was 453L

Reference variable

Emploee emp;
Manager man;
emp = new Manager();//As in the above example, an implicit conversion to a superclass occurs automatically, but the object emp actually points to is a subclass object
man = (Manager)emp;//Explicitly convert emp to the type of object it points to. In this case, you can cast the emp reference to a subtype. This conversion will not occur automatically, and the conversion must be displayed. This cast will not cause errors and can work normally because the object emp really points to is a subclass object. If you are not sure about this, you must not make a downward transformation.

Main applications of type conversion

  1. Assignment conversion: converts the expression or object type on the right of the assignment operator to the type on the left.
  2. Method call conversion: converts the type of an argument to the type of a formal parameter.
  3. Arithmetic expression conversion: in arithmetic mixed operation, operands of different types are converted to the same type for operation.
  4. String conversion (string splicing): during string connection operation, if one operand is a string and the other operand is of other types, other types will be automatically converted to strings.

Application examples of type conversion

The manager class inherits the Employee class, the Employee class inherits the person class, and the getname class method is declared in the person class; The getemployeenumber class method is declared in the Employee class. When we convert a reference of manager type into a reference of employee type, we can only access the methods in the Employee class and its superclass, such as the getname method in person and the getemployeenumber () method in employee. The getSalary() method in the manager class cannot be accessed through the superclass of the manager class, such as the reference of employee

4.2. 3. Search method

In the previous section, you learned that you can convert a reference of a subclass type up to a reference of a superclass type. When a reference type conversion occurs, if the type to which the reference belongs before the conversion and the type to which the reference belongs after the conversion declare the same prototype method, then after the type conversion, call or access the method through this reference, and which method body will be accessed is a problem about method search.

Method lookup

Finding instance methods

Start with the class at the time of object creation and look up along the class hierarchy

Manager man = new Manager();
Emploee emp1 = new Emploee();
Emploee emp2 = (Emploee)man;

The following exploration calls the Computepay method

emp1.Computepay();//The reference is of employee type, and the object actually pointed to is also of employee type. Naturally, the Computepay method in employee type is called
man.Computepay();//man is a Manager type object, and the object actually pointed to is also a Manager type object. It calls the Computepay method in the Manager class
emp2.Computepay();//The reference is of employee type, but the object pointed to is of Manager type. According to the above rules, start from the class when the object is created and look up along the class hierarchy, that is, start from the Manager class to find whether there is a Computepay() method, so the statement still calls the Computepay() method in the Manager class.

Class method lookup

Class methods are static, static and belong to the whole class.

Manager man = new Manager();
Emploee emp1 = new Emploee();
Emploee emp2 = (Emploee)man;

It is tested below

man.expenseAllowance();//in Manager
emp1.expenseAllowance();//in Emploee
emp2.expenseAllowance();//in Emploee!!

Note that the class method belongs to the whole class and does not belong to an object, so it is called emp2 When expenseallowance (), this method will not be found according to who the object pointed to by the reference is, because the class method does not belong to any object. Therefore, the only way to find is to reference the variable according to its own type.

4.3 concept of polymorphism

Polymorphism means that different types of objects can respond to the same message, and their corresponding behavior to the message can be different

Concept of polymorphism

  1. Superclass objects and objects of multiple subclasses derived from the same superclass can be treated as objects of the same type (because objects of subclasses can always be used as superclass objects).
  2. Objects of different types that implement a unified interface can be treated as objects of the same type (treated as objects of interface type).
  3. The same message can be sent to these different types of objects. Due to polymorphism, the behavior of these different types of objects in response to the same message can be different.

For example:

  1. All objects of the Object class respond to the same toString() method.
  2. All objects of the BankAccount class have the corresponding deposit() method.
  3. However, the above responses to methods can be different, because each class has its own coverage of the methods inherited from the superclass, that is, it implements the method body.

Purpose of polymorphism

  1. Make the code simple and easy to understand.
  2. So that the program has good scalability.

Example: graphics class

  1. Declare a drawing method draw() and an erase method erase() in the superclass Shape.

  2. The draw() and erase() methods are overridden (overridden) in each subclass.

  3. Later drawing can be carried out as follows:

    Shape s = new Circle();
    s.draw();//draw() of the actually called Circle object
    

Concept of binding

Binding is to combine a method call expression with the code of the method body.

According to different binding periods, it can be divided into:

  1. Early binding: binding is performed before the program runs (during compilation).
  2. Late binding: also known as "dynamic binding" or "runtime binding", it is an object-based category that performs binding when the program runs.

Example: dynamic binding

Still taking the drawing as an example, all classes are placed in the binding package

The superclass Shape establishes a general interface (because draw and erase are empty cube methods)

class Shape {
	void draw();
	void erase();
}

Subclasses override the draw() method and provide unique behavior for each particular geometry:

calss Circle extends Shape{
    void draw(){
        System.out.println("Circle.draw()");
    }
    void erase(){
        System.out.println("Circle.erase()");
    }
}
calss Square extends Shape{
    void draw(){
        System.out.println("Square.draw()");
    }
    void erase(){
        System.out.println("Square.erase()");
    }
}
calss Triangle extends Shape{
    void draw(){
        System.out.println("Triangle.draw()");
    }
    void erase(){
        System.out.println("Triangle.erase()");
    }
}

Perform the following tests on dynamic binding:

public class BindingTester{
    public satic void main(String[] args){
        Shape[] s = new Shape[9];
        int n;
        for(int i = 0;i < s.length();i++){
            n = (int)(Math.random() * 3);
            switch(n){
                case 0:s[i] = new Circle();
                    break;
                case 1:s[i] = new Square();
                    break;
                case 2:s[i] = new Triangle();
            }
        }
        for(int i = 0;i < s.length();i++){
            s[i].draw;
        }
    }
}

Operation results (due to the characteristics of random number, the following are only the results of one experiment):

Square.draw()
Triangle.draw();
Cicrcle.drwa();
Triangle.draw();
Triangle.draw();
Cicrcle.drwa();
Square.draw()
Cicrcle.drwa();
Triangle.draw();   

explain

  1. In the loop body of the main method, randomly generate one Circle, Square() or Triangle() object at a time.
  2. The actual object type pointed to by the s array element cannot be known at compile time, and the type can be determined at run time, so it is a dynamic binding.

Summary: the basis of polymorphism is dynamic binding technology and upward transformation technology.

4.4 application examples of polymorphism

Example: secondary distribution

  1. There are different kinds of vehicles, such as buses and cars. Therefore, an abstract class vehicle and two subclasses bus and car can be declared.
  2. Declare an abstract class Driver and two subclasses FemaleDriver and MaleDriver.
  3. The abstract method drives is declared in the Driver class, and this method is overridden in two subclasses.
  4. The drives method accepts parameters of a Vehicle class. When different types of vehicles are transferred to this method, specific vehicles can be output.
  5. All classes are placed in the drive package.

Test code:

package drive;

public class DriverTest {
	static void main(String args[]) {
		Driver a = new FemaleDriver();//Although a is of Driver type, the object actually pointed to is of FemaleDriver type
		Driver b = new MaleDriver();
		Vehicle x = new car();
		Vehicle y = new bus();
		a.drives(x);
		b.drives(y);
	}
}

Desired output:

A Female driver drives a car
A male driver drives a bus

Vehicle and its subclasses are declared as follows

package drive;
//abstract class
public abstract class Vehicle {
	private String type;

	public Vehicle() {
	};
//Abstract method
	public abstract void drivedByFemaleDriver();
//Abstract method
	public abstract void drivedByMaleDriver();
}
package drive;

public class Car extends Vehicle {
	public Car() {
	};

	public void drivedByFemaleDriver() {
		System.out.println("A Female driver drives a car");
	}

	public void drivedByMaleDriver() {
		System.out.println("A Male driver drives a car");
	}
}
package drive;

public class Bus {
	public Bus() {
	};

	public void drivedByFemaleDriver() {
		System.out.println("A female driver drives a bus");
	}

	public void drivedByMaleDriver() {
		System.out.println("A male driver drives a bus");
	}
}

Driver and its subclasses are declared as follows

package drive;

public abstract class Driver {
	public Driver() {
	};

	public abstract void drives(Vehicle v);

}
package drive;

public class FemaleDriver extends Driver {
	public FemaleDriver() {
	};

	public void drives(Vehicle v) {
		v.drivedByFemaleDriver();
	}
}
package drive;

public class MaleDriver extends Driver {
	public MaleDriver() {
	};

	public void drives(Vehicle v) {
		v.drivedByMaleDriver();
	}
}

explain:

  1. This technology is called double dispatching, that is, the request for the output message is distributed twice.
  2. First, it is sent to a class according to the type of driver.
  3. It is then sent to another class according to the type of vehicle.

4.5 construction method and polymorphism

The construction method is different from other methods and does not have the characteristics of polymorphism. But we still need to know how to call polymorphic methods in the construction method.

Call order of construction methods when constructing subclass objects

  1. First call the constructor of the superclass (if there is a superclass), and this step will be repeated. The constructor of the farthest superclass is executed first.
  2. Executes other statements in the constructor body of the current subclass.

Example: call order of construction method

Build a Point class Point, a Ball class Ball, and a moving Ball class MovingBall, which inherit from Ball

public class Point {
	private double xCoordinate;
	private double yCoordinate;

	public Point() {
	};//Constructor without parameters

	public Point(double x, double y) {
		xCoordinate = x;
		yCoordinate = y;
	}//Construction method with parameters

	public String toString() {
		return "(" + Double.toString(xCoordinate) + "," + Double.toString(yCoordinate) + ")";
	}
}
public class Ball {
	private Point center;//Center point
	private double radius;//radius
	private String color;//colour

	public Ball() {
	};//Parameterless construction method

	public Ball(double xValue, double yValue, double r) {//Construction method of three parameters
		center = new Point(xValue, yValue);//Call the constructor in Point
		radius = r;
	}

	public Ball(double xValue, double yValue, double r, String c) {//The construction method of four parameters can directly call the construction method of three parameters
		this(xValue, yValue, r);
		color = c;
	}

	public String toString() {
		return "A ball with center " + center.toString() + ",radius " + Double.toString(radius) + ",colour" + color;
	}
}
public class MovingBall extends Ball {
	private double speed;

	public MovingBall() {
	};

	public MovingBall(double xValue, double yValue, double r, String c, double s) {
		super(xValue, yValue, r, c);//Note that the method of the superclass must be called first
		speed = s;
	}

	public String toString() {
		return super.toString() + ",speed" + Double.toString(speed);
	}
}

Subclasses cannot directly access private data members declared in the parent class, super Tostring() calls the toString method of the parent class Ball to output the property value declared in the class Ball.

public class Tester {
	public static void main(String args[]) {
		MovingBall mb = new MovingBall(10, 20, 40, "green", 25);
		System.out.println(mb);
	}
}

output

A ball with center (10.0,20.0),radius 40.0,colourgreen,speed25.0

The calling order of the constructor is movingball (double xvalue, double yvalue, double R, string c, double s) - > ball (double xvalue, double yvalue, double R, string c) - > ball (double xvalue, double yvalue, double R) - > point (double x, double y)

Example: calling polymorphic method in construction method

Declare an abstract method in Glyph and call it inside the constructor

abstract class Glyph {
	abstract void draw();

	Glyph() {
		System.out.println("Glyph() before draw()");
		draw();// Don't worry about not finding the method body, because the abstract class cannot generate objects, it must be the draw() method of a non Abstract subclass
		System.out.println("Glyph() after draw()");
	}
}

class RoundGlyph extends Glyph {
	int radius = 1;
//The first sentence should be to call the superclass constructor, but if the superclass constructor is not explicitly called, the superclass parameterless constructor will be called by default
	RoundGlyph(int r) {
		radius = r;
		System.out.println("RoundGlyph.RoundGlyph(),radius = " + radius);
	}

	void draw() {
		System.out.println("RoundGlyph.draw(),radius = " + radius);
	}
}

public class PolyConstructors {//test
	public static void main(String args[]) {
		new RoundGlyph(5);
	}
}

Output:

Glyph() before draw()
RoundGlyph.draw(),radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(),radius = 5

Analysis: the radius of the first output is equal to 0 0 0 is because the object has not been constructed and radius = 1 in RoundGlyph has not been initialized, so it is the default value without initialization; In Java, there is no numeric data, and the default value without initialization is 0 0 0.

explain:

  1. In Glyph, the draw() method is an abstract method, which is overridden in the subclass RoundGlyph. The constructor of Glyph calls this method.
  2. From the running results, we can see that when the Glyph constructor calls draw(), the radius value is not even the default initial value 1 1 1, but 0 0 0.

Precautions for implementing the construction method:

  1. Set the state of the object with as few actions as possible, that is, the constructor is used for initialization. It's best not to do anything other than initialization.
  2. If you can avoid it, don't call any methods.
  3. Within the constructor, the only methods that can be safely called are those that have the final attribute in the superclass (also applicable to private methods, which have the final attribute). These methods cannot be overridden, so the potential problems mentioned above will not occur.

Keywords: Java

Added by arkleyjoe on Sun, 26 Dec 2021 20:58:27 +0200