Day13 Java inner class, anonymous inner class and common class Object

Posted by james182 on Tue, 18 Jan 2022 22:45:09 +0100

Internal class:

Overview of internal classes: if a class is defined inside other classes, this class is called an internal class.

Access characteristics of internal classes:

Internal classes can directly access members of external classes, including private classes.

An external class must create an internal class object to access members of an internal class.

According to the different positions of the internal class defined in the class, it can be divided into the following two formats:

Member location: member inner class

Local location: local inner class

Member inner class:

1. Defined on the member location of the class

2. Internal classes can access members of external classes, including private ones.

If you want to access the methods in the member's internal class in the test class, you must create an object.

Format for correctly creating class objects within members:

External class name Member internal class name object name = new external class name () Internal class name ();

Outer.Inner inner = new Outer().new Inner();

//    External class
class Outer{
    private int num=10;
//    Inner class
    class Inner{
        public void fun(){
            System.out.println(num);
        }
    }
//The Inner class here is the member Inner class. If you put it in fun(), it will become a local Inner class
}

public class Demo{
    public static void main(){
//        Create an internal class object
        Outer.Inner inner = new Outer().new Inner();
        inner.fun();
/*
    This format for creating objects is equivalent to:
        Outer outer = new Outer();
        outer.Inner inner = outer.new Inner();
        inner.fun();
*/
    }
}

Naturally, the output result can successfully access the fun() method in the Inner class, and output 10

Common modifiers for member inner classes:

Private: other classes cannot directly create objects of internal classes. If you want to use internal class members modified by private, you must indirectly create object calls in this class.

Static: if the inner class is modified by static, only static members in the outer class can be accessed. At the same time, there is another way to create internal classes:

When an internal class is statically decorated, another format for creating an internal class is:

External class name Internal class name object name = new external class name Internal class name ();

Outer.Inner inner = new Outer.Inner();

At the same time, when calling the fun method, you can directly call it with the class name:

Outer.Inner.fun();

Access different member variables in internal classes through different access methods:

class Outer2{
    public int num=10;
        class Inner2{
            public int num=20;
            public void fun(){
                int num=30;
                System.out.println(num);
//                Output 30
                System.out.println(this.num);
//                Access num in this class. Output 20
//                There are two ways to access member num in Outer:
                System.out.println(new Outer2().num);
//                Access num in Outer2 by creating an object. Output 10
//                super cannot be used here because Outer2 and Inner2 are not inherited
                System.out.println(Outer2.this.num);
//                By accessing this. In Outer Num, also output 10
            }
        }
}
public class Test2Demo {
    public static void main(String[] args) {
        Outer2.Inner2 inner=new Outer2().new Inner2();
        inner.fun();
    }
}

Local inner class:

1. Classes defined in methods

2. A local inner class has direct access to all members in the outer class

3. To use the methods of a local inner class, create a local inner class object and call the method in the member method that defines the local inner class.

Local cases:

class Out{
    private int num=10;

    public void fun(){
        int num2=20;
        class Inner{
            int num=30;
            public void show(){
                System.out.println(num);
                System.out.println(num2);            
//                num2=34;
/*
      The local variable referenced in the local inner class must be the final variable or the actual final variable
      Because variables defined in methods that exist in local inner classes are automatically added with the final keyword
      That is, int num2=30; In fact, the complete code should be: final int num2=30; Therefore, the value cannot be changed
      At jdk1 After 8, the final keyword will be added automatically
*/        
                num=44;
                System.out.println(num);
            }
        }
        Inner i=new Inner();
        i.show();
    }

Output result:

Anonymous inner class:

It is the abbreviation of local inner class. The premise for the existence of anonymous inner class:

There needs to be a class or interface, which can be abstract or concrete.

Statement definition format:

new class name (can be abstract or concrete) / interface (){

The method to override;

};

Example: new Inter(){

        public void show(){. . . }

};

Create object cases using anonymous inner classes:

interface Inter {
    public abstract void show();
    public abstract void show2();
}

/*
  The initial approach is to define a class to implement the interface, and then use polymorphism to create objects and call methods
class B implements Inter{

    @Override
    public void show() {
        System.out.println("This is the show method "");
    }

    @Override
    public void show2() {
        System.out.println("This is the show2 method "");
    }
}
    Inter inter=new B();
*/

class Outer3{
    public void fun(){
//        Use anonymous inner classes to create objects and implement methods in the interface inter
        new Inter(){

            @Override
            public void show() {
                System.out.println("This is show method");
            }

            @Override
            public void show2() {
                System.out.println("This is show2 method");
            }
        }.show();
//        Create an object by using an anonymous inner class and call the show method
        new Inter(){

            @Override
            public void show() {
                System.out.println("This is show method");
            }

            @Override
            public void show2() {
                System.out.println("This is show2 method");
            }
        }.show2();
//        Create an object by using an anonymous inner class and call the show2 method
/*        When you need to use anonymous inner classes to call methods in the future,
          If there are many methods, you need to create a lot of space, which is very troublesome, so give the anonymous inner class a name
          Use the form of interface polymorphism to name
*/
        Inter inter = new Inter() {
            @Override
            public void show() {
                System.out.println("This is show method");
            }

            @Override
            public void show2() {
                System.out.println("This is show2 method");
            }
        };
        inter.show();
        inter.show2();
    }
}
public class Test4Demo {
    public static void main(String[] args) {
        Outer3 outer3=new Outer3();
        outer3.fun();
    }
}

Output results:

This is the show method
This is the show2 method
This is the show method
This is the show2 method

Use of anonymous inner classes in development:

//Define an interface
interface Human{
    public abstract void sleep();
}

class Man{
    Human human;//Member variable whose data type is interface type

    public Man() {
    }

    public Man(Human human) {//Parametric structure
        this.human = human;
    }
    public void run(Human human){//The formal parameter is an interface type
        human.sleep();
    }
}

public class Test5Demo {
    public static void main(String[] args) {
//        Use anonymous inner classes to create objects and implement interfaces, and call sleep
        Human human =new Human(){

            @Override
            public void sleep() {
                System.out.println("Break your sleep quickly. Life matters");
            }
        };
        human.sleep();
//        Use anonymous inner class objects to pass parameters (construct methods to create objects and call run methods)
        Man man= new Man(new Human(){

            @Override
            public void sleep() {
                System.out.println("This is the construction method with parameters");
            }
        });
        man.run(new Human() {
            @Override
            public void sleep() {
                System.out.println("Break your sleep quickly. Life matters");
            }
        });
//        Improvement: objects are still created using parameterized constructs, but using chained programming:
        new Man(new Human(){

            @Override
            public void sleep() {
                System.out.println("This is the construction method with parameters");
            }
        }).run(new Human() {
            @Override
            public void sleep() {
                System.out.println("Break your sleep quickly. Life matters");
            }
        });
//        Another way to write: access the sleep method through the member variable in the Man class
        new Man(new Human() {
            @Override
            public void sleep() {
                System.out.println("This is the construction method with parameters");
            }
        }).human.sleep();

    }
}

Anonymous inner class complement code example:

 interface Inter { void show(); }

class Outer {

/ / supplement the code

}

class OuterDemo {

         public static void main(String[] args) {

                 Outer.method().show();

         }

}"HelloWorld" is required to be output on the console

analysis:

1, according to the code invoked in the main method, the method method is static, and can be directly invoked through the class name.

2, according to the show method in the interface and after calling the method method in the mian method, you can continue to call show. It can be promoted that the method method has a return value and the return value is exactly the interface Inter type.

3. The formal parameter of method method is null, so the method method has no parameters

The complete code is as follows: here, the anonymous inner class is directly used to create the object, implement the interface and return

interface Inter2{
    void show();
}

class Outer8{
//---------Supplement the code part---------------------------
    public static Inter2 method(){
        return new Inter2() {
            @Override
            public void show() {
                System.out.println("HelloWorld");
            }
        };

    }
//=========Supplement code part===========================
}

public class InnerClassDemo9 {
    public static void main(String[] args) {
        Outer8.method().show();
    }
}

Common classes:

Relative path: take the current project as the root directory (test.Test.src.com.changyonglei)

Absolute path / full path: with drive letter: (D:\IdeaProjects\src\test\Test\src\com\changyonglei\Student.java)

Object class:

Explanation in the Java help document:

Object:Class Object is the root of the class object structure. Each class has object as its superclass. All objects (including arrays) implement the methods of this class. Each class in java directly or indirectly inherits the object class

Methods in Object class:

public int hashCode(): returns the hash code value of the object. This method is supported for hash tables, as provided by HashMap.

Note: the hash code value here is a value calculated according to the hash algorithm. This value is related to the address, but the address value returned here is not the actual address value. Now it is simply understood as another form of address value.

public final Class getClass(): returns the class object of the object

Returns the runtime class of this Object. The returned class Object is an Object locked by the static synchronized method representing the class.

public class StduentTest {
    public static void main(String[] args) {
        Student s1 = new Student();
        System.out.println(s1.hashCode()); // 1163157884
        Student s2 = new Student();
        System.out.println(s2.hashCode()); // 1956725890
        Student s3 = s1;
        System.out.println(s3.hashCode()); // 1163157884
        System.out.println("=========================================");
        Student s4 = new Student();
        System.out.println(s4.getClass()); 
//        class test.Test.src.com.changyonglei.Student

        Class studentClass = s4.getClass();
//      Returns the name of the entity represented by the class object (class, interface, array class, primitive type or void) as a String.
        System.out.println(studentClass.getName());
//        test.Test.src.com.changyonglei.Student 

        //Chain programming
        System.out.println(s4.getClass().getName());
//        test.Test.src.com.changyonglei.Student


    }
}

public String toString() returns the string representation of the object.

Generally speaking, the toString method returns a string that "textually represents" the object.

The result should be a concise expression that is easy to read. It is recommended that all subclasses override this method.

The toString class method Object returns an unsigned hexadecimal representation of the Object in which the Object is an instance, the string @ "of the class name of the symbolic character ` and the hash code of the Object.

In other words, this method returns a string equal to the following values:

getClass().getName() + '@' + Integer.toHexString(hashCode())

Simple understanding: the actual meaning of toString before rewriting is:

The string of the class name of the symbol character + the character '@' + the address value of the object

Integer: public static String toHexString(int i): returns the string representation of an integer parameter as an unsigned integer in 16 bits. Converts the hash value to an address value.

Although we have mastered the use of the toString() method, the printed result is an address value that we can't understand. In other words, it's meaningless to get the result and return the string representation of the object. In fact, we prefer to see the values of each member variable in the object.

It happens that toString() method is modified by public, and its return value is of String type, so we can override it in other classes

The simple understanding is that after being rewritten, toString means to print the values of each member variable in a class

In the future, it can be generated automatically without handwriting under special circumstances.

Version 4.0 of a standard class:

Member variable: decorated with private keyword

Construction method: a parameterless. A method with all parameters.

Member method: setXxx(...)/getXxx()

toString(): it can be generated automatically instead of our previous show method.

Example after Rewriting:

public class Student2 extends Object {
    private String name;
    private int age;

    public Student2() {
    }

    public Student2(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
//    Overridden toString method   
    @Override
    public String toString() {
        return "Student2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

//    Test class
public class StudentTest2 {
    public static void main(String[] args) {
        Student2 s = new Student2();
        System.out.println(s.toString());
//    Outputs the default value of the member variable in the object s before assignment
        System.out.println("=======================================");
        System.out.println(s.getClass().getName()); 
//    The relative path of the file where the output object s is located
        System.out.println("=======================================");
//    toString() is equivalent to getclass() getName() + '@' + Integer. toHexString(hashCode())
       
//    s.getClass().getName()+'@'+ Integer.toHexString(s.hashCode())

//    this.getClass().getName()+'@'+ Integer.toHexString(this.hashCode())
        System.out.println(s.toString());
        System.out.println(s.getClass().getName()+"@"+Integer.toHexString(s.hashCode()));
//    Outputs the default value of the member variable in the object s before assignment
//    Output relative path + address value of current object
        System.out.println("========================================");
        Student2 s2 = new Student2("Xiao Wang", 18);
        System.out.println(s2.toString());
//    Output the value of the member variable in s after assignment

Output results:

public boolean equals(Object obj): indicates whether some other objects are equal to this.

In the future, when we want to figure out the implementation of a method and why the result is, look at the source code

Place the mouse cursor on the method you want to see, and press ctrl + the left mouse button to view the source code

By observing the source code, it is found that the underlying implementation of the equals method in the Object class is still==

public boolean equals(Object obj) {

        return (this == obj);

}

And = = when comparing reference data types, the comparison is the address value. When the address values are different, the return is false

==:

Basic data type: the comparison is whether the two values are the same

When referencing a data type: the comparison is whether the address values of the two objects are the same

equals:

Only referenced data types can be compared

In actual development, the equals method is called to compare whether the values of member variables are the same

So we should rewrite it in subclasses. We don't need to do it ourselves. It can be generated automatically

Summary: if the subclass does not override the equals method, it uses the method in the parent Object class and compares the address value. If the subclass overrides the equals method, it compares whether the member variable values are the same.

Test equals:

public class StudentTest3 {
    public static void main(String[] args) {
        Student3 s1 = new Student3("Xiao Liu", 18);
        Student3 s2 = new Student3("Xiao Liu", 18);
        System.out.println(s1==s2); // false
        Student3 s3 = s1;
        System.out.println(s1==s3); // true
        System.out.println("==========================");
        System.out.println(s1.equals(s2)); // false //true
        System.out.println(s1.equals(s3)); // true
        System.out.println(s1.equals(s1)); // true

//    Although we have made clear the comparison method of equals, we observe that in real life, the same name and the same age mean the same
//    For individuals, it should return true
        Student3 s4 = new Student3("Xiao Wang", 19);
        System.out.println(s1.equals(s4));
    }
}

Output results:

protected void finalize(): when the garbage collector determines that there is no longer a reference to the object, the garbage collector calls the object on the object. A subclass overrides the finalize method that handles system resources or performs other cleanup. Simply understand that this method is used for garbage collection, when to collect, uncertain GC mechanism, marking method.

protected Object clone() creates and returns a copy of this object. Perform specific cloning work.

If subclasses in other packages want to use the method modified by protected, use the super keyword to call. clone's method Object performs specific cloning operations.

First, if the class of this object does not implement the interface clonable, CloneNotSupportedException will be thrown. If a class wants to use clone(), it must implement the clonable interface. By observing the API, it is found that there are no constants or abstract methods in the clonable interface. In the future, we will see an interface similar to clonable, which has nothing in it. We call it the tag interface.

There are two common types of copy in the IT industry:

Shallow copy: shallow copy means that the address value of the internal reference type variable of the copied object is the same as that of the original object (pointing to the same object), but the entire copied object and the new object are not the same address value.

Deep copy: copy all the contents of the copied object, including the reference type of memory. When copying, re create an object, and the value of the member variable is the same as that of the original copied object. However, subsequent modifications to the copied reference data type variables will not affect the original copied.

Copy case:

import java.util.Objects;

//Student4 implements the tag interface clonable, which indicates that this is allowed to be cloned
public class Student4 extends Object implements Cloneable{
    private String name;
    private int age;
    private Demo demo;

    public Student4() {
    }

    public Student4(String name, int age,Demo demo) {
        this.name = name;
        this.age = age;
        this.demo = demo;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Demo getDemo() {
        return demo;
    }

    public void setDemo(Demo demo) {
        this.demo = demo;
    }
    //    @Override
//    public String toString() {
//
//

    @Override
    public String toString() {
        return "Student4{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", demo=" + demo +
                '}';
    }


//        return "Name:" + name + ", age:" + age;
//    }


    //s1.equals(s2)
    @Override
    public boolean equals(Object o) {
        //this -- s1
        //o -- s2
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student4 student3 = (Student4) o;
        return age == student3.age && Objects.equals(name, student3.name);
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Here is the test class:

public class StudentTest4 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Demo demo = new Demo();
        Student4 s1 = new Student4("Xiao Liu", 18,demo);
        System.out.println(s1.toString());

        //There is actually a polymorphism implied here
        Object obj = s1.clone();
        System.out.println(obj.toString());//Output copied member variable value
        System.out.println(s1.toString());//Output member variable value before copy

        //Compare the address value of the demo before copying with that after copying
        //It is found that the demo address value is the same
        System.out.println(s1.getDemo().hashCode());//Address value of demo method before copying
        Student4 s4 = (Student4)obj;
        System.out.println(s4.getDemo().hashCode());//Address value of demo method after copying

        //The address value of the whole object before copying and the address value of the whole object after copying
        //It is found that the address value after copying is different from that of the original object
        System.out.println(s1.hashCode()); //1956725890 / / address value of the whole object before copying
        System.out.println(obj.hashCode()); //356573597 / / the address value of the whole object after copying

        System.out.println("=================================");
        //What is the meaning of clone()?
        //To understand this meaning, we need to know a knowledge point (shallow copy / deep copy)
        //Is clone() a shallow copy or a deep copy
        //clone() is a shallow copy

Output results:

Topics: Java