I. Generics là gì?

1.  Định nghĩa:

Thuật ngữ “Generics” có nghĩa là tham số hóa dữ liệu. Tham số hóa dữ liệu rất quan trọng vì nó cho phép chúng ta tạo ra và sử dụng 1 class, interface, method với nhiều kiểu dữ liệu khác nhau. Một class, interface hay một method mà thực hiện trên một kiểu tham số xác định thì gọi là generic.(Generics đơn giản là kiểu biểu diễn của Types dưới dạng tham số khi định nghĩa lớp, hàm và interfaces. Tương tự như ý nghĩa của tham số tương ứng với một hàm, nó chỉ khác là với hàm thì dữ liệu đầu vào là các giá trị xác định, còn với Generics đó là Types.)

Generics là cách thức lập trình tổng quát cho phép một object hoạt động với nhiều kiểu dữ liệu khác nhau.

Ex: Với sự trợ giúp của Generics, bạn có thể tạo ra một đối tượng ArrayList chỉ cho phép chứa các phần tử có kiểu String, và không cho phép chứa các phần tử có kiểu khác.

package ss4generics;

import java.util.ArrayList;

public class ExampleGeneric1 {

   public static void main(String[] args) {
       // Tạo một đối tượng danh sách.
       // Mục đích chứa các tên người dùng.
       ArrayList<String> userNames = new ArrayList<String>();

       // Thêm String vào danh sách
       userNames.add("tom");
       userNames.add("jerry");

       // Bạn không thể thêm một phần tử khác kiểu String
       userNames.add(new Integer(100));

       // Bạn không cần ép kiểu.
       String userName1 = userNames.get(0);

       System.out.println("userName1 = " + userName1);

   }

}

2. Ưu điểm của Generic.

2.1. Kiểm tra kiểu dữ liệu trong thời điểm biên dịch.  

Trình biên dịch Java áp dụng việc kiểm tra đoạn mã generic để phát hiện các vấn đề như vi phạm an toàn kiểu dữ liệu. Việc sửa lỗi tại thời gian biên dịch dễ dàng hơn nhiều khi sửa chữa lỗi tại thời điểm chạy chương trình.                                                                                                                

Không cần ép kiểu dữ liệu: đoạn code sau đây không dùng generic nên phải ép kiểu.

List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);      //phải ép kiểu

Khi dùng generic, việc ép kiểu đã được loại bỏ:

List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0);   //không ép kiểu

2.2. Cho phép lập trình viên thực hiện các xử lý tổng quát.

Bằng cách sử dụng generics, người lập trình có thể thực hiện các thuật toán tổng quát với các kiểu dữ liệu tùy chọn khác nhau, và nội dung đoạn code trở nên rõ ràng và dễ hiểu.

3. Một số lưu ý khi sử dụng Generic.

3.1. Không thể gọi Generics bằng kiểu dữ liệu Primitive.

Có lớp generics: Colours<G,B>
Colours<int, char>//compile-time error
Colours<Integer, Character>//true

3.2. Không thể tạo instances của kiểu dữ liệu Generics.

class Gen<T>{
 T obj;
 Gen(){
   obj= new T(); //Illegal (error)
 }
}

3.3. Không thể sử dụng static cho Generics:

class Gen<T>{
 static T obj; //Kiểu T không thể là static
 static T getObj(){ //Phương thức không thể static
   return obj;
 }
}

3.4. Không thể ép kiểu hoặc sử dụng instanceof.

 public static <E> void rtti(List<E> list) {
     if (list instanceof ArrayList<Integer>) {  // compile-time error
     // ...
     }
 }
 List<Integer> li = new ArrayList<>();
 List<Number>  ln = (List<Number>) li;  // compile-time error

3.5. Không thể tạo mảng với parameterized types.

Gen<Integer> gens[] = new Gen<Integer>[10]; //error

Gen<?> gens[] = new Gen<?>[10]; //ok
Gens[0] = new Gen<Integer>(25);
Gens[1] = new Gen<String>("Hello");

3.6. Không thể tạo, catch, throw đối tượng của parameterized types.

// Extends Throwable indirectly
class MathException<T> extends Exception { /* ... */ }    // compile-time error

// Extends Throwable directly
class QueueFullException<T> extends Throwable { /* ... */ // compile-time error

3.7. Không thể overload các hàm trong một lớp giống như.

public class Example {
    public void print(Set<String> strSet) { }
    public void print(Set<Integer> intSet) { }
}

II. Generics trong Legacy Code.

1. Code snippet 30( displays the use of generics.)

package generic.codesnippet30;
import java.util.*;
interface NumStack<E> { // interface
    //method
    public boolean empty();//phương thức trả về T/F 

    public void push(E elt); //method push(E elt) không trả về

    public E retrieve(); //generic
}

@SuppressWarnings("unchecked")//được kiểm soát
class NumArrayStack<E> implements NumStack<E> { 

    private List listObj; //khai báo list kiểu private

    public NumArrayStack() {
        listObj = new ArrayList();//tạo 1 listOjb
    }

    public boolean empty() {
        return listObj.size() == 0; //phương thức trả về T/F
    }

    public void push(E obj) {
        listObj.add(obj); //add
    }

    public E retrieve() { //genecy
        Object value = listObj.remove(listObj.size() - 1);//remove 1 phần tử trong list Obj
        return (E) value;// trả về <E> value
    }

    public String toString() { //biểu thức đầu vào
        return "stack" + listObj.toString();
    }
}

class ClientLegacy {
    public static void main(String[] args) {//main
        NumStack stackObj = new NumArrayStack();
        for (int ctr = 0; ctr < 4; ctr++) {
            stackObj.push(new Integer(ctr));
        }
        assert stackObj.toString().equals("stack[0, 1, 2, 3]"); // hàm assert đánh giá biểu thức đầu vào
        int top = ((Integer) stackObj.retrieve()).intValue(); //
        System.out.println("Value is : " + top);
        System.out.println("Stack contains : " + stackObj.toString());
    }
}

2. Code snippet 31 ( the use of generics in legacy code.)

package codesnippet31;
import java.util.*;
//interface và các lớp được thực hiện kiểu tham số
//Các tham số kiểu <E> thay thế các đối tượng lấy ra từ push() và and retrieve()
interface NumStack<E> {// interface, tham số kiểu Element(phần tử)

    public void push(E elt);

    public E retrieve();
}

class NumArrayStack<E> implements NumStack<E> {

    private List<E> listObj; //khai báo list(có tham số E: phần tử) kiểu private

    public NumArrayStack() {
        listObj = new ArrayList<E>();//
    }

    public void push(E obj) {
        listObj.add(obj);//add
    }

    public E retrieve() {
        E value = listObj.remove(listObj.size() - 1);//xóa 1 phần tử trong listObj
        return value; //
    }

    public String toString() {
        return "stack" + listObj.toString();
    }
}

public class GenericClient {
    public static void main(String[] args) {
        NumStack<Integer> stackObj = new NumArrayStack<Integer>();
        for (int ctr = 0; ctr < 4; ctr++) {
            stackObj.push(ctr);
        }
        assert stackObj.toString().equals("stack[0, 1, 2, 3]");// hàm assert đánh giá biểu thức đầu vào
        int top = stackObj.retrieve();
        System.out.println("Value is : " + top);
        System.out.println("Stack contains : " + stackObj.toString());
    }
}

Capture12.JPG

Advertisements