此代码段来自深度中的C#
static bool AreReferencesEqual<T>(T first, T second)
where T : class
{
return first == second;
}
static void Main()
{
string name = "Jon";
string intro1 = "My name is " + name;
string intro2 = "My name is " + name;
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2));
}
Run Code Online (Sandbox Code Playgroud)
上面代码片段的输出是
True
False
Run Code Online (Sandbox Code Playgroud)
当main方法改为
static void Main()
{
string intro1 = "My name is Jon";
string intro2 = "My name is Jon";
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2));
}
Run Code Online (Sandbox Code Playgroud)
上面代码片段的输出是
True
True …Run Code Online (Sandbox Code Playgroud) 如果你正在解析,让我们说一下HTML,一旦你读到元素名称,实习生是否有益呢?这里的逻辑是这个解析器会一遍又一遍地解析相同的字符串(元素名称)?并且将解析几个文档.
理论:
// elemName is checked for null.
MarkupNode node = new MarkupNode()
{
Name = String.IsInterned(elemName) ? elemName : String.Intern(elemName),
...
};
Run Code Online (Sandbox Code Playgroud)
这个问题的动机是字符串 - 实习记忆.
我试着看看Java的String#intern()方法,但它确实如此public native String intern();
一般来说,如何实施实习?在String的情况下?
两个问题.
当我们声明文字字符串时,我们搜索堆的字符串池中是否有相同的字符串.这也是一个实习生(课堂实习生String)?
在我看来,每个文字字符串声明都需要二进制搜索,所以当n是池中现有字符串的数量时,它至少要花费log(n).如果池中有许多字符串,则可能成本很高.(可能需要权衡搜索成本和内存?)从这个角度来看,声明mant文字字符串可能很危险. 这种搜索成本的重要性以及为什么以这种方式设计java(在声明文字字符串时搜索池).
以下是我所提到的理解背景.
字符串是不变的; 它们的值在创建后无法更改.字符串缓冲区支持可变字符串.因为String对象是不可变的,所以可以共享它们.
http://www.janeg.ca/scjp/lang/strLiteral.html评论:
换句话说,因为编译器知道字符串原始值在创建后无法更改,所以它可以安全地使用现有数据并避免使用重复项来弥补内存.
公共语言运行库通过维护一个名为intern pool的表来保存字符串存储,该表包含对在程序中以编程方式声明或创建的每个唯一文字字符串的单个引用.因此,具有特定值的文字字符串实例仅在系统中存在一次.
例如,如果将相同的文字字符串分配给多个变量,则运行时将从实习池中检索对文字字符串的相同引用,并将其分配给每个变量.
Intern方法使用实习池来搜索等于str值的字符串.如果存在此类字符串,则返回其在实习池中的引用.如果该字符串不存在,则将对str的引用添加到实习池中,然后返回该引用.....如果您正在尝试减少应用程序分配的内存总量,请记住,实习字符串有两个不需要的副作用.首先,在公共语言运行时(CLR)终止之前,不太可能释放为被占用的String对象分配的内存.
那么,这是否意味着CLR为所有正在运行的.net应用程序保留一个单一的实习池?示例:如果程序A创建字符串文字"Test",并且如果另一个程序尝试创建另一个字符串文字"Test",则使用相同的副本?同样的问题也适用于JVM.
好的,这个问题是这个问题的延伸
Java字符串:"String s = new String("傻");"
上面的问题提出了与此问题相同的问题,但我有一个新的疑点.
根据Effective Java以上问题的答案,我们不应该这样做String s = new String("a new string");,因为那会产生不必要的对象.
我不确定这个结论,因为我认为Java正在进行自动字符串实习,这意味着对于一个字符串,无论如何在内存中只有一个副本.
所以让我们看看String s = new String("a new string");.
"a new string" 已经是在内存中创建的字符串.
当我这样做的时候String s = new String("a new string");,那s也是"a new string".所以根据automatic string interning,s应该指向相同的内存地址"a new string",对吧?
那我们怎么说我们创造了不必要的对象呢?
我想枚举字符串实习池中的字符串.
也就是说,我想所有的实例列表s的string这样:
string.IsInterned(s) != null
Run Code Online (Sandbox Code Playgroud)
有谁知道这是否可能?
我知道什么是字符串实习,以及为什么以下代码的行为方式如下:
var hello = "Hello";
var he_llo = "He" + "llo";
var b = ReferenceEquals(hello, he_llo); //true
Run Code Online (Sandbox Code Playgroud)
要么
var hello = "Hello";
var h_e_l_l_o = new string(new char[] { 'H', 'e', 'l', 'l', 'o' });
var b = ReferenceEquals(hello, he_llo); //false
Run Code Online (Sandbox Code Playgroud)
...或者我以为我做了,因为在我正在研究的一些代码中出现了一个微妙的错误:
var s = "";
var sss = new string(new char[] { });
var b = ReferenceEquals(s, sss); //True!?
Run Code Online (Sandbox Code Playgroud)
编译器如何知道这sss实际上将是一个空字符串?
问题1
String a1 = "I Love" + " Java";
String a2 = "I Love " + "Java";
System.out.println( a1 == a2 ); // true
String b1 = "I Love";
b1 += " Java";
String b2 = "I Love ";
b2 += "Java";
System.out.println( b1 == b2 ); // false
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,我理解它是两个字符串文字的串联,因此结果"我爱Java"将被实习,结果为真.但是,我不确定第二种情况.
问题2
String a1 = "I Love" + " Java"; // line 1
String a2 = "I Love " + "Java"; // line 2
String b1 = "I Love";
b1 += …Run Code Online (Sandbox Code Playgroud) 如何测试使用插值字符串与连接字符串的场景的差异,例如以下示例:
const string a = "I change per class or method";
string b = $"abcdefghijklmnopqrstuvw {a} xyz";
Console.WriteLine(b);
IL_0000: ldstr "abcdefghijklmnopqrstuvw {0} xyz"
IL_0005: ldstr "I change per class or method"
IL_000A: call System.String.Format
IL_000F: call System.Console.WriteLine
IL_0014: ret
Run Code Online (Sandbox Code Playgroud)
这有望a为所有代码存储一个通过字符串驻留的值,但使用的成本string.Format可能会抵消存储单个小字符串的好处。
const string a = "I change per class or method";
string b = "abcdefghijklmnopqrstuvw " + a + " xyz";
Console.WriteLine(b);
IL_0000: ldstr "abcdefghijklmnopqrstuvw I change per class or method xyz"
IL_0005: call System.Console.WriteLine …Run Code Online (Sandbox Code Playgroud)