Lập trình hướng đối tượng trong java

1. Tại sao cần OOP?

Giả sử rằng bạn muốn lắp ráp máy tính của riêng bạn, bạn đi đến một cửa hàng phần cứng và chọn lên một bo mạch chủ, bộ xử lý, một số RAM, ổ đĩa cứng, một vỏ bọc, một nguồn cung cấp năng lượng, và đặt chúng lại với nhau. Bạn bật điện, và các máy tính chạy. Bạn không cần phải lo lắng cho dù CPU là 1-core hoặc 6 lõi; bo mạch chủ là một 4-layer hay 6 lớp; các đĩa cứng có 4 tấm, 6 tấm, 3 inch hoặc 5 inch đường kính; RAM được thực hiện tại Nhật Bản hay Hàn Quốc, và như vậy. Bạn chỉ cần đặt hardwarecomponents với nhau và mong đợi máy để chạy. Tất nhiên, bạn phải chắc chắn rằng bạn có giao diện chính xác, ví dụ, bạn chọn một đĩa cứng IDE hơn là một đĩa cứng SCSI, nếu bo mạch chủ của bạn chỉ hỗ trợ IDE; bạn phải chọn RAMS với đánh giá tốc độ chính xác, và như vậy. Tuy nhiên, nó không phải là khó khăn để thiết lập một máy từ các thành phần phần cứng.


Tương tự như vậy, một chiếc xe được lắp ráp từ các bộ phận và linh kiện, chẳng hạn như khung xe, cửa ra vào, động cơ, bánh xe, phanh và truyền tải. Các thành phần có thể tái sử dụng, ví dụ, một bánh xe có thể được sử dụng trong rất nhiều xe ô tô (các thông số kỹ thuật tương tự).
Phần cứng, chẳng hạn như máy tính và xe hơi, được lắp ráp từ các bộ phận, đó là những thành phần tái sử dụng.
Làm thế nào về phần mềm? Bạn có thể “lắp ráp” một ứng dụng phần mềm bằng cách chọn một thói quen ở đây, một thói quen ở đó, và mong muốn các chương trình để chạy? Câu trả lời rõ ràng là không! Không giống như phần cứng, nó là rất khó khăn để “lắp ráp” một ứng dụng từ các thành phần phần mềm. Kể từ sự ra đời của máy tính 70 năm trước đây, chúng tôi đã viết tấn và tấn của các chương trình. Tuy nhiên, đối với mỗi ứng dụng mới, chúng ta phải tái phát minh ra bánh xe và ghi các chương trình từ đầu.
Tại sao lại phát minh ra bánh xe? Tại sao viết lại mã?
Lập trình hướng đối tượng trong java
Ngôn ngữ thủ tục hướng truyền thống
OOP_CFunction.png
Ngôn ngữ lập trình thủ tục theo định hướng truyền thống (chẳng hạn như C, Fortran, Cobol và Pascal) bị một số nhược điểm đáng chú ý trong việc tạo ra các thành phần phần mềm tái sử dụng:
1. Các chương trình thủ tục định hướng được tạo thành từ các chức năng. Chức năng ít sử dụng lại. Nó là rất khó khăn để sao chép một chức năng từ một chương trình và dùng lại trong các chương trình khác vì các chức năng có thể tham khảo các biến toàn cầu và các chức năng khác. Nói cách khác, chức năng này không được đóng gói như một đơn vị tái sử dụng khép kín.
2. Các ngôn ngữ thủ tục không phù hợp của các cấp cao trừu tượng để giải quyết các vấn đề thực tế cuộc sống. Ví dụ, chương trình C sử dụng các cấu trúc như if-else, cho-loop, mảng, phương pháp, con trỏ, đó là mức độ thấp và khó khăn cho các vấn đề thực trừu tượng như một Relationship Management (CRM) hệ thống hoặc một trò chơi bóng đá máy tính khách hàng.
Nói tóm lại, các thủ tục, ngôn ngữ truyền thống tách các cấu trúc dữ liệu và thuật toán của các thực thể phần mềm.
Trong năm 1970, Bộ Quốc phòng Mỹ (DoD) đưa một lực lượng đặc nhiệm để điều tra tại sao ngân sách IT của nó luôn luôn đi ra ngoài tầm kiểm soát; nhưng không có nhiều người thực hiện. Các phát hiện này là:
1. 80% ngân sách đã đi đến phần mềm (với 20% còn lại đến phần cứng).
2. Hơn 80% ngân sách phần mềm đi để bảo trì (chỉ có 20% còn lại cho phát triển phần mềm mới).
3. Các thành phần phần cứng có thể được áp dụng cho các sản phẩm khác nhau, và tính toàn vẹn của họ thường không ảnh hưởng đến các sản phẩm khác. (Phần cứng có thể chia sẻ và sử dụng lại! Lỗi phần cứng đang bị cô lập!)
4. Thủ tục phần mềm thường không thể chia sẻ và không thể tái sử dụng. Lỗi phần mềm có thể ảnh hưởng đến các chương trình khác đang chạy trong máy tính.
Các lực lượng đặc nhiệm đề xuất để làm cho phần mềm trở nên giống OBJECT phần cứng. Sau đó, Bộ Quốc phòng thay thế hơn 450 ngôn ngữ máy tính, sau đó được sử dụng để xây dựng các hệ thống DoD, với một ngôn ngữ hướng đối tượng được gọi là Ada.
Lập trình hướng đối tượng với java
OOP_Objects.png
Lập trình hướng đối tượng (OOP) Các ngôn ngữ được thiết kế để khắc phục những vấn đề này.
  1. Các đơn vị cơ bản của OOP là một lớp, và tóm cả các thuộc tính tĩnh và hoạt động năng động trong một “hộp”, và xác định các giao diện nào để sử dụng các hộp. Kể từ khi các lớp học đều được đóng gói, nó là dễ dàng hơn để sử dụng lại các lớp học. Nói cách khác, OOP kết hợp các cấu trúc dữ liệu và thuật toán của một phần mềm thực thể bên trong cùng một hộp.
  2. OOP ngôn ngữ cho phép mức độ trừu tượng cao hơn để giải quyết các vấn đề thực tế cuộc sống. Các ngôn ngữ thủ tục truyền thống (chẳng hạn như C và Pascal) buộc bạn phải suy nghĩ về cấu trúc của máy tính (ví dụ như bộ nhớ bit và byte, mảng, quyết định, vòng lặp) hơn là suy nghĩ về những vấn đề bạn đang cố gắng để giải quyết. Những ngôn ngữ OOP (như Java, C ++ và C #) cho bạn nghĩ rằng trong không gian vấn đề, và sử dụng các đối tượng phần mềm để đại diện và thực thể trừu tượng của không gian vấn đề để giải quyết vấn đề.

OOP_SoccerGame.png
Như một ví dụ, giả sử bạn muốn viết một trò chơi bóng đá máy tính (mà tôi coi như một ứng dụng phức tạp). Nó là khá khó khăn để mô hình các trò chơi trong ngôn ngữ thủ tục theo định hướng. Nhưng sử dụng OOP ngôn ngữ, bạn có thể dễ dàng mô hình chương trình cho phù hợp với “những điều thực sự” xuất hiện trong trò chơi bóng đá.
  • Player: thuộc tính bao gồm tên, số lượng, vị trí trong lĩnh vực, và vv; hoạt động bao gồm chạy, nhảy, đá-the-ball, và vv
  • Ball:
  • Reference:
  • Field:
  • Audience:
  • Weather:
Quan trọng nhất, một số trong các lớp này (chẳng hạn như bóng và khán giả) có thể được tái sử dụng trong một ứng dụng khác, ví dụ như, trò chơi bóng rổ máy tính, với rất ít hoặc không sửa đổi.
Hiệu quả của OOP
Các ngôn ngữ thủ tục định hướng tập trung vào các thủ tục, với chức năng là đơn vị cơ bản. Bạn cần phải đầu tiên tìm ra tất cả các chức năng và sau đó suy nghĩ về làm thế nào để đại diện cho dữ liệu.
Các ngôn ngữ hướng đối tượng tập trung vào các thành phần mà người sử dụng nhận thấy, với các đối tượng là đơn vị cơ bản. Bạn tìm ra tất cả các đối tượng bằng cách đặt tất cả các dữ liệu và các hoạt động mô tả sự tương tác của người dùng với các dữ liệu.
Công nghệ hướng đối tượng có nhiều lợi ích:
  • Dễ dàng trong thiết kế phần mềm như bạn có thể nghĩ rằng trong không gian vấn đề chứ không phải là bit của máy và byte. Bạn đang đối phó với những khái niệm cao cấp và trừu tượng. Dễ trong thiết kế dẫn đến phát triển phần mềm hiệu quả hơn.
  • Ease in software maintenance: hướng đối tượng phần mềm là dễ hiểu, do đó dễ dàng hơn để kiểm tra, gỡ lỗi, và duy trì.
  • Reusable software: bạn không cần phải tiếp tục tái phát minh ra bánh xe và viết lại các chức năng tương tự cho các tình huống khác nhau. Cách nhanh nhất và an toàn nhất của việc phát triển một ứng dụng mới là sử dụng lại mã số hiện có – mã số kiểm tra đầy đủ và đã được chứng minh.

2.  OOP in Java

2.1  Class & Instances

Trong Java, một lớp là một định nghĩa của các đối tượng cùng loại. Nói cách khác, một lớp học là một kế hoạch chi tiết, mẫu, hoặc một nguyên mẫu mà xác định và mô tả các thuộc tính tĩnh và hành vi động chung cho tất cả các đối tượng cùng loại.
Một ví dụ là một hiện thực của một mặt hàng cụ thể của một lớp. Nói cách khác, một thể hiện là một instantiation của một lớp. Tất cả các trường hợp của một lớp học có tính chất tương tự, như được mô tả trong định nghĩa lớp. Ví dụ, bạn có thể định nghĩa một lớp được gọi là “sinh viên” và tạo ra ba trường hợp của lớp “Sinh viên” cho “Peter”, “Paul” và “Pauline”.
Thuật ngữ “đối tượng” thường đề cập đến trường hợp. Nhưng nó thường được sử dụng một cách lỏng lẻo, có thể tham khảo một lớp hoặc một ví dụ.

2.2  A Class is a 3-Compartment Box encapsulating Data and Operations

OOP_ThreeCompartment.png
Một lớp có thể được hình dung như một hộp ba khoang, như minh họa:
  1. Name (or identity): xác định các lớp.
  2. Variables (or attribute, state, field):chứa các thuộc tính tĩnh của lớp.
  3. Methods (or behaviors, function, operation): chứa các hành vi năng động của lớp.
Nói cách khác, một lớp đóng gói các thuộc tính tĩnh (dữ liệu) và hành vi động (hoạt động hoạt động trên dữ liệu) trong một hộp.
Các con số sau đây cho thấy một vài ví dụ về các lớp học:
OOP_ClassExamples.png
Hình dưới đây cho thấy hai trường hợp của học sinh lớp, được xác định là “paul” và “peter”.
OOP_InstanceExamples.png
Unified Modeling Language (UML) Class và Instance Diagrams: Các sơ đồ lớp trên được rút ra theo các ký hiệu UML. Một lớp được biểu diễn như một hộp 3 ngăn, có chứa tên, các biến và phương pháp tương ứng. Tên lớp được in đậm và tập trung. Một ví dụ (đối tượng) cũng được biểu diễn như một hộp 3 ngăn, với tên dụ thể hiện asinstanceName: className và gạch chân.
Tóm tắt
  1. Một lớp là một lập trình viên xác định, trừu tượng, khép kín, tái sử dụng thực thể phần mềm bắt chước một điều thực tế.
  2. Một lớp là một hộp 3 ngăn chứa tên, các biến và các phương pháp.
  3. Một lớp đóng gói các cấu trúc dữ liệu (trong các biến) và thuật toán (phương pháp). Các giá trị của các biến tạo thành trạng thái của nó. Các phương pháp cấu thành hành vi của mình.
  4. Một ví dụ là một instantiation (hoặc thực hiện) của một mặt hàng cụ thể của một lớp.

2.3  Class Definition

Trong Java, chúng ta sử dụng từ khoá class định nghĩa một lớp. Cho ví dụ:
public class Circle {        // class name
double radius; // variables
String color;

double getRadius() {...} // methods
double getArea() {...}
}
public class SoccerPlayer {  // class name
int number; // variables
String name;
int x, y;

void run() {...} // methods
void kickBall() {...}
}
Cú pháp để định nghĩa lớp trong Java là:
[AccessControlModifier] class ClassName {
// class body contains definition of variables and methods
...
}
Chúng tôi sẽ giải thích sự sửa đổi điều khiển truy cập, chẳng hạn như công cộng và tư nhân, sau đó.
Quy ước đặt tên lớp: Một tên lớp phải là một danh từ hoặc một cụm danh từ tạo thành một vài từ. Tất cả các từ được ban đầu có vốn (camel-case). Sử dụng một danh từ số ít cho tên lớp. Chọn một classname ý nghĩa và tự mô tả. Đối với ví dụ, SoccerPlayer, HttpProxyServer, FileInputStream, PrintStream và SocketFactory.

2.4  Creating Instances of a Class

Để tạo ra một thể hiện của một lớp, bạn phải:
Khai báo một định danh dụ (ví dụ tên) của một lớp học đặc biệt.
Xây dựng các ví dụ (ví dụ, phân bổ lưu trữ cho các ví dụ và khởi tạo instance) bằng cách sử dụng toán tử “mới”.
Đối với ví dụ, giả sử rằng chúng ta có một lớp được gọi là Circle, chúng ta có thể tạo ra các trường hợp của các mối như sau:
// Declare 3 instances of the class Circle, c1, c2, and c3
Circle c1, c2, c3;
// Allocate and construct the instances via new operator
c1 = new Circle();
c2 = new Circle(2.0);
c3 = new Circle(3.0, "red");
// You can declare and construct in the same statement
Circle c4 = new Circle();

2.5  Dot Operator

Các biến và phương pháp thuộc về một lớp học được chính thức gọi là biến thành viên và phương pháp thành viên. Để tham khảo một biến thành viên hay phương pháp, bạn phải:
đầu tiên xác định các trường hợp bạn quan tâm, và sau đó
Sử dụng dấu chấm (.) Để tham khảo các thành viên (biến hay phương thức).
Ví dụ, giả sử rằng chúng ta có một lớp được gọi là Circle, với hai biến (bán kính và màu sắc) và hai phương thức (getRadius () và getArea ()). Chúng tôi đã tạo ra ba trường hợp của lớp Circle, cụ thể là, c1, c2 và c3. Để gọi các phương pháp getArea (), bạn phải nhận diện đầu tiên thể hiện sự quan tâm, nói c2, sau đó sử dụng các dấu chấm, dưới hình thức của c2.getArea (), để gọi getArea () phương pháp dụ c2.
Ví dụ,
// Declare and construct instances c1 and c2 of the class Circle
Circle c1 = new Circle ();
Circle c2 = new Circle ();
// Invoke member methods for the instance c1 via dot operator
System.out.println(c1.getArea());
System.out.println(c1.getRadius());
// Reference member variables for instance c2 via dot operator
c2.radius = 5.0;
c2.color = "blue";
Gọi getArea () mà không xác định các trường hợp là vô nghĩa, như bán kính là không rõ (có thể có nhiều trường hợp của Circle – từng duy trì bán kính của riêng mình).
Nói chung, giả sử có một lớp được gọi là Aclass với một biến thành viên được gọi là aVariable và một phương pháp gọi là thành viên aMethod (). Một ví dụ được gọi là anInstance được xây dựng cho Aclass. Bạn useanInstance.aVariable và anInstance.aMethod ().

2.6  Member Variables

Một biến thành viên có một cái tên (hoặc định danh) và một loại; và giữ một giá trị của loại hình cụ thể (như descried trong chương trước đó). Một biến thành viên cũng có thể là một thể hiện của một lớp nào đó (sẽ được thảo luận sau).
Quy ước đặt tên biến: Một tên biến phải là một danh từ hoặc một cụm danh từ tạo thành một vài từ. Từ đầu tiên là chữ thường và phần còn lại của từ này là ban đầu có vốn (camel-case), ví dụ như, fontSize, roomNumber, Xmax, ymin và xTopLeft. Hãy lưu ý rằng tên biến bắt đầu bằng một chữ thường, trong khi tên lớp học bắt đầu với một chữ hoa.
Cú pháp chính thức để định nghĩa biến trong Java là:
[AccessControlModifier] type variableName [= initialValue];
[AccessControlModifier] type variableName-1 [= initialValue-1] [, type variableName-2 [= initialValue-2]] ... ;
For example,
private double radius;
public int length = 1, width = 1;

2.7  Member Methods

Một phương pháp (như mô tả trong các chương trước):
nhận được các thông số từ người gọi,
thực hiện các hoạt động được xác định trong cơ thể phương pháp, và
trả lại một phần của kết quả (hoặc void) để người gọi.
Cú pháp để khai báo phương thức trong Java là như sau:
[AccessControlModifier] returnType methodName ([argumentList]) {
// method body or implementation
......
}
Cho ví dụ:
public double getArea() {
return radius*radius*Math.PI;
}
Quy ước đặt tên phương pháp: Một phương pháp hiệu sẽ là một động từ, hoặc một cụm động từ gồm nhiều từ. Từ đầu tiên là chữ thường và phần còn lại của từ này là ban đầu có vốn (camel-case). Ví dụ, getRadius (), getParameterValues ().
Hãy lưu ý rằng tên biến là một danh từ (biểu thị một thuộc tính tĩnh), trong khi tên phương pháp là một động từ (thể hiện một hành động). Họ có quy ước đặt tên. Tuy nhiên, bạn có thể dễ dàng phân biệt chúng với các ngữ cảnh. Phương pháp lấy đối số trong ngoặc đơn (có thể không tranh cãi với dấu ngoặc rỗng), nhưng các biến không. Trong văn bản này, các phương pháp được biểu thị bằng một cặp dấu ngoặc đơn, ví dụ như, println (), getArea () cho rõ ràng.

2.8  Đưa chúng với nhau: Một OOP Ví dụ

OOP_Circle.png
Một lớp được gọi là Circle là để được định nghĩa như được minh họa trong sơ đồ lớp. Nó bao gồm hai yếu tố: bán kính (kiểu double) và màu sắc (kiểu String); và ba phương pháp: getRadius (), getColor (), và getArea ().
Ba trường hợp của Circles gọi là c1, c2, c3 và sau đó sẽ được xây dựng với các thành viên dữ liệu của mình, như thể hiện trong sơ đồ ví dụ.
Các mã nguồn cho Circle.java là như sau:
Circle.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Define the Circle class
public class Circle { // Save as "Circle.java"
// Private variables
private double radius;
private String color;

// Constructors (overloaded)
public Circle() { // 1st Constructor
radius = 1.0;
color = "red";
}
public Circle(double r) { // 2nd Constructor
radius = r;
color = "red";
}
public Circle(double r, String c) { // 3rd Constructor
radius = r;
color = c;
}

// Public methods
public double getRadius() {
return radius;
}
public String getColor() {
return color;
}
public double getArea() {
return radius*radius*Math.PI;
}
}
Compile “Circle.java” into “Circle.class“.
Chú ý rằng lớp mối không có một phương pháp chính (). Do đó, nó là không một chương trình độc lập và bạn không thể chạy các lớp mối của chính nó. Lớp Circle có nghĩa là một khối xây dựng và sử dụng trong các chương trình khác.
TestCircle.java
Bây giờ chúng ta sẽ viết một lớp được gọi TestCircle, trong đó sử dụng các lớp Circle. Lớp TestCircle có một phương thức main () và có thể được thực hiện.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Test driver program for the Circle class
public class TestCircle { // Save as "TestCircle.java"
public static void main(String[] args) { // Execution entry point
// Construct an instance of the Circle class called c1
Circle c1 = new Circle(2.0, "blue"); // Use 3rd constructor
System.out.println("Radius is " + c1.getRadius() // use dot operator to invoke member methods
+ " Color is " + c1.getColor()
+ " Area is " + c1.getArea());

// Construct another instance of the Circle class called c2
Circle c2 = new Circle(2.0); // Use 2nd constructor
System.out.println("Radius is " + c2.getRadius()
+ " Color is " + c2.getColor()
+ " Area is " + c2.getArea());

// Construct yet another instance of the Circle class called c3
Circle c3 = new Circle(); // Use 1st constructor
System.out.println("Radius is " + c3.getRadius()
+ " Color is " + c3.getColor()
+ " Area is " + c3.getArea());
}
}
Compile TestCircle.java into TestCircle.class.
Run the TestCircle and study the output:
Radius is 2.0 Color is blue Area is 12.566370614359172
Radius is 2.0 Color is red Area is 12.566370614359172
Radius is 1.0 Color is red Area is 3.141592653589793

2.9  Constructors

Một constructor là một phương pháp đặc biệt có tên cùng một phương pháp như tên lớp. Trong lớp các mối ở trên, chúng ta định nghĩa ba phiên bản quá tải của nhà xây dựng “Circle (….)”. Một nhà xây dựng được sử dụng toconstruct và khởi tạo tất cả các biến thành viên. Để tạo ra một thể hiện mới của một lớp, bạn cần phải sử dụng một nhà điều hành “mới” đặc biệt tiếp theo là một cuộc gọi đến một trong những nhà xây dựng. Ví dụ,
Circle c1 = new Circle();
Circle c2 = new Circle(2.0);
Circle c3 = new Circle(3.0, "red");
Một nhà xây dựng là khác nhau từ một phương pháp thông thường ở các khía cạnh sau:
Tên của phương thức khởi tạo là giống như tên lớp, và theo quy ước className, bắt đầu bằng một chữ hoa.
Constructor không có kiểu trả về (hoặc ngầm trả về void). Do đó, không có tuyên bố trả lại được phép vào bên trong cơ thể của constructor.
Constructor chỉ có thể hiện thông qua các nhà điều hành “mới”. Nó chỉ có thể được sử dụng một lần để khởi tạo các ví dụ xây dựng. Bạn không thể gọi các constructor sau đó.
Các nhà xây dựng không được thừa kế (sẽ được giải thích sau).
Một constructor không có tham số được gọi là constructor mặc định, khởi tạo các biến thành viên với giá trị mặc định của chúng. Ví dụ, các Circle () trong ví dụ trên.

2.10  Method Overloading

Phương pháp quá tải có nghĩa là tên cùng một phương pháp có thể có hiện thực khác nhau (các phiên bản). Tuy nhiên, việc triển khai khác nhau phải được phân biệt bởi danh sách đối số của họ (hoặc số lượng các đối số, hoặc các loại của các đối số, hoặc đặt hàng của họ).
Ví dụ: Các phương pháp bình quân () có 3 phiên bản, với danh sách đối số khác nhau. Người gọi có thể gọi các phiên bản được lựa chọn bằng cách cung cấp các luận cứ hợp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Example to illustrate Method Overloading
public class TestMethodOverloading {
public static int average(int n1, int n2) { // A
return (n1+n2)/2;
}

public static double average(double n1, double n2) { // B
return (n1+n2)/2;
}

public static int average(int n1, int n2, int n3) { // C
return (n1+n2+n3)/3;
}

public static void main(String[] args) {
System.out.println(average(1, 2)); // Use A
System.out.println(average(1.0, 2.0)); // Use B
System.out.println(average(1, 2, 3)); // Use C
System.out.println(average(1.0, 2)); // Use B - int 2 implicitly casted to double 2.0
// average(1, 2, 3, 4); // Compilation Error - No matching method
}
}
Overloading Circle Class’ Constructor
The above Circle class has three versions of constructors differentiated by their parameter list, as followed:
Circle()
Circle(double r)
Circle(double r, String c)
Tùy thuộc vào các danh sách đối số thực tế sử dụng khi gọi phương pháp này, các nhà xây dựng phù hợp sẽ được gọi. Nếu danh sách đối số của bạn không phù hợp với bất kỳ một trong những phương pháp, bạn sẽ nhận được một lỗi biên dịch.

2.11  public vs. private – Access Control Modifiers

Một trình sửa đổi điều khiển truy cập có thể được sử dụng để kiểm soát tầm nhìn của một lớp, hoặc một biến thành viên hoặc một phương thức thành viên trong một lớp. Chúng tôi bắt đầu với hai bổ khiển truy cập sau đây:
công cộng: Lớp / biến / phương pháp tiếp cận được và có sẵn cho tất cả các đối tượng khác trong hệ thống.
tin: Các lớp học / biến / phương pháp tiếp cận và sẵn chỉ trong lớp học này.
Ví dụ, trong định nghĩa các mối trên, các thành viên bán kính biến được khai báo là private. Kết quả là, bán kính là ở bên trong lớp Circle, nhưng không bên trong lớp TestCircle. Nói cách khác, bạn không thể sử dụng “c1.radius” để chỉ bán kính c1 trong TestCircle. Hãy thử chèn các tuyên bố “System.out.println (c1.radius);” trong TestCircle và quan sát các thông báo lỗi. Hãy thử changingradius cho công chúng, và chạy lại các tuyên bố.
Mặt khác, các phương pháp getRadius () được khai báo nào trong lớp Circle. Do đó, nó có thể được áp dụng trong lớp TestCircle.
UML Notation: Trong UML ký hiệu, thành viên công cộng được thể hiện bằng một “+”, trong khi các thành viên riêng với một “-” trong sơ đồ lớp.
More bổ kiểm soát truy cập sẽ được thảo luận sau.

2.12 Ẩn thông tin và Encapsulation

Một lớp học gói gọn tên, thuộc tính tĩnh và hành vi động thành một “hộp 3 ngăn”. Khi một lớp được định nghĩa, bạn có thể đóng dấu lên các “hộp” và đặt “hộp” trên xiên cho người khác sử dụng và tái sử dụng. Bất cứ ai cũng có thể nhận các “hộp” và sử dụng nó trong ứng dụng của họ. Điều này không thể được thực hiện trong các ngôn ngữ thủ tục định hướng truyền thống như C, như các thuộc tính tĩnh (hoặc các biến) nằm rải rác trên toàn bộ chương trình và các tập tin tiêu đề. Bạn không thể “cắt” ra một phần của chương trình C, cắm vào một chương trình khác, và mong muốn các chương trình để chạy mà không cần thay đổi sâu rộng.
Biến thành viên của một lớp học thường được giấu kín từ bên ngoài (ví dụ, các lớp khác), với sửa đổi điều khiển truy cập tin. Truy cập vào các biến thành viên được cung cấp thông qua các phương pháp giám định viên công cộng, ví dụ như, getRadius () và getColor ().
Điều này theo nguyên tắc ẩn thông tin. Đó là, đối tượng giao tiếp với nhau bằng cách sử dụng giao diện cũng được xác định (phương pháp công cộng). Đối tượng không được phép để biết chi tiết thực hiện của người khác. Các chi tiết thực hiện được ẩn hoặc đóng gói trong lớp. Ẩn thông tin tạo điều kiện tái sử dụng của lớp.
Rule of Thumb: Không thực hiện bất kỳ công biến, trừ khi bạn có một lý do chính đáng.

2.13  Getters and Setters

Để cho phép các lớp khác để đọc các giá trị của một biến tư nhân nói xxx, bạn phải cung cấp một phương thức get (hoặc getter hoặc phương pháp accessor) gọi getXxx (). Một phương pháp get không cần phải tiếp xúc với các dữ liệu ở dạng thô. Nó có thể xử lý dữ liệu và hạn chế về dữ liệu người khác sẽ thấy. có được phương pháp này không thể sửa đổi các biến.
Để cho phép các lớp khác để sửa đổi các giá trị của một biến tư nhân nói xxx, bạn phải cung cấp một phương thức thiết lập (hoặc setter hoặc phương pháp mutator) gọi setXxx (). Một phương thức thiết lập có thể cung cấp dữ liệu xác nhận (chẳng hạn như phạm vi kiểm tra), và chuyển đổi dữ liệu thô thành các đại diện nội.
Ví dụ, trong lớp các mối của chúng tôi, các biến và bán kính màu được khai báo là private. Đó là để nói, họ chỉ có sẵn trong lớp Circle và không thể nhìn thấy trong bất kỳ lớp khác – lớp includingTestCircle. Bạn không thể truy cập các biến radius và màu sắc riêng từ lớp TestCircle trực tiếp – thông qua nói c1.radius hoặc c1.color. Lớp mối cung cấp hai phương pháp accessor công cộng, cụ thể là, getRadius () và getColor (). Những phương pháp này được tuyên bố công khai. Lớp TestCircle có thể gọi các phương pháp accessor công cộng để lấy bán kính và màu sắc của một đối tượng Circle, qua nói c1.getRadius () và c1.getColor ().
Không có cách nào bạn có thể thay đổi bán kính hoặc màu sắc của một đối tượng Circle, sau khi nó được xây dựng trong lớp TestCircle. Bạn không thể phát hành báo cáo như c1.radius = 5.0 để thay đổi bán kính của dụ c1, như bán kính được khai báo là tin trong lớp Circle và không nhìn thấy được đến các lớp học khác bao gồm TestCircle.
Nếu các nhà thiết kế của lớp mối cho phép thay đổi bán kính và màu sắc sau khi một đối tượng Circle xây dựng, ông có để cung cấp các phương pháp thích hợp tập (hoặc máy tạo hoặc các phương pháp mutator), ví dụ:
// Setter for color
public void setColor(String c) {
color = c;
}

// Setter for radius
public void setRadius(double r) {
radius = r;
}
Với việc thực hiện đúng các ẩn thông tin, các nhà thiết kế của một lớp có toàn quyền kiểm soát những gì người dùng của lớp có thể và không thể làm được.

2.14  Từ khóa”this

Bạn có thể sử dụng từ khoá “này” để chỉ trường hợp này bên trong một định nghĩa lớp.
Một trong những cách sử dụng chính của từ khóa này là để giải quyết sự mơ hồ.
public class Circle {
double radius; // Member variable called "radius"
public Circle(double radius) { // Method's argument also called "radius"
this.radius = radius;
// "this.radius" refers to this instance's member variable
// "radius" resolved to the method's argument.

}
...
}
Trong các mã trên, có hai định danh được gọi là bán kính – một biến thành viên của lớp học và lý luận của phương pháp. Điều này gây ra xung đột đặt tên. Để tránh sự trùng tên, bạn có thể tên của phương pháp luận r thay vì bán kính. Tuy nhiên, bán kính là khoảng hơn và có ý nghĩa trong bối cảnh này. Java cung cấp một từ khóa gọi này để giải quyết cuộc xung đột đặt tên này. “this.radius” đề cập đến các biến thành viên; trong khi “radius” giải quyết cho lập luận của phương pháp.
Sử dụng các từ khóa “này”, các phương pháp xây dựng, phương thức getter và setter cho một biến tư nhân gọi là xxx của loại T như sau:
public class Aaa {
// A private variable named xxx of type T
private T xxx;

// Constructor
public Aaa(T xxx) {
this.xxx = xxx;
}

// A getter for variable xxx of type T receives no argument and return a value of type T
public T getXxx() {
return xxx;
}

// A setter for variable xxx of type T receives a parameter of type T and return void
public void setXxx(T xxx) {
this.xxx = xxx;
}
}
Đối với một biến boolean xxx, các getter được đặt tên isXxx (), thay vì getXxx (), như sau:
// Private boolean variable
private boolean xxx;

// Getter
public boolean isXxx() {
return xxx;
}

// Setter
public void setXxx(boolean xxx) {
this.xxx = xxx;
}
Ghi chú:
this.varName đề cập đến varname của trường hợp này; this.methodName (…) gọi methodName (…) trong trường hợp này.
Trong một nhà xây dựng, chúng ta có thể sử dụng này (…) để gọi một constructor của lớp này.
Bên trong một phương pháp, chúng ta có thể sử dụng câu lệnh “quay trở lại này” để trở về trường hợp này để người gọi.

2.15  Method toString()

Mỗi lớp Java được thiết kế tốt nên có một phương pháp nào được gọi là toString () trả về một chuỗi mô tả của đối tượng. Bạn có thể gọi toString () phương pháp một cách rõ ràng bởi callinganInstanceName.toString () hoặc ngầm qua println () hoặc String hành nối ‘+’. Chạy println (anInstance) với một đối tượng sẽ gọi toString () phương pháp mà dụ ngầm.
Ví dụ, nếu toString () sau đây là phương pháp được đưa vào lớp mối của chúng tôi:
// Return a short String description of this instance
public String toString() {
return "Circle with radius = " + radius + " and color of " + color;
}
Trong lớp TestCircle của bạn, bạn có thể có được một mô tả văn bản ngắn của một đối tượng bằng các mối:
Circle c1 = new Circle();
System.out.println(c1.toString()); // explicitly calling toString()
System.out.println(c1); // implicit call to c1.toString()
System.out.println("c1 is: " + c1); // '+' invokes c1.toString() to get a String before concatenation
The signature of toString() is:
public String toString() { ...... }

2.16  Constants (final)

Hằng số là các biến được định nghĩa với các thức sửa đổi. Một biến cuối cùng chỉ có thể được chỉ định một lần và giá trị của nó có thể không được sửa đổi lần giao. Ví dụ,
public final double X_REFERENCE = 1.234;

private final int MAX_ID = 9999;
MAX_ID = 10000; // error: cannot assign a value to final variable MAX_ID

// You need to initialize a final member variable during declaration
private final int SIZE; // error: variable SIZE might not have been initialized
Quy ước đặt tên biến: Một tên hằng là một danh từ, hoặc một cụm danh từ tạo thành một vài từ. Tất cả các từ được viết hoa phân cách bằng dấu gạch dưới “_”, cho ví dụ, X_REFERENCE, MAX_INTEGER và MIN_VALUE.
Nâng cao:
  1. final primitive variable cannot be re-assigned a new value.
  2. final instance cannot be re-assigned a new address.
  3. final class cannot be sub-classed (or extended).
  4. final method cannot be overridden.

2.17  Putting Them Together in the Revised Circle Class

ClassDiagram_Circle.png
Circle.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// The Circle class definition
public class Circle { // Save as "Circle.java"
// Public constants
public static final double DEFAULT_RADIUS = 8.8;
public static final String DEFAULT_COLOR = "red";

// Private variables
private double radius;
private String color;

// Constructors (overloaded)
public Circle() { // 1st Constructor
radius = DEFAULT_RADIUS;
color = DEFAULT_COLOR;
}
public Circle(double radius) { // 2nd Constructor
this.radius = radius;
color = DEFAULT_COLOR;
}
public Circle(double radius, String color) { // 3rd Constructor
this.radius = radius;
this.color = color;
}

// Public getter and setter for private variables
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}

// toString() to provide a short description of this instance
public String toString() {
return "Circle with radius = " + radius + " and color of " + color;
}

// Public methods
public double getArea() {
return radius*radius*Math.PI;
}
}
TRY
Write a test driver to test ALL the public methods in the Circle class.

3.  More Examples on Classes

3.1  Example: The Account Class

class diagram
A class called Account, which models a bank account, is designed as shown in the class diagram. It contains:
  • Two private variables: accountNumber (int) and balance (double), which maintains the current account balance.
  • Public methods credit() and debit(), which adds or subtracts the given amount from the balance, respectively. The debit() method shall print “amount withdrawn exceeds the current balance!” if amount is more than balance.
  • toString(), which returns “A/C no: xxx Balance=xxx” (e.g., A/C no: 991234 Balance=$88.88), with balance rounded to two decimal places.
Account.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/* The Account class Definition */
public class Account {
// Private variables
private int accountNumber;
private double balance;

// Constructors
public Account(int accountNumber, double balance) {
this.accountNumber = accountNumber;
this.balance = balance;
}

public Account(int accountNumber) {
this.accountNumber = accountNumber;
balance = 0;
}

// Public getters and setters for private variables
public int getAccountNumber() {
return accountNumber;
}

public double getBalance() {
return balance;
}

public void setBalance(double balance) {
this.balance = balance;
}

public void credit(double amount) {
balance += amount;
}

public void debit(double amount) {
if (balance < amount) {
System.out.println("amount withdrawn exceeds the current balance!");
} else {
balance -= amount;
}
}

public String toString() {
return String.format("A/C no: %d Balance=%.2f", accountNumber, balance);
}
}
TestAccount.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class TestAccount {
public static void main(String[] args) {
Account a1 = new Account(1234, 99.99);
System.out.println(a1);
a1.credit(10.001);
a1.debit(5);
System.out.println(a1);
System.out.println(a1.getBalance());
a1.setBalance(0);
System.out.println(a1);

Account a2 = new Account(8888);
System.out.println(a2);
}
}

3.2  Example: The Ball class

class diagram
Ball class models a moving ball, designed as shown in the class diagram, contains the following members:
  • Two private variables xy, which maintain the position of the ball.
  • Constructors, public getters and setters for the private variables.
  • A method setXY(), which sets the position of the ball and setXYSpeed() to set the speed of the ball.
  • A method move(), which increases x and y by the given xDisp and yDisp, respectively.
  • toString(), which returns “Ball @ (x,y)“.
Ball.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// Define the class Ball
public class Ball {
// Private variables
private double x, y; // x and y location

// Constructors
public Ball(double x, double y) {
this.x = x;
this.y = y;
}
public Ball() {
x = 0.0;
y = 0.0;
}

// Public getters and setters for private variables x and y
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}

public void setXY(double x, double y) {
this.x = x;
this.y = y;
}

public void move(double xDisp, double yDisp) {
x += xDisp;
y += yDisp;
}

public String toString() {
return "Ball @ (" + x + "," + y + ")";
}
}

3.3  The Author and Book Classes

Let’s start with the Author class
OOP_AuthorClass.png
A class called Author is defined as shown in the class diagram. It contains:
  • Three private member variables: name (String), email (String), and gender (char of either 'm','f', or 'u' for unknown – you might also use a boolean variable called male having value of trueor false).
  • One constructor to initialize the nameemail and gender with the given values.
    (There is no default constructor for Author, as there are no defaults for nameemail and gender.)
  • Public getters/setters: getName()getEmail()setEmail(), and getGender().
    (There are no setters for name and gender, as these attributes cannot be changed.)
  • toString() method that returns “author-name (gender) at email“, e.g., “Tan Ah Teck (m) at ahTeck@somewhere.com“.
Author.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// The Author class definition
public class Author {
// Private variables
private String name;
private String email;
private char gender;

// Constructor
public Author(String name, String email, char gender) {
this.name = name;
this.email = email;
this.gender = gender;
}

// Public getters and setters for private variables
public String getName() {
return name;
}

public String getEmail() {
return email;
}

public char getGender() {
return gender;
}

public void setEmail(String email) {
this.email = email;
}

// toString() to describe itself
public String toString() {
return name + " (" + gender + ") at " + email;
}
}
A Test Driver Program: TestAuthor.java
1
2
3
4
5
6
7
8
9
// A test driver for the Author class
public class TestAuthor {
public static void main(String[] args) {
Author teck = new Author("Tan Ah Teck", "teck@somewhere.com", 'm');
System.out.println(teck); // toString()
teck.setEmail("teck@nowhere.com");
System.out.println(teck); // toString()
}
}
Book is written by an Author – Using an “Object” Member Variable
OOP_BookClass.png
Hãy thiết kế một lớp Book. Giả sử rằng một cuốn sách được viết bởi một và chỉ một tác giả. Lớp Book (như thể hiện trong sơ đồ lớp) có chứa các thành viên sau:
  • Four private member variables: name (String), author (an instance of the class Author you have just created, assume that each book has one and only one author), price (double), andqtyInStock (int).
  • Two overloaded constructors.
  • Getters/Setters: getName()getAuthor()getPrice()setPrice()getQtyInStock(),setQtyInStock().
  • toString() that returns “‘book-name' by author-name (gender) at email“.
    You should reuse the Author‘s toString() method, which returns “author-name (gender) at email“.
Book.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// The Book class definition
public class Book {
// Private variables
private String name;
private Author author;
private double price;
private int qtyInStock;

// Constructors
public Book(String name, Author author, double price) {
this.name = name;
this.author = author;
this.price = price;
this.qtyInStock = 0; // Not given, set to the default value
}

public Book(String name, Author author, double price, int qtyInStock) {
this.name = name;
this.author = author;
this.price = price;
this.qtyInStock = qtyInStock;
}

// Getters and Setters
public String getName() {
return name;
}

public Author getAuthor() {
return author; // return member author, which is an instance of class Author
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}

public int getQtyInStock() {
return qtyInStock;
}

public void setQtyInStock(int qtyInStock) {
this.qtyInStock = qtyInStock;
}

// toString() t describe itself
public String toString() {
return "'" + name + "' by " + author; // author.toString()
}
}
A Test Driver Program – TestBook.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// A test driver program for the Book class
public class TestBook {
public static void main(String[] args) {
Author teck = new Author("Tan Ah Teck", "teck@somewhere.com", 'm');
System.out.println(teck); // toString()

Book dummyBook = new Book("Java for dummies", teck, 9.99, 88);
System.out.println(dummyBook); // toString()

Book moreDummyBook = new Book("Java for more dummies",
new Author("Peter Lee", "peter@nowhere.com", 'm'), // anonymous instance of Author
19.99, 8);
System.out.println(moreDummyBook); // toString()
}
}

3.4  The Student Class

ExerciseOOP_Student.png
Giả sử rằng ứng dụng của chúng ta đòi hỏi chúng ta để mô hình một nhóm sinh viên. Một sinh viên có tên và địa chỉ. Chúng tôi được yêu cầu phải theo dõi các khóa học lấy của mỗi học sinh, cùng với các lớp (giữa 0 và 100) cho mỗi khóa học. Học sinh không phải mất hơn 30 khóa học cho toàn bộ chương trình. Chúng tôi được yêu cầu phải in tất cả các lớp học, và cũng là điểm trung bình tổng thể.
We can design the Student class as shown in the class diagram. The class contains:
  • Private member variables name (String), address (String), numCoursescourse and grades. The numCourses maintains the number of courses taken by the student so far. The courses andgrades are two parallel arrays, storing the courses taken (e.g.,{"IM101", "IM102", "IM103"}) and their respective grades (e.g. {89, 56, 98}).
  • A constructor that constructs an instance with the given name and Address. It also constructs thecourses and grades arrays and set the numCourses to 0.
  • Getters for name and address; setter for address. No setter is defined for name as it shall not be changed.
  • toString(), which prints “name(address)“.
  • A method addCourseGrade(course, grade), which appends the given course and grade into thecourses and gradesarrays, respectively, and increments numCourses.
  • A method printGrades(), which prints “name(address) course1:grade1, course2:grade2,...“. You should reuse thetoString() here.
  • A method getAverageGrade(), which returns the average grade of all the courses taken.
UML Notations: In UML notations, a variable is written as [+|-]varName:type; a method is written as[+|-]methodName(arg1:type1arg2:type2,...):returnType, where '+' denotes publicand '-'denotes private.
Student.java
The source code for Student.java is as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// The student class definition
public class Student {
// Private member variables
private String name;
private String address;
// Courses taken and grades for the courses are kept in 2 arrays of the same length
private String[] courses;
private int[] grades; // A grade is between 0 to 100
private int numCourses; // Number of courses taken so far
private static final int MAX_COURSES = 30; // maximum courses

// Constructor
public Student(String name, String address) {
this.name = name;
this.address = address;
courses = new String[MAX_COURSES]; // allocate arrays
grades = new int[MAX_COURSES];
numCourses = 0; // no courses so far
}

// Public getter for private variable name
public String getName() {
return name;
}

// Public getter for private variable address
public String getAddress() {
return address;
}

// Public setter for private variable address
public void setAddress(String address) {
this.address = address;
}

// Describe itself
public String toString() {
return name + "(" + address + ")";
}

// Add a course and grade
public void addCourseGrade(String course, int grade) {
courses[numCourses] = course;
grades[numCourses] = grade;
++numCourses;
}

// Print all courses taken and their grades
public void printGrades() {
System.out.print(this); // toString()
for (int i = 0; i < numCourses; ++i) {
System.out.print(" " + courses[i] + ":" + grades[i]);
}
System.out.println();
}

// Compute the average grade
public double getAverageGrade() {
int sum = 0;
for (int i = 0; i < numCourses; ++i) {
sum += grades[i];
}
return (double)sum/numCourses;
}
}
TestStudent.java
Hãy để chúng tôi viết một chương trình thử nghiệm để tạo ra một sinh viên tên là “Tân Ah Teck”, người đã 3 khóa học, “IM101″, “IM102″ và “IM103″ với điểm số 89, 57, và 96 tương ứng. Chúng tôi sẽ in tất cả các lớp học, và bậc trung bình.
1
2
3
4
5
6
7
8
9
10
11
// A test driver program for the Student class
public class TestStudent {
public static void main(String[] args) {
Student ahTeck = new Student("Tan Ah Teck", "1 Happy Ave");
ahTeck.addCourseGrade("IM101", 89);
ahTeck.addCourseGrade("IM102", 57);
ahTeck.addCourseGrade("IM103", 96);
ahTeck.printGrades();
System.out.printf("The average grade is %.2f", ahTeck.getAverageGrade());
}
}
Tan Ah Teck(1 Happy Ave) IM101:89 IM102:57 IM103:96
The average grade is 80.67

3.5  The MyPoint and MyCircle class

OOP_MyPoint.png
A class called MyPoint, which models a 2D point with x and y coordinates, is designed as shown in the class diagram. It contains:
  • Two private member variables x (int) and y (int).
  • default (no-arg) constructor that construct a point at (0,0).
  • A constructor that constructs a point with the given x and y coordinates.
  • Getter and setter for the private variables x and y.
  • A method setXY() to set both x and y.
  • toString() method that returns a string description of the instance in the format “(x,y)“.
  • A method distance(int x, int y), which returns the distance from this point to another point at the given (x,y) coordinates in double.
  • An overloaded distance(MyPoint another) method, which returns the distance from this point to the given MyPoint instance calledanother.
MyPoint.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// The MyPoint class definition
public class MyPoint {
// Private member variables
private int x;
private int y;

// Constructors
public MyPoint() {
x = 0;
y = 0;
}

public MyPoint(int x, int y) {
this.x = x;
this.y = y;
}

// Getters and Setters
public int getX() {
return x;
}

public int getY() {
return y;
}

public void setX(int x) {
this.x = x;
}

public void setY(int y) {
this.y = y;
}

public void setXY(int x, int y) {
this.x = x;
this.y = y;
}

public String toString() {
return "(" + x + "," + y + ")";
}

public double distance(int x, int y) {
int xDiff = this.x - x;
int yDiff = this.y - y;
return Math.sqrt(xDiff*xDiff + yDiff*yDiff);
}

public double distance(MyPoint another) {
int xDiff = this.x - another.x;
int yDiff = this.y - another.y;
return Math.sqrt(xDiff*xDiff + yDiff*yDiff);
}
}
Test Driver Program: TestMyPoint.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// A test driver for MyPoint class
public class TestMyPoint {
public static void main(String[] args) {
MyPoint p1 = new MyPoint();
System.out.println(p1);
p1.setXY(0, 3);
System.out.println(p1);

MyPoint p2 = new MyPoint(4, 0);
System.out.println(p2);

// Test distance() methods
System.out.println(p1.distance(4, 0));
System.out.println(p1.distance(p2));
}
}
ExerciseOOP_MyCircleMyPoint.png
A class called MyCircle is designed as shown in the class diagram. It contains:
  • Two private member variables: a radius (double) and a center (an instance of MyPoint, which we created earlier).
  • default (no-arg) constructor that construct a Circle at (0,0) with radius of 1.0.
  • A constructor that constructs a Circle with the given xCenteryCenter and radius.
  • A constructor that constructs a Circle with the given instance of MyPoint as center; and radius.
  • Getter and setter for the private variables center and radius.
  • Methods getCenterX()setCenterX()setCenterXY(), etc.
  • toString() method that returns a string description of the instance in the format “center=(x,y) radius=r“.
  • distance(MyCircle another) method that returns the distance from this Circle to the givenMyCircleinstance called another.
MyCircle.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// The MyCircle class definition
public class MyCircle {
// Private member variables
private MyPoint center; // Declare instance center
private double radius;

// Constructors
public MyCircle() {
center = new MyPoint(); // Construct instance at (0,0)
radius = 1.0;
}

public MyCircle(int xCenter, int yCenter, double radius) {
center = new MyPoint(xCenter, yCenter); // Construct instance
this.radius = radius;
}

public MyCircle(MyPoint center, double radius) {
this.center = center;
this.radius = radius;
}

// Getters and Setters
public double getRadius() {
return radius;
}

public void setRadius(double radius) {
this.radius = radius;
}

public MyPoint getCenter() {
return center;
}

public void setCenter(MyPoint center) {
this.center = center;
}

public int getCenterX() {
return center.getX();
}

public void setCenterX(int x) {
center.setX(x);
}

public int getCenterY() {
return center.getY();
}

public void setCenterY(int y) {
center.setY(y);
}

public void setCenterXY(int x, int y) {
center.setX(x);
center.setY(y);
}

public String toString() {
return "center=" + center + " radius=" + radius;
}

public double getArea() {
return Math.PI * radius * radius;
}

public double getPerimeter() {
return 2.0 * Math.PI * radius;
}

public double distance(MyCircle another) {
return center.distance(another.center); // use distance() of MyPoint
}
}
TestMyCircle.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// A test driver for MyCircle class
public class TestMyCircle {
public static void main(String[] args) {
MyCircle c1 = new MyCircle();
System.out.println(c1);
c1.setCenterXY(0, 3);
System.out.println(c1);

MyPoint p1 = new MyPoint(4, 0);
MyCircle c2 = new MyCircle(p1, 9);
System.out.println(c2);

// Test distance() methods
System.out.println(c1.distance(c2));
}
}

3.6  The MyTime class

ExerciseOOP_MyTime.png
A class called MyTime, which models a time instance, is designed as shown in the class diagram.
It contains the following private instance variables:
  • hour: between 00 to 23.
  • minute: between 00 to 59.
  • Second: between 00 to 59.
The constructor shall invoke the setTime() method (to be described later) to set the instance variable.
It contains the following public methods:
  • setTime(int hour, int minute, int second): It shall check if the given hourminute andsecond are valid before setting the instance variables.
    (Advanced: Otherwise, it shall throw an IllegalArgumentException with the message “Invalid hour, minute, or second!“.)
  • Setters setHour(int hour)setMinute(int minute)setSecond(int second): It shall check if the parameters are valid, similar to the above.
  • Getters getHour()getMinute()getSecond().
  • toString(): returns “HH:MM:SS“.
  • nextSecond(): Update this instance to the next second and return this instance. Take note that thenextSecond() of23:59:59 is 00:00:00.
  • nextMinute()nextHour()previousSecond()previousMinute()previousHour(): similar to the above.
MyTime.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// The MyTime class definition
public class MyTime { // "MyTime.java"
// Private member variables
private int hour; // 0-23
private int minute; // 0-59
private int second; // 0-59

// Constructor
public MyTime(int hour, int minute, int second) {
setTime(hour, minute, second);
}

void setTime(int hour, int minute, int second) {
setHour(hour);
setMinute(minute);
setSecond(second);
}

// Setters which validates input with exception handling
void setHour(int hour) {
if (hour >= 0 && hour <= 23) {
this.hour = hour;
} else {
throw new IllegalArgumentException("Invalid hour!");
}
}

void setMinute(int minute) {
if (minute >= 0 && minute <= 59) {
this.minute = minute;
} else {
throw new IllegalArgumentException("Invalid minute!");
}
}

void setSecond(int second) {
if (second >= 0 && second <= 59) {
this.second = second;
} else {
throw new IllegalArgumentException("Invalid second!");
}
}

// Getters
public int getHour() {
return hour;
}

public int getMinute() {
return minute;
}

public int getSecond() {
return second;
}

// Return description in the format "hh:mm:ss" with leading zeros
public String toString() {
return String.format("%02d:%02d:%02d", hour, minute, second);
}

// Increment this instance to the next second, return this instance
public MyTime nextSecond() {
++second;
if (second == 60) {
second = 0;
++minute;
}
if (minute == 60) {
minute = 0;
++hour;
}
if (hour == 24) {
hour = 0;
}
return this; // Return this instance, to support cascaded operation
}
}
Xử lý ngoại lệ -Exception
Phải làm gì nếu một giờ không hợp lệ, hoặc phút thứ hai được đưa ra trong các nhà xây dựng hoặc setter? In thông báo lỗi? Đột ngột chấm dứt chương trình? Tiếp tục hoạt động bằng cách thiết lập các thông số mặc định của nó? Đây là một quyết định khó khăn.
Trong Java, thay vì in một thông báo lỗi, bạn có thể ném một cái gọi là đối tượng ngoại lệ (như IllegalArgumentException) cho người gọi, và để cho người gọi xử lý các trường hợp ngoại lệ. Ví dụ,
void setHour(int hour) {
if (hour >= 0 && hour <= 23) {
this.hour = hour;
} else {
throw new IllegalArgumentException("Invalid hour!");
}
}
The caller can use the try-catch construct to handle the exception (in the test driver below). For example,
try {
MyTime t3 = new MyTime(12, 69, 69);
// skip remaining statements in try, goto catch
System.out.println(t1);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
} // after catch, continue next statement
Các câu lệnh trong các thử-khoản sẽ được thực thi. Nếu tất cả các câu lệnh đều thành công, các khoản catch-được bỏ qua. Tuy nhiên, nếu một trong các báo cáo trong các thử-mệnh đề throws anIllegalArgumentException, phần còn lại của try-khoản sẽ bị bỏ qua, và thực hiện chuyển giao cho các catch-clause. Chương trình luôn luôn tiếp tục các lệnh tiếp theo sau try-catch.
A Test Driver Class: TestMyTime.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// A test driver program for MyTime
public class TestMyTime {
public static void main(String[] args) {
MyTime t1 = new MyTime(23, 59, 58);
System.out.println(t1);
System.out.println(t1.nextSecond());
System.out.println(t1.nextSecond().nextSecond().nextSecond());

// MyTime t2 = new MyTime(12, 69, 69); // abrupt termination
// NOT continue to next statement

// Handling exception gracefully
try {
MyTime t3 = new MyTime(12, 69, 69);
// skip remaining statements in try, goto catch
System.out.println(t1);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
} // after try or catch, continue next statement

System.out.println("Continue after exception!");
}
}
Nếu không có sự hợp try-catch, “MyTime t2″ đột ngột sẽ chấm dứt chương trình (ví dụ, các phần còn lại của chương trình sẽ không được chạy). Với hợp xử lý try-catch, chương trình có thể tiếp tục hoạt động (ví dụ, xử lý duyên dáng của ngoại lệ).
Lập trình Java đối tượng theo định hướng

Nhận xét