foreword
When discussing the JAVA final exam questions with my classmates, I am thinking about the use of static and String in objects, and I hereby record it, and I wish friends who do not have objects new
to come out by themselves!
Then let's take a look at the original question in the test paper first;
original title
There are mainly two classes MyClass.java
and TestMyClass.java
, the part of filling in the code is skipped directly, and then the result is output to see if you can get it all correct. The specific codes of the two classes are as follows:
MyClass.java
public class MyClass {
private int count;
String info;
public static String message = "Good";
public MyClass increase() {
count++;
return this;
}
private MyClass() {
this.count=0;
this.info = "GoodLuck";
}
public int getCount() {
return count;
}
public static MyClass getInstance() {
return new MyClass();
}
}
复制代码
TestMyClass.java
public class TestMyClass {
public static void main(String[] args) {
MyClass mc1 = MyClass.getInstance();
MyClass mc2 = MyClass.getInstance();
mc1.message = "Great";
mc2.message = "Excellent";
MyClass.message = "Nice";
System.out.println(mc1.message+":"+mc2.message+":"+MyClass.message);
System.out.println(mc1.info == mc2.info);
mc2.info = new String("GoodLuck");
System.out.println(mc1.info == mc2.info);
System.out.println(mc1.info.equals(mc2.info));
System.out.println(mc1.increase().increase().getCount());
}
}
复制代码
operation result:
Nice:Nice:Nice
true
false
true
2
复制代码
If you got all the answers right, then congratulations, the foundation is very good; don't be discouraged if you answered incorrectly, then listen to me, and build a solid foundation;
static
If you want to do a good job, you must first sharpen your tools. Before starting the analysis, let's review some knowledge about static;
Introduction
Static means "global" or "static", which is used to modify member variables and member methods, and can also form static static code blocks, but there is no concept of global variables in the Java language;
The member variables and member methods modified by static are independent of any object of the class, that is, it does not depend on a specific instance of the class and is shared by all instances of the class;
As long as the class is loaded, the Java virtual machine can locate them in the method area of the runtime data area according to the class name, so the static object can be accessed before any of its objects are created, without referencing any objects;
Static member variables and member methods decorated with public are essentially global variables and global methods. When an object of its class is declared, a copy of the static variable is not generated, but all instances of the class share the same static variable;
A static variable can be modified with private, which means that the variable can be used in the static code block of the class or in other static member methods of the class, but cannot be directly referenced by the class name in other classes, which is very important;
In fact, you need to understand that private is the access limit, static means that it can be used without instantiation, so it is easier to understand, and the effect of adding other access keywords in front of static is analogous.
Static modified member variables and member methods are conventionally called static variables and static methods, and can be accessed directly through the class name. The access syntax is:
类名.静态方法名(参数列表…)
复制代码
use
After reviewing the static related knowledge, let's take a look at the use in the topic;
// MyClass.java
public static String message = "Good";
// TestMyClass.java
MyClass mc1 = MyClass.getInstance();
MyClass mc2 = MyClass.getInstance();
mc1.message = "Great";
mc2.message = "Excellent";
MyClass.message = "Nice";
System.out.println(mc1.message+":"+mc2.message+":"+MyClass.message);
复制代码
First, the member variable is modified with static message
, and then through the breakpoint debugging, we can know that the two objects mcl1
and mcl2
are assigned to two different addresses;
When debugging down, it is found mc1.message
that the values of mc2.message
the MyClass.message
three member variables are the same, and they are all from Great → Excellent → Nice
, which is just reviewed, the member variables modified by static become shared variables and are shared by all instances of the class;
Next, let's do another test to verify:
//修改前
private int count;
//修改后
private static int count;
复制代码
It can be found that we only operate on the mcl1
object , but mcl2
the member variables of the count
are also changed. This is because in the MyClass
class, the member variable count
is modified by static and has become the shared variable of the class, but any object of the class, both access the same count
variable ;
Of course, it can also be verified by an ID code:
System.out.println("mcl1: " + System.identityHashCode(mc1));
System.out.println("mcl2: " + System.identityHashCode(mc2));
System.out.println("mcl1_count: " + System.identityHashCode(mc1.getCount()));
System.out.println("mcl2_count: " + System.identityHashCode(mc2.getCount()));
复制代码
mcl1: 940553268
mcl2: 1720435669
mcl1_count: 1020923989
mcl2_count: 1020923989
复制代码
So the System.out.println(mc1.message+":"+mc2.message+":"+MyClass.message);
output is Nice:Nice:Nice
;
Next, let's talk about some little knowledge about String;
String
Regarding String, what is used here is not comprehensive;
== and equals()
Let's talk about the comparison of String first. There are two common comparisons, namely ==
and equals()
;
Among them, ==
the comparison is whether the addresses of the two strings are equal (the same address), and the equals()
method compares whether the contents of the two string objects are the same (of course, if the two strings refer to the same address, using the equals()
comparison also returns true
);
Here I have to mention the second knowledge point, the difference between String constant and non-constant;
constant and non-constant
So what is a constant and what is a non-const? A simple understanding is that String name = "sid10t."
this is a constant, which belongs name
to assigning to and directly stored in the constant pool, and String name = new String("sid10t.")
this is a non-const, because re-creating an object will convert the string sid10t.
Store in the constant pool, and then create an object in Heap to point to name
;
So why mention this here? Of course, because they are quite different;
There is a specification in Chapter 3.10.5 of the Java Language Specification (JavaSE 1.8 version). All Java language compilation and runtime environment implementations must be implemented according to this specification. There is such a sentence:
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.
The general meaning is that all string constants with the same content must refer to the same string object, in other words, the memory address is the same;
Because the string whose value is constant, will be limited to share the same object through the String.intern()
function ;
The intern()
function , or you can refer to the description String (Java Platform SE 8) ;
Back to the topic, take a look at this code in the language specification:
package testPackage;
class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((hello == "Hello") + " ");
System.out.print((Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
System.out.print((hello == ("Hel"+lo)) + " ");
System.out.println(hello == ("Hel"+lo).intern());
}
}
class Other { static String hello = "Hello"; }
复制代码
and a class in another package:
package other;
public class Other { public static String hello = "Hello"; }
复制代码
operation result:
true true true true false true
复制代码
in conclusion:
- Strings in the same class in the same package represent references to the same String object;
- Strings in different classes in the same package represent references to the same String object;
- Strings in different classes in different packages also represent references to the same String object;
- Strings evaluated by constant expressions are evaluated at compile time and then treated as literals;
- Strings computed by concatenation at runtime are newly created and therefore different;
- Explicitly embedding a computed string has the same result as any existing literal string with the same content;
If the understanding of the conclusion is not very deep, then look at the following explanation:
System.out.print((hello == "Hello") + " ");
System.out.print((Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
复制代码
"Hello" and "lo" are string constants, which are determined at compile time . First check whether the string constant pool contains "Hello" and "lo", if not, add "Hello" and "lo" to the character In the string constant pool, and directly point to them, so hello
and lo
directly point to "Hello" and "lo" of the string constant pool respectively, that is hello
, lo
the addresses pointed to are "Hello" and "lo" in the constant pool respectively, so the first An output is hello
actually "Hello", so "Hello" == "Hello"
the true
first three outputs are the same;
System.out.print((hello == ("Hel"+"lo")) + " ");
复制代码
"Hel" and "lo" are both string constants. When a string is formed by concatenating multiple string constants , it must also be a string constant itself. It will be optimized into "Hello" by the compiler, because "Hello" is in the constant pool, so the output is true
;
System.out.print((hello == ("Hel"+lo)) + " ");
System.out.println(hello == ("Hel"+lo).intern());
复制代码
JVM For string references, since there are string references in the +
connection of strings, and the value of the reference cannot be determined during program compilation, that is, it will not be stored in the constant pool "Hel"+lo
without executing the intern()
method . "Hel"+lo
, but "Hel" will be stored in the constant pool, so output one is true
and one is false
;
intern()
String.intern()
It is a Native method. Its function is to return a reference to the string in the string constant pool if the string constant pool already contains a string equal to this String object, otherwise the reference address of the current String object (in the heap) Add to the string constant pool and return.
JAVA source code
/*
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to
this String object as determined by the equals(Object) method, then the string from
the pool is returned. Otherwise, this String object is added to the pool and a
reference to this String object is returned.
It follows that for any two strings s and t, s.intern() == t.intern() is true if and
only if s.equals(t) is true.
All literal strings and string-valued constant expressions are interned. String
literals are defined in section 3.10.5 of the The Java Language Specification.
Returns:
a string that has the same contents as this string, but is guaranteed to be from a
pool of unique strings.
*/
public native String intern();
复制代码
native source code
String.c
Java_java_lang_String_intern(JNIEnv *env, jobject this)
{
return JVM_InternString(env, this);
}
复制代码
jvm.h
/*
* java.lang.String
*/
JNIEXPORT jstring JNICALL
JVM_InternString(JNIEnv *env, jstring str);
复制代码
jvm.cpp
JVM_ENTRY(jstring, JVM_InternString(JNIEnv *env, jstring str))
JVMWrapper("JVM_InternString");
JvmtiVMObjectAllocEventCollector oam;
if (str == NULL) return NULL;
oop string = JNIHandles::resolve_non_null(str);
oop result = StringTable::intern(string, CHECK_NULL);
return (jstring) JNIHandles::make_local(env, result);
JVM_END
复制代码
symbolTable.cpp
oop StringTable::intern(Handle string_or_null, jchar* name,
int len, TRAPS) {
unsigned int hashValue = java_lang_String::hash_string(name, len);
int index = the_table()->hash_to_index(hashValue);
oop string = the_table()->lookup(index, name, len, hashValue);
// Found
if (string != NULL) return string;
// Otherwise, add to symbol to table
return the_table()->basic_add(index, string_or_null, name, len,
hashValue, CHECK_NULL);
}
oop StringTable::lookup(int index, jchar* name,
int len, unsigned int hash) {
for (HashtableEntry<oop>* l = bucket(index); l != NULL; l = l->next()) {
if (l->hash() == hash) {
if (java_lang_String::equals(l->literal(), name, len)) {
return l->literal();
}
}
}
return NULL;
}
复制代码
Its general implementation structure is: JAVA uses jni to call the method of StringTable implemented by C++. The intern
method of StringTable intern
is similar to the implementation of HashMap in Java, but it cannot be automatically expanded, and the default size is 1009.
It should be noted that the String Pool of String is a fixed-size Hashtable, and the default size is 1009. If a lot of Strings are put into the String Pool, it will cause serious Hash conflicts, resulting in a very long linked list and a long linked list. The immediate impact is that when calling String.intern
, the performance will drop significantly (because it needs to be searched one by one).
It StringTable
is is the length of 1009, so if there are too many strings in the constant pool, the efficiency will drop rapidly.
In JDK7, the length of StringTable can be specified by a parameter: -XX:StringTableSize=99991
;
use
In versions before JDK1.7, when calling this method, it will go to the constant pool to check whether the constant already exists. If it already exists, it will directly return the address value of the constant in the constant pool. Create one in the constant pool and return its address value.
But in JDK1.7 and later versions, the constant pool moved from the perm area to the heap area. intern()
When it is detected that the constant does not exist in the constant pool, the object will not be created directly in the constant pool, but the reference of the object in the heap will be directly stored in the constant pool to reduce memory overhead.
Look at this code:
public static void main(String[] args) {
// part1
String s1 = new String("sid10t.");
s1.intern();
String s2 = "sid10t.";
System.out.println(s1 == s2);
// part2
String s3 = new String("Hello ") + new String("World!");
s3.intern();
String s4 = "Hello World!";
System.out.println(s3 == s4);
}
复制代码
Both are false
before JDK7, and the output after JDK7 is false
, respectively true
;
Next, analyze according to JDK7,
Let's look at part1 first:
String s1 = new String("sid10t.");
This line of code generates two final objects: one is the string constant in the constant pool sid10t.
, and the other is the object pointed to by the s1 reference in the heap;
Then the second line s1.intern();
returns the string constant sid10t.
in the constant pool, because the constant already exists in the constant pool, so it can be returned directly here. Therefore, in this situation of part1, this sentence can be written or not . Write , it has no effect on the output result;
So the final output must be false
that one address is in the heap and one is in the constant pool;
Let's take a look at the part2 part:
String s3 = new String("Hello ") + new String("World!");
This line of code generates three final objects: two objects in the constant pool Hello
, World!
, and an object pointed to by an s3 reference in the heap;
Then there is the second line s3.intern();
. Since there is no string constant in the current constant pool Hello World!
, it will directly store the reference address of s3 in the heap instead of copying it;
At this time, there is String s4 = "Hello World!";
already a Hello World!
constant , which is the reference address of s3, so the value of s4 is the reference address of s3, so the output is true
;
According to the above analysis, we slightly adjust the code of part2 as follows:
String s3 = new String("Hello ") + new String("World!");
// s3.intern();
String s4 = "Hello World!";
s3.intern();
System.out.println(s3 == s4);
复制代码
The output false
is , but if it is s3.intern() == s4
, the output is true
;
Presumably you should understand!
postscript
Helping others is also helping yourself, so you should always help others. In general, you have gained a lot. Not only did you consolidate your knowledge, but you also discovered and understood details that you didn’t know before. as a teacher;