1. Data types

1.1 Basic Types

type bit byte
byte 8 1
char 16 2
short 16 2
int 32 4
float 32 4
long 64 8
double 64 8
boolean ~ ~ ~
  • Boolean has only two values, true and false, and can be stored as a bit, but the size is not specified

  • The JVM converts Boolean data to int at compile time, using 1 for true and 0 for false

  • The JVM supports Boolean data, but does so by reading and writing byte arrays

1.2 Packaging Type

Each base type has a corresponding wrapper class, and the assignment between the base type and its corresponding wrapper type is done using automatic boxing and unboxing

Integer x = 2 // Boxing calls integer.valueof (2)
int y = x     // call x.ntValue ()
Copy the code

1.3 buffer pool

New Integer(123) differs from integer.valueof (123) :

  • New Integer(123) creates a new object each time;
  • Integer. The valueOf (123) will be usedObjects in the cache pool.Multiple calls get a reference to the same object
Integer x = new Integer(123);
Integer y = new Integer(123);
System.out.println(x == y); //false
Integer z = Integer.valueOf(123);
integer k = Integer.valueOf(123);
System.out.println(z == k); //true
Copy the code
  • The valueOf() method is simple to implement. It checks whether the value is in the cache pool and returns the contents of the cache pool if so
public static Integer valueOf(int i){

    if(i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);

}
Copy the code
  • In Java 8, the default Integer cache pool size is -128 to 127
static final int low = -128;
static final int high;
static final Integer cache[];

static {
    // high value may be configured by property
    int h = 127;
    String integerCacheHighPropValue =
        sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
    if(integerCacheHighPropValue ! =null) {
        try {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        } catch( NumberFormatException nfe) {
            // If the property cannot be parsed into an int, ignore it.
        }
    }
    high = h;

    cache = new Integer[(high - low) + 1];
    int j = low;
    for(int k = 0; k < cache.length; k++)
        cache[k] = new Integer(j++);

    // range [-128, 127] must be interned (JLS7 5.1.7)
    assert IntegerCache.high >= 127;
}
Copy the code
  • The compiler calls the valueOf() method during auto-boxing, so multiple instances of Integer with the same value and within the cache pool range are created using auto-boxing and reference the same object
Integer m = 123;
Integer n = 123;
System.out.println(m == n); //true
Copy the code

The basic types correspond to the following buffer pools:

  • boolean values true and false;
  • all bytes values
  • short values between -128 ~ 127
  • int values between -128 ~ 127
  • char in the range \u0000 to \u 007F

When using the wrapper type corresponding to these base types, if the value range is within the buffer pool scope, you can use objects from the buffer pool directly

Among all the numeric class buffers in JDK8,Integer’s buffer pool IntegerCache is special. The lower bound of the buffer pool is -128. The previous default was 127, but the upper bound is tunable, with -xx :AutoBoxCacheMax = size when the JVM is started To specify the size of the buffer pool, this option will set the JVM is initialized, a Java lang. IntegerCache. High system properties, then IntegerCache initialization time will read the system to determine the upper bound

2.String

2.1 an overview

String is declared final, so it cannot be inherited (nor can wrapper classes such as Integer)

In Java8, strings use char data internally to store data

public final class String
    implements java.io.Serializable.Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
}
Copy the code

After Java9, the implementation of String switched to byte data to store strings, while using coder to identify which encoding was used

public final class String
    implements java.io.Serializable.Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final byte[] value;

    /** The identifier of the encoding used to encode the bytes in {@code value}. */
    private final byte coder;
}
Copy the code
  • The value array is declared final, which means that the value array cannot reference any other array after it is initialized

  • And there is no way to change the value data inside the String, so the String is guaranteed to be immutable

2.2 Benefits of immutability

2.2.1 Can cache Hash values

  • Because String hash values are often used, for example String is used as the key of a HashMap
  • The immutable nature makes hash immutable, so it only needs to be evaluated once

2.2.2 String Pool Requirements

  • If a String object has already been created, the reference is fetched from the String Pool
  • String Pool can only be used if String is immutable

2.2.3 security

  • String is often used as a parameter, and String immutability ensures that the parameter is immutable
    • For example, in the case of network connection parameters if String is mutable, then during network connection,The String is changedThe party that changed the String thought it was connected to another host, which is not necessarily the case

2.2.4 Thread Safety

  • String immutability is inherently thread-safe and can be used safely across multiple threads

2.3 String. StringBuffer and StringBuilder

2.3.1 variability

  • String is immutable
  • StringBuffer and StringBuilder are mutable

2.3.2 Thread Safety

  • String is immutable and therefore thread-safe
  • StringBuilder is not thread-safe
  • StringBuffer is thread-safe and uses Synchronized internally

2.4 the String Pool

The string constant pool holds all the string literals that are determined at compile time. Not only that, you can also use the String intern() method to add strings to the String Pool at run time

  • When a string calls intern(),If there is already a String equal to that String in the String Pool(Use the equals() method to determine),A reference to the String in the String Pool is returned
  • Otherwise, a new String is added to the String Pool and a reference to the new String is returned

In the following example,s1 and S2 create two different strings using the new String() method, while S3 and S4 get the same String reference using the s1.intern() and s2.Intern () methods. Intern () first puts “AAA” into the String Pool and then returns the String reference, so S3 and S4 refer to the same String

String s1 = new String("aaa");
String s2 = new String("aaa");
System.out.println(s1 == s2);           // false
String s3 = s1.intern();
String s4 = s2.intern();
System.out.println(s3 == s4);           // true
Copy the code

If you create a String as a “BBB” literal, the String is automatically placed in the String Pool

String s5 = "bbb";
String s6 = "bbb";
System.out.println(s5 == s6);  // true
Copy the code
  • Prior to Java7,String pools were placed in the runtime constant Pool, which belonged to the persistent generation
  • In Java7,String pools are moved to the heap. Because the space of the permanent generation is limited, scenarios that use a lot of strings will result in OOM errors

2.5 the new String (” ABC “)

Two String objects are created in this way (provided there is no “ABC” String object in the String Pool yet)

  • “ABC” data String literal, so compile-time creates a String object in the String Pool that points to this “ABC” String literal
  • Using new creates a string object in the heap

Create a test class that uses this method to create string objects in its main method

public class NewStringTest {
    public static void main(String[] args) {
        String s = new String("abc"); }}Copy the code

Decompilation using javap-verbose yields the following:

// ...
Constant pool:
// ...
   #2 = Class              #18            // java/lang/String
   #3 = String             #19            // abc
// ...
  #18 = Utf8               java/lang/String
  #19 = Utf8               abc
// ...

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=2, args_size=1
         0: new           #2                  // class java/lang/String
         3: dup
         4: ldc           #3                  // String abc
         6: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
         9: astore_1
// ...
Copy the code
  • In Constant Pool,#19 stores the String variable “ABC “, and #3 is the String object for the String Pool, which refers to the String literal #19
  • In the main method, the 0: line uses new #2 to create a String object in the heap, and uses LDC #3 to take a String object from the String Pool as an argument to the String constructor

The following is the source code for the String constructor. You can see that when you take one String object as an argument to another String object, you do not copy the contents of the value array. Instead, you refer to the same value array

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

3. The operation

3.1 Parameter Transfer

Va parameters are passed into the method as values, not references

The Dog of Dog in the following code is a pointer that stores the address of an object. When passing a parameter to a method, you are essentially passing the address of the object as a value to the parameter

public class Dog {

    String name;

    Dog(String name) {
        this.name = name;
    }

    String getName(a) {
        return this.name;
    }

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

    String getObjectAddress(a) {
        return super.toString(); }}Copy the code

Changing the value of an object’s field in a method changes the value of the field in the original object because it refers to the same object

class PassByValueExample {
    public static void main(String[] args) {
        Dog dog = new Dog("A");
        func(dog);
        System.out.println(dog.getName());          // B
    }

    private static void func(Dog dog) {
        dog.setName("B"); }}Copy the code

But if a pointer refers to another object in a method, then the two Pointers inside and outside the method point to different objects. Changing the content of one pointer has no effect on the object pointed to by the other pointer

public class PassByValueExample {
    public static void main(String[] args) {
        Dog dog = new Dog("A");
        System.out.println(dog.getObjectAddress()); // Dog@4554617c
        func(dog);
        System.out.println(dog.getObjectAddress()); // Dog@4554617c
        System.out.println(dog.getName());          // A
    }

    private static void func(Dog dog) {
        System.out.println(dog.getObjectAddress()); // Dog@4554617c
        dog = new Dog("B");
        System.out.println(dog.getObjectAddress()); // Dog@74a14482
        System.out.println(dog.getName());          // B}}Copy the code

3.2 float (4) and double (8)

Java cannot implicitly perform a downward transition because it would reduce accuracy.

  • 1.1 literals are of type double. You cannot assign 1.1 directly to a float variable because this is a downward transition

  • A 1.1F literal is a float

// float f = 1.1;
float f = 1.1 f;
Copy the code

3.3 Implicit Type conversion

  • Because the literal 1 is an int, it is more precise than short, so you cannot implicitly cast an int downward to a short
short s1 = 1;
// s1 = s1 + 1;
Copy the code
  • But using the += or ++ operators performs implicit type conversions

s1 += 1; s1 ++;

The above sentence is equivalent to a downward transformation of the calculation results of S1 + 1: S1 = (short)(S1 + 1);

3.4 the switch

Starting with Java7, you can use strings in switch conditional statements

String s = "a";
switch (s) {
    case "a":
        System.out.println("aaa");
        break;
    case "b":
        System.out.println("bbb");
        break;
}
Copy the code

Long,float, and double are not supported by the Switch, because the switch is designed to evaluate types with only a few values. If values are too complex, use if

// long x = 111;
// switch (x) { // Incompatible types. Found: 'long', required: 'char, byte, short, int, Character, Byte, Short, Integer, String, or an enum'
// case 111:
// System.out.println(111);
// break;
// case 222:
// System.out.println(222);
// break;
// }
Copy the code

4. Key words

4.1 final

4.4.1 data

Declare data as constants, either compile-time constants or constants that cannot be changed after initialization at runtime

  • For basic data types: final leaves the data unchanged;
  • For reference data types: final leaves the reference unchanged and therefore cannot refer to other objects, but the referenced object itself can be modified

4.1.2 method

Declaration methods cannot be overridden by subclasses

  • Private methods are implicitly specified as final. If a method defined ina subclass has the same signature as a private method in the base class, the subclass’s method does not override the base class method, but redefines a new method in the subclass

4.1.3 class

Declare that classes are not allowed to be inherited

4.2 the Static

4.2.1 Static Variables

  • Static variable: Also known as a class variable, that is, the variable belongs to the class and is shared by all instances of the class and can be accessed directly by the class name. Only one copy of a static variable exists in memory
  • Instance variables: An instance variable is created for each instance created, and it lives and dies with the instance
public class A {

    private int x;         // Instance variables
    private static int y;  // Static variables

    public static void main(String[] args) {
        // int x = A.x; // Non-static field 'x' cannot be referenced from a static context
        A a = new A();
        int x = a.x;
        inty = A.y; }}Copy the code

4.2.2 Static method

  • A static method exists when the class is loaded and does not depend on any instance
  • So a static method must have an implementation, that is, it cannot be an abstract method
public abstract class A {
    public static void func1(a){}// public abstract static void func2(); // Illegal combination of modifiers: 'abstract' and 'static'
}
Copy the code

Only the static fields and methods of the owning class can be accessed. The methods cannot have the this and super keywords because they are associated with specific objects

public class A {

    private static int x;
    private int y;

    public static void func1(a){
        int a = x;
        // int b = y; // Non-static field 'y' cannot be referenced from a static context
        // int b = this.y; // 'A.this' cannot be referenced from a static context}}Copy the code

4.2.3 Static Statement Blocks

  • A static statement block is run once during class initialization
public class A {
    static {
        System.out.println("123");
    }

    public static void main(String[] args) {
        A a1 = new A();
        A a2 = newA(); }}Copy the code

4.2.4 Static inner Classes

A non-static inner class depends on an instance of an external class, which means that an instance of an external class must be created before it can be used to create a non-static inner class. Static inner classes do not

public class OuterClass {

    class InnerClass {}static class StaticInnerClass {}public static void main(String[] args) {
        // InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static context
        OuterClass outerClass = new OuterClass();
        InnerClass innerClass = outerClass.new InnerClass(a);
        StaticInnerClass staticInnerClass = newStaticInnerClass(); }}Copy the code

4.2.5 Static Packet Guide

When using static variables and methods, you no longer have to specify a ClassName, simplifying the code but greatly reducing readability

import static com.xxx.ClassName.*
Copy the code

4.2.6 Initialization Sequence

  • Static variables and static statement blocks take precedence over instance variables and normal statement blocks, and the order in which they are initialized depends on the order in which they are placed in the code

    • Public static String staticField = “static “;

    • Static {system.out.println (” static statement block “); }

    • Public String field = “instance variable “;

    • {system.out.println (” plain statement block “); }

    • Public InitialOrderTest() {system.out.println (” constructor “); }

  • In the case of inheritance, the initialization sequence is:

    • Parent (static variable, static statement block)

    • Children (static variables, static statement blocks)

    • Parent (instance variable, plain statement block)

    • Parent (constructor)

    • Child (instance variable, plain statement block)

    • Child (constructor)

5.Object Common methods

5.1 an overview


public native int hashCode(a)

public boolean equals(Object obj)

protected native Object clone(a) throws CloneNotSupportedException

public String toString(a)

public final nativeClass<? >getClass(a)

protected void finalize(a) throws Throwable {}

public final native void notify(a)

public final native void notifyAll(a)

public final native void wait(long timeout) throws InterruptedException

public final void wait(long timeout, int nanos) throws InterruptedException

public final void wait(a) throws InterruptedException
Copy the code

5.2 the equals ()

  • Equivalence relation
    • The equivalence relation between two objects must satisfy the following five conditions
      • 1. Reflexivityx.equals(x) //true
      • 2. The shapex.equals(y) == y.equals(x) // true
      • 3. The transitivityif (x.equals(y) && y.equals(z))
      • 4. Consistency (calls to equals() will not change after several times)x.equals(y) == x.equals(y); // true
      • 5. Comparison with NULL (x.equals(null) on any non-null object x results in falsex.equals(null); // false;
  • Equivalence and equality
    • For base datatypes,== determines whether two values are equal. Base datatypes have no equals method
    • For reference data types,== determines whether two variables refer to the same object, and equals() determines whether the referenced objects are equivalent
Integer x = new Integer(1);
Integer y = new Integer(1);
System.out.println(x.equals(y)); // true
System.out.println(x == y); // false
Copy the code
  • implementation
    • Check if it is a reference to the same object, or return true if it is;
    • Check if it is the same type, if not return false;
    • Transform the Object;
    • Determine whether each key field is equal
public class EqualExample {

    private int x;
    private int y;
    private int z;

    public EqualExample(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null|| getClass() ! = o.getClass())return false;

        EqualExample that = (EqualExample) o;

        if(x ! = that.x)return false;
        if(y ! = that.y)return false;
        returnz == that.z; }}Copy the code

5.3 hashCode ()

HashCode () returns the hash value, and equals() is used to determine whether two objects are equivalent. Two equivalent objects must have the same hash value, but two objects with the same hash value are not necessarily equivalent. This is because the calculation of the hash value is random. Two objects with different values may compute the same hash value

  • The hashCode() method should always be overridden when overriding equals(), ensuring that the hashes of two equivalent objects are also equal

  • Collection classes such as HashSet and HasMap use the hashCode() method to calculate where objects should be stored, so to add objects to these collection classes, you need to have the corresponding class implement the hashCode() method

The following code creates two equivalent objects and adds them to the HashSet. We want to treat these two objects as if they were the same and add only one object to the collection. But Equal Example does not implement the hashCode() method, so the hash values of the two objects are different, resulting in two equivalent objects being added to the collection

EqualExample e1 = new EqualExample(1.1.1);
EqualExample e2 = new EqualExample(1.1.1);
System.out.println(e1.equals(e2)); // true
HashSet<EqualExample> set = new HashSet<>();
set.add(e1);
set.add(e2);
System.out.println(set.size());   / / 2
Copy the code

An ideal hash function should be homogeneous, that is, unequal objects should be evenly distributed across all possible hashes. And that requires the hash function to take into account all of the fields. Each field can be treated as a bit of an r-base integer

  • R is usually 31, because it’s an odd prime, and if it’s even, when you have a multiplication overflow, the information gets lost, because multiplying by 2 is the same thing as moving one bit to the left, losing the leftmost bit

  • And a number equal to 31 can be converted to displacement and subtraction: 31 * x == (x<<5) -x, and the compiler automatically reverses this optimization

@Override
public int hashCode(a) {
    int result = 17;
    result = 31 * result + x;
    result = 31 * result + y;
    result = 31 * result + z;
    return result;
}
Copy the code

5.4 the toString ()

The default is to return toStringExample@4554617c this new style, where @ is followed by an unsigned hexadecimal representation of the numeric bit hash code

public class ToStringExample {

    private int number;

    public ToStringExample(int number) {
        this.number = number; }}Copy the code
ToStringExample example = new ToStringExample(123);
System.out.println(example.toString());
Copy the code
ToStringExample@4554617c
Copy the code

5.5 clone ()

5.5.1 cloneable

  • Clone () is a protected method of Object, which is not public. If a class does not explicitly override clone(), other classes cannot directly call the clone() method of the entity
public class CloneExample {
    private int a;
    private int b;
}
Copy the code
CloneExample e1 = new CloneExample();
// CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'
Copy the code
  • Rewrite clone() to get the following implementation:
public class CloneExample {
    private int a;
    private int b;

    @Override
    public CloneExample clone(a) throws CloneNotSupportedException {
        return (CloneExample)super.clone(); }}Copy the code
CloneExample e1 = new CloneExample();
try {
    CloneExample e2 = e1.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}
Copy the code
java.lang.CloneNotSupportedException: CloneExample
Copy the code

More than throw CloneNotSupportedException, this is because the CloneExample does not implement the Cloneable interface

It should be noted:

  • The Clone () method is notCloneableInterface methods,It’s a protected method of Object
  • The Cloneable interface simply specifies that a CloneNotSupportException will be thrown if a class calls the Clone () method without implementing the Cloneable interface
public class CloneExample implements Cloneable {
    private int a;
    private int b;

    @Override
    public Object clone(a) throws CloneNotSupportedException {
        return super.clone(); }}Copy the code

5.5.2 shallow copy

The reference type of the copy object and the original object refer to the same object

public class ShallowCloneExample implements Cloneable {

    private int[] arr;

    public ShallowCloneExample(a) {
        arr = new int[10];
        for (int i = 0; i < arr.length; i++) { arr[i] = i; }}public void set(int index, int value) {
        arr[index] = value;
    }

    public int get(int index) {
        return arr[index];
    }

    @Override
    protected ShallowCloneExample clone(a) throws CloneNotSupportedException {
        return (ShallowCloneExample) super.clone(); }}Copy the code
ShallowCloneExample e1 = new ShallowCloneExample();
ShallowCloneExample e2 = null;
try {
    e2 = e1.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}
e1.set(2.222);
System.out.println(e2.get(2)); / / 222
Copy the code

5.5.3 deep copy

The reference types of the copy object and the original object refer to different objects

public class DeepCloneExample implements Cloneable {

    private int[] arr;

    public DeepCloneExample(a) {
        arr = new int[10];
        for (int i = 0; i < arr.length; i++) { arr[i] = i; }}public void set(int index, int value) {
        arr[index] = value;
    }

    public int get(int index) {
        return arr[index];
    }

    @Override
    protected DeepCloneExample clone(a) throws CloneNotSupportedException {
        DeepCloneExample result = (DeepCloneExample) super.clone();
        result.arr = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            result.arr[i] = arr[i];
        }
        returnresult; }}Copy the code
DeepCloneExample e1 = new DeepCloneExample();
DeepCloneExample e2 = null;
try {
    e2 = e1.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}
e1.set(2.222);
System.out.println(e2.get(2)); / / 2
Copy the code

5.5.4 Alternative method of Clone ()

Copying an object using the Clone () method is complex and risky, throwing exceptions and requiring type conversions. The Effective Java book states that it is best not to use Clone (), but to use the copy constructor or copy factory to copy an object.

public class CloneConstructorExample {

    private int[] arr;

    public CloneConstructorExample(a) {
        arr = new int[10];
        for (int i = 0; i < arr.length; i++) { arr[i] = i; }}public CloneConstructorExample(CloneConstructorExample original) {
        arr = new int[original.arr.length];
        for (int i = 0; i < original.arr.length; i++) { arr[i] = original.arr[i]; }}public void set(int index, int value) {
        arr[index] = value;
    }

    public int get(int index) {
        returnarr[index]; }}Copy the code
CloneConstructorExample e1 = new CloneConstructorExample();
CloneConstructorExample e2 = new CloneConstructorExample(e1);
e1.set(2.222);
System.out.println(e2.get(2)); / / 2
Copy the code