2010-01-23 32 views
5

Chúng ta biết rằng khi chúng ta sử dụng các đối tượng trong câu lệnh sysout (System.out.Println) trong nội bộ thì phương thức toString được gọi. và với nguyên thủy nó in trực tiếp. nhưng khi chúng tôi sử dụng bất kỳ loại đối tượng lớp Wrapper nào được sử dụng giả sử Integer như sauunboxing hoặc toString() được sử dụng trong sysout trong java

 Integer i = new Integer(10) 
     System.out.Println(i); 

là toString() có chịu trách nhiệm in hoặc Unboxing không?

+0

Tôi nghĩ rằng nó sẽ chỉ unbox trong trường hợp int là lựa chọn duy nhất. Vì có một println (Object), có lẽ nó sẽ được gọi. –

+0

@gurukulki, được cập nhật bằng câu trả lời hy vọng nó sẽ giúp. –

Trả lời

10

Kiểm tra nhanh và chạy gỡ lỗi cho thấy rằng print(Object) được gọi, không phải print(int).

Một cách tốt để kiểm tra này là:

Integer val = null; 
System.out.print(val); 

Nếu un-boxing đã được sử dụng, điều này sẽ ném một NullPointerException. Tuy nhiên, điều này không xảy ra, nó in chuỗi null, là đầu ra của String.valueOf(Object) khi một giá trị rỗng được chuyển vào.

Một khía cạnh khác cần ghi nhớ là PrintStream tồn tại trước Java 5. Khi autoboxing được giới thiệu trong Java 5, nó phải được đảm bảo rằng bất kỳ mã hiện có sử dụng PrintStream sẽ không đột nhiên có hành vi của nó thay đổi.Vì vậy, bất kỳ mã hiện tại nào gọi là print(Object) không được đột ngột thay đổi hành vi của mình để gọi số print(int), chỉ đơn giản là vì một tính năng ngôn ngữ mới. Khả năng tương thích ngược phải luôn được duy trì.

+1

(+1) sâu sắc :) – Bozho

+1

Điều này thật thú vị, nhưng nó có kết luận không? Có thể có một 'if' xử lý null. –

+0

Một 'if' ở đâu? Không có phép thuật nào xảy ra ở đây, và không đánh boxing sẽ không * luôn * ném NPE. – skaffman

4

Tất cả điều này trước đây autoboxing, được giới thiệu trong 1.5. Mã trả lời các câu hỏi này - hoặc tài liệu API - không thay đổi gì cả cho 1,5+.

Về cơ bản, ở cuối dòng là phương thức toString đối với các tệp không nguyên thủy như các phiên bản Integer.

Vì vậy, trước tiên, với nguyên thủy, có một cách điều trị khác nhau cho mỗi loại. Đối với int, ví dụ:

In một số nguyên. Chuỗi được tạo ra bởi String.valueOf (int) được dịch thành các byte theo mã hóa ký tự mặc định của nền tảng và các byte này được ghi chính xác theo phương thức write (int) .

Nhưng đối với đối tượng như Integer, println gọi print đó:

In một đối tượng. Chuỗi được tạo ra theo phương thức String.valueOf (Object) được dịch thành byte theo ký tự mặc định của nền tảng mã hóa và các byte này được viết theo cách thức chính xác của phương pháp write (int).

Vì vậy, những gì hiện valueOf sử dụng? Đây là câu trả lời cho câu hỏi của bạn: cho phương thức Integer của nó là toString được gọi. Đây là từ các tài liệu trên String.valueOf

nếu đối số là rỗng, sau đó một chuỗi bằng "null"; nếu không, giá trị của obj.toString() được trả về.

+1

Bạn muốn giải thích điều gì ở đây. câu hỏi của tôi là toString() hoặc Unboxing đơn giản? cái nào chịu trách nhiệm? – GuruKulki

+0

sửa câu trả lời của tôi ngay bây giờ để xóa nội dung đó ... –

5

(...) nhưng khi chúng tôi sử dụng bất kỳ loại lớp Wrapper của các đối tượng được sử dụng nói rằng Integer như sau

Integer i = new Integer(10) 
    System.out.println(i); 

là nó toString() có trách nhiệm in nó hay Unboxing ?

Bạn đang đi qua một Object để println do đó, nó rõ ràng là println(Object obj) đó được gọi là mà viết đầu ra của String.valueOf(obj) trong đó kêu gọi obj.toString() nếu obj không phải là null.

PS: Không vi phạm nhưng, tại sao bạn không chỉ xem xét các nguồn?

Cập nhật: Tôi có thể đã bỏ lỡ điểm của câu hỏi (gây nhầm lẫn trong biểu mẫu hiện tại nếu tôi có thể). Trên thực tế, câu hỏi có thể là:

(...) nhưng khi chúng tôi sử dụng bất kỳ loại lớp Wrapper của các đối tượng được sử dụng nói giả sử Integer như sau

Integer i = new Integer(10) 
    System.out.println(i); 

phương pháp nào sẽ được gọi là: println(Object) hoặc println(int)?

Nếu đây là câu hỏi, thì câu trả lời nằm trong khóa học là The Java Language Specification. Để đơn giản hóa, phương thức được gọi vào thời gian chạy sẽ là phương thức được xác định tại thời gian biên dịch. Bây giờ, trình biên dịch xác định phương thức sẽ được gọi ra như thế nào? Vâng, điều này được giải thích trong phần 15.12 Method Invocation Expressions. Tôi sẽ không bao gồm tất cả các chi tiết, spec này tốt hơn tôi nhưng, về cơ bản, bước đầu tiên là tìm lớp hoặc giao diện để tìm kiếm, bước thứ hai là tìm tất cả các phương pháp áp dụng và sau đó chọn cụ thể nhất phương pháp, bước thứ ba là để xác minh nếu phương pháp được chọn là thích hợp. Tôi sẽ tập trung vào bước thứ 2 (đó là bước thú vị ở đây). Như đã trình bày trong phần 15.12.2 Compile-Time Step 2: Determine Method Signature:

Một phương pháp được áp dụng nếu nó là một trong hai áp dụng bởi subtyping (§15.12.2.2), áp dụng bằng phương pháp gọi chuyển đổi (§15.12.2.3), hoặc nó là một phương pháp được áp dụng biến arity (§15.12.2.4).

Quy trình xác định khả năng áp dụng bắt đầu bằng cách xác định các phương pháp có khả năng áp dụng (§15.12.2.1). Phần còn lại của quy trình được chia thành ba giai đoạn.


Thảo luận

Mục đích của việc phân chia thành các giai đoạn là để đảm bảo khả năng tương thích với phiên bản cũ của các lập trình Java ngôn ngữ.


Giai đoạn đầu (§15.12.2.2) Thực hiện quá tải độ phân giải mà không phép đấm bốc hay unboxing chuyển đổi, hoặc sử dụng các biến arity phương pháp gọi. Nếu không có phương pháp áp dụng được tìm thấy trong giai đoạn này thì quá trình xử lý tiếp tục đến giai đoạn thứ hai là .


Thảo luận

Điều này đảm bảo rằng bất kỳ cuộc gọi mà là hợp lệ trong các phiên bản cũ của ngôn ngữ không được coi là mơ hồ như là kết quả của sự ra đời của phương pháp arity biến, tiềm ẩn đấm bốc và/hoặc unboxing.


Giai đoạn thứ hai (§15.12.2.3) Thực hiện quá tải độ phân giải khi phép boxing và unboxing, nhưng vẫn ngăn cản việc sử dụng các biến arity phương pháp gọi. Nếu không có phương pháp áp dụng được tìm thấy trong giai đoạn này thì việc xử lý tiếp tục đến giai đoạn thứ ba là .


Thảo luận

này đảm bảo rằng một biến phương pháp arity không bao giờ được gọi nếu một áp dụng phương pháp arity cố định tồn tại.


Giai đoạn thứ ba (§15.12.2.4) cho phép quá tải phải được kết hợp với các phương pháp arity biến, boxing và unboxing .

Quyết định liệu một phương pháp là áp dụng ý chí, trong trường hợp của phương pháp chung (§8.4.4), yêu cầu đối số loại thực tế được xác định . Đối số loại thực tế có thể được chuyển một cách rõ ràng hoặc ngầm. Nếu chúng được chuyển hoàn toàn, chúng phải được phỏng đoán (§15.12.2.7) từ các loại biểu thức đối số .

Nếu áp dụng một số phương pháp đã được xác định trong một trong những ba giai đoạn thử nghiệm khả năng ứng dụng, thì một cụ thể nhất được chọn, theo quy định tại phần §15.12.2.5. Xem các phần phụ sau đây cho chi tiết .

Trong trường hợp đặc biệt này, println(Obj) được áp dụng bởi subtyping (và println(int) sẽ được áp dụng bằng cách chuyển đổi gọi là boxing/unboxing là một chuyển đổi (§5.3)). Vì vậy trình biên dịch sẽ nhập phase 1. Và nếu chúng ta nhìn vào câu cuối cùng:

Nếu không tìm thấy phương pháp áp dụng bằng cách phân loại, tìm kiếm các phương pháp áp dụng tiếp tục với giai đoạn 2 (§15.12.2.3). Nếu không, phương pháp cụ thể nhất (§15.12.2.5) được chọn trong số các phương pháp được áp dụng theo loại phụ.

Ở đây, không có bất kỳ phương pháp khác được áp dụng bởi subtyping vì vậy đây là kết thúc, println(Object) sẽ được gọi (và do đó toString() sẽ được gọi, để trả lời câu hỏi ban đầu).

+0

tôi có nghi ngờ rằng nó có thể unbox và in int nguyên thủy – GuruKulki

+0

@Pascal: Đây thực sự không phải là vấn đề về API, mặc dù, đó là câu hỏi liệu ngôn ngữ đó có thích unboxing hơn không truyền đối tượng. – skaffman

+0

@skaffman, đây là một vấn đề về API và phải làm gì với cách API chuỗi được chỉ định. Hành vi của String, là một đối tượng và không phải là một nguyên thủy, được xác định bởi API. –

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