Lớp String trong Java

Dạ e có một thắc mắc muốn hỏi mn ạ, nếu dùng toán tử == để so sánh 2 string trong TH này thì sẽ ra false, mà e kiểm tra kiểu dữ liệu thì chúng cùng kiểu String, e tìm hiểu qua lớp thì thấy rằng dùng new String() là tạo ra 1 đối tượng và biến đó là con trỏ trỏ vào đối tượng đó, nhưng lớp như String thì có 2 cách tạo là dùng new String và gán với toán tử “=”, mọi người có thể giải thích cho e sự khác nhau giữa 2 cách tạo này và tại sao khi so sánh với “==” thì chúng khác nhau đc ko ạ, và với các lớp mình tự tạo thì đều dùng new Obj() để tạo đối tượng mới, vậy tại sao String cũng là 1 lớp lại có 2 cách tạo ạ, kiến thức của e chưa vững nên nói gì sai xin mn chỉ bảo ạ.
Em cảm ơn !

String s1, s2;
s2 = new String(scan.nextLine());
s1 = scan.nextLine();
		
System.out.println("instance: " + s1 instanceof String);
System.out.println("instance: " + s2 instanceof String);
System.out.println(s2 == s1);

toán tử == chỉ dùng để so sánh Primitive Data Types thôi bạn. còn String trong java là một Class, so sánh String phải dùng phương thức Equal như so sánh 2 instance. à mà trong java không có con trỏ

7 Likes

Phép toán == trong Java với kiểu dữ liệu Object (ví dụ String) cho kết quả true chỉ khi 2 đối tượng đó là một (2 biến cùng trỏ đến một ô nhớ). Còn 2 object kể cả cùng giá trị nhưng khác ô nhớ (2 đối tượng khác nhau) thì false.

8 Likes

String có 2 kiểu lưu trữ: Lưu trên stack (chuỗi thuần) và heap (đối tượng).
Bạn hiểu đơn giản:

  • Đối với kiểu nguyên thủy (primitive type), toán tử == so sánh giá trị. Chỉ đúng với chuỗi trên stack.
  • Đối với thực thể của đối tượng, toán tử == so sánh đối tượng. Chỉ trả về true khi cả vế trái và phải cùng một thực thể của đối tượng.

Khi bạn dùng new String() tức là đã tạo đối tượng mới (heap) và duy nhất. Với toán tử == thì chỉ trả về true khi so sánh với chính nó.

Đối với lớp String thì bạn nên dùng phương thức equals() để so sánh.
Một vài ví dụ:

String a = "SITUVNgcd"; // Stack
String b = "SITUVNgcd"; // Stack
String c = new String("SITUVNgcd"); // Heap
String d = new String(a); // Heap

System.out.println(a == b); // true
System.out.println(a == c); // false
System.out.println(a == d); // false

System.out.println(c == d); // false
System.out.println(c.equals(d)); // true
8 Likes

Có 3 cách khai báo String
1/
String str="CoderTapSu";
2/
String str1= new String("CoderTapSu");
3/

 char ch[]={ 'C','o','d','e','r','T','a','p','S','u'};
 String str1=new String(ch);

String là immutable hoặc là final

String a = "JAVA";
String b = "JAVA";
System.out.println(a == b);

SẼ TRẢ VỀ TRUE bởi vì a và b đều trỏ về cùng một ô nhớ “JAVA”

String c = new String("JAVA");
String d = new String("JAVA");
System.out.println(c == d);

SẼ TRẢ VỀ FALSE vì nó nằm trên 2 ô nhớ khác nhau

5 Likes

String của Java thuộc dạng reference type, không phải là primitive type, nên không có vụ lưu trên stack đâu. Do đó, toán tử == trên 2 chuỗi String vẫn so sánh bằng address như thường.

Còn lý do tại sao đoạn code này, phần a == b ra true,…

String a = "SITUVNgcd";
String b = "SITUVNgcd";
String c = new String("SITUVNgcd");

thì đơn giản là trong compile time, chuỗi “SITUVNgcd” sẽ được lưu ở String pool và tất cả chuỗi “SITUVNgcd” trong đoạn code sẽ được thay 1 biến đại diện, chẳng hạn biến situStr.

Nói nôm na là đoạn code được chuyển sang dạng như thế này, dù không chính xác lắm

class StringPool {
    public static String situStr = "SITUVNgcd";
}

String a = StringPool.situStr;
String b = StringPool.situStr;
String c = new String(StringPool.situStr);
10 Likes

String là đối tượng immutable cũng có thể xem là hằng vì một khi đã khởi tạo một giá trị String thì không thể chỉnh sửa được chỉ có thể trỏ đến ô nhớ khác thôi. VD String str1 = new String("abcd"); muốn đổi sang “abcde” thì str1 = new String("abcde"); không còn nằm trên ô nhớ cũ nữa T.T

2 Likes

Có một điều khá thú vị.

Đó là class String được phép gán literal value trực tiếp (dạng String s = “abc”).
Giống class Boolean, Character, Integer, Long, Double cũng có luật được phép gán như thế. (VD Boolean b = false là hợp lệ). Nhưng những class này được định nghĩa là class bao (wrapper class) còn String thì ko.

Trong java, String được đối xử rất đặc biệt, có thể xem như lai giữa primitive & object. Nó là kiểu tham chiếu, nhưng lại được ké đặc ân ‘gán literal value như primitive type’.
Lý do: vì chuỗi được sử dụng rất thường xuyên, nên hiệu năng (về mặt tính toán & lưu trữ) phải cần được tối ưu.

Như hình dưới, String literal được lưu trong String pool, và nếu có giá trị bằng nhau thì nó share cùng 1 vùng nhớ. Trong khi đó String object, trỏ tới 2 đối tượng khác nhau. Nên về performance, string literal tối ưu hơn, đó có lẽ là lý do tại sao String được thiết kế để vừa khởi tạo được như primitive, vừa khởi tạo như object.
Capture

Thứ hai, có thể xài toán tử + vốn là để thao tác cộng trên primitive type, + với String thực hiện nối chuỗi mà nếu ko hiểu nguyên tắc sẽ dễ toang trong mấy bài kiểm tra =)))

Thứ 3 là immutable =))) Vì cơ chế lưu trữ của string literal, nên nếu ko là immutable thì khi thay đổi giá trị, có thể gây ảnh hưởng đến những string khác cùng share chung vùng nhớ.

10 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?