2015-09-22 20 views
35

String là trường hợp đặc biệt trong Java. Đó là một lớp, mà tôi có thể kiểm tra trong source code, nhưng nó cũng có toán tử infix riêng của nó +, có vẻ là cú pháp đường cho StringBuilder.Nơi `+ 'được triển khai cho các chuỗi trong mã nguồn Java?

Ví dụ,

"Hello " + yourName; 

có thể trở thành

new StringBuilder().append("Hello ").append(yourName).toString(); 

Không có nhà khai thác sử dụng theo quy định tại Java, vì vậy mà được + định cho String?

Cơ chế tương tự có thể được sử dụng để thực hiện các toán tử bổ sung, chẳng hạn như đối với vectơ không?

+0

Không. Có thể không. –

+6

'+' được chỉ định cho 'int' ở đâu? – gronostaj

+0

@gronostaj - '+' cũng được trình biên dịch nhận ra. 'int i = 2 + 3' sẽ được thay thế bởi' int i = 5'. Trong trường hợp giá trị của int không thể được xác định tại thời gian biên dịch, thì có các lệnh như 'iadd' được sử dụng thay cho' + ' – TheLostMind

Trả lời

44

+ được triển khai trong java trình biên dịch. Trình biên dịch thay thếString + String với thời gian biên dịch hằng số hoặc StringBuilder mã. Lưu ý rằng điều này cũng áp dụng cho nguyên thủy. tức là, int i=1+2 có thể được thay thế trực tiếp thành int i=3 trong quá trình biên dịch.

+2

Bạn có một liên kết đến nguồn trình biên dịch mà điều này xảy ra không? – sdgfsdh

+2

@sdgfsdh - Tôi có thể hiển thị cho bạn mã byte. Điều đó có đủ không ?. Bạn sẽ có thể thấy rằng '+' KHÔNG phải là một phần của mã byte – TheLostMind

+0

Tôi đồng ý với câu trả lời ở trên và cũng muốn thêm rằng '+' không phải là cú pháp đường cho StringBuilder. Khi bạn sử dụng StringBuilder nó cho phép không tạo ra nhiều đối tượng String. Trong trường hợp bạn sử dụng '+', mỗi phần tử bổ sung là một đối tượng String mới. – jokernoel

8

Trình biên dịch Java có triển khai cho +. Các Javadocs nói:

ngôn ngữ Java cung cấp hỗ trợ đặc biệt cho các nhà điều hành nối chuỗi (+), và chuyển đổi của các đối tượng khác để chuỗi. Nối chuỗi được thực hiện thông qua lớp StringBuilder (hoặc StringBuffer) và phương thức nối thêm của nó. Chuỗi chuyển đổi được triển khai thông qua phương thức toString, được xác định bởi Đối tượng và được kế thừa bởi tất cả các lớp trong Java. Để biết thêm thông tin về việc ghép nối và chuyển đổi chuỗi , xem Gosling, Joy, và Steele, Đặc tả Ngôn ngữ Java.

Bạn có thể thử để kiểm tra này:

public static void main(String[] args) { 
    String s1 = "s1"; 
    String s2 = "s2"; 
    String s3 = s1 + s2; 
    String s4 = new StringBuilder(s1).append(s2).toString(); 
} 

Đoạn mã trên tạo ra bytecode tương tự cho + và khi sử dụng StringBuilder:

L0 
LINENUMBER 23 L0 
LDC "s1" 
ASTORE 1 

L1 
LINENUMBER 24 L1 
LDC "s2" 
ASTORE 2 

// s3 = s1 + s2 

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 

// s4 = new StringBuilder(s1).append(s2).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 
23

Bạn có thể kiểm tra với đặc điểm kỹ thuật. Trình biên dịch có thực hiện nó, không phải mã nguồn Java.

Java Language Specification- 15.18.1. String Concatenation Operator +

An thực hiện có thể chọn để thực hiện chuyển đổi và nối trong một bước để tránh tạo ra và sau đó loại bỏ một đối tượng String trung gian. Để tăng hiệu suất của chuỗi nối lặp lại, một 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 String trung gian được tạo ra bằng cách đánh giá một biểu thức.

Nó cho thấy bằng chứng cho thấy việc triển khai phụ thuộc vào trình biên dịch.

+1

Có. * Trình biên dịch java có thể sử dụng * .. Nhưng hầu hết các trình biên dịch đều làm. :) – TheLostMind

5

Trong khi hiện tại hầu hết các trình biên dịch Java sử dụng chuỗi StringBuilder, nó không được chỉ định rằng nó phải luôn luôn theo cách này. Đặc biệt có proposal để thay đổi điều này một cách quyết liệt trong Java-9 thay thế bằng một cuộc gọi invokedynamic và giới thiệu metafactory mới sẽ tạo ra một MethodHandle thích hợp trong thời gian chạy để thực hiện nối.

+0

Tôi tự hỏi tại sao Java không kết nối các phương thức tĩnh có hai, ba hoặc bốn trường hợp 'String', và cũng là một trường hợp có hoặc không một' chuỗi [] ', và trong bất kỳ trường hợp nào trả về một chuỗi mới chứa nối của tất cả các chuỗi trong câu hỏi? Các hàm như vậy có thể trong mọi trường hợp hiệu quả hơn mã thực sự sử dụng 'StringBuilder'. Cách duy nhất tôi có thể thấy 'StringBuilder' là thậm chí từ xa hợp lý sẽ là nếu hầu hết các phiên bản của lỗ hổng JIT tối ưu hóa một số mẫu sử dụng nhất định để gọi các hàm nội bộ của biểu mẫu được chỉ định. – supercat

+0

@supercat, bạn đang tìm kiếm ['String.join (" ", String ...)'] (http://docs.oracle.com/javase/8/docs/api/java/lang/String.html # join-java.lang.CharSequence-java.lang.CharSequence ...-)? Lưu ý rằng 'StringBuilder' có thể chấp nhận không chỉ các chuỗi, mà là các giá trị nguyên thủy như' int', 'double',' boolean' và vân vân. Và trong chuỗi nối chúng không được đóng hộp, cũng không phải các chuỗi riêng biệt được tạo ra: các giá trị của chúng được nối trực tiếp vào bộ đệm. Làm thế nào bạn sẽ tưởng tượng để giải quyết điều này bằng phương pháp tĩnh? Số lượng kết hợp có thể quá lớn. –

+0

Đã "tham gia" một ấn bản sau? Nguồn lib Java của tôi không có. Sử dụng StringBuilder được đảm bảo để tạo ra một lượng rác lớn hơn tổng chiều dài của chuỗi được tạo ra. Đối với kịch bản mà tất cả mọi thứ được ghép nối là các con số, nó có thể kết thúc lên một chút trước 'String.join (thing1.toString(), thing2.toString(), vv)', nhưng không nhiều. – supercat

1

Đối với ngôn ngữ, không, nó không thể mở rộng được. Đây là hành vi cụ thể, không có lớp nào khác mở rộng toán tử +.

Đối với nơi này được thực hiện, tìm kiếm string_add (not a real JVM op) trong các tập tin sau đây:


Là tại sao, Java được cho là đơn giản, hoặc ít nhất đơn giản hơn C++ và ab những thứ như thao tác chuỗi là bắt buộc. Tuy nhiên, quá tải của toán tử sẽ làm tăng tính phức tạp.

Các vấn đề liên quan