.NETインタビューパースの質問(03)-stringと文字列操作

 一般的な面接の質問:

1.文字列型は、参照型または値のタイプは?

文字列の連結方法2.、どのような方法で最良の、理由は何ですか?

3.どのような問題にのStringBuilder、注意を払う必要性を使用して?

4.どのように多くの文字列を次のコードの実行がメモリに保存されていますか?彼らは何ですか?どのような出力がありますか?なぜ?

文字列ST1 = " 123 " + " ABC " ; 文字列ST2 = " 123ABC " Console.WriteLineを(ST1 == ST2)。Console.WriteLineを(System.Object.ReferenceEquals(ST1、ST2))。

5.どのように多くの文字列を次のコードの実行がメモリに格納されていますか?彼らは何ですか?どのような出力がありますか?なぜ?

文字列S1 = " 123 " ; 文字列s2を= S1 + " ABC " ; 文字列S3 = " 123ABC " Console.WriteLineを(S2 == S3)。Console.WriteLineを(System.Object.ReferenceEquals(S2、S3))。

6.例えば、C#の文字列反転アルゴリズムを使用して実装:「54321」、「12345」を入力し、出力を

7.次のコードを出力?なぜ?

コードをコピー
オブジェクトA = " 123 " オブジェクトB = " 123 " Console.WriteLineを(System.Object.Equals(b)参照)。Console.WriteLineを(System.Object.ReferenceEquals(b)参照)。文字列SA = " 123 " ; Console.WriteLineを(System.Object.Equals(SA))。Console.WriteLineを(System.Object.ReferenceEquals(SA))。
コードをコピー

  文字列操作素人

文字列は特別な参照型、値型の使用のようなビットです。これは、パフォーマンスを向上させるために、文字列の開発を容易にするために、あまりにも一般的な文字列は、いくつかの特別な機能に与えられた特別な処理を行った主な理由は、特別です。文字列連結操作上のパフォーマンス不足文字列の一部を補うために、StringBuilderのがありました。

笑い 文字列の理解

明確な、文字列の最初の必要性は、その値は、マネージヒープ上のオブジェクトに格納され、参照型です。CHAR文字列内部は彼の長さの長さの集合体である文字char配列内の文字数です。新しい文字列()の例として、しかし、別の簡単な構文、直接代入(文字列AA =も同様の値の型である「000」)の使用を許可していない文字列を作成します。

文字列の理解、開始するには、簡単なサンプルコードで起動します。

公共のボイドDoStringTest()
{
    VAR AA = " 000 " ; SetStringValue(AA)。Console.WriteLineを(AA)。} プライベートボイドSetStringValue(文字列AA){AA + = " 111 " }

上面的输出结果为“000”。

以前の値の型や記事の参照型を通じ、我々はそれが参照型のパラメータ渡しは、アドレスへの参照であるであることから、なぜ「000111」の平均を出力しない、文字列は参照型であることを知っていますか?それは機能の大きな値型ではありません!すべてこの理由の二つの重要な特徴文字列型から茎:恒常居住者の

紙魚 定数の文字列(不変)

文字列は、一度変更されません、作成された文字列不変である、任意の変更は、新しい文字列を持つことになります。以下に示すように、次のコード例は、文字列ヒープS1 =「」、文字列「b」を加えた後、そこであろう3つの文字列ヒープの一例を作成します。

文字列S1 = " " ; 文字列s2を= S1 + " B ";

画像

「上記において、新たな文字列の変更、文字列操作」などstr1.ToLower、トリム()、削除(としての機能の数、 int型のstartIndex、int型の数)、TOUPPER()は、新しいキャラクターを持っています非常に多くのプログラミング手法の文字列は、文字列比較のサイズを無視します:

IF(str1.ToLower()== str2.ToLower())// このアプローチ新しい文字列を生成します推奨されません
 IF(文字列。比較(STR1、STR2、真の))// この方法より優れた性能を

怒りました文字列の滞留

そのため、使用の多くでは、文字列、文字列操作の不変の、文字列オブジェクト、驚異的なパフォーマンスの低下の多数の作成で結果。したがって、CLRは別の魔法の文字列を提供した、文字列が常駐して、コードの列を見て、S1、S2同じオブジェクトであることが判明!

VAR S1 = " 123 " ; VAR S2 = " 123 " ; Console.WriteLineを(System.Object.Equals(S1、S2))。// 输出真Console.WriteLineを(System.Object.ReferenceEquals(S1、S2)); // 输出真

一度だけメモリ(ヒープ)に割り当てられた同一の文字列、第二のアプリケーション文字列は、文字列は基本的なプロセスが存在するで直接リターンアドレス既存の文字列を有することが見出されています。

基本的な原理は、文字列を常駐します:

  • CLRは、メモリ初期化に存在することをプールを作成し、内部には、実際に、ハッシュテーブル、記憶および他のメモリ常駐列アドレスです。
  • 居住者のプールは、プロセス・レベル、複数のアプリケーションドメインを共有しています。彼女はGCがリサイクルされないことを意味GC制御、プロセスとライフサイクル、ではありません(リサイクルではない!それを爆発ないメモリ原因ですか?ではない心配を行い、私は以下を見てみましょう)
  • 文字列を割り当てる場合は、最初のそれは新しい文字列オブジェクトを作成しないで、同じアドレスの文字列が返されている、見られるように、プール内に常駐することになります。見つからなかった場合は、新しい文字列を作成し、プールに存在する文字列を追加します。

大容量メモリに常駐する文字列の数が、リリースされていない、メモリが非常に高い爆発の権利を引き起こすことはありませんが、もちろん、それはないでしょうか?任意の文字列にのみIL命令に存在しませんのでldstr、文字列を保持作成されます。

文字列は、次のコードのように多数の方法を作成します。

VAR S1 = " 123 " ; VAR S2 = S1 + " ABC " ; VAR S3 = 文字列.Concat(S1、S2)。VAR S4 = 123 .ToString(); VAR S5 = s2.ToUpper()。

次のILコード

画像

在上面的代码中,出现两个字符串常量,“123”和“abc”,这个两个常量字符串在IL代码中都是通过IL指令ldstr创建的,只有该指令创建的字符串才会被驻留,其他方式产生新的字符串都不会被驻留,也就不会共享字符串了,会被GC正常回收

那该如何来验证字符串是否驻留呢,string类提供两个静态方法:

  • String.Intern(string str) 可以主动驻留一个字符串;
  • String.IsInterned(string str);检测指定字符串是否驻留,如果驻留则返回字符串,否则返回NULL

画像

请看下面的示例代码

var s1 = "123";
var s2 = s1 + "abc"; Console.WriteLine(s2); //输出:123abc Console.WriteLine(string.IsInterned(s2) ?? "NULL"); //输出:NULL。因为“123abc”没有驻留 string.Intern(s2); //主动驻留字符串 Console.WriteLine(string.IsInterned(s2) ?? "NULL"); //输出:123abc

 

ウィンク 认识StringBuilder

大量的编程实践和意见中,都说大量字符串连接操作,应该使用StringBuilder。相对于string的不可变,StringBuilder代表可变字符串,不会像字符串,在托管堆上频繁分配新对象,StringBuilder是个好同志。

首先StringBuilder内部同string一样,有一个char[]字符数组,负责维护字符串内容。因此,与char数组相关,就有两个很重要的属性:

  • public int Capacity:StringBuilder的容量,其实就是字符数组的长度。
  • public int Length:StringBuilder中实际字符的长度,>=0,<=容量Capacity。

StringBuilder之所以比string效率高,主要原因就是不会创建大量的新对象,StringBuilder在以下两种情况下会分配新对象:

  • 追加字符串时,当字符总长度超过了当前设置的容量Capacity,这个时候,会重新创建一个更大的字符数组,此时会涉及到分配新对象。
  • 调用StringBuilder.ToString(),创建新的字符串。

追加字符串的过程:

  • StringBuilder的默认初始容量为16;
  • 使用stringBuilder.Append()追加一个字符串时,当字符数大于16,StringBuilder会自动申请一个更大的字符数组,一般是倍增;
  • 在新的字符数组分配完成后,将原字符数组中的字符复制到新字符数组中,原字符数组就被无情的抛弃了(会被GC回收);
  • 最后把需要追加的字符串追加到新字符数组中;

简单来说,当StringBuilder的容量Capacity发生变化时,就会引起托管对象申请、内存复制等操作,带来不好的性能影响,因此设置合适的初始容量是非常必要的,尽量减少内存申请和对象创建。代码简单来验证一下:

StringBuilder sb1 = new StringBuilder();
Console.WriteLine("Capacity={0}; Length={1};", sb1.Capacity, sb1.Length); //输出:Capacity=16; Length=0; //初始容量为16 sb1.Append('a', 12); //追加12个字符 Console.WriteLine("Capacity={0}; Length={1};", sb1.Capacity, sb1.Length); //输出:Capacity=16; Length=12; sb1.Append('a', 20); //继续追加20个字符,容量倍增了 Console.WriteLine("Capacity={0}; Length={1};", sb1.Capacity, sb1.Length); //输出:Capacity=32; Length=32; sb1.Append('a', 41); //追加41个字符,新容量=32+41=73 Console.WriteLine("Capacity={0}; Length={1};", sb1.Capacity, sb1.Length); //输出:Capacity=73; Length=73;  StringBuilder sb2 = new StringBuilder(80); //设置一个合适的初始容量 Console.WriteLine("Capacity={0}; Length={1};", sb2.Capacity, sb2.Length); //输出:Capacity=80; Length=0; sb2.Append('a', 12); Console.WriteLine("Capacity={0}; Length={1};", sb2.Capacity, sb2.Length); //输出:Capacity=80; Length=12; sb2.Append('a', 20); Console.WriteLine("Capacity={0}; Length={1};", sb2.Capacity, sb2.Length); //输出:Capacity=80; Length=32; sb2.Append('a', 41); Console.WriteLine("Capacity={0}; Length={1};", sb2.Capacity, sb2.Length); //输出:Capacity=80; Length=73;

为什么少量字符串不推荐使用StringBuilder呢?因为StringBuilder本身是有一定的开销的,少量字符串就不推荐使用了,使用String.Concat和String.Join更合适。

 

舌の笑顔 高效的使用字符串

  • 在使用线程锁的时候,不要锁定一个字符串对象,因为字符串的驻留性,可能会引发不可以预料的问题;
  • 理解字符串的不变性,尽量避免产生额外字符串,如:
if(str1.ToLower()==str2.ToLower()) //这种方式会产生新的字符串,不推荐
if(string. Compare(str1,str2,true)) //这种方式性能更好
  • 在处理大量字符串连接的时候,尽量使用StringBuilder,在使用StringBuilder时,尽量设置一个合适的长度初始值;
  • 少量字符串连接建议使用String.Concat和String.Join代替。

  题目答案解析:

1.字符串是引用类型类型还是值类型?

引用类型。

2.在字符串连加处理中,最好采用什么方式,理由是什么?

少量字符串连接,使用String.Concat,大量字符串使用StringBuilder,因为StringBuilder的性能更好,如果string的话会创建大量字符串对象。

3.使用 StringBuilder时,需要注意些什么问题?

  • 少量字符串时,尽量不要用,StringBuilder本身是有一定性能开销的;
  • 大量字符串连接使用StringBuilder时,应该设置一个合适的容量;

4.以下代码执行后内存中会存在多少个字符串?分别是什么?输出结果是什么?为什么呢?

string st1 = "123" + "abc"; string st2 = "123abc"; Console.WriteLine(st1 == st2); Console.WriteLine(System.Object.ReferenceEquals(st1, st2));

输出结果:

True
True

内存中的字符串只有一个“123abc”,第一行代码(string st1 = "123" + "abc"; )常量字符串相加会被编译器优化。由于字符串驻留机制,两个变量st1、st2都指向同一个对象。IL代码如下:

画像

5.以下代码执行后内存中会存在多少个字符串?分别是什么?输出结果是什么?为什么呢?

string s1 = "123";
string s2 = s1 + "abc"; string s3 = "123abc"; Console.WriteLine(s2 == s3); Console.WriteLine(System.Object.ReferenceEquals(s2, s3));

和第5题的结果肯定是不一样的,答案留给读者吧,文章太长了,写的好累!

6.使用C#实现字符串反转算法,例如:输入"12345", 输出"54321"

这是一道比较综合的考察字符串操作的题目,答案可以有很多种。通过不同的答题可以看出程序猿的基础水平。下面是网上比较认可的两种答案,效率上都是比较不错的。

public static string Reverse(string str)
{
    if (string.IsNullOrEmpty(str)) { throw new ArgumentException("参数不合法"); } StringBuilder sb = new StringBuilder(str.Length); //注意:设置合适的初始长度,可以显著提高效率(避免了多次内存申请) for (int index = str.Length - 1; index >= 0; index--) { sb.Append(str[index]); } return sb.ToString(); }
public static string Reverse(string str)
{
    if (string.IsNullOrEmpty(str)) { throw new ArgumentException("参数不合法"); } char[] chars = str.ToCharArray(); int begin = 0; int end = chars.Length - 1; char tempChar; while (begin < end) { tempChar = chars[begin]; chars[begin] = chars[end]; chars[end] = tempChar; begin++; end--; } string strResult = new string(chars); return strResult; }

还有一个比较简单也挺有效的方法:

public static string Reverse(string str)
{
    CHAR [] ARR = str.ToCharArray()。Array.Reverse(ARR)。戻る新しい文字列(ARR)を、}

7.次のコードを出力?なぜ?

コードをコピー
オブジェクトA = " 123 " オブジェクトB = " 123 " Console.WriteLineを(System.Object.Equals(b)参照)。Console.WriteLineを(System.Object.ReferenceEquals(b)参照)。文字列SA = " 123 " ; Console.WriteLineを(System.Object.Equals(SA))。Console.WriteLineを(System.Object.ReferenceEquals(SA))。
コードをコピー

これらの文字列の同じインスタンスへのすべてのポイント、および文字列はここでオブジェクトの宣言文を使用して差は(文字列が参照型である)がないため、完全な出力は、真です。

最終的にはそれらとオブジェクトの宣言文を使用して文字列に違いはありませんか?インタビュアーがこの質問をしていたが、Aは少し混乱し、面接の時に友人が、インタビュアーが言った、SAは、そこに違いがあり、かつ等しくありません。これについての質問については、共有してください。

おすすめ

転載: www.cnblogs.com/ljdong7/p/12021286.html