[series of basic Java tutorials] Chapter 13 detailed explanation of Java Object class, String class, StringBuffer and StringBuilder (including principle analysis)

1, Object class

1.1 overview of object class

Package: Java lang

Class definition: public class Object

Class Object is the root class of class hierarchy. Each class uses Object as superclass. All objects (including arrays) implement the methods of this class.

Why define a hierarchy root class?
Java believes that all objects have some basic common content, which can be continuously extracted upward, and finally extracted into a top-level class (Object); What is defined in this class is the function of all objects.

If the extension keyword is not used in the declaration of a class to indicate its parent class, the default parent class is Java Lang.Object class.

In other words, the final effect of the following two kinds of definitions is exactly the same:

class Person { }

class Person extends Object { }

Use Object to receive objects of all classes:

public class UnderStandObject {
    // Define static methods
    public static void fun(Object obj) {
        System.out.println(obj);
    }

    public static void main(String[] args) {
        // Person Student is a subclass of Object and can be passed in as a parameter
        fun(new Person());
        fun(new Student());
    }

}

// human beings
class Person { }

// Student class
class Student { }

The Object class belongs to Java Lang package. All classes under this package do not need to be imported manually when in use. The system will import them automatically during program compilation;
    
We can see the commonly used packages and classes in rt.jar of JRE System Library;

1.2 Object class structure diagram

View the hierarchy in windows - > tool - > Structure; Or directly click Structure in the lower left corner;

1.3 detailed explanation of object class methods

private static native void registerNatives();

public Object(){}

static {
    registerNatives();
}

public final native Class<?> getClass();
    
public native int hashCode();
    
public boolean equals(Object obj) {
    return (this == obj);
}
    
protected native Object clone() throws CloneNotSupportedException;
    
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
    
public final native void notify();
    
public final native void notifyAll();
    
public final native void wait(long timeout) throws InterruptedException;
    
public final void wait(long timeout, int nanos) throws InterruptedException...
    
public final void wait() throws InterruptedException {
    wait(0);
}
    
protected void finalize() throws Throwable { }

1.3.1 registerNatives method

If you are careful, you may find that not only the Object Class, but also the System Class, Class class, ClassLoader Class, Unsafe Class and so on, you can find the following code in the Class code:

private static native void registerNatives();

static {
    registerNatives();
}

Understanding of local methods:

In order to understand the meaning and function of these four lines of code, we need to understand what local methods are first.

The definition of local methods in Java classes is modified with native, and there are only method definitions and no method implementations.

In section 1.3.1 of the book going deep into the Java virtual machine, Java methods are described as follows:
Java has two methods: Java method and native method.
Java method: written in Java language, compiled into bytecode and stored in class file.
Local method: use the native keyword to indicate that this method is a native function, that is, this method is implemented in C/C + + and other non java languages, and is compiled into a DLL and called by Java.
    
Java methods are platform independent, but native methods are not. When a running Java program calls a local method, the virtual machine loads the dynamic library containing the local method and calls the method. Local method is the connection method between Java program and underlying host operating system.

It can be seen that the implementation of local methods is written in other languages and stored in the dynamic connection library, so there is no need for method implementation in Java classes.

Why use the native method:

1. Java is very convenient to use. However, it is not easy to implement some levels of tasks in Java, or we are very concerned about the efficiency of the program. For example, sometimes Java applications need to interact with the environment outside Java. This is the main reason for the existence of local methods. You can think about the situation when Java needs to exchange information with some underlying systems, such as the operating system or some hardware. Local method is such a communication mechanism: it provides us with a very concise interface, and we don't need to understand the cumbersome details outside Java applications.
    
2. The method declared by native can be used as the same as other Java methods for callers.
A native method method can return any java type, including non basic types, and can also perform exception control.
The existence of native method will not have any impact on other classes calling these local methods. In fact, other classes calling these methods do not even know that it is calling a local method. The JVM will control all the details of calling local methods.
If a class containing a local method is inherited, the subclass will inherit the local method and can rewrite the method in the Java language (if necessary).

Understanding of registerNatives method:

registerNatives is essentially a local method, but it is a local method different from general local methods. From the method name, we can guess that this method should be used to register local methods.
    
The function of the above code is to first define the registerNatives() method, and then call this method to complete the registration of local methods in this class when the class is loaded.     
    
More: an in-depth introduction to the role of the registerNatives method in the object class
                https://blog.csdn.net/Saintyyu/article/details/90452826

1.3.2 getClass method

getClass method is a final method. Subclass rewriting is not allowed, and it is also a native method.

Return the Class object of the current runtime object. Note that this is the runtime. For example, in the following code, n is an instance of type Number, but the value in Java is of type integer by default, so the getClass method returns Java lang.Integer:
    
As long as it is a bytecode file Class, the jvm will create a class object to represent the bytecode;

public class GetClassTest {
    public static void main(String[] args) {
        // Returns the Class object of the current runtime object
        System.out.println("str".getClass());// class java.lang.String

        /*
         * every last. After the Class file is loaded by the jvm, an object of type Class will be created in the jvm to represent this bytecode,
         * You can use the class name Class gets the object of this class type, such as string class
         */
        System.out.println("str".getClass() == String.class); // true

        // Abstract class Number is a superclass of BigDecimal, BigInteger, Byte, Double, Float, Integer, Long and Short classes.
        Number n = 100;
        System.out.println(n.getClass()); // class java.lang.Integer

        Number n1 = 10.22;
        System.out.println(n1.getClass()); // class java.lang.Double

        /*
         * animal1/animal2 The object pointed to and the method call issued are uncertain in the compiler; The specific instance pointed to and the method call issued can only be determined at run time
         * */
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();
        // If a package is defined, the package name is included
        System.out.println(animal1.getClass()); // class Dog
        System.out.println(animal2.getClass()); // class Cat
    }
}

class Animal {
}

class Dog extends Animal {
}

class Cat extends Animal {
}

1.3.3 hashCode method

The hashCode method is also a native method.

This method returns the hash code of the object, which is mainly used in the hash table, such as HashMap in JDK.

The general convention of hash code is as follows:

Basis of hash code generation: hash code is not completely unique. It is an algorithm that allows objects of the same class to have different hash codes according to their different characteristics, but it does not mean that different object hash codes are completely different. There is the same situation. It depends on how the programmer writes the hash code algorithm.

In Java, hash codes represent the characteristics of objects.
Hash code Baidu Encyclopedia: https://baike.baidu.com/item/%E5%93%88%E5%B8%8C%E7%A0%81/5035512?fr=aladdin

General convention of hash code:
1. During the execution of java program, on the premise that an object has not been changed, the hashCode method will return the same integer value no matter how many times the object is called. The hash code of an object does not have to keep the same value in different programs.
2. If two objects are compared using the equals method and are the same, the hashCode method values of the two objects must also be equal.
3. If two objects are not equal according to the equals method, the hashCode values of the two objects need not be the same.

Generally, different objects produce different hash codes. By default, the hash code of an object is realized by converting the internal address of the object into an integer.

The hashCode method of String is implemented as follows. The calculation method is s[0]*31^(n-1) + s[1]*31^(n-2) +... + s[n-1], where s[0] represents the first character of the String and N represents the length of the String:

private int hash; // Default to 0

// String class hashCode source code
public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

public class HashCodeTest {
    public static void main(String[] args) {
        String str = "abc"; // {'a','b','c'}

        /*
         * h = 0
         * h = 31 * h + val[i];
         * h = 31 * 0 + 97  ,h = 97
         * h = 31 * 97 + 98 ,h = 3105
         * h = 31 * 3105 + 99 ,h = 96354
         * */
        int hashCode = str.hashCode();
        System.out.println(hashCode);

        /*
         * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
         * 97 * 31^2 + 98 * 31^1 + 99
         * 93217 + 3038 + 97 = 96354
         * */
    }
}

Method equals

Compare whether the two objects are equal (in fact, the internal comparison is the addresses of the two objects). The default implementation of Object class is to compare whether the memory addresses of two objects are equal:

public boolean equals(Object obj) {
	return (this == obj);
}

The equals method of the Object class refers to any non empty values X and y. this method returns true only when x and y refer to the same Object. This is what we often call address equality. (so don't say that equals() in Java is used to compare values)

For comparison of basic data types, for example: a == 3, b == 4, a == b; (compare whether the values are equal)

The reference data is directly compared by calling the equals() method:

public class Student {
    private String name;
    private int age;

    public Student() {

    }

    public Student(String name, int age) {
        super();
        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;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

}

public class Test_Student {
    public static void main(String[] args) {
        Student stu1 = new Student("Zhang San", 20);
        Student stu2 = new Student("Zhang San", 20);
        System.out.println(stu1.equals(stu2)); // false
    }
}

The contents of the two objects stu1 and stu2 are obviously equal. Should they be true? How could it be false?

At this time, the equals() method is called directly to compare the addresses of the two objects. If you click new, a new space will be created on the heap. Naturally, the addresses will not be the same, so it is false.

The equals() method is used for the comparison of String class objects. In fact, the equals() method of String class overrides the equals() method in Object class;

How do you compare the contents of an object to get true?

The answer is: override the equals() method;

In the above example, override the equals() method:

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        super();
        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;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

    // Override equals method
    public boolean equals(Object obj) {
        // If the parameter is null, return false directly
        if (obj == null) {
            return false;
        }

        // Judge whether the addresses are equal. The same address is the same object, and the contents must be equal
        if (this == obj) {
            return true;
        }

        // Judge whether the incoming object is a Student class object
        if (!(obj instanceof Student)) {
            return false;
        }

        /**
         * The object passed in is a Student class object and the addresses are not equal
         * Make a downward transformation, forcibly convert the Object class into the Object of Student class, and compare the attribute values
         */
        Student stu = (Student) obj;
        return stu.name.equals(this.name) && stu.age == this.age; // this represents the current object
    }

}

class Test_Student {
    public static void main(String[] args) {
        Student stu1 = new Student("Zhang San", 20);
        Student stu2 = new Student("Zhang San", 20);
        System.out.println(stu1.equals(stu2)); // true
    }
}

Therefore, when comparing data of reference type, the @ Override equals() method should be overridden first. Otherwise, the memory addresses of the two objects will not be equal.

Note: if the equals method is rewritten, it is usually necessary to rewrite the hashCode method, which has been explained in the hashCode method.

==Operators and equals methods

= = operator: can be used in basic data type variables and reference data type variables
Basic type comparison value: it is true as long as the values of two variables are equal.
                        int a=5; if(a==6){...}
Reference type comparison reference (whether to point to the same object): only when pointing to the same object, = = returns true.
                        Person p1=new Person();
                        Person p2=new Person();
                        if (p1==p2){...}
When comparing with "= =", the data types on both sides of the symbol must be compatible (except for the basic data types that can be automatically converted), otherwise the compilation will make an error

        equals():
If all classes inherit Object, they get the equals() method. It can also be rewritten.
Only reference types can be compared. Its function is the same as that of "= =". Compare whether it points to the same object.
Format: Obj 1 equals(obj2)
Special case: when the equals() method is used for comparison, the types and contents of classes File, String, Date and Wrapper Class are compared regardless of whether the same object is referenced;
Reason: the equals() method of the Object class is overridden in these classes.
When a custom class uses equals(), it can be overridden. Used to compare whether the contents of two objects are equal.

import java.util.Date;

public class EqualsTest {
    public static void main(String[] args) {
        // Basic data type
        int i = 10;
        int j = 10;
        double d = 10.0;
        System.out.println(i == j);//true
        System.out.println(i == d);//true

        boolean b = true;
        // System.out.println(i == b);

        char c = 10;
        System.out.println(i == c); // true

        char c1 = 'A';
        char c2 = 65;
        System.out.println(c1 == c2); // true

        // reference type
        Customer cust1 = new Customer("Tom", 21);
        Customer cust2 = new Customer("Tom", 21);
        System.out.println(cust1 == cust2); // false

        String str1 = new String("jeb");
        String str2 = new String("jeb");
        System.out.println(str1 == str2); // false

        System.out.println("------------------------------");
        // After overriding the equals method of the Customer class
        System.out.println(cust1.equals(cust2)); // false ---> true
        System.out.println(str1.equals(str2)); // true

        Date date1 = new Date(32432525324L);
        Date date2 = new Date(32432525324L);
        System.out.println(date1.equals(date2)); // true

    }
}

class Customer {

    private String name;
    private int 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;
    }

    public Customer() {
        super();
    }

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

    // Automatically generated equals()
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Customer other = (Customer) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }


    //Rewriting principle: compare whether the entity contents (i.e. name and age) of two objects are the same
    //Override equals() manually
    /*@Override
    public boolean equals(Object obj) {
        if (obj == null){
            return false;
        }

        if (this == obj) {
            return true;
        }

        if (obj instanceof Customer) {
            Customer cust = (Customer) obj;
            return this.age == cust.age && this.name.equals(cust.name);
        } else {
            return false;
        }
    }*/

    //Manual implementation
    @Override
    public String toString() {
        return "Customer[name = " + name + ",age = " + age + "]";
    }

}

Principles for overriding the equals() method:

Reflexive, reflexive. Any non null reference value x must return true for x.equals(x).

Symmetry. For any non null reference values X and y, if x.equals(y) is true, then y.equals(x) must also be true.

transitive. For any non null reference values x, y, and Z, if x.equals(y) is true and y.equals(z) is true, then x.equals(z) must also be true.

consistent. For any non null reference values X and y, multiple calls to x.equals(y) always return true or false, provided that the information used in the equals comparison on the object has not been modified

x.equals(null) should return false for any non null reference value x.

Judgment question:

int it = 65;
float fl = 65.0f;
System.out.println("65 And 65.0f Are they equal?" + (it == fl)); // true

char ch1 = 'A'; 
char ch2 = 12;
System.out.println("65 and'A'Are they equal?" + (it == ch1)); // true
System.out.println("12 and ch2 Are they equal?" + (12 == ch2)); // true

String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("str1 and str2 Are they equal?"+ (str1 == str2)); // false

System.out.println("str1 whether equals str2?"+(str1.equals(str2))); // true
System.out.println("hello" == new java.util.Date()); // Compilation failed

1.3.5 clone method

Creates and returns a copy of the current object. In general, for any object x, the expression x.clone()= X is true, X. clone() Getclass() = = x.getClass() is also true.
    
The clone method of the Object class is a protected native method.

        protected native Object clone() throws CloneNotSupportedException; When we see a throw exception on the method; It means that there may be exceptions when calling this method, but it is not handled in the method. Whoever calls it will handle it;

Because the Object itself does not implement the clonable interface, CloneNotSupportedException will occur if the clone method is not rewritten and called.
    
CloneNotSupportedException exception:
This exception is thrown when the clone method in the Object class is called to copy an Object, but the Object's class cannot implement the clonable interface.  

Clonable interface:
This class implements the clonable interface to indicate object Clone () method can legally copy such instances by field.  

For the detailed code, please refer to the deep copy and shallow copy explained earlier;

// Use of clone() of Object class
public class CloneTest {
    public static void main(String[] args) {
        Animal a1 = new Animal("tearful");
        try {
            Animal a2 = (Animal) a1.clone();
            System.out.println("Original object:" + a1);
            a2.setName("Hairy");
            System.out.println("clone Objects after:" + a2);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

class Animal implements Cloneable {
    private String name;

    public Animal() {
        super();
    }

    public Animal(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Animal [name=" + name + "]";
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        return super.clone();
    }

}

1.3.6 toString method

The toString() method is defined in the Object class. Its return value is String type and returns the class name and its reference address.
     
The default implementation of the Object object, that is, the hexadecimal of the hash code of the name @ instance of the output class:

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
import java.util.Date;

public class ToStringTest {
    public static void main(String[] args) {
        Object obj = new Object();

        // return getClass().getName() + "@" + Integer.toHexString(hashCode());
        System.out.println(obj.getClass()); // class java.lang.Object

        System.out.println(obj.getClass().getName()); // java.lang.Object

        System.out.println(obj.getClass().getSimpleName()); // Object

        System.out.println(obj.hashCode()); // 460141958

        /*
         * toHexString(int i) Returns a string representation of an integer parameter as a hexadecimal (Radix 16) unsigned integer.
         * 460141958  Hexadecimal 1b6d3586 of
         * */
        //If you call an object in the output statement, it is equivalent to the object calling toString()
        System.out.println(obj);// java.lang.Object@1b6d3586

        // String, Date, File, wrapper class, etc. all override the toString () method in the Object class. This enables the "entity content" information to be returned when the toString() of the Object is called
        String str = new String("MM");
        System.out.println(str); // MM

        Date date = new Date(4534534534543L);
        System.out.println(date.toString()); // Mon Sep 11 08:55:34 GMT+08:00 2113
    }
}

The result of the toString method should be a concise but easy to read string. You can override the toString() method in user-defined types as needed. It is recommended that all subclasses of Object override this method.
For example, the String class overrides the toString() method to return the value of the String.
                String s1="hello";
                System.out.println(s1);// Equivalent to system out. println(s1.toString());

When the basic type data is converted to String type, the toString() method of the corresponding wrapper class is called;
                int a=10; System.out.println("a="+a);

In general, we override toString() for classes that store data; For example: students, players, etc

During development, in most cases, we can use the tool to automatically rewrite toString() to meet most requirements; If you have special needs, you can rewrite the code yourself;

When connecting String with other types of data, toString() method will be called automatically;
                Date now=new Date();
                System.out.println("now="+now); 
Equivalent to
                System.out.println("now="+now.toString());

Interview questions:

char[] arr = new char[]{'a', 'b', 'c'};
System.out.println(arr); // abc

int[] arr1 = new int[]{1, 2, 3};
System.out.println(arr1); // [I@1b6d3586

double[] arr2 = new double[]{1.1, 2.2, 3.3};
System.out.println(arr2); // [D@4554617c

1.3.7 notify method

The notify method is a native method and is also final. Subclass rewriting is not allowed.

Wake up a thread waiting on this object monitor (monitor is equivalent to the concept of lock). If all threads are waiting on this object, only one thread will be selected. Choices are arbitrary and occur when decisions are made about implementation. A thread waiting on the object monitor can call the wait method.

The awakened thread cannot continue processing until the current thread relinquishes the lock on the object. The awakened thread will compete with all other threads actively synchronized on the object in a conventional manner. For example, a wakeup thread has no reliable privilege or disadvantage as the next thread to lock this object.

The notify method can only be called by a thread that is the owner of this object monitor. To become the owner of an object monitor, a thread can use the following three methods:
The synchronization instance method of the execution object;
Use synchronized built-in lock;
For Class objects, execute synchronous static methods;

Only one thread can own the monitor of the object at a time. If the current thread is not the owner of this object monitor, an IllegalMonitorStateException will be thrown.

Note:
Because notify can only be invoked in the owner thread that owns the object monitor, it will throw the IllegalMonitorStateException exception.

1.3.8 notifyAll method

Like notify, the only difference is that it wakes up all the threads waiting on this object monitor instead of one thread.

1.3.9 wait(long timeout) method

The wait(long timeout) method is also a native method and is final. Subclass rewriting is not allowed.

The wait method causes the current thread to wait until another thread calls the notify or notifyAll method of the object, or exceeds the timeout set by the parameter.

Like the notify and notifyAll methods, the current thread must be the monitor owner of this object, otherwise the IllegalMonitorStateException will still occur.

1.3.10 wait(long timeout, int nanos) method

Similar to the wait(long timeout) method, there is an additional nanos parameter, which represents the additional time (in nanoseconds, the range is 0-999999). Therefore, the timeout time needs to be added with nanos milliseconds.

It should be noted that the effect of wait(0, 0) and wait(0) is the same, that is, wait all the time.

1.3.11 wait() method

It is the same as the previous two wait methods, except that this method keeps waiting without the concept of timeout.

1.3.12 finalize method

The finalize method is a protected method. The default implementation of the Object class does not perform any operation.

The function of this method is to trigger the operation when the instance is collected by the garbage collector, just like "the last wave of struggle before death".

public class FinalizeTest {
    public static void main(String[] args) {
        Person p = new Person("Peter", 12);
        System.out.println(p);
        p = null; // At this time, the object entity is a garbage object, waiting to be recycled. But the time is uncertain.
        System.gc(); // Mandatory release space
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        super();
        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;
    }

    //Subclasses override this method to perform certain operations before releasing the object
    @Override
    protected void finalize() throws Throwable {
        System.out.println("Object is released--->" + this);
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

2, String string class

2.1 overview of string class

Package: Java lang

Class definition:
                public final class String
                    implements java.io.Serializable, Comparable<String>, CharSequence
    
The string class represents a string. All string literals (such as "abc") in Java programs are implemented as instances of this class. String is a final class that represents an immutable character sequence.

String is a constant, which is expressed in double quotation marks; Their values cannot be changed after creation. The string buffer supports variable strings. Because string objects are immutable, they can be shared.

The character content of String object is stored in a character array value [].
             
        public interface Serializable
Class by implementing Java io. Serializable interface to enable its serialization. A class that does not implement this interface will not be able to serialize or deserialize any of its states. The serialization interface has no methods or fields and is only used to identify serializable semantics.

        public interface CharSequence
CharSequence is a readable sequence of char values. This interface provides unified read-only access to many different kinds of char sequences.
Known implementation classes: CharBuffer, Segment, String, StringBuffer, StringBuilder
There are four methods defined in it:
char charAt(int index) returns the char value of the specified index.  
int length() returns the length of this character sequence.  
CharSequence subSequence(int start, int end) returns a new CharSequence, which is a subsequence of this sequence.
String toString() returns a string containing the characters in this sequence in the same order as this sequence.  

        public interface Comparable<T>
This interface forces an overall ordering of the objects of each class that implements it. This sort is called the natural sort of class, and the compareTo method of class is called its natural comparison method.
It defines a method:
int compareTo(T o) compares the order of this object with the specified object.

2.2 structure diagram of string class

2.2.1 view class structure diagram of idea

Take ArrayList as an example to show the schematic diagram, hierarchy and members of the class;

Schematic diagram of class:

In the specified class, right click - > diagrams - > show diagrams or Show Diagrams Popup;
Shortcut keys: Ctrl + Alt + Shift + U or Ctrl + Alt + U;
    
After this operation, we can see that the inheritance relationship of classes and interfaces is clearly presented in front of us; At the same time, this diagram can also be presented in various ways by right clicking in the blank space – > layout - > select layout.

Hierarchy of classes:

In the specified class, the menu navigation - > type hierarchy;
Shortcut key: Ctrl + H;
    
After this operation, we can see the parent class, interface and subclass of the current class;
If you just want to see the parent class and interface, you can click Supertypes Hierarchy;
If you just want to see subclasses, you can click Subtypes Hierarchy;
If you want to view by sorting, you can click Sort Alphabetically;

Members of class:

In the specified class, menu view - > tool windows - > structure;
Shortcut key: Structure in the lower left corner;

2.2.2 structure diagram of string class

2.3 method summary

2.3.1 construction method

String() initializes a newly created string object to represent a null character sequence.

String(String original) initializes a newly created string object to represent a character sequence with the same parameters; In other words, the newly created string is a copy of the parameter string.  

String(byte[] bytes) decodes the specified byte array by using the default character set of the platform to construct a new string.

String(byte[] bytes, int offset, int length) decodes the specified byte subarray by using the default character set of the platform to construct a new string.

public class StringConstructorTest {
    public static void main(String[] args) {
        // String() 	 Create a new string to represent an empty sequence of objects.
        String str1 = new String(); // "" empty string "" space string "
        System.out.println("str1 Value of:" + str1); // Value of str1:

        // String(String original) 		 Initialize a newly created string object to represent a character sequence with the same parameters; In other words, the newly created string is a copy of the parameter string.
        String str2 = new String("123"); // String str2 = "123";
        System.out.println("str2 Value of:" + str2); // Value of str2: 123

        // The parameter is the constructor related to byte array, which is very important; We will use it in IO later
        // String(byte[] bytes) 	 Decode the specified byte array by using the default character set of the platform to construct a new string.
        byte b[] = {97, 98, 99, 100, 101, 102}; // a,b,c,d
        String str3 = new String(b);
        System.out.println("str3 Value of:" + str3); // Value of str3: abcdef

        // String(byte[] bytes, int offset, int length) 	 A new string is constructed by decoding the specified byte subarray using the platform's default character set.
        String str4 = new String(b, 1, 3);
        System.out.println("str4 Value of:" + str4); // Value of str4: bcd
    }
}

String(byte[] bytes, Charset charset) constructs a new string by decoding the specified byte array with the specified charset.

String(byte[] bytes, String charsetName) decodes the specified byte array by using the specified charset to construct a new string. (this is more concise)

String(byte[] bytes, int offset, int length, Charset charset) constructs a new string by decoding the specified byte subarray with the specified charset.

String(byte[] bytes, int offset, int length, String charsetName) decodes the specified byte subarray using the specified character set to construct a new string.

import java.io.UnsupportedEncodingException;

public class StringConstructorTest {
    public static void main(String[] args) throws UnsupportedEncodingException {
        /*
         * Number of bytes
         * Chinese: ISO: 1 GBK: 2 utf-8:3
         * Numbers or letters: ISO: 1 GBK: 1 utf-8:1
         * */
        String username = "in";

        /*
         * byte[] getBytes(String charsetName) Encode this String into a byte sequence using the specified character set and store the result in a new byte array.
         *
         * String(byte[] bytes, Charset charset)	Construct a new String by decoding the specified byte array with the specified charset.
         * String(byte[] bytes, String charsetName)	Construct a new String by decoding the specified byte array using the specified charset. (this is more concise)
         * */
        byte[] u_iso = username.getBytes("ISO-8859-1");
        byte[] u_gbk = username.getBytes("GBK");
        byte[] u_utf8 = username.getBytes("UTF-8");
        System.out.println(u_iso.length); // 1
        System.out.println(u_gbk.length); // 2
        System.out.println(u_utf8.length); // 3

        // It is just opposite to the above, byte array ----- > string
        String un_iso = new String(u_iso, "ISO-8859-1");
        String un_gbk = new String(u_gbk, "GBK");
        String un_utf8 = new String(u_utf8, "UTF-8");
        System.out.println(un_iso); // ?
        System.out.println(un_gbk); // in
        System.out.println(un_utf8); // in

        // Sometimes it must be iso character encoding type. The processing method is as follows
        String un_utf8_iso = new String(u_utf8, "ISO8859-1");
        System.out.println("utf-8 Array pass ISO8859-1 Parse to string:" + un_utf8_iso);

        // Restore iso encoded string
        String un_iso_utf8 = new String(un_utf8_iso.getBytes("ISO8859-1"), "UTF-8");
        System.out.println(un_iso_utf8);
    }
}

String(char[] value) assigns a new string to represent the character sequence currently contained in the character array parameter.  

String(char[] value, int offset, int count) assigns a new string that contains characters from a sub array of character array parameters.  

String(int[] codePoints, int offset, int count) assigns a new string that contains the characters of a sub array of Unicode code point array parameters.  

String(StringBuffer buffer) allocates a new string that contains the character sequence currently contained in the string buffer parameter.  

String(StringBuilder builder) assigns a new string that contains the character sequence currently contained in the string generator parameters.

Summary: except for the constructor of passing array [byte/char array], other constructors can basically not be used, and it is better not to use them;

public class StringConstructorTest {
    public static void main(String[] args) {
        // String(char[] value) 	 Assign a new string to represent the character sequence currently contained in the character array parameter.
        char[] chars = new char[]{'a', 'b', 'c', 'd'};
        String str1 = new String(chars);
        System.out.println("str1 Value of:" + str1); // Value of str1: abcd

        // String(char[] value, int offset, int count) 		 Assign a new string that contains characters from a sub array of character array parameters.
        String str2 = new String(chars, 1, 2);
        System.out.println("str2 Value of:" + str2); // Value of str2: bc

        // String(int[] codePoints, int offset, int count) 		 Assign a new string that contains the characters of a subarray of Unicode code point array parameters.
        int[] ints = new int[]{97, 98, 99, 100};
        String str3 = new String(ints, 1, 2);
        System.out.println("str3 Value of:" + str3); // Value of str3: bc

        // String(StringBuffer buffer) 		 Allocates a new string that contains the sequence of characters currently contained in the string buffer parameter.
        StringBuffer stringBuffer = new StringBuffer("abcd");
        String str4 = new String(stringBuffer);
        System.out.println("str4 Value of:" + str4); // Value of str4: abcd
    }
}

2.3.2 membership method

  • Acquisition method:
	char charAt(int index)	Returns at the specified index char Value. 
	
    int codePointAt(int index)	Returns the character at the specified index( Unicode Code point). 
        
    int codePointBefore(int index)	Returns the character before the specified index( Unicode Code point). 
        
    int codePointCount(int beginIndex, int endIndex)	Return to this String In the specified text range of Unicode Code points.     

	int hashCode()	Returns the hash code of this string. 

	int indexOf(int ch)		Returns the index of the first occurrence of the specified character in this string. 

	int indexOf(int ch, int fromIndex)	Returns the index at the first occurrence of the specified character in this string, starting with the specified index. 

	int indexOf(String str)		Returns the index of the specified substring at the first occurrence in this string. 

	int indexOf(String str, int fromIndex)	Returns the index of the specified substring at the first occurrence in this string, starting from the specified index. 

	String intern()		Returns the normalized representation of a string object. 

	int lastIndexOf(int ch)		Returns the index of the last occurrence of the specified character in this string. 

	int lastIndexOf(int ch, int fromIndex)	Returns the index of the last occurrence of the specified character in this string, starting from the specified index. 

	int lastIndexOf(String str)	Returns the index of the rightmost occurrence of the specified substring in this string. 

	int lastIndexOf(String str, int fromIndex)	Returns the index of the last occurrence of the specified substring in this string, and searches reversely from the specified index. 

	int length()	Returns the length of this string. 

	String substring(int beginIndex)	Returns a new string, which is a substring of this string. 

	String substring(int beginIndex, int endIndex)	Returns a new string, which is a substring of this string. 
  • Judgment method:
	boolean contains(CharSequence s)	If and only if this string contains the specified char Value sequence, return true. 
        
    boolean contentEquals(CharSequence cs)	Matches this string with the specified CharSequence Compare.  
        
	boolean contentEquals(StringBuffer sb)	Matches this string with the specified StringBuffer Compare.     
        
    boolean endsWith(String suffix)		Tests whether this string ends with the specified suffix.  
        
    boolean equals(Object anObject)		Compares this string with the specified object.
        
    boolean equalsIgnoreCase(String anotherString)	Will this String With another String Compare, regardless of case. 

	boolean isEmpty()	if and only if length() Return when is 0 true.  

	boolean matches(String regex)	Tells whether this string matches the given regular expression. The regular part will be explained again.

	boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)	Tests whether two string regions are equal. 

	boolean startsWith(String prefix)	Tests whether this string starts with the specified prefix. 

	boolean startsWith(String prefix, int toffset)	Tests whether the substring of this string starting from the specified index starts with the specified prefix. 

Similarities and differences between equals and contentEquals:

equals and contentEquals in String can be used to compare whether the contents of String objects are the same.
    
However, equals can only compare the contents of two String objects, otherwise it returns false;

contentEquals comparison type is Java Whether the object contents of lang.charsequence are the same.

Why is it necessary to define contentEquals(StringBuffer sb) when there is contentEquals(CharSequence cs)

We can see from the underlying source code that contentEquals(StringBuffer sb) calls contentEquals(CharSequence cs). As for why this definition is required, one is provided by version 1.4 and the other is provided by version 1.5.
        public boolean contentEquals(StringBuffer sb) {
            return contentEquals((CharSequence)sb);
        }

  • Conversion method:
	String concat(String str)	Concatenates the specified string to the end of this string. 

	static String copyValueOf(char[] data)	Returns the string representing the character sequence in the specified array String.  

   	static String copyValueOf(char[] data, int offset, int count)	Returns the string representing the character sequence in the specified array String.  
        
	byte[] getBytes()	Use the platform's default character set to convert this String Code as byte Sequence and store the results in a new byte Array.
    
    byte[] getBytes(Charset charset)	Use the given charset Will this String Code to byte Sequence and store the results in a new byte Array.     
        
	byte[] getBytes(String charsetName)		Use the specified character set to convert this String Code as byte Sequence and store the results in a new byte Array.      
    
	void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)	Copy characters from this string to the target character array.     

	String replace(char oldChar, char newChar)	Returns a new string by using newChar Replace all occurrences in this string oldChar Got it. 

	String replace(CharSequence target, CharSequence replacement)	Replaces all substrings of this string that match the literal target sequence with the specified literal replacement sequence. 

	String replaceAll(String regex, String replacement)	Use the given replacement Replace this string with all substrings that match the given regular expression. 

	String replaceFirst(String regex, String replacement)	Use the given replacement Replace this string to match the first substring of the given regular expression. 

	String[] split(String regex)	Splits the string based on the match of the given regular expression. 

	String[] split(String regex, int limit)		Splits the string based on matching the given regular expression. 

	char[] toCharArray()	Converts this string to a new character array. 

	String toLowerCase()	Use the rules of the default locale to set this String All characters in are converted to lowercase. 
	
	String toUpperCase()	Use the rules of the default locale to set this String All characters in are converted to uppercase. 
	
	String toString()	Returns the object itself (it is already a string!). 

	String trim()	Returns a copy of a string, ignoring leading and trailing whitespace. 

	static String valueOf(char c)	return char The string representation of the parameter. 

	static String valueOf(char[] data, int offset, int count)	return char The string representation of a specific subarray of an array parameter. 
	
	static String valueOf(boolean b)	return boolean The string representation of the parameter. 

	static String valueOf(char c)	return char The string representation of the parameter. 

	static String valueOf(double d)		return double The string representation of the parameter. 

	static String valueOf(float f)	return float The string representation of the parameter. 

	static String valueOf(int i)	return int The string representation of the parameter. 

	static String valueOf(long l)	return long The string representation of the parameter. 

	static String valueOf(Object obj)	return Object The string representation of the parameter. 

	static String format(Locale l, String format, Object... args)	Returns a formatted string using the specified locale, format string, and parameters.     
    
	static String format(String format, Object... args)	Use a format string and return a specified format string.   
    	String.format()Detailed usage of: https://blog.csdn.net/anita9999/article/details/82346552

The difference and usage between replace and replaceAll:

Replace and replaceAll are commonly used methods to replace characters in JAVA

Difference:
1. The parameters of replace are char and CharSequence, which can support both character replacement and string replacement (CharSequence means string sequence, in other words, string);

2. The parameter of replaceAll is regex, that is, replacement based on regular expression. For example, you can replace all numeric characters of a string with asterisks through replaceAll("\d", "*");

Similarities:
Replace all, that is, replace a character or string in the source string with a specified character or string. If you only want to replace the first occurrence, you can use replaceFirst(). This method is also based on regular expression replacement, but different from replaceAll(), only replace the first occurrence of the string;
In addition, if the parameter data used by replaceAll() and replaceFirst() are not based on regular expressions, the effect of replacing strings with replace() is the same, that is, they also support string operations;

Another note: the content of the source string does not change after the replacement operation.

public class StringMethodTest {
    public static void main(String[] args) {
        String src = new String("ab43a2c43d");
        System.out.println(src.replace("3", "f")); // ab4fa2c4fd     
        System.out.println(src.replaceAll("\\d", "f")); // abffafcffd
        System.out.println(src.replaceAll("a", "f")); // fb43f2c43d
        System.out.println(src.replaceFirst("\\d", "f")); // abf3a2c43d
        System.out.println(src.replaceFirst("4", "h")); // abh3a2c43d

        String str = "12hello34world5java7891mysql456";
        //Replace the number in the string with,, and remove it if there are at the beginning and end of the result
        String string = str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");
        System.out.println(string);

        String str1 = "12345";
        //Judge whether all str strings are composed of numbers, i.e. 1-n numbers
        boolean matches = str1.matches("\\d+");
        System.out.println(matches);
        
        String tel = "0571-4534289";
        //Judge whether this is a fixed line telephone in Hangzhou
        boolean result = tel.matches("0571-\\d{7,8}");
        System.out.println(result);
    }
}

split combined with regular:

public class StringMethodTest {
    public static void main(String[] args) {
        String str = "hello|world|java";
        String[] strs = str.split("\\|");
        for (int i = 0; i < strs.length; i++) {
            System.out.println(strs[i]);
        }
        System.out.println();
        String str2 = "hello.world.java";
        String[] strs2 = str2.split("\\.");
        for (int i = 0; i < strs2.length; i++) {
            System.out.println(strs2[i]);
        }
    }
}
  • Comparison method:

Int CompareTo (string otherstring) compares two strings in dictionary order.  

int compareToIgnoreCase(String str) compares two strings in dictionary order, regardless of case.  
    
The return values of the two methods are integers. Compare the two strings in dictionary order. If the first character and the first character of the parameter are not equal, end the comparison and return the difference between them. If the first character and the first character of the parameter are equal, compare the second character with the second character of the parameter, and so on until one of the compared characters or the compared characters is compared, and then compare the length of the characters  

The comparison is based on the Unicode value of each character in the String. Compare the character sequence represented by this String object with the character sequence represented by the parameter String in dictionary order. If this String object precedes the parameter String in dictionary order, the comparison result is a negative integer. If this String object follows the parameter String in dictionary order, the comparison result is a positive integer. If the two strings are equal, the result is 0; compareTo returns 0 only when the method equals(Object) returns true.  

public class StringMethodTest {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "abcd";
        String s3 = "abcdfg";
        String s4 = "1bcdfg";
        String s5 = "cdfg";
        System.out.println(s1.compareTo(s2)); // -1 (equal in front and 1 less in s1 length)
        System.out.println(s1.compareTo(s3)); // -3 (equal in front and 3 less in s1 length)
        System.out.println(s1.compareTo(s4)); // 48 ("the ASCII code of" a "is 97, and the ASCII code of" 1 "is 49, so 48 is returned)
        System.out.println(s1.compareTo(s5)); // -2 ("the ASCII code of" a "is 97 and the ASCII code of" C "is 99, so - 2 is returned)
    }
}

2.4 brief analysis of string memory

2.4.1 brief analysis of string literal memory storage

String s1 = "abc";//Definition of literal quantity
String s2 = "abc";
s1 = "hello";

2.4.2 brief analysis of creating string memory storage by constructor

2.4.3 compare literal and constructor memory storage

        String str1 = “abc”; And String str2 = new String("ABC"); What's the difference?

String constants are stored in the string constant pool for sharing; String non constant objects are stored in the heap.

2.4.4 exercise analysis memory storage

Exercise 1:

String s1 = "javaEE";
String s2 = "javaEE";
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false

Exercise 2:

Person p1 = new Person();
p1.name = "jimbo";
Person p2 = new Person();
p2.name = "jimbo";
System.out.println(p1.name.equals(p2.name)); // true
System.out.println(p1.name == p2.name); // true
System.out.println(p1.name == "jimbo"); // true

String s1 = new String("bcde");
String s2 = new String("bcde");
System.out.println(s1 == s2); // false
Person p1 = new Person("Tom",12);
Person p2 = new Person("Tom",12);
System.out.println(p1.name == p2.name);//true

Exercise 3:

Conclusion:
The splicing results of constants and constants are in the constant pool. And constants with the same content will not exist in the constant pool.
As long as one of them is a variable, the result is in the heap.
If the result of splicing calls the intern() method, the return value is in the constant pool.

String usage trap:
        String s1 = "a"; 
Description: a string with literal "a" is created in the string constant pool.

        s1 = s1 + "b"; 
Note: in fact, the original "a" string object has been discarded. Now a string s1+"b" (i.e. "ab") is generated in the heap space. If these operations to change the string content are performed multiple times, a large number of copy string objects will be stored in memory, reducing efficiency. If such operations are put into the loop, it will greatly affect the performance of the program.
        
        String s2 = "ab";
Description: directly create a string with literal "ab" in the string constant pool.

        String s3 = "a" + "b";
Note: s3 refers to the string of "ab" that has been created in the string constant pool.

        String s4 = s1.intern();
Note: s1 object in heap space will assign the existing "ab" string in constant pool to s4 after calling intern().

Exercise 4:

The results of the following procedures:

public class StringTest {
    String str = new String("good");
    char[] ch = { 't', 'e', 's', 't' };
    public void change(String str, char ch[]) {
        str = "test ok";
        ch[0] = 'b';
    }
    public static void main(String[] args) {
        StringTest ex = new StringTest();
        ex.change(ex.str, ex.ch);
        System.out.println(ex.str);// good
        System.out.println(ex.ch); // best
    }
}

2.5 in depth understanding of string

There are two ways to assign value to string. The first is to assign value through "literal". What is a string literal? A string literal is a character sequence between two double quotes, such as "string" and "literal".
                String str = "Hello";
    
The second is to create a new object through the new keyword.
                String str = new String("Hello");        

To figure out the difference between the two methods, we must first know their storage location in memory.

2.5.1 Java memory area

The memory we usually talk about is the Runtime Data Area in the figure, in which the Method Area, Heap Area and Stack Area are related to the creation of strings.
Method area: store class information, constants and static variables, and share them globally.
Heap: store objects and arrays and share them globally.
Stack area: store the reference of basic data type and object, and the thread is private.

Whenever a method is executed, a Stack Frame will be created in the stack area, and the basic data types and object references will exist in the Local Variables table in the Stack Frame.

When a class is loaded, the class information is stored in the non heap method area. In the method area, there is a piece called the Runtime Constant Pool, which is private to each class. The "constant pool" in each class file is mapped and stored here after being loaded by the loader. This will be mentioned later.

The most relevant to string is the String Pool, which is located at the location of the resident strings above the method area. It has been confused with the runtime constant pool before. In fact, it is two completely different storage areas. The string constant pool is shared globally. String calls string After the intern () method, its reference is stored in the String Pool.

2.5.2 differences between the two creation methods in memory

After understanding these concepts, let's talk about the difference between the two string creation methods.

The following Test class assigns "Hello" to the string str in the way of "literal" assignment in the main method.

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

        String str = "Hello";

    } 
}

        Test.java file compiled Class file, which contains class information, including an area called Constant Pool Class Constant Pool and Constant Pool in memory are not the same thing.

        . The class file constant pool mainly stores literal quantities, which include constants defined in the class. Since String is immutable, the String "Hello" is stored here.

When the program uses the Test class, Test Class is parsed into the method area in memory The constant pool information in the class file will be loaded into the runtime constant pool, but String is not.

In the example, "Hello" will create an object in the heap and store a reference to it in the String Pool, as shown in the following figure.

At this time, only the Test class has just been loaded, the str in the main function has not been created, and the "Hello" object has been created in the heap.

When the main thread starts to create the str variable, the virtual opportunity goes to the String pool to find whether there is a String of equals("Hello"). If it is equal, copy the reference of "Hello" in the String pool to str. If the equivalent String cannot be found, a new object will be created in the heap, the reference will reside in the String pool, and then the reference will be assigned to str.

When a string is created by literal assignment, no matter how many times it is created, as long as the value of the string is the same, they all point to the same object in the heap.

public class Test {
    public static void main(String[] args) {
        
        String str1 = "Hello";
        String str2 = "Hello";
        String str3 = "Hello";
        
    } 
}

When using the new keyword to create a string, the previous loading process is the same, but at run time, no matter whether there is an object reference equal to the current value in the string pool, a new piece of memory will be opened up in the heap to create an object.

public class Test {
    public static void main(String[] args) {
        
        String str1 = "Hello";
        String str2 = "Hello";
        String str3 = new String("Hello");
        
    } 
}

Code reading questions:

String s1 = "Hello";
String s2 = "Hello";
String s3 = "Hel" + "lo";
String s4 = "Hel" + new String("lo");
String s5 = new String("Hello");
String s6 = s5.intern();
String s7 = "H";
String s8 = "ello";
String s9 = s7 + s8;
          
System.out.println(s1 == s2);  // true
System.out.println(s1 == s3);  // true
System.out.println(s1 == s4);  // false
System.out.println(s1 == s9);  // false
System.out.println(s4 == s5);  // false
System.out.println(s1 == s6);  // true

With the above foundation, this problem will be solved easily.

s1 while creating the object, the reference of its object is also created in the string pool.

Since s2 is also created by literal quantity, we will first look for whether there is an equal string in the string pool. Obviously, s1 has been created for it, and it can use its reference directly. Then s1 and s2 point to the same address, so s1==s2.

s3 is a string splicing operation. The parts involved in splicing are literal. The compiler will optimize it. s3 becomes "Hello" at compile time, so s1==s3.

Although s4 is also spliced, "lo" is created through the new keyword. Its address cannot be known at compile time, so it cannot be optimized like s3. Therefore, you must wait until runtime to determine. The address of the new object must be different from the previous one.

Similarly, s9 is spliced by two variables, and the compiler does not know their specific location, so it will not be optimized.

s5 is new. The address in the heap must be different from s4.

s6 uses the intern() method to get the reference of s5 in the string pool, which is not the address of s5 itself. Since their references in the string pool all point to the same "Hello" object, naturally s1==s6.

To sum up:
When creating a literal string, first look in the string pool to see if there are equal objects. If not, create it in the heap and store the address in the string pool; In some cases, the reference in the pool is used directly to avoid creating objects repeatedly.
When the new keyword is created, the previous operation is the same as the literal creation, except that a new object will be created at runtime, and the variable references the address of the new object.
Due to some changes in the memory of different versions of JDK, jdk1 6 the string constant pool is in the permanent generation, 1.7 is moved to the heap, and 1.8 uses meta space to replace the permanent generation. But it basically has no effect on the above conclusion, and the thought is the same.

2.5.3 classic interview questions

        String str=new String("abc"); How many string objects have been created?

1. Idea: we can divide the above line of code into four parts: String str, = "," abc "and new String().
String str just defines a variable of string type named str, so it does not create an object;

= initializes the variable str, assigns a reference to an object, and obviously does not create an object;

Why can new String ("abc") be regarded as "abc" and new String()? Let's take a look at the constructor of the String we called:

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

We know that there are two common methods to create an instance (object) of a class:
Use new to create objects.
Call the newInstance method of Class class and create the object by using the reflection mechanism

We use new to call the constructor method above the String class to create an object and assign its reference to the str variable. At the same time, we notice that the parameter accepted by the called constructor method is also a String object, which is "abc". Therefore, we will introduce another way to create String objects - including text in quotation marks.

Here we need to introduce relevant knowledge of string pool:

String str="abc";//Create an object

String a="abc";
String b="abc";//Create an object

String c="ab"+"cd";//Create three objects

There is a String pool in JAVA virtual machine (JVM), which holds many String objects and can be shared, so it improves efficiency. Because the String class is final, its value cannot be changed once it is created, so we don't have to worry about the confusion of the program caused by the sharing of String objects. The String pool is maintained by the String class. We can call the intern() method to access the String pool.

Let's look back at String a = "abc";, When this line of code is executed, the JAVA virtual machine first looks for whether an object with the value of "abc" already exists in the String pool. Its judgment is based on the return value of the String class equals(Object obj) method. If yes, no new object will be created, and the reference of the existing object will be returned directly; If not, first create this object, then add it to the String pool, and then return its reference. Therefore, it is not difficult for us to understand why the first two of the first three examples are the answer.

For the third example, "ab" and "cd" create an object respectively. After being connected with "+", they create another object "abcd", so there are three in total, and they are saved in the string pool.

Now the question comes again. Will all strings obtained after "+" connection be added to the string pool? We all know that "= =" can be used to compare two variables. It has the following two cases:

If you are comparing two basic types (char, byte, short, int, long, float, double, boolean), judge whether their values are equal.

If the table compares two object variables, judge whether their references point to the same object.

Back to the point:
The answer should be: two or one.
        
1. If the abc String has not been used before, there is no doubt that two objects are created, one is a new object created by new String, and the other is a new String object created by the content of the constant "abc" object;
    
2. If the abc string has been used before, create an object.

3, String buffer

3.1 overview of StringBuffer class

Package: Java lang

Class definition:
                public final class StringBuffer
                         extends AbstractStringBuilder
                         implements java.io.Serializable, CharSequence

Thread safe variable character sequence, jdk1 0, the string content can be added or deleted, and no new object will be generated at this time. Although it contains a specific character sequence at any point in time, the length and content of the sequence can be changed through some method calls.  

String buffers can be safely used for multiple threads. These methods can be synchronized when necessary, so all operations on any particular instance appear to occur in a serial order, which is consistent with the order of method calls made by each thread involved.  

The main operations on StringBuffer are append and insert methods, which can be overloaded to accept any type of data. Each method can effectively convert the given data into a string, and then append or insert the characters of the string into the string buffer. The append method always adds these characters to the end of the buffer; The insert method adds characters at the specified point.

Generally, if sb refers to an instance of StringBuffer, sb Append (x) and sb Insert (sb. Length(), x) has the same effect.  

When an operation related to the source sequence occurs, such as an append or insert operation in the source sequence, the class synchronizes only on the string buffer where the operation is performed, not on the source.  

Each string buffer has a certain capacity. As long as the length of the character sequence contained in the string buffer does not exceed this capacity, there is no need to allocate a new internal buffer array. This capacity increases automatically if the internal buffer overflows. Starting from JDK 5, this class is supplemented with an equivalent class used by a single thread, namely StringBuilder. In general, the StringBuilder class should be preferred over this class because it supports all the same operations, but it is faster because it does not perform synchronization.  

Features:
1. You can modify the string content.
2. It is a container.
3. It is of variable length.
4. Any type of data can be stored in the buffer.
5. Finally, it needs to be changed into a string.

3.2 structure diagram of StringBuffer class

3.3 method summary

There are many methods in the StringBuffer class that are the same as those in the String class. The functions of these methods are exactly the same as those in the String class.

However, one of the most significant differences is that each modification of the StringBuffer object will change the object itself, which is the biggest difference from the String class.

When passed as a parameter, the value can be changed inside the method.

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage
     * value Without the final statement, value can be continuously expanded.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     * count Record the number of valid characters.
     */
    int count;
}

3.3.1 construction method

StringBuffer() constructs a string buffer without characters, with an initial capacity of 16 characters.

        StringBuffer(CharSequence seq)    public java.lang.StringBuilder(CharSequence seq) constructs a string buffer that contains the same characters as the specified charsequence.

StringBuffer(int capacity) constructs a string buffer without characters but with a specified initial capacity.

StringBuffer(String str) constructs a string buffer and initializes its contents to the specified string contents.

3.3.2 membership method

  • Add method:
    StringBuffer append(Parameters of various data types)	Append the string representation of parameters of various data types to the sequence. 
		Parameter type:
			boolean b: take boolean The string representation of the parameter is appended to the sequence.
			char c: take char The string representation of the parameter is appended to this sequence.
			char[] str: take char The string representation of the array parameter is appended to this sequence.
			char[] str, int offset, int len: take char The string representation of the subarray of the array parameter is appended to this sequence.
			CharSequence s: Will be specified CharSequence Append to the sequence.
			CharSequence s, int start, int end: Will specify CharSequence The subsequence of is appended to this sequence.
			double d: take double The string representation of the parameter is appended to this sequence.
			float f: take float The string representation of the parameter is appended to this sequence.
			int i: take int The string representation of the parameter is appended to this sequence.
			long lng: take long The string representation of the parameter is appended to this sequence.
			Object obj: Add Object The string representation of the parameter.
			String str: Appends the specified string to this character sequence.
			StringBuffer sb: Will be specified StringBuffer Append to this sequence.
	
	StringBuffer appendCodePoint(int codePoint)	take codePoint The string representation of the parameter is appended to this sequence.

    StringBuffer insert(int offset, Parameters of various data types)	Insert string representations of parameters of various data types into this sequence.
		Parameter type and append agreement;
  • Delete method:
	StringBuffer delete(int start, int end)	Remove characters from substrings of this sequence. 

	StringBuffer deleteCharAt(int index)	Remove the specified location of this sequence char.  
  • Modification method:
	void ensureCapacity(int minimumCapacity)	Ensure that the capacity is at least equal to the specified minimum value. 

	StringBuffer replace(int start, int end, String str)	Use given String Replace the characters in the substring of this sequence with the characters in. 

	void setCharAt(int index, char ch)	Sets the character at the given index to ch.  

	void setLength(int newLength)	Sets the length of the character sequence. 

	void trimToSize()	Try to reduce the storage space for character sequences. 
  • Find method:
    int indexOf(String str)	Returns the index of the first occurrence of the specified substring in the string. 

    int indexOf(String str, int fromIndex)	Returns the index of the first occurrence of the specified substring in the string, starting at the specified index. 

    int lastIndexOf(String str)	Returns the index of the specified substring appearing on the far right in this string. 

    int lastIndexOf(String str, int fromIndex)	Returns the index of the last occurrence of the specified substring in this string. 
  • Get substring method:
	CharSequence subSequence(int start, int end)	Returns a new character sequence that is a subsequence of this sequence. 

	String substring(int start)	Returns a new String,It contains the character subsequence currently contained in this character sequence. 
	
	String substring(int start, int end)	Returns a new String,It contains the character subsequence currently contained in this sequence. 
  • Inversion method:
StringBuffer reverse()	Replace this character sequence with its inverted form. 
  • Method principle analysis
	When append and insert When, if the original value The length of the array is not enough. It can be expanded.
	
	The above methods support method chain operation.
	
	Principle of method chain:
@Override
public synchronized StringBuffer append(Object obj) {
    toStringCache = null;
    super.append(String.valueOf(obj));
    return this;
}

@Override
public synchronized StringBuffer insert(int offset, String str) {
    toStringCache = null;
    super.insert(offset, str);
    return this;
}

4, StringBuilder string buffer

4.1 overview of StringBuilder class

Package: Java lang

Class definition:
        public final class StringBuilder
            extends AbstractStringBuilder
            implements java.io.Serializable, CharSequence

A variable character sequence. This class provides an API compatible with StringBuffer, but does not guarantee synchronization. This class is designed to be a simple replacement for StringBuffer when the string buffer is used by a single thread (which is common). If possible, it is recommended to take this class first, as it is faster than StringBuffer in most implementations.  

The main operations on StringBuilder are append and insert methods, which can be overloaded to accept any type of data. Each method can effectively convert the given data into a string, and then append or insert the characters of the string into the string generator. The append method always adds these characters to the end of the generator; The insert method adds characters at the specified point.

It is not safe to use an instance of StringBuilder for multiple threads. If such synchronization is required, it is recommended to use StringBuffer.  

4.2 method summary

The methods of Stringbuilder and StringBuffer are the same; Only one is thread safe; One is thread unsafe;

No longer list the methods one by one;

4.3 deeply understand the differences between String, StringBuffer and StringBuilder classes

Java provides String, StringBuffer and StringBuilder classes to encapsulate strings, and provides a series of methods to operate String objects.

Their common point is that they are used to encapsulate strings; Both implement the CharSequence interface. The differences between them are as follows:

4.3.1 variable and immutable

String class is an immutable class, that is, after creating a string object, the string in the object cannot be changed until the object is destroyed.
    
Both StringBuffer and StringBuilder inherit from AbstractStringBuilder class. AbstractStringBuilder also uses character array to save strings, which is a variable class.

Because String is an immutable class, it is suitable for sharing. When a String is often modified, it is best to use StringBuffer. If you use String to save a frequently modified String, new useless objects will be created every time the String is modified. These useless objects will be recycled by the garbage collector, which will affect the performance of the program. This is not recommended.

4.3.2 initialization mode

When creating a String object, you can initialize it by using the construction method String str = new String("Java"), or you can initialize it directly by using the assignment method String s = "Java".
    
StringBuffer and StringBuilder can only be initialized by construction method.

4.3.3 string modification method

The String string modification method is to first create a StringBuilder, then call the append method of StringBuilder, and finally call the toString() method of StringBuilder to return the result. The example code is as follows:
                String str = "hello";
                str += "java";

The above code is equivalent to the following code:
                StringBuilder sb = new StringBuilder(str);
                sb.append("java");
                str = sb.toString();

The modification process of the above String string requires more additional operations than StringBuffer, which will add some temporary objects, resulting in reduced execution efficiency of the program. StringBuffer and StringBuilder perform better than String in modifying strings.

4.3.4 are the equals and hashCode methods implemented

String implements the equals() method and hashCode() method, and new string ("Java") The result of equals (new string ("Java")) is true;

StringBuffer does not implement the equals() method and hashCode() method. Therefore, new StringBuffer ("Java") The result of equals (New StringBuffer ("Java")) is false. There will be a problem storing the StringBuffer object into the Java collection class.

4.3.5 is thread safe

Both StringBuffer and StringBuilder provide a series of methods to insert, append and change the character sequence in the string. Their usage is basically the same, but StringBuilder is thread unsafe and StringBuffer is thread safe. If you only use string buffers in a single thread, StringBuilder will be more efficient, but it is best to use StringBuffer when accessing multiple threads.

public class CompareTimeTest {
    public static void main(String[] args) {
        //Initial settings
        long startTime = 0L;
        long endTime = 0L;
        String text = "";
        StringBuffer buffer = new StringBuffer("");
        StringBuilder builder = new StringBuilder("");

        //Start comparison
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {
            buffer.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer Execution time of:" + (endTime - startTime));

        startTime = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {
            builder.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder Execution time of:" + (endTime - startTime));

        startTime = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {
            text = text + i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("String Execution time of:" + (endTime - startTime));
    }
}

4.3.6 to sum up

To sum up, in terms of execution efficiency, StringBuilder is the highest, StringBuffer is the second, and String is the lowest. In this case, generally speaking, if the number of operations is relatively small, the String class should be used first; If you operate a large amount of data under a single thread, you should give priority to the use of StringBuilder class; If you operate a large amount of data under multithreading, you should give priority to the StringBuffer class.

5, Interview questions

1. Understanding of Object class?
Class Object is the root class of the class hierarchy. Each class uses Object as its superclass. All objects (including arrays) implement the methods of this class.
If the extension keyword is not used in the declaration of a class to indicate its parent class, the default parent class is Java Lang.Object class.

2. Why define a hierarchy root class (*)?
Java believes that all objects have some basic common content, which can be continuously extracted upward, and finally extracted into a top-level class (Object);
This class defines the functions that all objects have;

3. native method?
The definition of native methods in Java classes is modified by native, and there are only method definitions and no method implementations.

4. Can native methods be overridden?
In Java, only final modified methods cannot be rewritten, and native methods can be rewritten;     

5. Classification of Java methods?
On a large level, Java methods are divided into Java methods and native methods.
Java method is written in Java language, compiled into bytecode and stored in class file.
Java methods are divided into: member methods, construction methods and static methods;
Native methods are written in other languages (such as C,C + +, or assembly) and compiled into processor related machine code. Local methods are stored in dynamic link libraries (DLLs) in a format specific to each platform.

6. What is the role of the registerNatives method in the Object class?
registerNatives is essentially a local method, but it is a local method different from general local methods. This method should be used to register local methods.
Firstly, the registerNatives() method is defined, and then when the class is loaded, this method is called to complete the registration of local methods in the class.

7. What is the function of getClass method in Object class?
getClass method is a final method. Subclass rewriting is not allowed, and it is also a native method.
Returns the Class object of the current runtime object;

8. What is the function of hashCode method in Object class?
The hashCode method is also a native method. The method returns the hash code of the object;
This method returns the hash code of the object. It is an algorithm that allows objects of the same class to have different hash codes as much as possible according to their different characteristics;

9. The role of clone method in Object class?
The clone method of the Object class is a protected native method. Creates and returns a copy of the current Object.

10. What is the role of the equals method in the Object class?
equals is defined in the Object class. All classes inherit the Object class indirectly or directly;
Then, if the subclass does not override the equals method, equals compares the address;
If you override the equals method, it is usually used to compare the content;
Note: to rewrite equals, you'd better rewrite hasCode as well; Generally, it is generated using IDE tools;

11. What is the difference between = = and equals?
= =: you can compare basic data type variables with reference data type variables;
Basic type comparison value: it is true as long as the values of two variables are equal.
Reference type comparison reference (whether to point to the same object): only when pointing to the same object, = = returns true.
    equals:
Only reference data types can be compared, and basic data types cannot be compared;
By default, addresses are compared; When a custom class uses equals(), it can be overridden. Used to compare whether the contents of two objects are equal.

12. The role of toString method in Object class?
The return value is of type String, which returns the class name and its reference address.

13. What is the role of the finalize method in the Object class?
The function of this method is to trigger the operation when the instance is collected by the garbage collector, just like "the last wave of struggle before death".

14. What are the similarities and differences between equals and contentEquals?
equals and contentEquals in String can be used to compare whether the contents of String objects are the same.
However, equals can only compare the contents of two String objects, otherwise it returns false;
contentEquals comparison type is Java Whether the object contents of lang.charsequence are the same.

15. Conversion between string and array?
Conversion between string and byte array:
String(byte[] bytes) decodes the specified byte array by using the default character set of the platform to construct a new string.
byte[] getBytes() encodes this String as a byte sequence using the platform's default character set and stores the result in a new byte array.
Conversion between string and char array:
String(char[] value) assigns a new string to represent the character sequence currently contained in the character array parameter.
static String valueOf(char[] data) returns the string representation of char array parameters.
char[] toCharArray() converts this string to a new character array.

16. What is the difference between replace and replaceAll of String class?
Replace and replaceAll are commonly used methods to replace characters in JAVA;
Difference:
1. The parameters of replace are char and CharSequence, which can support both character replacement and string replacement (CharSequence means string sequence, in other words, string);
2. The parameter of replaceAll is regex, that is, replacement based on regular expression. For example, you can replace all numeric characters of a string with asterisks through replaceAll("\d", "*");
Similarities:
Replace all, that is, replace a character or string in the source string with a specified character or string. If you only want to replace the first occurrence, you can use replaceFirst(). This method is also based on regular expression replacement, but different from replaceAll(), only replace the first occurrence of the string;
In addition, if the parameter data used by replaceAll() and replaceFirst() are not based on regular expressions, the effect of replacing strings with replace() is the same, that is, they also support string operations;

17. How to understand that String is an immutable character sequence?
String is a constant, which is expressed in double quotation marks; Their values cannot be changed after creation.
The String class operates on strings by generating new strings instead of modifying the original strings; Specifically reflected in:
        1.concat() appends the specified string to the original string to generate a new character sequence;
        2.replace()/replaceAll() replaces the character / string of the original string with the specified character / string to generate a new character sequence;
        3.lowerCase()/upperCase() converts the string to uppercase / lowercase and generates a new character sequence;

18. What is the difference between String, StringBuffer and StringBuilder classes?
Their common point is that they are used to encapsulate strings; Both implement the CharSequence interface.
Variable and immutable: String is an immutable character sequence, and StringBuffer and StringBuilder are variable character sequences;
The bottom layer of the String class is the character array decorated with final, which is immutable; However, the bottom layers of StringBuffer and StringBuilder also use character arrays, but they do not use final modification, which is variable;
Thread safe: both String and StringBuffer are thread safe and inefficient; StringBuilder is thread unsafe and efficient;
Execution efficiency: StringBuilder > StringBuffer > string
Initialization method: String can create an instance through String literal and constructor; However, StringBuffer and StringBuilder can only create instances through constructors;
String modification method: the String string modification method is to create a StringBuilder first, then call the append method of StringBuilder, and finally call the toString() method of StringBuilder to return the result. StringBuffer and StringBuilder perform better than string in modifying strings.
Whether the equals and hashCode methods are implemented: String implements the equals() method and hashCode() method; StringBuffer does not implement the equals() method and hashCode() method;

19. CloneNotSupportedException (*)?
This exception is thrown when the clone method in the Object class is called to copy an Object, but the Object's class cannot implement the clonable interface.

20. Function of clonable interface (*)?
There is no definition in the interface, just an identification. The class that implements the interface can legally copy the instances of this class by field;

21. Function of Serializable interface (*)?
There is no definition in the interface, just an identification. The class that implements the interface can enable its serialization function.

22. Is the length attribute or length() (*) obtained by array / string?
Get the length of the array through the length attribute of the array;
String gets the length of the string through the length() method;

23. Can String class be inherited (*)?
No, String class is a class modified by final

24. Capacity expansion mechanism of StringBuffer and StringBuilder?
Current capacity * 2 + 2;

25. The underlying implementation of the append method in StringBuffer (*)?
A series of append() are overloaded in StringBuffer, which can pass any data type parameter;
When adding specified parameters, first judge whether the capacity is sufficient;
If the capacity is sufficient, it is directly appended to the string buffer; If the capacity is insufficient, expand the capacity;
The capacity expansion mechanism is: the default value of capacity expansion is: move one bit left + 2 on the binary bit of buffer capacity; If the preset value of capacity expansion is less than the minimum capacity, the preset value is equal to the minimum capacity
The essence of its capacity expansion is to expand the capacity on the basis of the original array;

26. What is the difference between replace() of String and replace() of StringBuffer?
Replace() of String can pass two char parameters and two String sequence parameters; The replace() of StringBuffer passes the start subscript, the end subscript and the String to be replaced;
Replace() of String does not modify the original String to produce a new character sequence; The replace() of StringBuffer modifies the original character sequence;

27,String str=new String("abc"); How many string objects have been created?
Two or one.
1. If the abc String has not been used before, there is no doubt that two objects are created, one is a new object created by new String, and the other is a new String object created by the content of the constant "abc" object;
2. If the abc string has been used before, create an object.

Keywords: Java Back-end JavaSE

Added by mwkemo on Mon, 07 Mar 2022 05:27:16 +0200