Nhà phân tích tình báo Jennifer Kohnke quét ảnh vệ tinh liên tục. Kể từ khi hệ thống hoạt động trở lại vào tháng trước, khối lượng công việc của cô gần như quá tải. Giám sát của cô liên tiếp đưa cô ảnh của khu liên hợp nào đó bên phía đông của Đức Quốc Xã. Họ muốn biết quân Đức đang làm gì ở đó. Tần suất tàu liên tục ám chỉ rằng khu liên hợp đó là khu công nghiệp. Cùng với số lượng lớn các doanh trại cho công nhân. Vấn đề là cô không thấy được nhân tố nào đáng để ý. Chỉ có một tòa nhà nhỏ với nhiều ống khói to. Nó quá nhỏ cho bất kỳ mục đích công nghiệp thật sự nào. Tuy nhiên luôn có một khối lượng khói khổng lồ tuôn ra từ những ống khói đó.

Avery và tôi học được rất nhiều từ những thử nghiệm với generics của Java thứ Sáu tuần trước. Và chúng tôi quyết định những khám phá như vậy sẽ được thực hiện mỗi ngày kể từ giờ. Chúng tôi lên kế hoạch gặp vào 11:00 mỗi sáng trong vài phút để bàn luận và thể hiện, một số thứ chúng tôi học được. Hôm nay là lượt của tôi.

Thứ Hai, 25 Tháng Hai 2002, 1100

Jasper và tôi đã làm việc cả sáng với story Đình chỉ Người dùng, có tiến bộ với nó. Đến 11:00, Avery bước đến và nói: “Sẵn sàng chưa?”

Tôi nhìn Jasper và nói: “Có phiền không nếu tao nghỉ trong vòng 15 phút?”

Hắn sáng mắt lên và nở một nụ cười toàn răng với tôi và nói: “Được chứ, Alphonse, chơi vui nhé!”

“Cảm ơn. Tí gặp lại sau.‘

Avery và tôi tìm được một phòng họp. Bọn tôi đóng của, và tôi chuẩn bị máy tính của tôi. Bọn tôi ngồi quây quanh nó. Và tôi bắt đầu.

“Được rồi, giờ giả sử tao có chức năng giống như getSuitsOverdueForInspection”:

“Ặc!” Avery nói. “Đoạn mã bị lặp! Mày phải sửa lại nó đi!” Rồi Avery lấy bàn phím và giảm hai vòng lặp xuống còn một:

Tôi ngăn hắn ngay lúc đó. “Ừ, Avery, Đúng. Nhưng để ý xem nó không biên dịch được!”

Avery nhìn kỹ màn hình và để ý thấy hai chỗ gọi đến getSuitsOverdueForInspectionFromList  đang báo lỗi về kiểu của đối số đầu tiên.

“Được rôi!” Hắn nói. “Cái này giống như cái ta nói hôm thứ Sáu. Một danh sách các hậu sinh, như là List<MensSuit> không thể truyền như là List của lớp gốc như là List<Suit>. Và ta biết phải làm gì với nó.”

Và Avery tiếp tục gõ, sửa lỗi biên dịch như sau:

“Chính xác!” Tôi nói. “Cái này làm cho phương thức getSuitsOverdueForInspectionFromList còn tổng quát hơn cả hai vòng lặp trước. Nếu theo như thế ? extends Suit còn tổng quát hơn là Suit. Tuy nhiên, tao có một vấn đề. Tao muốn gọi đến chức năng đầu tiên, getSuitsOverdueForInspection, từ nhiều nơi khác nhau. Để tao làm cho xem. Giả sử là tao có lớp SuitInspector như này.”

Avery nhìn nó vài giây và nói: “Được rồi, lớp này tìm tất cả bộ đồ quá hạn kiểm tra, và kiểm tra chúng.”

“Đúng!” Tôi nói. “Nhưng tao cũng có một lớp GeneralInspector trông như này.”

Một lần nữa, Avery nhìn màn hình vài giây và nói: “Được, chắc rồi. Mày đang chỉ thu thập lại mấy Bộ đồ quá hạn và các đối tượng Van và ghi nó ra. Này! Câu lệnh printf là gì kia?”

“Cái đó à?” Tôi nói với nụ cười nhếch mép. “Cái đó hơi cổ điển. Nó như kiểu câu lệnh printf trong C hồi xưa. Mày có thể nói về nó vào ngày mai. Hoặc có thể là tao. Bây giờ, thứ thú vị hơn là hai dòng getXXXOverdueForInspection không biên dịch được.”

“Dĩ nhiên là chúng không được.” Avery chế nhạo. “Mày đang truyền List<Object> vào đó, khi chúng lần lượt nhận vào List<Suit> và List<Valve>”.

Hắn đang rơi vào bẫy của tôi. Tốt. “Thế giờ ta sửa như nào?”

“Mày phải sửa đối số của chức năng getXXXOverdueForInspection để nhận vào List<? extends Object>.” Rồi Avery lấy bàn phím và bắt đầu gõ.

Trước khi hắn viết xong tôi nói: “Tao muốn chỉ ra là kiểu của đối số truyền vào getSuitsOverdueforInspection hơi lạ. Nó nên nhận vào List<? extends Suit>!” Nhưng Avery giả vờ không nghe thấy trong lúc gõ đoạn mã sau:

“Ôi không!” Avery hét lên. “Như này thì GeneralInventory biên dịch được, nhưng làm hỏng phần gọi đến getSuitsOverdueForInspectionFromList.”

“Đúng!” Tôi nói. “Vì mày không thể truyền List<? extends Object> vào một đối số nhận vào List<Suit>.”

“Được rồi.” Avery nói. “Vậy ta chỉ cần mở rộng đối số của getSuitsOverdueForInspectionFromList như này.”

“Aarrrgghh!” Avery mè nheo. Giờ câu lệnh ‘Add’ lại hỏng”

“Lại đúng nữa!” Tôi nói. “Đó là vì mày không thể thêm thứ gì vào danh sách các kiểu không được khai báo. ? extends Object hoàn toàn là kiểu chưa được khai báo!”

Avery nhìn tôi gần như hoảng loạn. Tôi có thể thấy nỗi sợ ép kiểu và sử dụng instanceofs trên mặt hắn. Nhưng rồi hắn có vẻ bỗng nhiên nhận ra là tôi đã gài bẫy hắn. Trông hắn thoải mái hơn; nở một nụ cười nhẹ và nói: “Được rồi, vậy tao chắc là mày có câu trả lời cho câu đố này.”

“Dĩ nhiên là tao có!”

“Chơi đi, Nhạc trưởng! Chơi đi!”

“Hóa ra là, Avery thân mến, mày có thể mở rộng kiểu của một danh sách bằng cách sử dụng ? extends X, nhưng chỉ khi mày muốn đọc từ danh sách đó. Tuy nhiên, nếu, mày có ý định viết thêm vào danh sách đó, như chức năng getSuitsOverdueForInspection của ta muốn làm, thì mày phải sử dụng mẫu khác. Mày sẽ phải dùng <? super X>.”

 Avery trút hơi vào một cú rít gió.

Tôi tiếp tục: “Cho phép tao cho mày xem nó hoạt động như nào.” Và tôi thay đổi như sau vào lớp SuitInventory.

“Như này giải quyết được vấn đề.” Tôi nói. “Giờ chức năng này nhận vào List<? super Suit>, tức là một danh sách các kiểu chưa được khai báo nhưng được biết là danh sách những thứ không phải là hậu sinh sau Suit.”

“Không phải là hậu sinh sau…” Avery nhắc lại. “Nghe thật đau đầu.”

“Nghĩ về nó như này, Avery. Khi mày đặt một đối tượng vào trong danh sách, tất cả những gì mày quan tâm là đối tượng là một kiểu phù hợp với kiểu của danh sách. Vậy mày muốn danh sách đó nhận vào kiểu của đối tượng đó, hoặc là một trong những lớp tiền sinh của đối tượng đó.”

“Ow! Ow! Ow! Đầu tao đau quá.”

“Mặt khác, khi mày đọc từ một danh sách, mày muốn kiểu mày đang đọc là kiểu nằm trong danh sách, hoặc là hậu sinh của kiểu đó.”

“Ow!”

“Giờ thì khi mày đọc từ một danh sách, mày dúng <? extends X>, nhưng nếu mày viết vào trong danh sách mày dùng <? super X>. Thấy không?”

“Ow!”

“Mày nghĩ nó hay không?”

“Ow!”

Vui thật! Avery thường là đứa giỏi hơn, và giờ hắn không hiểu được như tôi về cái này. Tôi chắc lần sau tôi cũng sẽ thế. Nhưng như thế cũng vui.


Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.