Take the java Road Again - java Foundation

1, Data type

Basic type

  • byte - 8
  • short - 16
  • char - 16
  • int - 32
  • float- 32
  • long - 64
  • double - 64
  • boolean ~~
    boolean has only two values: true and false. It can be stored in 1 bit, but the specific size is not specified. The JVM will convert boolean data to int at compile time, using 1 to indicate true and 0 to indicate false. The JVM supports boolean arrays, but it is implemented by reading and writing byte arrays.

Packaging type

Primitive typeWrapper class
booleanBoolean
byteByte
charCharacter
floatFloat
intInteger
longLong
shortShort
doubleDouble

Each basic type has a corresponding packaging type. The assignment between the basic type and its corresponding packaging type is completed by automatic packing and unpacking.

	Integer x = 2;     // Boxing called Integer.valueOf(2)
	int y = x;         // Unpacking called X.intValue()

Cache pool

The difference between new Integer(123) and Integer.valueOf(123) is:

  • new Integer(123) creates a new object each time;
  • Integer.valueOf(123) will use the objects in the cache pool, and multiple calls will get the reference of 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

The implementation of valueOf() method is relatively simple, that is, first judge whether the value is in the cache pool, and if so, directly return the contents of the cache pool.

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

In Java 8, the size of Integer cache pool is - 128 ~ 127 by default.

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;
}

The compiler calls the valueOf() method during the auto boxing process, so if multiple Integer instances with the same value and within the cache pool are created using auto boxing, the same object will be referenced.

Integer m = 123;
Integer n = 123;
System.out.println(m == n); // true

The buffer pool corresponding to the basic type is as follows:

  • boolean values true and false
  • all byte values
  • short values between -128 and 127
  • int values between -128 and 127
  • char in the range \u0000 to \u007F

When using the wrapper type corresponding to these basic types, if the value range is within the buffer pool range, you can directly use the objects in the buffer pool.

Among all the numeric buffer pools in jdk 1.8, Integer buffer pool IntegerCache is very special. The lower bound of this buffer pool is - 128, and the upper bound is 127 by default, but this upper bound is adjustable. When starting the JVM, specify the size of this buffer pool through - XX:AutoBoxCacheMax =, This option will set a system property named java.lang.IntegerCache.high during JVM initialization, and then read the system property to determine the upper bound during IntegerCache initialization.

2, String

overview

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

In Java 8, String uses a char array 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[];
}

After Java 9, the implementation of String class uses byte array to store strings, and uses coder to identify which encoding is 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;
}

The value array is declared final, which means that the value array cannot reference other arrays after initialization. Moreover, there is no method to change the value array inside the String, so it can ensure that the String is immutable.

Immutable benefits

  1. You can cache hash values
    Because the hash value of String is often used, for example, String is used as the key of HashMap. The immutable feature can make the hash value immutable, so it only needs to be calculated once.
  2. String Pool needs
    If a string object has been created, it will get a reference from the String Pool. String Pool can be used only if string is immutable.
  3. Security
    String is often used as a parameter. The immutability of string can ensure that the parameter is immutable. For example, if string is variable as a network connection parameter, the string is changed during the network connection. The party who changes the string thinks that other hosts are connected, but the actual situation is not necessarily the same.
  4. Thread safety
    String immutability is inherently thread safe and can be used safely in multiple threads.
    Program Creek : Why String is immutable in Java?.

String, StringBuffer and StringBuilder

  1. variability
    String immutable
    StringBuffer and StringBuilder variable
  2. Thread safety
    String is immutable, so it is thread safe
    StringBuilder is not thread safe
    StringBuffer is thread safe and uses synchronized internally for synchronization

StackOverflow : String, StringBuffer, and StringBuilder.

String Pool

The String constant pool holds all String literal strings, which are determined at compile time. In addition, strings can be added to the String Pool at run time using the String's intern() method.

When a string calls the intern() method, if a string already exists in the String Pool and the string value is equal (determined by using the equals() method), the string reference in the String Pool will be returned; otherwise, a new string will be added to the String Pool and the reference of the new string will be returned.

In the following example, S1 and S2 create two different strings in the way of new String(), while s3 and s4 obtain the same string reference through s1.intern() and s2.intern() methods. Intern() first puts "aaa" into the String Pool, and then returns the string reference. Therefore, 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

If you create a string in the literal form of "bbb", the string will be automatically put into the String Pool.

String s5 = "bbb";
String s6 = "bbb";
System.out.println(s5 == s6);  // true

Before Java 7, the String Pool was placed in the runtime constant pool, which belongs to the permanent generation. In Java 7, the String Pool was moved to the heap. This is because the space of the permanent generation is limited, which will lead to OutOfMemoryError errors in scenarios where a large number of strings are used.

new String("abc")

In this way, a total of two string objects will be created (provided that there is no "abc" string object in the String Pool).

  • "abc" is a string literal, so a string object will be created in the String Pool during compilation to point to the "abc" string literal;
  • Using new will create a string object in the heap.
    Create a test class whose main method uses this method to create string objects.
public class NewStringTest {
    public static void main(String[] args) {
        String s = new String("abc");
    }
}

Decompile with javap -verbose to get 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
// ...

In the Constant Pool, #19 stores the String literal "abc", #3 is the String object of the String Pool, which points to #19 this String literal. In the main method, line 0: creates a String object in the heap using new #2, and uses ldc #3 to take the String object in the String Pool as the parameter of the String constructor.

The following is the source code of the String constructor. You can see that when a String object is used as the constructor parameter of another String object, the content of the value array will not be completely copied, but will all point to the same value array.

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

3, Operation

Parameter transfer

Java parameters are passed into the method in the form of value passing, not by reference.

In the following code, the dog of dog is a pointer and stores the address of the object. When a parameter is passed into a method, it is essentially to pass the address of the object to the formal parameter in the form of value.

public class Dog {

    String name;

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

    String getName() {
        return this.name;
    }

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

    String getObjectAddress() {
        return super.toString();
    }
}

Changing the field value of the object in the method will change the field value of the original object, because the same object is referenced.

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");
    }
}

However, if the pointer refers to other objects in the method, the two pointers inside and outside the method point to different objects. Changing the content of the object pointed to by 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
    }
}

StackOverflow: Is Java "pass-by-reference" or "pass-by-value"?

float and double

Java cannot implicitly perform a downward transformation because it reduces precision.

1.1 literal is of double type and cannot be directly assigned to float variable because it is a downward transformation.

// float f = 1.1;

1.1f literal quantity is the float type.

float f = 1.1f;

Implicit type conversion

Because literal 1 is an int type, it is more precise than short type, so you cannot implicitly convert int type down to short type.

short s1 = 1;
// s1 = s1 + 1;

However, using the + = or + + operator performs implicit type conversion.

s1 += 1;
s1++;

The above statement is equivalent to transforming the calculation result of s1 + 1 downward:

s1 = (short) (s1 + 1);

StackOverflow : Why don't Java's +=, -=, *=, /= compound assignment operators require casting?

switch

Starting with Java 7, you can use String objects in switch conditional judgment statements.

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

Switch does not support long, float and double because the original design intention of switch is to judge the equivalence of types with only a few values. If the values are too complex, it is better to 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;
// }

StackOverflow : Why can't your switch statement data type be long, Java?

4, Keywords

final

1. Data

The declared data is a constant, which can be a compile time constant or a constant that cannot be changed after run initialization.

  • For primitive types, final leaves their values unchanged
  • For reference types, final keeps the reference unchanged, but the referenced object can be changed internally
final int x = 1;
// x = 2;  // cannot assign value to final variable 'x'
final A y = new A();
y.a = 1;

2. Method

Methods modified by final cannot be overridden by subclasses
The private method is implicitly specified as final. If the signature of the method defined in the subclass is the same as that of a private method in the base class, the subclass method does not override the base class method, but defines a new method in the subclass.

3. Class

Declared classes are not allowed to be inherited

static

1. Static variables

  • Static variable: also known as class variable. This variable belongs to a class. All instances of a class share a static variable and can be accessed directly through the class name. The static variable has a value in memory
  • Instance variables generate an instance variable without creating an instance, and live and die together with the instance
public class A {

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

    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;
        int y = A.y;
    }
}

2. Static method

Static methods exist when the class is loaded. They do not depend on any instance. They must be implemented and cannot be abstract methods
Only static fields and static methods of the class can be accessed. this and super keywords are not allowed in methods

3. Static statement block

Static statement blocks run only once during class initialization

4. Static internal class

The non static inner class depends on the instance of the outer class, that is, you need to create an outer class instance before you can use this instance 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();
        StaticInnerClass staticInnerClass = new StaticInnerClass();
    }
}

Static internal classes cannot access non static variables and methods of external classes.

5. Initialization sequence

Static variables and static statements take precedence over instance variables and ordinary statement blocks. The initialization order of static variables and static statement blocks depends on their order in the code

public static String staticField = "Static variable";
static {
    System.out.println("Static statement block");
}
public String field = "Instance variable";
{
    System.out.println("Common statement block");
}

The last is the initialization of the constructor.

public InitialOrderTest() {
    System.out.println("Constructor");
}

In case of inheritance, the initialization order is:

Parent class (static variable, static statement block)
Subclasses (static variables, static statement blocks)
Parent class (instance variable, common statement block)
Parent class (constructor)
Subclasses (instance variables, common statement blocks)
Subclass (constructor)

5, Object general method

overview

public native int hashCode()

public boolean equals(Object obj)

protected native Object clone() throws CloneNotSupportedException

public String toString()

public final native Class<?> getClass()

protected void finalize() throws Throwable {}

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

equals()

1. Equivalence relation

The two objects have an equivalence relationship, and the following five conditions need to be met:

I reflexivity

x.equals(x); // true

Ⅱ symmetry

x.equals(y) == y.equals(x); // true

III transitivity

if (x.equals(y) && y.equals(z))
x.equals(z); // true;

Ⅳ consistency

The equals() method is called multiple times, and the result remains unchanged

x.equals(y) == x.equals(y); // true

V comparison with null

Calling x.equals(null) on any object x that is not null will result in false

x.equals(null); // false;

2. Equivalence and equality

  • For primitive types, = = determines whether two values are equal. Primitive types have no equals() method.

  • For reference types, = = determines whether two variables refer to the same object, while equals() determines whether the referenced object is equivalent.

      Integer x = new Integer(1);
      Integer y = new Integer(1);
      System.out.println(x.equals(y)); // true
      System.out.println(x == y);      // false
    

3. Realization

  • Check whether it is a reference to the same object. If yes, return true directly;
  • Check whether it is the same type. If not, return false directly;
  • Transform the Object 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;
        return z == that.z;
    }
}

hashCode()

toString()

clone()

6, Inherit

Access rights

Abstract classes and interfaces

super

Rewriting and overloading

7, Reflection

8, Abnormal

9, Generics

10, Annotation

11, Characteristics

New features in Java versions

The difference between Java and C + +

JRE or JDK

Tags: Java Eclipse Hibernate Interview

Posted on Fri, 15 Oct 2021 04:39:43 -0400 by lapith