9.1. String related classes
- Understand the immutability of String
String: a string represented by a pair of ""
1.String is declared as final and cannot be inherited
2.String implements the Serializable interface: it means that the string supports serialization, that is, the string can be turned into a byte stream and transmitted to the other party through the network
The Comparable interface is implemented: it means that strings can compare sizes
3.String defines final char value internally, which is used to store string data at the bottom. Adding final means that the array can no longer be re assigned, and the elements of the array can no longer be modified
4.String: represents an immutable character sequence. Abbreviation: immutability
Embodiment: 1. When the string is re assigned, the memory area must be re assigned, and the original value cannot be assigned
2. When the existing string is connected, the memory area assignment should also be reformulated, and the original value cannot be used for assignment
3. When calling the replace() method of String to modify the specified character or String, the memory area must be assigned again. The original value cannot be assigned
5. Assign a value to a string by literal (different from new), and the string value is declared in the string constant pool
6. Strings with the same content (which can be understood as compared with rewritten equals) will not be stored in the string constant pool
@Test public void test1(){ // As long as any modification is made to the contents of the string, the memory must be rebuilt, and the original cannot be moved, which is called immutability // Strings in the constant pool are immutable, but can be newly created for both final and reference reasons // The value array is final, which only means that the first address value and array length of the character array cannot be changed // For the first time, an abc is created in the constant pool to point to s1. This assignment method is considered to be saved in the string constant pool in the method area // Two strings with the same content will not be stored in the constant pool String s1 = "abc";// Assign a value directly to the String, not new. Only the String type is like this. The literal is defined String s2 = "abc"; // The bottom layer of the string is stored in the value array. The original s1 length is specified as 3. Once the array length is determined, it cannot be modified. Because the array is modified as final, the value cannot be modified in the original specified array, and only a new space can be opened // At this time, the address of the new hello storage space points to s1, but it has no impact on s2 (abc), reflecting immutability: the original value value cannot be re assigned at the original position s1 = "hello"; // s1 and s2 use the same content in memory System.out.println(s1 == s2);// Compare the address values of s1 and s2 System.out.println(s1);// hello System.out.println(s2);// abc System.out.println("==============="); String s3 = "abc";// At first, it points to the same memory space as s2 s3 += "def"; // Reassign memory area after splicing // To splice new content after an existing string, create a new space to save abcdef System.out.println(s3);// abcdef System.out.println(s2);// abc System.out.println("================"); String s4 = "abc"; String s5 = s4.replace('a', 'm'); System.out.println(s5);//mbc, rebuild memory space System.out.println(s4);//abc } }
Instantiation method of String:
Method 1: defined by literal quantity
Mode 2: through the new + constructor
Interview question: String s = new String("abc"); How many objects are created in memory?
Two: one is the object created by the new structure in the heap space, and the other is char Data "abc" in the corresponding constant pool
If it is declared in the constant pool at the beginning, you can use the existing one, because there will not be two "abc" with the same content in the constant pool, but there are actually two objects
@Test public void test2(){ // Through literal definition: at this time, the data of s1 and s2 are declared in the string constant pool in the method area String s1 = "javaEE"; String s2 = "javaEE"; // Through the new + constructor: the address values saved in s3 and s4 at this time are the corresponding address values after the data opens up space in the heap space // If the String constructor parameter of new is an object, it will have the attribute value. Value is the final of char array, and the value attribute also has a value. Because it is a reference type variable, it stores the address value, which is the address value of the corresponding String in the constant pool String s3 = new String("javaEE");// When new, first load (open up space) in the heap String s4 = new String("javaEE");// The parameter stores an object of type String, which is a character array. The passed in String is assigned to the attribute value of the object as a parameter System.out.println(s1 == s2);// true System.out.println(s1 == s3);// false System.out.println(s1 == s4);// false System.out.println(s3 == s4);// false System.out.println("=============="); Person p1 = new Person("tom", 12); Person p2 = new Person("tom", 12); System.out.println(p1.name.equals(p2.name)); // true; name is a String type, and the equals method of String type rewrites the comparison content System.out.println(p1.name == p2.name);// true; Because name is defined literally, the data of name is stored in the string constant pool. Both names record the address value of the same tom in the constant pool, so the address value is the same p1.name = "Jerry"; System.out.println(p2.name);// tom; No variability, p1 can only re point to the new memory area }
public class Person { String name; int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } }
Conclusion:
1. The splicing result of constant (literal) and constant is in the constant pool, and there will be no constant with the same content in the constant pool
2. As long as one of them is constant, the result is in the heap
3. If the splicing result calls the intern() method, the return value is in the constant pool
@Test public void test4(){ String s1 = "javaEEhadoop"; String s2 = "javaEE"; String s3 = s2 + "hadoop"; final String s4 = "javaEE"; String s5 = s4 + "hadoop"; System.out.println(s1 == s5);// true becomes a constant because s4 is modified by final } @Test public void test3(){ String s1 = "javaEE"; String s2 = "hadoop"; String s3 = "javaEEhadoop";//s3 is the same as s4, so just one String s4 = "javaEE" + "hadoop";// It is defined by literal quantity. It is regarded as the connection of two literal quantities, which is equivalent to s3. The two contents are the same, so they are declared in the constant pool // During assignment, as long as there is a variable name involved, it is not in the constant pool, because there can only be one copy of the same content in the constant pool, which must be opened up in the heap space, which is equivalent to new // Take s5 as an example: declare a variable s5 in the stack. First, create an object in the heap space, and the address value of the object is assigned to s5. Then, the assigned string is used as the literal quantity. Essentially, the data is in the constant pool, and the attribute (value) of the object in the heap space is stored as a reference variable. The address value points to the literal quantity in the constant pool // Therefore, the address values of the heap space recorded in S5, S6 and S7 are different String s5 = s1 + "hadoop"; String s6 = "javaEE" + s2; String s7 = s1 + s2; System.out.println(s3 == s4);// true;s3 is the same as s4, so just one System.out.println(s3 == s5);// false System.out.println(s3 == s6);// false System.out.println(s3 == s7);// false System.out.println(s5 == s6);// false // s8 stores the address of the s5 object in the constant pool String s8 = s5.intern();// intern() is a method in a string. When calling this method through a string object, whether the object is in the heap or elsewhere, the return value of the intern method is forced to be declared in the constant pool System.out.println(s3 == s8);// true String s9 = (s1 + s2).intern(); System.out.println(s3 == s9);// true; If the result of splicing calls the intern method, the return value is in the constant pool }
- Memory analysis of String
- One to interview questions
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; Due to the immutability of the string, the local variable test ok in the change method will not overwrite the good in the constant pool, but open up a new space in the constant pool System.out.println(ex.ch); // best } }
- Memory analysis diagram
- The JVM involves the memory structure of strings
- Common methods of String
public class StringMethodTest { @Test public void test3(){ String s1 = "helloworld"; boolean b1 = s1.endsWith("ld");// Tests whether this string ends with the specified suffix System.out.println(b1); boolean b2 = s1.startsWith("He");// Tests whether this string starts with the specified prefix System.out.println(b2); boolean b3 = s1.startsWith("ll",2);// Tests whether this string starts with the prefix of the specified index value System.out.println(b3); String s2 = "wo"; System.out.println(s1.contains(s2));// Determines whether the string contains the specified string, similar to the KMP algorithm System.out.println(s1.indexOf("lo"));// Judge the index value of the current string for the first time in the specified string. If it is not found, return - 1 System.out.println(s1.indexOf("lo", 5));// Finds the specified string starting with the specified index value String s3 = "hellorworld"; System.out.println(s3.lastIndexOf("or"));// Find the specified string from back to front, but count from front to back System.out.println(s3.lastIndexOf("or", 6));// Start from the specified index value and find the specified string from back to front, counting from front to back /* When does indexOf(str) and lastIndexOf(str) return the same value? Case 1: there is only one (single) str. case 2: there is no STR, return - 1 */ } @Test public void test2(){ String s1 = "HelloWorld"; String s2 = "helloworld"; System.out.println(s1.equals(s2)); System.out.println(s1.equalsIgnoreCase(s2));// Ignore the case comparison string entity content for the verification code String s3 = "abc"; String s4 = s3.concat("def");// Connects the specified string to the end of the string, which is equivalent to "+", and is used in the database System.out.println(s4); String s5 = "abc"; String s6 = new String("abd"); System.out.println(s5.compareTo(s6));// Compare the size of two strings, 99-101 = - 2, negative: the former is large, positive: the latter is large; Involving string sorting String s7 = "Superman beat monster"; String s8 = s7.substring(2);// Returns a new string that intercepts a substring from the start index position System.out.println(s7);// unchanged System.out.println(s8);// Fight monsters String s9 = s7.substring(2,4);// Truncate a string from the start index position (inclusive) to the end index position (exclusive), and close the left and open the right interval System.out.println(s9); } @Test public void test1(){ String s1 = "HelloWorld"; System.out.println(s1.length());// 10; Length of the underlying array System.out.println(s1.charAt(0));// h; Returns the character at an index, which is essentially an array of operations System.out.println(s1.charAt(9));// d // System.out.println(s1.charAt(10)); System.out.println(s1.isEmpty());// false; Judge whether the string (whether the length of the underlying array is 0) is empty // Conversion or matching needs to be used, and the string itself remains unchanged String s2 = s1.toLowerCase();// Converts all characters of String type to lowercase System.out.println(s1); // s1 is immutable, and the conversion method does not modify s1 itself System.out.println(s2); // Create a new memory area and assign it to s2 String s3 = " he llo world "; String s4 = s3.trim();// Remove the space at the beginning and end of the string, and the space in the string remains unchanged. It is used for login and registration System.out.println(s4); } }
- Conversion between String, basic data type and wrapper class
Conversion between String, basic data type and wrapper class
String -- > basic data type, wrapper class: call the static method of wrapper class: parseXxx(str)
Basic data type, wrapper class -- > String: call vallueOf(xxx) overloaded by String
@Test public void test1(){ String s1 = "123";// In constant pool int n1 = Integer.parseInt(s1); String s2 = String.valueOf(n1);// "123" String s3 = n1 + ""; // As long as there are variables involved, they are all in the heap System.out.println(s1 == s3);// false ; }
- Conversion between String and char []
String -- > char []: call toCharArray() of string
Char [] -- > String: call the constructor of String
@Test public void test2(){ String s1 = "abc123"; char[] charArray = s1.toCharArray(); for (int i = 0; i < charArray.length;i++){ System.out.println(charArray[i]); } char[] arr = new char[]{'h','e','l'}; String s2 = new String(arr); System.out.println(s2); }
- Conversion between String and byte []
Code: String -- > byte []: call getBytes() of string
Decoding: byte [] -- > String: call the constructor of String
Encoding: character set -- > bytes (understandable -- > incomprehensible binary data)
Decoding: inverse process of encoding, byte -- > string (incomprehensible binary data -- > understandable)
Note: during decoding, the character set used for decoding must be consistent with the character set used for encoding, otherwise garbled code will appear
@Test public void test3() throws UnsupportedEncodingException { String s1 = "abc123 China";//Use the default character set (UTF-8) for encoding; Chinese does not exist in ASCII values, because UTF-8 character set is currently used, and one Chinese character occupies three digits byte[] bytes = s1.getBytes(); System.out.println(Arrays.toString(bytes));// Traversal array byte[] gbks = s1.getBytes("gbk");// Encoding with gbk character set; Use another character set that supports Chinese System.out.println(Arrays.toString(gbks)); System.out.println("======decode========"); String s2 = new String(bytes);//If not specified, decode with the default character set System.out.println(s2); String s3 = new String(gbks); // UTF-8 is used for decoding, so it will be garbled System.out.println(s3);// Garbled code; The encoding set and decoding set are inconsistent String s4 = new String(gbks,"gbk");//The encoding set is consistent with the decoding System.out.println(s4); }
- Introduction to StringBuffer and StringBuilder
What are the similarities and differences among string, StringBuffer and StringBuilder?
String: immutable character sequence; The bottom layer uses char [] storage, which has the lowest efficiency and needs to be rebuilt every time
StringBuffer: variable character sequence: thread safe and inefficient; The bottom layer uses char [] storage
StringBuilder: variable character sequence: new in jdk5.0, thread unsafe and efficient; The bottom layer uses char [] storage
- String,StringBuffer,StringBuilder source code analysis:
String str = new String();//char[] value = new char[0];
String st1 = new String("abc");//char[] value = new char[]{'a','b','c'};
StringBuffer sb1 = new StringBuffer();// char[] value = new char[16]; The bottom layer creates an array with a length of 16
It can be modified in the original array to reflect variability
sb1.append('a');// value[0] = 'a';
sb1.append('b');// value[1] = 'b';
StringBuffer s2 = new StringBuffer("abc");// char[] value = new char["abc".length() + 16];
Question 1: system. Out. Println (S2. Length())// three
Problem 2: capacity expansion: if the underlying array of data to be added cannot be placed, the underlying array must be expanded
By default, the capacity is expanded to 2 times + 2 of the original capacity, and the elements in the original array are copied to the new array
Guiding significance: it is recommended to use StringBuffer(int capacity) or StringBuilder(int capacity) in development. In order to avoid capacity expansion, use a constructor with parameters at the beginning, so that the efficiency is high
@Test public void test1(){ StringBuffer s1 = new StringBuffer("abc"); s1.setCharAt(0, 'm'); System.out.println(s1); StringBuffer s2 = new StringBuffer(); System.out.println(s2.length());// 0. According to the length method, the return value is the number of elements in the array }
- StringBuffer, a common method of StringBuilder
@Test public void test2(){ StringBuffer s1 = new StringBuffer("abc"); s1.append(1);// Add element for string splicing s1.append("1"); // System.out.println(s1);// abc11 //s1.delete(2,4);// ab1 delete the contents of the specified position, close left and open right // s1.replace(2, 4, "hello");// Replace the [start,end) position with str //s1.insert(2, "false"); / / specify the index value to insert the element. Like the String connector, false is regarded as five characters //s1.reverse(); / / reverse the current character sequence String s2 = s1.substring(1,3);//Returns the string at the specified index position without cutting the original string System.out.println(s1.charAt(0));//lookup System.out.println(s2); System.out.println(s1.length()); System.out.println(s1);// Variable } /* String,StringBuffer,StringBuilder What are the similarities and differences between the three? String: Immutable character sequence; the bottom layer uses char [] storage, which has the lowest efficiency and needs to be rebuilt every time StringBuffer: Variable character sequence: thread safe and inefficient; the bottom layer uses char [] storage StringBuilder: Variable character sequence: new in jdk5.0, thread unsafe, high efficiency; char [] storage is used at the bottom Source code analysis: String str = new String();//char[] value = new char[0]; String st1 = new String("abc");//char[] value = new char[]{'a','b','c'}; StringBuffer sb1 = new StringBuffer();// char[] value = new char[16];The bottom layer creates an array with a length of 16 It can be modified in the original array to reflect variability sb1.append('a');// value[0] = 'a'; sb1.append('b');// value[1] = 'b'; StringBuffer s2 = new StringBuffer("abc");// char[] value = new char["abc".length() + 16]; Problem 1: System.out.println(s2.length());// 3 Problem 2: capacity expansion: if the underlying array of data to be added cannot be placed, the underlying array must be expanded By default, the capacity is expanded to 2 times + 2 of the original capacity, and the elements in the original array are copied to the new array Guiding significance: it is recommended to use StringBuffer(int capacity) or StringBuilder(int capacity) in development. In order to avoid capacity expansion, use a constructor with parameters at the beginning, so that the efficiency is high */ @Test public void test1(){ StringBuffer s1 = new StringBuffer("abc"); s1.setCharAt(0, 'm'); System.out.println(s1); StringBuffer s2 = new StringBuffer(); System.out.println(s2.length());// 0. According to the length method, the return value is the number of elements in the array }
- Efficiency comparison of string, StringBuffer and StringBuilder:
Arrange from high to low: StringBuilder > StringBuffer > string
9.4.Java comparator
1, Note: under normal circumstances, objects in Java can only be compared: = = or! =. You can't use > or <
However, in the development scenario, multiple objects need to be sorted. The implication is to compare the size of objects
How to implement it? Use either of the two interfaces: Comparable or Comparator, two specifications that define the comparison size
2, Comparison between Comparable interface and Comparator:
Once the method of the Comparable interface is specified, the size of the object of the implementation class of the Comparable interface can be compared at any position
The Comparator interface is a temporary comparison. Specify it when necessary and temporarily create a Comparator interface implementation class for comparison
- Natural sorting: java.lang.Comparable
An example of using the Comparable interface: natural sorting: by default, Comparable will be considered, and sorting this class of data will implement the Comparable interface
1. For example, String and wrapper classes have implemented the Comparable interface, rewritten the CompareTo(obj) method, and given the way to compare the sizes of two objects
2. For example, String, after rewriting the compareTo() method, the wrapper class arranges from small to large, so you can directly use the sorting method
3. Rules for rewriting compareTo(obj) method:
If the current object this is greater than the formal parameter object obj, a positive integer is returned,
If the current object this is less than the formal parameter object obj, a negative integer is returned,
Returns zero if the current object this is equal to the parameter object obj
4. For custom classes, if you want to sort, you can let the custom class implement the Comparable interface and override the compareTo(obj) method
Indicate how to sort in the compareTo(obj) method
@Test public void test1(){ String[] arr = new String[]{"AA", "CC", "KK", "MM", "GG", "JJ", "DD"}; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); }
@Test public void test2(){ Goods[] arr = new Goods[5]; arr[0] = new Goods("lenovomouse", 20); arr[1] = new Goods("dell", 15); arr[2] = new Goods("xiaomi", 43); arr[3] = new Goods("huawei", 38); arr[4] = new Goods("microsoft", 38); // When calling the sort method, the compareTo method inside the Comparable interface is called Arrays.sort(arr); System.out.println(Arrays.toString(arr)); }
// Implement Comparable interface public class Goods implements Comparable{ private String name; private double price; public Goods() { } public Goods(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Goods{" + "name='" + name + '\'' + ", price=" + price + '}'; } // Indicates the method of comparing the size of goods @Override public int compareTo(Object o) { // Judge whether the object is a commodity if (o instanceof Goods){ Goods goods = (Goods) o; // Mode 1: if (this.price > goods.price){ return 1; }else if (this.price < goods.price){ return -1; }else{ // Secondary sorting: when the prices are the same, compare by name. If it is a user-defined class, override the compareTo method in the user-defined class return this.name.compareTo(goods.name); } // Method 2: use the compare method of packaging class //return Double.compare(this.price,goods.price); } // Type error, throwing runtime exception throw new RuntimeException("The incoming data type is inconsistent"); } }
- Custom sorting: java.util.Comparator
Use of Comparator interface: custom sorting
1. Background:
When the element type does not implement the java.lang.Comparable interface and it is inconvenient to modify the code,
Or the collation that implements the java.langComparable interface is not suitable for the current operation,
Then consider using Comparator objects to sort
2. Rewrite the Compare(Object o1,Object o2) method to compare the sizes of o1 and o2:
If 0 is returned, it means equal;
Returns a negative integer indicating that o1 is less than o2
// The String type implements the sorting method of the Comparator interface @Test public void test3(){ String[] arr = new String[]{"AA", "CC", "KK", "MM", "GG", "JJ", "DD"}; // If only one parameter is passed, it is sorted from small to large // Pass two parameters and use the anonymous object of Comparator interface to implement the anonymous object of the class Arrays.sort(arr, new Comparator() { // Override the compare method in the Comparator interface // Other methods are static and cannot be overridden // Custom sorting: sort strings from large to small @Override public int compare(Object o1, Object o2) { if (o1 instanceof String && o2 instanceof String){ String s1 = (String) o1; String s2 = (String) o2; // You can call the compareTo method overridden by the String class. Comparison: the default is from large to small return -s1.compareTo(s2); } // Inconsistent types, throwing exceptions throw new RuntimeException("Inconsistent input type"); } }); System.out.println(Arrays.toString(arr)); } // The custom type implements the sorting method of the Comparator interface @Test public void test4(){ Goods[] arr = new Goods[6]; arr[0] = new Goods("lenovomouse", 20); arr[1] = new Goods("dell", 15); arr[2] = new Goods("xiaomi", 43); arr[3] = new Goods("huawei", 38); arr[4] = new Goods("huawei", 338); arr[5] = new Goods("microsoft", 38); Arrays.sort(arr, new Comparator() { // Specify how to compare the size of goods: first sort according to the commodity name from low to high, and then sort according to the price from high to low @Override public int compare(Object o1, Object o2) { if (o1 instanceof Goods && o2 instanceof Goods){ Goods g1 = (Goods) o1; Goods g2 = (Goods) o2; // First determine whether the names are the same if (g1.getName().equals(g2.getName())){ // With the same name, compare prices, and override the compare method with the Double class return -Double.compare(g1.getPrice(), g2.getPrice()); }else{ // The names are different. The names are ranked from low to high. The compareTo method rewritten with String type is used for comparison return g1.getName().compareTo(g2.getName()); } } // Throw exceptions for different types throw new RuntimeException("Inconsistent input type"); } }); System.out.println(Arrays.toString(arr)); }