Fundamentals of Java - object oriented 3

Posted by gypmaster on Wed, 20 Oct 2021 21:25:57 +0200

  • Application of abstract classes: design patterns of template classes
// Application of abstract classes: design patterns of template methods
public class TemplateTest {
    public static void main(String[] args) {
        Template t = new SubTemplate();
        t.spendTime();
    }
}
abstract class Template{
    // Calculate the time spent executing a piece of code
    public void spendTime() {
        // This is also the method of executing the parent class
        long start = System.currentTimeMillis(); // The start time of execution is recorded as start
        // This is where you begin to execute subclass methods
        code(); // Uncertain part
        long end = System.currentTimeMillis(); // The end time is recorded as end
        System.out.println("Time spent is: " + (end - start));
    }

    // The method of the uncertain part of the code and abstract it
    public abstract void code();
}

class SubTemplate extends Template {
    // Overridden the abstract method of the parent class
    @Override
    public void code() {
        for (int i = 2; i <= 1000; i++) {
            // Define an identification, which will be reset automatically every time it comes in without manual operation
            boolean isFlag = true;
            for (int j = 2; j <= Math.sqrt(i); j++) {
                if (i % j == 0) {
                    isFlag = false;
                    break;
                }
            }
            // If the isFlag has not changed, it indicates that the above if judgment has not been made, indicating that it is a prime number
            if (isFlag) {
                System.out.println(i);
            }
        }
    }
}
  • Abstract class exercise:

import java.time.Month;
import java.util.Calendar;
import java.util.Scanner;

public class PayrollSystem {
    public static void main(String[] args) {
        // Method 1: manual acquisition
        // Enter the month value of the current month. If the birthday of an Employee object in the current month, the salary increase information will be output
        /*Scanner scan = new Scanner(System.in);
        System.out.println("Enter the current month: ";
        int month = scan.nextInt();*/
        // Mode 2: automatic acquisition
        // Gets an instance of the calendar
        Calendar calendar = Calendar.getInstance();
        // Gets the month of the current instance
        int month = calendar.get(Calendar.MONTH);
        System.out.println(month);
        // Here, only space is opened in the heap to save this type of object, but there is no new object
        // The address of this reference type is stored in the array, but the Employee constructor is not called to generate the object,
        // The emps variable in the stack points to the length of the array created in the heap space. Each location is declared as an Employee type, but there is no new object, but a new array. The array elements are temporarily declared as abstract classes
        Employee[] emps = new Employee[2];
        // The new object in the array cannot be an object of an abstract class. Birthday is a user-defined class, so you need to new a user-defined class
        // Reflecting polymorphism, the array declaration is the parent class, and the actual placement is the child class object
        emps[0] = new SalariedEmployee("Masson", 1002, new MyDate(1992, 3, 2),10000);
        emps[1] = new HourlyEmployee("Jack Ma", 2001, new MyDate(1998, 3, 6), 60, 240);
        for (int i = 0; i < emps.length; i++) {
            System.out.println(emps[i]);
            // When printing wages, it is an abstract type. After execution, it is a subclass override method
            double salary = emps[i].earnings();
            System.out.println("The monthly salary is: " + salary);
            if (month + 1 == emps[i].getBirthday().getMonth()) {
                System.out.println("Happy birthday!,Reward 100 yuan");
                salary += 100;
            }
        }
    }
}
public abstract class Employee {
    private String name;
    private int number;
    private MyDate birthday;
    public Employee(String name, int number, MyDate birthday) {
        super();
        this.name = name;
        this.number = number;
        this.birthday = birthday;
    }
    public abstract double earnings();
    // Override the toString method of Object class. Because it is an abstract class, it cannot be called by an Object, so it can only be called by subclasses
    // It needs to be modified; if a non abstract method is defined in the parent class, it should be used by the child class, otherwise it will be meaningless
    @Override
    public String toString() {
        return "name='" + name + '\'' +
                ", number=" + number +
                ", birthday=" + birthday.toDateString();
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setNumber(int number) {
        this.number = number;
    }
    public int getNumber() {
        return this.number;
    }
    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }
    public MyDate getBirthday() {
        return this.birthday;
    }
}
public class MyDate {
    private int year;
    private int month;
    private int day;
    public MyDate(int year, int month, int day) {
        super();
        this.year = year;
        this.month = month;
        this.day = day;
    }
    // Be careful not to call the toString method, otherwise the output is the address value
    public String toDateString() {
        return year + "year" + month + "month" + day + "day";
    }
    public void setYear(int year) {
        this.year = year;
    }
    public int getYear() {
        return year;
    }

    public void setMonth(int month) {
        this.month = month;
    }
    public int getMonth() {
        return month;
    }
    public void setDay(int day) {
        this.day = day;
    }
    public int getDay() {
        return day;
    }
}
public class SalariedEmployee extends Employee{
    private double monthSalary; // Monthly salary
    public SalariedEmployee(String name, int number, MyDate birthday) {
        super(name, number, birthday);
    }
    public SalariedEmployee(String name, int number, MyDate birthday, double monthSalary) {
        super(name, number, birthday);
        this.monthSalary = monthSalary;
    }
    @Override
    public double earnings() {
            return monthSalary;
    }
    // Rewrite the toString method to avoid the trouble of get and directly call the toString method of the parent class
    @Override
    public String toString() {
        return "SalariedEmployee{" +
                "monthSalary=" + super.toString() +
                '}';
    }
    public void setMonthSalary(double monthSalary) {
        this.monthSalary = monthSalary;
    }
    public double getMonthSalary() {
        return monthSalary;
    }
}
public class HourlyEmployee extends SalariedEmployee{
    private int wage; // Hourly wage
    private int hour; // Monthly working hours
    public HourlyEmployee(String name, int number, MyDate birthday) {
        super(name, number, birthday);
    }
    public HourlyEmployee(String name, int number, MyDate birthday, int wage, int hour) {
        super(name, number, birthday);
        this.wage = wage;
        this.hour = hour;
    }
    @Override
    public double earnings() {
        return wage * hour;
    }
    @Override
    public String toString() {
        return "HourlyEmployee{" +
                super.toString() +
                '}';
    }
}

6.6. Interface

Use of interfaces
1. The interface is defined by interface
2. In Java, interfaces and classes are two parallel structures
3. How to define interfaces and define members in interfaces (classes are also members of defined classes)
3.1.jdk7 and before, only global constants and abstract methods can be defined
Global constant declaration: public static final, which can be omitted from writing (all attributes in the interface are public)
Abstract method declaration: public abstract
3.2.jdk8: in addition to defining global constants and abstract methods, you can also define static methods and default methods
4. Constructor cannot be defined in the interface! This means that the interface cannot be instantiated
5. In java development, interfaces are used by letting classes implement (classes implement interfaces)
If the implementation class implements (overrides) all abstract methods in the interface, the implementation class can be instantiated
If the implementation class does not implement (override) all the abstract methods in the interface, the implementation class is still an abstract class
The method that a subclass covers an ordinary parent class is called rewriting, and the abstract method that a subclass covers an abstract class is called implementation. The abstract method itself has nothing, so we implemented it
The abstract method in the implementation class coverage interface is called implementation
6.Java classes can implement multiple interfaces -- > making up for the limitation of Java single inheritance
Format: Class AA extensions BB implementations CC, DD, EE
7. Interfaces can be inherited from one another, and multiple interfaces can be inherited
8. The specific use of the interface reflects polymorphism
9. Interface can actually be regarded as a specification

public class InterfaceTest {
    public static void main(String[] args) {
        System.out.println(Flyable.MAX_SPEED);
        System.out.println(Flyable.MIN_SPEED);
        Plane plane = new Plane();
        // Class implementation interface
        plane.fly();
    }
}
// Define interface
interface Flyable {
    // Interface member
    // Global constant
    public static final int MAX_SPEED = 7900;
    int MIN_SPEED = 1; // Because they are global constants, the public static final keyword can be omitted

    // Abstract method
    public abstract void fly();

    // Keywords can be omitted
    void stop();

    // Constructors cannot be defined in an interface
    /*public Flyable(){

    }*/
}
// Aggressive
interface Attackable {
    // Declare abstract methods
    void attack();
}
// If the Plane class implements the interface, it has related functions
class Plane implements Flyable {
    // Implementing an interface is equivalent to taking over the abstract methods in the interface and defining two abstract methods, which is similar to subclass inheriting abstract classes
    @Override
    public void fly() {
        System.out.println("Take off by engine");
    }
    @Override
    public void stop() {
        System.out.println("Driver deceleration stop");
    }
}
// To implement multiple interfaces, you need to implement all abstract methods in the interface if you want to instantiate a class
// First inherit the parent class, and then implement the specific interface
class Bullet extends Object implements Flyable, Attackable, CC{
    @Override
    public void fly() {

    }
    @Override
    public void stop() {

    }
    @Override
    public void attack() {

    }
    @Override
    public void method1() {

    }
    @Override
    public void method2() {

    }
}
// Does not implement all abstract methods or abstract classes in the interface
abstract class Kite implements Flyable {
    @Override
    public void fly() {

    }
}
// Multiple inheritance between interfaces
interface AA {
    // Abstract method
    void method1();
}
interface BB{
    // Abstract method
    void method2();
}
// Now that you inherit, you have all the abstract methods of the parent interface
interface CC extends AA, BB{

}

Use of interfaces
1. The interface also meets polymorphism
2. Interface actually defines a specification
3. Experience interface oriented programming during development

// The driver can be understood as a collection of many implementation classes of the interface, which is the implementation class of the interface, which can be regarded as the implementation of the interface
public class USBTest {
    public static void main(String[] args) {
        // Use a computer to transfer data and create a computer object
        Computer com = new Computer();
        // Take the computer object and call the method to transfer data. The method parameter needs to be passed into the object of interface type,
        // Interfaces cannot create objects, but can only create objects of interface implementation classes, which is equivalent to reflecting polymorphism
        // 1. Create a non anonymous object of the non anonymous implementation class of the interface
        Flash flash = new Flash();
        com.transferData(flash);
        // 2. Create the anonymous object of the non anonymous implementation class of the interface
        com.transferData(new Print());
        // 3. Create a non anonymous object of the anonymous implementation class of the interface. If there is no class name, use the USB interface name as a reference
        USB phone = new USB() {
            @Override
            public void start() {
                System.out.println("The phone starts working");
            }
            @Override
            public void stop() {
                System.out.println("The phone stops working");
            }
        };
        com.transferData(phone);
        // 4. Create an anonymous object of an anonymous implementation class
        com.transferData(new USB() {
            @Override
            public void start() {
                System.out.println("mp3 Start work");
            }
            @Override
            public void stop() {
                System.out.println("mp3 Stop working");
            }
        });
    }
}
// Define a computer class
class Computer{
    // To define a data transmission method, you need to contact external devices, and the method needs to follow the specification of USB interface
    // From the perspective of formal parameters, the declared is the USB interface, and the actual new is the implementation class that implements USB USB usb = new Flash();
    // The interface to be used must be used in a polymorphic manner
    public void transferData(USB usb){ // The interface cannot create an object for the object passed into USB. At this time, the implementation class of the interface needs to be passed in, and so does the abstract class, which reflects polymorphism
        // To transmit data, first open the USB interface
        // Different devices have different functions and provide different abstract methods. Here are only two simple examples of abstract methods
        // When compiling, it will be considered that the call is the abstract method of the interface, and the actual implementation is the method of object rewriting of the implementation class
        usb.start();
        System.out.println("Details of specific transmission data");
        usb.stop();
    }
}
// Defining a USB interface reflects a specification. As long as it is a specification for data transmission with a computer, it is defined as USB. Anyone who wants to transfer data with the above computer must implement the USB interface and clarify the specification
interface USB {
    // Constants can be defined: length, width, maximum and minimum transmission speed, etc
    // Abstract method: USB function
    void start();
    void stop();
}
// Define a USB flash disk class to implement USB interface
class Flash implements USB{
    // Abstract method of rewriting interface
    @Override
    public void start() {
        System.out.println("U Disc opening operation");
    }
    @Override
    public void stop() {
        System.out.println("U Disk end work");
    }
}
class Print implements USB{
    @Override
    public void start() {
        System.out.println("Printer on");
    }
    @Override
    public void stop() {
        System.out.println("Printer finished working");
    }
}
  • Interface application: proxy mode

// Static proxy: one class operates on another
public class NetWorkTest {
    public static void main(String[] args) {
        // Create an object of the proxy class as an implementation class object and pass it to the proxy class as a formal parameter
        Server server = new Server();
        // Because the formal parameter of the proxied class is the NetWork interface type, and the interface cannot create an object, only the object of the implementation class can be passed in
        // Reflect polymorphism, declare that the reference of the NetWork interface points to the implementation class object of the implementation interface, which is equivalent to polymorphism, and the parent class reference points to the object of the child class
        ProxyServer proxyServer = new ProxyServer(server); // NetWork work = new Server(); It is equivalent to assigning server to work
        // Formally speaking, calling the proxy class browsing method actually includes the call of the method rewritten by the proxy class object when the proxy class object calls the method
        proxyServer.browse();
    }
}
// Declare an interface that can implement functions
interface NetWork{
    // The function of browsing can be realized by connecting to the Internet
    public void browse();
}
// Provide the proxy class to see what you want to do
// Servers are needed to access the network. Two servers are defined to implement the network interface
class Server implements NetWork{
    // Expose the uncertain part
    @Override
    public void browse() {
        System.out.println("Real server access network");
    }
}
// Proxy classes, like proxy servers, have other methods besides browsing
class ProxyServer implements NetWork{
    // This property is the interface implemented by the proxy class and the proxy class
    private NetWork work;
    // What is really connected is the object of the proxy class
    // Provide the constructor of the current proxy class to initialize the properties of the interface type
    public ProxyServer(NetWork work){
        this.work = work;
    }
    // When browsing, help the agent to access the network, first do the verification operation
    public void check() {
        System.out.println("Inspection before networking");
    }
    // When adjusting the browse method, verify it first (adjust the verification method)
    @Override
    public void browse() {
        check();
        // After verification, you can connect to the network, but what is really connected to the network is that the agent class only operates as an agent and the object of the agent class
        // Call the browse method through the object of the proxy class
        work.browse();
    }
}
  • Proxy mode exercise:
public class StaticProxyTest {
    public static void main(String[] args) {
       /* //Create proxy class object
        RealStar realStar = new RealStar();*/
        // Create a proxy class object without exposing the proxy class object
        Proxy proxy = new Proxy(new RealStar());
        proxy.confer();
        proxy.bookTicket();
        proxy.singContract();
        proxy.collectMoney();
        proxy.sing();
    }
}
// Define a star interface: the functions that stars can achieve
interface Star{
    void confer(); // interview
    void singContract(); // sign a contract
    void bookTicket(); // booking
    void sing(); // sing
    void collectMoney(); // Collect money
}
// Proxied class: it can implement the methods of the interface, but it doesn't want to do it
class RealStar implements Star{
    // Most methods are replaced by proxy classes, so there is no need to write
    @Override
    public void confer() {

    }
    @Override
    public void singContract() {

    }
    @Override
    public void bookTicket() {

    }
    @Override
    public void sing() {
        System.out.println("Star Singing");
    }
    @Override
    public void collectMoney() {

    }
}
// Agent class: the agent does what the agent class does not want to do
class Proxy implements Star{
    // Calling proxy classes through interfaces
    public Star real;
    public Proxy(Star real){
        this.real = real;
    }
    @Override
    public void confer() {
        System.out.println("Broker interview");
    }
    @Override
    public void bookTicket() {
        System.out.println("Broker Booking");
    }
    @Override
    public void singContract() {
        System.out.println("Broker sign contract");
    }
    @Override
    public void collectMoney() {
        System.out.println("Brokers collect money");
    }
    // The proxy class calls the proxy class through the interface, and the broker calls the star to sing
    @Override
    public void sing() {
        // Method can be called
        real.sing();
    }
}
  • Interface application: factory mode

  • Interface exercise: comparing object sizes

public class ComparableCircleTest {
    public static void main(String[] args) {
        ComparableCircle c1 = new ComparableCircle(3.4);
        ComparableCircle c2 = new ComparableCircle(3.6);
        int compareValue = c1.CompareTo(c2);
        if (compareValue > 0){
            System.out.println("c1 Large object");
        }else if (compareValue < 0){
            System.out.println("c2 Large object");
        }else{
            System.out.println("The same big as that");
        }
        int comPareValue1 = c1.CompareTo(new java.lang.String("AA"));
        System.out.println(comPareValue1);
    }
}
public interface CompareObject {
    // If the return value is 0, it means equal. If it is a positive number, it means the current object is large, and a negative number means the current object is small
    public int CompareTo(Object o);
}
public class Circle {
    // Change the double type to the wrapper type
    private Double radius;
    public Circle(){

    }
    public Circle(Double radius){
        this.radius = radius;
    }

    public void setRadius(Double radius) {
        this.radius = radius;
    }

    public Double getRadius() {
        return this.radius;
    }
}
public class ComparableCircle extends Circle implements CompareObject{
    // Provides a constructor with a radius
    public ComparableCircle(Double radius){
        super(radius);
    }
    @Override
    public int CompareTo(Object o) {
        if (this == o){
            return 0;
        }
        if (o instanceof ComparableCircle){
            ComparableCircle c = (ComparableCircle) o;
            // Incorrect writing, loopholes and loss of accuracy. If 2.3-2.1 = 0.2, it will be misjudged as 0
            //return (int) (this.getRadius() - c.getRadius());
            // Correct way 1:
            /*if (this.getRadius() > c.getRadius()){
                return 1;
            }else if (this.getRadius() < c.getRadius()){
                return -1;
            }else{
                return 0;
            }*/
             // If you change all radius types to Double wrapper types
            // In the source code of the double wrapper class, implements the comparable interface to judge the value of the double type encapsulated by the double, so you don't have to write your own comparison method
            // When the attribute radius is declared as Double, you can call the method of the wrapper class, which can automatically help you compare the size
            //Correct way 2:
            return this.getRadius().compareTo(c.getRadius());
        }else{ // If it is not of type comparableCirlcle
            // return 0; //  For the time being
            // Object that throws an exception class
            throw new RuntimeException("Incoming data type mismatch"); // Replace return 0;
        }
    }
}
public class ComparableCircleTest {
    public static void main(String[] args) {
        ComparableCircle c1 = new ComparableCircle(3.4);
        ComparableCircle c2 = new ComparableCircle(3.6);
        int compareValue = c1.CompareTo(c2);
        if (compareValue > 0){
            System.out.println("c1 Large object");
        }else if (compareValue < 0){
            System.out.println("c2 Large object");
        }else{
            System.out.println("The same big as that");
        }
        int comPareValue1 = c1.CompareTo(new java.lang.String("AA"));
        System.out.println(comPareValue1);
    }
}
  • New interface features in Java 8
public class SubClassTest {
    public static void main(String[] args) {
        SubClass s = new SubClass();
        // Neither the implementation class nor the object implementing the class can call the static method of the interface
        // s.method1(); //  report errors
        // SubClass.method1(); //  report errors
        // Knowledge point 1: static methods defined in the interface can only be called through the interface
        // To put it bluntly, the static methods of the interface are not called by other implementation classes, but used by themselves, just like tool classes
        CompareA.method1();
        // Knowledge point 2: you can call the default method in the interface by implementing the object of the class
        // If the implementation class overrides the default method in the interface, the overridden method will still be called
        // This default method is the same as that method in the parent class
        s.method2(); // See the default method in the interface in the future. Subclass objects can be called directly
        // Knowledge point 3: if the parent class inherited by the subclass (or implementation class) and the implemented interface declare a default method with the same name and parameter,
        // If the subclass does not override this method, it will call the method with the same name and parameter in the parent class by default - class priority principle
        // If there is an indirect parent class, the proximity principle is used
        // The method class with the same name takes precedence, and the properties with the same name are displayed differently
        // Knowledge point 4: if the implementation class does not inherit the parent class but implements multiple interfaces, and the default methods with the same name and parameters are defined in these interfaces,
        // If the implementation class does not override this method, an error will be reported. -- > interface conflict
        // Since there is a conflict, but you want to implement two interfaces at the same time, you must override this method in the implementation class

        // If the implementation class implements multiple interfaces in which abstract methods with the same name and parameters are defined,
        // Then the implementation class will be considered to override the abstract methods with the same name and parameters of multiple interfaces at the same time
        s.method3();
        // SubClass.method2();//  An error is reported. Method2 is not static
        // System.out.println(s.x); //  Calling a variable with the same name of the parent class and the interface will report an error. The compiler cannot judge whose variable it is, and the attribute cannot be overwritten. It should be displayed and distinguished
    }
}
public class SuperClass {
    // int x = 2;
    public void method3(){
        System.out.println("superclass: Beijing");
    }
}
public interface CompareA {
    // int x = 1;
    // Static method: it can be called directly through the interface
    public static void method1(){
        System.out.println("CompareA: Beijing");
    }
    // Default method: called through the implementation class of the interface
    public default void method2(){
        System.out.println("CompareA: Shanghai");
    }
    // The public keyword can be omitted, instead of the method permission becoming the default, which is similar to the default in the switch loop
    // Just like ordinary non static methods called by objects that implement classes
    default void method3(){
        System.out.println("CompareA: Guangzhou");
    }
}
public interface compareB {
    default void method3(){
        System.out.println("compareB: Shanghai");
    }
}
// Implementation class implementation interface
// No error is reported, because the interface has no abstract method and has a method body
class SubClass extends SuperClass implements CompareA,compareB{
    // Override the default method of the interface
    @Override
    // Overridden methods with method bodies are called rewriting, and overridden methods without method bodies (abstract methods) are called implementation
    public void method2() {
        System.out.println("subclass: Shanghai");
    }
    public void method3(){
        System.out.println("Rewrite interface: Beijing");
    }
    // Knowledge point 5: how to call the parent class in the subclass (or implementation class) method and the method to be rewritten in the interface.
    // Define a unique common method
    public void myMethod(){
        method3(); // Call your own defined override method
        super.method3(); // Call the method declared in the parent class
        // Call the default method of the interface
        CompareA.super.method2();
        compareB.super.method3();
    }
}
  • Interface new features exercise:
// If the implementation class does not override the method with the same name and parameter that implements multiple interfaces, the interface conflict will occur
// No error will be reported after rewriting
// When the subclass inherits the parent class and implements the interface at the same time, and the subclass does not override this method, it will call the method with the same name and parameters in the parent class by default - class priority principle
// After the subclass overrides the method, it has priority to call its own method
public class Man extends Father implements Filial,Spoony {
    public void help(){
        System.out.println("Who should I save");
        Filial.super.help(); // Save the fuck
        Spoony.super.help(); // Save your daughter-in-law
    }
}
class Father{
    public void help(){
        System.out.println("My son is my daughter-in-law");
    }
}
interface Filial{ // Filial piety
    default void help(){
        System.out.println("Mom, I'll save you");
    }
}
interface Spoony{
    default void help(){
        System.out.println("Daughter in law, I'll save you");
    }
}

6.7. Category 5: internal category

Inner member of class 5: inner class
1.Java allows one class A to be declared in another class B, then class A is the inner class, and class B is called the outer class
2. Classification of internal classes: member internal classes (static, non static) vs local internal classes (within methods, code blocks, constructors)
3. Member internal class:
On the one hand, as a member of an external class:
You can call the structure of an external class
On the other hand, as a class:
Properties, methods, constructors, etc. can be defined within a class
It can be modified by the final keyword to indicate that this class cannot be inherited. It can be inherited without final
It can be modified by the abstract keyword to indicate that it cannot be instantiated
Can be modified by static keyword
It can be modified by four permission modifiers: public, default, protected and private
4. Pay attention to the following three issues
4.1. How to instantiate an object of a member's internal class
4.2. How to distinguish the structure of calling external classes in member internal classes
4.3. Use of internal classes of bureau and department in development

public class InnerClassTest {
    public static void main(String[] args) {
        // 4.1.
        // Create a Dog instance (static member inner class)
        Person.Dog dog = new Person.Dog(); // The inner class object is created through the constructor of the inner class of the outer class. Member
        dog.show();
        // Create Bird instance (non static member inner class)
        Person p = new Person(); // To invoke a non static structure, you must first instantiate the class
        Person.Bird bird = p.new Bird(); // Create the object of the inner class through the constructor of the inner class of the outer class object. new member
        bird.sing();
        bird.display("Oriole");
    }
}
// Normal external classes can only be modified by public and default permission modifiers
class Person{
    String name = "Xiao Ming";
    int age;
    public void eat(){
        System.out.println("People eat");
    }
    // Static member inner class
    abstract class Cat{

    }
    static class Dog{
        String name;
        int age;
        public void show(){
            System.out.println("Carla is a dog");
            // Static classes are static as a whole. Static loading takes place earlier and non static methods take place later, so they cannot be called
            // eat(); //  Static classes cannot call non static methods
        }
    }
    // Non static member inner class
    class Bird{
        String name = "cuckoo";
        // Constructor of non static member inner class
        public Bird(){

        }
        public void sing(){
            System.out.println("I am a bird");
            // The eat method of the object of the Person class, where Person.this. Can be omitted
            Person.this.eat(); // Calling non static properties of an external class
            eat(); // Same as the previous one
            System.out.println(age); // If the internal class and external class properties do not have the same name, there will be no conflict. You can directly omit the calling
        }
        // 4.2.
        // Calling method with duplicate name attribute between inner class and outer class
        public void display(String name){
            System.out.println(name); // The name attribute of the formal parameter of the method
            System.out.println(this.name); // Attribute of internal class: name variable of the class where the display method is located
            System.out.println(Person.this.name); // Attribute of external class: the name variable of the object of the current Person class
        }
    }
    public void method(){
        // Local inner class
        class AA{

        }
    }
    {
        // Local inner class
        class BB{

        }
    }
    public Person(){
        // Local inner class
        class CC{

        }
    }
}
public class InnerClassTest1 {
    // 4.3.
    // Rare in development
    public void method(){
        // Local inner class
        class AA{

        }
    }
    // Returns an object of the class of the Comparable interface
    public Comparable getComparable(){
        // Mode 1:
        // Create a well-known implementation class that implements the Comparable interface: the local inner class
        /*class MyComparable implements Comparable{
            // Override methods in interfaces
            @Override
            public int compareTo(Object o) {
                return 0;
            }
        }
        // Returns an anonymous object of a named implementation class
        return new MyComparable();*/
        // Method 2: create an anonymous object of an anonymous implementation class (anonymous inner class) that implements the Comparable interface
        // Returns an anonymous object of an interface's anonymous implementation class
        return new Comparable() {
            @Override
            public int compareTo(Object o) {
                return 0;
            }
        };
    }
}
  • One note about the use of local internal classes:
  • In the method of the local inner class (for example: show), if you call the local variable in the method declared by the external class (for example: method) (for example: num),
    This local variable is required to be declared final
  • The external class generates a bytecode file, and the internal class is also an independent bytecode file. The two files correspond to two classes. Because the storage space and life cycle of the two files are different, the external class passes in the attributes of the internal class
    It is equivalent to just a copy (replicated), so the local inner class cannot modify the properties of the outer class
  • jdk7 and earlier: this local variable is required to be explicitly declared final
  • jdk8 and later versions: the final declaration can be omitted
  public void method(){
        int num = 10; // The final keyword is omitted
        class AA{
            public void show(){
                // num = 20; //  An error is reported and cannot be modified
                System.out.println(num);
            }
        }
    }

7. Exception handling

What's the difference between throw and throws?

  • throw indicates the process of throwing an exception class object and generating an exception class object. Life is in the method body
  • throws is a way of handling exceptions, which is declared at the declaration of the method

7.1. Exception overview and exception architecture

Examples of common exceptions

1, Exception architecture is inheritance
Top level exception class: java.lang.Throwable
There are the following subclasses:
java.lang.Error: generally, targeted code is not written for processing
java.lang.Exception: you can handle exceptions
Divided into:
Compile time exception (checked exception) (checked)
IOException
FileNotFoundException
ClassNotFoundException
Runtime exception (non checked exception) (unchecked/RuntimeException)
NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
NumberFormatException
InputMmismatchException
ArithmeticException: arithmetic exception
Interview question: what are the common exceptions? Examples

public class ExceptionTest {
    // -----The following are compile time exceptions-----
    // An error will be reported when compiling. If you operate on the command line, an error will be reported when compiling this file with javac.exe,
    // This means that the corresponding bytecode file will not be generated after execution
    @Test
    public void test7() {
        // Read data operation
        // Indicates that the file is from hello, and the class needs to import the package
        File file = new File("hello.txt");
        // Create a file stream
        // FileInputStream fis = new FileInputStream(file);
        // fis read s a byte in the file and stores it
        // int data = fis.read();
        // Judging whether the data is not equal to - 1 involves the use of the read method. If - 1 means that the file is at the end, but not - 1, the file still has data
        /*while (data != -1) {
            // Output data, read here is a byte
            System.out.println((char) data); // If a is written in the file, 97 is output here, so it is strongly converted to char type
            // Iteration conditions, see if the next one is - 1, and exit the loop at the end of the file
            data = fis.read();
        }*/
    }
    // The fis resource stream will not be automatically collected by the garbage collector after the file object above is executed
    // Like scanner, resources need to be closed explicitly
    // fis.close();

    // -----The following are runtime exceptions-----
    // Try to put it into a source file and run it on the command line. There is no error when compiling when executing javac,
    // The corresponding bytecode file will also be generated. When java is executed, an error will be reported only when it is interpreted. In fact, it is a runtime exception
    // ArithmeticException arithmetic exception: generally, there is a division by 0 operation
    // Any number divided by 0 will get infinite results
    @Test
    public void test6() {
        int a = 10;
        int b = 0;
        System.out.println(a / b);
    }

    // Inputmismatch exception input mismatch exception
    @Test
    public void test5() {
        // Memory leaks may occur if scanner is not closed
        Scanner scanner = new Scanner(System.in); // The standard input stream is used here
        int score = scanner.nextInt();
        System.out.println(score);
        scanner.close(); // Manual shutdown
    }

    // NumberFormatException number conversion exception
    @Test
    public void test4() {
        String str = "123";
        str = "abc"; // In essence, a string is not a numeric type and cannot be forcibly converted to a number
        int num = Integer.parseInt(str);
    }

    @Test
    // ClassCastException type conversion exception
    public void test3() {
        //Object obj = new Date(); //  Upward transformation / polymorphism
        // String str = (String) obj; //  Downward transformation / forced transformation 0
    }

    // IndexOutOfBoundsException
    @Test
    public void test2() {
        // ArrayIndexOutOfBoundsException
        /*int[] arr = new int[10];
        System.out.println(arr[10]);*/
        // StringIndexOutOfBoundsException
        String str = "abc";
        System.out.println(str.charAt(3));
    }

    // NullPointerException
    @Test
    public void test1() {
        /*int[] arr = null;
        System.out.println(arr[3]);*/
        /*String str = null;
        System.out.println(str.charAt(3));*/
    }
}

7.3. Exception handling mechanism 1: try catch finally

  • Overview of exception handling methods:

Exception handling: grab and throw model

  • Process I:
    • "Throwing": once an exception occurs during the normal execution of the program, an object corresponding to the exception class will be generated at the exception code. (java is object-oriented programming, and each exception is defined as a class.)
      And throw this object to the caller of the program
    • Once an object exception is thrown, the subsequent code will not be executed
  • Process 2:
    • "Catch": it can be understood as the exception handling method: ① try catch finally ② throws
  • Exception handling: try catch method:

2, Use of try catch finally
try{
//Possible exception codes
}Catch (exception type 1 variable name 1){
//How to handle exceptions 1
}Catch (exception type 2 variable name 2){
//How to handle exceptions 2
}Catch (exception type 3 variable name 3){
//How to handle exceptions 3
}
...
finally {/ / keyword, just like the default in the switch loop, does not have to be written
//Code that must execute
}
explain:
1.finally is optional
2. Use try to wrap the possible exception codes in curly braces. Once an exception occurs during execution,
An object corresponding to the exception class will be generated and matched in catch according to the type of this object
3. Once the exception object in the try matches a catch, it will enter the catch for exception processing. Once the processing is completed,
Jump out of the current try catch structure. Even if there is a catch structure matching below, it will not be executed down (without writing finally), and continue to execute the subsequent code
4. If the exception type in catch has no child parent relationship, it doesn't matter who declares it on the top and who declares it on the bottom
If the exception type in catch satisfies the child parent relationship, the child class must be declared on the parent class. Otherwise, an error is reported
5. Common exception object handling methods:
① String getMessage(), print and get exception information
② printStackTrace(), prints the information of the entire stack
6. Variables declared in the try structure cannot be called again after the try structure
7. Try catch finally structure can be nested
Summary: how do you view compile time and run-time exceptions in your code?
Experience 1:
Try catch finally is used to deal with compile time exceptions, so that the program will no longer report errors when compiling, but it may still report errors when running
It is equivalent to using try catch finally to delay an exception that may occur during compilation until it occurs at runtime
Experience 2:
In development, because runtime exceptions are common, we usually don't write try catch finally for runtime exceptions
For compile time exceptions, you must consider exception handling, because compile time exceptions are not handled, compilation cannot pass, and bytecode files cannot be generated

public class ExceptionTest1 {
    // Handling compile time exceptions
    @Test
    public void test2(){
        try {
            File file = new File("hello.ext");
            FileInputStream fis = new FileInputStream(file);
            int data = fis.read();
            while (data != -1){
                System.out.println((char) data);
                data = fis.read();
            }
            fis.close();
            // It doesn't have to run. If there is no hello file, it will still report an operation exception
            // FileNotFoundException is a subclass of IOException, so the two exception handling positions cannot be reversed
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    @Test
    public void test1(){
        // Go on a trip
        String str = "123";
        str = "abc";
        int num = 0; // Assign a value of 0 first to avoid the external call reporting an error. If it is not assigned, the compiler is worried that there is no assignment in the try, and the external variable is equivalent to no initialization, so the external call will report an error
        try { // Package the code that may have exceptions
            // Suddenly I got sick. After I got sick, the virus (abnormal object) appeared
            num = Integer.parseInt(str); // There is an exception here
            // Once an exception occurs in the above statement, an object corresponding to the exception type will be generated and thrown
            System.out.println("hello-1");
            // Then it is captured in the catch, and the exact type matching is entered, so the statements in it are output
            // After output, it is equivalent to handling the exception object
            // Two structures are written side by side
            //NullPointerException and NumberFormatException have no relationship. They are two subclasses of a parent class, and there is no inheritance relationship between them
        }catch (NullPointerException e){ // The e variable is only valid in the current catch. The parent variable can receive objects of any of its subclasses
            // How to handle exceptions
            // Take medicine
            System.out.println("Null pointer exception occurred");
        }catch (NumberFormatException e){
            // Two methods of constant tone in catch
            // getMessage();  Return String type, print and get exception information
            // System.out.println(e.getMessage());
            // (more commonly used) printStackTrace(); If there is no return value, the information of the whole stack is printed
            e.printStackTrace();
            // System.out.println("value conversion exception occurs");
        }catch (Exception e){
            System.out.println("An exception occurred");
        }
        // After processing, the program can continue normally
        // Return to normal
        System.out.println("hello-2");
        // If it is declared outside the try and used for assignment inside the try, no error will be reported
         System.out.println(num); //Variables declared in try cannot be used without try braces
    }
} 
  • finally use:

Use of finally in try catch finally:
1.finally is optional
2.finally declares the code that must be executed. Even if an exception occurs in catch,
There is a return statement in try and a return statement in catch
3. In database connection, input / output stream, network programming Socket and other resources, the jvm cannot recycle automatically. We need to release the resources manually
At this time, the resource release needs to be declared in finally. Why should it be declared in finally? In case the operation of closing or releasing resources is disturbed by the above code, which makes it impossible to execute. Whether there is an exception or not, the resources must be released, so they will be declared in finally

public class FinallyTest {
    @Test
    public void test2(){

        FileInputStream fis = null; // If variables are declared and initialized in the try structure, they cannot be called out of the try structure
        try {
            File file = new File("hello.txt"); // The file path belongs to a relative path
            fis = new FileInputStream(file); // There may be no exceptions, and the creation is successful
            int data = fis.read(); // It is possible to report an exception
            while (data != -1) {
                System.out.println(data);
                fis.read();
            }
            // fis.close(); //  If int data = fis.read(); Only when an exception is reported, it will jump directly to the following to obtain IOException. The closing operation here will be ignored, so it cannot be written here
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                if (fis != null) // Judge whether the fis space is created successfully. If the creation fails, fis is a null pointer. There is no need to release resources. Add a judgment to deal with the null pointer exception
                fis.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    @Test
    public void testMethod(){
        int num = method();
        System.out.println(num);
    }
    // Returns a method of type int
    public int method(){
        try {
            int[] arr = new int[10];
            // System.out.println(arr[10]);
            return 1;
        }catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
            return 2; // If the above output array element has an exception, it will jump to catch the exception, so it should also be returned here
        }finally {
            System.out.println("I will execute it before exiting the method");
            // return 3;
        }
    }
    @Test
    public void test1(){
        // int a = 10;
        // int b = 0;
        // System.out.println(a / b); //  If you output directly without exception handling, an arithmetic exception will be reported
        try {
            int a = 10;
            int b = 0;
            System.out.println(a / b);
        }catch (ArithmeticException e){
//             e.printStackTrace();
            int[] arr = new int[10]; // If the exception is not handled (wrapped with try), it will exit test1 directly after the exception
            System.out.println(arr[10]);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // The exception must be the code that will be executed before exiting the method
            System.out.println("I'm so handsome");
        }
        // If the program exits abnormally, it will not be executed, and the method will terminate when the program is abnormal
        System.out.println("I'm so handsome!!");
    }
}
  • Different handling of compile time and run-time exceptions

Experience 2: in development, since runtime exceptions are common, we usually don't write try catch finally for runtime exceptions
For compile time exceptions, you must consider exception handling, because compile time exceptions are not handled, compilation cannot pass, and bytecode files cannot be generated

7.4. Exception handling: throws mode

Exception handling method 2: throws + exception type
1."throws + exception type" is written at the declaration of the method. It indicates the exception type that may be thrown when the method is executed
Once an exception occurs during the execution of the method body, an object of exception class will still be generated at the exception code. When this object meets the exception type after throws, it will be thrown (equivalent to throwing the pot to others)
It is a little different from try catch finally. There is no so-called finally structure. Exception code and subsequent code will not be executed!
2. Experience: try catch finally: the exceptions are really handled
Throws only throws the exception to the caller of the method. It doesn't really handle the exception

public class ExceptionTest2 {
    public static void main(String[] args) {
        // After handling the exception, you can't throw it up to the main method
        try {
            method2();
        }catch (IOException e){
            e.printStackTrace(); // If the handling methods are different, multiple throws exceptions will be written. If the handling methods are the same, and the exception handling is a child parent relationship, it is not necessary to write multiple throws exceptions
        }
    }
    // If the exception is handled in the method
    public static void method3(){
        try {
            method2();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    // method1 is thrown to the main body of the caller, and now the problem is concentrated on method2
    // method2 can continue to throw up and handle the same exceptions. Just synthesize a parent exception
    public static void method2() throws IOException{
        method1(); // The exception of method1 is thrown to method2. What is thrown is the compile time exception
    }
    // In essence, the exception catch is not killed, but the strategy of throwing up is adopted to let it be handled at a higher level
    public static void method1() throws FileNotFoundException, IOException {
        File file = new File("hello.txt"); // Read file data
        FileInputStream fis = new FileInputStream(file); // Create file stream
        int data = fis.read(); // Do the read operation, read the byte information and store it
        while (data != -1){
            System.out.println((char) data); // Convert to character type to print each byte in the file
            data = fis.read(); // Continue reading the next byte
        }
        fis.close();
        // System.out.println("hahaha!"); //  The code following the exception is no longer executed
    }
}
  • Override the rule thrown by the exception method

One of the rules for method overrides:
The exception type thrown by the method overridden by the subclass shall not be greater than (less than or equal to) the exception type thrown by the method overridden by the parent class

public class OverrideTest {
    public static void main(String[] args) {
        OverrideTest test = new OverrideTest();
        test.display(new SubClass());// new, a subclass object, polymorphism
    }
    // A formal parameter is passed into the declaration of a parent class
    public void display(SuperClass s){
        // The IO exception occurred in the method method is handled
        try {
            // In the case of polymorphism, the method is called through the s object. In fact, the method of subclass rewriting is called
            s.method();
            // The subclass rewriting method also throws an exception. If the subclass throws an exception larger than the parent class, the catch here can't cover it. If the exception is handled, there will be an exception
            // Here, the exception type of catch is the exception type thrown by the parent class
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
// Parent class
class SuperClass{
    // If the method of the parent class does not throw exceptions with throws, the subclass must not throw exceptions with throws
    public void method() throws IOException{

    }
}
// Subclass
class SubClass extends SuperClass{
    // This is an override. The exception of a child class can be as small as a limit as that of the parent class. It's OK to have no exception
    public void method() throws FileNotFoundException {

    }
}
  • How to choose which method to handle exceptions in development

3. How to choose whether to use try catch finally or throws in development?
3.1. If the overridden method in the parent class does not handle exceptions in the throw mode, the overridden method of the child class cannot use throws,
This means that if there is an exception in the method overridden by the subclass, it must be handled in a try catch finally manner
3.2. In the executed method a, several other methods are called successively. These methods are executed in a progressive relationship. It is suggested that these methods be processed in the way of throws. While the executed method a can be processed in the way of try catch finally
Progressive relationship. If there is an exception in the front, don't execute it later. It's meaningless
In one method, try catch finally and throws, just choose one to handle exceptions. If both methods are used, throws is meaningless. (for example, if you get well, you have to report to the superior)
Do you want to modify the code when there are real runtime exceptions

7.5. Manually throw exception object: Throw

try automatic throwing, throw manual throwing, catch catch handling, throws let others handle

public class StudentTest {
    public static void main(String[] args) {
        try { // After other methods throw up, they must be solved in the main method
            Student s = new Student();
            s.regist(-1001); // An Exception occurred. The following input statement will not be executed
            System.out.println(s); // If the assignment is not successful, the output is still the initial value
        }catch (Exception e){
            System.out.println(e.getMessage()); // This is equivalent to the get method of message of the object of the exception class
        }
        /*Student s = new Student();
        s.regist(-100);
        System.out.println(s);*/
    }
}
class Student{
    private int id;
    public void regist(int id) { // The exception handling method is reflected here. The exception type object is thrown upward at the method declaration
        if (id > 0){
            this.id = id;
        }else{
            // System.out.println("illegal data input");
            // Manually throw (create) an exception object when the id is negative
            // There is a method called getMessage for exception handling, which is equivalent to that the exception class assigns a value to the message attribute through the constructor. This method is the get method of this attribute. You can get what is written here
            // Run time exception, no error will be reported during compilation, and an error will be reported only after running
            // throw new RuntimeException("the input data is illegal")// This exception has a constructor with formal parameters
            // If you want to handle compile time exceptions, create an Exception object, including runtime and compile time exceptions
            // The formal parameter in the constructor is message
            // throw: after throwing an exception object, you need to handle the thrown object
             throw new RuntimeException("The data entered is illegal"); // Here, you can manually generate an exception object in the method
            // throw new Exception(); //  If you want to handle compile time exceptions, create an exception. You can either try catch or throw + exception type at the method declaration
            // throw new MyException("negative number cannot be entered")// You must throw the object of the exception class
             // Wrong, only the exception system can throw, and other objects cannot throw
            // throw new String("negative number cannot be entered");
        }
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                '}';
    }
}

7.6. User defined exception class

How to customize exception classes?
1. Inherit from the existing exception structure: runtimeException (runtime exception: you can consider not explicitly handling), exception (you must consider explicitly handling compile time exceptions)
2. Provide global constants: serialVersionUID: serial number: only one copy coexists with the class, which can be understood as the unique ID of the class
3. Provide overloaded constructors

// If you want to become an exception, you can inherit the existing exception system; the inheritance relationship is who is a what (parent class)
public class MyException extends Exception{
    static final long serialVersionUID = -703489719074523439L;
    // Define an empty parameter constructor
    public MyException(){

    }
    // Define a constructor with parameters. The message in the formal parameter is not an attribute defined by itself, but in the parent class
    public MyException(String msg){
        super(msg);// So just make a call about the parent class
    }
}
  • Exception handling exercise: basic usage
public class ReturnExceptionDemo {
    public static void main(String[] args) {
        try {
            methodA();
        } catch (Exception e) {
            System.out.println(e.getMessage());// Get the value of the message attribute
        }
        methodB();
    }
    public static void methodA() {
        try {
            System.out.println("Entry method A"); //1
            // Assign a value to the attribute of message through the constructor of the exception class
            throw new RuntimeException("Manufacturing exception"); //3
        }finally{
            System.out.println("use A Methodical finally"); //2
        }
    }
    public static void methodB(){
        try {
            System.out.println("get into B method");
            return;
            // In case there is a runtime exception in the try, the runtime exception can not be handled. You can not write catch. Finally, it will ensure that the code will be executed
        }finally{
            System.out.println("call B Methodical finally");
        }
    }
}

-Comprehensive exercise of exception handling:

  public class EcmDef {
    // Receive the parameters of the command line and receive them from the formal parameters of the main method
    public static void main(String[] args) {
        try {
            // Because args is of String type, type conversion is required
            // There may be a problem with the conversion,
            int i = Integer.parseInt(args[0]);
            int j = Integer.parseInt(args[1]);
            int result = ecm(i, j);// If the calling method needs to pass in the entity value, it needs to take the formal parameter of main
            System.out.println(result);
        }catch(NumberFormatException e){
            System.out.println("Inconsistent data type");
        }
        // Missing command line parameters, write less or none
        catch (ArrayIndexOutOfBoundsException e){
            System.out.println("Missing command line argument");
        }catch (ArithmeticException e){
            System.out.println("Divide by 0");
        }catch (EcDef e){
            System.out.println(e.getMessage());
        }
    }
    // Define an exception method (ecm) in the main class to divide two numbers
    public static int ecm(int i, int j) throws EcDef{
        if (i < 0 || j < 0){
            // Create a custom exception object. If this object is a non runtime exception, you need to handle the exception at the method declaration
            throw new EcDef("The numerator or denominator is negative");
        }
        return i / j;
    }
}
// Custom exception class
public class EcDef extends Exception{
    static final long serialVersionUID = -3387515324124229948L;
    // Provides an empty argument constructor
    public EcDef(){

    }
    // Provide a constructor with parameters,
    public EcDef(String msg){
        super(msg); // Call the properties of the parent class
    }
}

Topics: Java Back-end JavaSE