oop

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 11

ĐỀ 1

Câu 1: Trình bày các nguyên lý chính của lập trình hướng đối tượng. Viết mã
Java thể hiện nguyên lý thừa kế.
1. Nguyên lý chính của OOP:
1 Tính đóng gói (Encapsulation): Nguyên lý này liên quan đến việc ẩn thông
tin của một đối tượng và chỉ tiết lộ các phương thức public để tương tác với
nó. Điều này giúp giảm sự phức tạp và rủi ro của việc thay đổi mã nguồn.
2 Tính kế thừa (Inheritance): Kế thừa cho phép một lớp (class) mới có thể
kế thừa các thuộc tính và phương thức từ một lớp đã tồn tại (lớp cha), giúp
tái sử dụng mã nguồn và tạo ra các lớp con có tính chất chung với lớp cha.
3 Tính đa hình (Polymorphism): Đa hình cho phép một đối tượng có thể thể
hiện ở nhiều hình dạng khác nhau. Điều này có thể được đạt được thông qua
kỹ thuật ghi đè phương thức (method overriding) và nạp chồng phương thức
(method overloading).
4 Tính trừu tượng (Abstraction): Trừu tượng là việc che giấu các chi tiết
không cần thiết và chỉ hiển thị thông tin cần thiết cho người dùng. Trong
OOP, trừu tượng thường được đạt được thông qua việc sử dụng lớp trừu
tượng (abstract class) và giao diện (interface).

2. Ví dụ thể hiện tính kế thừa


// Lớp cha (Superclass)
class Animal {
void eat() {
System.out.println("Animal is eating");
}
}

// Lớp con (Subclass) kế thừa từ lớp cha


class Dog extends Animal {
void bark() {
System.out.println("Dog is barking");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // Gọi phương thức từ lớp cha
dog.bark(); // Gọi phương thức từ lớp con
}
}

Câu 2: Thiết kế biểu đồ lớp cho một hệ thống đăng kí khóa học đơn giản
Quan hệ lớp cha con (
Quan hệ bình thường
Object A có thể là 1 phần của Object B, nếu B bị mất nhưng A vẫn bth, k lms

…. B mất là A cx mất
Lấy kiểu dữ liệu của lớp khác

- : private
+ : public
# : protected
~ : package/default
0..1 :0/1
n : nhiều
0..* :0/nhiều
1..*
m..n
Câu 3:
class Exam {
static void exam(int i, Integer wi, Integer[] a, int len) { //Khai báo phương
thức exam với các tham số
a[0] = wi; // Gán giá trị của wi vào phần tử đầu tiên của mảng a
wi = a[len - 1]; // Gán giá trị của phần tử cuối cùng của mảng a vào wi
wi = 1; // Gán giá trị 1 vào biến wi (Integer)
}
}

public class Main {


public static void main(String[] args) {
Integer[] arr = {10, 20}; //khai báo và tạo mảng arr
Exam.exam(30, arr[1], arr, arr.length); // Gọi phương thức exam từ lớp
Exam, truyền các đối số tương ứng
System.out.println(arr[0]); // In ra giá trị của phần tử đầu tiên của mảng arr
(sau khi thay đổi trong phương thức exam)
}
System.out.println(arr[1]); // In ra giá trị của phần tử thứ hai của mảng arr
}
Kết quả là 20

ĐỀ 2:
Câu 1: Trình bày kiểu dữ liệu tham chiếu và kiểu dữ liệu nguyên thủy trong
Java. Giải thích và cho ví dụ minh họa?
Trong Java, có hai loại kiểu dữ liệu chính: kiểu dữ liệu tham chiếu và kiểu dữ
liệu nguyên thủy.
Kiểu dữ liệu tham chiếu (Reference Data Types):
Lưu trữ địa chỉ của đối tượng trong bộ nhớ.
Có thể tham chiếu đến các đối tượng được tạo ra từ các lớp hoặc các mảng.
Có thể tham chiếu đến null.
Thực tế, các biến của kiểu dữ liệu tham chiếu không lưu trực tiếp dữ liệu
của đối tượng, mà chỉ lưu trữ địa chỉ của đối tượng đó.
Ví dụ:
// Khai báo một biến tham chiếu kiểu String và gán cho nó giá trị là một chuỗi
String str = "Hello World";
// Khai báo một biến tham chiếu kiểu ArrayList để tham chiếu đến một danh
sách các chuỗi
ArrayList<String> myList = new ArrayList<>();
myList.add("Apple");
myList.add("Banana");
Kiểu dữ liệu nguyên thủy (Primitive Data Types):
Lưu trữ dữ liệu trực tiếp trong bộ nhớ.
Không thể tham chiếu đến các đối tượng hoặc mảng.
Không thể có giá trị null.
Các kiểu dữ liệu nguyên thủy được xác định sẵn trong ngôn ngữ Java.
Các kiểu dữ liệu nguyên thủy trong Java bao gồm:
Kiểu số nguyên: byte, short, int, long
Kiểu số thực: float, double
Kiểu ký tự: char
Kiểu boolean: boolean
Ví dụ:
// Khai báo một biến kiểu số nguyên và gán cho nó một giá trị nguyên
int num = 10;
// Khai báo một biến kiểu ký tự và gán cho nó một giá trị ký tự
char ch = 'A';
// Khai báo một biến kiểu boolean và gán cho nó một giá trị boolean
boolean flag = true;

Câu 2: Giải thích ngắn gọn các khái niệm mã nguồn, mã máy, chương trình, tiến
trình. Viết lệnh dịch một file mã nguồn Main.java trong terminal để tạo ra
bytecode trong một thư mục khác
1. **Mã nguồn (Source code)**: Là phiên bản của một chương trình được viết
bằng ngôn ngữ lập trình như Java, C++, Python, v.v. Mã nguồn thường được
viết và hiểu bởi con người.

2. **Mã máy (Machine code)**: Là mã nhị phân được hiểu bởi máy tính. Đây
là ngôn ngữ mà CPU có thể thực thi trực tiếp.

3. **Chương trình (Program)**: Là một tập hợp các hướng dẫn được viết bằng
một ngôn ngữ lập trình cụ thể để thực hiện một tác vụ cụ thể trên máy tính hoặc
thiết bị điện tử.

4. **Tiến trình (Process)**: Là một chương trình được thực thi trên hệ thống
máy tính. Mỗi tiến trình có một không gian bộ nhớ riêng, bao gồm mã máy, dữ
liệu và bộ nhớ stack.
Để dịch một file mã nguồn `Main.java` để tạo ra bytecode trong một thư mục
khác, bạn có thể sử dụng trình biên dịch của Java là `javac` trong terminal. Dưới
đây là lệnh để thực hiện điều này:

```
javac -d /path/to/output/directory Main.java
```

Trong đó:
- `-d /path/to/output/directory` chỉ định thư mục đầu ra cho bytecode. Thay
`/path/to/output/directory` bằng đường dẫn thư mục bạn muốn lưu trữ bytecode.
- `Main.java` là tên của file mã nguồn bạn muốn biên dịch. Đảm bảo rằng bạn
đang ở trong thư mục chứa file `Main.java` hoặc sử dụng đường dẫn tuyệt đối
đến file `Main.java`.

Câu 3:
public class Main {
class Exam{ //Khai báo lớp Exam
private int id = 0; //Khai báo thuộc tính id kiểu int và khởi tạo giá trị mặc định là
0. Thuộc tính được khai báo với truy cập private nên chỉ có thể truy cập từ bên
trong lớp Exam.
String difficulty = "medium"; //Khai báo thuộc tính difficulty kiểu String và gán
giá trị "medium" cho nó.
String getDifficulty(){ //Khai báo phương thức getDifficulty không tham số, kiểu
trả về là String.
return this.difficulty;// trả về giá trị của thuộc tính difficulty của đối tượng hiện tại
(this).
}}
public static void main(String[] args) {
Exam exam01 = new Exam(); //Khởi tạo một đối tượng mới của lớp Exam và gán
nó cho biến exam01
System.out.println(exam01.id); In ra giá trị của thuộc tính id của đối tượng
exam01. Do id được khởi tạo mặc định là 0, nên kết quả in ra sẽ là 0
System.out.println(exam01.difficulty);// Gọi phương thức getDifficulty của đối
tượng exam01 và in ra giá trị trả về. Phương thức này sẽ trả về giá trị của thuộc
tính difficulty là "medium", nên kết quả in ra sẽ là "medium".
}}

ĐỀ 3:
Câu 1: Minh họa dữ liệu lưu trữ trong bộ nhớ khi sử dụng kiểu dữ liệu tham
chiếu và cho ví dụ.
Khi sử dụng kiểu dữ liệu tham chiếu trong Java, dữ liệu được lưu trữ trong bộ nhớ
bao gồm hai phần:
1. **Stack**: Lưu trữ các biến tham chiếu và các biến nguyên thủy cục bộ.
2. **Heap**: Lưu trữ các đối tượng và mảng được tạo ra trong chương trình.

Khi một biến tham chiếu được khởi tạo, nó sẽ được lưu trữ trên stack và trỏ đến
một vùng nhớ trên heap chứa đối tượng hoặc mảng tương ứng.

Ví dụ:
public class Main {
public static void main(String[] args) {
// Khởi tạo một đối tượng kiểu String và gán cho biến str
String str = new String("Hello");

// Khởi tạo một đối tượng kiểu StringBuilder và gán cho biến builder
StringBuilder builder = new StringBuilder("World");
}
}

Trong ví dụ trên:
- Biến `str` là một biến tham chiếu kiểu `String`, được lưu trữ trên stack. Đối
tượng `String` được tạo ra ("Hello") được lưu trữ trên heap, và `str` trỏ đến vùng
nhớ chứa đối tượng này.
- Biến `builder` là một biến tham chiếu kiểu `StringBuilder`, cũng được lưu trữ
trên stack. Đối tượng `StringBuilder` được tạo ra ("World") cũng được lưu trữ trên
heap, và `builder` trỏ đến vùng nhớ chứa đối tượng này.
Đây là cách dữ liệu được tổ chức trong bộ nhớ khi sử dụng kiểu dữ liệu tham
chiếu trong Java.

Câu 2: Hãy nạp chồng hàm khởi tạo cho lớp MyDate, với tham số truyền vào là
một số nguyên 8 chữ số hoặc một xâu kí tự dưới dạng yyyymmdd.
public class MyDate {

private int year;


private int month;
private int day;

// Hàm khởi tạo mặc định


public MyDate() {
this.year = 2023;
this.month = 1;
this.day = 1;
}

// Hàm khởi tạo với tham số là số nguyên 8 chữ số


public MyDate(int dateInt) {
this.year = dateInt / 10000;
this.month = (dateInt % 10000) / 100;
this.day = dateInt % 100;
}
// Hàm khởi tạo với tham số là xâu kí tự dưới dạng yyyymmdd
public MyDate(String dateStr) {
this.year = Integer.parseInt(dateStr.substring(0, 4));
this.month = Integer.parseInt(dateStr.substring(4, 6));
this.day = Integer.parseInt(dateStr.substring(6, 8));
}

// ... (các phương thức khác của lớp MyDate)

}
MyDate date1 = new MyDate(); // Sử dụng hàm khởi tạo mặc định
MyDate date2 = new MyDate(20230326); // Sử dụng hàm khởi tạo với tham số
số nguyên
MyDate date3 = new MyDate("2023-03-26"); // Sử dụng hàm khởi tạo với tham
số xâu kí tự

System.out.println(date1); // In ra ngày tháng năm hiện tại


System.out.println(date2); // In ra "2023-03-26"
System.out.println(date3); // In ra "2023-03-26"

ĐỀ 04:
Câu 1: Giải thích tại sao hàm:
void x2SoNguyen(Integer i){
i = i*2; }
không làm thay đổi giá trị của tham số truyền vào.
Trong Java, tham số của hàm được truyền theo giá trị. Điều này có nghĩa là khi
bạn truyền một tham số vào hàm, một bản sao của giá trị tham số đó được tạo ra
và được sử dụng bên trong hàm. Bất kỳ thay đổi nào được thực hiện trên bản
sao này không ảnh hưởng đến giá trị của biến gốc bên ngoài phạm vi của hàm.
Trong trường hợp của bạn, khi bạn thực hiện phép nhân `i * 2` trong hàm
`x2SoNguyen`, bạn thực hiện phép toán trên bản sao của giá trị được truyền
vào, không phải trực tiếp trên giá trị của tham số. Do đó, các thay đổi này không
được phản ánh trở lại nơi gọi hàm. Để thay đổi giá trị của tham số truyền vào,
bạn có thể sử dụng một loại dữ liệu có thể thay đổi như một mảng hoặc một đối
tượng được truyền theo tham chiếu.

Câu 2:
Một phương thức của lớp Account với chỉ định truy cập mặc định không thể
được truy cập bên ngoài gói chứa lớp đó. Viết code và lệnh dịch code để minh
họa phát biểu trên.
// Trong file Account.java
package banking; // Gói chứa lớp Account

public class Account {


// Phương thức có chỉ định truy cập mặc định
void defaultMethod() {
System.out.println("This is a default method.");
}
}
// Trong một file khác nằm ở gói không phải banking
import banking.Account; // Import lớp Account từ gói banking

public class Main {


public static void main(String[] args) {
// Tạo một đối tượng Account
Account account = new Account();

// Gọi phương thức có chỉ định truy cập mặc định từ lớp Main
// Phương thức này không thể được truy cập vì nó có chỉ định truy cập mặc
định
// và lớp Main không nằm trong cùng gói với lớp Account
account.defaultMethod(); // Lỗi: Cannot access defaultMethod() from
outside package
}
}

You might also like