Java cơ bản
Cú pháp cơ bản
Khi nói về một chương trình Java, do đây là một ngôn ngữ được tạo ra với thiên hướng “Hướng đối tượng” rất lớn, nên chương trình Java có thể tóm tắt bằng việc một tập hợp các vật thể – object tương tác với nhau bằng các hàm, thông số, …
- Object – Vật thể: Chứa thông số và các hàm. VD Object Máy tính có thông số CPU, Ram, dung lượng máy, .. có các hàm tương tác như: lướt web, bật máy, …
- Class – Lớp: Là một bản gốc chứa các thông số và các hàm mà vật thể được tạo lên
- Method – Hàm: Là các hàm tương tác với 1 object
Trước nhất, một cấu trúc chương trình cơ bản trong Java sẽ trông như sau:
Các lưu ý về cú pháp trong Java:
- Quan trọng viết hoa: Tức là Hello và hello sẽ khác nhau trong Java
- Tên file: Tên một file thường trùng tên với class trong file đó
- Hàm Main(): Trong mỗi class luôn cần có method main(), sẽ là thứ đầu tiên được chạy của hàm đó
Nhập xuất
Để nhập vào các dữ liệu từ input phía người dùng trong Java, chúng ta sẽ sử dụng lớp Scanner có sẵn trong Java để nhập vào dữ liệu.
Đầu tiên cần khai báo và import thư viện Scanner
Khởi tạo một object Scanner trong chương trình để đảm nhận việc lấy dữ liệu
Ở đây ta đã lấy dữ liệu cho một biến int – tương tự như C, là một kiểu dữ liệu lưu số nguyên bằng hàm nextInt().
Cú pháp:
(data-type) (variable-name) = scan.next…();
Ta cần thay trong dấu “…” bằng phương thức ta muốn:
Phương thức | Mô tả |
nextByte() | Đọc một số nguyên kiểu byte |
nextShort() | Đọc một số nguyên kiểu short |
nextInt() | Đọc một số nguyên kiểu int |
nextLong() | Đọc một số nguyên kiểu long |
nextFloat() | Đọc một số kiểu float |
nextDouble() | Đọc một số kiểu double |
next() | Đọc một string kết thức trước một ký tự trắng |
nextLine() | Đọc một line of text (kết thúc bằng phím Enter) |
Ví dụ: Nhập một string.
- Trong Java cũng gặp tình trạng bị trôi lệnh khi nhập 1 string ngay sau khi nhập 1 số. Cách sử lý là dùng thêm 1 lần nhập scan.nextLine() trước khi nhập string.
Để in ra dữ liệu trong Java
- Sử dụng System.out.println();
- Xuất kết quả ra màn hình đồng thời con trỏ chuột nhảy xuống dòng tiếp theo
- Sử dụng System.out.print();
- Xuất kết quả ra màn hình nhưng con trỏ chuột không xuống dòng.
- Sử dụng System.out.printf();
- Xuất ra màn hình kết quả đồng thời có thể định dạng được kết quả đó nhờ vào các đối số thích hợp. (đặc tả)
- Giống trong C và CPP.
Ví dụ chương trình nhập vào a, b, c và in ra a+b+c
Biến
Khai báo: Data-type Variable-name = giá trị;
Biến trong Java có 3 loại, mỗi loại nằm ở vị trí riêng:
- Biến thực thể (instance variable): nằm trong class, không thuộc method nào. Biến này thuộc về các thực thể (instance – object) được tạo ra từ class.
- Biến tĩnh (static variable): tương tự biến thực thể, nhưng có từ khóa static để đánh dấu biến thuộc về class, không phải object.
- Biến cục bộ (local variable): được khai báo trong method.
Toán tử
Các toán tử trong java tương tự như C++:
- Toán tử tăng giảm (increment, decrement): a++, ++a, a–, –a
- Toán tử thuận và đối (position, negation): +a, -a
- Toán tử số học (arithmetic): a + b, a – b, a * b, a / b (chia nguyên), a % b (chia dư)
- Toán tử ba ngôi (ternary): a > b ? a : b và có thể lồng nhau như (a > 0) ? “Dương” : (a < 0) ? “Âm” : “Số không”
- Toán tử gán (assignment): phép gán a = 5 và phép gán kết hợp như a += 5, a -= 3
- Toán tử quan hệ (relational): So sánh bằng a == 5, khác a != 5, lớn a > 5, bé a < 5, lớn hơn hoặc bằng a >= 5, bé hơn hoặc bằng a <= 5.
- Toán tử logic (thực hiện trên boolean): phép and a && b, or a || b và not !a
- Toán tử thao tác bit (bitwise): gồm and 10 & 3, or 10 | 3 và not !10. Các phép bitwise thực hiện trên số nguyên, và kí hiệu chỉ gồm 1 dấu.
- Toán tử dịch chuyển bit (bit shifting): phép dịch trái x << y (nhân 2^y), dịch phải điền cùng dấu x >> y (chia nguyên 2^y) và dịch phải điền 0 (zero filled – chia nguyên lấy trị tuyệt đối cho 2^y) x >>> y.
Câu lệnh rẽ nhánh if else
Lệnh if else tương tự như trong C++. Nếu điều kiện trong if đúng thì thực hiện lệnh, nếu không thì đi tiếp hoặc thực hiện lệnh trong else (nếu có).
Ngoài ra ta có thể thay if else bằng toán tử 3 ngôi hoặc switch-case với cấu trúc giống như C++.
Vòng lặp
While loop
Vòng lặp while kiểm tra điều kiện, nếu đúng thì thực hiện lệnh, sau đó quay lại kiểm tra điều kiện lần nữa,… cho tới khi điều kiện sai thì dừng.
Do while loop
Lặp do while khác với while chút xíu, là do while sẽ thực hiện lệnh trước rồi mới check điều kiện. Do đó, lệnh luôn được thực hiện ít nhất một lần.
Cả hai vòng lặp do while và while cần tránh lặp vô tận.
For loop
Lệnh lặp for gồm 3 phần trong ngoặc tròn:
- Phần init dùng khởi tạo biến đếm
- Phần condition chỉ định điều kiện lặp tiếp
- Phần increment dùng tăng, giảm biến đếm, để tới lúc nào đó điều kiện trở thành false.
Java có một vòng lặp khác, gọi là for each nhưng vẫn dùng từ khóa for, nhưng theo cú pháp khác.
Mảng – Array
Cần import thư viện Array để sử dụng
Khai báo mảng: Data-type Array-name
- Truy cập một phần tử trong mảng: Tên mảng[vị trí] – giống với C++ a[x]
- Bằng các cú pháp nhập xuất tương tự C++, có thể triển khai sắp xếp, làm việc trên mảng
Wrapper Class
Lớp Wrapper sẽ giúp chúng ta chuyển đổi qua lại giữa một kiểu dữ liệu nguyên thủy sang kiểu dữ liệu đối tượng và ngược lại.
Kiểu nguyên thủy | Kiểu Wrapper |
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
int a = 5;
a.ham()
Integer a = 5; a.ham()
- Chuyển đổi một kiểu nguyên thủy sang kiểu Wrapper của nó người ta gọi là Boxing. Ngược lại, khi bạn chuyển từ một kiểu Wrapper sang kiểu nguyên thủy của nó người ta gọi là Unboxing.
- Một số cấu trúc khác bên trong ngôn ngữ Java, như ArrayList hay Vector đều chứa đựng các tập hợp kiểu dữ liệu đối tượng thay vì kiểu nguyên thủy, nên việc biết và vận dụng các lớp Wrapper là một bắt buộc.
- Ngoài ra thì kiểu dữ liệu đối tượng sẽ thích hợp hơn trong việc thực thi đa luồng (multithreading) và đồng bộ hóa (synchronization).
- Các phương thức với Wrapper class:
- …Value(): giúp chuyển đổi một giá trị của lớp Wrapper nào đó về kiểu dữ liệu nguyên thủy (unboxing).
- parse…(“”): Tham số truyền vào cho phương thức là một chuỗi, kết quả nhận được là một giá trị nguyên thủy tương ứng với chuỗi truyền vào.
- toString(): chuyển đổi từ liểu dữ liệu Wrapper thành string.
String Class
String không phải kiểu dữ liệu nguyên thuỷ, mà một đối tượng của class String.
Cần import thư viện
- Class String chứa các hàm có chức năng tương đồng với kiểu dữ liệu chuỗi của các ngôn ngữ khác như C++, Python, có thể kể đến vài hàm chính như:
- length() : Trả về độ dài chuỗi
- charAt(i): Kí tự ở vị trí i ;
- trim(): Bỏ đi khoảng trắng hai đầu
- replace(): Thay đổi hết các đoạn chuỗi con thành đoạn chuỗi con mới
- Và rất nhiều hàm khác được tích hợp sẵn
Math Class
Là lớp chứa các phương thức, hỗ trợ Toán Học trong Java, tương tự C++, có rất nhiều hàm được dùng phổ biến như:
- Pow : Luỹ thừa
- Sqrt: Lấy căn
- Sin, cos, tan: Lượng giác
- Floor, Ceil: Làm tròn
- Và nhiều hàm hỗ trợ khác cho các công việc đặc thù.
Regex
Thuật ngữ Regex viết tắt của Regular expression. Nó là một chuỗi ký tự khác nhau diễn tả một mẫu tìm kiếm cụ thể. Nó cũng được gọi là Rational expression.
Nó được dùng để tìm kiếm và thao tác trên chuỗi văn bản. Nói một cách dễ hiểu là bạn có thể tìm một một mẫu dễ dàng và thay thế chúng bằng những mẫu phù hợp với sự giúp đỡ của biểu thức chính quy.
Pattern Class: (Lớp khuôn mẫu)
- Đây là phiên bản biên dịch của một biểu thức chính quy. Nó được sử dụng để xác định một khuôn mẫu cho các biểu thức chính quy.
- Lớp này có phương thức Compile(), ta sẽ truyền Xâu cần so khớp vào trong phương thức này, và nó sẽ trả về 1 đối tượng Pattern.
No. | Phương thức | Mô tả |
1 | static Pattern compile(String regex) | biên dịch regex đã cho và trả về thể hiện của Pattern. |
2 | Matcher matcher(CharSequence input) | tạo một matcher khớp với đầu vào đã cho với mẫu. |
3 | static boolean matches(String regex, CharSequence input) | Nó biên dịch biểu thức chính quy và tìm kiếm các chuỗi con từ chuỗi input phù hợp với mẫu regex. |
4 | String[] split(CharSequence input) | chia chuỗi input đã cho thành mảng các kết quả trùng khớp với mẫu đã cho. |
5 | String pattern() | trả về mẫu regex. |
Matcher Class – Lớp so sánh
- Lớp Matcher thực thi interface MatchResult. Nó được sử dụng để thực hiện các hoạt động so khớp trên một chuỗi ký tự.
- Thực hiện chức năng So khớp chính.
- Ta sẽ có được 1 đối tượng Matcher khi gọi tới phương thức matcher() trên một đối tượng Pattern.
- Ta truyền Xâu đầu vào – Xâu cần so khớp vào matcher() và xem xem nó có chứa mẫu mong muốn xuất hiện.
No. | Phương thức | Mô tả |
1 | boolean matches() | kiểm tra xem biểu thức chính quy có khớp với mẫu hay không. |
2 | boolean find() | tìm biểu thức tiếp theo khớp với mẫu. |
3 | boolean find(int start) | tìm biểu thức tiếp theo khớp với mẫu từ số bắt đầu đã cho. |
4 | String group() | trả về chuỗi con phù hợp. |
5 | int start() | trả về vị trí bắt đầu của chuỗi con phù hợp. |
6 | int end() | trả về vị trí kết thúc của chuỗi con phù hợp. |
7 | int groupCount() | trả về tổng số các chuỗi con phù hợp. |
Cú pháp Regex
No. | Biểu thức chính quy | Mô tả |
1 | . | Khớp (match) với bất kỳ ký tự nào |
2 | ^regex | Biểu thức chính quy phải khớp tại điểm bắt đầu |
3 | regex$ | Biểu thức chính quy phải khớp ở cuối dòng. |
4 | [abc] | Thiết lập định nghĩa, có thể khớp với a hoặc b hoặc c. |
5 | [abc][vz] | Thiết lập định nghĩa, có thể khớp với a hoặc b hoặc c theo sau là v hay z. |
6 | [^abc] | Khi dấu ^ xuất hiện như là nhân vật đầu tiên trong dấu ngoặc vuông, nó phủ nhận mô hình. Điều này có thể khớp với bất kỳ ký tự nào ngoại trừ a hoặc b hoặc c. |
7 | [a-d1-7] | Phạm vi: phù hợp với một chuỗi giữa a và điểm d và con số từ 1 đến 7. |
8 | X |∣ Z | Tìm X hoặc Z. |
9 | XZ | Tìm X và theo sau là Z. |
10 | $ | Kiểm tra kết thúc dòng. |
11 | \d | Số bất kỳ, viết ngắn gọn cho [0-9] |
12 | \D | Ký tự không phải là số, viết ngắn gon cho [^0-9] |
13 | \s | Ký tự khoảng trắng, viết ngắn gọn cho [ \t\n\x0b\r\f] |
14 | \S | Ký tự không phải khoản trắng, viết ngắn gọn cho [^\s] |
15 | \w | Ký tự chữ, viết ngắn gọn cho [a-zA-Z_0-9] |
16 | \W | Ký tự không phải chữ, viết ngắn gọn cho [^\w] |
17 | \S+ | Một số ký tự không phải khoảng trắng (Một hoặc nhiều) |
18 | \b | Ký tự thuộc a-z hoặc A-Z hoặc 0-9 hoặc , viết ngắn gọn cho [a-zA-Z0-9]. |
19 | *∗ | Xuất hiện 0 hoặc nhiều lần, viết ngắn gọn cho {0,} |
20 | ++ | Xuất hiện 1 hoặc nhiều lần, viết ngắn gọn cho {1,} |
21 | ?? | Xuất hiện 0 hoặc 1 lần, ? viết ngắn gọn cho {0,1}. |
22 | \{ X \}{X} | Xuất hiện X lần, {} |
23 | \{ X, Y \}{X,Y} | Xuất hiện trong khoảng X tới Y lần. |
24 | *?∗? | * có nghĩa là xuất hiện 0 hoặc nhiều lần, thêm ? phía sau nghĩa là tìm kiếm khớp nhỏ nhất. |
Class và Object – Java OOP
Encapsulation (Tính đóng gói)
- Tính đóng gói trong java là kỹ thuật ẩn giấu thông tin không liên quan và hiện thị ra thông liên quan. Mục đích chính của đóng gói trong java là giảm thiểu mức độ phức tạp phát triển phần mềm. Tức là thiết kế để các thuộc tính và phương thức thuộc về (bên trong) một lớp.
- Với các access modifier, tính đóng gói sẽ có thể giúp ngăn chặn những lớp bên ngoài truy cập, thay đổi thuộc tính và phương thức của một lớp. Từ đó, giúp cho việc che giấu dữ liệu, để bảo vệ trạng thái bên trong của một đối tượng. Hơn nữa, việc ẩn giấu các biến thì các lớp sẽ không chia sẻ thông tin với nhau được. Điều này làm giảm số lượng khớp nối có thể có trong một ứng dụng.
Ví dụ: Các biến của class đều ở private và chỉ truy cập được qua các phương thức public.
Tính kế thừa
Tính kế thừa trong Java là một cơ chế trong đó một đối tượng có được tất cả các thuộc tính và hành vi của một đối tượng cha.
- Khi bạn kế thừa từ một class có sẵn, bạn có thể tái sử dụng các phương thức và trường của class cha. Hơn nữa, bạn có thể thêm các phương thức và trường mới trong class hiện tại.
- Sử dụng tính kế thừa, ta có thể thực hiện Method Overriding, từ đó xuất hiện tính Đa hình trong runtime.
- Phân loại:
- Đơn kế thừa.
- Kế thừa nhiều cấp.
- Kế thừa thứ bậc.
- Đa kế thừa và Kế thừa hỗn hợp không được hỗ trợ thông qua Class trong Java, nhưng vẫn được hỗ trợ thông qua Interface.
Cú pháp: sử dụng từ khóa extends
- Ngoài ra còn có từ khóa super để tham chiếu trực tiếp đến đối tượng của lớp cha gần nhất.
- Sử dụng từ khóa super.xxx để gọi đến phương thức xxx của lớp cha gần nhất.
- Sử dụng super() để gọi trực tiếp constructor (hàm tạo) của lớp cha gần nhất.
Polymorphism (Tính đa hình).
- Đa hình là ta có thể thực hiện một hành động bằng nhiều cách khác nhau.
- Có hai kiểu của đa hình trong java, đó là đa hình lúc biên dịch (compile) và đa hình lúc thực thi (runtime). Chúng ta có thể thực hiện đa hình trong java bằng cách method overriding (ghi đè phương thức) và method overloading (nạp chồng phương thức).
- Ghi đè phương thức: method overriding – ghi đè method ở lớp cha trong lớp con, ta chỉ cần viết code thực thi khác của method đó ở trong lớp con là được.
- Nạp chồng phương thức : method overloading – Trong một class có thẻ có nhiều method cùng tên nhưng khác nhau tham số truyền vào và dữ liệu trả về, cách hoạt động khác nhau.
Abstract Classes (Lớp trừu tượng).
- Một phương thức được khai báo là abstract và không có code thực thi thì đó là phương thức trừu tượng, (giống virtual trong C++), được khai báo với từ khóa abstract ở trước.
- Lớp trừu tượng thường được dùng để kế thừa. Và lớp trừu tượng không thể tạo ra instance.
- Lớp abstract là lớp có các abstract method (Phương thức trừu tượng) (Có thể có hàm không trừu tượng)
- Phương thức trừu tượng (abstract method)
- Một phương thức được khai báo là abstract và không có trình triển khai thì đó là phương thức trừu tượng.
- Nếu muốn một lớp chứa một phương thức cụ thể nhưng bạn muốn triển khai thực sự phương thức đó để được quyết định bởi các lớp con, thì bạn có thể khai báo phương thức đó trong lớp cha ở dạng abstract.
Interface
Là một bản thiết kế của một lớp. Nó chỉ có các phương thức trừu tượng. Interface là một kỹ thuật để thu được tính trừu tượng hoàn toàn và đa kế thừa trong Java. Nó không thể được khởi tạo giống như lớp trừu tượng.
Một interface khác với một class ở một số điểm sau đây:
- Không thể khởi tạo interface, interface không có Constructor
- Phương thức interface đều phải là abstract (Khác lớp trừu tượng vẫn có thể có phương thức không trừu tượng)
- Tất cả trường interface đều là static hoặc final
- Interface chỉ có thể kế thừa từ interface
Modifiers
- Có hai loại Modifier trong Java, đó là: Access Modifier và Non-access Modifier.
- Tương tự OOP trong C++, trong Java có 4 phạm vi truy cập của Access Modifier như sau:
- private
- default
- protected
- public
Access Modifier | Trong lớp | Trong package | Ngoài package bởi lớp con | Ngoài package |
Private | Y | N | N | N |
Default | Y | Y | N | N |
Protected | Y | Y | Y | N |
Public | Y | Y | Y | Y |
Lưu ý:
- Constructor cần để public để có thể thực hiện tính Kế thừa.
- Nếu không khai báo Access Modifier, thì nó mặc định là default.
- Protected access modifier được truy cập bên trong package và bên ngoài package nhưng phải kế thừa.
- Ngoài ra có thêm final dùng để hạn chế người dùng:
- final variable: không thể thay đổi giá trị (hằng số)
- final parameter: tương tự final variable
- final method: không thể ghi đè
- final class: không thể kế thừa