"Xin chào! Tôi sẽ tiếp tục bài học của Ellie về thuốc generic. Sẵn sàng nghe chưa?"

"Đúng."

"Vậy chúng ta bắt đầu đi."

"Điều đầu tiên bạn cần biết là các phương thức của một lớp cũng có thể có các tham số kiểu riêng của chúng."

"Tôi biết."

"Không, ý tôi cụ thể là tham số kiểu riêng của chúng: "

Ví dụ
class Calculator
{
  T add(T a, T b); // Add
  T sub(T a, T b); // Subtract
  T mul(T a, T b); // Multiply
  T div(T a, T b); // Divide
}

"Các tham số loại này liên quan cụ thể đến các phương thức. Lớp không có tham số. Bạn thậm chí có thể khai báo các phương thức này là tĩnh và gọi chúng mà không cần đối tượng."

"Tôi hiểu rồi. Điểm của các tham số kiểu trong các phương thức giống như đối với các lớp?"

"Vâng. Nhưng có một cái gì đó mới."

"Như bạn đã biết, bạn có thể sử dụng ký tự đại diện trong khai báo kiểu. Sau đó, hãy tưởng tượng tình huống sau:"

ví dụ 1
public void doSomething(List<? extends MyClass> list)
{
 for(MyClass object : list)
 {
  System.out.println(object.getState()); // Everything works well here.
 }
}

"Nhưng nếu chúng ta muốn thêm một mục mới vào bộ sưu tập thì sao:"

ví dụ 2
public void doSomething(List<? extends MyClass> list)
{
 list.add(new MyClass()); // Error!
}

"Vấn đề là trong trường hợp chung, phương thức doS Something có thể được chuyển một Danh sách có các phần tử không phải là đối tượng MyClass, mà là đối tượng của bất kỳ lớp con nào của MyClass. Nhưng bạn không thể thêm đối tượng MyClass vào danh sách như vậy!"

"À. Vậy, có thể làm gì với điều đó?"

"Không có gì. Trong tình huống này, bạn không thể làm gì cả. Nhưng điều này khiến những người sáng tạo Java phải suy nghĩ. Và họ đã nghĩ ra một từ khóa mới: super ."

"Cú pháp trông gần giống nhau:"

List<? super MyClass> list

Nhưng có một sự khác biệt quan trọng giữa mở rộng và siêu.

"«? extends T» có nghĩa là lớp phải là hậu duệ của T."

"«? super T» có nghĩa là lớp phải là tổ tiên của T."

"Thánh moly. Cái này dùng ở đâu?"

"«? super T» được sử dụng khi một phương thức liên quan đến việc thêm vào một tập hợp các đối tượng T. Trong trường hợp này, nó có thể là một tập hợp các đối tượng T hoặc bất kỳ tổ tiên nào của T."

"À. Đối tượng AT có thể được gán cho một biến tham chiếu có kiểu là bất kỳ tổ tiên nào của T"

"Thành thật mà nói, phương pháp này không được sử dụng thường xuyên. Hơn nữa, nó có một thiếu sót. Ví dụ:"

ví dụ
public void doSomething(List<? super MyClass> list)
{
 for(MyClass object : list) // Error!
 {
  System.out.println(object.getState());
 }
}
public void doSomething(List<? super MyClass> list)
{
 list.add(new MyClass()); // Everything works well here.
}

"Bây giờ ví dụ đầu tiên không hoạt động."

"Vì danh sách thậm chí có thể là Danh sách<Object> (Đối tượng là siêu lớp trên cùng của MyClass), về cơ bản, chúng tôi đang viết mã không hợp lệ sau:"

ví dụ 1
List<Object> list; 

for(MyClass object : list) // Error!
{ 
 System.out.println(object.getState()); 
}

"Tôi hiểu rồi. Cảm ơn vì bài học thú vị."

"Không có gì."