Tại sao trong Java bạn có thể thêm Chuỗi bằng toán tử +, khi Chuỗi là một lớp? bên trongString.java
mã tôi không tìm thấy bất kỳ triển khai cho toán tử này. Liệu khái niệm này có vi phạm định hướng đối tượng?
Tại sao trong Java bạn có thể thêm Chuỗi bằng toán tử +, khi Chuỗi là một lớp? bên trongString.java
mã tôi không tìm thấy bất kỳ triển khai cho toán tử này. Liệu khái niệm này có vi phạm định hướng đối tượng?
Câu trả lời:
Hãy xem các biểu thức đơn giản sau trong Java
int x=15;
String temp="x = "+x;
Trình biên dịch chuyển đổi "x = "+x;
thành một StringBuilder
bên trong và sử dụng .append(int)
để "thêm" số nguyên vào chuỗi.
Bất kỳ loại nào cũng có thể được chuyển đổi thành loại Chuỗi bằng cách chuyển đổi chuỗi.
Giá trị x của kiểu nguyên thủy T trước tiên được chuyển đổi thành giá trị tham chiếu như thể bằng cách đưa nó làm đối số cho biểu thức tạo cá thể lớp thích hợp (§15.9):
- Nếu T là boolean, thì sử dụng Boolean (x) mới.
- Nếu T là char, thì sử dụng Ký tự mới (x).
- Nếu T là byte, short hoặc int, thì sử dụng Integer (x) mới.
- Nếu T dài thì sử dụng Long (x) mới.
- Nếu T là float, sau đó sử dụng Float mới (x).
- Nếu T là gấp đôi, sau đó sử dụng Double (x) mới.
Giá trị tham chiếu này sau đó được chuyển đổi thành kiểu Chuỗi bằng chuyển đổi chuỗi.
Bây giờ chỉ cần xem xét các giá trị tham chiếu:
- Nếu tham chiếu là null, nó được chuyển đổi thành chuỗi "null" (bốn ký tự ASCII n, u, l, l).
- Mặt khác, việc chuyển đổi được thực hiện như thể bằng một lời gọi của phương thức toString của đối tượng được tham chiếu không có đối số; nhưng nếu kết quả của việc gọi phương thức toString là null, thì chuỗi "null" được sử dụng thay thế.
Phương thức toString được xác định bởi Đối tượng lớp nguyên thủy (§4.3.2). Nhiều lớp ghi đè lên nó, đáng chú ý là Boolean, Ký tự, Số nguyên, Dài, Nổi, Đôi và Chuỗi.
Xem §5.4 để biết chi tiết về bối cảnh chuyển đổi chuỗi.
Tối ưu hóa chuỗi kết nối: Một triển khai có thể chọn thực hiện chuyển đổi và nối chuỗi trong một bước để tránh tạo và sau đó loại bỏ một đối tượng Chuỗi trung gian. Để tăng hiệu năng nối chuỗi lặp lại, trình biên dịch Java có thể sử dụng lớp StringBuffer hoặc một kỹ thuật tương tự để giảm số lượng các đối tượng Chuỗi trung gian được tạo bằng cách đánh giá biểu thức.
Đối với các kiểu nguyên thủy, việc triển khai cũng có thể tối ưu hóa việc tạo đối tượng trình bao bọc bằng cách chuyển đổi trực tiếp từ kiểu nguyên thủy sang chuỗi.
Phiên bản tối ưu hóa sẽ không thực sự thực hiện chuyển đổi Chuỗi được gói đầy đủ trước tiên.
Đây là một minh họa tốt về một phiên bản tối ưu hóa được sử dụng bởi trình biên dịch, mặc dù không có sự chuyển đổi của một nguyên thủy, nơi bạn có thể thấy trình biên dịch thay đổi mọi thứ thành StringBuilder trong nền:
http://caprazzi.net/posts/java-bytecode-opes-concatenation-and-opesbuilder/
Mã java này:
public static void main(String[] args) {
String cip = "cip";
String ciop = "ciop";
String plus = cip + ciop;
String build = new StringBuilder(cip).append(ciop).toString();
}
Tạo điều này - xem cách hai kiểu ghép nối dẫn đến mã byte rất giống nhau:
L0
LINENUMBER 23 L0
LDC "cip"
ASTORE 1
L1
LINENUMBER 24 L1
LDC "ciop"
ASTORE 2
// cip + ciop
L2
LINENUMBER 25 L2
NEW java/lang/StringBuilder
DUP
ALOAD 1
INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
ASTORE 3
// new StringBuilder(cip).append(ciop).toString()
L3
LINENUMBER 26 L3
NEW java/lang/StringBuilder
DUP
ALOAD 1
INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
ASTORE 4
L4
LINENUMBER 27 L4
RETURN
Nhìn vào ví dụ trên và cách tạo mã byte dựa trên mã nguồn trong ví dụ đã cho, bạn sẽ có thể nhận thấy rằng trình biên dịch đã chuyển đổi nội bộ câu lệnh sau
cip+ciop;
vào
new StringBuilder(cip).append(ciop).toString();
Nói cách khác, toán tử +
trong nối chuỗi có hiệu quả là một tốc ký cho StringBuilder
thành ngữ dài dòng hơn .
Đây là tính năng biên dịch Java để kiểm tra toán hạng của +
toán tử. Và dựa trên các toán hạng, nó tạo ra mã byte:
Đây là những gì đặc tả Java nói :
Các toán tử + và
-
được gọi là các toán tử phụ gia. AdditiveExpression: MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpressionCác toán tử cộng gộp có cùng mức ưu tiên và được liên kết trái cú pháp (chúng nhóm từ trái sang phải). Nếu kiểu toán hạng của
+
toán tử làString
, thì phép toán là nối chuỗi.Mặt khác, kiểu của mỗi toán hạng của
+
toán tử phải là loại có thể chuyển đổi (§5.1.8) thành kiểu số nguyên thủy hoặc xảy ra lỗi thời gian biên dịch.Trong mọi trường hợp, loại của mỗi toán hạng của toán
-
tử nhị phân phải là loại có thể chuyển đổi (§5.1.8) thành kiểu số nguyên thủy hoặc xảy ra lỗi thời gian biên dịch.
Làm thế nào lớp String ghi đè toán tử +?
Nó không. Trình biên dịch thực hiện nó. Nói đúng ra, trình biên dịch sẽ quá tải toán tử + cho toán hạng String.
Trước hết (+) bị quá tải không bị ghi đè
Ngôn ngữ Java cung cấp hỗ trợ đặc biệt cho toán tử nối chuỗi (+), đã bị quá tải cho các đối tượng Chuỗi Java.
Nếu toán hạng bên trái là String, nó hoạt động như ghép.
Nếu toán hạng bên trái là Integer, nó hoạt động như toán tử cộng
int
và sau đó áp dụng các quy tắc thông thường của Java.
Ngôn ngữ Java cung cấp hỗ trợ đặc biệt cho toán tử nối chuỗi (+) và để chuyển đổi các đối tượng khác thành chuỗi. Nối chuỗi được thực hiện thông qua lớp StringBuilder
(hoặc StringBuffer
) và append
phương thức của nó .
Ý nghĩa của +
toán tử khi áp dụng cho String
được xác định bởi ngôn ngữ, như mọi người đã viết. Vì bạn dường như không thấy điều này đủ thuyết phục, hãy xem xét điều này:
Ints, float và double đều có các biểu diễn nhị phân khác nhau, và do đó, thêm hai int là một hoạt động khác nhau, về mặt thao tác bit, hơn là thêm hai float: Đối với int bạn có thể thêm từng bit, mang theo một bit và kiểm tra tràn; đối với phao bạn phải đối phó với mantissas và số mũ riêng biệt.
Vì vậy, về nguyên tắc, "bổ sung" phụ thuộc vào bản chất của các đối tượng được "thêm". Java định nghĩa nó cho String cũng như ints và float (longs, double, ...)
Các +
nhà điều hành thường được thay thế bằng một StringBuilder
lúc biên dịch. Kiểm tra câu trả lời này để biết thêm chi tiết về vấn đề đó.
+
vận hành không được thay thế bởi StringBuilder
?
+
Toán tử Plus ( ) là tính năng ngôn ngữ của Java.