Chuỗi Java: “String s = new String (” ngớ ngẩn “);”


85

Tôi là một chàng trai C ++ đang học Java. Tôi đang đọc Java hiệu quả và có điều gì đó khiến tôi bối rối. Nó nói không bao giờ viết mã như thế này:

String s = new String("silly");

Vì nó tạo ra Stringcác đối tượng không cần thiết . Nhưng thay vào đó nó nên được viết như thế này:

String s = "No longer silly";

Ok tốt cho đến nay ... Tuy nhiên, với lớp này:

public final class CaseInsensitiveString {
    private String s;
    public CaseInsensitiveString(String s) {
        if (s == null) {
            throw new NullPointerException();
        }
        this.s = s;
    }
    :
    :
}

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";
  1. Tại sao câu lệnh đầu tiên là ok? Không nên

    CaseInsensitiveString cis = "Polish";

  2. Làm cách nào để thực hiện CaseInsensitiveStringhành vi như Stringvậy để câu lệnh trên là OK (có và không mở rộng String)? Điều gì ở String khiến bạn có thể chuyển nó theo một nghĩa đen như vậy? Theo hiểu biết của tôi, không có khái niệm "phương thức khởi tạo sao chép" trong Java?


2
Chuỗi str1 = "foo"; Chuỗi str2 = "foo"; Cả str1 và str2 đều thuộc về cùng một đối tượng String, "foo", b'coz cho Java quản lý các Chuỗi trong StringPool, do đó, một biến mới tham chiếu đến cùng một Chuỗi, nó không tạo một biến khác thay vì gán cùng một alerady có trong StringPool. Nhưng khi chúng ta làm điều này: String str1 = new String ("foo"); String str2 = new String ("foo"); Ở đây cả str1 và str2 đều thuộc về các Đối tượng khác nhau, b'coz new String () bắt buộc phải tạo một Đối tượng chuỗi mới.
Akash5288

Câu trả lời:


110

Stringlà một lớp cài sẵn đặc biệt của ngôn ngữ. Nó là dành cho các Stringlớp chỉ mà bạn nên tránh nói

String s = new String("Polish");

Bởi vì nghĩa đen "Polish"đã thuộc loại String, và bạn đang tạo thêm một đối tượng không cần thiết. Đối với bất kỳ lớp nào khác, nói

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");

là điều đúng (và duy nhất, trong trường hợp này) cần làm.


8
điểm thứ hai là trình biên dịch có thể tạo ra các nội dung liên kết / lan truyền ưa thích với các ký tự chuỗi mà không nhất thiết phải có với một hàm gọi kỳ lạ như "Chuỗi (ký tự)"
Tetha

4
Vì bạn không bao giờ nên gọi new String("foo"), bạn có thể tự hỏi mình tại sao hàm tạo new String(String)tồn tại. Câu trả lời là đôi khi có một cách sử dụng tốt cho nó: stackoverflow.com/a/390854/1442870
Enwired

FYI, nhận xét của Tetha ở trên đã viết sai chính tả từ "interning", như trong chuỗi interning .
Basil Bourque,

56

Tôi tin rằng lợi ích chính của việc sử dụng dạng chữ (nghĩa là "foo" chứ không phải là Chuỗi mới ("foo")) là tất cả các ký tự của Chuỗi đều được VM 'thực tập'. Nói cách khác, nó được thêm vào một nhóm sao cho bất kỳ mã nào khác tạo ra cùng một chuỗi sẽ sử dụng Chuỗi được gộp thay vì tạo một phiên bản mới.

Để minh họa, đoạn mã sau sẽ in đúng cho dòng đầu tiên, nhưng sai cho dòng thứ hai:

System.out.println("foo" == "foo");
System.out.println(new String("bar") == new String("bar"));

14
Tương tự, đó là lý do tại sao FindBugs yêu cầu bạn thay thế "Integer (N) mới" bằng "Integer.valueOf (N)" - vì quá trình thực hiện đó.
Paul Tomblin

6
Bạn cũng nên thêm "foo" == new String ( "foo") thực tập ().
James Schek

4
Sửa: Các ký tự chuỗi được trình biên dịch tạo ra để trỏ tới cùng một tham chiếu bởi trình biên dịch, không phải VM. Máy ảo có thể thực hiện các đối tượng Chuỗi trong thời gian chạy, vì vậy dòng thứ hai có thể trả về true hoặc false!
Craig P. Motlin

1
@Motlin: Tôi không chắc điều đó chính xác. Javadoc cho lớp String yêu cầu "Tất cả các chuỗi ký tự và các biểu thức hằng có giá trị chuỗi đều được thực hiện". Vì vậy, chúng ta có thể dựa vào các nghĩa được thực hiện, có nghĩa là "foo" == "foo" phải luôn trả về true.
Leigh

3
@Leigh Có, các ký tự được thực hiện, nhưng bởi trình biên dịch chứ không phải VM. Điều Motlin nhận được là máy ảo có thể thêm vào các chuỗi, do đó, có hay không chuỗi new ("bar") == new String ("bar") -> false là việc triển khai Phụ thuộc.
Aaron Maenpaa

30

Các chuỗi được xử lý đặc biệt một chút trong java, chúng là bất biến vì vậy sẽ an toàn cho chúng khi được xử lý bằng cách đếm tham chiếu.

Nếu bạn viết

String s = "Polish";
String t = "Polish";

thì s và t thực sự tham chiếu đến cùng một đối tượng và s == t sẽ trả về true, đối với "==" đối với các đối tượng được đọc "là cùng một đối tượng" (hoặc dù sao thì cũng có thể, tôi không chắc đây có phải là một phần của đặc tả ngôn ngữ thực tế hoặc chỉ đơn giản là một chi tiết của việc triển khai trình biên dịch-vì vậy có thể không an toàn khi dựa vào điều này).

Nếu bạn viết

String s = new String("Polish");
String t = new String("Polish");

thì s! = t (vì bạn đã tạo một chuỗi mới một cách rõ ràng) mặc dù s.equals (t) sẽ trả về true (vì chuỗi thêm hành vi này thành bằng).

Điều bạn muốn viết,

CaseInsensitiveString cis = "Polish";

không thể hoạt động vì bạn đang nghĩ rằng các trích dẫn là một số loại phương thức khởi tạo ngắn mạch cho đối tượng của bạn, trong khi thực tế điều này chỉ hoạt động với java.lang.Strings cũ đơn thuần.


+1 để đề cập đến tính bất biến, đối với tôi đó là lý do thực sự trong java người ta viết strA = strB, thay vì strA = new String(strB). nó thực sự không phải làm gì nhiều với quá trình tạo chuỗi.
kritzikratzi

Chúng không được xử lý bằng cách đếm tham chiếu. JLS yêu cầu gộp chuỗi.
Marquis of Lorne

20
String s1="foo";

nghĩa đen sẽ đi trong nhóm và s1 sẽ tham chiếu.

String s2="foo";

lần này nó sẽ kiểm tra chữ "foo" đã có sẵn trong StringPool hay chưa vì hiện tại nó đã tồn tại nên s2 sẽ tham chiếu đến cùng một chữ.

String s3=new String("foo");

Chữ "foo" sẽ được tạo trong StringPool trước sau đó thông qua phương thức khởi tạo string arg String Object sẽ được tạo tức là "foo" trong heap do việc tạo đối tượng thông qua toán tử mới sau đó s3 sẽ tham chiếu đến nó.

String s4=new String("foo");

giống như s3

vì thế System.out.println(s1==s2);// **true** due to literal comparison.

System.out.println(s3==s4);// **false** due to object

so sánh (s3 và s4 được tạo ở các vị trí khác nhau trong heap)


1
Không sử dụng định dạng trích dẫn cho văn bản không được trích dẫn và sử dụng định dạng mã cho mã.
Marquis of Lorne,

12

Strings là đặc biệt trong Java - chúng là bất biến và các hằng chuỗi được tự động chuyển thành Stringcác đối tượng.

Không có cách nào để SomeStringClass cis = "value"ví dụ của bạn áp dụng cho bất kỳ lớp nào khác.

Bạn cũng không thể mở rộng String, vì nó được khai báo là final, nghĩa là không cho phép phân loại con.


7

Chuỗi Java rất thú vị. Có vẻ như các câu trả lời đã bao hàm một số điểm thú vị. Đây là hai xu của tôi.

chuỗi là bất biến (bạn không bao giờ có thể thay đổi chúng)

String x = "x";
x = "Y"; 
  • Dòng đầu tiên sẽ tạo một biến x sẽ chứa giá trị chuỗi "x". JVM sẽ tìm trong nhóm các giá trị chuỗi của nó và xem liệu "x" có tồn tại hay không, nếu có, nó sẽ trỏ biến x đến nó, nếu không tồn tại thì nó sẽ tạo nó rồi thực hiện việc gán
  • Dòng thứ hai sẽ xóa tham chiếu đến "x" và xem liệu "Y" có tồn tại trong nhóm các giá trị chuỗi hay không. Nếu nó tồn tại, nó sẽ gán nó, nếu nó không tồn tại, nó sẽ tạo nó trước rồi mới gán. Khi các giá trị chuỗi được sử dụng hay không, không gian bộ nhớ trong nhóm các giá trị chuỗi sẽ được lấy lại.

so sánh chuỗi phụ thuộc vào những gì bạn đang so sánh

String a1 = new String("A");

String a2 = new String("A");
  • a1 không bằng a2
  • a1a2là các tham chiếu đối tượng
  • Khi chuỗi được khai báo rõ ràng, các thể hiện mới sẽ được tạo và các tham chiếu của chúng sẽ không giống nhau.

Tôi nghĩ rằng bạn đang đi sai đường khi cố gắng sử dụng lớp phân biệt chữ hoa chữ thường. Để dây yên. Điều bạn thực sự quan tâm là cách bạn hiển thị hoặc so sánh các giá trị. Sử dụng một lớp khác để định dạng chuỗi hoặc để so sánh.

I E

TextUtility.compare(string 1, string 2) 
TextUtility.compareIgnoreCase(string 1, string 2)
TextUtility.camelHump(string 1)

Vì bạn đang tạo lớp, bạn có thể làm cho các so sánh làm những gì bạn muốn - so sánh các giá trị văn bản.


Trình biên dịch tạo nhóm chuỗi, không phải JVM. Các biến không chứa các đối tượng, chúng tham chiếu đến chúng. Không gian nhóm chuỗi cho các ký tự chuỗi không bao giờ được lấy lại.
Marquis of Lorne,

6

Bạn không thể. Những thứ trong dấu ngoặc kép trong Java được trình biên dịch đặc biệt nhận dạng là Chuỗi và rất tiếc là bạn không thể ghi đè (hoặc mở rộng java.lang.String- nó được khai báo final).


cuối cùng là một con cá trích đỏ ở đây. Ngay cả khi String không phải là cuối cùng, việc mở rộng String sẽ không giúp được gì cho anh ta trong trường hợp này.
Darron

1
Tôi nghĩ bạn có nghĩa là may mắn thay bạn không thể ghi đè điều này. :)
Craig P. Motlin

@Motlin: Ha! Bạn cũng có thể đúng. Tôi nghĩ rằng tôi đã đọc ở đâu đó rằng Java được thiết kế để ngăn chặn bất kỳ ai làm điều gì ngu ngốc bằng cách cố tình loại trừ bất cứ điều gì thú vị như thế này ...
Dan Vinton

6

Cách tốt nhất để trả lời câu hỏi của bạn là giúp bạn làm quen với "Nhóm hằng chuỗi". Trong java, các đối tượng chuỗi là bất biến (nghĩa là giá trị của chúng không thể thay đổi sau khi chúng được khởi tạo), vì vậy khi chỉnh sửa một đối tượng chuỗi, bạn sẽ tạo một đối tượng chuỗi đã chỉnh sửa mới trong đó đối tượng cũ chỉ nổi xung quanh trong một bộ nhớ đặc biệt được gọi là "chuỗi hồ bơi không đổi ”. tạo một đối tượng chuỗi mới bằng cách

String s = "Hello";

sẽ chỉ tạo một đối tượng chuỗi trong nhóm và tham chiếu s sẽ tham chiếu đến nó, nhưng bằng cách sử dụng

String s = new String("Hello");

bạn tạo hai đối tượng chuỗi: một trong nhóm và một trong heap. tham chiếu sẽ tham chiếu đến đối tượng trong đống.


4

- Làm cách nào để làm cho CaseInsensitiveString hoạt động giống như String để câu lệnh trên là ok (với và w / out mở rộng String)? Điều gì ở String khiến bạn có thể chuyển nó theo một nghĩa đen như vậy? Theo sự hiểu biết của tôi thì không có khái niệm "copy constructor" trong Java phải không?

Đã nói đủ ngay từ điểm đầu tiên. "Ba Lan" là một chuỗi ký tự và không thể được gán cho lớp CaseInsentiviveString.

Bây giờ về điểm thứ hai

Mặc dù bạn không thể tạo các ký tự mới, nhưng bạn có thể làm theo mục đầu tiên của cuốn sách đó để có cách tiếp cận "tương tự" để các câu sau là đúng:

    // Lets test the insensitiveness
    CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
    CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");

    assert cis5 == cis6;
    assert cis5.equals(cis6);

Đây là mã.

C:\oreyes\samples\java\insensitive>type CaseInsensitiveString.java
import java.util.Map;
import java.util.HashMap;

public final class CaseInsensitiveString  {


    private static final Map<String,CaseInsensitiveString> innerPool 
                                = new HashMap<String,CaseInsensitiveString>();

    private final String s;


    // Effective Java Item 1: Consider providing static factory methods instead of constructors
    public static CaseInsensitiveString valueOf( String s ) {

        if ( s == null ) {
            return null;
        }
        String value = s.toLowerCase();

        if ( !CaseInsensitiveString.innerPool.containsKey( value ) ) {
             CaseInsensitiveString.innerPool.put( value , new CaseInsensitiveString( value ) );
         }

         return CaseInsensitiveString.innerPool.get( value );   
    }

    // Class constructor: This creates a new instance each time it is invoked.
    public CaseInsensitiveString(String s){
        if (s == null) {
            throw new NullPointerException();
         }         
         this.s = s.toLowerCase();
    }

    public boolean equals( Object other ) {
         if ( other instanceof CaseInsensitiveString ) {
              CaseInsensitiveString otherInstance = ( CaseInsensitiveString ) other;
             return this.s.equals( otherInstance.s );
         }

         return false;
    }


    public int hashCode(){
         return this.s.hashCode();
    }

// Kiểm tra lớp bằng từ khóa "khẳng định"

    public static void main( String [] args ) {

        // Creating two different objects as in new String("Polish") == new String("Polish") is false
        CaseInsensitiveString cis1 = new CaseInsensitiveString("Polish");
        CaseInsensitiveString cis2 = new CaseInsensitiveString("Polish");

        // references cis1 and cis2 points to differents objects.
        // so the following is true
        assert cis1 !=  cis2;      // Yes they're different
        assert cis1.equals(cis2);  // Yes they're equals thanks to the equals method

        // Now let's try the valueOf idiom
        CaseInsensitiveString cis3 = CaseInsensitiveString.valueOf("Polish");
        CaseInsensitiveString cis4 = CaseInsensitiveString.valueOf("Polish");

        // References cis3 and cis4 points to same  object.
        // so the following is true
        assert cis3 == cis4;      // Yes they point to the same object
        assert cis3.equals(cis4); // and still equals.

        // Lets test the insensitiveness
        CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
        CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");

        assert cis5 == cis6;
        assert cis5.equals(cis6);

        // Futhermore
        CaseInsensitiveString cis7 = CaseInsensitiveString.valueOf("SomethinG");
        CaseInsensitiveString cis8 = CaseInsensitiveString.valueOf("someThing");

        assert cis8 == cis5 && cis7 == cis6;
        assert cis7.equals(cis5) && cis6.equals(cis8);
    }

}

C:\oreyes\samples\java\insensitive>javac CaseInsensitiveString.java


C:\oreyes\samples\java\insensitive>java -ea CaseInsensitiveString

C:\oreyes\samples\java\insensitive>

Đó là, tạo một nhóm bên trong các đối tượng CaseInsensitiveString và trả về cá thể tương ứng từ đó.

Bằng cách này, toán tử "==" trả về true cho hai tham chiếu đối tượng đại diện cho cùng một giá trị .

Điều này rất hữu ích khi các đối tượng tương tự được sử dụng rất thường xuyên và việc tạo ra chi phí đắt đỏ.

Tài liệu lớp chuỗi nói rằng lớp sử dụng một nhóm bên trong

Lớp chưa hoàn chỉnh, một số vấn đề thú vị phát sinh khi chúng ta cố gắng tìm hiểu nội dung của đối tượng khi triển khai giao diện CharSequence, nhưng mã này đủ tốt để cho thấy mục đó trong Sách có thể được áp dụng như thế nào.

Điều quan trọng cần lưu ý là bằng cách sử dụng đối tượng InternalPool , các tham chiếu không được giải phóng và do đó không được thu gom rác và điều đó có thể trở thành một vấn đề nếu nhiều đối tượng được tạo.

Nó hoạt động cho lớp String vì nó được sử dụng chuyên sâu và nhóm chỉ được tạo thành từ đối tượng "interned".

Nó cũng hoạt động tốt cho lớp Boolean, vì chỉ có hai giá trị có thể.

Và cuối cùng đó cũng là lý do tại sao valueOf (int) trong lớp Integer bị giới hạn từ -128 đến 127 giá trị int.


3

Trong ví dụ đầu tiên của bạn, bạn đang tạo một Chuỗi, "ngớ ngẩn" và sau đó chuyển nó dưới dạng tham số cho phương thức khởi tạo sao chép của Chuỗi khác, điều này tạo nên một Chuỗi thứ hai giống với chuỗi đầu tiên. Vì các chuỗi Java là bất biến (thứ thường gây nhức nhối cho những người đã quen với chuỗi C), đây là một sự lãng phí tài nguyên không cần thiết. Thay vào đó, bạn nên sử dụng ví dụ thứ hai vì nó bỏ qua một số bước không cần thiết.

Tuy nhiên, chuỗi ký tự không phải là Chuỗi phân biệt chữ hoa chữ thường nên bạn không thể làm những gì bạn muốn trong ví dụ cuối cùng của mình. Hơn nữa, không có cách nào để nạp chồng toán tử ép kiểu như bạn có thể làm trong C ++ nên không có cách nào để thực hiện những gì bạn muốn. Thay vào đó, bạn phải chuyển nó vào dưới dạng một tham số cho hàm tạo của lớp bạn. Tất nhiên, tôi có thể chỉ sử dụng String.toLowerCase () và hoàn thành nó.

Ngoài ra, CaseInsensitiveString của bạn nên triển khai giao diện CharSequence cũng như có thể là các giao diện Có thể nối tiếp và Có thể so sánh được. Tất nhiên, nếu bạn triển khai So sánh, bạn cũng nên ghi đè bằng () và hashCode ().


3

Chỉ vì bạn có từ Stringtrong lớp của mình, không có nghĩa là bạn nhận được tất cả các tính năng đặc biệt của lớp được tích hợp sẵn String.


3

CaseInsensitiveStringkhông phải là a Stringmặc dù nó chứa a String. Một Stringví dụ theo nghĩa đen chỉ có thể được gán cho a String.


2

CaseInsensitiveString và String là các đối tượng khác nhau. Bạn không thể làm:

CaseInsensitiveString cis = "Polish";

bởi vì "Polish" là một chuỗi, không phải là một chuỗi phân biệt chữ hoa chữ thường. Nếu String mở rộng CaseInsensitiveString String thì bạn không sao, nhưng rõ ràng là không.

Và đừng lo lắng về việc xây dựng ở đây, bạn sẽ không tạo ra những đồ vật không cần thiết. Nếu bạn nhìn vào mã của hàm tạo, tất cả những gì nó đang làm là lưu trữ một tham chiếu đến chuỗi bạn đã truyền vào. Không có gì bổ sung đang được tạo.

Trong trường hợp String s = new String ("foobar"), nó đang làm điều gì đó khác. Đầu tiên bạn tạo chuỗi theo nghĩa đen "foobar", sau đó tạo bản sao của nó bằng cách xây dựng một chuỗi mới từ nó. Không cần tạo bản sao đó.


Ngay cả khi bạn mở rộng Chuỗi, điều này sẽ không hoạt động. Bạn cần String để mở rộng CaseInsensitiveString.
Darron

trong cả hai trường hợp, nó là không thể, bởi vì chuỗi được tích hợp sẵn hoặc bởi vì nó được khai báo cuối cùng
luke

2

khi họ nói hãy viết

String s = "Silly";

thay vì

String s = new String("Silly");

chúng có nghĩa là nó khi tạo đối tượng String vì cả hai câu lệnh trên đều tạo đối tượng String nhưng phiên bản String () mới tạo ra hai đối tượng String: một trong heap và một trong chuỗi hằng số. Do đó sử dụng nhiều bộ nhớ hơn.

Nhưng khi bạn viết

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");

bạn không tạo một Chuỗi thay vào đó bạn đang tạo một đối tượng của lớp CaseInsensitiveString. Do đó bạn cần sử dụng toán tử mới.


1

Nếu tôi hiểu nó một cách chính xác, câu hỏi của bạn có nghĩa là tại sao chúng ta không thể tạo một đối tượng bằng cách gán trực tiếp giá trị cho nó, đừng hạn chế nó trong một lớp Wrapper of String trong java.

Để trả lời rằng tôi chỉ nói, các ngôn ngữ lập trình hướng đối tượng thuần túy có một số cấu trúc và nó nói rằng, tất cả các ký tự khi được viết một mình có thể được chuyển đổi trực tiếp thành một đối tượng của kiểu đã cho.

Điều đó chính xác có nghĩa là, nếu trình thông dịch nhìn thấy 3, nó sẽ được chuyển đổi thành một đối tượng Integer vì số nguyên là kiểu được xác định cho các ký tự như vậy.

Nếu trình thông dịch nhìn thấy bất kỳ thứ nào trong dấu ngoặc kép như 'a', nó sẽ trực tiếp tạo một đối tượng có kiểu ký tự, bạn không cần chỉ định nó vì ngôn ngữ xác định đối tượng mặc định của kiểu ký tự cho nó.

Tương tự, nếu trình thông dịch nhìn thấy một cái gì đó trong "" nó sẽ được coi là một đối tượng thuộc kiểu mặc định của nó tức là chuỗi. Đây là một số mã gốc hoạt động trong nền.

Cảm ơn MIT video bài giảng khóa học 6.00, nơi tôi có gợi ý cho câu trả lời này.


0

Trong Java, cú pháp "text" tạo ra một thể hiện của lớp java.lang.String. Nhiệm vụ:

String foo = "text";

là một phép gán đơn giản, không cần hàm tạo bản sao.

MyString bar = "text";

Bất cứ điều gì bạn làm là bất hợp pháp vì lớp MyString không phải là java.lang.String hoặc lớp cha của java.lang.String.


0

Đầu tiên, bạn không thể tạo một lớp mở rộng từ Chuỗi, vì Chuỗi là một lớp cuối cùng. Và java quản lý Chuỗi khác với các lớp khác nên chỉ với Chuỗi bạn có thể làm

String s = "Polish";

Nhưng tùy theo lớp của bạn, bạn phải gọi hàm tạo. Vì vậy, mã đó là tốt.


0

Tôi chỉ muốn nói thêm rằng Java có các hàm tạo Sao chép ...

Đó là một hàm tạo thông thường với một đối tượng cùng kiểu với đối số.


2
Đó là một mẫu thiết kế, không phải một cấu trúc ngôn ngữ. Với Java, có rất ít cách sử dụng mà ở đó một hàm tạo bản sao sẽ thú vị vì mọi thứ luôn là "bằng tham chiếu" và mỗi đối tượng chỉ có một bản sao. Trên thực tế, việc sao chép thực sự sẽ gây ra RẤT NHIỀU vấn đề.
Bill K

0

Trong hầu hết các phiên bản của JDK, hai phiên bản sẽ giống nhau:

String s = new String ("ngớ ngẩn");

String s = "Không còn ngớ ngẩn";

Bởi vì chuỗi là bất biến, trình biên dịch duy trì một danh sách các hằng số chuỗi và nếu bạn cố gắng tạo một hằng số mới, trước tiên sẽ kiểm tra xem chuỗi đã được xác định hay chưa. Nếu nó là tham chiếu đến chuỗi bất biến hiện có sẽ được trả về.

Để làm rõ - khi bạn nói "String s =", bạn đang xác định một biến mới chiếm không gian trên ngăn xếp - sau đó cho dù bạn nói "Không còn ngớ ngẩn" hay Chuỗi mới ("ngớ ngẩn") thì điều tương tự sẽ xảy ra - một điều mới chuỗi hằng được biên dịch vào ứng dụng của bạn và các tham chiếu trỏ đến đó.

Tôi không thấy sự khác biệt ở đây. Tuy nhiên, đối với lớp của riêng bạn, không phải là bất biến, hành vi này không liên quan và bạn phải gọi hàm tạo của mình.

CẬP NHẬT: Tôi đã sai! Dựa trên một phiếu bầu và nhận xét đi kèm, tôi đã kiểm tra điều này và nhận ra rằng sự hiểu biết của tôi là sai - Chuỗi mới ("Ngớ ngẩn") thực sự tạo ra một chuỗi mới thay vì sử dụng lại chuỗi hiện có. Tôi không rõ tại sao điều này sẽ là (lợi ích là gì?) Nhưng mã nói to hơn lời nói!


0

Chuỗi là một trong những lớp đặc biệt mà bạn có thể tạo chúng mà không cần phần Sring mới

nó giống như

int x = y;

hoặc là

ký tự c;



0
 String str1 = "foo"; 
 String str2 = "foo"; 

Cả str1 và str2 đều thuộc về cùng một đối tượng String, "foo", b'coz Java quản lý các Chuỗi trong StringPool, vì vậy nếu một biến mới tham chiếu đến cùng một Chuỗi, nó sẽ không tạo một biến khác thay vì gán cùng một alerady có trong StringPool .

 String str1 = new String("foo"); 
 String str2 = new String("foo");

Ở đây cả str1 và str2 đều thuộc các Đối tượng khác nhau, b'coz new String () bắt buộc phải tạo một Đối tượng chuỗi mới.


-1

Java tạo một đối tượng Chuỗi cho mỗi ký tự chuỗi mà bạn sử dụng trong mã của mình. Bất cứ lúc nào ""được sử dụng, nó cũng giống như gọinew String() .

Chuỗi là dữ liệu phức tạp chỉ "hoạt động" như dữ liệu nguyên thủy. Các chuỗi ký tự thực sự là các đối tượng mặc dù chúng ta giả sử chúng là các ký tự nguyên thủy, như 6, 6.0, 'c',v.v. Vì vậy, "chữ" của Chuỗi "text"trả về một đối tượng Chuỗi mới có giá trị char[] value = {'t','e','x','t}. Do đó, việc kêu gọi

new String("text"); 

thực sự giống như gọi điện

new String(new String(new char[]{'t','e','x','t'}));

Hy vọng từ đây, các bạn có thể thấy tại sao sách giáo khoa của mình lại coi điều này là thừa.

Để tham khảo, đây là cách triển khai của Chuỗi: http://www.docjar.com/html/api/java/lang/String.java.html

Đây là một bài đọc thú vị và có thể truyền cảm hứng cho một số thông tin chi tiết. Nó cũng tuyệt vời cho người mới bắt đầu đọc và cố gắng hiểu, vì mã thể hiện mã rất chuyên nghiệp và tuân thủ quy ước.

Một tài liệu tham khảo tốt khác là hướng dẫn Java về Chuỗi: http://docs.oracle.com/javase/tutorial/java/data/strings.html


Bất kỳ lúc nào "" được sử dụng, nó là một tham chiếu đến cùng một chuỗi, trong nhóm hằng số.
Marquis of Lorne,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.