As always, we have a lot of late arrivals to the beginning of the course, so only yesterday we had the second lesson among the new Java developer stream. But this is so, little things in life, but for now we are continuing to publish a series of articles on Java Challengers, the translation of which has been prepared for you.
In Java, the String
class encapsulates an array of char
( note of a translator — from java 9 this is already a byte
array, see Compact Strings in Java 9 ). Speaking of simple, String
is an array of characters used to make words, sentences, or other constructs.
Encapsulation is one of the most powerful concepts of object-oriented programming. Thanks to encapsulation, you don't need to know how the String
class works. You only need to know the methods of its interface.
When you look at the String
class in Java, you can see how the char
array is encapsulated:
public String(char value[]) { this(value, 0, value.length, null); }
To better understand encapsulation, imagine a physical object: a machine. Do you need to know how the car works under the hood to control it? Of course not, but you need to know what the car’s interfaces are doing: the gas pedal, brakes and steering wheel. Each of these interfaces supports certain actions: acceleration, braking, turning left, turning right. The same goes for object oriented programming.
The first article in the Java Challengers series was about method overloading, which is widely used in the String
class. Overloading can make your classes really flexible:
public String(String original) {} public String(char value[], int offset, int count) {} public String(int[] codePoints, int offset, int count) {} public String(byte bytes[], int offset, int length, String charsetName) {} // ...
Instead of trying to understand how the String
class works, this article will help you understand what it does and how to use it in your code.
The String
class is probably the most commonly used class in Java. If a new object is created in dynamic memory (memory heap) every time we use a String
, then we will waste a lot of memory. A string pool (String pool) solves this problem by storing only one object for each value of the string.
Rows in the row pool
Although we created several String
variables with Duke
and Juggy
, only two objects are created and stored in the heap. See the following sample code for proof. (Recall that in Java the operator " ==
" is used to compare two objects and determine whether the object is the same or not.)
String juggy = "Juggy"; String anotherJuggy = "Juggy"; System.out.println(juggy == anotherJuggy);
This code will return true
, because two String
variables point to the same object in the string pool. Their meanings are the same.
new
operatorNow look at this code - it looks like the previous example, but there is a difference.
String duke = new String("duke"); String anotherDuke = new String("duke"); System.out.println(duke == anotherDuke);
Based on the previous example, you might think that this code will return true
, but it is not. Adding the new
operator results in the creation of a new String
object in memory. Thus, the JVM will create two different objects.
Native methods
Native methods in Java are methods that will be compiled using the C language, usually for the purpose of memory management and performance optimization.
intern()
methodA method called "string interning" is used to store strings in a pool.
Here is what Javadoc tells us about the intern()
method:
/** * . * * ( ) {@code String}. * * intern, , * {@code String}, * {@link #equals(Object)}, . * , {@code String} * {@code String}. * * , {@code s} {@code t}, * {@code s.intern() == t.intern()} {@code true} * , {@code s.equals(t)} {@code true}. * * . * 3.10.5 The Java™ Language Specification. * * @returns , , * , , . * * @jls 3.10.5 String Literals */ public native String intern();
The intern()
method is used to store strings in a string pool. First, it checks to see if the string already created exists in the pool. If not, it creates a new line in the pool. The string pool logic is based on the Flyweight pattern.
Now, notice what happens when we use new
to create two lines:
String duke = new String("duke"); String duke2 = new String("duke"); System.out.println(duke == duke2); // false System.out.println(duke.intern() == duke2.intern()); // true
Unlike the previous example with the keyword new
, in this case the comparison returns true
. This is because using the intern()
method ensures that the string is in the pool.
equals
method in the String
classThe equals()
method is used to check whether the two classes are the same or not. Since equals()
is in Object
class, every Java class inherits it. But the equals()
method must be redefined to work correctly. Of course, String
redefines equals()
.
Take a look:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String aString = (String)anObject; if (coder() == aString.coder()) { return isLatin1() ? StringLatin1.equals(value, aString.value) : StringUTF16.equals(value, aString.value); } } return false; }
As you can see, the value of the String
class is compared through equals()
, and not through an object reference. It does not matter if the references to objects are different; states will be compared.
String
methodsThere is one more thing you need to know before solving a string comparison puzzle.
Consider the most common methods of the String
class:
// trim() // substring(int beginIndex, int endIndex) // length() // , replaceAll(String regex, String replacement) // , CharSequence contains(CharSequences)
Let's check what you learned about the String
class by solving a small puzzle.
In this problem, you compare several lines using the concepts studied. Looking at the code below, can you determine the value of each result
variable?
public class ComparisonStringChallenge { public static void main(String... doYourBest) { String result = ""; result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1"; result += "flexibleCode" == "flexibleCode" ? "2" : "3"; result += new String("doYourBest") == new String("doYourBest") ? "4" : "5"; result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7"; result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9"; System.out.println(result); } }
What will be the conclusion?
The correct answer is given at the end of the article.
String
BehaviorIn the first line we see:
result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1";
In this case, the result is false
, because when the trim()
method removes spaces, it creates a new String
using the new
operator.
Next we see:
result += "flexibleCode" == "flexibleCode" ? "2" : "3";
There is no mystery here, the strings are the same in the string pool. This comparison returns true
.
Then, we have:
result += new String("doYourBest") == new String("doYourBest") ? "4" : "5";
Using new
leads to the creation of two new lines and it does not matter whether their values are equal or not. In this case, the comparison will be false
even if the values are the same.
Further:
result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7";
Since we used the equals()
method, the string value will be compared, not an object instance.
In this case, it does not matter whether different objects or not, since the value is compared. The result is true
.
Finally, we have:
result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9";
As you saw earlier, the intern()
method puts a string into a pool of strings. Both lines point to the same object, so in this case true
.
It can be difficult to determine whether two lines indicate the same object or not, especially when the lines contain the same value. It is useful to remember that using new
always leads to the creation of a new object in memory, even if the string values are the same.
Using the methods of the String
class to compare references to objects can also be complex. The peculiarity is that if a method changes something in a string, then there will be different references to objects.
A few examples that will help clarify:
System.out.println("duke".trim() == "duke".trim());
This comparison will be true, because the trim()
method does not create a new string.
System.out.println(" duke".trim() == "duke".trim());
In this case, the first trim()
method generates a new string, since the method will do its work and therefore the links will be different.
Finally, when trim()
does its job, it creates a new line:
// trim String new String(Arrays.copyOfRange(val, index, index + len), LATIN1);
Strings are not changeable, so the status of the string cannot be changed.
To save memory, the JVM stores rows in a row pool. When creating a new line, the JVM checks its value and points to an existing object. If there is no line in the pool with this value, the JVM creates a new line.
The " ==
" operator compares object references. The equals()
method compares string values. The same rule will apply to all objects.
When using the new
operator, a new line will be created in the heap (Note of the translator - it’s originally written in the pool, but this is not so, thanks to zagayevskiy ), even if there is a line with the same value.
The answer to this problem is D. The output will be 12,568.
To be continued...
Source: https://habr.com/ru/post/428449/
All Articles