2013-08-04 41 views
6

Tại sao StringBuilder không in những gì nó nên in trong một mã nhỏTại sao StringBuilder không in?

public final class Test1 { 

    public void test() { 
     System.out.println(setFin().toString()); 
    } 

    protected StringBuilder setFin() { 
     StringBuilder builder = new StringBuilder(); 
     try { 
      builder.append("John"); 
      return builder.append("Ibrahim"); 
     } finally { 
      System.out.println("In finaly"); // builder.append("-DarElBeida"); 
      builder = null; 
     } 
    }  

    public static void main(String args[]){ 
     new Test1().test(); 
    } 
} 

Trong báo cáo kết quả cuối cùng thực hiện trong setFin() (trong khối finally) Tôi đã gán null để builder, nhưng in mã của tôi "In finally" và sau đó "JohnIbrahim" . Ai có thể giải thích cho tôi chuyện gì đang xảy ra ở đây không?

+1

Đây là mã độc hại. Có lẽ, bạn chỉ muốn đọc http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html – nes1983

Trả lời

5

Khi có tuyên bố return bên trong khối try, nó sẽ thực thi khối finally trước khi thực sự trở lại.

Và phương pháp này không trả lại null vì tuyên bố return giữ một tham chiếu đến StringBuilder đối tượng thực tế, chứ không phải để biến builder.

Đặt builder == null không tự xóa StringBuilder chính nó, nó chỉ giảm tham chiếu đến số builder.

Hành vi này có thể gây nhầm lẫn. Để làm rõ mọi thứ, có thể hữu ích khi trả lại từ bên ngoài khối try/catch/finally:

StringBuilder builder = new StringBuilder(); 

try { 
    builder.append("John"); 
    builder.append("Ibrahim"); 
} finally { 
    System.out.println("In finaly"); // builder.append("-DarElBeida"); 
    builder = null; 
} 

return builder; 
+1

Tôi nghĩ rằng OP bị nhầm lẫn là tại sao nó không in 'null'. –

+0

không, anh ta hy vọng nó sẽ in tên mà không có "cuối cùng". – duffymo

+0

Tôi nghĩ rằng sự nhầm lẫn là về lý do tại sao điều này không in 'null' (mà câu lệnh của bạn không thực sự giải thích - nó' builder = null' được "đánh giá trước khi trả về" sau đó nó "sẽ trả về null") – Mat

3

Bạn đang trả lại builder. Sau đó bạn đặt builder thành vô giá trị. Nhưng nó đã được trả lại. Nó không quan trọng những gì bạn làm với biến sau đó. Giá trị trả lại đã "bị khóa". Những gì bạn có thể làm là lộn xộn với đối tượng đang được trả về. Ví dụ: builder.setLength(0) sẽ xóa tất cả văn bản.

Về lý thuyết, bạn cũng có thể return null từ khối cuối cùng, nhưng điều đó (thay đổi giá trị trả lại) được khuyến khích cao.

3

Return giá trị được đánh giá và lưu trữ trên chồng, trước khi finally khối chạy. Lưu ý rằng giá trị trên ngăn xếp thực sự là giá trị của tham chiếu StringBuilder. Vì vậy, ngay cả khi bạn đặt builder thành null, điều đó không thay đổi giá trị return được đánh giá đã có trên ngăn xếp. Tuy nhiên, nếu giá trị trả lại là tham chiếu đến đối tượng có thể thay đổi, bạn có thể thay đổi đối tượng và thay đổi sẽ hiển thị trong giá trị return.

Đối với ví dụ, nếu bạn thêm các tuyên bố dưới đây trong khối finally thay vì nullifying tài liệu tham khảo:

builder.append("Hrithik Roshan"); 

sau đó bạn sẽ thấy rằng nội dung trong giá trị trả về.

Tuy nhiên, nếu bạn return lại builder, từ khối finally, nó sẽ bị hủy trước tuyên bố được đánh giá trước đó là return. Nhưng hãy nhớ rằng đó không phải là một ý tưởng hay.

2

finally luôn được thực hiện, trừ khi JVM bị lỗi hoặc thoát trước khi kết thúc khối try.

Nếu khối try hoàn thành do một tuyên bố return, sự biểu hiện của return được đánh giá vào một giá trị duy nhất trước các finally thực thi khối. Giá trị đó được lưu và trả về khi khối finally hoàn tất.

Do đó, việc gán builder = null không có hiệu lực vì việc đánh giá builder.append("Ibrahim") đã kết thúc vào thời điểm thực hiện finally.

1

builder giữ tham chiếu đến StringBuilder mà bạn đã tạo. Khi bạn thực hiện builder = null, bạn đang đặt builder để không còn giữ tham chiếu đó nữa. Bản thân StringBuilder vẫn tồn tại (ít nhất là cho đến khi việc thu gom rác xảy ra).

Điều gì đang xảy ra là tuyên bố return của bạn đang trả lại tham chiếu đến StringBuilder. Đó là không phải trả về biến số builder; nó trở về một tham chiếu đến điều mà builder đề cập đến. Vì vậy, ngay cả khi bạn đang xóa biến, câu lệnh return đã có một tham chiếu đến đối tượng đã tạo.

Nếu bạn in builder trong khối finally của mình, nó sẽ không có ở đó.

0

Đầu tiên được thực hiện return tuyên bố thực thi builder.append("Ibrahim") trả về tham chiếu StringBuilder. Lời giới thiệu được lưu vào ngăn xếp. Sau đó, cắt bỏ khối finally. Bạn đã vô hiệu biến cục bộ, nhưng tham chiếu đến đối tượng StringBuilder được truyền cho người gọi sau khi phương thức thực sự trở lại. Đó là lý do tại sao in tất cả các giá trị. Lỗi là bạn chỉ định giá trị cho số builder trong khối finally không bao giờ được sử dụng. Ngăn xếp giữ giá trị của toán hạng câu lệnh return trước khi nó thực sự được trả về, tức là sau khối finally. Nếu bạn không muốn trả lại tham chiếu từ phương thức, bạn nên return null trong khối finally, sẽ ghi đè giá trị trong ngăn xếp.

} finally { 
    System.out.println("In finaly"); // builder.append("-DarElBeida"); 
    return null; 

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