Truyền các biến trong Java


84

Tôi tự hỏi nếu có ai có thể cho tôi biết công việc đúc diễn ra như thế nào? Tôi hiểu khi nào tôi nên làm điều đó, nhưng không thực sự nó hoạt động như thế nào. Về kiểu dữ liệu nguyên thủy, tôi hiểu một phần nhưng khi nói đến truyền đối tượng, tôi không hiểu nó hoạt động như thế nào.

Làm cách nào để một đối tượng có kiểu Đối tượng đột nhiên được truyền đến, giả sử, MyType(chỉ là một ví dụ) và sau đó nhận tất cả các phương thức?


Đề xuất đọc: Người thừa kế
Francesco Menzani

Câu trả lời:


182

Truyền trong Java không phải là phép thuật, đó là bạn nói với trình biên dịch rằng một Đối tượng của loại A thực sự thuộc loại B cụ thể hơn, và do đó có được quyền truy cập vào tất cả các phương thức trên B mà bạn sẽ không có. Bạn không thực hiện bất kỳ loại phép thuật hoặc chuyển đổi nào khi thực hiện truyền, về cơ bản bạn đang nói với trình biên dịch "tin tôi đi, tôi biết tôi đang làm gì và tôi có thể đảm bảo với bạn rằng Đối tượng ở dòng này thực sự là một <Chèn ép gõ vào đây>. " Ví dụ:

Object o = "str";
String str = (String)o;

Ở trên là tốt, không phải phép thuật và tất cả đều tốt. Đối tượng đang được lưu trữ trong o thực sự là một chuỗi, và do đó chúng ta có thể ép kiểu thành một chuỗi mà không gặp bất kỳ vấn đề gì.

Có hai cách điều này có thể xảy ra sai. Thứ nhất, nếu bạn đang truyền giữa hai loại trong các phân cấp kế thừa hoàn toàn khác nhau thì trình biên dịch sẽ biết bạn đang ngớ ngẩn và ngăn bạn lại:

String o = "str";
Integer str = (Integer)o; //Compilation fails here

Thứ hai, nếu chúng ở trong cùng một hệ thống phân cấp nhưng vẫn là một cast không hợp lệ thì a ClassCastExceptionsẽ được ném vào thời gian chạy:

Number o = new Integer(5);
Double n = (Double)o; //ClassCastException thrown here

Về cơ bản, điều này có nghĩa là bạn đã vi phạm sự tin cậy của trình biên dịch. Bạn đã nói với nó, bạn có thể đảm bảo đối tượng thuộc một loại cụ thể, và nó không phải.

Tại sao bạn cần đúc? Vâng, để bắt đầu, bạn chỉ cần nó khi đi từ một loại tổng quát hơn sang một loại cụ thể hơn. Ví dụ: Integerkế thừa từ Number, vì vậy nếu bạn muốn lưu trữ Integerdưới dạng một Numberthì không sao (vì tất cả các Số nguyên đều là Số.) Tuy nhiên, nếu bạn muốn đi theo hướng khác, bạn cần ép kiểu - không phải tất cả các Số đều là Số nguyên (cũng như như Integer chúng tôi có Double, Float, Byte, Long, vv) và ngay cả khi chỉ có một phân lớp trong dự án của bạn hoặc JDK, ai đó có thể dễ dàng tạo ra khác và phân phối đó, vì vậy bạn đã có gì đảm bảo ngay cả khi bạn nghĩ rằng đó là một duy nhất, sự lựa chọn rõ ràng !

Về việc sử dụng để truyền, bạn vẫn thấy sự cần thiết của nó trong một số thư viện. Trước Java-5, nó được sử dụng nhiều trong các bộ sưu tập và nhiều lớp khác, vì tất cả các bộ sưu tập đều hoạt động trên việc thêm các đối tượng và sau đó truyền kết quả mà bạn nhận được từ bộ sưu tập. Tuy nhiên, với sự ra đời của generic, phần lớn việc sử dụng để truyền đã không còn - nó đã được thay thế bằng generic cung cấp một giải pháp thay thế an toàn hơn nhiều, không có tiềm năng cho ClassCastExceptions (thực tế là nếu bạn sử dụng generic rõ ràng và nó biên dịch không có cảnh báo, bạn có một đảm bảo rằng bạn sẽ không bao giờ nhận được ClassCastException.)


Cảm ơn bạn đã giải thích của bạn. Nếu tôi hiểu điều này đúng, có lẽ tôi không hiểu, khi bạn ép kiểu một đối tượng, bạn chỉ đang nói với trình biên dịch rằng tôi biết đối tượng trên địa chỉ bộ nhớ này biết cách phản hồi với các phương thức này, v.v., vì vậy đừng từ chối tôi? Đúng không?
user626912

1
@ user626912 Đại loại - đừng nghĩ về nó về địa chỉ bộ nhớ. Bạn không chỉ nói với trình biên dịch rằng đối tượng đã cho phù hợp với một giao diện và do đó có các triển khai của các phương thức đã cho (bạn có thể tạo một đối tượng hoàn toàn khác với các phương thức giống nhau và việc ép kiểu sẽ không nhất thiết hoạt động.) Bạn đang nói với trình biên dịch rằng đối tượng của một kiểu thực sự là một kiểu cụ thể hơn, và do đó bạn có thể sử dụng các phương pháp có sẵn trên đối tượng cụ thể hơn đó. Hãy đọc kỹ về đa hình nếu bạn chưa đọc, nó có thể giúp làm rõ ràng hơn một số điều.
Michael Berry

Tôi nghi ngờ tuyên bố của bạn "bạn chỉ cần nó khi đi từ một loại tổng quát hơn sang một loại cụ thể hơn". ((Đối tượng) gpsLastLoc.getLatitude ()). GetClass (). GetSimpleName () sẽ trả về tên "kép" trong thời gian chạy và đây là ví dụ sử dụng truyền từ kiểu cụ thể hơn sang kiểu chung hơn.
Trái cây

1
@ 林果 皞 Trong trường hợp này, bạn chỉ sử dụng ép kiểu để quảng bá nguyên mẫu - điều này không giống với việc chuyển sang một loại tổng quát hơn và một cách làm rất kỳ quặc. Cách bình thường hơn (tốt hơn) sẽ là Double.valueOf(gpsLastLoc.getLatitude()).getClass().getSimpleName(). Trong cả hai trường hợp, bạn không cần phải lấy động lớp của một nguyên thủy, vì nếu getLatitude()trả về một nguyên thủy kép, bạn luôn biết rằng nó sẽ thăng cấp cho một Doubleđối tượng.
Michael Berry

Tôi thích cách bạn nói rằng mã đã "vi phạm sự tin cậy của trình biên dịch". (Ps. Bạn mắc lỗi đánh máy, bạn đã viết "bạn" thay vì "bạn".)
Jason L.

7

Trên thực tế, không phải lúc nào cũng có kết quả. Nếu đối tượng không phải là một instanceoflớp mà bạn đang truyền nó cho bạn, bạn sẽ nhận được một ClassCastExceptiontrong thời gian chạy.


5

Giả sử bạn muốn ép kiểu từ a Stringđến a File(vâng, điều đó không có ý nghĩa gì), bạn không thể ép kiểu trực tiếp vì Filelớp không phải là con và không phải là cha của Stringlớp (và trình biên dịch phàn nàn).

Nhưng bạn có thể truyền của bạn Stringđến Object, bởi vì a StringObject( Objectlà cha mẹ). Sau đó, bạn có thể truyền đối tượng này thành a File, vì Tệp là một Object.

Vì vậy, tất cả các hoạt động của bạn là 'hợp pháp' theo quan điểm đánh máy tại thời điểm biên dịch, nhưng nó không có nghĩa là nó sẽ hoạt động trong thời gian chạy!

File f = (File)(Object) "Stupid cast";

Trình biên dịch sẽ cho phép điều này ngay cả khi nó không có ý nghĩa, nhưng nó sẽ sụp đổ trong thời gian chạy với ngoại lệ này:

Exception in thread "main" java.lang.ClassCastException:
    java.lang.String cannot be cast to java.io.File

3

Truyền tham chiếu sẽ chỉ hoạt động nếu đó là instanceofloại tham chiếu . Bạn không thể truyền các tham chiếu ngẫu nhiên. Ngoài ra, bạn cần đọc thêm Casting Objects.

ví dụ

String string = "String";

Object object = string; // Perfectly fine since String is an Object

String newString = (String)object; // This only works because the `reference` object is pointing to a valid String object.

3

Cách đúng là:

Integer i = Integer.class.cast(obj);

Phương pháp cast()này là một giải pháp thay thế an toàn hơn nhiều cho truyền thời gian biên dịch.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.