Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 14 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
14
Dung lượng
180,5 KB
Nội dung
Giáo trình Java tóm tắt Java Collections Framework Java Collections Framework Java Collections Framework 1 1. Giới thiệu chung 1 2. List 2 3. Các interface Iterable, Iterator và Enumerator 9 4. Set 11 5. Map 14 1. Giới thiệu chung Array là cách nhanh và dễ nhất để lưu trữ các loại dữ liệu dạng mảng. Tuy nhiên, array có một nhược điểm là kích thước cố định. Dĩ nhiên là ta có thể "thay đổi kích thước" của array bằng cách tạo ra một array mới rồi sao chép dữ liệu qua đó, nhưng việc này sẽ tốn thời gian và công sức. Để khắc phục nhược điểm trên của array, Java đã xây dựng một dạng dữ liệu gọi chung là collection, được đặt trong package java.util. Các đối tượng collection có khả năng lưu trữ dữ liệu dạng mảng như array, ngoài ra nó còn cho phép thêm và xóa các phần tử một cách tùy ý. Dĩ nhiên là khi đó collection sẽ ko thể chạy nhanh và dễ dùng như array. Trong Java, collection được cài đặt trong Collections Framework. Collections Framework bao gồm hai phần chính là collection và map. Việc mô tả các chức năng chung của các collection được quy định trong interface Collection, Collection lại được chia thành hai loại chính là List và Set, ngoài ra còn vài interface phụ khác. Còn các map được đại diện bởi interface Map. Dưới đây là sơ đồ quan hệ của Java Collections Framework (chỉ có một số interface và class chính). Châu Hải Duy 1/14 Giáo trình Java tóm tắt Java Collections Framework Hình 1: Collections Framework 2. List List là một bộ phận của Java Collections, list được đại diện bởi interface List. Interface List được kế thừa từ interface Collection. Dưới List là lớp AbstractList, dưới nữa là các lớp Vector, AbstractSequentalList, ArrayList, LinkedList, Stack, Ở đây xin giới thiệu về Vector, các class khác cũng có cách dùng và tính năng tương tự. Châu Hải Duy 2/14 HashSet AbstractCollection AbstractSet Collection Set SortedSet WeakHashMap TreeSet ArrayList AbstractList List Vector AbstractSequentalList Stack LinkedList AbstractMap HashMap Map SortedMap TreeMap HashTableDictionary Properties Giáo trình Java tóm tắt Java Collections Framework 2.1. Lớp Vector 2.1.1. Giới thiệu Vector là một collection dạng List, được tạo ra bằng cách extend class AbstractList, AbstractList lại được extend từ AbstractCollection. Ngoài ra Vector còn implement từ các interface Serializable, Cloneable, Iterable, List, RandomAccess và dĩ nhiên không thể thiếu interface Collection. Class AbstractCollection là một lớp ảo, trong đó khai báo các thuộc tính và phương thức cơ bản cho các đối tượng dạng collection. Class AbstractList là một lớp ảo, trong đó khai báo các thuộc tính và phương thức cơ bản cho các đối tượng dạng list (bao gồm mảng, danh sách liên kết,…) để phân biệt với các đối tượng dạng set (tập hợp). Interface Serializable cho biết đối tượng Vector có khả năng biến đổi thành một dãy byte dữ liệu (VD: để ghi vào file) và phục hồi từ dãy byte dữ liệu (VD: để đọc từ file). Chi tiết về object serialization sẽ được trình bày trong một phần riêng. Interface Cloneable cho biết đối tượng Vector có thể tạo ra bản sao của nó thông qua phương thức Object clone(). Interface Iterable cho biết đối tượng Vector có thể tạo ra đối tượng Iterator. Iterator cho phép lấy các phần tử trong collection từ đầu đến hết mà không cần quan tâm tới chỉ số và thứ tự của chúng. Interface List cho biết Vector lưu các phần tử một cách có thứ tự (sequence) và cho phép tìm kiếm các phần tử. List cũng nói rằng Vector cho phép lưu những phần tử trùng nhau. List dùng để phân biệt với Set (tập hợp). Interface RandomAccess cho biết ta có thể truy cập đến một phần tử bất kỳ trong Vector thông qua chỉ số (index), và việc truy cập này không tốn thời gian xử lý (chính xác hơn là thời gian xử lý không đáng kể và như nhau với mọi vị trí). Điều này cho thấy Vector không phải là danh sách liên kết mà là sự phát triển của array. Trong phần sau, các constructor của Vector sẽ cho ta thấy rõ điều này. Interface Collection cho biết Vector có khả năng chứa đựng dữ liệu dạng mảng và cho phép thêm/xóa các phần tử. Châu Hải Duy 3/14 Giáo trình Java tóm tắt Java Collections Framework Hình 2 Vị trí của Vector trong Java Collections Framework Ngoài Vector, ta còn có thể dùng ArrayList. Nhìn chung ArrayList tương tự như Vector, ngoại trừ việc nó không có tính năng đồng bộ (synchronize - bảo đảm tính nhất quán dữ liệu khi chạy trong ứng dụng đa tiểu trình). 2.1.2. Các constructor Trước khi đi vào các constructor, ta cần điểm qua các thuộc tính quan trọng của Vector, đó là initialCapacity, capacityIncrement và size. initialCapacity: là sức chứa khởi đầu của Vector. Ví dụ nếu initialCapacity = 10 thì Vector được tạo ra sẽ có khả năng chứa 10 phần tử. Nếu trong quá trình hoạt động, số phần tử thêm vào vượt quá sức chứa (capacity) thì Vector sẽ tự gia tăng sức chứa. capacityIncrement: là độ gia tăng sức chứa của Vector khi số phần tử thêm vào vượt quá sức chứa hiện tại. Quy ước: Nếu độ tăng nhỏ hơn 1 có nghĩa là sức chứa sẽ tăng gấp đôi mỗi khi cần thiết. size: là số phần tử hiện có trong Vector. Do đó, size không thể vượt quá sức chứa (capacity). Châu Hải Duy 4/14 Iterable Collection List AbstractCollection AbstractList Vector Stack Serializable Cloneable RandomAccess Giáo trình Java tóm tắt Java Collections Framework Bảng dưới đây là các constructor của Vector. Constructor Ý nghĩa Vector() Đây là constructor default. Constructor này sẽ tạo ra một đối tượng Vector với sức chứa mặc định là 10, độ tăng sức chứa là 0 (nghĩa là tăng gấp đôi khi cần tăng). Vector(int initialCapacity) Constructor này tạo ra một Vector với sức chứa khởi đầu là initialCapacity, độ tăng sức chứa là 0 (nghĩa là tăng gấp đôi khi cần tăng). Vector(int initialCapacity, int capacityIncrement) Constructor này tạo ra một Vector với sức chứa khởi đầu là initialCapacity, độ tăng sức chứa là capacityIncrement (nếu capacityIncrement nhỏ hơn 1 thì Vector sẽ là tăng gấp đôi sức chứa khi cần tăng). Vector(Collection c) Constructor này tạo ra một Vector với các phần tử có sẵn trong Collection c. Bảng 1 Các constructor của lớp Vector 2.1.3. Các phương thức chính Bảng dưới đây là các phương thức thường dùng của Vector. Chi tiết xin xem thêm trong Java API Documents. Phương thức Ý nghĩa Object get(int index) Trả về object ở vị trí index (bắt đầu từ 0) . void set(int index, Object e) Thay thế về object ở vị trí index bởi e. void add(Object e) Chèn phần tử e vào cuối Vector. void add(int index, Object e) Chèn phần tử e vào vị trí index. Object lastElement() Trả về phần từ cuối cùng của Vector. Object remove(int index) Xóa và trả về phần tử tại vị trí index. int size() Trả về số phần tử đang có trong Vector. Lưu ý: cần phân biệt số phần tử (size) với sức chứa (capacity). boolean remove(Object e) Xóa handle quản lý đối tượng e trong Vector. Nếu trong Vector có nhiều handle cùng quản lý e thì chỉ có handle đầu tiên bị xóa. Nếu trong Vector không có handle nào quản lý e thì sẽ trả Châu Hải Duy 5/14 Giáo trình Java tóm tắt Java Collections Framework về false, khi đó Vector sẽ không bị thay đổi gì. Enumeration elements() Trả về một đối tượng Enumeration chứa các phần tử trong Vector. Iterator iterator() Trả về một đối tượng Iterator chứa các phần tử trong Vector. Bảng 2 Các phương thức thường dùng của lớp Vector 2.2. Vector hỗn tạp Như đã nói trên, do Object là lớp "cha" của mọi lớp khác trong Java, nên nếu ta tạo ra một mảng các Object (thực chất là mảng các handle kiểu Object) thì mảng đó sẽ có khả năng chứa mọi loại đối tượng (thông qua up-cast). Trong collection, các phần tử của chúng cũng đều là các handle kiểu Object. Nên collection (cụ thể là Vector) cũng có khả năng chứa mọi loại đối tượng. Khi một mảng (hoặc collection) chứa nhiều đối tượng không cùng loại (nghĩa là không cùng lớp) ta nói đó là mảng (hoặc collection) hỗn tạp. Khi đó phải thật cẩn thận khi sử dụng để tránh lỗi down-cast. Cách xửlý và kiểm tra với mảng hỗn tạp và collection hỗn tạp là tương tự nhau: upcast khi thêm phần tử mới và down-cast khi dùng phần tử, kèm theo đó là kiểm tra tính hợp lệ của down-cast. 2.2.1. Ví dụ về Vector hỗn tạp Trong ví dụ này, ta tạo ra Vector V chứa phân số (lớp PhanSo) và học sinh (lớp HocSinh). PhanSo và HocSinh là hai lớp độc lập (không extend nhau). Vector V=new Vector(); HocSinh hs=new HocSinh(); hs.Nhap(); V.add(hs); // Up-cast HocSinh-Object V.add(new PhanSo()); // Up-cast PhanSo-Object ((PhanSo)V.lastElement()).Nhap(); // Down-cast Object-PhanSo V.add(new HocSinh()); // Up-cast HocSinh-Object ((HocSinh)V.lastElement()).Nhap(); // Down-cast Object-HocSinh Như vậy, Vector V sẽ chứa 3 handle kiểu Object, trong đó có 2 handle quản lý HocSinh và 1 handle quản lý PhanSo. 2.2.2. Lỗi down-cast Đoạn code này được thực thi ngay sau đoạn code tạo Vector ở trên. Nó sẽ gây ra lỗi ép kiểu khi down-cast. /* !!! Đoạn code gây lỗi down-cast !!! */ for(int i=0;i<V.size();i++) ((HocSinh)V.get(i)).Xuat(); Châu Hải Duy 6/14 Giáo trình Java tóm tắt Java Collections Framework Ban đầu, ta thêm vào V hai đối tượng HocSinh và một PhanSo. Đối tượng PhanSo là do handle thứ 1 (tính từ 0) quản lý. Trong đoạn code lỗi, ta ép kiểu tất cả các handle của V từ Object về HocSinh và gọi phương thức xuất. Do đó, handle thứ 1 là handle quản lý PhanSo cũng sẽ bị ép về HocSinh, đây là nguyên nhân gây lỗi down-cast. Lưu ý: đôi khi trong Vector hỗn tạp, ta có thể gọi thực thi các phương thức của từng phần tử một cách "vô tư" mà không hề bị lỗi down-cast. Xem ví dụ sau: /* !!! Dùng Vector hỗn tạp mà ko bị lỗi down-cast !!! */ for(int i=0;i<V.size();i++) System.out.println(V.get(i).toString()); Lý do: phương thức toString() đã có từ lớp Object nên việc gọi tới nó mà không cần ép kiểu là hoàn toàn hợp lệ. 2.2.3. Từ khóa instanceof Để tránh lỗi down-cast khi dùng mảng hỗn tạp, ta cần kiểm tra kiểu của đối tượng do handle quản lý (bằng từ khóa instanceof) rồi mới down-cast. for(int i=0;i<V.size();i++) { if (V.get(i) instanceof HocSinh) // Kiểm tra kiểu của V[i] ((HocSinh)V.get(i)).Xuat(); // Down-cast Object-HocSinh else if (V.get(i) instanceof PhanSo) // Kiểm tra kiểu của V[i] ((PhanSo)V.get(i)).Xuat(); // Down-cast Object-PhanSo System.out.println(); } 2.3. Vector định kiểu 2.3.1. Bao bọc Như đã nêu trên, Vector có khả năng lưu trữ mọi loại đối tượng. Trong hoàn cảnh cụ thể, để tránh rắc rồi về xác định kiểu của các handle trong Vector, ta có thể tạo ra một "MyVector" của riêng mình với kiểu phần tử cố định và duy nhất. Việc này có thể được thực hiện bằng cách tạo ra một đối tượng mới bao bọc đối tượng Vector. Ví dụ, để tạo ra một đối tượng chỉ cho phép lưu trữ các HocSinh, ta có thể làm như sau: // Lớp MangHocSinh tương tự như Vector nhưng chỉ cho phép lưu trữ và xử // lý cho các đối tượng kiểu HocSinh public class MangHocSinh { // MangHocSinh bao bọc một đối tượng Vector private Vector lop; public MangHocSinh() { lop=new Vector(); } Châu Hải Duy 7/14 Giáo trình Java tóm tắt Java Collections Framework /* Cài đặt lại các phương thức lấy dữ liệu */ void ThemHocSinh(HocSinh hs) { // Up-cast HocSinh-Object lop.add(hs); } HocSinh LayHocSinh(int i) { // Down-cast Object-HocSinh: luôn luôn OK return (HocSinh)lop.elementAt(i); } HocSinh HocSinhCuoiCung() { // Down-cast Object-HocSinh: luôn luôn OK return (HocSinh)lop.lastElement(); } public int SoHocSinh() { return lop.size(); } public void XoaHocSinh(int i) { lop.removeElementAt(i); } } Khi đó, MangHocSinh sẽ được dùng để lưu trữ HocSinh một cách dễ dàng và an toàn. // Tạo mảng học sinh MangHocSinh mhs=new MangHocSinh(); // Nhập mảng học sinh for(int i=0;i<3;i++) { // Không thể add gì khác ngoài HocSinh vào "Vector" này mhs.ThemHocSinh(new HocSinh()); // Không cần lo lỗi down-cast nữa mhs.HocSinhCuoiCung().Nhap(); } // Xuất mảng học sinh for(int i=0;i<mhs.SoHocSinh();i++) { // Không cần lo lỗi down-cast nữa mhs.LayHocSinh(i).Xuat(); System.out.println(); } 2.3.2. Generics Khi làm việc với các Collection, để xử lý trên dữ liệu mà kiểu là chưa biết trước, ta có thể dùng lớp Object và gọi ép kiểu (down-cast, up-cast) khi cần. Việc này khiến chương trình sẽ rối rắm và dễ xảy ra lỗi (ClassCastException). Để khắc phục vấn đề này, từ JDK 5, Java bổ sung một tính năng mới gọi là Generics. Với Generics ta không cần phải ép kiểu và kiểm tra kiểu nữa. Ví dụ: Châu Hải Duy 8/14 Giáo trình Java tóm tắt Java Collections Framework // Khai báo một Vector chứa các HocSinh Vector<HocSinh>v=new Vector(); // Chèn vào một HocSinh v.insert(new HocSinh()); // Chèn vào một PhanSo không cho phép // v.insert(new PhanSo()); // Dòng lệnh này sẽ bị lỗi // Nhập dữ liệu cho học sinh vừa chèn (không cần ép kiểu) v.getLastElement().Nhap(); 2.4. Stack Lớp này kế thừa trực tiếp từ lớp Vector, dùng khi cần truy cập các phần tử theo dạng LIFO ("last in first out" hay "vào sau ra trước"). Các phương thức chính: Phương thức Ý nghĩa Object pop() Lấy phần tử ở đỉnh ra khỏi stack void push(Object o) Thêm một phần tử vào stack Object peek() Xem giá trị của phần tử đỉnh của stack mà không lấy nó ra khỏi stack Bảng 3 Các phương thức chính của lớp Stack 3. Các interface Iterable, Iterator và Enumerator 3.1. Giới thiệu Iterable không phải là một bộ phận của Collections Framework, nhưng việc sử dụng nó thường gắn liền với các đối tượng collection. Iterable quy định khả năng duyệt qua các phần tử của collection một cách tuần tự mà không quan tâm tới chỉ số lẫn vị trí của chúng bằng Iterator hoặc Enumeration. Điều này giúp việc truy cập trở nên nhanh chóng (đối với các collection dạng danh sách liên kết, so với truy cập qua chỉ số) và tự nhiên hơn. Nhìn chung, Enumeration và Iterator là tương tự nhau. Ban đầu, JDK chỉ có Enumeration. Iterator được bổ sung vào sau này và là sự cải tiến của Enumeration: Enumeration chỉ cho phép lấy phần tử và xử lý, còn Iterator cho phép xóa phần tử, ngoài ra các phương thức của Iterator được đặt lại tên cho dễ nhớ hơn. Do là interface, Enumeration và Iterator không thể được tạo ra tùy ý thông qua constructor mà bắt buộc phải được tạo ra từ một collection nào đó (như Vector chẳn hạn). Để tạo ra Enumeration, ta dùng phương thức Enumeration elements(), còn để tạo ra Iterator, ta dùng phương thức Iterator iterator() (như đã để cập trong phần trước). Ngoài ra, kể từ JDK5, Iterable cho phép truy cập dữ liệu của collection bằng vòng lặp "for-each" (xem trong phần sau). Châu Hải Duy 9/14 Giáo trình Java tóm tắt Java Collections Framework 3.2. Các phương thức Phương thức Ý nghĩa Enumeration boolean hasMoreElements() Cho biết Enumeration này còn phần tử chưa xét tới hay không. Trả về true nếu còn. Object nextElement() Trả về đối tượng kế tiếp đối tượng đang xét. Nếu gọi lần đầu thì sẽ trả về phần tử đầu tiên của Enumeration. Iterator boolean hasNext() Cho biết Iterator này còn phần tử chưa xét tới hay không. Trả về true nếu còn. Object next() Trả về đối tượng kế tiếp đối tượng đang xét. Nếu gọi lần đầu thì sẽ trả về phần tử đầu tiên của Iterator. void remove() Xóa phần tử đang xét của Iterator. Phương thức này chỉ được gọi tối đa một lần ứng với một lời gọi next. Bảng 4 Các phương thức thường dùng của Enumerator và Iterator 3.3. Enumeration vs. Vector Dưới đây ta sẽ xem một ví dụ để thấy rõ sự khác biệt khi dùng Enumeration và Iterator so với Vector. Xuất ra các phần tử của Vector V - cách thông thường (dùng chỉ số): // Xuất ra các phần tử của Vector V for (int i=0; i<V.size(); i++) System.out.println(V.get(i)); Xuất ra các phần tử của Vector V - dùng Enumeration: // Xuất ra các phần tử của Vector V – dùng Enumeration // Cách 1 - for for (Enumeration E = V.elements(); E.hasMoreElements();) System.out.println(E.nextElement()); // Cách 2 - while Enumeration E = V.elements(); while (E.hasMoreElements()) System.out.println(E.nextElement()); Xuất ra các phần tử của Vector V - dùng Iterator: // Xuất ra các phần tử của Vector V – dùng Enumeration Châu Hải Duy 10/14 [...].. .Giáo trình Java tóm tắt Java Collections Framework // Cách 1 - for for (Iterator I = V.iterator(); I.hasNext();) System.out.println(I.next()); // Cách 2 - while Iterator I = V.iterator(); while (I.hasNext()) System.out.println(I.next()); 3.4 Vòng lặp "for-each" Từ JDK 5, để lấy các phần tử dữ liệu từ Collections (hoặc từ một đối tượng được dẫn xuất từ... trả về true boolean remove(Object o) Xóa phần tử o khỏi tập hợp Nếu o không có trong tập hợp thì trả về false Châu Hải Duy 11/14 Giáo trình Java tóm tắt Java Collections Framework Bảng 5 Các phương thức chính của interface Set Để dùng được các chức năng của interface Set, Java cung cấp sẵn lớp trừu tượng AbstractSet, dưới lớp này là hai lớp con HashSet và TreeSet, Ngoài ra, AbstractSet còn implement... Châu Hải Duy 12/14 Giáo trình Java tóm tắt Java Collections Framework } public boolean equals(Object o) { return compareTo(o)==0; } public String toString() { return tu+"/"+mau; } public int hashCode() { return (int)tu*10000/mau; } public int compareTo(Object o) { if (o instanceof PhanSo) { PhanSo ps=(PhanSo)o; if (tu*ps.mau==mau*ps.tu) return 0; if (tu*ps.mau< mau*ps.tu) return -1 ; } return 1; } }... System.out.println(p); } Kết quả: (các phần tử được truy cập theo giá trị của hàm băm không đoán được) 4/7 3/8 9/5 1/2 Press any key to continue Dùng TreeSet để chứa các phân số: Châu Hải Duy 13/14 Giáo trình Java tóm tắt Java Collections Framework Set set=new TreeSet(); set.add(new set.add(new set.add(new set.add(new set.add(new PhanSo(1,2)); PhanSo(4,7)); PhanSo(3,8)); PhanSo(9,5)); PhanSo(9,5)); // Ko thể thêm... dạng list (cho phép lưu các phần tử trùng nhau và xử lý chúng một cách có thứ tự), collection còn có dạng set (tập hợp, không cho phép lưu phần tử trùng nhau và không quan tâm tới thứ tự của chúng) Trong Collections Framework, set được đại diện bởi interface Set Set là một interface "con" của interface Collection (và dĩ nhiên cả Iterable) Nó dùng để mô tả chung cho các đối tượng thuộc dạng tập hợp, bao... JDK 5, để lấy các phần tử dữ liệu từ Collections (hoặc từ một đối tượng được dẫn xuất từ Iterator) một cách tuần tự mà không quan tâm tới chỉ số của chúng trong danh sách, ta có thể dùng vòng lặp "for-each" như sau: // Với v là một Vector for (Object o:v) System.out.println(o.toString()); Với Vector định kiểu ta cũng có thể làm tương tự: // Tạo Vector v chứa các HocSinh Vectorv = new Vector(); . Giáo trình Java tóm tắt Java Collections Framework Java Collections Framework Java Collections Framework 1 1. Giới thiệu chung 1 2. List. đây là sơ đồ quan hệ của Java Collections Framework (chỉ có một số interface và class chính). Châu Hải Duy 1/14 Giáo trình Java tóm tắt Java Collections Framework Hình 1: Collections Framework 2 mảng và cho phép thêm/xóa các phần tử. Châu Hải Duy 3/14 Giáo trình Java tóm tắt Java Collections Framework Hình 2 Vị trí của Vector trong Java Collections Framework Ngoài Vector, ta còn có thể dùng