top of page

Java Fundamental Revision - Data Type (1)

  • Writer: DeJia Wang
    DeJia Wang
  • Jan 26, 2022
  • 5 min read

Updated: Jan 27, 2022


This article serve as the first series of my Java revision notes. Content includes technical revision on Default Types, Wrapper Types & Buffer Pool.


1) Data Type

1.1 Default types

  • byte/8

  • char/16

  • short/16

  • int/32

  • float/32

  • long/64

  • double/64

  • boolean/~

Boolean has only two values: true and false, which can be stored in 1 bit, but the specific size is not clearly specified. The JVM converts data of type boolean to int at compile time, using 1 for true and 0 for false. The JVM supports boolean arrays, but does so by reading and writing byte arrays.

1.2 Wrapper types

Basic types have corresponding wrapper types, and the assignment between basic types and their corresponding wrapper types is done using automatic boxing and unboxing.

1.3 Buffer pool

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

  • new Integer(123) will create a new object every time;

  • Integer.valueOf(123) will use the object in the buffer pool, and multiple calls will get a reference to the same object.

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

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

The compiler will call the valueOf() method during the autoboxing process, so multiple Integer instances with the same value and the value in the buffer pool scope are created using autoboxing and will refer to the same object.

The buffer pools corresponding to the basic types are 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 types corresponding to these basic types, if the value range is within the range of the buffer pool, the objects in the buffer pool can be used directly.


Among all the numeric buffer pools of jdk 1.8, Integer's 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. Using -XX:AutoBoxCacheMax=<size> , we can specify the size of the buffer pool, this option will set a system property named java.lang.IntegerCache.high when the JVM is initialized, and then the system will be read when the IntegerCache is initialized properties to determine the upper bound.

Q: Is it ok to use only primitive types or wrapper types?

A: From the Java language alone, you can only use wrapper types, but there will be some problems with only basic types (collections). Basic types can implement most operations, but basic types do not have the characteristics of classes. Packaging types are the encapsulation of basic types. The two can be converted into each other, enriching the basic types of operations.


Q:Why have primitive types when only using wrapper types works?

A: Basic types are stored in the virtual machine stack. Unlike classes in java, which are stored in the heap and can only be used by reference, it can be found that the use of basic types is more efficient and saves memory, and the use of basic types in projects is large and frequent. , so using basic types can save a lot of resources and improve efficiency.


2) String

2.1 String class type

String is declared final, so it is not inheritable. (Wrapper classes such as Integer cannot be inherited either)

After Java 9, implementations of the String class use byte arrays instead to store strings, and use a coder to identify which encoding is used.

The value array is declared final, which means that after the value array is initialized, no other arrays can be referenced. And there is no method inside String to change the value array, so String is guaranteed to be immutable.


2.2 Benefits of immutability

1) The hash value can be cached: 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 also immutable, so only one calculation is required.


2) The need for String Pool


If a String object has already been created, a reference is taken from the String Pool. Using String Pool is only possible if String is immutable.

3) Security

String is often used as a parameter, and String immutability ensures that the parameter is immutable. For example, if String is variable when used as a network connection parameter, then in the process of network connection, String is changed, and the party who changed String thinks that it is now connected to another host, but the actual situation is not necessarily so.


4) Secured Thread

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

2.3 String, StringBuffer and StringBuilder

1) In terms of variability, String is immutable while StringBuffer and StringBuilder is mutable. when it comes to thread safety, String is immutable and therefore thread-safe. StringBuffer is thread-safe and uses synchronized internally for synchronization. StringBuilder is not thread safe.

2.4 String Pool

The String Pool holds all string literals, which are determined at compile time. Not only that, but you can use String's intern() method to add strings to the String Pool at runtime.


When a string calls the intern() method, if there is already a string in the String Pool that is equal to the string value (using the equals() method to determine), then 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 use the new String() method to create two different strings, while s3 and s4 obtain the same string reference through 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.

If the string is created in the form of a literal "bbb", the string is automatically put into the String Pool.

Before Java 7, String Pool was placed in the runtime constant pool, which belonged to the permanent generation. Whereas in Java 7, 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.

2.5 new String("abc")

Using this method will create a total of two string objects (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 at compile time, pointing to this "abc" string literal;

  • using the keyword 'new' will create a string object on the heap.

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

Decompiling with javap -verbose yields the following:


In the Constant Pool, #19 stores the string literal "abc", and #3 is the String Object of the String Pool, which points to the string literal #19. In the main method, line 0: uses new #2 to create a string object on the heap, and uses ldc #3 to pass the string object from the String Pool as an argument to 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 contents of the value array will not be copied completely, but will all point to the same value array.



References:



Tags: #Java

Comments


©2018 by DeJia

bottom of page