Lập trình hướng đối tượng (OOP) là một phương pháp lập trình mạnh mẽ, đóng vai trò then chốt trong việc xây dựng các ứng dụng Java hiện đại. Bài viết này sẽ cung cấp một cái nhìn toàn diện về OOP trong Java, từ những khái niệm cơ bản như đối tượng, lớp, package đến các khái niệm nâng cao hơn như constructor và phạm vi truy cập.
Mục Lục
Khái niệm về lập trình hướng đối tượng trong Java
Lập trình hướng đối tượng (Object-Oriented Programming – OOP) là một phương pháp thiết kế chương trình bằng cách sử dụng các lớp và các đối tượng.
Java là một ngôn ngữ lập trình hướng đối tượng, do đó nó hỗ trợ các đặc tính của lập trình hướng đối tượng:
- Đa hình (Polymorphism)
- Thừa kế (Inheritance)
- Đóng gói (Encapsulation)
- Trừu tượng (Abstraction)
Mô hình lập trình hướng đối tượng OOP trong Java
Đối tượng (Object) trong Java
Đối tượng là một thực thể có trạng thái và hành vi. Nó có thể mang tính vật lý hoặc logic.
Trong thế giới thực, chúng ta có thể tìm thấy nhiều đồ vật xung quanh: cái bàn, con chó, con người,… Tất cả các đối tượng này đều có thuộc tính và hành vi.
Ví dụ, một con chó có các thuộc tính như tên, giống, màu sắc và các hành vi như sủa, chạy, ăn,… Trong phần mềm, thuộc tính của đối tượng được lưu trữ trong trường (field) và hành vi được lưu trữ trong phương thức (method).
Lớp (Class) trong Java
Lớp có thể được xem như một khuôn mẫu (template) của đối tượng (Object). Nó bao gồm dữ liệu của đối tượng (fields hay properties) và các phương thức (methods) tác động lên thành phần dữ liệu đó.
Khai báo lớp
Cú pháp:
class <Tên lớp> {
// Khai báo thuộc tính (field) hay biến
<Kiểu dữ liệu> <Tên biến 1>;
<Kiểu dữ liệu> <Tên biến 2>;
// Hàm khởi tạo không có tham số
<Tên lớp>() {
// Khởi tạo dữ liệu
}
// Hàm khởi tạo có tham số
<Tên lớp>(<Kiểu dữ liệu> <Tham số 1>[, <Kiểu dữ liệu> <Tham số 2>]) {
// Khởi tạo dữ liệu
}
// Phương thức xử lý (method)
<Kiểu trả về> method_1() {
// Logic xử lý
}
<Kiểu trả về> method_2(<Tham số>) {
// Logic xử lý
}
}
Trong đó:
class: từ khóa để khai báo lớp trong Java.<Tên lớp>: tên của lớp (viết hoa mỗi chữ cái đầu).field_1,field_2: các thuộc tính, biến hoặc thành phần dữ liệu của lớp (chữ cái đầu tiên viết thường, các chữ cái đầu của từ tiếp theo viết hoa).- Hàm khởi tạo (constructor): hàm dùng để khởi tạo đối tượng lớp.
method_1,method_2: các phương thức thể hiện các thao tác xử lý, tác động lên các thành phần dữ liệu của lớp.
Ví dụ:
public class Student {
// Khai báo thuộc tính
private int id;
private String name;
// Hàm khởi tạo có 1 tham số là id
public Student(int id) {
// Sử dụng từ khóa this để truy cập thuộc tính trong lớp
this.id = id;
}
// Cung cấp phương thức lấy giá trị id
public int getId() {
return id;
}
// Cung cấp phương thức lấy giá trị name
public String getName() {
return name;
}
// Cung cấp phương thức gán giá trị name
public void setName(String name) {
this.name = name;
}
}
Lưu ý:
- Từ khóa
thisdùng để chỉ đến chính lớp đang được tham chiếu đến.this.namesẽ tham chiếu đến thuộc tínhnamecủa classStudent. - Các phương thức (method) dùng để gán giá trị của một thuộc tính (field) nên bắt đầu là
set. - Các phương thức (method) dùng để lấy giá trị của một thuộc tính (field) nên bắt đầu là
get.
Sử dụng lớp
Cú pháp:
<Tên lớp> <Tên đối tượng> = new <Tên lớp>();
<Tên đối tượng>.<Thuộc tính> = <Giá trị>;
<Tên đối tượng>.<Phương thức>();
Sử dụng từ khóa new để khởi tạo một đối tượng của một lớp.
Ví dụ:
Student student = new Student(1);
student.setName("Sen Tay Ho");
System.out.println("Id=" + student.getId());
System.out.println("Name=" + student.getName());
Sự khác nhau giữa lớp và đối tượng trong Java
| Đặc điểm | Đối tượng | Lớp |
|---|---|---|
| Khái niệm | Thể hiện của một lớp | Khuôn mẫu hoặc thiết kế để tạo ra các đối tượng |
| Tính chất | Thực thể trong thế giới thực (ví dụ: con mèo) | Nhóm các đối tượng tương tự (ví dụ: lớp động vật) |
| Bản chất | Thực thể vật lý | Thực thể logic |
| Cách tạo | Sử dụng từ khóa new |
Sử dụng từ khóa class |
| Số lượng | Có thể tạo nhiều lần | Chỉ được khai báo một lần duy nhất |
| Cấp phát bộ nhớ | Được cấp phát bộ nhớ khi tạo | Không được cấp phát bộ nhớ khi tạo |
| Tạo thành phần | Nhiều cách (new, newInstance, clone,…) | Chỉ có một cách (class) |
Package trong Java
Định nghĩa
Một package (gói) trong Java là một nhóm các kiểu tương tự của các lớp, giao diện và các package con.
Package trong Java có thể được phân loại theo hai hình thức, package được dựng sẵn và package do người dùng định nghĩa.
Có rất nhiều package được dựng sẵn như java.lang, java.net, java.io, java.util, java.sql,…
Package do người dùng tự định nghĩa
Cú pháp:
package [<Tên package cha>.[<Tên package con>]];
Ví dụ về Java package:
package gpcoder; // Package cha
package gpcoder.example; // Package example là con của package gpcoder
Lợi thế của việc sử dụng package trong Java:
- Package được sử dụng để phân loại lớp và interface giúp dễ dàng bảo trì.
- Package cung cấp bảo vệ truy cập.
- Package khắc phục được việc đặt trùng tên.
Truy cập package từ package khác
Có 3 cách để truy cập package từ package bên ngoài:
- *Khai báo `import <Tên package>.
**: Tránh sử dụng cách này vì không xác định sẽ sử dụng class nào, có thể gặp vấn đề trùng tên lớp nếu cả 2 package importpackage.giống nhau. Ví dụ: sử dụng classDatecó thể gặp lỗi biên dịch do không thể xác định chính xác sử dụng classDatecủa package nào nếu import cảjava.util.vàjava.sql.*`.
package com.example;
import java.util.*;
import java.sql.*;
import com.example.service.*;
public class PackageDemo {
public static void main(String[] args) {
Date d = new Date();
}
}
- Khai báo
import <Tên package>.<Tên class>: Nên sử dụng cách này để giữ code đơn giản, rõ ràng, tái sử dụng lại nhiều chỗ, hạn chế xung đột về tên. - Sử dụng tên đầy đủ: Tránh sử dụng cách này, do code trở nên dài dòng nếu package gồm nhiều cấp cha, con.
Ví dụ: một project có package như sau:
Cấu trúc package trong Java
Class CommonService cung cấp 2 phương thức method1 và method2.
Chúng ta có thể sử dụng method1 từ một class khác ngoài package com.example.service như sau:
- Khai báo
import com.example.service.*:
package com.example;
import com.example.service.*;
public class PackageDemo {
public static void main(String[] args) {
CommonService service = new CommonService();
service.method1();
}
}
- Khai báo
import com.example.service.CommonService:
package com.example;
import com.example.service.CommonService;
public class PackageDemo {
public static void main(String[] args) {
CommonService service = new CommonService();
service.method1();
}
}
- Sử dụng tên đầy đủ:
package com.example;
public class PackageDemo {
public static void main(String[] args) {
com.example.service.CommonService service = new com.example.service.CommonService();
service.method1();
}
}
Lưu ý:
- Nếu bạn import một package thì package con của package đó không được import.
- Thứ tự của chương trình phải là khai báo
package->import->class. - Khi sử dụng một class của package này ở package khác nên sử dụng ở dạng
import <Tên package>.<Tên class>. - Mỗi package tương ứng với một thư mục.
Constructor trong Java
Định nghĩa
Constructor trong Java là một dạng đặc biệt của phương thức được sử dụng để khởi tạo các đối tượng.
Java Constructor được gọi tại thời điểm tạo đối tượng. Nó khởi tạo các giá trị để cung cấp dữ liệu cho các đối tượng, đó là lý do tại sao nó được gọi là constructor.
Khai báo của Constructor giống với khai báo của method (phương thức). Nó phải có cùng tên với class (lớp) và không có giá trị trả về.
Có 2 kiểu của constructor:
- Constructor mặc định (không có tham số truyền vào – default constructors).
- Constructor tham số (parameterized constructors).
Constructor mặc định trong Java
Một constructor mà không có tham số được gọi là constructor mặc định. Constructor mặc định được sử dụng để cung cấp các giá trị mặc định cho các thuộc tính như 0, null, false …, tùy thuộc vào kiểu dữ liệu được sử dụng.
Nếu một lớp không khai báo contructor thì trình biên dịch sẽ tự động tạo một constructor mặc định trong lớp đó.
Cú pháp:
<Tên lớp>() {
// Khởi tạo dữ liệu
}
Ví dụ:
package com.example;
public class JavaDefaultConstructor {
public JavaDefaultConstructor() {
System.out.println("This is default constructor.");
}
public static void main(String[] args) {
JavaDefaultConstructor obj = new JavaDefaultConstructor();
}
}
Kết quả khi chạy chương trình trên:
This is default constructor.
Constructor tham số trong Java
Một constructor có tham số truyền vào được gọi là constructor tham số. Constructor tham số được sử dụng để cung cấp các giá trị khác nhau cho các đối tượng khác nhau.
<Tên lớp>(<Kiểu dữ liệu> <Tham số 1>[, <Kiểu dữ liệu> <Tham số 2>]) {
// Khởi tạo dữ liệu
}
Ví dụ:
package com.example;
public class JavaParameterizedConstructor {
private String website;
public JavaParameterizedConstructor(String website) {
this.website = website;
System.out.println("This is parameterized constructor");
System.out.println("from website = " + website);
}
public static void main(String[] args) {
JavaParameterizedConstructor obj = new JavaParameterizedConstructor("gpcoder.com");
}
}
Kết quả:
This is parameterized constructor
from website = gpcoder.com
Overloading Constructor trong Java
Constructor Overloading là một kỹ thuật trong Java. Bạn có thể tạo nhiều constructor trong cùng một lớp với danh sách tham số truyền vào khác nhau, điều này được gọi là phép đa năng hóa (Overloading). Trình biên dịch phân biệt các constructor này thông qua số lượng và kiểu của các tham số truyền vào.
Ví dụ:
package com.example;
public class JavaOverloadingConstructors {
private String website;
private String subject;
public JavaOverloadingConstructors() {
System.out.println("This is default constructor.");
}
public JavaOverloadingConstructors(String website) {
this.website = website;
System.out.println("This is parameterized constructor");
System.out.println("from website = " + website);
}
public JavaOverloadingConstructors(String website, String subject) {
this.website = website;
this.subject = subject;
System.out.println("This is parameterized constructor");
System.out.println("from website = " + website);
System.out.println("with subject = " + subject);
}
public static void main(String[] args) {
JavaOverloadingConstructors obj = new JavaOverloadingConstructors();
System.out.println("-");
obj = new JavaOverloadingConstructors("gpcoder.com");
System.out.println("-");
obj = new JavaOverloadingConstructors("gpcoder.com", "OOP");
}
}
Kết quả:
This is default constructor.
-
This is parameterized constructor
from website = gpcoder.com
-
This is parameterized constructor
from website = gpcoder.com
with subject = OOP
Lưu ý:
- Từ khóa
thistrong java là một biến tham chiếu được sử dụng để tham chiếu tới đối tượng của lớp hiện tại. - Từ khóa
supertrong java là một biến tham chiếu được sử dụng để tham chiếu trực tiếp đến đối tượng của lớp cha gần nhất.
Sự khác nhau giữa constructor và phương thức trong Java
| Đặc điểm | Constructor | Phương thức |
|---|---|---|
| Chức năng | Khởi tạo trạng thái của một đối tượng | Thể hiện hành động của một đối tượng |
| Kiểu trả về | Không có kiểu trả về | Có kiểu trả về |
| Tạo mặc định | Trình biên dịch Java tạo nếu không có constructor nào | Không được tạo bởi trình biên dịch Java |
| Tên | Phải giống tên lớp | Có thể giống hoặc khác tên lớp |
Phạm vi truy cập (Access Modifier) trong Java
Có hai loại modifier trong java: access modifiers và non-access modifiers.
Các access modifiers trong java xác định độ truy cập (Phạm vi) vào dữ liệu của của các trường (field), phương thức (method), cấu tử (constructor) hoặc lớp (class).
Có 4 kiểu của java access modifiers:
private(default)protectedpublic
Và có một vài non-access modifiers chẳng hạn static, abstract, synchronized, native, volatile, transient,…
Bảng mô tả tổng quan về cách sử dụng các access modifier:
| Access Modifier | Truy cập bên trong class? | Truy cập bên trong package? | Truy cập bên ngoài package bởi class con? | Truy cập bên ngoài class và không thuộc class con? |
|---|---|---|---|---|
private |
Có | Không | Không | Không |
default |
Có | Có | Không | Không |
protected |
Có | Có | Có | Không |
public |
Có | Có | Có | Có |
Kết luận
Bài viết đã cung cấp một cái nhìn tổng quan về lập trình hướng đối tượng trong Java. Hiểu rõ các khái niệm và nguyên tắc OOP là rất quan trọng để xây dựng các ứng dụng Java mạnh mẽ, dễ bảo trì và mở rộng. Hy vọng rằng bài viết này sẽ giúp bạn nắm vững kiến thức cơ bản và áp dụng OOP hiệu quả trong các dự án thực tế của mình.
