Tôi đã xem xét một trong các đường mòn của Oracle trên các Generics Java, mang tên "Effects of Type Erasure and Bridge Methods" và tôi không thể thuyết phục bản thân mình về một lời giải thích được đưa ra. Tò mò, tôi đã thử nghiệm mã cục bộ và tôi thậm chí không thể tái tạo hành vi mà đường mòn giải thích. Đây là mã có liên quan:Vấn đề tiềm ẩn với một trong những đường mòn của Oracle trên các hình khối Java
public class Node<T> {
public T data;
public Node(T data) { this.data = data; }
public void setData(T data) {
System.out.println("Node.setData");
this.data = data;
}
}
public class MyNode extends Node<Integer> {
public MyNode(Integer data) { super(data); }
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}
Đường mòn Oracle tuyên bố những hành vi sau đây cho đoạn mã này:
MyNode mn = new MyNode(5);
Node n = mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = mn.data; // Causes a ClassCastException to be thrown.
Đoạn mã này sẽ trông giống như sau sau khi loại tẩy xoá:
MyNode mn = new MyNode(5);
Node n = (MyNode)mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = (String)mn.data; // Causes a ClassCastException to be thrown.
Tôi không hiểu các phôi được sử dụng ở đây hoặc hành vi. Khi tôi cố gắng chạy mã này tại địa phương sử dụng IntelliJ với Java 7, tôi có hành vi này:
MyNode mn = new MyNode(5);
Node n = mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello"); // Causes a ClassCastException to be thrown.
Integer x = mn.data;
Nói cách khác, các JVM sẽ không cho phép một String
được sử dụng với setData()
. Điều này thực sự trực quan với tôi, và nó đồng ý với sự hiểu biết của tôi về Generics. Vì MyNode
mn
được xây dựng với Integer
, trình biên dịch phải truyền mọi cuộc gọi đến setData()
với Integer
để đảm bảo an toàn loại (tức là Integer
đang được chuyển vào).
Ai đó có thể làm sáng tỏ một số lỗi rõ ràng này trong đường mòn Oracle không?
Tôi nghĩ rằng trang này là lỏng lẻo với ngôn ngữ của nó là cho nó tín dụng quá nhiều. Vì vậy, những gì bạn đang nói là các cuộc gọi 'n.setData (" Hello ")' thực sự nhấn phương pháp cầu được tạo ra bởi trình biên dịch, mà sẽ đúc tất cả các đối tượng được truyền cho nó để 'Integer' trước khi gọi phương pháp siêu. Vâng điều này giải thích tất cả mọi thứ tôi cho rằng, cảm ơn cho những hiểu biết. –
Tôi có xu hướng ghê tởm về tài liệu xấu, nhưng tôi đã quen với việc xuất bản quân đoàn xuất bản tài liệu khủng khiếp, đặc biệt là cho các API. Trớ trêu thay, Java đã có một số tài liệu hay nhất từ trước đến nay, khi nó còn trẻ. Ngày nay ... Tôi cố gắng giữ sự khinh miệt của mình cho bản thân mình :). – Adam