Bai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquatBai08 lap trinhtongquat
2. Mục tiêu
Giới thiệu về lập trình tổng quát
Giới thiệu về collection framework với các cấu trúc
tổng quát: List, HashMap, Tree, Set, Vector,…
Định nghĩa và sử dụng Template và ký tự đại diện
(wildcard)
2
3. Nội dung
1. Giới thiệu
2. Lập trình tổng quát trong Java
3. Java collection framework
4. Ký tự đại diện (Wildcard)
3
5. 1. Giới thiệu về lập trình tổng quát
Lập trình tổng quát (Generic programming): Tổng quát hóa
chương trình để có thể hoạt động với các kiểu dữ liệu khác
nhau, kể cả kiểu dữ liệu trong tương lai
Thuật toán đã xác định
Ví dụ:
5
Phương thức sort()
• Số nguyên int
• Xâu ký tự String
• Đối tượng số phức
Complex object
• ...
Thuật toán giống nhau, chỉ
khác về kiểu dữ liệu
Kiểu dữ liệu trở thành tham số cho phương thức, lớp, giao diện, v.v.
6. 1. Giới thiệu về lập trình tổng quát
Lập trình tổng quát
C: dùng con trỏ không định kiểu (con trỏ void)
C++: dùng template
Java 1.5 trở về trước: lợi dụng upcasting, downcasting
và lớp object
Java 1.5: đưa ra khái niệm về generics (~template)
6
7. 1. Giới thiệu về lập trình tổng quát
Ví dụ C: hàm memcpy() trong thư viện string.h
void* memcpy(void* region1, const void* region2, size_t n);
Hàm memcpy() bên trên được khai báo tổng quát bằng
cách sử dụng các con trỏ void*
Điều này giúp cho hàm có thể sử dụng với nhiều kiểu
dữ liệu khác nhau
• Dữ liệu được truyền vào một cách tổng quát thông qua địa chỉ
và kích thước kiểu dữ liệu
• Hay nói cách khác, để sao chép dữ liệu, ta chỉ cần địa chỉ và
kích cỡ của chúng
7
8. 1. Giới thiệu về lập trình tổng quát
Ví dụ: Lập trình tổng quát từ trước Java 1.5
Lớp Object là lớp cha tổng quát nhất có thể chấp nhận
các đối tượng thuộc lớp con của nó
Hạn chế: Phải ép kiểu có thể ép sai kiểu / Nhầm lẫn
8
public class ArrayList {
public Object get(int i) { . . . }
public void add(Object o) { . . . }
. . .
private Object[] elementData;
}
List myList = new ArrayList();
myList.add("Fred");
myList.add(new Dog());
myList.add(new Integer(42));
String name = (String) myList.get(1); //Dog!!!
10. 2.1. Lớp tổng quát
Sử dụng <> để xác định tham số cho kiểu dữ liệu khi
tạo lớp
Không được dùng các kiểu nguyên thủy làm tham số
Các phương thức hay thuộc tính của lớp tổng quát có thể sử
dụng các kiểu được khai báo như mọi lớp bình thường khác
Sử dụng
10
class Test<T> {
private T obj;
Test(T obj) { this.obj = obj; }
public T getObject() { return this.obj; }
}
Test <Integer> iObj = new Test<Integer>(15);
Integer num = iObj.getObject();
Test <String> sObj = new Test<String>("GeeksForGeeks");
String str = sObj.getObject();
iObj = sObj; //This results an error
11. Ví dụ
11
public class Information<T> {
private T value;
public Information(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
Information<Circle> circle =
new Information<Circle>(new Circle());
Information<2DShape> shape =
new Information<>(new 2DShape());
12. 2.2. Lớp tổng quát nhiều tham số
12
class Test<T, U> {
T obj1; // An object of type T
U obj2; // An object of type U
Test(T obj1, U obj2){
this.obj1 = obj1;
this.obj2 = obj2;
}
public void print(){
System.out.println(obj1);
System.out.println(obj2);
}
}
// in main()
Test <String, Integer> obj = new Test<String,
Integer>("GfG", 15);
obj.print();
GfG
15
13. 2.3. Giao diện tổng quát
13
public interface GenericInterface<G> {
public G doSomething();
}
public class GenericInterfaceImpl<G> implements
GenericInterface<G>{
private G something;
@Override
public G doSomething() {
return something;
}
}
14. 2.4. Phương thức tổng quát
14
Có thể được viết trong lớp bất kỳ (tổng quát hoặc không)
Cú pháp
Ví dụ
chỉĐịnhTruyCập <kiểu…> kiểuTrảVề tênPhươngThức
(danh sách tham số) {
//…
}
public static <E> void print(E[] a) {
…
}
15. Ví dụ
15
class KeyValue<K,V> {
K key;
V value;
KeyValue(K key, V value){…}
K getKey(){
return key;
}
}
class MyUtils {
public static <K,V> K getKeyFromMyUtils(KeyValue<K,V> entry){
K key = entry.getKey();
return key;
}
}
// in main
KeyValue<Integer,String> entry1 = new
KeyValue<Integer,String>(12000111,"Tom");
Integer phone = MyUtils.getKeyFromMyUtils(entry1);
System.out.println(phone);
16. Ví dụ
class ArrayTool {
// in các phần tử trong mảng String
public static void print(String[] a) {
for (String e : a) System.out.print(e + " ");
System.out.println();
}
// in các phần tử trong mảng với kiểu dữ liệu bất kỳ
public static <E> void print(E[] a) {
for (E e : a) System.out.print(e + " ");
System.out.println();
}
}
16
...
String[] str = new String[5];
Point[] p = new Point[3];
int[] intnum = new int[2];
ArrayTool.print(str);
ArrayTool.print(p);
// Không dùng được với kiểu dữ liệu nguyên thủy
ArrayTool.print(intnum);
17. 2.5 Giới hạn kiểu dữ liệu tổng quát
Có thể giới hạn các kiểu dữ liệu tổng quát sử dụng
phải là dẫn xuất của một hoặc nhiều lớp
<type_param extends bound>
Ví dụ:
17
public class Information<T extends 2DShape> {
…
}
Information<Point> pointInfo =
new Information<Point>(new Point()); // OK
Information<String> stringInfo =
new Information<String>(); // error
Chấp nhận các kiểu là lớp con
của 2DShape
19. 3.1. Java Collection Framework
Collection là đối tượng có khả năng chứa các đối
tượng khác.
Các thao tác thông thường trên collection
Thêm/Xoá đối tượng vào/khỏi collection
Kiểm tra một đối tượng có ở trong collection không
Lấy một đối tượng từ collection
Duyệt các đối tượng trong collection
Xoá toàn bộ collection
Các collection đầu tiên của Java:
Mảng
Vector: Mảng động
Hastable: Bảng băm
19
20. 3.1. Java Collection Framework (2)
Collections Framework (từ Java 1.2)
Là một kiến trúc hợp nhất để biểu diễn và thao tác trên các
collection.
Giúp cho việc xử lý các collection độc lập với biểu diễn chi
tiết bên trong của chúng.
Một số lợi ích của Collections Framework
Giảm thời gian lập trình
Tăng cường hiệu năng chương trình
Dễ mở rộng các collection mới
Khuyến khích việc sử dụng lại mã chương trình
20
21. 3.1. Java Collection Framework (3)
Collections Framework bao gồm
Interfaces: Là các giao diện thể hiện tính chất của các kiểu
collection khác nhau như List, Set, Map.
Implementations: Là các lớp collection có sẵn được triển
khai các collection interfaces.
Algorithms: Là các phương thức tĩnh để xử lý trên collection,
ví dụ: sắp xếp danh sách, tìm phần tử lớn nhất...
Các giao diện và lớp thực thi trong Collection framework
của Java đều được xây dựng theo generics
Cho phép xác định tập các phần tử cùng kiểu nào đó
Chỉ định kiểu dữ liệu của các Collection sẽ hạn chế việc
thao tác sai kiểu dữ liệu
21
22. 3.1. Java Collection Framework (4)
List: Tập các đối tượng tuần tự, kế tiếp nhau, có thể lặp lại
Set: Tập các đối tượng không lặp lại
Map: Tập các cặp khóa-giá trị (key-value) và không cho
phép khóa lặp lại
22
Lớp thực thi các giao diện
đã được xây dựng sẵn
24. 3.2 Interfaces (2)
24
Giao diện SortedMap
bổ sung thêm:
firstKey( ): returns the first (lowest) value currently in the map
lastKey( ): returns the last (highest) value currently in the map
25. 3.3. Các lớp thực thi giao diện Collection
Java đã xây dựng sẵn một số lớp thực thi các giao
diện Set, List và Map và cài đặt các phương thức
tương ứng
25
26. ArrayList
Mảng động, nếu các phần tử thêm vào vượt quá
kích cỡ mảng, mảng sẽ tự động tăng kích cỡ
26
ArrayList<Integer> al = new ArrayList<Integer>();
for (int i = 1; i <= 5; i++) al.add(i);
System.out.println(al);
al.remove(3);
System.out.println(al);
// Printing elements one by one
for (int i = 0; i < al.size(); i++)
System.out.print(al.get(i) + " ");
[1, 2, 3, 4, 5]
[1, 2, 3, 5]
1 2 3 5
27. LinkedList
Danh sách liên kết
Hỗ trợ thao tác trên đầu và cuối danh sách
Được sử dụng để tạo ngăn xếp, hàng đợi, cây
27
LinkedList<Integer> ll = new LinkedList<Integer>();
for (int i = 1; i <= 5; i++) ll.add(i);
System.out.println(ll);
ll.remove(3);
System.out.println(ll);
// Printing elements one by one
for (int i = 0; i < ll.size(); i++)
System.out.print(ll.get(i) + " ");
[1, 2, 3, 4, 5]
[1, 2, 3, 5]
1 2 3 5
28. HashMap và HashSet
HashMap – implementation của giao diện Map
Tập Ánh xạ giữa key và value. Vd {a->1, b->2, c->2, d->4}
Các Key không được trùng nhau
Sử dụng công nghệ Hashing để lưu phần tử
Thêm phần tử vào HashMap bằng lệnh put(Object key, Object
value)
HashSet – implementation của giao diện Set
Tập các đối tượng không lặp lại. Ví dụ {1,2,3,4,5,6,7}.
Bên trong HashSet sử dụng một HashMap để thêm phần tử.
Thêm phần tử vào HashSet bằng lệnh add(Object o)
HashSet chậm hơn HashMap
28
HashMap vs HashTable: Tự tham khảo
29. HashMap và HashSet
29
HashMap<Integer, String> hm
= new HashMap<Integer, String>();
hm.put(1, "Geeks");
hm.put(2, "For");
hm.put(3, "Geeks");
System.out.println("HashMap: " + hm);
// Finding the value for a key
System.out.println("Value for 1 is " + hm.get(1));
// Traversing through the HashMap
for (Map.Entry<Integer, String> e : hm.entrySet())
System.out.println(e.getKey() + " " + e.getValue());
HashSet<String> hs = new HashSet<String>();
hs.add("Geeks");
hs.add("For");
hs.add("Geeks");
hs.add("Is");
hs.add("Very helpful");
System.out.println("HashSet: " + hs);
// Traversing elements
Iterator<String> itr = hs.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
HashSet: [Very helpful, Geeks, For, Is]
Very helpful
Geeks
For
Is
HashMap: {1=Geeks, 2=For, 3=Geeks}
Value for 1 is Geeks
1 Geeks
2 For
3 Geeks
30. Iterator
Cung cấp cơ chế thuận tiện để duyệt qua toàn bộ nội dung
của tập hợp, mỗi lần là một đối tượng trong tập hợp
Iterator của các tập hợp đã sắp xếp duyệt theo thứ tự tập
hợp
ListIterator : duyệt cả 2 chiều
Iterator : Các phương thức
iterator( ): yêu cầu container trả về một iterator
next( ): trả về phần tử tiếp theo
hasNext( ): kiểm tra có tồn tại phần tử tiếp theo
hay không
remove( ): xóa phần tử gần nhất của iterator
31. Ví dụ
Định nghĩa iterator
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
Sử dụng iterator
Collection c ;
Iterator i = c.iterator();
while (i.hasNext()) {
Object o = i.next();
// Process this object
...
}
31
32. Comparator
Giao diện Comparator được sử dụng để cho phép so sánh
hai đối tượng trong tập hợp
Một Comparator phải định nghĩa một phương thức
compare( ) lấy 2 tham số Object và trả về -1, 0 hoặc 1
Phương thức Collections.sort() sẽ dùng đó làm cơ sở để
thực hiện sắp xếp
Không cần thiết nếu tập hợp đã có khả năng so sánh tự
nhiên (vd. String, Integer…)
32
33. Ví dụ
33
class Person {
private int age;
private String name;
public void setAge(int age){…}
public int getAge() {…}
public void setName(String name) {…}
public String getName() {…}
}
class AgeComparator implements Comparator {
public int compare(Object ob1, Object ob2) {
int ob1Age = ((Person)ob1).getAge();
int ob2Age = ((Person)ob2).getAge();
if(ob1Age > ob2Age)
return 1;
else if(ob1Age < ob2Age)
return -1;
else
return 0;
}
}
Cài đặt AgeComparator
34. Ví dụ
34
public class ComparatorExample {
public static void main(String args[]) {
ArrayList<Person> lst = new ArrayList<Person>();
Person p = new Person();
p.setAge(35); p.setName("A");
lst.add(p);
p = new Person();
p.setAge(30); p.setName("B");
lst.add(p);
p = new Person();
p.setAge(32); p.setName("C");
lst.add(p);
Sử dụng AgeComparator
System.out.println("Order before sorting");
for (Person person : lst) {
System.out.println(person.getName() +
"t" + person.getAge());
}
Collections.sort(lst, new AgeComparator());
System.out.println("nOrder of person " +
"after sorting by age");
for (Iterator<Person> i = lst.iterator();
i.hasNext();) {
Person person = i.next();
System.out.println(person.getName() + "t" +
person.getAge());
} //End of for
} //End of main
} //End of class
Order before sorting
A 35
B 30
C 32
Order of person after sorting by age
B 30
C 32
A 35
36. 4.1. Ký tự đại diện (Wildcard)
Trong LTTQ, dấu chấm hỏi (?), được gọi là một
đại diện cho một loại/kiểu chưa rõ ràng.
Khi biên dịch, dấu ? có thể được thay thế bởi bất
kì kiểu dữ liệu nào.
36
37. 3.2. Ý nghĩa ký tự đại diện
"?": Xác định tập tất cả các kiểu hoặc bất kỳ kiểu nào.
"? extends Type": Xác định một tập các kiểu con của
Type.
"? super Type": Xác định một tập các kiểu cha của
Type
Ví dụ:
Collection<?> mô tả một tập hợp chấp nhận tất cả các loại
đối số (chứa mọi kiểu đối tượng).
List<? extends Number> mô tả một danh sách, nơi mà các
phần tử là kiểu Number hoặc kiểu con của Number.
Comparator<? super String> Mô tả một bộ so sánh
(Comparator) mà thông số phải là String hoặc cha
của String.
Hai cú pháp sau là tương đương:
37
public void foo( ArrayList<? extends Animal> a)
public <T extends Animal> void foo( ArrayList<T> a)
38. 3.3. Sử dụng ký tự đại diện
? được dùng trong LTTQ như kiểu của một tham
số, trường (field), hoặc biến địa phương; đôi khi
như một kiểu trả về
không được dùng như là một đối số cho lời gọi
một phương thức tổng quát, p/t khởi tạo đối
tượng của lớp tổng quát, hoặc p/t lớp cha
38
List<? extends Object> list=
new ArrayList<? extends Object>(); // Error
39. Ví dụ
39
Collection<?> coll = new ArrayList<String>();
// Một tập hợp chỉ chứa kiểu Number hoặc kiểu con của Number
List<? extends Number> list = new ArrayList<Long>();
// Một đối tượng có kiểu tham số đại diện.
Pair<String,?> pair = new Pair<String,Integer>();
Một số khai báo không hợp lệ
// String không phải là kiểu con của Number, vì vậy lỗi.
List<? extends Number> list = new ArrayList<String>();
// Integer không phải là kiểu cha String của vì vậy lỗi
ArrayList<? super String> cmp = new ArrayList<Integer>();
ArrayList<?> list = new ArrayList<String>();
list.add("a1"); //compile error
list.add(new Object()); //compile error
// Vì không biết list là danh sách cho kiểu dữ liệu nào, nên không thể thêm phần tử vào list, kể
cả đối tượng của lớp Object
40. Ví dụ
40
public class Example1 {
public static void main(String[] args) {
ArrayList<String> listString = new ArrayList<String>();
listString.add("Tom");
listString.add("Jerry");
ArrayList<Integer> listInteger = new ArrayList<Integer>();
listInteger.add(100);
ArrayList<Object> list1 = listString; // ==> Error!
// Một đối tượng kiểu tham số đại diện.
ArrayList<? extends Object> list2;
list2 = listString; // ok
list2 = listInteger; // ok
}
}
41. Bài tập
Trừu tượng hoá mô tả sau: một quyển sách là tập
hợp các chương, chương là tập hợp các trang.
Phác hoạ các lớp Book, Chapter, và Page
Tạo các thuộc tính cần thiết cho các lớp, sử dụng Collection
Tạo các phương thức cho lớp Chapter cho việc thêm trang
và xác định một chương có bao nhiêu trang
Tạo các phương thức cho lớp Book cho việc thêm chương và
xác định quyển sách có bao nhiêu chương, và số trang cho
quyển sách
41