Category Archives: Java

Java 8 – Toán tử

Toán tử là các kí tự dùng để thao tác với các biến, có thể là một, hai hoặc ba biến.

Toán tử cũng có thứ tự, nếu trong một biểu thức có nhiều toán tử thì toán tử nào có thứ tự cao hơn thì sẽ được thực hiện trước.

Dưới đây là bảng các toán tử và thứ tự ưu tiên của chúng, từ trên xuống dưới và từ trái qua phải:

e++ e--
++e --e +e -e ~ !
* / %
+ -
<< >> >>>
< > <= >= instanceof
== !=
&
^
|
&&
||
? :
= += -= *= /= %= &= ^= |= <<= >>= >>>=

Toán tử gán

Toán tử gán làm nhiệm vụ gán giá trị cho biến, kí hiệu là dấu “=“.

int gear = 1;
int speed = 0;

Toán tử số học

Đây là các toán tử thực hiện các phép cộng, trừ, nhân, chia như trong toán học, khác ở chỗ là đối với phép chia số nguyên thì ở đây có 2 phép chia lấy phần nguyên và phép chia lấy phần dư chứ không tính thành số thực.

+ Cộng
Trừ
* Nhân
/ Chia lấy phần nguyên
% Chia lấy phần dư

Ví dụ:

int result = 1 + 2;  // = 3
result = 3 - 1;      // = 2
result = 2 * 2;      // = 4
result = 4 / 3;      // = 1
result = 10 % 7;     // = 3

Chúng ta có thể kết hợp với toán tử gán để hợp thành toán tử ghép như sau:

x += 1;    // Tương đương x = x + 1

Toán tử một toán hạng

Chúng là các toán tử chỉ làm việc với một biến duy nhất.

+ Chỉ định giá trị dương cho biến (tuy nhiên bình thường không có thì cũng là số dương)
Chỉ định giá trị âm cho biến
++ Tăng giá trị lên một đơn vị
Giảm giá trị đi một đơn vị
! Đảo ngược giá trị của biến boolean

Ví dụ:

int result = +1;    // result = 1
result--;           // result = 0
result++;           // result = 1
result = -result;   // result = -1

boolean successs = false;    // success = false
success = !success;          // success = true

Toán tử ++-- có thể viết trước hoặc sau biến, ví dụ ++result, result++, cả 2 cách đều cho ra giá trị giống nhau, sự khác nhau là ++result sẽ tăng giá trị của result lên n rồi trả về n, còn result++ sẽ tăng result lên n rồi trả về n - 1.

Toán tử quan hệ

Các toán tử này xác định xem một toán hạng lớn hơn, bé hơn, khác hay bằng một toán tử khác, kết quả là một giá trị boolean (true hoặc false), kí hiệu của chúng cũng rất dễ nhận biết.

== Bằng
!= Không bằng
> Lớn hơn
>= Lớn hơn hoặc bằng
< Bé hơn
<= Bé hơn hoặc bằng

Ví dụ:

int value1 = 1;
int value2 = 2;
boolean check = value1 == value2;    // check = false
check = value1 != value2;            // check = true
check = value1 < value2;             // check = true
check = value1 > value2;             // check = false

Toán tử điều kiện

Toán tử điều kiện gồm có 2 toán tử là &&||. Chúng thực hiện điều kiện ANDOR và trả về kết quả là một giá trị boolean. Đây là các toán tử 2 toán hạng và các toán hạng được đánh giá từ trái sang phải.

Ví dụ:

int value1 = 1;
int value2 = 2;
if((value1 == 1) && (value2 == 2))
    System.out.println("value1 = 1 and value2 = 2");
if((value1 == 1) || (value2 == 1))
    System.out.println("value1 = 1 OR value2 = 1");

Ngoài ra còn có một toán tử khác nữa là ?:, đây là toán tử thực hiện câu lệnh if-else (chúng ta sẽ tìm hiểu sau), toán tử này thao tác với 3 toán hạng. Cú pháp là x ? y : z, ý nghĩa là nếu x = true thì trả về y, ngược lại trả về z.

Ví dụ:

int value1 = 1;
int value2 = 2;
int result;
boolean condition = true;
result = condition ? value1 : value2;    // result = value1

Toán tử instanceof

Toán tử instanceof so sánh toán hạng với một kiểu dữ liệu nào đó để kiểm tra xem toán hạng đó có phải mang kiểu dữ liệu đó hay không. Chúng ta sẽ không đi sâu vào toán tử này ở đây.

Toán tử thao tác bit

Đây là các toán tử dùng để dịch chuyển hoặc đảo ngược các bit của các giá trị số nguyên và số thực.

~ Đảo ngược các bit của một số
<< Dịch các bit của một số về bên trái một lần
>>  Dịch các bit của một số về bên phải một lần
& Thực hiện phép toán AND
^ Thực hiện phép toán XOR
| Thực hiện phép toán OR

Ví dụ:

int eight = 8;    
eight = ~eight;   // eight = 7, vì 8 trong hệ nhị phân là 1000, 
                  // đảo ngược thành 0111 tức là 7 trong hệ thập phân
int val = 8 & 4;  // val = 0, vì 8 = 1000, 4 = 0100, 
                  // 1000 & 0100 = 0000 tức là 0 trong hệ 10

Java 8 – Mảng

Mảng là một kiểu dữ liệu dùng để lưu trữ danh sách các đối tượng có kiểu dữ liệu khác. Số lượng các phần tử trong mảng là cố định.

Trong các bài trước chúng ta đã làm gặp mảng rồi, đó là tham số args trong phương thức main().

Mỗi thành phần trong mảng được gọi là một phần tử (element), mỗi phần tử sẽ được đánh số thứ tự, bắt đầu từ 0, chúng ta gọi đó là chỉ số (index) của phẩn tử, các phần tử sẽ được đọc thông qua chỉ số đó.

Trong hình trên mô phỏng một mảng có 10 phần tử, phần tử đầu tiên có chỉ số là 0 và phần tử cuối cùng là 9.

Trong Java thì chúng ta khai báo một mảng theo cú pháp:

<kiểu_dữ_liêu>[] <tên_mảng> = new <kiểu_dữ_liệu>[<độ_dài_mảng>];

Chúng ta đọc và ghi các phần tử mảng bằng cách sử dụng cặp dấu ngoặc vuông [].

Ví dụ đoạn code dưới đây sẽ tạo một mảng lưu trữ các số nguyên int và in giá trị đó ra màn hình:

class ArrayExample {
    public static void main(String[] args) {
        int[] array = new int[10];
        array[0] = 100;
        array[1] = 200;
        array[2] = 300;
        array[3] = 400;
        array[4] = 500;
        array[5] = 600;
        array[6] = 700;
        array[7] = 800;
        array[8] = 900;
        array[9] = 1000;

        System.out.println("Element 0: " + array[0]);
        System.out.println("Element 1: " + array[1]);
        System.out.println("Element 2: " + array[2]);
        System.out.println("Element 3: " + array[3]);
        System.out.println("Element 4: " + array[4]);
        System.out.println("Element 5: " + array[5]);
        System.out.println("Element 6: " + array[6]);
        System.out.println("Element 7: " + array[7]);
        System.out.println("Element 8: " + array[8]);
        System.out.println("Element 9: " + array[9]);
    }
}

Dịch và chạy ra được kết quả:

Element 0: 100
Element 1: 200
Element 2: 300
Element 3: 400
Element 4: 500
Element 5: 600
Element 6: 700
Element 7: 800
Element 8: 900
Element 9: 1000

Trong thực tế thì khi thao tác với mảng chúng ta sẽ dùng với câu lệnh lặp cho nhanh vì số lượng phần tử trong mảng có thể lên tới hàng ngàn. Chúng ta sẽ tìm hiểu câu lệnh lặp sau.

Tương tự với int, chúng ta có thể tạo mảng cho các kiểu dữ liệu khác:

byte[] byteArray;
short[] shortArray;
long[] longArray;
float[] floatArray;
double[] doubleArray;
boolean[] booleanArray;
char[] charArray;
String[] stringArray;

Cặp dấu ngoặc vuông có thể được đặt phía sau tên mảng thay vì đặt sau tên kiểu dữ liệu:

int intArray[];

Khởi tạo mảng

Trong đoạn code trên chúng ta tạo mảng bằng cách dùng toán tử new, khi sử dụng toán tử này thì chúng ta phải khai báo thêm số lượng phần tử trong mảng luôn:

int[] array = new int[10];

Tiếp theo là các dòng gán giá trị cho các phần tử:

array[0] = 100;

array[1] = 200;

Thay vào đó, chúng ta có cú pháp tạo và gán giá trị nhanh như sau:

int[] array = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };

Dùng cú pháp này chúng ta không cần phải khai ra số lượng phần tử mảng, Java sẽ tự biết số lượng thông qua các giá trị chúng ta đưa vào trong cặp dấu ngoặc nhọn {}.

Các phần tử trong một mảng ngoài chứa các giá trị như int, float, double…v.v thì chúng còn có thể là một mảng khác, mảng như thế được gọi là mảng đa chiều (multidimensional array).

Để khai báo mảng đa chiều thì chúng ta chỉ cần ghi thêm các cặp dấu ngoặc vuông, chẳng hạn [][], [][][]…v.v 2 cặp dấu ngoặc vuông được gọi là mảng 2 chiều, 3 cặp thì là 3 chiều…v.v

Ví dụ:

class MultiDArray {
    public static void main(String[] args) {
        String[][] languages = {
            {"C++", "Java"},
            {"Python", "Ruby"}   
        };
     
        System.out.println(names[0][0] + " and " + [0][1]);
        System.out.println(names[1][0] + " and " + [1][1]);
    }
}

Chúng ta truy xuất các phần tử cũng thông qua các cặp dấu ngoặc vuông [] và chỉ số tương ứng.

C++ and Java
Python and Ruby

Mảng là một đối tượng và có thuộc tính length lưu trữ số lượng các phần tử để chúng ta có thể sử dụng:

class ArrayLength {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4};
        System.out.println("Array length: " + array.length);
    }
}
4

Sao chép mảng

Lớp System có một phương thức tên là arraycopy() cho phép chúng ta sao chép một mảng sang một mảng khác một cách dễ dàng:

public static void arraycopy(Object src, int srcPos, Object dest, int desPos, int length)

Tham số đầu tiên là mảng nguồn, tham số thứ 2 là vị trí của phần tử đầu tiên được sao chép, tham số thứ 3 là mảng đích, tham số thứ 4 là phần tử đầu tiên trong mảng đích được sao chép, tham số thứ 5 là số lượng các phần tử được sao chép. Ví dụ:

class CopyArrray {
    public static void main(String[] args) {
        char[] from = { 
            'd', 'e', 'c', 'a', 'f', 'f', 
            'e', 'i', 'n', 'a', 't', 'e', 'd'
        };
        char[] to = new char[7];

        System.arraycopy(from, 2, to, 0, 7);
        System.out.println(new String(to));
    }
}
caffein

Một số thao tác trên mảng

Mảng là một kiểu dữ liệu quan trọng, do đó trong Java có một lớp có tên là java.util.Arrays chứa rất nhiều phương thức giúp chúng ta thực hiện các thao tác thường dùng trên mảng một cách dễ dàng.

Số lượng phương thức trong phiên bản Java 8 rất lớn, ở đây chỉ ví dụ một số phương thức:

class ArrayMani {
    public static void main(String[] args) {
        int[] binSearch = {
            1, 3, 15, 29, 40,
            83, 105, 189, 314
        }; 
        int found40 = java.util.Arrays.binarySearch(binSearch, 40);
        System.out.println("40 appears at index " + found40);
 
        char[] arr1 = { 'p', 'h', 'o' };
        char[] arr2 = { 'p', 'h', 'i' };
        boolean same = java.util.Arrays.equals(arr1, arr2);
        if(same == true)
            System.out.println("arr1 and arr2 are the same");
        else 
            System.out.println("arr1 and arr2 are different"); 
 
        int[] intArray = new int[2];
        java.util.Arrays.fill(intArray, 2017);
        System.out.println(intArray[0]);
        System.out.println(intArray[1]);
 
        int[] forSort = { 19, 2, 5, 80, -36 };
        java.util.Arrays.parallelSort(forSort);
        System.out.println(forSort[0]);
        System.out.println(forSort[1]);
        System.out.println(forSort[2]);
        System.out.println(forSort[3]);
        System.out.println(forSort[4]);
   }
}

Trong đoạn code trên chúng ta sử dụng 4 phương thức trong lớp java.util.Arrays là:

  • binarySearch(): phương thức này nhận vào một mảng số đã được sắp xếp theo thứ tự từ bé đến lớn, và một giá trị, phương thức này sẽ trả về vị trí của giá trị đó trong mảng nếu có bằng thuật toán tìm kiếm nhị phân (Binary Search)
  • equals(): phương thức này nhận vào 2 mảng và kiểm tra xem 2 mảng này có giống nhau không, nếu giống thì trả về true, khác thì false.
  • fill(): phương thức này nhận vào một mảng, một giá trị và sẽ gán toàn bộ phần tử trong mảng có giá trị đó
  • parallelSort(): phương thức này sẽ nhận vào một mảng và sắp xếp mảng đó theo thuật toán sắp xếp song song (Parallel Sort), đây là phương thức mới của phiên bản Java 8.
40 appears at index 4
arr1 and arr2 are different
2017
2017
-36
2
5
19
80

Java 8 – Kiểu dữ liệu

Trong phần này chúng ta sẽ tìm hiểu về các kiểu dữ liệu cơ bản.

Kiểu dữ liệu là các từ khóa trong Java dùng để chỉ ra loại giá trị của biến.

Java là một ngôn ngữ rất nặng về kiểu dữ liệu, nghĩa là chúng ta phải khai báo rõ kiểu dữ liệu cho biến trước khi thực hiện các thao tác trên biến:

int gear = 1;

Dòng code trên báo cho chương trình biết là có một trường tên là gear, lưu trữ dữ liệu dạng số, và có giá trị ban đầu là “1”. Kiểu dữ liệu của biến sẽ quyết định những giá trị mà biến đó được nhận. Ngoài int ra thì Java còn có 7 kiểu dữ liệu cơ bản khác, tức là có tổng cộng 8 kiểu dữ liệu như sau:

KIỂU DỮ LIỆU
GHI CHÚ
GIÁ TRỊ
 GIÁ TRỊ MẶC ĐỊNH
byte Số nguyên 8 bít -128 → 127 0
short Số nguyên 16 bit -32768 → 32767 0
int Số nguyên 32 bit -2147483648 → 2147483647 0
long Số nguyên 64 bit -2^63 → 2^63 – 1 0L
float Số thực 32 bit 2^-149 → (2-2^(-23))*2^127 0.0f
double Số thực 64 bit 2^(-1074) → (2-2^(-52))*2^1023   0.0d
boolean Kiểu luận lý TRUE / FALSE ‘\u0000’ (hay kí tự số ‘0’)
char Kiểu kí tự Unicode 16 bit false

Giá trị là các ký tự được gán cho các biến có kiểu dữ liệu cơ bản, chúng ta không dùng toán tử new.

Số nguyên

Số nguyên kiểu long (64 bit) được ghi kèm theo kí tự 'L' hoặc 'l' sau cùng, nếu không Java sẽ hiểu đó là số nguyên int (32 bit).

Chúng ta có thể sử dụng 3 hệ số cho số nguyên là hệ 16 (thập lục phân), hệ 2 (nhị phân) và hệ 10 (thập phân).

  • Hệ 16: sử dụng các kí tự từ 0-9 và từ A-F. Khi khai báo thì chúng ta thêm 2 kí tự '0x' vào trước số.
  • Hệ 12: chỉ sử dụng 2 kí tự 0 hoặc 1. Khi khai báo thì chúng ta thêm 2 kí tự '0b' vào trước số.
  • Hệ 10: sử dụng các số từ 0 đến 9.

Ví dụ:

int hexa = 0x1A;        // Hệ 16
int bin  = 0b110110;    // Hệ 2
int dec  = 26;          // Hệ 10

Số thực

Số thực được biểu diễn bằng phần thập phân và phần thực, ngăn cách nhau bởi dấu chấm '.'. Có thể thêm kí tự 'F' hoặc 'f' sau cùng để chỉ rõ kiểu dữ liệu là float, kí tự 'D' hoặc 'd' để chỉ rõ kiểu kí tự là double, nếu không thì Java sẽ hiểu là dùng kiểu float.

Ngoài ra chúng ta còn có thể kết thúc bằng cú pháp e<x>, trong đó x là một số nguyên, để biểu diễn phần lũy thừa của 10.

Ví dụ:

double d1 = 123.4;
double d2 = 1.234e2;    // Tương đương 1.234 x 10^2 = 123.4
float  d3 = 123.4f;

Kiểu ký tự

Giá trị của ký tự có thể chứa cả kí tự Unicode nếu hệ điều hành và phần mềm bạn dùng để viết code có hỗ trợ Unicode. Nếu không thì chúng ta có thể dùng mã Unicode để biểu diễn kí tự Unicode, ví dụ '\u0108' là kí tự 'C'. Kiểu kí tự được bọc trong cặp dấu nháy đơn.

Ngoài các kí tự có thể nhìn thấy, chúng ta còn có một số mã dùng để biểu diễn các kí tự điều khiển là:

  • \b : nút Backspace
  • \t : nút Tab
  • \n : xuống dòng
  • \r : nút Enter

Ngoài ra còn một giá trị đặc biệt nữa là null, biến có giá trị null mang ý nghĩa là biến này không có giá trị gì cả.

Phân nhóm giá trị số

Kể từ Java 7 trở đi, chúng ta có thể sử dụng dấu gạch dưới '_' để phân nhóm các số cho dễ đọc.

long ATM = 1234_5678_9012_3456;
long CMND = 2255_111_11L;
float PI = 3.14_15F;
long MAC_ADDRESS = 0xFF_EC_DE_5E_AA_6E_0F_43;
long binary = 0b1101_0011_1000_0100;

Lưu ý:

  • Chỉ để dấu gạch dưới giữa các con số, không phải ở đầu hoặc cuối số.
  • Dấu gạch dưới phải nằm cạnh một chữ số trong số thực
  • Dấu gạch dưới phải nằm trước kí tự 'F' hoặc 'L'

String

Ngoài 8 kiểu dữ liệu cơ bản trên thì Java còn hỗ trợ một kiểu đặc biệt dùng để lưu trữ chuỗi kí tự là lớp java.lang.String. Kiểu này bọc các chuỗi trong cặp dấu nháy kép '"'. Ví dụ:

String s = "Pho Code";

Giá trị mặc định của Stringnull.

Giá trị của String là không thể thay đổi, bạn chỉ có thể thay đổi tham chiếu của biến thôi. Ví dụ:

String s1 = "C++";
String s2 = s1;

System.out.println(s2);    // s2 có giá trị là 'C++'

s1 = "Java";
System.out.println(s2);    // s2 vẫn có giá trị là 'C++'

Chúng ta sẽ tìm hiểu thêm về tham chiếu sau.

Java 8 – Biến

 

Biến là các đối tương dùng để lưu trữ dữ liệu, trong Java thì chúng còn được gọi là trường hoặc thuộc tính.

public class Bicycle {
    int gear = 1;
    int speed = 0;
}

Trong đoạn code trên thì gearspeed là các biến, có kiểu dữ liệu là int, chúng ta sẽ tìm hiểu về kiểu dữ liệu sau.

Trong Java có 4 loại biến:

  • Biến đối tượng: đây là biến động, tức là mỗi biến trong mỗi đối tượng sẽ khác nhau, chẳng hạn như biến speed trong 2 đối tượng Bicycle sẽ có giá trị khác nhau.
  • Biến lớp: hay còn gọi là biến tĩnh – static, giá trị của biến này trong các đối tượng cùng lớp là giống nhau. Để khai báo biến tĩnh thì chúng ta thêm từ khóa static vào trước tên kiểu dữ liệu, ví dụ static int gears = 6.
  • Biến cục bộ: biến cục bộ là các biến được khai báo trong một phạm vi nào đó, về cơ bản thì chúng không khác gì biến đối tượng bình thường, và cũng không cần một từ khóa thêm nào. Biến cục bộ chỉ đơn giản là nằm giữa một cặp dấu ngoặc nhọn {} nào đó, và chúng ta chỉ có thể làm việc với chúng trong cặp dấu ngoặc nhọn đó.
  • Biến tham số: trong các bài trước chúng ta đã thấy dòng code public static void main(String[] args), trong đó args chính là một biến tham số, biến tham số là các dữ liệu được truyền vào một phương thức, và chỉ có thể được đọc hoặc ghi trong phương thức đó.

Đặt tên biến

Ứng với mỗi ngôn ngữ lập trình thì lại có những quy tắc đặt tên biến khác nhau mà chúng ta phải tuân theo:

  • Tên biến trong Java là có phân biệt HOA-thường, tức là ageAge là 2 biến khác nhau.
  • Kí tự đầu tiên của tên biến có thể là các kí tự Latin (A-Z, a-z),  dấu '$' hoặc dấu gạch dưới '_'. Không được sử dụng dấu cách.
  • Các kí tự tiếp theo có thể là các kí tự Latin (A-Z, a-z), kí tự số (0-9), dấu '$' và dấu gạch dưới '_'.
  • Thông thường nếu tên biến là một từ có nghĩa thì chúng ta ghi từ đó viết thường, còn nếu có 2 từ trở lên thì kí tự đầu tiên của từ thứ 2 trở đi nên được viết HOA. Ví dụ age, fullName, dateOfBirth.
  • Không được phép đặt tên biến trùng với các từ khóa có sẵn trong Java.

Dưới đây là danh sách các từ khóa có sẵn trong Java:

abstract    continue    for           new          switch
assert      default     goto          package      synchronized
boolean     do          if            private      this
break       double      implements    protected    throw
byte        else        import        public       throws
case        enum        instanceof    return       transient
catch       extends     int           short        try
char        final       interface     static       void
class       finally     long          strictfp     volatile
const       float       native        super        while

Ví dụ dưới đây là các biến hợp lệ:

int age;
int $hairColor;
String _name;
int subject1;

Và đây là các biến không hợp lệ:

int try;             // Trùng với từ khóa try
int 1year;           // Bắt đầu bằng chữ số
String your name;    // Có khoảng trắng

Java 8 – Hướng đối tượng – Phần 2

Trong phần này chúng ta tiếp tục tìm hiểu về các đặc điểm của lập trình hướng đối tượng.

Thừa kế – Inheritance

Trong thế giới thực, có nhiều đối tượng khác nhau nhưng có chung một số đặc điểm nào đó. Chẳng hạn như xe đạp thì có nhiều loại như xe đạp leo núi, xe đạp đi đường, xe đạp đôi…v.v

Cho dù là loại nào thì chúng cũng có chung các đặc điểm như vận tốc, loại tay lái… và tùy loại xe mà sẽ có thêm các đặc điểm riêng biệt khác nhau, chẳng hạn như xe đạp đôi xe có 2 ghế ngồi và 2 tay lái, xe đạp leo núi có nhiều dây chuyền hơn…v.v

Lập trình hướng đối tượng cho phép chúng ta thực hiện việc kế thừa các thuộc tính và phương thức giữa các lớp. Chẳng hạn như lớp Bicycle (xe đạp) sẽ có lớp kế thừa là MountainBike (xe đạp leo núi), RoadBike (xe đạp đi đường) và CoupleBike (xe đạp đôi). Trong Java thì mỗi lớp chỉ có một lớp cha, tức là chỉ kế thừa từ một lớp, và có thể có nhiều lớp con, tức là nhiều lớp kế thừa từ nó.

Cú pháp kế thừa lớp trong Java rất đơn giản, chúng ta ghi từ khóa extends và tên lớp cha sau lớp con là được. Ví dụ:

class Bicycle {

}

class MountainBike extends Bicycle {

}

class RoadBike extends Bicycle {

}

class CoupleBike extends Bicycle {

}

Tất cả các lớp con là MountainBike, RoadBikeCoupleBike sẽ có các thuộc tính và phương thức giống với thuộc tính của lớp cha là Bicycle, bây giờ coder chỉ cần tập trung vào việc khai báo các thuộc tính và phương thức riêng của mỗi lớp con chứ không cần phải khai báo các thuộc tính và phương thức cũ lại từ đầu.

Giao diện – Interface

Giao diện ở đây không phải là giao diện màn hình, giao diện đồ họa hay bất cứ thứ gì liên quan tới hình họa như nút bấm, nhãn, textbox..v.v.

Chúng ta đã biết là các đối tượng sẽ tương tác với thế giới bên ngoài thông qua phương thức, thế giới bên ngoài sẽ gọi phương thức của đối tượng là giao diện, ý nghĩa của từ giao diện là một cái gì đó thực hiện một chức năng gì đó mà không biết nó thực hiện như thế nào.

Chẳng hạn như cái TV có nút bấm dùng để chuyển kênh, người dùng chỉ biết là nút đó dùng để chuyển kênh chứ không biết nó làm những gì để chuyển kênh được.

Trong Java thì giao diện là một tập hợp các phương thức nhưng không có phần thân {}, các lớp có thể khác cài đặt (implement) các phương thức này. Để khai báo một giao diện thì chúng ta dùng từ khóa interface, theo sau là tên giao diện, bên trong là tập hợp các tên phương thức, ví dụ:

interface Bicycle {
    void changeGear(int newGear);
    void speedUp(int value);
}

Các lớp khác có thể code giao diện này, tức là code lại các phương thức có trong giao diện, chúng ta dùng từ khóa implements sau tên lớp, rồi ghi tên giao diện cần cài đặt. Ví dụ:

class RoadBike implements Bicycle {
    int gear = 1;
    int speed = 0;

    void changeGear(int newGear) {
        gear = newGear;
    }

    void speedUp(int value) {
        speed = speed + value;
    }
}

class MountainBike implements Bicycle {
    int gear = 1;
    int speed = 0;

    void changeGear(int newGear) {
        gear = newGear;
    }

    void speedUp(int value) {
        speed = speed + value * 10;
    }
}

Một lớp code lại một giao diện cho phép lớp đó trở nên “chính thức” hơn, bởi vì chúng ta có thể có nhiều lớp cùng code lại một giao diện, nhưng các lớp khác nhau sẽ code lại các phương thức trong giao diện một cách khác nhau tùy vào mục đích của từng lớp, do đó khi nhìn tên lớp thì chúng ta có thể hình dùng là lớp đó code các phương thức như thế nào, và dùng lớp thích hợp.

Ví dụ như trong đoạn code trên, chúng ta cho phương thức speedUp() của lớp MountainBike tính ra giá trị cao hơn so với phương thức speedUp() của lớp RoadBike, khi người khác dùng thì cũng sẽ luôn nghĩ là lớp MountainBike sẽ có speed cao hơn lớp RoadBike, và họ sẽ dùng lớp tương ứng tùy mục đích của họ.

Khi code lại một giao diện thì phải code toàn bộ phương thức có trong giao diện.

Gói – Package

Gói ở đây là một cái tên dùng để gom nhóm các lớp và giao diện có liên quan với nhau lại. Bạn có thể nghĩ gói cũng giống như một cái thư mục trên máy tính vậy, chẳng hạn như trong làm web, các file HTML nằm chung một thư mục, các file ảnh nằm chung một thư mục…v.v

Trong Java cũng thế, sẽ có lúc số lượng các lớp lên tới hàng trăm, hàng ngàn, và tốt nhất là nên gom những thứ có liên quan với nhau lại cho đễ quản lý.

Chúng ta sẽ tìm hiểu thêm sau.

Java 8 – Hướng đối tượng – Phần 1

Nếu bạn chưa biết về lập trình hướng đối tượng (Object Oriented Programming – OOP) thì bạn nên tìm hiểu trước khi học Java, vì Java là một ngôn ngữ rất nặng về hướng đối tượng.

Đối tượng – Object

Đối tượng là khái niệm cốt lõi trong công nghệ hướng đối tượng. Thế giới xung quanh chúng ta tràn ngập các đối tượng: con chó, cái bàn, tivi, xe đạp…

Trong một đối tượng có 2 thành phần chính là trạng thái (state)hành vi (behavior). 

Trạng thái là các thông tin, đặc điểm của đối tượng, chẳng hạn như con chó thì có tên, màu sắc, giống loài…, xe đạp thì có loại bánh xe, loại tay cầm, tốc độ hiện tại…v.v

Hành vi là các hoạt động của đối tượng, chẳng hạn như con chó thì vẫy đuôi, sủa…, xe đạp thì có thể tăng tốc, thắng, quẹo trái phải…v.v

Để có thể thiết kế các trạng thái và hành vi của đối tượng và viết thành code thì bạn cần trả lời 2 câu hỏi, “Đối tượng này có thể có các trạng thái gì?” và “Đối tượng này có thể thực hiện những gì?”. Đôi khi trong quá trình quan sát, bạn có thể nhận thấy cấu trúc của các đối tượng có sự phức tạp rất khác nhau, chẳng hạn như cái đèn thì chỉ có 2 trạng thái là mở và tắt, 2 hành vi là bật đèn và tắt đèn, trong khi cái đài radio thì lại có thể có các trạng thái như mở, tắt, âm lượng, kênh…v.v và các hành vi là mở đài, tắt đài, tăng âm lượng, giảm âm lượng, tìm kiếm, dò sóng…v.v Đôi khi các trạng thái và hành vi này nhiều và phức tạp đến nỗi bạn có thể chuyển nó thành một đối tượng khác, tức là bây giờ đối tượng này chứa một đối tượng khác.

Đối tượng trong lập trình cũng được thiết kế giống với đối tượng ngoài đời thật, nhưng thay vì gọi 2 thành phần là trạng tháihành vi, thì chúng ta gọi là trường (field) hoặc thuộc tính, biến trong một số ngôn ngữ khác, và phương thức (method) hoặc hàm trong một số ngôn ngữ khác. Phương thức làm công việc tính toán, thay đổi giá trị của các trạng thái, trao đổi thông tin với các đối tượng khác.

Một đặc điểm của lập trình hướng đối tượng là che giấu thông tin, các thông tin về trường/thuộc tính của đối tượng chỉ có thể được biết thông qua việc gọi phương thức/hàm chứ không thể được đọc một cách trực tiếp. Tính năng này cho phép chúng ta bảo vệ dữ liệu của các đối tượng, không để chúng bị điều khiển một cách vô trật tự.

Ví dụ như chúng ta có đối tượng xe đạp có thuộc tính tốc độ, thì khi muốn tăng tốc cho giá trị này, chúng ta sẽ gọi phương thức để tăng tốc, thay vì gán giá trị trực tiếp cho thuộc tính này, phương thức sẽ nhận vào giá trị cần tăng tốc và kiểm tra xem giá trị này có phù hợp (lớn hơn 0, không được vượt quá 50 kmh chẳng hạn) hay không rồi mới gán cho thuộc tính, chứ các đối tượng bên ngoài không trực tiếp thao tác với thuộc tính đó.

Việc gom nhóm code thành các đối tượng có một số lợi ích như sau:

  • Tính module hóa: việc phân nhóm các thuộc tính và các phương thức tương tự nhau vào một đối tượng đã vận dụng phương pháp chia-để-trị một cách triệt để, giúp quản lý thông tin dễ dàng hơn.
  • Che giấu thông tin: thông tin của các đối tượng chỉ có thể được đọc/ghi thông qua phương thức chứ không được thao tác một cách trực tiếp, như thế dữ liệu sẽ không bị sửa chữa một cách bừa bãi, vô tổ chức.
  • Tái sử dụng code: một đối tượng được tạo ra thì có thể sử dụng trong các chương trình khác, giúp việc kiểm tra, phát triển một cách dễ dàng.
  • Dễ kiểm tra: nếu chẳng may chương trình bị lỗi, và một đối tượng nào đó có thể là nguyên nhân gây lỗi thì chúng ta chỉ cần xóa đối tượng đó ra và thay bằng một đối tượng mới.

Lớp – Class

Trong thế giới thực thì bạn sẽ thấy nhiều đối tượng giống nhau, chẳng hạn như có hàng ngàn chiếc xe đạp cùng tồn tại, cùng mẫu mã, cùng được sản xuất theo một quy trình và bản thiết kế như nhau, cùng có các bộ phận giống nhau.

Trong lập trình hướng đối tượng thì chúng ta gọi mỗi chiếc xe đạp là một thực thể của một lớp có tên là “Lớp xe đạp”.

Tóm lại một “lớp” có thể hiểu là một bản thiết kế của các đối tượng cụ thể nào đó.

Dưới đây là một đoạn code khai báo lớp Bicycle (xe đạp) tượng trưng trong Java:

class Bicycle {
    int speed = 0;
    int gear = 1;
   
    void changeGear(int newGear) {
        gear = newGear;
    }

    void speedUp(int value) {
        speed = speed + value;
    }
}

Chúng ta sẽ tìm hiểu chi tiết về đoạn code sau. Nếu bạn đã từng lập trình trước đây rồi thì bạn có thể đoán trong đoạn code trên gearspeed là các thuộc tính/trường, changeGear()speedUp() là các phương thức/hàm.

Trong đoạn code trên thì chúng ta không có phương thức main(), bởi vì đây chỉ là bản thiết kế lớp xe đạp để được sử dụng ở nơi khác.

Chẳng hạn như chúng ta có lớp Demo như sau:

class Demo {
    public static void main(String[] args) {
        Bicycle bike1 = new Bicycle();
        Bicycle bike2 = new Bicycle();

        bike1.speedUp(10);
        bike2.changeGear(2);
    }
}

Chúng ta sẽ tìm hiểu kỹ hơn về code sau. Nếu bạn đã từng lập trình rồi thì có thể biết trong đoạn code trên chúng ta tạo ra 2 đối tượng Bicyclebike1bike2, sau đó gọi phương thức speedUp() cho bike1changeGear() cho bike2. Chúng ta không thay đổi giá trị cho các thuộc tính một cách trực tiếp, chẳng hạn như không dùng các câu lệnh như bike1.speed = 10 hay đại loại như thế.

Java 8 – Hello World

Trong bài trước chúng ta đã viết đoạn code in dòng chữ “Hello World”, bây giờ chúng ta sẽ tìm hiểu đoạn code đó:

/*
 *    Class Example
 */
public class Example {
    public static void main(String[] args) {
        System.out.println("Hello World!");     // Print the string
    }
}

Trong đoạn code trên có 3 phần, phần comment (bình luận), phần định nghĩa lớp Example và cuối cùng là phương thức main().

Comment – Bình luận

Bình luận là những đoạn văn được biết phía sau dấu // hoặc nằm giữa cặp dấu /* */, trong đoạn code trên thì

/*
 *    Class Example
 */

//    Print the string

là các dòng bình luận. Các đoạn bình luận sẽ không được biên dịch bởi trình biên dịch, đây chỉ là các câu văn dùng để ghi chú thích cho người viết code đọc thôi.

Trong Java thì ngoài 2 cú pháp bình luận trên, còn có một cú pháp nữa là ghi giữa cặp dấu /** */. Ví dụ:

/** 
 *    Class Example
 */

Cú pháp này sẽ hỗ trợ công cụ javadoc tạo tài liệu cho đoạn code, nhưng chúng ta sẽ không tìm hiểu ở đây.

Định nghĩa lớp

Lớp là khái niệm trong lập trình hướng đối tượng, chúng ta sẽ tìm hiểu sau.

Trong đoạn code Hello World ở trên thì phần định nghĩa lớp là:

public class Example {

}

Cú pháp chung cho phần định nghĩa lớp là:

class <tên_lớp> {

}

Sau từ khóa class là tên của lớp, tên này do chúng ta tự đặt, rồi tới dấu mở ngoặc nhọn {, tiếp theo là các đoạn code khai báo thuộc tính và phương thức, rồi tới dấu đóng ngoặc nhọn }. Chúng ta sẽ tìm hiểu thêm về lớp sau.

Phương thức main()

Phương thức main() là đoạn code sau:

public static void main(String[] args) {

}

Trong bất cứ một chương trình viết bằng Java nào cũng phải có một dòng khai báo phương thức main() tương tự như sau:

public static void main(String[] args)

Đầu tiên là từ khóa public, đây là từ khóa dùng để khai báo phạm vi hoạt động của phương thức, rồi tới từ khóa static cho biết phương thức này là phương thức tĩnh, hai từ khóa publicstatic có thể đổi chỗ cho nhau (public static hoặc static public), chúng ta sẽ tìm hiểu thêm về chúng sau.

Tiếp theo là từ khóa void, đây là một kiểu dữ liệu, rồi đến main là tên phương thức, chúng ta phải đặt tên chính xác là "main". Đoạn code nằm trong main sẽ được chạy đầu tiên khi chương trình chạy, đây là điểm mở đầu của chương trình.

Sau main là đoạn String[] args trong cặp dấu ngoặc tròn (). String[] là kiểu dữ liệu mảng chuỗi, chúng ta sẽ tìm hiểu sau, args là tên tham số được truyền vào khi chạy chương trình, chúng ta có thể đặt tên tham số khác args, nhưng thông thường thì chúng ta sẽ đặt là args hoặc argvĐây là cơ chế truyền thông tin vào chương trình khi chạy. Trong phần trước chúng ta đã chạy chương trình bằng lệnh:

java -cp . Example

Nếu muốn truyền thêm thông tin gì thì chúng ta ghi vào phía sau “Example”, chẳng hạn chúng ta muốn truyền thêm chuỗi happy vào thì gõ lệnh là:

java -cp . Example happy

Và chuỗi happy sẽ nằm trong mảng args. Trong đoạn code Hello World ở đầu bài thì chúng ta không quan tâm tới tham số args này mà chỉ có dòng lệnh:

System.out.println("Hello World");

Dòng lệnh trên sẽ gọi phương thức println() của lớp System và in dòng chữ Hello World lên bộ nhớ xuất, và màn hình Command Prompt sẽ hiển thị dòng chữ đó.

Java 8 – Cài đặt

Chúng ta có thể dịch và chạy code Java từ dòng lệnh hoặc dùng IDE đều được.

Sử dụng NetBeans IDE

Bạn lên trang web chính thức của Oracle và tải Java cùng với bộ phần mềm NetBeans tại địa đây:

http://www.oracle.com/technetwork/java/javase/downloads/index.html

Click vào nút Download phía trên dòng chữ NetBeans with JDK 8, click nút Accept License Agreement rồi click vào đường link phù hợp với hệ điều hành của mình để tải về.

Sau đó tiến hành cài đặt như bình thường.

Để tạo project mới thì chúng ta vào menu File → New Project…, chọn kiểu project là Java Application, sau đó bấm Next, tiếp theo chúng ta đặt tên project, chọn thư mục lưu trữ, mọi thứ khác giữ nguyên cũng được, rồi bấm Finish.

Ở trên mình tạo project có tên Example.

Nếu bạn giữ nguyên ô check Create Main Class thì NetBeans sẽ tự tạo cho chúng ta một file có tên Example.java, đây là file chứa code Java:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package example;

/**
 *
 * @author Gigabyte
 */
public class Example {

    /**
      * @param args the command line arguments
    */
    public static void main(String[] args) {
        // TODO code application logic here
    }
 
}

Chúng ta sẽ tìm hiểu đoạn code trên sau. Để dịch và chạy đoạn code trên thì chúng ta bấm nút F6 hoặc click chuột vào nút hình tam giác màu xanh lá cây.

Trong cửa sổ Output ở dưới có hiện ra dòng chữ BUILD SUCCESSFUL là đã biên dịch và chạy thành công.

Biên dịch từ dòng lệnh

Nếu máy tính của bạn “cùi” quá không chạy nổi NetBeans hoặc bạn muốn sử dụng dòng lệnh cho “cool”, hay vì một lý do gì đó…v.v thì bạn cũng bắt đầu bằng việc lên trang web chính thức của Oracle tải về trình biên dịch Java Platform (JDK) 8xxx thay vì tải bản NetBeans with JDK 8.

Bạn tải về và cài đặt như bình thường. Nếu bạn cài đặt trên Windows thì bạn phải thêm đường dẫn đến thư mục bin trong thư mục cài đặt Java vào biến môi trường Path, trên Windows 10 bạn có thể vào Computer → System Properties → Advanced system settings → Environment Variables….Trong hộp System variables bạn tìm biến Path, click Edit, click vào nút New và copy đường dẫn đến thư mục bin vào rồi click OK là xong.

Để kiểm tra thì bạn có thể mở Command Prompt (cmd) lên và gõ lệnh java -version để kiểm tra phiên bản Java cũng như kiểm tra xem chúng ta đã đưa đường dẫn đến thư mục bin vào biến Path hay chưa, nếu ra được tương tự như hình dưới đây là được.

Khi chạy bằng dòng lệnh thì chúng ta không có công cụ nào để tạo project cả, chúng ta chỉ đơn giản là tạo một thư mục với tên mà chúng ta muốn đặt thôi. Sau đó bên trong thư mục này chúng ta tạo file .java.

Chẳng hạn mình tạo một thư mục với tên Example trong ổ C: và tạo file Example.java trong thư mục này:

Chúng ta mở file này với các trình soạn thảo văn bản thông thường, ở đây mình dùng Notepad++, và viết đoạn code sau đây:

public class Example {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

Để dịch file Example.java, chúng ta mở Command Prompt lên, chuyển đến thư mục C:\Example (bằng lệnh cd) chúng ta gõ lệnh javac Example.java.

Chúng ta sẽ được file có tên Example.class trong thư mục Example

Khi có file .class là chúng ta có thể chạy được rồi, chúng ta chạy bằng cách gõ lệnh java -cp . Example. Tham số -cp là đường dẫn đến thư mục chứa file .class vừa được tạo ra, ở đây chúng ta đưa vào dấu chấm '.', tức là thư mục hiện tại trong Command Prompt, nếu thư mục hiện tại trong Command Prompt không phải là thư mục chứa file .class thì bạn phải ghi rõ ra đường dẫn đến thư mục đó.

Kết quả ra dòng chữ Hello World là được.

Java 8 – Giới thiệu

Java là tên của một ngôn ngữ lập trình và một nền tảng lập trình.

Ngôn ngữ lập trình Java

Ngôn ngữ lập trình Java là một ngôn ngữ cấp cao với các đặc tính sau:

  • Đơn giản
  • Hướng đối tượng
  • Phân tán
  • Đa luồng
  • Kiến trúc trung hòa
  • Hiệu suất cao
  • Mạnh mẽ
  • Bảo mật cao

File chứa code Java sẽ có phần mở rộng là .java, khi biên dịch bởi trình biên dịch javac thì các file này sẽ tạo ra các file cùng tên nhưng có phần mở rộng là .class. Khác với các ngôn ngữ như C++, Pascal là khi biên dịch thì ra được các file chứa code nhị phân của hệ điều hành, thì file .class của Java lại chứa mã bytecode, các đoạn code này sẽ được đọc bởi một phần mềm có tên là Máy ảo Java (Java Virtual Machine – Java VM). Chúng ta chỉ cần dùng chạy lệnh java là máy ảo Java sẽ được chạy và đọc code trong file .class.

Máy ảo Java là được viết cho rất nhiều hệ điều hành, từ Windows, Linux, Mac…v.v do đó khi chúng ta viết code trong file .java và dịch ra file .class, thì chỉ cần đem file .class đó lên máy nào có cài máy ảo Java là cũng có thể chạy được mà không cần phải biên dịch lại hay code lại cho phù hợp

Nền tảng lập trình Java

Nền tảng (tiếng Anh: platform) là một môi trường phần mềm hoặc phần cứng để các chương trình có thể chạy trên đó. Chẳng hạn như hệ điều hành Windows, Ubuntu, MacOS, iOS, Android chính là các nền tảng, máy ảo Java cũng là một nền tảng, máy chủ web Apache, NginX, IIS cũng là các nền tảng…v.v

Nền tảng Java bao gồm 2 phần:

  • Máy ảo Java
  • Các thư viện API

Máy ảo Java là một nền tảng để chạy các chương trình viết bằng Java và có mặt trên hầu hết các hệ điều hành và phần cứng phổ biến.

Các thư viện API là tập hợp các phần mềm đã được viết sẵn, chúng cung cấp rất nhiều công dụng hữu ích và được gom nhóm lại thành các thư viện dưới dạng lớp giao diện, rồi được đóng thành các gói, chúng ta sẽ tìm hiểu các khác niệm này sau.

Chính vì các chương trình Java không chạy trực tiếp trên hệ điều hành mà lại chạy trên máy ảo Java được cài trên hệ điều hành đó, nên đôi khi các chương trình này không chạy nhanh bằng các chương trình được viết bằng ngôn ngữ có thể chạy trực tiếp trên hệ điều hành. Tuy nhiên nền tảng Java luôn được phát triển để có thể bắt kịp tốc độ với code của hệ điều hành.

JNI – Reflection

Reflection hay Introspection là tính năng cho phép chúng ta “điều tra” xem đối tượng/lớp/biến…v.v gồm có những gì. Chẳng hạn như tìm hiểu xem một đối tượng đó gồm có những thuộc tính gì và phương thức gì.

Trong Java thì reflection được hỗ trợ rất đầy đủ trong gói java.lang.reflect, ngoài ra một số phương thức trong lớp java.lang.Objectjava.lang.Class cũng hỗ trợ reflection, chúng ta có thể gọi các lớp này ở native để thực hiện reflection cũng được, hoặc chúng ta có thể dùng một số hàm của JNI như:

  • jclass GetSuperclass(jclass cls): nhận vào một lớp, trả về lớp cha của lớp đó
  • jboolean IsAssignableFrom(jclass clsA, jclass clsB): nhận vào 2 lớp a, b trả về true hoặc false, cho biết lớp a có thể ép kiểu sang lớp b hay không
  • jclass GetObjectClass(jobject obj): chúng ta đã làm nhiều với hàm này rồi, hàm này nhận vào một đối tượng và trả về lớp của đối tượng đó
  • jboolean IsInstanceOf(jobject obj, jclass cls): nhận vào một đối tượng và một lớp, trả về true hoặc false cho biế đối tượng đó có phải sinh ra từ lớp đó hay không
  • jmethodID FromReflectedField(jobject method)chuyển một đối tượng java.lang.reflect.Method hoặc java.lang.reflect.Constructor sang một đối tượng jmethodID
  • jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic): chuyển một đối tượng jfieldID từ cls sang một đối tượng java.lang.reflect.Field, nếu trường đó là static thì isStatic là true, ngược lại là false
  • jmethodID FromReflectedMethod(jobject method): chuyển một đối tượng java.lang.reflect.Method hoặc java.lang.reflect.Constructor sang một đối tượng jmethodID
  • jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic): chuyển một đối tượng jmethodID kế thừa từ jclass sang một đối tượng java.lang.reflect.Method hoặc java.lang.reflect.Constructor, nếu phương thức là static thì isStatic là true, ngược lại là false