Generic trong java (Bài 6) | Gia Sư Tin Học

Generic trong java sẽ bắt đầu với khái niệm Generics. Thuật ngữ “Generics” nghĩa là tham số hóa kiểu dữ liệu. Tham số hóa kiểu dữ liệu rất quan trọng vì nó cho phép chúng ta tạo ra và sử dụng một 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 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.

Generic trong java – Một số ví dụ

Ví du 1: Tạo class tên SampleGeneric1 trong package generic và sử dụng ArrayList với các kiểu dữ liệu khác nhau

package generic;
import java.util.ArrayList;
/**
 *
 * @author giasutinhoc.vn
 */
public class SampleGeneric1 {
 public static void main(String[] args) {
   // Sử dụng ArrayList với các kiểu dữ liệu khác nhau
   ArrayList mylist = new ArrayList();
   // Thêm vào array
   mylist.add(10);
   mylist.add("Hello");
   mylist.add(true);
   mylist.add(15.75);
   // Lấy ra
   int i = (Integer)mylist.get(0);
   String s = (String)mylist.get(1);
   boolean b = (boolean)mylist.get(2);
   double d = (double)mylist.get(3);
   // Hiển thị
   System.out.println("Phan tu thu nhat la: " + i);
   System.out.println("Phan tu thu hai la: " + s);
   System.out.println("Phan tu thu ba la: " + b);
   System.out.println("Phan tu thu tu la: " + d);
 }
}

Ví dụ 2 : Sử dụng ArrayList với những kiểu tài liệu Integer
generic trong java 1

Tạo class tên SampleGeneric2 trong package generic

package generic;
import java.util.ArrayList;
/**
 *
 * @author giasutinhoc.vn
 */
public class SampleGeneric2 {
 public static void main(String[] args) {
   // Sử dụng ArrayList với các kiểu dữ liệu Integer
   ArrayList mylist = new ArrayList();
   // Thêm vào array
   mylist.add(10);
   mylist.add("Hello");  //Error
   // Lấy ra
   int i = mylist.get(0);
   // Hiển thị
   System.out.println("So nguyen: " + i);
  }
}

Ví dụ 3 : Sử dụng ArrayList với những kiểu tài liệu String

Tạo class tên SampleGeneric3 trong package generic

package generic;
import java.util.ArrayList;
/**
 *
 * @author giasutinhoc.vn
 */
public class SampleGeneric3 {
 public static void main(String[] args) {
   // Sử dụng ArrayList với các kiểu dữ liệu String
   ArrayList mylist = new ArrayList();
   // Thêm vào array
   mylist.add("Nguyen Thi Xuan");
   mylist.add("Tran Van Ha");
   // Lấy ra
   String name1 = mylist.get(0);
   String name2 = mylist.get(1);
   // Hiển thị
   System.out.println("Ho ten nguoi thu nhat: " + name1);
   System.out.println("Ho ten nguoi thu hai: " + name2);
  }
}

Generic trong java – Ưu điểm của generic

Kiểm tra kiểu tài liệu trong thời gian biên dịch

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

Không cần ép kiểu tài 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 vô hiệu :

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

Cho phép lập trình viên thực thi những giải quyết và xử lý tổng quát .

Bằng cách sử dụng generics, người lập trình hoàn toàn có thể triển khai những thuật toán tổng quát với những kiểu tài 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 .

Generic trong java – Generic Methods

Là giải pháp giúp tạo ra một phương pháp mà hoàn toàn có thể được gọi với nhiều kiểu tài liệu khác nhau. Dựa vào kiểu tài liệu được truyền vào, trình biên dịch sẽ giải quyết và xử lý mỗi lời gọi phương pháp sao cho tương thích .
Quy ước đặt tên tham số kiểu cho Generics

tự Ý nghĩa
E Element – phần tử
K Key – khóa
V Value – giá trị
T Type – kiểu dữ liệu
N Number – số

Ví dụ tạo class tên GenericMethodTest trong package generic

package generic;
/**
 *
 * @author giasutinhoc.vn
 */
public class GenericMethodTest {
 // generic method printArray
 public  void printArray(T[] inputArray) {
  // Display array elements
   for ( T element : inputArray ){
    System.out.print(element);
   }
   System.out.println();
 }
 public static void main( String args[] ){
   // Create arrays of Integer, Double and Character
   Integer[] intArray = { 1, 2, 3, 4, 5 };
   Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
   Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
   // Create object
   GenericMethodTest gmt = new GenericMethodTest();
   System.out.println( "Array integerArray contains:" );
   gmt.printArray( intArray ); // pass an Integer array
   System.out.println( "\nArray doubleArray contains:" );
   gmt.printArray( doubleArray ); // pass a Double array
   System.out.println( "\nArray characterArray contains:" );
   gmt.printArray( charArray ); // pass a Character array
 }
}

Chạy chương trình sẽ cho tác dụng như sau :
generic trong java 2

Generic trong java – Generic Classes

Khai báo một lớp dạng generic giống như khai báo một lớp không phải generic ngoại trừ theo sau tên lớp là một kiểu tài liệu tổng quát .
Giống như phương pháp dạng generic, trong trường hợp có nhiều tham số thì mỗi tham số được ngăn cách bởi dấu phẩy .

Ví dụ tạo class tên Box trong package generic

package generic;
/**
 *
 * @author giasutinhoc.vn
 */
public class Box {
 private T t;
 public void add(T t) {
   this.t = t;
 }
 public T get() {
   return t;
 }
 public static void main(String[] args) {
  Box intBox = new Box();
  Box strBox = new Box();
  intBox.add(new Integer(10));
  strBox.add(new String("Hello World"));
  System.out.println("Integer Value: " + intBox.get());
  System.out.println("String Value: " + strBox.get());
 }
}

Kết quả sau khi chạy chương trình là :

Integer Value :10 
String Value :Hello World

Generic trong java – Các ký tự đại diện generic (Wildcards)

Ký tự đại diện

Xét ví dụ sau :

private boolean checkEquals(RestricExample e) {
 if(number.doubleValue() == e.number.doubleValue()) {
   return true;
 }
 return false;
}
 private boolean checkEquals2(RestricExample e) {
  if(number.doubleValue() == e.number.doubleValue()) {
   return true;
  }
  return false;
 }

Phương thức checkEquals chỉ gật đầu tham số e có kiểu tài liệu giống với biến number. Phương thức checkEquals2 gật đầu tham số e có kiểu tài liệu khác với biến number .

Ký tự đại diện chấp nhận bất ký đối tượng nào miễn là đối tượng này kế thừa từ type hoặc đối tượng của type

Ví dụ :

public void processElement(List elements){
 ...
}

Trong đó :
Sử dụng phương pháp processElement ( Chấp nhận bất ký đối tượng người tiêu dùng nào miễn là đối tượng người dùng này phải kế thừa từ lớp A hoặc đối tượng người dùng của A => ClassA, ClassB và ClassC )

List listA = new ArrayList();
processElement(listA);

List listB = new ArrayList();
processElement(listB);

List listC = new ArrayList();
processElement(listC);

Ký tự đại diện chấp nhận bất ký đối tượng nào miễn là đối tượng này là cha của type hoặc đối tượng của type

Ví dụ :

public void processElement(List elements){
 ...
}
List listA = new ArrayList();
processElement(listA);

List listO = new ArrayList();
processElement(listO);

Generic trong java – Giới hạn kiểu dữ liệu với ký tự đại diện

Có 1 số ít trường hợp tất cả chúng ta muốn hạn chế kiểu tài liệu của những tham số. Chẳng hạn tạo phương pháp chỉ gật đầu tham số với kiểu tài liệu là số nguyên hoặc số thực .

package generic;
/**
 *
 * @author giasutinhoc.vn
 */
public class RestricExample  {
 private T number;
 public RestricExample(T number) {
  this.number = number;
 }

 public double reciprocal() {
   return 1/number.doubleValue();
 }

 public static void main(String[] args) {
   RestricExample n1 = new RestricExample(5);
   System.out.println("Reciprocal: " + n1.reciprocal());
   RestricExample n2 = new RestricExample(7.5);
   System.out.println("Reciprocal: " + n2.reciprocal());
   //error
   //RestricExample s1 = new RestricExample("Hello");
 }
}

Xây dựng một phương thức xử lý với nhiều kiểu dữ liệu khác nhau.

Ví dụ tạo class tên MaximumTest trong package generic

package generic;
/**
 *
 * @author giasutinhoc.vn
 */
public class MaximumTest {
 // determines the largest of three Comparable objects
 public > T maximum(T x, T y, T z) {
   T max = x; // assume x is initially the largest

   if (y.compareTo(max) > 0) {
     max = y; // y is the largest so far
   }

   if (z.compareTo(max) > 0) {
    max = z; // z is the largest now
   }

   return max; // returns the largest object
 }

 public static void main(String args[]) {
   // Create object
   MaximumTest mt = new MaximumTest();
   System.out.println("Max of 3, 4, 5 is " + mt.maximum(3, 4, 5));
   System.out.println("Maxm of 6.6, 8.8, 7.7 is " + mt.maximum(6.6, 8.8, 7.7));
   System.out.println("Max of pear, apple, orange is " + mt.maximum("pear", "apple", "orange"));
 }

Kết quả khi sau khi chạy là :

Max of 3, 4, 5 is 5
Max of 6.6, 8.8, 7.7 is 8.8
Max of pear, apple, orange is pear

Một số hạn chế của Generic

Không thể khởi tạo generic với tài liệu kiểu nguyên thủy

Pair p = new Pair<>(8, 'a'); //error
Pair p = new Pair<>(8, 'a');

Không thể tạo instance cho kiểu tài liệu

class Gen {
 T obj;

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

Không thể là static trong class

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

Không thể tạo mảng

Gen gens[] = new Gen[10]; //error
Gen gens[] = new Gen[10]; //ok
Gens[0] = new Gen(25);
Gens[1] = new Gen("Hello");

Không thể tạo class ngoại lệ là generic

Generic trong java – Bài tập thực hành

Bài thực hành số 1: Tạo class tên MyArrayList và thực hiện các công việc sau:

  • Thêm vào ArrayList một số nguyên
  • Thêm vào ArrayList một số thực
  • Thêm vào ArrayList một giá trị boolean
  • Thêm vào ArrayList một chuỗi
  • In ra màn hình 4 giá trị trên

Bài thực hành số 2: Tạo class tên MyGenericArrayList và thực hiện các công việc sau:

  • Tham số hoá dữ liệu cho ArrayList là Integer.
  • Sử dụng vòng lặp để nhập các số từ 1 đến 10 vào ArrayList.
  • In ra màn hình các giá trị trong ArrayList

Bài thực hành số 3: Tạo class tên Student có các thuộc tính như id, name, age. Viết các phương thức constructor, setter, getter, toString.

Bài thực hành số 4: Tạo class tên Employee có các thuộc tính như id, name, salary. Viết các phương thức constructor, setter, getter, toString.

Bài thực hành số 5: Tạo class PersonModel và thực hiện các công việc sau:

package generic;
import java.util.ArrayList;
/**
 *
 * @author giasutinhoc.vn
 */
public class PersonModel  {

  private ArrayList al = new ArrayList();

  public void add(T obj) {
   al.add(obj);
  }

  public void display() {
   for (T o : al) {
    System.out.println(o);
   }
  }

  public static void main(String[] args) {
   //Viết xử lý cho phương thức main
  }
}

Đoạn code cần viết thêm vào phương pháp main để thực thi những việc làm sau :

Tạo đối tượng PersonModel

  • Gọi phương thức add để nhập vào 2 sinh viên
  • Gọi phương thức display để hiển thị thông tin của 2 sinh viên vừa nhập

Tạo đối tượng PersonModel

  • Gọi phương thức add để nhập vào 2 nhân viên
  • Gọi phương thức display để hiển thị thông tin của 2 nhân viên vừa nhập

Tạo đối tượng PersonModel

  • Gọi phương thức add để nhập vào họ tên của 2 người.
  • Gọi phương thức display để hiển thị họ tên vừa nhập.