Regarding the questions in this series, everyone who studies Java should understand them. Of course, it doesn't matter if you just learn Java for fun. If you think you have surpassed the beginner level but do not understand these issues well, please add yourself to the beginner team.
Question 1: What am I stating?
String s = "Hello world!";
Many people have done this, but what exactly do we declare? The answer is usually: a String with the content "Hello world!". Such vague answers are often the source of unclear concepts. If you were to give an accurate answer, probably half of the people would answer it wrong.
This statement declares a reference to an object, named "s", which can point to any object of type String. Currently, it points to the String type object "Hello world!". This is what really happened. We did not declare a String object, we just declared a reference variable that can only point to the String object. So, if after the statement just now, if you run another sentence:
String string = s;
We have declared another reference that can only point to the String object, named string. No second object is generated. String still points to the original object, that is, it points to the same object as s.
Question 2: What is the difference between "==" and equals method?
The == operator is specifically used to compare the values of variables for equality. The easier thing to understand is:
Copy the code code as follows:
int a=10;
int b=10;
Then a==b will be true.
But what’s hard to understand is:
Copy the code code as follows:
String a=new String("foo");
String b=new String("foo");
Then a==b will return false.
According to the previous post, object variables are actually references, and their values point to the memory address where the object is located, not the object itself. Both a and b use the new operator, which means that two strings with the content "foo" will be generated in the memory. Since there are "two", they are naturally located at different memory addresses. The values of a and b are actually the values of two different memory addresses, so using the "==" operator, the result will be false. It is true that the objects pointed to by a and b have the content "foo" and should be "equal", but the == operator does not involve comparison of object contents.
Comparison of object contents is exactly what the equals method does.
Take a look at how the equals method of the Object object is implemented:
Copy the code code as follows:
boolean equals(Object o){
return this==o;
}
Object objects use the == operator by default. So if your self-created class does not override the equals method, then your class will get the same result using equals and using ==. It can also be seen that the equals method of Object does not achieve the goal that the equals method should achieve: to compare whether the contents of two objects are equal. Because the answer should be determined by the creator of the class, Object leaves this task to the creator of the class.
Take a look at an extreme class:
Copy the code code as follows:
Class Monster{
private String content;
...
boolean equals(Object another){ return true;}
}
I overridden the equals method. This implementation causes comparisons between Monster instances to always return true regardless of their contents.
So when you use the equals method to determine whether the contents of an object are equal, please don't take it for granted. Because maybe you think they are equal, but the author of this class doesn't think so, and the implementation of the equals method of the class is controlled by him. If you need to use the equals method, or use any hash code based collection (HashSet, HashMap, HashTable), please check the java doc to confirm how the equals logic of this class is implemented.
Question 3: Has String changed?
No. Because String is designed to be an immutable class, all its objects are immutable objects. Please look at the following code:
Copy the code code as follows:
String s = "Hello";
s = s + "world!";
Has the target pointed by s changed? This conclusion can be easily derived from the conclusion in the first article of this series. Let's see what happened. In this code, s originally pointed to a String object with the content "Hello", and then we performed a + operation on s. Has the object pointed to by s changed? The answer is no. At this time, s no longer points to the original object, but to another String object with the content "Hello world!". The original object still exists in the memory, but the reference variable s no longer points to it.
Through the above explanation, we can easily derive another conclusion. If strings are frequently modified in various ways, or unforeseeably modified, then using String to represent a string will cause a lot of memory overhead. Since the String object cannot be changed after it is created, a String object is required to represent each different string. At this time, you should consider using the StringBuffer class, which allows modification, rather than generating a new object for each different string. Moreover, the policy change between these two types is very simple.
At the same time, we can also know that if you want to use a string with the same content, you don’t need to create a new String every time. For example, if we want to initialize a String reference variable named s in the constructor and set it to the initial value, we should do this:
Copy the code code as follows:
public class Demo {
private String s;
…
public Demo {
s = "Initial Value";
}
…
}
Instead of s = new String("Initial Value");
The latter will call the constructor every time to generate a new object, which has low performance and large memory consumption, and is meaningless. Because the String object cannot be changed, only one String object can be used to represent a string with the same content. In other words, if you call the above constructor multiple times to create multiple targets, their String type attributes will all point to the same target.
The above conclusion is also based on the fact that for string constants, if the contents are the same, Guangzhou Java Training believes that they represent the same String object. Calling the constructor with the keyword new will always create a new target, regardless of whether the content is the same.
As for why the String class should be described as an immutable class, it is determined by its purpose. In fact, not only String, but also many classes in the Java standard class library are immutable. When developing a system, we sometimes need to describe immutable classes to pass a set of related values, which is also a manifestation of goal-oriented thinking. Immutable classes have some advantages. For example, because its purpose is read-only, there will be no problems with concurrent access by multiple threads. Of course, there are also some shortcomings. For example, each different situation needs an object to represent it, which may cause functional problems. Therefore, the Java standard class library also provides a variable version, namely StringBuffer.