Hai ví dụ này là tương đương và trên thực tế sẽ biên dịch theo cùng mã byte.
Có hai cách để thêm một kiểu chung bị ràng buộc vào một phương thức như trong ví dụ đầu tiên của bạn sẽ làm bất cứ điều gì.
Truyền tham số loại cho loại khác
Hai chữ ký phương thức này cuối cùng giống nhau trong mã byte, nhưng trình biên dịch thực thi an toàn kiểu:
public static <T extends Animal> void addAnimals(Collection<T> animals)
public static void addAnimals(Collection<Animal> animals)
Trong trường hợp đầu tiên, chỉ cho phép một Collection
(hoặc kiểu con) Animal
. Trong trường hợp thứ hai, một Collection
(hoặc kiểu con) với một loại chung Animal
hoặc một kiểu con được cho phép.
Ví dụ, điều sau đây được cho phép trong phương thức đầu tiên nhưng không phải là phương thức thứ hai:
List<Cat> cats = new ArrayList<Cat>();
cats.add(new Cat());
addAnimals(cats);
Lý do là cái thứ hai chỉ cho phép các bộ sưu tập động vật, trong khi cái thứ nhất cho phép các bộ sưu tập của bất kỳ đối tượng nào có thể gán cho động vật (tức là các kiểu con). Lưu ý rằng nếu danh sách này là danh sách các động vật tình cờ có chứa một con mèo, thì một trong hai phương pháp sẽ chấp nhận nó: vấn đề là đặc điểm chung của bộ sưu tập, chứ không phải những gì nó thực sự chứa.
Trả lại đồ vật
Lần khác nó quan trọng là với các đối tượng trở lại. Chúng ta hãy giả sử phương pháp sau tồn tại:
public static <T extends Animal> T feed(T animal) {
animal.eat();
return animal;
}
Bạn sẽ có thể làm như sau với nó:
Cat c1 = new Cat();
Cat c2 = feed(c1);
Trong khi đây là một ví dụ giả định, có những trường hợp nó có ý nghĩa. Nếu không có khái quát, phương thức sẽ phải trả về Animal
và bạn sẽ cần thêm kiểu truyền để làm cho nó hoạt động (đó là những gì trình biên dịch thêm vào mã byte dù sao đằng sau hậu trường).
addAnimals(List<Animal>)
và thêm Danh sách Mèo!