You are on page 1of 41

IT3100

LẬP TRÌNH HƯỚNG


ĐỐI TƯỢNG
Bài 08. Lập trình tổng quát

1
Mục tiêu
 Giới thiệu về lập trình tổng quát và cách thực hiện
trong các ngôn ngữ lập trình
 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
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
1/ GIỚI THIỆU

4
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ụ:

• Số nguyên int
• Xâu ký tự String
Phương thức sort() • Đố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.

5
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
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
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
public class ArrayList {
public Object get(int i) { . . . }
public void add(Object o) { . . . }
. . .
private Object[] elementData;
}
 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ó
List myList = new ArrayList();
myList.add("Fred");
myList.add(new Dog());
myList.add(new Integer(42));

 Hạn chế: Phải ép kiểu  có thể ép sai kiểu / Nhầm lẫn


String name = (String) myList.get(1); //Dog!!!
8
2/ LẬP TRÌNH TỔNG QUÁT
TRONG JAVA

9
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 dung 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
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

10
Ví dụ
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());

11
2.2. Lớp tổng quát nhiều tham số
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(){
GfG
System.out.println(obj1);
15
System.out.println(obj2);
}
}

// in main()
Test <String, Integer> obj = new Test<String,
Integer>("GfG", 15);
obj.print();

12
2.3. Giao diện tổng quát

public interface GenericInterface<G> {


public G doSomething();
}

public class GenericInterfaceImpl<G> implements


GenericInterface<G>{
private G something;

@Override
public G doSomething() {
return something;
}
}

13
2.4. Phương thức tổng quát
 Có thể được viết trong lớp bất kỳ (tổng quát hoặc không)
 Cú pháp

chỉĐịnhTruyCập <kiểu…> kiểuTrảVề tênPhươngThức


(danh sách tham số) {
//…
}

 Ví dụ

public static <E> void print(E[] a) {



}

14
Ví dụ

public class KeyValue<K, V> { ... }


public class MyUtils {
public static <K, V> K getKey(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.getKey(entry1);

15
Ví dụ
public 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();
}
} ...
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); 16
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ụ: Chấp nhận các kiểu là lớp con
của 2DShape

public class Information<T extends 2DShape> {



}
Information<Point> pointInfo =
new Information<Point>(new Point()); // OK
Information<String> stringInfo =
new Information<String>(); // error

17
3/ JAVA COLLECTION
FRAMEWORK

18
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
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
3.1. Java Collection Framework (3)
 Collections Framework bao gồm
 Interfaces: Là các giao tiếp 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 cài đặt
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
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

Lớp thực thi các giao diện


đã được xây dựng sẵn
22
3.2. Interfaces

23
3.2 Interfaces (2)

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

24
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
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ỡ

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) + " ");

26
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
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) + " ");

27
HashSet và HashMap
 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
 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)

HashMap vs HashTable: Tự tham khảo

28
HashSet và HashMap
HashSet<String> hs = new HashSet<String>();

hs.add("Geeks");
hs.add("For");
hs.add("Geeks");
hs.add("Is");
hs.add("Very helpful"); HashMap<Integer, String> hm
= new HashMap<Integer, String>();
System.out.println(“HashSet: " + hs);
hm.put(1, "Geeks");
// Traversing elements hm.put(2, "For");
Iterator<String> itr = hs.iterator(); hm.put(3, "Geeks");
while (itr.hasNext()) {
System.out.println(itr.next()); 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());
29
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 thêm các phương thức đưa ra bản chất tuần tự
của danh sách cơ sở
 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
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
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ẽ dung đó 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
Ví dụ
class Person { Cài đặt AgeComparator
private int age;
class AgeComparator implements
private String name;
Comparator {
public void setAge(int age){ public int compare(Object ob1,
this.age=age; Object ob2) {
} int ob1Age =
public int getAge(){
((Person)ob1).getAge();
return this.age;
} int ob2Age =
public void setName(String name){ ((Person)ob2).getAge();
this.name=name;
} if(ob1Age > ob2Age)
public String getName(){
return 1;
return this.name;
} else if(ob1Age < ob2Age)
} return -1;
else
return 0;
}
}

33
Sử dụng AgeComparator
Ví dụ
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"); System.out.println("Order before sorting");
lst.add(p); for (Person person : lst) {
p = new Person(); System.out.println(person.getName() +
p.setAge(30); p.setName("B"); "\t" + person.getAge());
lst.add(p); }
p = new Person();
p.setAge(32); p.setName("C"); Collections.sort(lst, new AgeComparator());
lst.add(p); System.out.println("\n\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

34
4. KÝ TỰ ĐẠI DIỆN
(WILDCARD)

35
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
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:
public void foo( ArrayList<? extends Animal> a)
public <T extends Animal> void foo( ArrayList<T> a)
37
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

List<? extends Object> list=


new ArrayList<? extends Object>(); // Error

38
Ví dụ
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 liên kết 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

39
Ví dụ
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
}
}

40
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

You might also like