Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

Continuing where we left off, this time we’ll look at inheritance, polymorphism, and multithreading.

  • A subclass

    The hierarchy of classes in Java is a tree structure, which is similar to describing things in nature. For example, animals can be divided into mammals and reptiles, and then the two groups can be subdivided, so that both mammals and reptiles can be considered subclasses of animals. In Java, things can also be characterized by subclasses and superclasses. Large, more general classes can be considered superclasses, and special classes contained within them are subclasses. The relationship between a subclass and its parent is that the subclass object “is a” (or “is kind of”), that is, any member of the subclass is also a member of the parent class. It not only describes the relationship between objects, but also embodies another feature in the program design, which is the use of inheritance.

    • Is a relationship between

      public class Employee { // Have a generic class
          private String name, jobTitle;
          private DatehireDate, dateOfBirth;
          private int grade;
      }
      public class Manager {// A class with a special nature
          private String name, jobTitle;
          private DatehireDate, dateOfBirth;
          private int grade; // These are the attributes shared with Employee
          private String department; // Unique attributes
          private Employee[]subordinates;  // Unique attributes
      }
      Copy the code

      As you can see from the above definition, there is duplication between the Manager class and the Employee class. In fact, many of the attributes and methods that apply to Employee can be used by The Manager without modification. There is an “Is A” relationship between Manager and Employee. Manager “is a” Employee.

    • The extends keyword

      Like normal object-oriented languages, Java provides a derivation mechanism that allows programmers to define a new class from a previously defined class. The new class is called a subclass, and the original class is also called a parent class, a base class or a superclass. The content common to both classes goes into the parent class, and the special content goes into the child class. When defining a class, you can indicate whether a class is a subclass of another class. In Java, derivation is denoted by the extends keyword in the following format:

      Class extends superclass name {body}

      public class Employee { 
          private String name, jobTitle;
          private DatehireDate, dateOfBirth;
          private int grade;
      }
      public class Manager extends Employee { // Derive a subclass
          private String department; // List only attributes that are not in the Employee class
          private Employee[]subordinates;
      }
      Copy the code

      The Manager class has all the variables and methods of the Employee class, all of which inherit from the parent class definition. Subclasses simply define additional features or make necessary changes.

    • Object class

      The Object class is the direct or indirect parent of all classes in a Java program and is at the highest point in the class hierarchy. All other classes are derived from the Object class. The Object class contains the common properties of all Java classes. Its constructor is Object (). The main methods in the class are as follows

      • public final class getClass(); Gets information about the class to which the current object belongs, returning the class object
      • Public String toString(): String object returns information about the current object
      • Public Boolean equals(Object obj): Compares whether two objects are the same Object, returns true if they are.

      There are two ways to determine object equality in Java. One is to use the == operator and the other is to use the equals () method. Both methods determine whether two objects are the same object (become the same). Two objects are equal if they have the same type and the same attribute value. Identical objects must be equal, but equal objects are not necessarily the same.

    • Single inheritance

      Java is a fully object-oriented language with full OOP capabilities. In the inheritance mechanism of class, it abandons the function of multiple inheritance and implements the single inheritance mechanism.

      Multiple inheritance is the common derivation of a subclass from multiple classes, that is, a class can have more than one parent class. Multiple inheritance relationships are like a web. If a subclass has methods and attributes of the same name in more than one parent class, it is easy to confuse subclass instances. This is an insurmountable disadvantage of multiple inheritance. Multiple inheritance is abandoned in Java, allowing only single inheritance.

      In Java, the concept of an interface is provided, which is a special class through which multiple inheritance capabilities are implemented. In general, in Java, if a class has a parent class, it can only have one parent class, that is, it is only allowed to extend classes from one class. This restriction is called single inheritance.

      Although a subclass can inherit all methods and member variables from its parent and ancestor classes, it cannot inherit constructors. There are only two ways for a class to get a constructor. One way is to write its own constructor; Alternatively, the system provides a single default constructor for a class when the user has not written one.

    • Transformation of object

      Like most object-oriented languages, Java allows you to point to an object using a variable of its superclass type, which is called object transformation.

      public class Employee { 
          private String name, jobTitle;
          private DatehireDate, dateOfBirth;
          private int grade;
      }
      public class Manager extends Employee { 
          private String department;
          private Employee[]subordinates;
      }
      Employee e = new Manager(); / / right
      Manager m = new Employee(); / / error
      Copy the code

      In general, there are the following rules for object reference transformations

      • It is always legal to transition “up” along the class hierarchy, for example, from a Manager reference to an Employee reference. In this way, no transition operator is required and only a simple assignment statement can be used.
      • For “down” transitions, only ancestor classes can be converted to descendant classes, not between other classes. For example, it is illegal to change the Manager reference to the Contractor reference, because the Contractor is not the Manager. There is no inheritance relationship between the two classes. The class to be replaced (to the right of the assignment number) must be a parent of the current reference type (to the left of the assignment number), and an explicit conversion is used.
  • Method covering and polymorphism

    Using class inheritance, you can create a new class from an existing class. On the basis of the original features, new features are added. Existing methods in the parent class may not meet the new requirements, so you need to modify existing methods in the parent class. This is method override, also known as method override or hiding. The names, return types, and argument lists used to define methods in subclasses are exactly the same as those used in the parent class, that is, they have the same method signature. At this point, the subclass method overrides (overrides) the method in the parent class, which logically means that the member method in the subclass will hide the method with the same name in the parent class.

    • Method override and its rules

      In object-oriented programming, the concept of method override is often used. Through method coverage, language polymorphism can be achieved. When something to do in a subclass (a method) is not exactly the same as in the parent class, override the related method in the parent class.

      Note: If the method name is the same but the argument list is different, it is an overload of the method. When an overloaded method is called, the compiler selects the corresponding method to execute based on the number and type of arguments. Overridden methods belong to the same class, and overridden methods belong to parent classes and subclasses. Method override instance

      public class Employee {
          String name;
          int salary;
          public String getDetails(a) {
              return "Name:" +name + "\n" + "salary:"+ salary; }}public class Manager extends Emplyee {
          String department;
          public String getDetails(a) {
              return "Name:" +name + "\n" + "salary:" + salary + "\n" "Manager of"+ department; }}Copy the code

      There are two important rules to be aware of when applying overrides:

      • An override method cannot have less access than the original method
      • An override method cannot throw more exceptions than the original method
    • Invoke the constructor of the parent class

      For security reasons, Java is very strict about object initialization. For example, Java requires that objects of a parent class be fully initialized before a subclass can run

      The super keyword can also be used in constructors to call the constructor of the parent class. A subclass cannot inherit a constructor from its parent, and it is good programming style to call the parent constructor in a subclass’s constructor.

      If the parent constructor is not explicitly called in the definition of the subclass constructor, the system automatically calls the default constructor of the parent class (that is, the no-arguments constructor) when executing the subclass constructor.

      If the parent class constructor is called in the definition of the subclass constructor, the call statement must appear on the first line of the subclass constructor.

    • polymorphism

      In Java, polymorphism is an important concept that allows the same method call instruction to do different things in different contexts.

      Overloading a method name can be considered polymorphic. Method names overwritten directly or indirectly between parent and child classes depend on which method will be called at run time by the object.

      The static type of a variable is the type that appears in the declaration. Static types, also known as reference types, are determined when code is compiled. The type of the object that the variable points to at some point in the run is called dynamic type, which is its true type at the moment. The dynamic type of a variable changes with the running process.

      This process of calling methods that may later be overridden is called dynamic binding or post-binding. Dynamic binding cannot determine the method code to execute until runtime. The ability to determine how a calling method is handled during compilation is called static binding or pre-binding.

      class SuperClass {
          public void method (a) {
              System.out.printIn("superclass!"); }}class SubClass extends SuperClass {
          public void method (a) {
              System.out.printIn("sbuclass!")}}public class Test {
          public static void main(String args[]) {
              SuperClass superc = new SuperClass();
              SubClass subc = new SubClass();
              SuperClass ssc = new SubClass();
              superc.method();// Execute the method of the parent class
              subc.method();// Execute the method of the subclass
              ssc.method();// Execute the method of the subclass}}// The type declared by SSC is SuperClass, but it refers to an instance of Subclass, so ssc.method() calls the method of the instance's class (Subclass) rather than the method of the declared class (SuperClass).
      Copy the code
  • Final class and abstract class

    An important keyword in Java, final, represents ultimate, and can modify either a class or a member variable or method within a class. As the name implies, classes or members of classes modified with this keyword cannot be changed. If a class is defined as final, it cannot have subclasses; If a method is defined as final, it cannot be overridden; If a variable is defined as final, its value cannot be changed.

    The corresponding keyword is abstract, which can be used for classes or methods to represent abstraction. The body of a method that uses the abstract modifier is empty, and the modified class must be inherited by subclasses

    • The ultimate class

      Sometimes classes cannot be inherited, as is the case with the predefined java.lang.string class in Java. The purpose of this is to ensure that if a method has a reference to the String class, it must be a true String and not a modified subclass of String. The other case is when a class is structurally and functionally complete and does not need to be subclassed. In this case, the class declaration should also be decorated with the keyword final. Classes marked as final cannot be inherited, and such classes are called final classes or endstate classes. format

      final classThe ultimate class name{} class bodyCopy the code
    • The ultimate way to

      Member methods can also be marked as final, thus being called final methods or endstate methods. Methods marked as final cannot be overridden, ensuring that the method being called is the original method and not the method in the subclass that has been changed. In addition, marking methods as final is sometimes used for optimizations to make compilation runs more efficient. Final method definition format:

      finalReturn value type Final method name ([parameter list]) {method body}Copy the code
    • The ultimate variable

      A variable is marked final and is called a final variable or final state variable. It’s actually going to be a constant. Changing the value of the final variable causes a compilation error.

      When some special-purpose constants are needed in a program, they can be defined in a class, and other classes can use them directly by introducing modifications. This ensures the uniformity of constant usage and facilitates modification.

      If you mark a variable of a reference type as final, the variable can no longer point to other objects, but the value of the property it refers to can still change.

    • An abstract class

      In Java, a class can be defined as abstract by the keyword abstract, and every method that does not define a concrete implementation should also be marked abstract. Such methods are called abstract methods.

      Note:

      An abstract class can contain common behaviors shared by all of its subclasses, and common properties shared by all of its subclasses.

      You cannot use an abstract class as a template to create an object in a program. You must generate a nonabstract subclass of the abstract class before you can create an instance.

      Abstract classes can contain non-abstract methods, and you cannot define abstract methods in non-abstract classes.

      If an abstract class has nothing but abstract methods, an interface is more appropriate.

  • interface

    An interface is another way to represent the functionality of an abstract class, which you can think of as a “pure” abstract class. It allows the author to specify the basic form of a class, including the method name, argument list, and return value type, but not the method body. Therefore, all methods in the interface are abstract methods with no method body. Java allows a class to implement multiple interfaces, enabling multiple inheritance and a clear structure.

    • Interface Definition

      Interface definition format:

      [Interface modifier]interfaceThe interface name [extendsList of parent interfaces]{...// Method prototype or static constant
      }
      
      interface CharStorage {
          void put(char c);
          char get(a);
      }
      Copy the code

      Interfaces, like general classes, also have data member variables and methods, but data member variables must be assigned an initial value, and this value cannot be changed, and methods must be “abstract methods”.

      Member variables in the interface definition default to final static variables, that is, the system automatically adds the final and static keywords to them, and the variable must have an initial value.

    • Interface implementation

      The implementation of an interface is similar to the inheritance of a class, except that the class implementing the interface cannot inherit any behavior from the definition of that interface. Methods defined in this interface can be called from any object of the class that implements the interface. A class can implement multiple interfaces simultaneously.

      To implement an interface, you can use the keyword implements in the class declaration. All abstract methods in an interface must be implemented in a class or subclass. Implements statement format

      public classThe name of the classimplementsInterface name [, interface name [, interface name]]{
          // Definition of abstract methods and ultimate static variables
      }
      Copy the code

      In Java programs, you can declare multiple interface names after implements, which means that a class implements more than one interface. Interface is actually a special abstract class and implement multiple interfaces at the same time also means that it has the ability of multiple inheritance, because in the interface methods are abstract methods, does not contain any specific code, the implementation of these abstract method in concrete classes to complete, so even if have the same name in different interface method, instances of the class will not confuse. This is where Java removes the ability to display multiple inheritance while retaining the ability to have multiple function inheritance.

      interface Shape2D {
          final double pi = 3.14;
          public abstract double area(a);
      }
      
      class Circle implements Shape2D {
          double radius;
          public Circle(double r) {radius = r; }public double area (a) {return (pi*radius*radius);}
      }
      
      class Rectangle implements Shape2D {
          double width, heigth;
          public Rectangle (int w, int h) {
              width = w;
              height = h;
          }
          public double area (a) {
              return(width * heigth); }}public class InterfaceTester {
          public static void main(String args[]) {
              Rectangle rect = new Rectangle(5.6);
              System.out.printIn("Area of rect" + rect.area());
              Circle cir = new Circle(2.0);
              System.out.printIn("Area of cir ="cir.area()); }}Copy the code
  • multithreading

    • Threads and multithreading

      When the program is to be put into operation, the system starts from the program entrance according to the order of the statement (including sequence, branch and loop structure) to complete the corresponding instructions until the end, and then exits from the exit, the whole program ends. Such a statement is called a process, which is a dynamic execution of the program, corresponding to a complete process from code loading, execution to completion of execution; Or a process is a run of a program in a processor. In such a structure, not only the program code, but also the concept of system resources are included. Specifically, a process includes both the instructions to be executed and any system resources needed to execute the instructions, such as CPU, memory space, I/O ports, etc. Different processes occupy relatively independent system resources.

      Threads are threads of execution that occur during the execution of a process. Threads are smaller units of execution than process units and are similar in form to processes — they use a sequential sequence of statements to perform a specific function. The difference is that it has no entrance and no exit, so it cannot operate automatically by itself, but must reside in a process and be executed by the process. In the use of system resources, all threads belonging to the same process share system resources on that process, but switching between threads is much faster than switching between processes.

      • Thread structure

        The virtual CPU, encapsulated in the java.lang.Thread class, controls the execution of the entire Thread.

        The code executed is passed to the Thread class, which controls the sequence of execution.

        The processed data, passed to the Thread class, is the data to be processed during code execution.

      • Thread state

        A thread has four states: New, runnable, dead, and blocked

        1. New: The thread object has just been created and has not been started. It is still in an unrunnable state. At this point, the newly created thread is in the new state, but has the corresponding memory space and other resources.

        2. Runnable: The thread has been started and is in the run () method of the thread. In this case the thread may be running, or it may not be running, but it will run as soon as the CPU is free. Threads that are runnable but not runnable are placed in a queue called the ready queue. In runnable state, the running thread is in the running state and the thread waiting to run is in the ready state. Typically, with a single CPU, at most one thread is running, and there may be multiple threads in the ready state.

        3. Death: A thread dies either when the last statement in the run () method completes, or when it encounters an abnormal exit

        4. Blocking: if a thread is suspended for some special reason, it enters the blocking state. When the thread is blocked, it cannot enter the ready queue and can re-enter the queue only after the cause of the blocking is eliminated. There are many reasons for blocking, and different methods should be used to remove different reasons. Sleep () and wait () are two common ways to cause blocking.

        Interrupt threads: It is common in programs to terminate threads with an interrupt (). Interrupt () can interrupt not only a running thread but also a thread in the blocked state, throwing an InterruptedException.

        Java provides several methods for testing whether a thread is interrupted:

        • Void interrupt () : Sends an interrupt request to a thread whose “interrupted” status is set to true. If the thread is “blocked,” InterruptedException is thrown
        • Static Boolean interrupted () : Checks whether the current thread has been interrupted and resets the status “interrupted” value. If this method is called twice in a row, the second call returns true
        • Boolean isInterrupted () : Checks whether the current thread has been interrupted without changing the status of “interrupted”
    • Create a thread

      There are two ways to create threads: by defining a subclass that inherits Thread, or by implementing the Runnable interface

      • Inherits the Thread class to create a Thread

        Java.lang.Thread is a Java class used to represent threads. If a class is defined as a subclass of Thread, objects of that class can be used to represent threads

        A typical constructor for Thread is Thread(ThreadGroup group, Tunnable target, String name).

        Where name is the name of the new thread and is a member of the thread group, target must implement the Runnale interface, which is another thread object that calls Target’s run () method when the thread starts. When target is null, the run method of this thread is started. There is only one method defined in the Runnale interface, void Run (), which acts as the thread body. Any object that implements the Runnale interface can be the target object of a thread. Each parameter in the constructor can be defaulted.

        class Leftand extends Thread {
            public void run (a) {
                for (int i = 0; i <= 5; i++) {
                    System.out.printIn("I am Lefthand!");
                }
                try {
                    sleep(500);
                } catch (InterrupedException e) {}
            }
        }
        
        class Rightand extends Thread {
            public void run (a) {
                for (int i =0; i <= 5; i++) {
                    System.out.printIn("I am Rightand!");
                }
                try {
                    sleep(300);
                } catch (interruptException e) {}
            }
        }
        
        public class ThreadTest {
            static Lefthand left;
            static Rightand right;
            public static void main(String[] args) {
                left = new Leftand();
                right = newRightand(); left.start(); right.start(); }}Copy the code
      • Implement the Runnable interface to create threads

        There is only one method defined in the Runnale interface: the run () method, which is the thread body. When implementing multithreading with the Runnale interface, the run () method must also be implemented, and the Thread must be started using start (), but Thread objects are often created using the constructor of the Thread class. Thread’s constructor contains a Runnable instance parameter. That is, a class that implements the Runnable interface must be defined and an instance of that class must be generated. References to that instance are the parameters that apply to the constructor.

        // Write the thread body
        public class xyz implements Runnable {
            int i;
            public void run (a) {
                while(true) {
                    System.out.printIn("Hello" + i++);
                }
            }
        }
        Runnable r = new xyz();
        Thread t = new Thread(r);
        // defines a thread, represented by t, that executes program code in the run () method of the XYZ class. The data used by this thread is provided by an object of the XYZ class referenced by R.
        Copy the code
      • Conditions apply for both methods of creating a thread

        • 1. This method is applicable when implementing the Runnable interface

          Because Java only allows single inheritance, if a class already inherits Thread, it cannot inherit from another class, forcing the implementation of Runnable in some cases. In addition, since the original thread implements the Runnable interface, it may continue to use this method in order to preserve the program style

        • 2. This method is applicable when Thread class methods are inherited

          When a run () method is placed in a subclass of Thread, this actually refers to the Thread instance that controls the current running system. The code can be simplified.

          Thread.currentThread().getState(); => getState();
          Copy the code
    • Basic control of threads

      Although a thread has been created, it is not actually running right away. For threads to actually run in a Java environment, they must be started by the start () method, which is also in the Thread class

      • The following thread operations are provided in the API:

        • Start () : Starts the thread object from the new state to the ready state
        • Run () : Defines operations to be performed after a thread object is scheduled. The user must override the run () method.
        • Yield () : forces the execution of a thread to terminate
        • IsAive () : tests whether the current thread is active
        • Sleep (int millSecond) : Puts the thread to sleep for a period of time determined by millsecond, in ms
        • Void wait () : makes the thread wait.
      • Scheduling of threads

        In Java, thread scheduling is usually preemptive rather than timeslice. Preemption scheduling is when there may be multiple threads ready to run, but only one is actually running. A thread gains execution, and that thread will continue to execute until it finishes running or blocks for some reason, or another priority thread is ready, which is called preempting a lower-priority thread by a higher-priority thread.

        Each thread has a priority, and Java thread scheduling uses the following priority policy.

        • The value with a higher priority is executed first, and the value with a lower priority is executed later.
        • Each thread is automatically assigned a priority when created and, by default, inherits the priority of its parent class
        • Threads with urgent tasks have a higher priority
        • Threads of the same priority are scheduled on a first-in, first-out basis

        The Thread class has three static quantities related to Thread priority:

        • MAX_PRIORITY: indicates the highest priority. The value is 10
        • MIN_PRIORITY: indicates the lowest priority. The value is 1
        • NORM_PRIORITY: indicates the default priority. The value is 5
      • The end of the thread

        When a thread returns from the end of the run () method, it dies automatically and can no longer be run, which can be considered a natural death. Another situation is when an exception is encountered that causes the thread to terminate, which can be understood as a forced death. You can also interrupt the execution of a thread with the interrupt () method.

      • Hung thread

        There are several methods you can use to suspend a thread. Suspending a thread is also called suspension. After the suspension, the thread must be reawakened to run, but it is very slow to execute commands

        • Sleep () : temporarily stops the execution of a thread
        • Wait () and notify () /notifyAll () : Wait () causes the current thread to wait until another thread calls notify () or notifyAll () on this object to wake up the thread
        • Join () : Causes the current thread to wait until the thread called by the join () method terminates.
    • Mutual exclusion of threads

      • Object mutex

        In the Java language, the concept of an object mutex, also known as a monitor, was introduced to synchronize operations on shared data between different threads. The object mutex prevents multiple threads from accessing the same condition variable at the same time. Java can have an “object mutex” for every instance of an object

        There are two ways to implement “object mutex”

        • Use the keyword volatile to declare a shared data

        • Use the keyword synchronized to declare a method or a piece of code that operates on shared data

    • Synchronization of threads

      To address thread speed, Java provides a way to interact based on object instances. Each object instance in Java has two thread queues attached to it. The first thread used to line up waiting for the lock flag. The second is used to implement wait () and notify ().

      There are three methods defined in the java.lang.object class: wait (), notify (), and notifyAll ()

      The wait method causes the current thread to wait. It releases the object mutex held by the current thread and enters the wait queue. Notify () /notifyAll () wakes up one or all of the waiting threads and moves them to the queue waiting for the same “object mutex”.

Programming topics:

  • 1. Design and implement a MyGraphic class and its subclasses that represent basic graphics, including rectangles, triangles, circles, ellipses, diamonds, and trapezoids. Give the attributes and access methods necessary to describe these figures.
  • 2. Design and implement a Vehicle class and its subclasses, such as bicycle automobile, ship and aircraft, which represent the main means of transportation and define the necessary attribute information, construction methods and access methods. Optional attributes include name, type, weight, size, fuel, purpose, passenger capacity, cargo tonnage, maximum speed, etc. Alternative access methods include displaying information about themselves, setting and reading a property, and so on.