Thong thường, các biển trường sẽ được đóng/bao gói với quyền truy cập.
(access modifiers) 6 các mức độ khác nhau. Để cập nhật và truy xuất chúng, ta thường dùng đến các phương thức đọc, ghỉ để định nghĩa ra một kênh giao tiếp (từ bên ngoài) tới chúng được an toàn và bảo mật. Do vậy, phạm vỉ truy cập của các phương thức này thường là từ mọi nơi của chương trình (được xác định bởi từ khóa publie).
Các phương thire ghi (setters) được gọi là phương thức thay đôi
(mutator methods), chúng được dùng để thiết lập các giá trị cho các biển trường.
Trong quá trình gán giá trị, cần có sự kiêm tra tính hợp lệ dữ liệu trước dé an toàn hơn. Còn các phương thức đọc (getters), hay được gọi là phương thức truy xuất (accessor methods), ching được dùng dé lay (get) giá trị của các biến trường.
Thông thường, mỗi một biến thành viên bỗ từ truy cập là private sẽ có.
một cặp phương thite getter, setter.
„._ Ví dụ 4.9: Sử dụng phương các phương thức set/getters để đọc và ghỉ các biến thể hiện hiện có bổ từ truy cập private.
pe * file name: LopChinh. java
*/
Package ctu.vdlinh.chapter4;
class HinhTron {
int x = 50, y= 50; //tọa độ tâm x, y private double bk; //ban kinh
public HinhTron(double bk) { this.bk = bk;
public HinhTron(int x, int y, đouble bk) { }
super();
this.x = x; this.y = ys" this.bk = bk;
zt public double getBk()r{
return\ bk3
} public void\setBk(double bk) { if (bk < 0.0) {
System.err.print]n("Bán kính phải có giá trị dương. ");
this.bk = bk; }
public double tinhDienTich() { }
return Math.PI * Math.pow(bk, 2);
- public class LopChinh {
public static void main(string[] args) {
HinhTron ht1 = new HinhTron(2@, 20, 10.379);
System.out.printf( "Diện tích hình tròn với bán kính= %..2f là:
%.2f\n", - ht1.getBk(), ht1. tỉnhDienTich());
ht1.setBk(5.5); // đổi bk =
System.ứut.printf( “Diện tớch hỡnh trũn với bỏn kớnh= %.2f là:
%.2f\n", - ht1.getBk(), h1. tinhD1enTich());
} ie
4.6 PHƯƠNG THỨC HUY
Khác với C and C++, sự thu hồi bộ nhớ được Java tự động thực hiện bởi Garbage collector, giúp cho ta thực hiện các yêu câu trước khi đôi tượng bị hủy (destructors), đú phương thức fùnalize(). Ta cú thể ghi chồng lại phương thức finalize() này để quan lý các đối tượng trong chương trình.
„.... Ví dụ 4.10: Viết chương trình dé định nghĩa kiểu lớp Cirele, sau đó đếm số đối tượng được tạo ra/ được huỷ khi chạy chương trình.
package ctu.vdlinh.chapter4;
"
* Created đate: 17-01-2011
* @author Vu Duy Linh
* File name: DemDoiTuong. java M
class Circle {
private int x, y; double radius; // biến thể hiện
private static int numOfCircles = @; // biến lớp
mà -Một số phương thức thể hiện ---
public Circle() {
ap super();
x=y =1; radius = 6.5;
nunOƒCircLes++;
} public Circle(int x, int y, double radius) { super();
this.x = x; this.y = y5 this.radius = radius;
numofCircles++s
} public double getRadius() { return radius;
} public void setRadius(double radius) { this.radius = radius;
= public static int getNumofcircle() { return numofcircles;
public double circumference() { +
return (get_2Pi() * radius);
void showInfo(String name){ }
System.out.printf(name + “ban kinh = %5.2f, va chu vi =
%10.4f \n", getRadius(); circumference());
} protected void finalize() throws Throwable { super. finalize();
= -numofcireles;
}
PE =
public static void setNumOfCircles(int numofCircles) {
Một Số phương thức lớp --
Circle.numOfCircLes = nunOfCircles;
private static double get_2Pi() { }
return 2 * Math.PT;
public class DenDoiTuong {
public static void main(String[] args) { Circle c1 = new Circle();
Circle c2 = new Circle(1, 29, 4.50);
new Circle(58, 59, 12.25);
Circle c3
Circle c4 = new Circle(166, 56, 7.89);
System.owt.print1n(*"Số đối tượng được tạo là:
Circle.getNumofcircle());
c1.shouTnfo("Hình tròn c1 có: *);
c2.showTnfo("Hình tròn c2 có: ");
c3.shouTnfo("Hình tròn c3 có: *);
c4.showTnfo("Hình tròn c4 có: ");
c3 = nu11;
Runtine.getRuntime().gc(); // System.gc();
system.runFinalization();
S5ystem.ứut.print1n("Số đối tượng cũn lại sau khi hủy là: "+
Circ1e.getNunoƒCircLe());
}
Kết quả chương trình:
Console £3
<terminated> DemDoiTuong [Java Application] C:\Program Files\Java\jdk1.7.0_45\) Số đối tượng
Hình trồn c1 và chủ vi = — 3.1416
Hình tròn c2 va chu vi 28.2743
Hình tron c3 va chu vi 76.9690
Hình tròn c4
Số đối tượng và chu vi = 49.0088
lại sau khi hủy là: 3
4/7 TRUYEN THAM SỐ.
Khi gọi phương thức có chứa tham số, ta cần phải truyền đối số cho nó.
Trong Java, vì không có khái niệm con trỏ, nên tắt cả các kiểu dữ liệu đều được truyền bằng tham trị (pass by value).
Đối với biến kiểu nguyên thủy (primitive type variable): Khi ta ra lời gọi phương thức thì Java sẽ tạo một bản sao của biển tham số thực và bản sao này sẽ truyền cho tham số hình thức £> giá trị của biến bản sao tham số thực này sẽ bằng với giá trị của biến tham số hình thức nhưng không ảnh hưởng đến giá trị
của tham số thực ban đầu.
Đối với biến kiểu tham chiéw/ déi tugng (reference! object type variable):
Java cũng truyền đối số bằng trị, nghĩa là giá trị (của) biến tham chiều của tham số thực sẽ được truyền cho biến tham chiếu của tham số hình thức. Như vậy, biến tham số thực và tham số hình thức đều tham chiếu đến cùng một đối tượng nên giá trị của chúng sẽ ảnh hưởng đến nhau.
Ví dụ 4.11: Minh họa truyền tham số đối với kiểu dữ liệu nguyên thủy và
đối tượng.
package ctu.vdlinh.chapter4 ye * Created date: 17-01-2011
* File name: PassParametters. java class HinhTron {
private int bk;
private String trThai;
public void setBk(int bk) { this.bk = bk;}
public void setTrThai(String trthai) { this.trThai = trThai;
@0verride }
public String toString() {
return "trạng thái; \"" + trThai“+ "\*'và bán kín
+ bk;
} public class PassParametters {
static void, passBy0bject(HinhTron ht2) {
ht2.setTrThai("Đã cập nhật!"); // thay đổi giá trị ht2, setBk(46) ;
} static void passByPrimitive(int a) { a = 200; // thay đổi giá trị của tsht public static void main(String[] args) { †
int x = 18; // tham số thực
System.out.print]n("‹*ằ Truyền tham số đối với kiểu nguyên thủy:");
System.out.primtln("\tằ›> Trước khi gọi phương thức passByPrimitive, x= " + x);
pass8yPrimitive(x);
System.out.println("\tằằ> Sau khi gọi phương thức passByPrimitive, x=" + x);
System.out.print1n("\n<*› Truyền tham số đối với kiểu đối tượng:");
HinhTron ht1 = new HinhTron(); - // tham số thực ht1.setTrThai ("Ban đầu."); _ ht1.setBk(388);
System.out.print1n(*\t>>> Trước khi gọi phương thức
passByObject, ht1:\n\t\t " + ht1.toString());
passBy0bject(ht1) ;
System.out.print1n("\n\t››>Sau khi gọi phương thức passByObject,hti:\n\t\t "+ hti.toString());
}
Nết quả chương trình:
-<terminated> PassParametters [Java Application] C:\Program Files\ava\jdk1.7.0 45°
<*› Truyền tham số đối với kiểu nguyên thủy: >>> Trước khi gọi phương thức passByPrimitive, x= 100
>>> Sau khi gọi phương thức passByPrimitive, x= 109
<*› Truyền tham số đối với kiểu đối tượng: >>> Trước khi gọi phương thức passByObject, ht1: trạng thái: "Ban đầu." và bán kính" 389
>>ằsau khi gọi phương thức pass8y0bject, h1:
trạng thái: "Đã cập nhật!” và bán kính= 409.
.. Sau đây là hình minh họa cho việc truyền đối với kiểu nguyên thủy và kiểu đối tượng trong ngôn ngữ Java
Ví dụ 4.12: Định nghĩa một lớp người dùng số thực (Complex), rồi sử
dụng nó đề tính các phép tính cụ thể.
i/Rile: Complex. java
package ctu.vdlinh. chapter;
yt * @author Robert Sedgewick
* @author Kenvin Wayne
* website: www.princeton.edu
public class Complex {
private final double re; // the real part private final double im; // the imaginary part
// create a new object with the given real and imaginary parts public Complex(double real, double imag) {
re = real;
im = imag;
} // return a stoing representation-of the invoking Complex object public String toString() {
if (im if (re
if (im < @) return
8) return re + "";
6) return im +
return re + "4" +
7/ return abs/modulus/magnitude and angle/phase/argument }
public double abs() {
// Math.sqrt(re*re + imtim) return Math.hypot(re, im);
public double phase() { }
// between -pi and pi return Math.atan2(im, re);
// return a new Complex object whose value is (this + b) public Complex plus(Complex b) {
Complex a = this; // invoking object double real = a.re + b.re;
double imag = a.im + b. im;
return new Complex(real, imag);
} // return a new Complex object whose value is (this - b) public Complex minus (Complex b) {
Complex a = this;
double real = a.re - b.re double imag = a.im - b. im;
return new Complex(real, imag);
} // return a new Complex object whose value is (this * b) public Complex times (Complex b) {
Complex a = this;
double real = a.re * b.re - a.im * b.im;
double imag = a.re * b.im + a.im * b.re;
return new Complex(real, imag);
} // scalar multiplication
// return a new object whose value is (this * alpha) public Complex times(double alpha) {
return new Complex(alpha * re, alpha * im);
+ // return a new Complex object whose value is the conjugate of this public Complex conjugate() {
return new Complex(re, -im);
// return a new Complex object whose value is the reciprocal of this }
public Complex reciprocal() {
đouble scale = re*re + in*im;
return new Conplex(re / scale, -im / scale);
// return the real or imaginary part public double re() {
return re;
public double im() { }
return im;
// return a/b }
public Complex divides (Complex b) { Complex a = this;
return a.times(b.reciprocal())5
/* return a new Complex object whose value is the complex }
exponential of this */
public Complex exp() {
return new Complex(Math.exp(re) * Math:€s(im), Math.exp(re)* Math, sin(im))5
+ /* return a new Complex object’ whose value is the complex sine of this */
public Complex sin() {
return new Complex(Math.sin(re) * Math.cosh(im), Math.cos(re) * Math.sinh(im));
} /* return a new Complex object whose value is the complex cosine of this */
public Complex cos() {
return new Complex(Math.cos(re) * Math.cosh(im), -Math.sin(re) * Math.sinh(im))5
a /* return a new Complex object whose value is the complex tangent of this */
public Complex tan() {
return sin().divides(cos());
J/ a static version of plus}
public static Complex plus(Complex a, Complex b) { double real = a.re + b.re;
double imag = a.im + b.im;
Complex sum = new Complex(real, imag);
return sum;
: Conp1exTest,
package_ctu.vd1inh..chapter4;
+ * website: www.princeton.edu
* pata type for complex numbers.
* The data type is “immutable” so once you create and initialize
* a Complex object, you cannot change it. The "final" keyword
* when declaring re and im enforces this rule, making it a
* compile-time error to change the .re or .im fields after
* they've been initialized.
public class ConplexTest { Sự
// sample client for testing
public static void main(string[] args) { Complex a = new Complex(5.0, 6.0);
Complex b = new Complex(-3.0, 4.6);
System.out.printin("a ays
system.out.print1n("b b);
system.out.println("Re(a) a.re())3 system. out. printIn(*"Im(a) a.im());
system.out.printin("b + a = system.out.printin("a - b = System.out.println(*a * b =
b.plus(a));
a.minus(b));
a.times(b));
+ b.times(a))5 a.divides(b));
system.out.printin("b * a =
System.out.printin("a / b
System.out.println("(a / b) *b_ = " + a.divides(b).times(b));
System.owt.print1n("conj (a) =" + a-conjugate())5 System.out.print1n(*a| =" + a.abs())5
System. out.printIn("tan(a) =" + a.tan());
} }
Kết quả chương trình:
a = 5.0 + 6.04
b 3.0 + 4.01
Re(a) 8
Im(a) = 6.0
b+a .0.+ 18.01
a-b 8.0 + 2.01
a*b 39.0 + 2.01
b*a 39.0 + 2.01
aso = 0.36 - 1.521 (a/b) *b =5.0+6.0i
conj(a) 5.0= 6.01
lal = 7,810249675906654
tan(a) 6.685231390246571E-6 + 1.0000103108981198i
4.8. TRUYỀN THÔNG ĐIỆP GIỮA CÁC ĐÓI TƯỢNG
Trong phương pháp lập trình hướng đối tượng, khi xây dựng mô hình các đối tượng, chúng ta cân phải xem xét đến những khả năng tương tác có thể có giữa chúng trong không gian bài toán đang xem xét. Sự tương tác này được thực hiện thông qua việc gửi
yêu cầu, nhận và đáp ứng yêu cầu giữa chúng. Sự yêu
cầu và đáp ứng yêu cầu như thể được thực hiện bởi cơ chế truyền thông điệp (messages).
“9: result S =
takeOrder
Benjamin Sean
Hình 4.8 Sự tương tác giữa đối tượng Benjamin va Sean
Ví dụ 4.13: Trong hệ thống, các đối tượng sẽ tương tác với nhau theo.
một kịch bản sẵn có, chăng hạn như khách hàng Benjamin gửi một thông điệp cho người bán hàng là Sean với yêu cầu *Tôi muốn đặt mua một bộ salon có 6 món, được giao vào thứ Từ tuần tới". Tiếp đến, Sean sẽ xem xét xem có thẻ đáp ứng được cho Benjamin không (như gọi về cửa hàng, kiểm tra hàng và lịch
) rồi sẽ thông báo kết quả đặt hàng lại cho anh ta là “Ok: Đồng ý, còn mặt hàng này” hoặc “Not ok: Xin lỗi, mặt hàng này đã hết”.
Message ơ zÊ Arguments va
takeOrder (so:
address, del iver
Benjamin
N— object Object —~
Hình 4.9 Sự tương tác giữa các đối tương bằng message
Với tình huống trong thể giới thực như trên, ta có cấu trúc lớp nhân viên,
Customer, và lớp người bán hàng, SalesPerson, như sau:
Class Customer
Customer
Attributes:
address name
at address
purchase) budget
Methods:
purchaseQ) {send a purchase request to a salesperson}
getBudget() {return budget}
“SalesP. ss SalesPerson Attributes:
: a name
Methods:
takeOrder) — {
check with warehouse on stock availability check with warehouse on delivery schedule if ok then {
instruct warehouse to deliver stock(address, date) return ok
else return not ok i
Với lớp Customer, tạo ra đối tượng khách hàng có tên là “Benjamin” '
như sau:
Benjamin as an Object Attributes:
name= "Benjamin"
address = "1, Robinson Road”
budget = 2000 Methods:
getBudget() {return budget}
purchase() {send a purchase request to a salesperson}
Với lớp SalesPerson, tạo ra đối tượng và 02 đối tượng bán hang la “Sean”
và *Sara” như sau:
Sean as an Object
Attributes:
name= "Sean"
Methods:
takeOrder)) {
check with warehouse on stock availability
check with warehouse on delivery schedule
ifok then {
instruct warehouse to deliver stock(address, date)
return ok
} else return not ok
Sara as an Object
Attributes:
name= "Sara"
Methods:
takeOrder() {
check with warehouse on stock availability check with warehouse on delivery schedule
if ok then {
instruct warehouse to deliver stock(address, date) return ok
} else return not ok
Như vậy: Thông điệp là một lời gọi phương thức từ một đối tượng gửi
thông điệp (message-sending object) tới đối tượng nhận thông điệp
(message-recciving object).. Đối tượng gửi thông điệp được gọi là sender còn đối tượng nhận thông điệp gọi là receiver. Ở ví dụ trên, Benjamin là sender còn
Sean la receiver.
Một thông điệp thi bao gồm 3 thành phi
~_ Định danh của đối tượng tiếp nhận thông điệp (receiver),
~ Tên phương thức (của đối tượng receiver),
..— Và các đối số (arguments) được truyền vào đẻ cung cấp thêm thông tin cần thiết để thực hiện phương thức trên.
Benjamin as an Object
Attributes:
name = "Benjamin"
address = "1, Robinson Road"
budget = 2000 Methods
purchase() {
Sean.takeOrder("Benjamin”, "sofa", "1, Robinson Road","12 November")
getBudget() {return budget} 1
Một thông điệp là hợp lệ nếu đối tượng receiver có một phương thức
(method) tương ứng với tên phương thức và các đối số phù hợp (nếu có) của thông điệp. Như vậy, đối tượng sender sẽ thực thi một phương thức nào đó, chăng hạn purchase(){...}, mà trong đó có lời gọi một phương thức của
tượng reciever để truyền thông điệp nhu takeOrder() {
Sean as an Object Attributes:
name = "Sean"
Methods
takeOrder(who, stock, address, date) { check with warehouse on stock availability check with warehouse on delivery schedule if ok then {
instruct warehouse to deliver stock to address on date return ok
} else return not ok
‡
Trong lập trình hướng đối tượng, đối tượng Benjamin và Sean được tuân
theo nguyên tắc che dấu thông tin (information hiding) vi Scan lim như thế nào để đáp ứng được yêu cầu của Benjamin là điều mà Benjamin không thể biết
hoặc bị che khuất
... Môhình khách — chủ (elient đối tượng luôn có dạng mô hình
reciever là phía server.
server): Trong quá trình trao đổi thông tin
\y; Đối tượng sender là phía client còn
đụ yes/no available?
send
Sean ok <⁄
Hình 4.10 Quá trình liên lạc giữa các đối tượng theo mô hình client-server
Benjamin
'Thông điệp mang lại 02 lợi ích quan trong, đó là: Các hành vi của một đối tượng được thể hiện thông qua phương thức của nó, và do đó (ngoài truy cập bien trực tiếp) nó hỗ trợ tắt cả các tương tác có thé có giữa các đối tượng. Và đôi
tượng không cần phải ở trong cùng một quá trình (proeess) hoặc thậm chí trên
cùng một máy đề gửi và nhận thông điệp qua lại với nhau.
Các thông điệp này được sử dụng trong biểu đồ tương tác (interaction diagram) dé thé hign cho các đối tượng tương tác với nhau. Biểu đô tương tác này là sự tổng quát hóa của cả biểu d6 twin tyr (sequence diagram) và biểu đồ
(collaboration diagram) được chuyên biệt từ nó.
j"""—~. ‘sd Retreive Balance (nt accountNumber) ni }
myBank : Bank ledger : accountLedger [acent: customerAccount
‘getBalance(aNum)
Hình 4.11 Minh họa messages trong sơ đồ tuần tự
(Source: Tech-ICT.com)
49 GÓI
Gói (package) là một cách để gom chung các kiểu dữ liệu (lớp, giao dign,...) c6 liên hệ với nhau thành một nhóm với phạm vi quyển truy xuất nhất định - việc quan trọng đồi với những dự án phát triền theo phương pháp lập trình
hướng đối tượng. Ngoài ra, nó còn được dùng đẻ phân vùng không gian tên (name space) để tránh xung đột tên (name) trong quá trình viết mã lệnh.
PockageName
ClassinThisPackage
Hình 4.12 Ky higu UML cua package
Hệ thống phân cấp của package được xác định thông qua từ khóa
package thường đứng trước việc định nghĩa cho một lớp.
Cú pháp: paekagetên gói[tên gói con];
class MyClass{
/imembers
Ví dụ 4.1
package mypackage.core;
class MyStack{
J/members
ạo lớp MyStack thuộc vào gói mypackage.core
Để sử dụng các lớp được định nghĩa trong package nào đó, ta nạp chúng vào lớp/giao diện hiện hành, UsingMyStack, thông qua tir khéa import như các cách sau:
= Nap tit cả các lớp trong mypackage.core vào lớp hiện hành
UsingMyStack:
import mypackage.core.*;
class UsingMyStack { J/members
- Hoặc chỉ nạp lớp MyStack vào lớp UsingMyStack như lệnh sau: }
import mypackage.core. MyStack;
class UsingMyStack{
members
truy xuất trực tiếp chúng thông qua dấu chấm phân cách trong
hệ thống phân cấp của gói:
class UsingMyStack{
mypackage.core, MyStack stackl =
new mypackage.core. MyStack();
Khi sử dụng gói, dự án cần phải được xác định phạm vi truy cập ở mức } } lớp, mức các thành viên lớp/giao diện của các gói sao cho cho có thẻ truy xuất được với nhau.
Dưới đây là bảng mô tả phạm vỉ truy cập của các thành viên giữa các lớp
€ oi:
Quyền truy xuất. KG Biches eee peat
Pham vi =
Ở cùng lớp. Yes Yes Yes Yes
Ở khác lớp và cùng gói Yes Yes Yes No
Ở lớp con và cùng gói Yes Yes Yes No
Ở lớp con và khác gói Yes Yes No No
O khác lớp và khác gói Yes No No No
'Ví dụ 4.15: Viết chương trình giải phương trình bậc 2 gồm hai lớp được.
đặt trong hai gói khác nhau như hình 4.13
Hf Package Explorer 2 BSle 7
4 ÊJ VD_PTB2 4 Bsc
4 {8 ctuvdlinh.obp.packagel 4 [) PTB2java
4 © PTB2
aa 2b
& PTB2(double, double, double) ac
© tinhPTB20 : void 4 { ctuvdlinh.obp.package2
4 {D) MainClassjave
Q MainClass
6Ÿ main(String[]) : void
4 BÀ, JRE System Library [J2v2SE-1.7]
Hình 4.13. Cấu trúc dự án giải phương trình bậc hai