JavaRush /Blog Java /Random-VI /Dịch: Tạo đối tượng Chuỗi trong Java - sử dụng " " hoặc h...
FellowSparrow
Mức độ
Lvov

Dịch: Tạo đối tượng Chuỗi trong Java - sử dụng " " hoặc hàm tạo?

Xuất bản trong nhóm
Bản gốc: Tạo chuỗi Java bằng cách sử dụng “ ” hoặc Trình xây dựng? Bởi X Wang Dịch: Tạo đối tượng chuỗi trong Java - Cách sử dụngTrong Java, một chuỗi có thể được tạo bằng hai phương thức:
String x = "abc";
String y = new String("abc");
Sự khác biệt giữa việc sử dụng dấu ngoặc kép và sử dụng hàm tạo là gì?

1. Báo giá kép so với Người xây dựng

Câu hỏi này có thể được trả lời bằng cách xem xét hai ví dụ đơn giản. Ví dụ 1:
String a = "abcd";
String b = "abcd";
System.out.println(a == b);  // True
System.out.println(a.equals(b)); // True
a==bđúng vì cả ahai đều btham chiếu đến cùng một đối tượng - một chuỗi được khai báo dưới dạng ký tự (chuỗi ký tự bên dưới) trong vùng phương thức (chúng tôi giới thiệu người đọc đến nguồn trên tài nguyên của chúng tôi: 8 sơ đồ hàng đầu để hiểu Java , sơ đồ 8). Khi cùng một chuỗi ký tự được tạo nhiều lần, chỉ một bản sao của chuỗi được lưu trong bộ nhớ, chỉ một phiên bản của chuỗi đó (trong trường hợp của chúng tôi là "abcd"). Điều này được gọi là "thực tập chuỗi". Tất cả các hằng chuỗi được xử lý tại thời điểm biên dịch sẽ tự động được đưa vào Java. Ví dụ 2:
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d);  // False
System.out.println(c.equals(d)); // True
c==dsai vì cchúng dđề cập đến hai đối tượng khác nhau trong bộ nhớ (trên heap). Các đối tượng khác nhau luôn có các tham chiếu khác nhau. Sơ đồ này minh họa hai tình huống được mô tả ở trên: Dịch: Tạo đối tượng chuỗi trong Java - Cách sử dụng

2. Thực hiện chuỗi ở giai đoạn thực hiện chương trình

Tác giả cảm ơn LukasEder (nhận xét bên dưới là của anh ấy): Việc thực hiện chuỗi cũng có thể xảy ra trong quá trình thực thi chương trình, ngay cả khi hai chuỗi được tạo bằng hàm tạo:
String c = new String("abcd").intern();
String d = new String("abcd").intern();
System.out.println(c == d);  // Now true
System.out.println(c.equals(d)); // True

3. Khi nào nên sử dụng dấu ngoặc kép và khi nào nên sử dụng hàm tạo

Do thực tế là chữ "abcd" luôn có kiểu Chuỗi, nên việc sử dụng hàm tạo sẽ tạo thêm một đối tượng không cần thiết. Vì vậy nên sử dụng dấu ngoặc kép nếu bạn chỉ cần tạo một chuỗi. Nếu bạn thực sự cần tạo một đối tượng mới trên heap, bạn nên sử dụng hàm tạo. Các trường hợp sử dụng được hiển thị ở đây (bản gốc) . (Tôi cung cấp văn bản dịch bên dưới. Nhưng tôi vẫn khuyên bạn nên tự làm quen với mã của người bình luận tại liên kết này.)

Phương thức substring() trong JDK 6 và JDK 7

Phương thức chuỗi con() trong JDK 6 và JDK 7 của X Wang Phương thức substring(int beginIndex, int endIndex)trong JDK 6 và JDK 7 là khác nhau. Biết những khác biệt này có thể giúp bạn sử dụng phương pháp này tốt hơn. Để dễ đọc, dưới đây substring()chúng tôi sẽ đề cập đến cú pháp đầy đủ, tức là. substring(int beginIndex, int endIndex).

1. Chuỗi con() có tác dụng gì?

Phương thức substring(int beginIndex, int endIndex)trả về một chuỗi bắt đầu bằng số ký tự beginIndexvà kết thúc bằng số ký tự endIndex-1.
String x = "abcdef";
x = x.substring(1,3);
System.out.println(x);
Đầu ra:
bc

2. Điều gì xảy ra khi chuỗi con() được gọi?

Có thể bạn biết rằng, do tính bất biến nên xkhi gán x kết quả của x.substring(1,3), xnó trỏ tới một hàng hoàn toàn mới (xem sơ đồ): Dịch: Tạo đối tượng chuỗi trong Java - Cách sử dụngTuy nhiên, sơ đồ này không hoàn toàn chính xác; nó không chứng minh được điều gì thực sự đang diễn ra trong heap. Điều thực sự xảy ra khi được gọi là substring()khác nhau ở JDK 6 và JDK 7.

3. chuỗi con() trong JDK 6

Kiểu chuỗi được hỗ trợ bởi kiểu mảng char. Trong JDK 6, lớp Stringchứa 3 trường: char value[], int offset, int count. Chúng dùng để lưu trữ mảng ký tự thực tế, chỉ số của ký tự đầu tiên trong mảng, số lượng ký tự trong dòng. Khi phương thức được gọi substring(), nó sẽ tạo một hàng mới, nhưng giá trị của biến vẫn trỏ đến cùng một mảng trên heap. Sự khác biệt giữa hai chuỗi là số lượng ký tự và giá trị chỉ mục của ký tự bắt đầu trong mảng. Dịch: Tạo đối tượng chuỗi trong Java - Cách sử dụngMã bên dưới được đơn giản hóa và chỉ chứa những thông tin cơ bản để minh họa sự cố.
//JDK 6
String(int offset, int count, char value[]) {
	this.value = value;
	this.offset = offset;
	this.count = count;
}

public String substring(int beginIndex, int endIndex) {
	//check boundary
	return  new String(offset + beginIndex, endIndex - beginIndex, value);
}

4. Sự cố gây ra bởi chuỗi con() trong JDK 6

Nếu bạn có một chuỗi RẤT dài nhưng bạn chỉ cần một phần nhỏ của chuỗi đó mà bạn nhận được mỗi khi sử dụng substring(). Điều này sẽ gây ra vấn đề khi thực thi vì bạn chỉ cần một phần nhỏ nhưng vẫn phải lưu trữ toàn bộ chuỗi. Đối với JDK 6, giải pháp là mã bên dưới, mã này sẽ chuyển chuỗi thành chuỗi con thực:
x = x.substring(x, y) + ""
Người dùng STepeR đã đặt câu hỏi (xem bình luận của anh ấy) và có vẻ cần phải thêm điểm 4. "Sự cố gây ra substring()trong JDK 6" là một ví dụ rộng hơn. Tôi hy vọng đây sẽ là câu trả lời và sẽ giúp người khác nhanh chóng tìm ra vấn đề là gì. Đây là mã:
String a = "aLongLongString";
String b = a.substring(1, 2);
String c = a.substring(2, 6);
Vì vậy, trong JDK 7 b, các đối tượng сthuộc loại a Stringđược tạo bằng cách gọi một phương thức substring()trên đối tượng thuộc loại a Stringsẽ tham chiếu hai mảng mới được tạo trong heap - Lfor b, ongLfor c. Hai mảng mới này sẽ được lưu trữ trên heap CÙNG với mảng ban đầu aLongLongStringđược tham chiếu bởi a. Những thứ kia. mảng ban đầu không biến mất ở bất cứ đâu. Bây giờ chúng ta hãy quay lại JDK 6. Trong JDK 6, một đống chứa một mảng duy nhất aLongLongString. Sau khi thực thi các dòng mã
String b = a.substring(1, 2);
String c = a.substring(2, 6);
các đối tượng btham chiếu cđến cùng một mảng trong heap, tương ứng với đối tượng a: b- đến các phần tử từ chỉ mục thứ 1 đến thứ 2, c- đến các phần tử từ chỉ mục thứ 2 đến thứ 6 (đánh số bắt đầu từ 0, nhắc nhở). Những thứ kia. Rõ ràng, bất kỳ quyền truy cập nào nữa vào các biến bhoặc c trong JDK 6 sẽ thực sự dẫn đến các phần tử mong muốn của mảng ban đầu được “đếm” vào vùng nhớ heap. Trong JDK 7, bất kỳ quyền truy cập nào nữa vào các biến bhoặc c sẽ tạo ra quyền truy cập vào các mảng nhỏ hơn cần thiết đã được tạo và “sống” trong heap. Những thứ kia. Rõ ràng JDK 7 sử dụng nhiều bộ nhớ vật lý hơn trong những tình huống như thế này. Nhưng hãy tưởng tượng một tùy chọn khả thi: một số chuỗi con nhất định của biến được gán cho các biến bvà trong tương lai mọi người chỉ sử dụng chúng - các đối tượng và . Không ai còn truy cập vào biến a nữa; không có tài liệu tham khảo nào đến nó (đây là ý của tác giả bài viết). Kết quả là, tại một thời điểm nào đó, trình thu gom rác được kích hoạt và (tất nhiên là ở dạng chung nhất), chúng tôi nhận được 2 tình huống khác nhau: JDK 6 : đối tượng bị phá hủy (rác được thu thập) , NHƯNG - mảng khổng lồ ban đầu trong đống vẫn còn sống; nó được sử dụng liên tục và . JDK 7: đối tượng a bị hủy cùng với mảng ban đầu trong vùng heap. Đây là điểm trong JDK 6 có thể dẫn đến rò rỉ bộ nhớ. cabcabc

5. chuỗi con() trong JDK 7

Phương pháp này đã được cải tiến trong JDK 7. Trong JDK 7 substring(), nó thực sự tạo ra một mảng mới trên heap. Dịch: Tạo đối tượng chuỗi trong Java - Cách sử dụng
//JDK 7
public String(char value[], int offset, int count) {
	//check boundary
	this.value = Arrays.copyOfRange(value, offset, offset + count);
}

public String substring(int beginIndex, int endIndex) {
	//check boundary
	int subLen = endIndex - beginIndex;
	return new String(value, beginIndex, subLen);
}
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION