Analysis of string storage in Java
Realization of various functions of library management code in the previous issue 🚑
- Borrow books
public class BorrowOperation implements IOperation{ public void work(BookList bookList){ System.out.println("Borrow books!"); System.out.println("Please enter the title of the book you need to borrow:"); Scanner scanner=new Scanner(System.in); String name=scanner.nextLine(); int size=bookList.getUsedSize(); for (int i = 0; i < size; i++) { Book book=bookList.getPos(i); if(book.getName().equals(name)){ System.out.println("The book has been found and borrowed by you! look forward to seeing you next time!"); book.setBorrowed(true); System.out.println(book); return; } } System.out.println("There is no such book!"); } }
2. Delete books
public class DelOperation implements IOperation{ public void work(BookList bookList){ System.out.println("Delete books!"); Scanner scanner=new Scanner(System.in); System.out.println("Please enter the title of the book you want to delete:"); String name=scanner.nextLine(); int size=bookList.getUsedSize(); int pos=-1; for (int i = 0; i < size; i++) { Book book=bookList.getPos(i); if(book.getName().equals(name)){ pos=i; break; } } if(pos==-1){ System.out.println("There is no such book!"); return; } for (int i = pos; i < size-1; i++) { //bookList.getPos(i)= bookList.getPos(i+1); Misexpression Book book=bookList.getPos(i+1); bookList.setPos(i,book); } bookList.setPos(bookList.getUsedSize(), null);//Remember to leave the reference type blank bookList.setUsedSize(bookList.getUsedSize()-1); System.out.println("Delete succeeded!"); } }
3. Print books
public class DisplayOperation implements IOperation{ public void work(BookList bookList){ System.out.println("Print books!"); int size=bookList.getUsedSize(); for (int i = 0; i <size ; i++) { Book book=bookList.getPos(i); System.out.println(book); } } }
4. Exit the system
public class ExitOperation implements IOperation{ public void work(BookList bookList){ System.out.println("Exit the system!"); System.exit(0); } }
5. Find books
public class FindOperation implements IOperation{ public void work(BookList bookList){ System.out.println("Find books!"); System.out.println("Please enter the title of the book you need to find:"); Scanner scanner=new Scanner(System.in); String name=scanner.nextLine(); int size=bookList.getUsedSize(); for (int i = 0; i < size; i++) { Book book=bookList.getPos(i); if(book.getName().equals(name)){ System.out.println("The book has been found! The information is as follows:"); System.out.println(book); break; } } System.out.println("There is no such book!"); } }
6. Return books
public class ReturnOperation implements IOperation{ public void work(BookList bookList){ System.out.println("Return the books!"); System.out.println("Please enter the title of the book you want to return:"); Scanner scanner=new Scanner(System.in); String name=scanner.nextLine(); int size=bookList.getUsedSize(); for (int i = 0; i < size; i++) { Book book=bookList.getPos(i); if(book.getName().equals(name)){ if(book.isBorrowed()==false){ System.out.println("The book is not lent and does not need to be returned!"); return; }else{ book.setBorrowed(false); System.out.println("Return successful!look forward to seeing you next time!"); System.out.println(book);//Return succeeded. Print it out and have a look return; } } } System.out.println("There is no record of this book in the library. There is no need to return it. Thank you!"); } }
character string 💛
-
A string is a string of characters enclosed in double quotation marks. Of course, this string of characters can also be "nothing". A single quotation mark cannot quote a string of characters!
-
There is no string end flag like that in C in java!
-
Initialization method of String
-
String str1=“abcdef”;// ABCDEF is a constant string
-
String str2=new String(“abcdef”);// This is the initialization of the constructor
-
char [] chars={'a','b','c','d','e','f'};
String str=new String(chars);// This is also a constructor (once the new object is, a constructor will be called)
-
-
View the source code of the String class: (ctrl + left click; ALT+7 to see all the String construction methods)
There are two important fields: char[] value and int hash;value is modified by final, which is the same as the const modification in C in front of the pointer symbol *. The meaning expressed here is that value cannot be changed, or the stored address of value cannot be changed
- One small problem:
public class Main { public static void func(String s,char[] c){ s="pig"; c[0]='g'; } public static void main(String[] args) { String str="abcdef"; char[] chars={'a','b','c','d','e','f'}; func(str,chars); System.out.println(str); System.out.println(Arrays.toString(chars)); } }
What are the running results?
Answer: abcdef and [g,b,c,d,e,f]
What we should understand is that when s on the stack accepts str, it does point to the same String object as str, but s later changes a point, which has no impact on the pointing of the argument, so str still points to the original abcdef
In C, we know that c[0] is equivalent to * (c+0), that is, in func, c[0] is already operating on the array of arguments! It is conceivable that the array modified by func will change.
- Concept of file pool 🍢
- Class file pool: the constants in the compiled bytecode file will be put into the class file pool
- Runtime constant pool: as the name suggests, when the above class bytecode file runs, the above file pool will become a runtime constant pool
- String constant pool: during the above operation: the string constant enclosed by double quotation marks will be put into the string constant pool
The runtime constant pool is in the method area! The string constant pool is from jdk1 8 starts in the heap, which is essentially a hash table!
The significance of file pool: improve efficiency. The toolbox is ready for you, which is better than finding tools one by one.
-
Along the top, is there a hash table on it?
Its essence is a data structure used to describe and organize data.
-
Is there anything special about the hash table?
When the hash table stores data, the elements are located according to the hash function. When taking an element, it is taken out by the same means. In other words, finding an element can reduce the time complexity to O(1)! We often know that the time complexity of sequential search of general arrays is O(N)
-
So what is a hash function?
When organizing data, the hash table will place each element to the specified position according to a mapping relationship. For example, the hash function is: key%length, a 12, which will be placed in the hash table of 10 grids. Then, if the calculation result of the hash function is 2, it will be placed in the position with subscript 2. According to this hash function, multiple elements may be placed in the same position. At this time, each position will string these elements with a one-way linked list, which is the hash table.
Memory layout of string
- A small question: (ask the running result) 📦
public class Main { public static void main(String[] args) { String str1="abcdef"; String str2=new String("abcdef"); System.out.println(str1==str2); }
The result is false
Why?
In short: the String pointed to by str1 will be generated a String object by the compiler, and the first field Value will point to a character array, which stores hello
Since the constant String "hello" needs to be entered into the String constant pool, the compiler will drop it to the specified position according to the hash function. The second field of the linked list node stores the address of the String object; and str1 points to the address of the String object stored in the second field of the linked list node of the hash table.
Each linked list node is as follows:
Since str2 will create a new String object, it will first go to the String constant pool to find whether there is hello. If there is no Hello, it will save a hash table, and point the first field val of the new String object to the character array. If there is, it can directly point to it.
Of course, we can also check whether the above figure is reasonable through debugging:
It is found that the value s stored in the two String objects are in the same location, but the result is false.
- Change the above code to: (what is the print result?) 🌈
public class Main { public static void main(String[] args) { String str1="hello"; String str2="hello"; System.out.println(str1==str2); } }
Print true
Why?
The String enclosed in double quotation marks is put into the String constant pool first. str1 and str2 on the stack point to the String object implemented at the bottom (the first field val of the object stores the first character address of the hello character array), so str1==str2
- Result of code change: 🌡
public class Main { public static void main(String[] args) { String str1="hello"; String str2="hel"+"lo"; System.out.println(str1==str2); } }
true
Why?
Because hel and lo are equivalent to hello at compile time, there is no difference between this question and the previous one.
- Then change the code and ask the result 👊
public class Main { public static void main(String[] args) { String str1="hello"; String str2="he"; String str3=str2+"llo"; System.out.println(str1==str3); } }
false
Why?
It can be seen that first there are two strings: hello and he, which are put into the pool first. The underlying optimization calls StringBuilder (new one), and then append("he") and append("llo") successively, and llo is also put into the pool, In other words, the character array pointed to by the val of the current StringBuilder is hello (not in the pool!), but the address of the StringBuilder object cannot be given to str3, so StringBuilder calls toString(), generates a new String object, makes its first field store the first character address of the character array just now, and returns the address of the String object to str3, overview str3!=str1
- Re change 😋
public class Main { public static void main(String[] args) { String str1="11"; String str2=new String("1")+new String("1"); System.out.println(str1==str2); } }
false
Why?
Interpretation: "11" into the pool, And str1 on the stack points to the String object generated at the bottom (the first field of the object stores the first character address of the "11" character array), new a StringBuilder object, call the parameterless constructor, "1" into the pool, and two new String objects store "1". When the design String is spliced, append "1" into the StringBuilder object and call toString() Generate a String object to store the character array address just now. And return the address of this String object to STR2 Overview: obviously str1= str2; The String object pointed to by str1 has been pooled, and the object pointed to by STR2 has not been pooled.
- Re change 🐰
public class Main { public static void main(String[] args) { String str1=new String("1")+new String("1"); str1.intern(); String str2="11"; System.out.println(str1==str2); } }
true
Why?
"1" into the pool, the address of the String object generated at the bottom layer is stored in the first field of the two new String objects, which involves String splicing, and is optimized by the bottom layer into StringBuilder. After splicing, toString() is called to generate a String object to store the address of that character array. After manual pooling, during subsequent "11" compilation, We will first find out whether the String "11" already exists in the String constant pool. Obviously, it already exists here (because there is a manual pool "11"), so the underlying layer will no longer regenerate the String object, but str2 directly points to the String object just entered the pool! So str1==str2
- Re change 👶
public class Main { public static void main(String[] args) { String str2="11"; String str1=new String("1")+new String("1"); str1.intern(); System.out.println(str1==str2); } }
false
Why?
This is just to change the order of the previous question. The purpose is to explain that if there is a String in the String constant pool, a String object that stores the same String cannot enter the pool. Even if you do the pool entry operation, str2 and str1 point to two different String objects. Therefore, it is false.
- One error prone point:
int[] arr={1,2,3,4,5}; arr={2,3,4};
Is there a problem with the above code?
have This is wrong. Why do you say this is because the references of the String object just now can be changed. Here, arr is also a reference. Why can't you change the object!
Because the java syntax stipulates that a form similar to {2,3,4} can only be used for array initialization, and the overall assignment of the array has only one chance, the above code is wrong! Bottom line: violation of initialization syntax. But it can be changed as follows:
int[] arr={1,2,3,4,5}; arr=new int[]{2,3,4};//This is a change of direction
A question for readers: (how many String objects are generated in the following code? Including those generated at the bottom.)
public class Main { public static void main(String[] args) { String str="hello"; for (int i = 0; i < 10; i++) { str+=i; } System.out.println(str); } }
(including those generated at the bottom.)
public class Main { public static void main(String[] args) { String str="hello"; for (int i = 0; i < 10; i++) { str+=i; } System.out.println(str); } }
- We know that the first field val of the String object is modified by private final. It is not only private and cannot be modified, but there is a means to view and modify it, that is, reflection. Later, when it comes to reflection, let's focus on it.