Advanced Object-Oriented Programming in Java

class variables and class methods

Class Variables - Ask Questions

Define a variable count in the main method. When a child joins the game, count++, and the last count records how many children play the game.

problem analysis:

Count is an object independent, which is very embarrassing. It will be very troublesome for us to access count in the future, and OOP is not used. Therefore, we introduce class variables/static variables.

package com.hspedu.static_;

public class ChildGame {
    
    

    public static void main(String[] args) {
    
    

        //定义一个变量 count, 统计有多少小孩加入了游戏
        int count = 0;

        Child child1 = new Child("白骨精");
        child1.join();
        //count++;
        child1.count++;

        Child child2 = new Child("狐狸精");
        child2.join();
        //count++;
        child2.count++;

        Child child3 = new Child("老鼠精");
        child3.join();
        //count++;
        child3.count++;

        //===========
        // 类变量,可以通过类名来访问
        System.out.println("共有" + Child.count  + " 小孩加入了游戏...");
        // 下面的代码输出什么?
        System.out.println("child1.count=" + child1.count);//3
        System.out.println("child2.count=" + child2.count);//3
        System.out.println("child3.count=" + child3.count);//3



    }
}

class Child {
    
     //类
    private String name;
    // 定义一个变量 count ,是一个类变量(静态变量) static 静态!!!
    // 该变量最大的特点就是会被 Child 类的所有的对象实例共享!!!
    public static int count = 0;
    public Child(String name) {
    
    
        this.name = name;
    }
    public void join() {
    
    
        System.out.println(name + " 加入了游戏..");
    }
}

class variable memory layout

https://blog.csdn.net/x_iya/article/details/81260154/

https://www.zhihu.com/question/59174759/answer/163207831

Some books say that in the method area... the jdk version is related, remember two points:

(1) static variables are shared by all objects of the same class

(2) Static class variables are generated when the class is loaded. Static variables are created when the class is loaded, so they can be 类名.类变量名accessed

What is a class variable

Class variables are also called static variables/static attributes. They are variables shared by all objects of this class. When any object of this class accesses it, it gets the same value. Similarly, any object of this class modifies it. , the same variable is modified. This can also be seen from the previous figure.

How to define class variables

Definition syntax:

Access modifier static data type variable name; [recommended]

static access modifier data type variable name;

How to access class variables

classname.classvariablename

Or object name. Class variable name [The access rights and scope of access modifiers of static variables are the same as those of ordinary properties]

Recommended use: class name. class variable name;

Notes on using class variables

1. When do you need to use class variables

When we need to let all objects of a certain class share a variable, we can consider using class variables (static variables): for example: define the student class, and count how much all students pay. Student (name, static fee)

2. The difference between class variables and instance variables (ordinary attributes)

Class variables are shared by all objects of the class, while instance variables are exclusive to each object.

3. Adding static is called class variable or static variable, otherwise it is called instance variable/ordinary variable/non-static variable

4. Class variables can be accessed through class name. class variable name or object name. class variable name, but java designers recommend that we use class name. class variable name to access. [The premise is that the access rights and scope of the access modifier are satisfied]

5. Instance variables cannot be accessed through class name. class variable name.

6. The class variable is initialized when the class is loaded, that is to say, even if you do not create an object, as long as the class is loaded, you can use the class variable.

7. The life cycle of class variables starts with the loading of the class and is destroyed with the demise of the class.

Basic introduction to class methods

Class methods are also called static methods. The form is as follows:

Access modifier static data return type method name (){} [recommended]

static access modifier data return type method name(){}

class method call

How to use:

Class name. Class method name or object name. Class method name

package com.hspedu.static_;

public class StaticMethod {
    
    
    public static void main(String[] args) {
    
    
        //创建2个学生对象,叫学费
        Stu tom = new Stu("tom");
        //tom.payFee(100);
        Stu.payFee(100);//对不对?对

        Stu mary = new Stu("mary");
        //mary.payFee(200);
        Stu.payFee(200);//对


        //输出当前收到的总学费
        Stu.showFee();//300

        //如果我们希望不创建实例,也可以调用某个方法(即当做工具来使用)
        //这时,把方法做成静态方法时非常合适
        System.out.println("9开平方的结果是=" + Math.sqrt(9));


        System.out.println(MyTools.calSum(10, 30));
    }
}
//开发自己的工具类时,可以将方法做成静态的,方便调用
class MyTools  {
    
    
    //求出两个数的和
    public static double calSum(double n1, double n2) {
    
    
        return  n1 + n2;
    }
    //可以写出很多这样的工具方法...
}
class Stu {
    
    
    private String name;//普通成员
    //定义一个静态变量,来累积学生的学费
    private static double fee = 0;

    public Stu(String name) {
    
    
        this.name = name;
    }
    // 说明
    // 1. 当方法使用了static修饰后,该方法就是静态方法
    // 2. 静态方法就可以访问静态属性/变量
    public static void payFee(double fee) {
    
    
        Stu.fee += fee;//累积到
    }
    public static void showFee() {
    
    
        System.out.println("总学费有:" + Stu.fee);
    }
}

Classic usage scenarios of class methods

When the method does not involve any object-related members, the method can be designed as a static method to improve development efficiency.

for example:

The method utils in the tools class. The Math class, Arrays class, and Collections collection class look at the source code and you can find that they are all static methods.

Precautions and detailed discussion of class method usage

  1. Both class methods and ordinary methods are loaded with the loading of the class, and the structure information is stored in the method area: there is no this parameter in the class method. The this parameter is implied in ordinary methods.

  2. Class methods can be called by the class name or by the object name. Ordinary methods are related to objects, and need to be called by object name, such as object name. method name (parameter), and cannot be called by class name.

  3. Object-related keywords , such as this and super, are not allowed in class methods. Ordinary methods (member methods) do.

  4. Only static variables or static methods can be accessed in class methods (static methods) . Ordinary member methods can access both non-static members and static members!!

package com.hspedu.static_;

public class StaticMethodDetail {
    
    
    public static void main(String[] args) {
    
    

        D.hi();//ok
        //非静态方法,不能通过类名调用
        //D.say();, 错误,需要先创建对象,再调用
        new D().say();//可以
    }
}
class D {
    
    

    private int n1 = 100;
    private static  int n2 = 200;
    public void say() {
    
    //非静态方法,普通方法

    }

    public static  void hi() {
    
    //静态方法,类方法
        //类方法中不允许使用和对象有关的关键字,
        //比如this和super。普通方法(成员方法)可以。
        //System.out.println(this.n1);
    }

    //类方法(静态方法)中 只能访问 静态变量 或静态方法
    //口诀:静态方法只能访问静态成员.
    public static void hello() {
    
    
        System.out.println(n2);
        System.out.println(D.n2);
        //System.out.println(this.n2);不能使用
        hi();//OK
        //say();//错误
    }
    //普通成员方法,既可以访问  非静态成员,也可以访问静态成员
    //小结: 非静态方法可以访问 静态成员和非静态成员
    public void ok() {
    
    
        //非静态成员
        System.out.println(n1);
        say();
        //静态成员
        System.out.println(n2);
        hello();

    }
}

practise:

package com.hspedu.static_;

public class StaticExercise03 {
    
    
}

class Person {
    
    
    private int id;
    private static int total = 0;
    public static void setTotalPerson(int total){
    
    
        // this.total = total;//错误,因为在static方法中,不可以使用this 关键字

        Person.total = total;
    }
    public Person() {
    
    //构造器
        total++;
        id = total;
    }
    //编写一个方法,输出total的值
    public static void m() {
    
    
        System.out.println("total的值=" + total);
    }
}
class TestPerson {
    
    
    public static void main(String[] args) {
    
    

        Person.setTotalPerson(3); // 这里没有调用构造器
        new Person(); // new了之后调用构造器,count++
        Person.m();// 最后 total的值就是4
    }
}

Notice:

Person.setTotalPerson(3); Call the static method here has not yet called the constructor

new Person(); call the constructor after new, count++

Because the constructor completes the initialization of the object when the object is created.

Understand the main method syntax

In-depth understanding of the main method

Explain the form of the main method:public static void main(String[] args){}

1. When the main method is called by the virtual machine

2. The java virtual machine needs to call the main() method of the class, so the access permission of this method must be public

3. The java virtual machine does not need to create an object when executing the main() method, so the method must be static

4. This method receives an array parameter of String type, which stores the parameters passed to the running class when executing the java command. Case demonstration, receiving parameters.

5. The program parameter 1 parameter 2 parameters executed by java.

Description: How to pass parameters in idea?

Just pass in parameters in Program arguments.

Special Note

In the main() method, we can directly call the static method or static property of the class where the main method is located. However, you cannot directly access the non-static members of the class. You must create an instance object of the class before you can access the non-static members of the class through this object.

code block

basic introduction

Coding blocks, also known as initialization blocks, belong to members of the class [that is, part of the class], similar to methods, encapsulating logic statements in the method body and enclosing them.

But unlike a method, there is no method name, no return, no parameters, only the method body , and it does not need to be explicitly called through the object or class, but implicitly called when the class is loaded, or when the object is created .

basic grammar

[修饰符]{
    
    
   代码
};

note note;

  1. The modifier is optional, if you want to write, you can only write static

  2. Code blocks are divided into two categories, those with static decoration are called static code blocks, and those without static decoration are called ordinary code blocks/non-static code blocks.

  3. The logic statement can be any logic statement (input, output, method call, loop, judgment, etc.)

  4. The ; sign can be written or omitted.

Benefits of Code Blocks and Case Demos

  1. Equivalent to another form of constructor (a supplementary mechanism to the constructor), which can perform initialization operations

  2. Scenario: If there are repeated statements in multiple constructors, they can be extracted into the initialization block to improve code reusability

In this way, no matter which constructor we call to create an object, the content of the code block will be called first, and the order of calling the code block takes precedence over the constructor.

package com.hspedu.codeblock_;

public class CodeBlock01 {
    
    
    public static void main(String[] args) {
    
    
        Movie movie = new Movie("你好,李焕英");
        System.out.println("===============");
        Movie movie2 = new Movie("唐探3", 100, "陈思诚");
    }
}

class Movie {
    
    
    private String name;
    private double price;
    private String director;

    // 3个构造器-》重载
    {
    
    
        System.out.println("电影屏幕打开...");
        System.out.println("广告开始...");
        System.out.println("电影正是开始...");
    };

    public Movie(String name) {
    
    
        System.out.println("Movie(String name) 被调用...");
        this.name = name;
    }

    public Movie(String name, double price) {
    
    

        this.name = name;
        this.price = price;
    }

    public Movie(String name, double price, String director) {
    
    

        System.out.println("Movie(String name, double price, String director) 被调用...");
        this.name = name;
        this.price = price;
        this.director = director;
    }
}

Code block usage notes and details discussion!!!

  1. The static code block is also called the static code block. Its function is to initialize the class, and it is executed as the class is loaded , and it will only be executed once. If it is a normal code block, it will be executed every time an object is created.

  2. when the class is loaded

  • When an object instance is created (new)
  • Create a subclass object instance, and the parent class will also be loaded
  • When using static members of a class (static properties, static methods)
  1. Ordinary code blocks are called implicitly when an object instance is created . Once created, it will be called once.

If only static members of the class are used, ordinary code blocks will not be executed. (no object instance created)

  1. When creating an object, the calling sequence in a class is (emphasis, difficulty) :

  2. Call static code block and static attribute initialization (note: static code block and static attribute initialization call have the same priority, if there are multiple static code blocks and multiple static variable initialization, they will be called in the order in which they are defined)

  3. Call the initialization of ordinary code blocks and ordinary attributes (note: the priority of ordinary code blocks and ordinary attribute initialization calls is the same, if there are multiple ordinary code blocks and multiple ordinary attribute initializations, they will be called in the order of definition)

  4. call constructor

  5. The front of the constructor actually implies super() and calling ordinary code blocks , statically related code blocks, attribute initialization, and is executed when the class is loaded, so it is executed prior to the constructor and ordinary code blocks.

  6. When we look at creating a subclass object (inheritance relationship), their calling sequence is as follows :

  7. Static code blocks and static properties of the parent class (same priority, executed in the order of definition) (class loading)

  8. Static code blocks and static properties of subclasses (same priority, executed in the order of definition) (class loading)

  9. Ordinary code blocks of the parent class and ordinary attribute initialization (same priority, executed in the order of definition)

  10. Constructor of parent class

  11. Ordinary code blocks of subclasses and ordinary property initialization (same priority, executed in the order of definition)

  12. Subclass Constructor

  13. Static code blocks (essentially static methods) can only directly call static members (static properties and static methods), and ordinary code blocks (essentially ordinary methods) can call any member.

package com.hspedu.codeblock_;

public class CodeBlockDetail04 {
    
    
    public static void main(String[] args) {
    
    
        //老师说明
        //(1) 进行类的加载
        //1.1 先加载 父类 A02 1.2 再加载 B02
        //(2) 创建对象
        //2.1 从子类的构造器开始
        //new B02();//对象

        new C02();
    }
}

class A02 {
    
     //父类
    private static int n1 = getVal01();
    static {
    
    
        System.out.println("A02的一个静态代码块..");//(2)
    }
    {
    
    
        System.out.println("A02的第一个普通代码块..");//(5)
    }
    pulic int n3 = getVal02();//普通属性的初始化
    public static int getVal01() {
    
    
        System.out.println("getVal01");//(1)
        return 10;
    }

    public int getVal02() {
    
    
        System.out.println("getVal02");//(6)
        return 10;
    }

    public A02() {
    
    //构造器
        //隐藏
        //super()
        //普通代码和普通属性的初始化......
        System.out.println("A02的构造器");//(7)
    }

}

class C02 {
    
    
    private int n1 = 100;
    private static  int n2 = 200;

    private void m1() {
    
    

    }
    private static void m2() {
    
    

    }

    static {
    
    
        //静态代码块,只能调用静态成员
        //System.out.println(n1);错误
        System.out.println(n2);//ok
        //m1();//错误
        m2();
    }
    {
    
    
        //普通代码块,可以使用任意成员
        System.out.println(n1);
        System.out.println(n2);//ok
        m1();
        m2();
    }
}

class B02 extends A02 {
    
     //

    private static int n3 = getVal03();

    static {
    
    
        System.out.println("B02的一个静态代码块..");//(4)
    }
    public int n5 = getVal04();
    {
    
    
        System.out.println("B02的第一个普通代码块..");//(9)
    }

    public static int getVal03() {
    
    
        System.out.println("getVal03");//(3)
        return 10;
    }

    public int getVal04() {
    
    
        System.out.println("getVal04");//(8)
        return 10;
    }
    //一定要慢慢的去品..
    public B02() {
    
    //构造器
        //隐藏了
        //super()
        //普通代码块和普通属性的初始化...
        System.out.println("B02的构造器");//(10)
        // TODO Auto-generated constructor stub
    }
}

practise:

package com.hspedu.codeblock_;

public class CodeBlockExercise02 {
    
    
}

class Sample
{
    
    
    Sample(String s)
    {
    
    
        System.out.println(s);
    }
    Sample()
    {
    
    
        System.out.println("Sample默认构造函数被调用");
    }
}
class Test{
    
    
    Sample sam1=new Sample("sam1成员初始化");//
    static Sample sam=new Sample("静态成员sam初始化 ");//
    static{
    
    
        System.out.println("static块执行");//
        if(sam==null)System.out.println("sam is null");
    }
    Test()//构造器
    {
    
    
        System.out.println("Test默认构造函数被调用");//
    }
    //主方法
    public static void  main(String  str[])
    {
    
    
        Test a=new Test();//无参构造器
    }

}

1. 静态成员sam 初始化
2. static 块执行
3. sam1 成员初始化
4. Test 默认构造函数被调用

singleton design pattern

what is design pattern

Classic use of static methods and properties

Design patterns are the preferred code structure, programming style, and problem-solving way of thinking after summarizing and theorizing in a large number of practices. Design patterns are like classic chess records. We use different chess records for different chess games, so as to save us from thinking and groping ourselves.

What is a singleton pattern

  1. The so-called singleton design pattern of a class is to adopt a certain method to ensure that in the entire software system, there can only be one object instance for a certain class , and this class only provides a method to obtain its object instance.

  2. There are two ways of singleton mode: 1) hungry man style 2) lazy man style

Hungry Chinese style

Proceed as follows:

  1. Constructor privatization = "prevent direct new

  2. object created inside the class

  3. Expose a static public method. getlnstance

Hungry Chinese style: It is possible that this object has not been used yet, but the object has been created due to the mechanism of the class. It has been instantiated before the thread appears, so the hungry Chinese thread must be safe.

package com.hspedu.single_;

public class SingleTon01 {
    
    

    public static void main(String[] args) {
    
    
//        GirlFriend xh = new GirlFriend("小红");
//        GirlFriend xb = new GirlFriend("小白");

        //通过方法可以获取对象
        GirlFriend instance = GirlFriend.getInstance();
        System.out.println(instance);
        // 都是同一个对象
        GirlFriend instance2 = GirlFriend.getInstance();
        System.out.println(instance2);

        System.out.println(instance == instance2);// T 同一个对象
        //System.out.println(GirlFriend.n1);
    }
}

// 有一个类, GirlFriend
// 只能有一个女朋友
class GirlFriend {
    
    

    private String name;
    // public static  int n1 = 100;
    // 为了能够在静态方法中,返回 gf对象,需要将其修饰为static
    // 對象,通常是重量級的對象, 餓漢式可能造成創建了對象,但是沒有使用.
    // 只要类加载了,就一定创建了gf对象
    private static GirlFriend gf = new GirlFriend("小红红");

    // 如何保障我们只能创建一个 GirlFriend 对象
    // 步骤[单例模式-饿汉式]
    // 1. 将构造器私有化
    // 2. 在类的内部直接创建对象(该对象是static)
    // 3. 提供一个公共的static方法,返回 gf 对象
    private GirlFriend(String name) {
    
    
        System.out.println("構造器被調用.");
        this.name = name;
    }

    // 用static的目的就是在不创建对象的前提下直接调用
    public static GirlFriend getInstance() {
    
    
        return gf;
    }

    @Override
    public String toString() {
    
    
        return "GirlFriend{" +
                "name='" + name + '\'' +
                '}';
    }
}

Lazy

Lazy style, only when the user uses getInstance, the cat object is returned, and when called again later, the cat object created last time will be returned.

The lazy style may have thread safety problems.

package com.hspedu.single_;

/**
 * 演示懶漢式的單例模式
 */
public class SingleTon02 {
    
    
    public static void main(String[] args) {
    
    
        //new Cat("大黃");
        //System.out.println(Cat.n1);
        Cat instance = Cat.getInstance();
        System.out.println(instance);


        //再次調用getInstance
        Cat instance2 = Cat.getInstance();
        System.out.println(instance2);

        System.out.println(instance == instance2);//T

    }
}


//希望在程序運行過程中,只能創建一個Cat對象
//使用單例模式
class Cat {
    
    
    private String name;
    public static  int n1 = 999;
    private static Cat cat ; //默認是null

    //步驟
    //1.仍然構造器私有化
    //2.定義一個static靜態屬性對象
    //3.提供一個public的static方法,可以返回一個Cat對象
    //4.懶漢式,只有當用戶使用getInstance時,才返回cat對象, 後面再次調用時,會返回上次創建的cat對象
    //  從而保證了單例
    private Cat(String name) {
    
    
        System.out.println("構造器調用...");
        this.name = name;
    }
    public static Cat getInstance() {
    
    

        if(cat == null) {
    
    //如果還沒有創建cat對象
            cat = new Cat("小可愛");
        }
        return cat;
    }

    @Override
    public String toString() {
    
    
        return "Cat{" +
                "name='" + name + '\'' +
                '}';
    }
}

Compare

  1. The main difference between the two lies in the timing of creating the object: the hungry style creates an object instance when the class is loaded, while the lazy style creates it when it is used.

  2. There is no thread safety problem in the hungry style, but there is a thread safety problem in the lazy style. (After learning the thread later, I will improve it).

  3. There is a possibility of wasting resources in the hungry Chinese style. Because if the programmer does not use a single object instance, the objects created by the hungry style will be wasted, and the lazy style will only be created when it is used, so there is no such problem.

  4. In our javaSE standard class, java.lang.Runtime is the classic singleton pattern.

final keyword

basic introduction

Final Chinese meaning: final, final.

final can modify classes, properties, methods and local variables

In some cases, programmers may use final if they have the following requirements:

  1. When the class is not expected to be inherited, it can be modified with final.

  2. When you do not want a method of the parent class to be overwritten/overridden by the subclass, you can use the final keyword to modify it. [Case demonstration: access modifier final return type method name]

  3. When you do not want the value of an attribute of the class to be modified, you can use final modification. (Example: public final double TAX RATE=0.08)

  4. When you do not want a local variable to be modified, you can use final modification (for example: final double TAX RATE=0.08)

final usage considerations and detailed discussion

  1. Final modified attributes are also called constants, generally named with XX_XX_XX (uppercase)

  2. The final modified attribute must be assigned an initial value when it is defined, and it cannot be modified later. The assignment can be in one of the following positions:

When defining: such as public final double TAX_RATE=0.08;

in the constructor

in the code block

class AA {
    
    
/*
1. 定义时:如public final double TAX_RATE=0.08;
2. 在构造器中
3. 在代码块中
*/
public final double TAX_RATE = 0.08;//1.定义时赋值
public final double TAX_RATE2 ;
public final double TAX_RATE3 ;
public AA() {
    
    //构造器中赋值
    TAX_RATE2 = 1.1;
    }
    {
    
    //在代码块赋值
        TAX_RATE3 = 8.8;
    }
}
  1. If the final modified property is static, the initialization position can only be

① When defining

②In the static code block (cannot be assigned in the constructor. Because the constructor is assigned when the object is created)

  1. Final classes cannot be inherited, but objects can be instantiated. (instantiation is no problem)

  2. If the class is not a final class, but contains a final method, although the method cannot be overridden, it can be inherited. (It is no problem to use subclasses, although they cannot be rewritten)

  3. Generally speaking, if a class is already a final class, there is no need to modify the method into a final method. (Because a class cannot be inherited, it cannot be rewritten accordingly).

  4. final cannot modify the construction method (that is, the constructor).

  5. Final and static are often used together, which is more efficient, because it will not cause class loading , and the underlying compiler has optimized it.

  6. Packaging classes (Integer, Double, Float, Boolean, etc. are all final), and String is also a final class.

abstract class

lead out

When some methods of the parent class need to be declared, but you are not sure how to implement them, you can declare them as abstract methods, then this class is an abstract class.

The so-called abstract method is the method without implementation, the so-called no implementation means that there is no method body.

When there is an abstract method in a class, the class needs to be declared as an abstract class . Generally speaking, an abstract class will be inherited, and its subclasses will implement the abstract method.

abstract class Animal {
    
    
    private String name;

    public Animal(String name) {
    
    
        this.name = name;
    }
    public abstract void eat()  ;
}

Introduction to abstract classes

1) When a class is modified with the abstract keyword, the class is called an abstract class access modifier

2) When the abstract keyword is used to modify a method, the method is an abstract method

访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体

3) The value of the abstract class lies more in the design. After the designer designs, let the subclass inherit and implement the abstract class.

4) Abstract classes are knowledge points that examiners love to ask, and they are often used in frameworks and design patterns.

Precautions and detailed discussions on the use of abstract classes

1) Abstract classes cannot be instantiated

2) Abstract classes do not necessarily contain abstract methods. That is, an abstract class can have no abstract method.

3) Once a class contains an abstract method, the class must be declared as abstract.

4) abstract can only modify classes and methods, not attributes and others.

5) An abstract class can have any members [the essence of an abstract class is still a class], such as: non-abstract methods, constructors, static properties, etc.

6) An abstract method cannot have a subject, that is, it cannot be implemented .

7) If a class inherits an abstract class, it must implement all the abstract methods of the abstract class, unless it itself is also declared as an abstract class.

8) Abstract methods cannot be modified with private, final, and static, because these keywords are contrary to rewriting.

Abstract Class Best Practice - Template Design Pattern

basic introduction

The abstract class embodies the design of a template pattern. The abstract class serves as a general template for multiple subclasses. The subclasses are extended and transformed on the basis of the abstract class, but the subclasses generally retain the behavior of the abstract class.

Problems the template design pattern can solve

1) When part of the internal realization of the function is determined, part of the realization is uncertain. At this time, you can expose the uncertain part and let the subclass implement it.
2) Write an abstract parent class, the parent class provides the common methods of multiple subclasses, and leaves one or more methods for its subclasses to implement, which is a template pattern.

Best Practices

need:

There are multiple classes to complete different tasks job

Require statistics to get the time to complete the task

package com.hspedu.abstract_;

abstract public class Template {
    
     //抽象类-模板设计模式

    public abstract void job();//抽象方法

    public void calculateTime() {
    
    //实现方法,调用job方法
        //得到开始的时间
        long start = System.currentTimeMillis();
        job(); //动态绑定机制
        //得的结束的时间
        long end = System.currentTimeMillis();
        System.out.println("任务执行时间 " + (end - start));
    }
}

The above is to expose the uncertain part and let the subclasses realize it.

interface

basic introduction

The interface is to give some methods that have not been implemented, encapsulate them together, and write out these methods according to the specific situation when a class needs to use them. grammar:

interface 接口名{
    
    
    //属性
    //抽象方法(接口中可以省略abstract关键字)(在jdk8后还可以有静态方法和默认方法)
}

class 类名 implements 接口 {
    
    
    // 自己属性;
    // 自己方法;
    // 必须实现的接口的抽象方法
}

summary:

Interfaces are more abstract classes. Methods in abstract classes can have method bodies, and all methods in interfaces have no method bodies (jdk7.0). The interface embodies the design idea of ​​polymorphism and high cohesion and low coupling in program design.

Special Note: After Jdk8.0, interface classes can have static methods (static) and default methods (default), that is to say, interfaces can have specific implementations of methods.

Discuss in-depth

Say there is a project manager (Duan Yu) who manages three programmers and develops a software function. In order to control and manage the software, the project manager can define some interfaces, which are then implemented by the programmers.

Through the interface, not only can the method name be unified, but also only need to be identified according to the interface when calling.

package com.hspedu.interface_;

public interface DBInterface {
    
     //项目经理

    public void connect();//连接方法
    public void close();//关闭连接
}
package com.hspedu.interface_;
//A程序
public class MysqlDB implements DBInterface {
    
    
    @Override
    public void connect() {
    
    
        System.out.println("连接mysql");
    }

    @Override
    public void close() {
    
    
        System.out.println("关闭mysql");
    }
}
package com.hspedu.interface_;

//B程序员连接Oracle
public class OracleDB implements DBInterface{
    
    

    @Override
    public void connect() {
    
    
        System.out.println("连接oracle");
    }

    @Override
    public void close() {
    
    
        System.out.println("关闭oracle");
    }
}
package com.hspedu.interface_;

public class Interface03 {
    
    
    public static void main(String[] args) {
    
    

        MysqlDB mysqlDB = new MysqlDB();
        t(mysqlDB);
        OracleDB oracleDB = new OracleDB();
        t(oracleDB);
    }

    public static void t(DBInterface db) {
    
    
        db.connect();
        db.close();
    }
}

Notes and Details

  1. Interface cannot be instantiated (new)

  2. All the methods in the interface are public methods, and the abstract methods in the interface do not need to be modified by abstract
    . void aaa(); is actually abstract void aa(); (Similarly, not writing public is also the default public method, so when implementing this method, an error will be reported if not writing public.)

  3. For a common class to implement an interface, all methods of the interface must be implemented.

  4. An abstract class implements an interface without implementing the methods of the interface.

  5. A class can implement multiple interfaces at the same time .

class Timer implements IA, IB{
    
     }
  1. The properties in the interface can only be final, and they are public static final modifiers . For example: int a=1; is actually public static final int a=1; (must be initialized)

  2. The access form of the attribute in the interface: interface name. attribute name

  3. Interfaces cannot inherit other classes, but can inherit multiple other interfaces. (Interfaces cannot implement interfaces)

interface A extends B,C{
    
    }
  1. Interface modifiers can only be public and default, which is the same as class modifiers.

Implementing Interfaces vs Inheriting Classes

When the subclass inherits the parent class, it automatically has the functions of the parent class. If the subclass needs to extend the function, it can be extended by implementing the interface. It can be understood that implementing an interface is a supplement to the java single inheritance mechanism.

  1. Interfaces and inheritance solve different problems

The value of inheritance mainly lies in: solving code reusability and maintainability.

  1. The value of the interface mainly lies in: design, design various specifications (methods), and let other classes implement these methods. more flexible

Interfaces are more flexible than inheritance: Inheritance satisfies the is-a relationship, while interfaces only need to satisfy the like-a relationship.

The interface realizes code decoupling to a certain extent [ie: interface standardization + dynamic binding mechanism]

Interface polymorphism

  1. polymorphic parameters

In the previous Usb interface case, UsbInterface usb can receive both mobile phone objects and camera objects, which embodies interface polymorphism (interface references can point to objects of classes that implement the interface).

package com.hspedu.interface_;

public class InterfacePolyParameter {
    
    
    public static void main(String[] args) {
    
    

        //接口的多态体现
        //接口类型的变量 if01 可以指向 实现了IF接口类的对象实例
        IF if01 = new Monster();
        if01 = new Car();

        // 继承体现的多态
        // 父类类型的变量 a 可以指向 继承AAA的子类的对象实例
        AAA a = new BBB();
        a = new CCC();
    }
}

interface IF {
    
    }
class Monster implements IF{
    
    }
class Car implements  IF{
    
    }

class AAA {
    
    

}
class BBB extends AAA {
    
    }
class CCC extends AAA {
    
    }
2. 多态数组

演示一个案例:给**Usb数组中,存放 Phone 和相机对象**,Phone类还有一个特有的方法call(),请遍历Usb数组,如果是Phone对象,除了调用Usb接口定义的方法外,还需要调用Phone特有方法call。

```java
package com.hspedu.interface_;

public class InterfacePolyArr {
    public static void main(String[] args) {

        //多态数组 -> 接口类型数组
        Usb[] usbs = new Usb[2];
        usbs[0] = new Phone_();
        usbs[1] = new Camera_();
        /*
        给Usb数组中,存放 Phone 和 相机对象,Phone类还有一个特有的方法call(),
        请遍历Usb数组,如果是Phone对象,除了调用Usb 接口定义的方法外,
        还需要调用Phone 特有方法 call
         */
        for(int i = 0; i < usbs.length; i++) {
            usbs[i].work();//动态绑定..
            //和前面一样,我们仍然需要进行类型的向下转型
            if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_
                ((Phone_) usbs[i]).call();
            }
        }
    }
}

interface Usb{
    void work();
}
class Phone_ implements Usb {
    public void call() {
        System.out.println("手机可以打电话...");
    }

    @Override
    public void work() {
        System.out.println("手机工作中...");
    }
}
class Camera_ implements Usb {

    @Override
    public void work() {
        System.out.println("相机工作中...");
    }
}
  1. Interface has polymorphic transfer phenomenon
package com.hspedu.interface_;

/**
 * 演示多态传递现象
 */
public class InterfacePolyPass {
    
    
    public static void main(String[] args) {
    
    
        //接口类型的变量可以指向,实现了该接口的类的对象实例
        IG ig = new Teacher();
        //如果IG 继承了 IH 接口,而Teacher 类实现了 IG接口
        //那么,实际上就相当于 Teacher 类也实现了 IH接口.
        //这就是所谓的 接口多态传递现象.
        IH ih = new Teacher();
    }
}

interface IH {
    
    
    void hi();
}
interface IG extends IH{
    
     }
class Teacher implements IG {
    
    
    @Override
    public void hi() {
    
    
    }
}

inner class

If the definition class is in the local position (in the method/code block) (1) local inner class (2) anonymous inner class
defined in the member position (1) member inner class (2) static inner class

basic introduction

Another class structure is completely nested inside a class. A class that is nested is called an inner class, and a class that nests other classes is called an outer class.

It is the fifth largest member of our class (the five largest members of the class: properties, methods, constructors, code blocks, inner classes ). The biggest feature of inner classes is that they can directly access private properties and can reflect the inclusion between classes Relationship, attention: internal classes are the difficulty of learning, but also the key point. When looking at the underlying source code later, there are a large number of internal classes.

basic grammar

class Outer{
    
     // 外部类
    class Inner{
    
    
        // 内部类
        }
}
class Other{
    
    // 外部其他类
}

Classification of inner classes

Defined locally in the outer class (such as within a method):

  1. Local inner class (with class name)

  2. anonymous inner class (no class name, emphasis!!!)

Defined in the member position of the outer class:

  1. Member inner class (not decorated with static)

  2. Static inner class (decorated with static )

Use of local inner classes

Explanation: The local inner class is defined in the local position of the outer class, such as in a method, and has a class name .

1. You can directly access all members of the external class, including private ones.

2. The access modifier cannot be added, because its status is a local variable. Local variables cannot use modifiers. But you can use final modification, because local variables can also use final.

3. Scope: only in the method or code block that defines it .

4. Local inner classes access members of outer classes [access method: direct access]

5. Outer classes access members of local inner classes

Access method: create an object, then access (note: must be within the scope)

summary:

(1) The local inner class is defined in the method/code block
(2) The scope is in the method body or code block
(3) The essence is still a class

6. Other external classes cannot access the local inner class (because the local inner class status is a local variable).

7. If the members of the external class and the local internal class have the same name, the principle of proximity is followed by default. If you want to access the members of the external class, you can use (external class name.this.member) to access.

Here is 外部类名.thisessentially the object of the external class, that is, which object calls n2, then 外部类名.thisit points to that object.

System.out.printin(""外部类的n2=+外部类名.this.n2);
package com.hspedu.innerclass;
/**
 * 演示局部内部类的使用
 */
public class LocalInnerClass {
    
    //
    public static void main(String[] args) {
    
    
        //演示一遍
        Outer02 outer02 = new Outer02();
        outer02.m1();
        System.out.println("outer02的hashcode=" + outer02);
    }
}


class Outer02 {
    
    //外部类
    private int n1 = 100;
    private void m2() {
    
    
        System.out.println("Outer02 m2()");
    }//私有方法
    public void m1() {
    
    //方法
        //1.局部内部类是定义在外部类的局部位置,通常在方法
        //3.不能添加访问修饰符,但是可以使用final 修饰
        //4.作用域 : 仅仅在定义它的方法或代码块中
        final class Inner02 {
    
    //局部内部类(本质仍然是一个类)
            //2.可以直接访问外部类的所有成员,包含私有的
            private int n1 = 800;
            public void f1() {
    
    
                //5. 局部内部类可以直接访问外部类的成员,比如下面 外部类n1 和 m2()
                //7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,
                //   使用 外部类名.this.成员)去访问
                //  Outer02.this 本质就是外部类的对象, 即哪个对象调用了m1, Outer02.this就是哪个对象
                System.out.println("n1=" + n1 + " 外部类的n1=" + Outer02.this.n1);
                System.out.println("Outer02.this hashcode=" + Outer02.this);
                m2();
            }
        }
        //6. 外部类在方法中,可以创建Inner02对象,然后调用方法即可
        Inner02 inner02 = new Inner02();
        inner02.f1();
    }
}

Use of Anonymous Inner Classes!!!

(1) The essence is a class (2) Internal class (3) The class has no name (4) It is also an object

Explanation: An anonymous inner class is defined in a local location of the outer class, such as a method, and has no class name

1. Basic syntax of anonymous inner class

new 类或接口 (参数列表){
    
    
   类体
);
package com.hspedu.innerclass;


/**
 * 演示匿名内部类的使用
 */
public class AnonymousInnerClass {
    
    
    public static void main(String[] args) {
    
    
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}

class Outer04 {
    
     //外部类
    private int n1 = 10;//属性
    public void method() {
    
    //方法
        //基于!!!接口!!!的匿名内部类
        //解读
        //1.需求:想使用IA接口,并创建对象
        //2.传统方式,是写一个类,实现该接口,并创建对象
        //3.需求是 Tiger/Dog 类只是使用一次,后面再不使用
        //4. 可以使用匿名内部类来简化开发
        //5. tiger的编译类型 ? IA
        //6. tiger的运行类型 ? 就是匿名内部类  Outer04$1
        /*
            我们看底层 会分配 类名 Outer04$1
            class Outer04$1 implements IA {
                @Override
                public void cry() {
                    System.out.println("老虎叫唤...");
                }
            }
         */
        //7. jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1实例,并且把地址
        //   返回给 tiger
        //8. 匿名内部类使用一次,就不能再使用, 但是tiger这个对象就没有限制了。
        IA tiger = new IA() {
    
    
            @Override
            public void cry() {
    
    
                System.out.println("老虎叫唤...");
            }
        };
        System.out.println("tiger的运行类型=" + tiger.getClass());
        tiger.cry();
        tiger.cry();
        tiger.cry();

//        IA tiger = new Tiger();
//        tiger.cry();

        // 演示基于!!!类!!!的匿名内部类
        //分析
        //1. father 编译类型 Father
        //2. father 运行类型 Outer04$2
        //3. 底层会创建匿名内部类
        /*
            具体的实现代码与注释中的代码近似等价
            class Outer04$2 extends Father{
                @Override
                public void test() {
                    System.out.println("匿名内部类重写了test方法");
                }
            }
         */
        //4. 同时也直接返回了 匿名内部类 Outer04$2的对象
        //5. 注意("jack") 参数列表会传递给 Father 构造器
        Father father = new Father("jack"){
    
    
            @Override
            public void test() {
    
    
                System.out.println("匿名内部类重写了test方法");
            }
        };
        System.out.println("father对象的运行类型=" + father.getClass());//Outer04$2
        father.test();

        //基于!!!抽象类!!!的匿名内部类
        Animal animal = new Animal(){
    
    
            @Override
            void eat() {
    
    
                System.out.println("小狗吃骨头...");
            }
        };
        animal.eat();
    }
}

interface IA {
    
    //接口
    public void cry();
}
//class Tiger implements IA {
    
    
//
//    @Override
//    public void cry() {
    
    
//        System.out.println("老虎叫唤...");
//    }
//}
//class Dog implements  IA{
    
    
//    @Override
//    public void cry() {
    
    
//        System.out.println("小狗汪汪...");
//    }
//}

class Father {
    
     //类
    public Father(String name) {
    
     //构造器
        System.out.println("接收到name=" + name);
    }
    public void test() {
    
     //方法
    }
}

abstract class Animal {
    
     //抽象类
    abstract void eat();
}

2. The syntax of an anonymous inner class is rather peculiar, because an anonymous inner class is not only a class definition, but also an object itself, so from a grammatical point of view, it has both the characteristics of defining a class and the characteristics of creating an object. For the previous code Analysis can see this feature, so anonymous inner class methods can be called.

3. You can directly access all members of the outer class, including private ones.

4. The access modifier cannot be added, because its status is a local variable.

5. Scope: Only in the method or code block that defines it.

6. Anonymous inner class - access ----> external class members [access method: direct access]

7. Other external classes - cannot be accessed -----> anonymous inner class (because the anonymous inner class status is a local variable)

8. If the members of the external class and the anonymous internal class have the same name, the anonymous internal class will follow the principle of proximity by default. If you want to access the members of the external class, you can use (external class name.this.member) to access

package com.hspedu.innerclass;

public class AnonymousInnerClassDetail {
    
    
    public static void main(String[] args) {
    
    

        Outer05 outer05 = new Outer05();
        outer05.f1();
        //外部其他类---不能访问----->匿名内部类
        System.out.println("main outer05 hashcode=" + outer05);
    }
}

class Outer05 {
    
    
    private int n1 = 99;

    public void f1() {
    
    
        //创建一个基于类的匿名内部类
        //不能添加访问修饰符,因为它的地位就是一个局部变量
        //作用域 : 仅仅在定义它的方法或代码块中
        Person p = new Person(){
    
    
            private int n1 = 88;
            @Override
            public void hi() {
    
    
                // 可以直接访问外部类的所有成员,包含私有的
                // 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,
                // 默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问
                System.out.println("匿名内部类重写了 hi方法 n1=" + n1 +
                        " 外部内的n1=" + Outer05.this.n1 );
                // Outer05.this 就是调用 f1的 对象
                System.out.println("Outer05.this hashcode=" + Outer05.this);
            }
        };
        p.hi();//动态绑定, 运行类型是 Outer05$1

        //也可以直接调用, 匿名内部类本身也是返回对象
        // class 匿名内部类 extends Person {}
//        new Person(){
    
    
//            @Override
//            public void hi() {
    
    
//                System.out.println("匿名内部类重写了 hi方法,哈哈...");
//            }
//            @Override
//            public void ok(String str) {
    
    
//                super.ok(str);
//            }
//        }.ok("jack");


    }
}

class Person {
    
    //类
    public void hi() {
    
    
        System.out.println("Person hi()");
    }
    public void ok(String str) {
    
    
        System.out.println("Person ok() " + str);
    }
}
//抽象类/接口...

Best Practices for Anonymous Inner Classes

Pass it directly as an actual parameter, which is concise and efficient.

package com.hspedu.innerclass;

import com.hspedu.abstract_.AA;

public class InnerClassExercise01 {
    
    
    public static void main(String[] args) {
    
    

        //当做实参直接传递,简洁高效
        f1(new IL() {
    
    
            @Override
            public void show() {
    
    
                System.out.println("这是一副名画~~...");
            }
        });
        //传统方法
        f1(new Picture());
    }

    //静态方法,形参是接口类型
    public static void f1(IL il) {
    
    
        il.show();
    }
}

//接口
interface IL {
    
    
    void show();
}


//类->实现IL => 编程领域 (硬编码)
class Picture implements IL {
    
    

    @Override
    public void show() {
    
    
        System.out.println("这是一副名画XX...");
    }
}

There is a bell interface Bell, which has a ring method. There is a cell phone class Cellphone, which has the alarm clock function alarmclock, and the parameter is Bell type. Test the alarm clock function of the mobile phone class, and use the anonymous inner class (object) as a parameter to print: the lazy pig has woken up. Then pass in another anonymous inner class (object), print: the little friend is in class

package com.hspedu.innerclass;

public class InnerClassExercise02 {
    
    
    public static void main(String[] args) {
    
    
        /*
        1.有一个铃声接口Bell,里面有个ring方法。(右图)
        2.有一个手机类Cellphone,具有闹钟功能alarmClock,参数是Bell类型(右图)
        3.测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
        4.再传入另一个匿名内部类(对象),打印:小伙伴上课了
         */
        CellPhone cellPhone = new CellPhone();
        //老韩解读
        //1. 传递的是实现了 Bell接口的匿名内部类 InnerClassExercise02$1
        //2. 重写了 ring
        //3. Bell bell = new Bell() {
    
    
        //            @Override
        //            public void ring() {
    
    
        //                System.out.println("懒猪起床了");
        //            }
        //        }
        cellPhone.alarmClock(new Bell() {
    
    
            @Override
            public void ring() {
    
    
                System.out.println("懒猪起床了");
            }
        });

        cellPhone.alarmClock(new Bell() {
    
    
            @Override
            public void ring() {
    
    
                System.out.println("小伙伴上课了");
            }
        });
    }
}
interface Bell{
    
     //接口
    void ring();//方法
}
class CellPhone{
    
    //类
    public void alarmClock(Bell bell){
    
    //形参是Bell接口类型
        System.out.println(bell.getClass());
        bell.ring();//动态绑定
    }
}

Use of member inner classes

Explanation: The member inner class is defined in the member position of the outer class, and there is no static modification.

1. You can directly access all members of the external class, including private ones.

2. You can add any access modifier (public, protected, default, private), because its status
is a member.

3. The scope is the same as other members of the external class. For the entire class body such as the previous case, create a member internal class object in the member method of the external class, and then call the method.

4. Member inner class—access---->external class member (for example: attribute) access method: direct access

5. External class - access ------> member internal class (description) access method: create an object, and then access

6. Other external classes - access ----> member inner class

7. If the members of the external class and the internal class have the same name, the internal class access will follow the principle of proximity by default. If you want to access the members of the external class, you can use (external class name.this.member) to access

package com.hspedu.innerclass;

public class MemberInnerClass01 {
    
    
    public static void main(String[] args) {
    
    
        Outer08 outer08 = new Outer08();
        outer08.t1();

        //外部其他类,使用成员内部类的三种方式
        // 第一种方式
        // outer08.new Inner08(); 相当于把 new Inner08()当做是outer08成员
        // 这就是一个语法,不要特别的纠结.
        Outer08.Inner08 inner08 = outer08.new Inner08();
        inner08.say();
        // 第二方式 在外部类中,编写一个方法,可以返回 Inner08对象
        Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
        inner08Instance.say();


    }
}

class Outer08 {
    
     //外部类
    private int n1 = 10;
    public String name = "张三";

    private void hi() {
    
    
        System.out.println("hi()方法...");
    }

    //1.注意: 成员内部类,是定义在外部内的成员位置上
    //2.可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
    public class Inner08 {
    
    //成员内部类
        private double sal = 99.8;
        private int n1 = 66;
        public void say() {
    
    
            //可以直接访问外部类的所有成员,包含私有的
            //如果成员内部类的成员和外部类的成员重名,会遵守就近原则.
            //,可以通过  外部类名.this.属性 来访问外部类的成员
            System.out.println("n1 = " + n1 + " name = " + name + " 外部类的n1=" + Outer08.this.n1);
            hi();
        }
    }
    //方法,返回一个Inner08实例
    public Inner08 getInner08Instance(){
    
    
        return new Inner08();
    }


    //写方法
    public void t1() {
    
    
        //使用成员内部类
        //创建成员内部类的对象,然后使用相关的方法
        Inner08 inner08 = new Inner08();
        inner08.say();
        System.out.println(inner08.sal);
    }
}

Use of static inner classes

Explanation: The static inner class is defined in the member position of the outer class, and has static modification

1. You can directly access all static members of the external class, including private ones, but you cannot directly access non-static members.

2. Any access modifier (public. protected, default, private) can be added, because its status is a member.

3. Scope: Like other members, it is the entire class body.

4. Static inner class - access ----> outer class (eg: static properties) [access method: direct access to all static members].

5. External class—access ------> Static internal class access method: create an object, and then access.

6. External Other Classes—Access -----> Static Inner Classes.

7. If the members of the external class and the static internal class have the same name, when the static internal class is accessed, the proximity principle is followed by default. If you want to access the members of the external class, you can use (external class name. member) to access.

package com.hspedu.innerclass;

public class StaticInnerClass01 {
    
    
    public static void main(String[] args) {
    
    
        Outer10 outer10 = new Outer10();
        outer10.m1();

        //外部其他类 使用静态内部类
        //方式1
        //因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
        Outer10.Inner10 inner10 = new Outer10.Inner10();
        inner10.say();
        //方式2
        //编写一个方法,可以返回静态内部类的对象实例.
        Outer10.Inner10 inner101 = outer10.getInner10();
        System.out.println("============");
        inner101.say();

        Outer10.Inner10 inner10_ = Outer10.getInner10_();
        System.out.println("************");
        inner10_.say();
    }
}

class Outer10 {
    
     //外部类
    private int n1 = 10;
    private static String name = "张三";
    private static void cry() {
    
    }
    //Inner10就是静态内部类
    //1. 放在外部类的成员位置
    //2. 使用static 修饰
    //3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
    //4. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
    //5. 作用域 :同其他的成员,为整个类体
    static class Inner10 {
    
    
        private static String name = "Timerring";
        public void say() {
    
    
            //如果外部类和静态内部类的成员重名时,静态内部类访问的时,
            //默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.成员)
            System.out.println(name + " 外部类name= " + Outer10.name);
            cry();
        }
    }

    public void m1() {
    
     //外部类---访问------>静态内部类 访问方式:创建对象,再访问
        Inner10 inner10 = new Inner10();
        inner10.say();
    }

    public Inner10 getInner10() {
    
    
        return new Inner10();
    }

    public static Inner10 getInner10_() {
    
    
        return new Inner10();
    }
}

classroom test questions

Judgment output:

package com.hspedu.innerclass;

public class InnerClassExercise {
    
    
    public static void main(String[] args) {
    
    

    }
}

class Test {
    
    //外部类

    public Test() {
    
    //构造器
        Inner s1 = new Inner();
        s1.a = 10;
        Inner s2 = new Inner();
        System.out.println(s2.a);
    }

    class Inner {
    
     //内部类,成员内部类
        public int a = 5;
    }

    public static void main(String[] args) {
    
    
        Test t = new Test();
        Inner r = t.new Inner();//5
        System.out.println(r.a);//5
    }
}

Articles and codes have been archived in [Github warehouse: https://github.com/timerring/java-tutorial] or the public account [AIShareLab] can also be obtained by replying to java .

Guess you like

Origin blog.csdn.net/m0_52316372/article/details/130213691