Generic trong java – Những điều cần biết
Generic trong Java là một tính năng cho phép sử dụng kiểu dữ liệu động được thông qua khi tạo đối tượng hoặc khai báo một lớp. Khi sử dụng Generic, ta có thể tái sử dụng và tối ưu hóa mã nguồn, đồng thời giảm thiểu lỗi do kiểu dữ liệu không chính xác hơn.
Vậy học về Generic như thế nào? Bắt đầu từ đâu? Tìm hiểu với chúng tôi thật chi tiết cùng R2S nhé!
Generic trong java là gì?
Trước khi học về những thao tác và cú pháp với Generic trong java, mời bạn hãy cùng với chúng tôi
Generics là thuật ngữ chỉ tham số hóa kiểu dữ liệu, rất quan trọng trong việc tạo ra và sử dụng class, interface và method với nhiều kiểu dữ liệu khác nhau. Khi một class, interface hoặc method được thực hiện trên một kiểu tham số cụ thể, ta gọi nó 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.
Một số ví dụ về Generic trong java
Dưới đây là một số ví dụ dễ hiểu nhất về Generic trong java mà bạn có thể tham khảo:
Ví dụ 1
- Đến mục package generic
- Tạo class tên SampleGeneric1
- Sử dụng ArrayList với các kiểu dữ liệu khác nhau
- Bạn sẽ nhận được:
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 – Generic trong java
- Sử dụng ArrayList với các kiểu dữ liệu Integer như sau:
- Đến mục package generic
- Tạo class tên SampleGeneric2
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<Integer> mylist = new ArrayList<Integer>();
// 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);
}
}
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 khác nhau theo sự lựa chọn của mình. Việc này giúp làm rõ nội dung và tạo sự dễ hiểu hơn cho đoạn code của chương trình.
Khái niệm Generic Methods – Generic trong java là gì?
Generic Methods trong Java là các phương thức có tham số kiểu dữ liệu chung hoặc có thể là kiểu dữ liệu chung cho kiểu trả về của phương thức.
Generic Methods sẽ cho phép người lập trình có thể sử dụng chung một phương thức để xử lý các kiểu dữ liệu khác nhau, giúp tối ưu hóa mã nguồn và tăng tính linh hoạt của chương trình.
Quy ước đặt tên tham số kiểu cho Generic trong Java
Ký tự viết tắt | Viết đầy đủ | Giải thích |
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ụ minh họa
Tạo class tên GenericMethodTest trong package generic như sau:
package generic;
/**
*
* @author giasutinhoc.vn
*/
public class GenericMethodTest {
// generic method printArray
public <T> 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
}
}
Khi bạn chạy chương trình sẽ cho kết quả như sau:
Generic Classes trong java là gì?
Generic Classes là các lớp được tham số hóa kiểu dữ liệu, cho phép sử dụng các kiểu dữ liệu khác nhau khi tạo đối tượng hoặc khai báo một lớp. Generic Classes sẽ giúp tối ưu hóa mã nguồn, giảm thiểu lỗi do kiểu dữ liệu không chính xác và tăng tính linh hoạt của chương trình.
Ví dụ tạo class tên Box trong package generic trong java
package generic;
/**
*
* @author giasutinhoc.vn
*/
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> intBox = new Box<Integer>();
Box<String> strBox = new Box<String>();
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 Generic trong java là:
Integer Value :10
String Value :Hello World
Các ký tự đại diện generic (Wildcards) cần biết
Ký tự đại diện <?>
Xét ví dụ sau:
private boolean checkEquals(RestricExample<T> 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;
}
Trả về phương thức checkEquals chỉ cho phép tham số e có cùng kiểu dữ liệu với biến number. Trong khi đó, phương thức checkEquals2 có thể chấp nhận tham số e là kiểu dữ liệu khác với biến number.
Sử dụng ký tự đại diện “<? extends type>” cho phép chấp nhận bất kỳ đối tượng nào kế thừa hoặc là đối tượng của type.
Ví dụ minh họa
public void processElement(List<? extends A> elements){
...
}
Trong đó:
Sử dụng phương thức processElement (Chấp nhận bất ký đối tượng nào miễn là đối tượng này phải kế thừa từ lớp A hoặc đối tượng của A => ClassA, ClassB và ClassC)
List<A> listA = new ArrayList<A>();
processElement(listA);
List<B> listB = new ArrayList<B>();
processElement(listB);
List<C> listC = new ArrayList<C>();
processElement(listC);
Ký tự đại diện <? super type> 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<? super A> elements){
...
}
List<A> listA = new ArrayList<A>();
processElement(listA);
List<Object> listO = new ArrayList<Object>();
processElement(listO);
Giới hạn kiểu dữ liệu với ký tự đại diện <? extends type> như thế nào?
Trong một số trường hợp, chúng ta muốn giới hạn kiểu dữ liệu được sử dụng cho các tham số.
Chẳng hạn, khi tạo phương thức chỉ chấp nhận tham số là số nguyên hoặc số thực. Điều này giúp tăng tính chính xác và đảm bảo rằng đầu vào chương trình được đúng và chính xác.
package generic;
/**
*
* @author giasutinhoc.vn
*/
public class RestricExample <T extends Number> {
private T number;
public RestricExample(T number) {
this.number = number;
}
public double reciprocal() {
return 1/number.doubleValue();
}
public static void main(String[] args) {
RestricExample<Integer> n1 = new RestricExample<Integer>(5);
System.out.println("Reciprocal: " + n1.reciprocal());
RestricExample<Double> n2 = new RestricExample<Double>(7.5);
System.out.println("Reciprocal: " + n2.reciprocal());
//error
//RestricExample<String> s1 = new RestricExample<String>("Hello");
}
}
Xây dựng một phương thức xử lý với nhiều kiểu dữ liệu đa dạng khác nhau.
Ví dụ tạo class tên MaximumTest trong package generic trong Java
package generic;
/**
*
* @author giasutinhoc.vn
*/
public class MaximumTest {
// determines the largest of three Comparable objects
public <T extends Comparable<T>> 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 như sau:
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
Generic sẽ có một số hạn chế như sau
Dữ liệu kiểu nguyên thủy không thể khởi tạo generic
Pair<int, char> p = new Pair<>(8, 'a'); //error
Pair<Integer, Character> p = new Pair<>(8, 'a');
Với kiểu dữ liệu không thể tạo instance
class Gen<T> {
T obj;
Gen() {
obj= new T(); //Illegal (error)
}
}
Không thể là static trong class
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;
}
}
Không thể tạo được mảng – Generic trong java
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");
Không thể tạo class ngoại lệ là generic
Bài tập thực hành với generic
Bài thực hành thứ nhất
Tạo class tên MyArrayList rồi thực hiện các công việc sau:
- Thêm một số nguyên
- Thêm một số thực
- Thêm một giá trị boolean
- Thêm một chuỗi
- In ra màn hình 4 giá trị trên
Bài thực hành thứ hai
Tạo class tên MyGenericArrayList và thực hiện các công việc sau:
- Tham số hoá dữ liệu về dạng nteger.
- 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ị vừa rồi
Kết luận
Các Generic trong Java là một tính năng quan trọng giúp tăng tính linh hoạt và tái sử dụng mã trong chương trình.
Việc sử dụng Generics cho phép chúng ta tạo ra các lớp hoặc phương thức có thể áp dụng cho nhiều kiểu dữ liệu khác nhau mà không cần viết lại nhiều mã. Do đó, hãy học cách sử dụng Generic trong java thật chăm chỉ nhé!
Bài viết gốc được đăng tại: giasutinhoc.vn