Think Java: Cách suy nghĩ nh

ư nhà khoa h c

ọ

máy tính

Phiên bản 5.1.2

Xem thêm ở Facebook.

Think Java là cuốn sách giới thiệu về lập trình Java cho người mới học. Nó được soạn riêng cho học viên chuẩn bị

thi Computer Science Advanced Placement (AP) Exam,

nhưng cũng dành cho bất kì ai muốn học Java.

• Think Java rất ngắn gọn. Sách chỉ dùng một bộ phận nhỏ

của ngôn ngữ Java đủ để giúp học viên thực hiện những bài

tập lớn mà không bị sa đà vào những tiểu tiết của ngôn ngữ

lập trình.

• Think Java dạy cách phát triển và gỡ lỗi chương trình; những chủ đề này được thảo luận trong suốt cuốn sách

và được tóm tắt trong hai phụ lục.

• Think Java bao gồm cả nghiên cứu cụ thể GridWorld vốn là một phần của đề thi AP. Cuốn sách này cung cấp kiến thức

cơ sở cần để làm quen với GridWorld, cùng với những bài

tập phụ thêm để thực hành.

• Think Java được viết theo cuốn sách gốc How to Think Like a Computer Scientist, một cuốn sách trực tuyến quen

thuộc với những phiên bản cho lập trình Python, C++ và

OCaml, cùng với những bản dịch sang tiếng Tây Ban Nha,

tiếng Pháp và những thứ tiếng khác.

Think Java là sách giáo trình t

ự do đư c

ợ phát hành theo gi y

ấ phép Creative Commons Attribution-

NonCommercial-ShareAlike 3.0 Unported License. B n ạ đọc có th

ể tùy ý sao chép và phân ph i

ố n i

ộ

dung trong sách; đ ng

ồ th i

ờ cũng tùy ý s a

ử đ i

ổ đ

ể phù h p

ợ v i

ớ yêu c u

ầ c

ụ th ,

ể và đ

ể phát tri n

ể n i

ộ dung

gi n

ả g d y

ạ m i

ớ .

M c

ụ l c

ụ

Chương 1: Lối đi của chương trình máy tính

Chương 11: Tự tạo nên những đối tượng riêng

Chương 2: Biến, biểu thức và câu lệnh

Chương 12: Mảng

Chương 3: Phương thức rống

Chương 13: Mảng các đối tượng

Chương 4: Câu lệnh điều kiện và đệ quy

Chương 14: Đối tượng chứa các mảng

Chương 5: GridWorld: Phần 1

Chương 15: Lập trình hướng đối tượng

Chương 6: Phương thức trả giá trị

Chương 16: Grid World: Phần 3

Chương 7: Lặp

Phụ lục A: Đồ họa

Chương 8: Chuỗi kí tự

Phụ lục B: Nhập và xuất dữ liệu ở Java

Chương 9: Đối tượng có thể biến đổi

Phụ lục C: Phát triển chương trình

Chương 10: GridWorld: Phần 2

Phụ lục D: Gỡ lỗi

Chư ng

ơ

0. L i

ờ nói đ u

ầ

““Khi được hưởng những Thành qu

ả l n

ớ t

ừ Phát minh c a

ủ ngư i

ờ khác, ta nên vui v

ẻ đó

nh n

ậ Cơ h i

ộ đ

ể giúp đ

ỡ ngư i

ờ khác b ng

ằ Phát minh c a

ủ ta, và vi c

ệ này nên làm m t

ộ cách tự

ý và hào phóng.”

—Benjamin Franklin, trích t

ừ cu n

ố Benjamin Franklin c a

ủ tác gi

ả Edmund S. Morgan.

Lý do mà tôi viết cu n

ố sách này

Đây là n

ấ b n

ả th

ứ năm c a

ủ cu n

ố sách mà tôi đã b t

ắ đ u

ầ vi t

ế t

ừ năm 1999, khi còn d y

ạ

ở trư ng

ờ Colby

College. Tôi d

ẫ d y

ạ m t

ộ l p

ớ h c

ọ nh p

ậ môn khoa h c

ọ máy tính b ng

ằ ngôn ng

ữ Java, nh ng

ư ch a

ư tìm

được một cuốn giáo trình v a

ừ ý. M t

ộ trong nh ng

ữ lý do là, chúng quá dày! Không có cách nào mà sinh

viên có th

ể đọc h t

ế cu n

ố sách dày c

ỡ 800 trang, đ y

ầ nh ng

ữ ki n

ế th c

ứ kĩ thu t

ậ , k

ể c

ả tôi có yêu c u

ầ h

ọ

thực hi n.

ệ Mà tôi ch ng

ẳ mu n

ố th .

ế Ph n

ầ l n

ớ nh ng

ữ gì vi t

ế trong sách đ u

ề quá c

ụ th —nh

ể

ng

ữ chi ti t

ế v

ề

Java cùng các thư vi n

ệ c a

ủ nó mà s

ẽ l c

ạ h u

ậ ngay khi h c

ọ kì k t

ế thúc, đ ng

ồ th i

ờ nh ng

ữ th

ứ đó s

ẽ làm lu

mờ những ki n

ế th c

ứ mà tôi th c

ự s

ự mu n

ố sinh viên h c

ọ .

Một v n

ấ đ

ề khác mà tôi th y

ấ , đó là ph n

ầ gi i

ớ thi u

ệ l p

ậ trình hư ng

ớ đ i

ố tư ng

ợ là quá đ t

ộ ng t

ộ . Nhi u

ề

sinh viên đáng ra đã h c

ọ suôn s

ẻ r i

ồ nh ng

ư khi b t

ắ đ u

ầ vào ph n

ầ “đ i

ố tư ng

ợ ” là b ịv p,

ấ b t

ấ k

ể ph n

ầ này

được đưa vào đâu trong giáo trình.

Vì v y

ậ tôi b t

ắ tay vào vi t

ế . M i

ỗ ngày tôi vi t

ế m t

ộ chư ng

ơ , liên t c

ụ trong 13 ngày đ u

ầ . R i

ồ ngày th

ứ 14 tôi

biên t p

ậ l i

ạ . Sau đó tôi đi phô-tô và đóng bìa. Bu i

ổ h c

ọ đ u

ầ tiên khi phân phát giáo trình, tôi d n

ặ sinh

viên mỗi tu n

ầ ph i

ả đ c

ọ m t

ộ chư ng

ơ . Nói cách khác, h

ọ c n

ầ đ c

ọ ch m

ậ h n

ơ 7 l n

ầ so v i

ớ t c

ố đ

ộ vi t

ế c a

ủ

tôi.

Tri t

ế lý n

ẩ sau cu n

ố sách

Sau đây là m t

ộ s

ố ý tư ng

ở đ nh

ị hình cho cu n

ố sách:

• Thu t

ậ ngữ là quan tr ng

ọ . Sinh viên c n

ầ ph i

ả trao đ i

ổ đư c

ợ v

ề chư ng

ơ trình máy tính và hi u

ể đư c

ợ đi u

ề

tôi gi n

ả g. Tôi c

ố g ng

ắ gi i

ớ thi u

ệ m t

ộ s

ố t i

ố thi u

ể các thu t

ậ ng ,

ữ đ

ể đ nh

ị nghĩa đư c

ợ rõ ràng khi dùng l n

ầ

đ u

ầ , và đ

ể tổ ch c

ứ l i

ạ thành m c

ụ “Thu t

ậ ng ”

ữ cu i

ố t ng

ừ chư ng

ơ . Trên l p,

ớ tôi có đ a

ư nh ng

ữ câu h i

ỏ liên

quan đ n

ế thu t

ậ ng

ữ vào đ

ề ki m

ể tra, đ

ề thi, và yêu c u

ầ sinh viên ph i

ả dùng thu t

ậ ng

ữ thích h p

ợ đ

ể vi t

ế

vào đáp án.

• Để viết một chương trình, sinh viên c n

ầ ph i

ả hi u

ể đư c

ợ thu t

ậ toán, bi t

ế ngôn ng

ữ l p

ậ trình, và có kh

ả

năng g

ỡ lỗi. Tôi nghĩ r ng

ằ quá nhi u

ể quy n

ể sách b

ỏ qua khâu g

ỡ l i

ỗ . Cu n

ố sách này có m t

ộ ph

ụ l c

ụ vi t

ế

về gỡ lỗi và một ph

ụ l c

ụ v

ề phát tri n

ể chư ng

ơ trình (giúp tránh đư c

ợ g

ỡ l i

ỗ ). Tôi khuy n

ế khích sinh viên

sớm đọc ngay nh ng

ữ ph n

ầ này và thư ng

ờ xuyên tham kh o

ả đ n

ế chúng.

• Một số khái ni m

ệ ph i

ả m t

ấ th i

ờ gian m i

ớ l ng

ắ đ ng

ọ l i

ạ đư c

ợ . M t

ộ s

ố ch

ỗ khó trong sách, nh

ư đ

ệ quy, sẽ

xu t

ấ hiện vài l n.

ầ B ng

ằ cách nêu l i

ạ nh ng

ữ đi m

ể này, tôi c

ố g n

ắ g t o

ạ cho sinh viên c

ơ h i

ộ đ

ể ôn l i

ạ và

c ng

ủ cố, ho c

ặ n u

ế l n

ầ đ u

ầ h

ọ không n m

ắ đư c

ợ , thì đó là c

ơ h i

ộ đ

ể theo k p

ị .

• Tôi cố g ng

ắ dùng càng ít Java càng t t

ố đ

ể đ t

ạ đư c

ợ công hi u

ệ l p

ậ trình t i

ố đa. M c

ụ đích c a

ủ cu n

ố sách

này là d y

ạ l p

ậ trình và m t

ộ s

ố ý tư ng

ở c

ơ b n

ả v

ề khoa h c

ọ máy tính, ch

ứ không ph i

ả d y

ạ Java. Tôi b

ỏ

qua một số đ c

ặ đi m

ể c a

ủ ngôn ng

ữ này, nh

ư l nh

ệ switch, vốn không c n

ầ thi t

ế , và tránh h u

ầ h t

ế các th

ư

viện chương trình, đ c

ặ bi t

ệ nh ng

ữ th

ư vi n

ệ nh

ư AWT v n

ố đã thay đ i

ổ quá nhanh ho c

ặ có xu hư ng

ớ l i

ỗ

thời, ph i

ả thay th .

ế

Phương pháp ti p

ế c n

ậ theo xu hư ng

ớ “t i

ố thi u

ể ” nh

ư v y

ậ có m t

ộ s

ố u

ư đi m

ể . T ng

ừ chư ng

ơ ch ỉdài

kho n

ả g 10 trang, không kể bài t p.

ậ Trên l p,

ớ tôi yêu c u

ầ sinh viên đ c

ọ m i

ỗ chư ng

ơ trư c

ớ khi th o

ả lu n,

ậ

và th y

ấ được r n

ằ g h

ọ s n

ẵ sàng th c

ự hi n

ệ và n m

ắ b t

ắ đư c

ợ lư ng

ợ ki n

ế th c

ứ . S

ự chu n

ẩ b ịtrư c

ớ c a

ủ sinh

viên đã giúp dành kho n

ả g th i

ờ gian trên l p

ớ đ

ể th o

ả lu n

ậ nh ng

ữ n i

ộ dung tr u

ừ tư ng

ợ h n,

ơ đ

ể làm bài

t p

ậ trên l p,

ớ và nh ng

ữ ch

ủ đ

ề thêm không có trong sách.

Nhưng xu hư ng

ớ “tối thi u

ể ” cũng có nh ng

ữ như c

ợ đi m

ể . Không có nhi u

ề ch

ỗ thú v ịv

ề b n

ả ch t

ấ . Đa s

ố

các ví dụ trong sách nh m

ằ minh h a

ọ cho cách s

ử d n

ụ g c

ơ b n

ả nh t

ấ c a

ủ ngôn ng ,

ữ và nhi u

ề bài t p

ậ có

liên quan đ n

ế thao tác chu i

ỗ kí t

ự và khái ni m

ệ toán h c

ọ . Tôi nghĩ m t

ộ s

ố bài thì thú v ,ị song nh ng

ữ th

ứ

làm sinh viên thích ngành khoa h c

ọ máy tính, nh

ư đ

ồ h a

ọ , âm thanh và ng

ứ d ng

ụ m n

ạ g, l i

ạ ch ỉđư c

ợ

giới thi u

ệ qua loa.

V n

ấ đ

ề n m

ằ

ở ch

ỗ ph n

ầ l n

ớ các đ c

ặ đi m

ể thú v ịnh

ư v y

ậ thì liên quan t i

ớ chi ti t

ế v t

ặ mà ít liên quan đ n

ế

khái ni m

ệ . Xét trên khía c nh

ạ giáo d c

ụ , đi u

ề này có nghĩa là nhi u

ề công s c

ứ b

ỏ ra đ

ể thu đư c

ợ ít. Nh

ư

v y

ậ có một s

ự tráo đ i

ổ gi a

ữ n i

ộ dung mà sinh viên a

ư thích và n i

ộ dung mang đ m

ậ tri th c

ứ . Vi c

ệ gi

ữ cân

b n

ằ g hợp lý, tôi như ng

ờ l i

ạ cho giáo viên đ n

ứ g l p.

ớ Đ

ể giúp ph n

ầ nào, cu n

ố sách này có ph

ụ l c

ụ đ

ề c p

ậ

đến đồ họa, nh p

ậ li u

ệ t

ừ bàn phím và t

ừ t p

ậ tin.

L p

ậ trình hư n

ớ g đối tư n

ợ g

Một số quy n

ể sách gi i

ớ thi u

ệ ngay khái ni m

ệ đ i

ố tư ng

ợ ; l i

ạ có quy n

ể d o

ạ đ u

ầ b ng

ằ phong cách l p

ậ trình

th

ủ t c

ụ và d n

ầ d n

ầ xây d ng

ự phong cách hư ng

ớ đ i

ố tư ng

ợ . Cu n

ố sách này thì theo l i

ố “gi i

ớ thi u

ệ đ i

ố

tượng sau”.

Nhi u

ề đ c

ặ đi m

ể hư ng

ớ đ i

ố tư ng

ợ c a

ủ Java kh i

ở ngu n

ồ t

ừ các v n

ấ đ

ề đ t

ặ ra cho ngôn ng

ữ đi trư c

ớ , và

cách th c

ự hi n

ệ nh ng

ữ đ c

ặ đi m

ể này ch u

ị nh

ả hư ng

ở b i

ở quá trình l c

ị h s .

ử M t

ộ s

ố đ c

ặ đi m

ể r t

ấ khó gi i

ả

thích n u

ế ngư i

ờ h c

ọ không th o

ạ nh ng

ữ bài toán c n

ầ gi i

ả .

Việc hoãn l i

ạ kĩ thu t

ậ l p

ậ trình hư ng

ớ đ i

ố tư ng

ợ không ph i

ả là ch

ủ ý c a

ủ tôi. Trái l i

ạ , tôi c

ố g n

ắ g t i

ớ đó

càng nhanh càng t t

ố , song b ịh n

ạ ch

ế b i

ở ý mu n

ố gi i

ớ thi u

ệ l n

ầ lư t

ợ t ng

ừ khái ni m

ệ m t

ộ , th t

ậ rõ ràng,

theo cách mà sinh viên có th

ể th c

ự hành riêng t ng

ừ khái ni m

ệ trư c

ớ khi chuy n

ể ti p.

ế Nh ng

ư cũng ph i

ả

thừa nh n

ậ r n

ằ g ph i

ả m t

ấ m t

ộ th i

ờ gian h c

ọ m i

ớ đ n

ế đư c

ợ ph n

ầ hư ng

ớ đ i

ố tư ng

ợ .

Kì thi Computer Science AP

Theo l

ẽ thường, khi đư c

ợ bi t

ế r ng

ằ H i

ộ đ ng

ồ tuy n

ể sinh (College Board) công b

ố r ng

ằ n i

ộ dung thi AP

sẽ chuy n

ể sang dùng Java, tôi đã có k

ế ho c

ạ h c p

ậ nh t

ậ phiên b n

ả Java c a

ủ cu n

ố sách này. Đ i

ố chi u

ế v i

ớ

đề cương AP được đưa ra, tôi th y

ấ r ng

ằ b

ộ ph n

ậ nh

ỏ c a

ủ Java dùng đ

ể thi r t

ấ gi ng

ố v i

ớ b

ộ ph n

ậ mà tôi

đã chọn.

Trong tháng 1 năm 2003, tôi đã so n

ạ n

ấ b n

ả th

ứ 4 c a

ủ cu n

ố sách, v i

ớ nh ng

ữ s a

ử đ i

ổ sau:

• Tôi đã thêm vào các m c

ụ nh m

ằ bao quát đư c

ợ n i

ộ dung trong đ

ề cư ng

ơ thi AP.

• Tôi hoàn thi n

ệ các ph

ụ l c

ụ v

ề g

ỡ l i

ỗ và phát tri n

ể chư ng

ơ trình.

• Tôi đi t p

ậ h p

ợ l i

ạ nh ng

ữ bài t p,

ậ câu đ ,

ố và câu h i

ỏ thi đã ra trên l p

ớ r i

ồ đ a

ư vào cu i

ố các chư ng

ơ , ngoài

ra còn so n

ạ thêm một số câu h i

ỏ giúp chu n

ẩ b ịkì thi AP.

Cu i

ố cùng, vào tháng 8-2011, tôi vi t

ế xong n

ấ b n

ả th

ứ 5, bao quát đư c

ợ ph n

ầ nghiên c u

ứ c

ụ th

ể

GridWorld là n i

ộ dung trong kì thi AP.

Sách phát hành t d

ự o

Ngay t

ừ đ u

ầ , cu n

ố sách này đã theo gi y

ấ phép mà b n

ạ đ c

ọ đư c

ợ quy n

ề sao chép, phân ph i

ố và s a

ử ch a

ữ

nội dung. Độc giả có th

ể t i

ả sách v

ề v i

ớ nhi u

ề đ nh

ị d n

ạ g khác nhau và có th

ể đ c

ọ trên màn hình ho c

ặ in

ra gi y

ấ . Giáo viên có th

ể in bao nhiêu b n

ả tùy ý. Và m i

ọ ngư i

ờ đ u

ề có th

ể s a

ử đ i

ổ sách theo nhu c u

ầ .

Đã có ngư i

ờ chuy n

ể n i

ộ dung cu n

ố sách sang cho nh ng

ữ ngôn ng

ữ l p

ậ trình khác (nh

ư Python và Eiffel),

và nh ng

ữ th

ứ ti ng

ế khác (nh

ư Tây Ban Nha, Pháp, và Đ c

ứ ). Trong s

ố đó, nhi u

ề phiên b n

ả đư c

ợ đăng

theo hình th c

ứ t

ự do.

Với động l c

ự t

ừ Ph n

ầ m m

ề ngu n

ồ m ,

ở tôi đã đón nh n

ậ tri t

ế lý phát hành sách th t

ậ s m

ớ và c p

ậ nh t

ậ

thường xuyên. Tôi đã c

ố g ng

ắ h t

ế s c

ứ đ

ể gi m

ả thi u

ể các l i

ỗ , nh ng

ữ cũng nh

ờ b n

ạ đ c

ọ giúp s c

ứ .

Tinh hình ph n

ả h i

ồ th t

ậ tuy t

ệ . G n

ầ nh

ư ngày nào tôi cũng nh n

ậ đư c

ợ thông tin t

ừ b n

ạ đ c

ọ , v i

ớ s

ự a

ư

thích cuốn sách đ n

ế n i

ỗ h

ọ g i

ử h n

ẳ m t

ộ “danh sách li t

ệ kê l i

ỗ ”. Thông thư ng

ờ tôi ch a

ữ m t

ộ l i

ỗ m t

ấ vài

phút và sau đó c p

ậ nh t

ậ ngay b n

ả th o

ả qua s a

ử đ i

ổ . Tôi coi cu n

ố sách nh

ư m t

ộ tác ph m

ẩ đang trong quá

trình hoàn thi n,

ệ sẽ đư c

ợ c i

ả ti n

ế ít m t

ộ m i

ỗ khi tôi có th i

ờ gian so n

ạ l i

ạ , ho c

ặ khi b n

ạ đ c

ọ g i

ử ph n

ả h i

ồ .

À, còn về tiêu đề

Tôi đã th t

ậ bu n

ồ phi n

ề v

ề tiêu đ

ề cu n

ố sách Không ph i

ả ai cũng hi u

ể đư c

ợ r ng

ằ ch

ủ y u

ế đó ch ỉlà cách

nói đùa. Có th

ể sau khi đ c

ọ cu n

ố sách này, b n

ạ ch a

ư t

ư duy đư c

ợ nh

ư nhà khoa h c

ọ máy tính. Đi u

ề đó

c n

ầ th i

ờ gian, kinh nghi m

ệ , và có th

ể ph i

ả qua m y

ấ l p

ớ h c

ọ n a

ữ .

Nhưng có một đi m

ể c t

ố lõi có th t

ậ

ở tiêu đ

ề này: cu n

ố sách này không ph i

ả vi t

ế v

ề Java, và nó ch ỉm t

ộ

ph n

ầ là về l p

ậ trình. N u

ế có chăng, s

ự thành công

ở cu n

ố sách là n m

ằ ch

ỗ m t

ộ cách nghĩ m i

ớ . Nhà khoa

học máy tính luôn có m t

ộ cách ti p

ế c n

ậ đ

ể gi i

ả quy t

ế v n

ấ đ ,

ề và m t

ộ cách đ n

ị h hình l i

ờ gi n,

ả r t

ấ đ c

ộ

đáo, linh ho t

ạ và m nh

ạ mẽ. Tôi hi v ng

ọ r ng

ằ cu n

ố sách này giúp b n

ạ hình dung đư c

ợ phư ng

ơ pháp đó

là gì, và

ở nh ng

ữ lúc nào đó b n

ạ s

ẽ t

ự th y

ấ mình có t

ư duy nh

ư nhà khoa h c

ọ máy tính.

Allen B. Downey

Needham Massachusett, Hoa Kì

13-7-2011

Danh sách b n

ạ đ c

ọ đã đóng góp nội dung

Khi b t

ắ đầu vi t

ế sách thể lo i

ạ t

ự do, tôi v n

ẫ ch a

ư có ý đ nh

ị l p

ậ danh sách đóng góp t

ừ phía b n

ạ đ c

ọ . R i

ồ

Jeff Elkner đ

ề xu t

ấ , và rõ ràng tôi đã t

ỏ ra lúng túng vì thi u

ế sót này. Danh sách dư i

ớ đây tính t

ừ n

ấ b n

ả

thứ 4, vì v y

ậ nó không có tên nhi u

ề ngư i

ờ đã đóng góp, s a

ử đ i

ổ t

ừ trư c

ớ đó.

Nếu b n

ạ có b t

ấ kì nh n

ậ xét nào thêm, hãy g i

ử th

ư v

ề đ i

ạ chỉ feedback@greenteapress.com

• Ellen Hildreth đã dùng sách này đ

ể d y

ạ môn h c

ọ C u

ấ trúc d

ữ li u

ệ

ở trư ng

ờ Wellesley College, và cô đã

gửi một lo t

ạ nh ng

ữ ch

ỗ c n

ầ đính chính, kèm theo m t

ộ s

ố đ

ề xu t

ấ hay.

• Tania Passfield ch ỉra r ng

ằ ph n

ầ Thu t

ậ ng

ữ cu i

ố Chư ng

ơ 4 đã ghi th a

ừ m t

ộ s

ố m c

ụ không có trong sách.

• Elizabeth Wiethoff nh n

ậ th y

ấ cách tôi khai tri n

ể exp(− x 2) là sai. Cô cũng đã so n

ạ ra m t

ộ phiên b n

ả sách

dùng ngôn ngữ l p

ậ trình Ruby!

• Matt Crawford đã g i

ử m t

ộ file “b n

ả vá” đ y

ầ nh ng

ữ ch

ỗ c n

ầ s a

ử !

• Chi-Yu Li ch ỉra m t

ộ l i

ỗ typo và m t

ộ l i

ỗ trong mã l nh

ệ ví d .

ụ

• Doan Thanh Nam ch a

ữ l i

ạ m t

ộ ví d

ụ

ở Chư ng

ơ 3.

• Stijn Debrouwere phát hi n

ệ m t

ộ typo trong bi u

ể th c

ứ toán.

• Muhammad Saied d c

ị h cu n

ố sách sang ti ng

ế A-r p,

ậ và phát hi n

ệ m t

ộ s

ố l i

ỗ .

• Marius Margowski phát hi n

ệ m t

ộ đi m

ể không nh t

ấ quán trong mã l nh

ệ ví d .

ụ

• Guy Driesen phát hi n

ệ m t

ộ s

ố l i

ỗ typo.

• Leslie Klein phát hi n

ệ m t

ộ ch

ỗ sai khác trong cách khai tri n

ể exp(− x 2), phát hi n

ệ các typo trong hình v

ẽ

bi u

ể di n

ễ m n

ả g ch a

ứ các quân bài, và có đ

ề xu t

ấ hay giúp cho bài t p

ậ đư c

ợ rõ ràng h n.

ơ

Sau cùng, tôi xin đư c

ợ cám n

ơ Chris Mayfield đã đóng góp đáng k

ể cho phiên b n

ả 5.1 c a

ủ sách. Qua vi c

ệ

ph n

ả bi n

ệ c n

ẩ th n,

ậ ông đã ch ỉra h n

ơ m t

ộ trăm ch

ỗ c n

ầ s a

ử và b

ổ sung. M t

ộ s

ố đ c

ặ đi m

ể m i

ớ g m

ồ có

liên k t

ế đ n

ế các trang web và liên k t

ế chéo gi a

ữ các m c

ụ trong sách, s

ự trình bày nh t

ấ quán v

ề hình th c

ứ

cho các bài t p,

ậ và tô màu mã l nh

ệ Java [ch ỉcó

ở sách g c

ố ].

Ch

ng

ươ 1: L i

ố đi c a

ủ ch ng

ươ trình máy tính

Trở về M c

ụ l c

ụ cuốn sách M c

ụ đích c a

ủ cu n

ố sách này là hư ng

ớ d n

ẫ b n

ạ suy nghĩ nh

ư là m t

ộ nhà khoa h c

ọ máy tính. Tôi thích l i

ố

suy nghĩ c a

ủ nh ng

ữ nhà khoa h c

ọ máy tính vì

ở đó có s

ự k t

ế h p

ợ nh ng

ữ đ c

ặ đi m

ể hay nh t

ấ c a

ủ toán học,

kĩ thuật, và khoa h c

ọ t

ự nhiên. Cũng nh

ư nh ng

ữ nhà toán h c

ọ , nh ng

ữ nhà khoa h c

ọ máy tính dùng

những ngôn ngữ có quy cách để di n

ễ đ t

ạ ý tư ng

ở (đ c

ặ bi t

ệ là tính toán). Gi ng

ố nh

ư nh ng

ữ kĩ s ,

ư h

ọ

cũng làm công vi c

ệ thi t

ế k ,

ế g n

ắ k t

ế các thành ph n

ầ t o

ạ nên m t

ộ h

ệ th ng

ố và đánh giá nh ng

ữ u

ư khuy t

ế

giữa các phư ng

ơ án khác nhau. Gi ng

ố nh

ư nh ng

ữ nhà khoa h c

ọ , h

ọ kh o

ả sát các đ ng

ộ thái c a

ủ h

ệ th ng

ố

phức t p

ạ , đề ra các gi

ả thi t

ế , và ki m

ể đ nh

ị nh ng

ữ tính toán.

Kĩ năng quan tr ng

ọ nh t

ấ c a

ủ nhà khoa h c

ọ máy tính là giải quy t

ế v n

ấ đề. Gi i

ả quy t

ế v n

ấ đ

ề chính là

cách t o

ạ l p

ậ v n

ấ đ ,

ề suy nghĩ gi i

ả pháp m t

ộ cách sáng t o

ạ , và trình bày gi i

ả pháp m t

ộ cách rõ ràng và

chính xác. Nh

ư b n

ạ s

ẽ th y

ấ , vi c

ệ h c

ọ l p

ậ trình chính là m t

ộ c

ơ h i

ộ tuy t

ệ v i

ờ đ

ể b n

ạ luy n

ệ t p

ậ nh ng

ữ kĩ

năng gi i

ả quy t

ế v n

ấ đ .

ề Đó là lí do t i

ạ sao chư ng

ơ này l i

ạ có tên là “L i

ố đi c a

ủ chư ng

ơ trình máy tính”.

Một m t

ặ , b n

ạ s

ẽ đư c

ợ h c

ọ cách l p

ậ trình, v n

ố b n

ả thân nó là m t

ộ kĩ năng h u

ữ d n

ụ g. M t

ặ khác, b n

ạ s

ẽ

dùng l p

ậ trình nh

ư m t

ộ phư ng

ơ ti n

ệ đ

ể gi i

ả quy t

ế v n

ấ đ .

ề Đi u

ề này b n

ạ s

ẽ d n

ầ d n

ầ làm đư c

ợ trong quá

trình học.

1.1 Ngôn ng l

ữ p t

ậ rình là gì?

Ngôn ngữ l p

ậ trình mà b n

ạ sẽ h c

ọ là Java, v n

ố là m t

ộ ngôn ng

ữ tư ng

ơ đ i

ố m i

ớ (phiên b n

ả đ u

ầ tiên do

Sun phát hành vào tháng 5-1995). Java là m t

ộ ví d

ụ trong s

ố các ngôn ng

ữ l p

ậ trình b c

ậ cao; một số

ngôn ng

ữ l p

ậ trình b c

ậ cao khác mà b n

ạ có th

ể bi t

ế đ n

ế g m

ồ có Python, C, C++, và Perl.

Nh c

ắ đ n

ế “ngôn ngữ l p

ậ trình b c

ậ cao”, có l

ẽ b n

ạ cũng suy đoán đư c

ợ r ng

ằ còn nh ng

ữ ngôn ng

ữ l p

ậ

trình b c

ậ th p

ấ , đôi khi mà ta g i

ọ là “ngôn ng

ữ máy” ho c

ặ “h p

ợ ng ”.

ữ Nói nôm na, máy tính ch ỉcó th

ể

thực hi n

ệ các chư ng

ơ trình đư c

ợ vi t

ế b ng

ằ ngôn ng

ữ b c

ậ th p

ấ . Vì v y

ậ nh ng

ữ chư ng

ơ trình đư c

ợ vi t

ế

b n

ằ g một ngôn ngữ b c

ậ cao c n

ầ đư c

ợ x

ử lý trư c

ớ khi chúng có th

ể ch y

ạ đư c

ợ . Bư c

ớ ph

ụ tr

ợ này s

ẽ t n

ố

thêm thời gian, đây là m t

ộ như c

ợ đi m

ể nh

ỏ c a

ủ các ngôn ng

ữ b c

ậ cao.

Tuy v y

ậ , các u

ư đi m

ể là r t

ấ l n.

ớ Th

ứ nh t

ấ , vi c

ệ l p

ậ trình b ng

ằ ngôn ng

ữ b c

ậ cao d

ễ h n

ơ nhi u

ề . Chương

trình đư c

ợ vi t

ế b ng

ằ ngôn ngữ b c

ậ cao đư c

ợ vi t

ế nhanh h n,

ơ n i

ộ dung chư ng

ơ trình ng n

ắ h n,

ơ d

ễ đ c

ọ

hơn, và nhi u

ề kh

ả năng là chúng chính xác. Th

ứ hai, các ngôn ng

ữ b c

ậ cao có tính kh

ả chuy n

ể theo

nghĩa ch y

ạ đư c

ợ trên nhi u

ề h

ệ máy tính khác nhau mà ít ho c

ặ không c n

ầ ph i

ả s a

ử đ i

ổ . Các chư ng

ơ trình

b c

ậ th p

ấ chỉ có th

ể ch y

ạ trên m t

ộ lo i

ạ máy tính và ph i

ả đư c

ợ vi t

ế l i

ạ n u

ế mu n

ố ch y

ạ trên các h

ệ máy

khác.

B i

ở các u

ư đi m

ể nêu trên, h u

ầ h t

ế các chư ng

ơ trình đ u

ề đư c

ợ l p

ậ trình b ng

ằ ngôn ng

ữ b c

ậ cao. Các

ngôn ng

ữ b c

ậ th p

ấ chỉ được dùng cho m t

ộ s

ố ít nh ng

ữ ng

ứ d ng

ụ đ c

ặ bi t

ệ .

Hai lo i

ạ chư ng

ơ trình có nhi m

ệ v

ụ chuy n

ể đ i

ổ các ngôn ng

ữ b c

ậ cao v

ề d ng

ạ ngôn ng

ữ b c

ậ th p:

ấ trình

thông d c

ị h và trình biên d c

ị h. Trình thông d c

ị h là m t

ộ chư ng

ơ trình máy tính, có nhi m

ệ v

ụ đ c

ọ m t

ộ

chương trình b c

ậ cao và th c

ự hi n

ệ nó theo đúng nh ng

ữ gì mà chư ng

ơ trình ch ỉđ nh

ị . Nó x

ử lý chư ng

ơ

trình một cách d n

ầ d n

ầ , nghĩa là đ c

ọ câu l nh

ệ đ n

ế đâu thì th c

ự hi n

ệ tính toán t i

ớ đó.

Còn trình biên d c

ị h thì có nhi m

ệ v

ụ đ c

ọ chư ng

ơ trình và d c

ị h nó hoàn toàn trư c

ớ khi th c

ự hi n

ệ b t

ấ kì

một câu l nh

ệ nào trong chư ng

ơ trình. Thư ng

ờ thì b n

ạ th c

ự hi n

ệ bư c

ớ biên d c

ị h chư ng

ơ trình trư c

ớ , sau

đó m i

ớ ch y

ạ mã l nh

ệ đã biên d c

ị h. Khi đó, chư ng

ơ trình b c

ậ cao đư c

ợ g i

ọ là mã ngu n

ồ , và chư ng

ơ

trình sau khi đư c

ợ d c

ị h g i

ọ là mã đ i

ố t n

ượ g, ho c

ặ ch n

ươ g trình ch y

ạ .

Chương trình Java v a

ừ đư c

ợ biên d c

ị h l n

ẫ thông d c

ị h. Thay vì vi c

ệ chuy n

ể chư ng

ơ trình sang ngôn ng

ữ

máy, trình biên d c

ị h Java phát sinh ra mã byte. Mã byte d

ễ thông d c

ị h (và thông d c

ị h cũng nhanh),

giống nh

ư mã máy; song nó còn kh

ả chuy n,

ể nh

ư m t

ộ ngôn ng

ữ b c

ậ cao. Vì v y

ậ , ta có th

ể biên d c

ị h m t

ộ

chương trình trên máy này, đ a

ư mã byte sang máy khác, sau đó thông d c

ị h mã byte này trên máy m i

ớ .

Khả năng này là m t

ộ l i

ợ thế c a

ủ Java so v i

ớ nhi u

ề ngôn ng

ữ b c

ậ cao khác.

M c

ặ dù quá trình này có v

ẻ ph c

ứ t p,

ạ nh ng

ư đa s

ố các môi trư ng

ờ phát tri n

ể chư ng

ơ trình đ u

ề giúp b n

ạ

tự động th c

ự hi n

ệ các bư c

ớ k

ể trên. Thông thư ng

ờ b n

ạ s

ẽ ch ỉph i

ả vi t

ế m t

ộ chư ng

ơ trình r i

ồ n

ấ m t

ộ nút

ho c

ặ gõ vào một câu l nh

ệ đ

ể biên d c

ị h và ch y

ạ . M t

ặ khác, ta v n

ẫ c n

ầ bi t

ế nh ng

ữ bư c

ớ nào đang đư c

ợ

máy th c

ự hi n

ệ ng m

ầ , đ

ể nh

ỡ có tr c

ụ tr c

ặ thì có th

ể hình dung ra sai

ở khâu nào.

1.2 Chư n

ơ g trình là gì?

Chư n

ơ g trình là một danh sách các ch ỉd n

ẫ cách th c

ự hi n

ệ tính toán.1 Việc tính toán có th ể là phép

thao tác toán h c

ọ , ch n

ẳ g h n

ạ gi i

ả h

ệ phư ng

ơ trình ho c

ặ tìm nghi m

ệ đa th c

ứ , nh ng

ư cũng có th

ể là

những phép tính trên các kí hi u

ệ , ch n

ẳ g h n

ạ tìm ki m

ế và thay th

ế ch

ữ trong m t

ộ văn b n,

ả ho c

ặ (kì l

ạ

hơn) là biên d c

ị h m t

ộ chư ng

ơ trình.

Những chỉ d n

ẫ , mà ta g i

ọ là nh ng

ữ câu l n

ệ h, sẽ khác nhau tùy lo i

ạ ngôn ngữ l p

ậ trình, nh ng

ư chung

quy l i

ạ có m t

ộ s

ố ít các phép thao tác mà nhi u

ề ngôn ng

ữ th c

ự hi n:

ệ

nh p

ậ s

ố li u:

ệ

Là vi c

ệ l y

ấ s

ố li u

ệ t

ừ bàn phím, file, ho c

ặ m t

ộ thi t

ế b ịkhác.

xu t

ấ k t

ế qu :

ả

Hi n

ể th ịkết qu

ả trên màn hình ho c

ặ g i

ử k t

ế qu

ả ra file ho c

ặ m t

ộ thi t

ế b ịkhác.

tính toán:

Th c

ự hi n

ệ các phép toán c

ơ b n

ả nh

ư c ng

ộ và nhân.

kiểm tra:

Ki m

ể tra m t

ộ đi u

ề ki n

ệ c

ụ th

ể và th c

ự hi n

ệ danh sách câu l nh

ệ

tư ng

ơ ng

ứ v i

ớ đi u

ề ki n

ệ đó.

tính l p:

ặ

Th c

ự hi n

ệ l p

ặ l i

ạ công vi c

ệ nhi u

ề l n,

ầ th n

ườ g là v i

ớ m t

ộ s

ố thay đ i

ổ gi a

ữ các l n

ầ l p

ặ .

Như v y

ậ đã tư ng

ơ đ i

ố đ y

ầ đ .

ủ M i

ỗ chư ng

ơ trình mà b n

ạ đã t ng

ừ dùng qua, b t

ấ k

ể nó ph c

ứ t p

ạ đ n

ế đâu,

đều được hợp thành từ nh ng

ữ câu l nh

ệ th c

ự hi n

ệ tính toán. Vì v y

ậ , m t

ộ cách mô t

ả l p

ậ trình, đó là quá

trình chia một bài toán l n,

ớ ph c

ứ t p

ạ thành nhi u

ề bài toán nh

ỏ h n

ơ cho đ n

ế khi t ng

ừ bài toán nh

ỏ này

đơn gi n

ả đ n

ế m c

ứ có th

ể đư c

ợ th c

ự hi n

ệ theo m t

ộ trong các ch ỉd n

ẫ trên đây.

1.3 Gỡ l i l

ỗ à gì?

Việc l p

ậ trình r t

ấ hay m c

ắ ph i

ả l i

ỗ . Vi c

ệ theo dõi, phân tích nguyên nhân gây ra l i

ỗ đư c

ợ g i

ọ là g

ỡ l i

ỗ .

Có ba lo i

ạ lỗi có th

ể xu t

ấ hi n

ệ trong chư ng

ơ trình: l i

ỗ cú pháp, l i

ỗ ch y

ạ và l i

ỗ ng

ữ nghĩa. Đ

ể nhanh

chóng tìm ra l i

ỗ ta c n

ầ phân bi t

ệ đư c

ợ chúng.

1.3.1 L I C

Ỗ

Ú PHÁP

Trình biên d c

ị h ch ỉcó th

ể chuy n

ể đ i

ổ đư c

ợ chư ng

ơ trình n u

ế nh

ư nó đúng đ n

ắ v

ề cú pháp; còn n u

ế

không, vi c

ệ biên d c

ị h s

ẽ th t

ấ b i

ạ và b n

ạ s

ẽ không ch y

ạ đư c

ợ chư ng

ơ trình. Cú pháp nghĩa là c u

ấ trúc

c a

ủ chương trình và các quy t c

ắ v

ề c u

ấ trúc đó.

Ch ng

ẳ h n,

ạ trong ti ng

ế Anh, m t

ộ câu vi t

ế ph i

ả b t

ắ đ u

ầ b ng

ằ ch

ữ in hoa và k t

ế thúc b ng

ằ d u

ấ ch m

ấ . câu

này có một lỗi cú pháp. Và câu này cũng v y

ậ

Đa ph n

ầ ban đ c

ọ thư ng

ờ không đ

ể tâm đ n

ế m t

ộ s

ố ít l i

ỗ cú pháp, vì v y

ậ ta có th

ể đ c

ọ th

ơ c a

ủ tác gi

ả e e

cummings mà không th t

ố ra l i

ờ thông báo l i

ỗ nào.

Các trình biên d c

ị h thì không nh

ư v y

ậ . Ch ỉc n

ầ trong chư ng

ơ trình có l i

ỗ cú pháp

ở b t

ấ c

ứ đâu, trình

biên d c

ị h s

ẽ hi n

ể th ịthông báo l i

ỗ và k t

ế thúc, và b n

ạ s

ẽ không th

ể ch y

ạ chư ng

ơ trình.

Tệ hơn n a

ữ là trong Java có nhi u

ề quy t c

ắ cú pháp h n

ơ là trong ti ng

ế Anh, và thư ng

ờ thì nh ng

ữ thông

báo l i

ỗ mà b n

ạ nh n

ậ đư c

ợ t

ừ trình biên d c

ị h đ u

ề không giúp ích gì nhi u

ề . Nếu b n

ạ mới nh p

ậ môn l p

ậ

trình đư c

ợ vài tu n

ầ , r t

ấ có th

ể b n

ạ ph i

ả dành nhi u

ề th i

ờ gian dò tìm l i

ỗ . Khi kinh nghi m

ệ tăng d n

ầ lên,

b n

ạ sẽ tránh đư c

ợ lỗi t t

ố h n

ơ và n u

ế m c

ắ thì cũng phát hi n

ệ ra l i

ỗ nhanh h n.

ơ

1.3.2 L I T

Ỗ

H C

Ự THI

Lo i

ạ lỗi th

ứ hai là l i

ỗ th c

ự thi; chúng có tên nh

ư v y

ậ b i

ở vì ch ỉxu t

ấ hi n

ệ khi chư ng

ơ trình đã b t

ắ đ u

ầ

ch y

ạ . Trong Java, l i

ỗ th c

ự thi x y

ả ra khi trình thông d c

ị h đang ch y

ạ mã byte và có đi u

ề gì đó tr c

ụ tr c

ặ .

Java có xu hư ng

ớ là ngôn ngữ an toàn, theo nghĩa trình biên d c

ị h s

ẽ b t

ắ r t

ấ nhi u

ề l i

ỗ . Do v y

ậ l i

ỗ th c

ự

thi s

ẽ hi m

ế , đ c

ặ bi t

ệ là

ở nh ng

ữ chư ng

ơ trình đ n

ơ gi n.

ả

Trong Java, l i

ỗ th c

ự thi đư c

ợ g i

ọ là bi t

ệ lệ, và

ở hầu h t

ế các môi trư ng

ờ l p

ậ trình, chúng xu t

ấ hi n

ệ dư i

ớ

hình th c

ứ c a

ủ s

ổ ho c

ặ h p

ộ tho i

ạ ghi rõ nh ng

ữ thông tin v

ề tình tr ng

ạ đã di n

ễ ra và lúc đó thì chư ng

ơ

trình đang th c

ự hi n

ệ nh ng

ữ gì. Thông tin này r t

ấ có ích đ i

ố v i

ớ vi c

ệ g

ỡ l i

ỗ .

1.3.3 L I L

Ỗ

OGIC VÀ NG N

Ữ GHĨA

Lo i

ạ lỗi th

ứ ba là l i

ỗ logic hay l i

ỗ ngữ nghĩa. Trong trư ng

ờ h p

ợ có l i

ỗ ki u

ể này, chư ng

ơ trình s

ẽ v n

ẫ

được biên d c

ị h và ch y

ạ mà không phát ra thông báo l i

ỗ nào, nh ng

ư s

ẽ không th c

ự hi n

ệ đúng yêu c u

ầ

mong muốn, mà s

ẽ cho k t

ế qu

ả khác. C

ụ th

ể là th c

ự hi n

ệ theo đúng nh ng

ữ câu l nh

ệ mà b n

ạ đã ch ỉd n

ẫ .

V n

ấ đ

ề

ở đây là chư ng

ơ trình b n

ạ vi t

ế s

ẽ không đúng theo ý mu n

ố c a

ủ b n.

ạ Ý nghĩa c a

ủ chư ng

ơ trình b ị

sai l c

ệ h. Vi c

ệ phát hi n

ệ các l i

ỗ ng

ữ nghĩa đôi lúc r t

ấ khó vì b n

ạ c n

ầ ph i

ả quay ngư c

ợ l i

ạ và nhìn vào k t

ế

quả c a

ủ chương trình đ

ể phán đoán xem b n

ả thân chư ng

ơ trình đã th c

ự hi n

ệ nh ng

ữ gì.

1.3.4 GỠ L I

Ỗ TH N

Ử GHI M

Ệ

Một trong nh ng

ữ kĩ năng quan tr ng

ọ nh t

ấ mà b n

ạ s

ẽ h c

ọ đư c

ợ , đó là g

ỡ l i

ỗ . M c

ặ dù đôi khi b ịv p

ấ váp,

nhưng vi c

ệ g

ỡ l i

ỗ r t

ấ thú v ,ị ch a

ứ đ y

ầ th

ử thách và là m t

ộ ph n

ầ có giá tr ịtrong l p

ậ trình.

Gỡ lỗi giống nh

ư vi c

ệ đi u

ề tra t i

ộ ph m

ạ . B n

ạ có trong tay các manh m i

ố , ph i

ả suy lu n

ậ ra các quá trình

và sự ki n

ệ d n

ẫ đ n

ế nh ng

ữ h u

ậ qu

ả đang ch ng

ứ ki n.

ế

Việc gỡ lỗi cũng gi ng

ố nh

ư khoa h c

ọ th c

ự nghi m

ệ . M i

ỗ khi có ý ki n

ế v

ề nguyên nhân d n

ẫ đ n

ế l i

ỗ sai,

b n

ạ sửa chữa chư ng

ơ trình và th c

ự hi n

ệ l i

ạ . N u

ế gi

ả thi t

ế c a

ủ b n

ạ là đúng thì b n

ạ thu đư c

ợ k t

ế qu

ả c a

ủ

công vi c

ệ s a

ử ch a

ữ , đ ng

ồ th i

ờ ti n

ế m t

ộ bư c

ớ g n

ầ h n

ơ t i

ớ chư ng

ơ trình đúng. Còn n u

ế gi

ả thi t

ế là sai thì

b n

ạ c n

ầ đề ra một gi

ả thi t

ế m i

ớ . Sherlock Holmes đã ch ỉra, “Khi b n

ạ đã lo i

ạ tr

ừ t t

ấ c

ả nh ng

ữ đi u

ề

không th

ể thì nh ng

ữ gì còn l i

ạ , dù có m p

ậ m

ờ đ n

ế đâu, chính là s

ự th t

ậ ”. (A. Conan Doyle, Dấu của b

ộ

tứ)

Đ i

ố v i

ớ một s

ố ngư i

ờ , vi c

ệ l p

ậ trình và g

ỡ l i

ỗ là gi ng

ố nhau. Đó là vì l p

ậ trình chính là quá trình g

ỡ l i

ỗ

d n

ầ d n

ầ đến khi b n

ạ có đư c

ợ chư ng

ơ trình mong mu n.

ố Ý tư ng

ở

ở đây là b n

ạ nên b t

ắ đ u

ầ v i

ớ m t

ộ

chương trình th c

ự hi n

ệ đư c

ợ m t

ộ điều gì đó, rồi thực hi n

ệ các ch nh

ỉ s a

ử nh ,

ỏ g

ỡ l i

ỗ trong quá trình

phát tri n,

ể đ n

ế khi b n

ạ có đư c

ợ m t

ộ chư ng

ơ trình hoàn thi n.

ệ

Ch ng

ẳ h n,

ạ Linux là m t

ộ h

ệ đi u

ề hành bao g m

ồ hàng nghìn dòng l nh

ệ , nh ng

ư nó ch ỉb t

ắ đ u

ầ t

ừ m t

ộ

chương trình đ n

ơ gi n

ả do Linus Torvalds dùng đ

ể khám phá chip Intel 80386. Theo Larry Greenfield

thì “Một trong nh ng

ữ d

ự án trư c

ớ đó c a

ủ Linus là m t

ộ chư ng

ơ trình có nhi m

ệ v

ụ chuy n

ể t

ừ vi c

ệ in

AAAA thành BBBB. Sau đó nó d n

ầ tr

ở thành Linux”. ( The Linux Users’ Guide Beta Version 1 / H ng ướ

dẫn s

ử dụng Linux, phiên b n

ả Beta 1).

Các chương ti p

ế sau đây s

ẽ nói thêm v

ề vi c

ệ g

ỡ l i

ỗ và các v n

ấ đ

ề th c

ự t

ế trong l p

ậ trình.

1.4 Ngôn ng h

ữ ình th c v

ứ

à ngôn ng t

ữ

n

ự hiên

Ngôn ng

ữ t

ự nhiên được mọi người dùng đ

ể giao ti p,

ế ví d

ụ Ti ng

ế Anh, Ti ng

ế Tây Ban Nha, Ti ng

ế

Pháp. Chúng t

ự do phát tri n

ể mà không đ nh

ị theo khuôn m u

ẫ v i

ớ b t

ấ kì m c

ụ đích nào (m c

ặ dù có m t

ộ

số tr t

ậ tự ch ng

ẳ h n

ạ nh

ư ng

ữ pháp);

Ngôn ng

ữ hình th c

ứ được con ngư i

ờ thi t

ế k

ế đ

ể ng

ứ d n

ụ g trong nh ng

ữ lĩnh v c

ự riêng. Ch n

ẳ g h n

ạ , kí

hiệu toán học chính là m t

ộ ngôn ng

ữ hình th c

ứ r t

ấ h u

ữ d n

ụ g đ

ể bi u

ể di n

ễ m i

ố quan h

ệ gi a

ữ nh ng

ữ bi n

ế

lượng và con số. Trong hoá h c

ọ , m t

ộ lo i

ạ ngôn ng

ữ hình th c

ứ khác đư c

ợ dùng đ

ể bi u

ể di n

ễ c u

ấ trúc hoá

học c a

ủ các phân t .

ử Và quan tr ng

ọ nh t

ấ :

Ngôn ngữ l p

ậ trình là nh n

ữ g ngôn ng

ữ hình th c

ứ đ c

ượ thi t

ế k

ế ph c

ụ v

ụ m c

ụ đích

diễn tả quá trình tính toán.

Các ngôn ng

ữ hình th c

ứ thư ng

ờ có quy đ nh

ị r t

ấ ch t

ặ ch

ẽ v

ề cú pháp. Ch n

ẳ g h n

ạ , 3 +

3

=

6

là một bi u

ể

thức toán học đúng, nh ng

ư 3 $

=

t

hì không. H2O là một công th c

ứ hoá h c

ọ đúng v

ề cú pháp, còn 2Zz thì

không.

Các quy t c

ắ cú pháp có hai d n

ạ g, thu c

ộ v

ề các nguyên tố và c u

ấ trúc. Nguyên t

ố là các thành ph n

ầ c

ơ s

ở

c a

ủ ngôn ng ,

ữ ch ng

ẳ h n,

ạ các t ,

ừ các con s ,

ố và các nguyên t

ố hoá h c

ọ . Trong ví d

ụ nêu trên, 3 $

=

c

ó l i

ỗ

sai vì $ không ph i

ả là m t

ộ nguyên t

ố h p

ợ l

ệ trong toán h c

ọ (theo nh

ư tôi đư c

ợ bi t

ế ). Tư ng

ơ t

ự nh

ư

v y

ậ , 2Zz không h p

ợ l

ệ vì không có nguyên t

ố hoá h c

ọ nào có kí hi u

ệ là Zz.

Lo i

ạ lỗi cú pháp th

ứ hai thu c

ộ v

ề d ng

ạ c u

ấ trúc c a

ủ m t

ộ m nh

ệ đ ;

ề nghĩa là cách s p

ắ x p

ế các nguyên t .

ố

Mệnh đề 3 $

= không h p

ợ l

ệ v

ề c u

ấ trúc là vì b n

ạ không th

ể đ

ể d u

ấ b ng

ằ

ở cu i

ố phư ng

ơ trình đư c

ợ .

Tương tự như v y

ậ , trong m t

ộ công th c

ứ hoá h c

ọ thì ch ỉs

ố ph i

ả đư c

ợ đ t

ặ sau tên nguyên t

ố ch

ứ không

ph i

ả đ t

ặ trước.

Mỗi khi đọc m t

ộ câu trong ngôn ng

ữ t

ự nhiên, ho c

ặ trong ngôn ng

ữ hình th c

ứ , b n

ạ c n

ầ hình dung đư c

ợ

c u

ấ trúc c a

ủ câu đó là gì (m c

ặ dù v i

ớ ngôn ng

ữ t

ự nhiên thì vi c

ệ làm này đư c

ợ th c

ự hi n

ệ m t

ộ cách vô

thức). Quá trình này đư c

ợ g i

ọ là phân tách.

M c

ặ dù ngôn ng

ữ hình th c

ứ và ngôn ng

ữ t

ự nhiên có nhi u

ề đ c

ặ đi m

ể chung—nguyên t ,

ố c u

ấ trúc, cú

pháp, và ngữ nghĩa—nh ng

ư chúng có m t

ộ s

ố khác bi t

ệ :

về s

ự m p

ậ m :

ờ

Ngôn ng

ữ t

ự nhiên ch a

ứ đ ng

ự s

ự m p

ậ m

ờ theo nghĩa con ng i

ườ mu n

ố hi u

ể đúng ph i

ả có suy lu n

ậ tuỳ

từng ng

ữ c nh.

ả

và có thêm các thông tin khác đ

ể b

ổ sung. Các ngôn ng

ữ hình th c

ứ đ c

ượ thi t

ế k

ế g n

ầ

nh

ư rõ ràng tuy t

ệ đ i

ố , t c

ứ là m i

ỗ m nh

ệ đ

ể ch ỉcó đúng m t

ộ nghĩa, b t

ấ k

ể ng

ữ c nh

ả

nh

ư th

ế nào.

về s

ự d

ư th a

ừ :

Đ

ể lo i

ạ tr

ừ s

ự m p

ậ m

ờ và tránh gây hi u

ể nh m

ầ , ngôn ng

ữ t

ự nhiên c n

ầ dùng đ n

ế nhi u

ề n i

ộ dung b

ổ

trợ làm dài thêm n i

ộ dung. Các ngôn ng

ữ hình thì g n

ọ gàng h n.

ơ

về văn phong:

Các ngôn ng

ữ t

ự nhiên có ch a

ứ nhi u

ề thành ng

ữ và n

ẩ d .

ụ Các ngôn ng

ữ hình th c

ứ luôn luôn có nghĩa

đúng theo nh ng

ữ gì đư c

ợ vi t

ế ra.

Chúng ta dùng ngôn ng

ữ t

ự nhiên ngay t

ừ thu

ở nh ,

ỏ nên thư ng

ờ có m t

ộ th i

ờ gian khó khăn ban đ u

ầ khi

làm quen v i

ớ ngôn ng

ữ hình th c

ứ . V

ề phư ng

ơ di n

ệ nào đó, s

ự khác bi t

ệ gi a

ữ ngôn ng

ữ hình th c

ứ và

ngôn ng

ữ t

ự nhiên cung nh

ư khác bi t

ệ gi a

ữ th

ơ ca và văn xuôi, dù h n

ơ th

ế n a

ữ .

Thơ ca:

Các t

ừ đ c

ượ dùng v i

ớ c

ả ch c

ứ năng âm đi u

ệ bên c nh

ạ

ch c

ứ năng ý nghĩa, và toàn b

ộ bài th /

ơ ca t o

ạ ra

hiệu qu

ả c m

ả xúc. Luôn mang tính không rõ ràng, th m

ậ chí còn là ch

ủ đ nh

ị c a

ủ tác gi .

ả

Văn xuôi:

Coi tr ng

ọ ý nghĩa c a

ủ câu ch

ữ h n,

ơ và c u

ấ trúc giúp cho vi c

ệ di n

ễ đ t

ạ ý nghĩa.

Chư n

ơ g trình:

Ý nghĩa c a

ủ m t

ộ ch ng

ươ trình máy tính là rõ ràng và đư c

ợ di n

ễ đ t

ạ hoàn toàn thông qua câu ch ,

ữ theo

đó ta có th

ể hi u

ể đ c

ượ tr n

ọ ven b ng

ằ cách phân tích các nguyên t

ố và c u

ấ trúc.

Khi đọc chư ng

ơ trình (ho c

ặ m t

ộ ngôn ng

ữ hình th c

ứ nào khác) b n

ạ nên làm nh

ư sau. Trư c

ớ h t

ế , hãy

nhớ r n

ằ g ngôn ng

ữ hình th c

ứ cô đ ng

ọ h n

ơ ngôn ng

ữ t

ự nhiên, nên ph i

ả m t

ấ nhi u

ề th i

ờ gian đ

ể đ c

ọ h n.

ơ

M t

ặ khác, c u

ấ trúc cũng r t

ấ quan tr ng

ọ , do đó không nên ch ỉđ c

ọ qua m t

ộ lư t

ợ t

ừ trên xu ng

ố dư i

ớ . Thay

vì v y

ậ , b n

ạ nên h c

ọ cách phân tách ngôn ng

ữ trong trí óc, nh n

ậ di n

ệ các nguyên t

ố và di n

ễ gi i

ả c u

ấ trúc.

Cu i

ố cùng, nh ng

ữ chi ti t

ế đóng vai trò quan tr ng

ọ . Các l i

ỗ dù là nh

ỏ nh t

ấ trong cách vi t

ế các t

ừ ho c

ặ d u

ấ

câu trong ngôn ng

ữ hình th c

ứ s

ẽ có th

ể gây ra khác bi t

ệ l n

ớ v

ề ý nghĩa.

1.5 Chương trình đ u t

ầ

iên

Theo thông l ,

ệ chư ng

ơ trình đ u

ầ tiên mà b n

ạ vi t

ế theo m t

ộ ngôn ng

ữ l p

ậ trình m i

ớ có tên g i

ọ là “Hello,

World!” vì t t

ấ c

ả nh ng

ữ gì nó th c

ự hi n

ệ ch ỉlà làm hi n

ệ ra dòng ch

ữ “Hello, World!” M t

ộ chư ng

ơ trình

như v y

ậ trong Java đư c

ợ vi t

ế nh

ư sau:

class Hello {

// main: xuất ra một thông tin đơn giản

public static void main(String[] args) {

System.out.println("Hello, world.");

}

}

Chương trình này có nh ng

ữ đ c

ặ đi m

ể h i

ơ khó gi i

ả thích cho ngư i

ờ m i

ớ b t

ắ đ u

ầ , song nó giúp ta có cái

nhìn bao quát v

ề nh ng

ữ ch

ủ đề sau này s

ẽ đư c

ợ h c

ọ .

Một chương trình Java đư c

ợ h p

ợ thành t

ừ nh ng

ữ l i

ờ khai báo l p

ớ , vốn có d ng

ạ sau:

class TENLOP {

public static void main (String[] args) {

CAC_CAU_LENH

}

}

Ở đây TENLOP là m t

ộ tên g i

ọ do ngư i

ờ l p

ậ trình đ t

ặ . Trong ví d

ụ trên, tên l p

ớ là Hello.

main là một ph

n

ươ g th c

ứ , tức là một t p

ậ h p

ợ đư c

ợ đ t

ặ tên, bao g m

ồ các câu l nh

ệ . Tên g i

ọ main này

r t

ấ đ c

ặ bi t

ệ ; nó đánh d u

ấ đi m

ể kh i

ở đ u

ầ c a

ủ chư ng

ơ trình. Khi ch y

ạ chư ng

ơ trình, câu l nh

ệ đ u

ầ tiên

trong main sẽ là đi m

ể b t

ắ đ u

ầ và k t

ế thúc

ở câu l nh

ệ cu i

ố cùng trong đó.

main có thể gồm nhi u

ề câu l nh

ệ , nh ng

ư

ở ví d

ụ trên thì ch ỉcó m t

ộ . Đó là câu l nh

ệ in, nghĩa là nó hi n

ể

thị một giá trị trên màn hình. Ch

ỗ này d

ễ gây l n,

ẫ “print” có th

ể mang ý nghĩa “hi n

ệ ra trên màn hình”

hay “gửi nội dung đ n

ế máy in”. Trong cu n

ố sách này, tôi không nói v

ề vi c

ệ g i

ử đ n

ế máy in; t t

ấ c

ả vi c

ệ in

c a

ủ chúng ta là hi n

ể th ịlên màn hình. L nh

ệ in k t

ế thúc b n

ằ g m t

ộ d u

ấ ch m

ấ ph y

ẩ (;).

System.out.println là một phương th c

ứ do th

ư vi n

ệ c a

ủ Java cung c p.

ấ M t

ộ thư vi n

ệ là t p

ậ hợp

gồm những l i

ờ đ nh

ị nghĩa l p

ớ và phư ng

ơ th c

ứ .

Java dùng nh ng

ữ c p

ặ ngo c

ặ nh n

ọ ({ và }) đ

ể nhóm thông tin l i

ạ v i

ớ nhau. C p

ặ ngo c

ặ nh n

ọ

ở ngoài cùng

(các dòng 1 và 8) ch a

ứ l i

ờ đ nh

ị nghĩa l p,

ớ còn c p

ặ ngo c

ặ nh n

ọ phía trong thì ch a

ứ l i

ờ đ nh

ị nghĩa cho

main.

Dòng 3 b t

ắ đ u

ầ b ng

ằ //. Nh

ư v y

ậ dòng này là m t

ộ l i

ờ chú thích, tức là một đo n

ạ ch

ữ mà b n

ạ có thể

viết vào chương trình, thư ng

ờ đ

ể gi i

ả thích công d ng

ụ c a

ủ chư ng

ơ trình. Khi trình biên d c

ị h th y

ấ //, nó

sẽ phớt lờ những gì k

ể t

ừ đó đ n

ế cu i

ố dòng.

1.6 Thu t

ậ ngữ

gi i

ả quy t

ế v n

ấ đ :

ề

Quá trình thi t

ế l p

ậ bài toán, tìm l i

ờ gi i

ả , và bi u

ể di n

ễ l i

ờ gi i

ả .

ngôn ng

ữ b c

ậ cao:

Ngôn ng

ữ l p

ậ trình nh

ư Python đư c

ợ thi t

ế k

ế nh m

ằ m c

ụ đích đ

ể con ng i

ườ d

ễ đ c

ọ và vi t

ế .

ngôn ng

ữ b c

ậ th p:

ấ

Ngôn ng

ữ l p

ậ trình đư c

ợ thi t

ế k

ế nh m

ằ m c

ụ đích đ

ể máy tính d

ễ th c

ự hi n

ệ ; còn g i

ọ là “ngôn ng

ữ máy”

hoặc “h p

ợ ng ”

ữ .

tính khả chuy n

ể :

Đặc tính c a

ủ ch ng

ươ trình mà có th

ể ch y

ạ trên nhi u

ề lo i

ạ máy tính khác nhau.

thông d c

ị h:

Th c

ự hi n

ệ ch ng

ươ trình đ c

ượ vi t

ế b ng

ằ ngôn ng

ữ b c

ậ cao b ng

ằ cách d c

ị h nó theo t ng

ừ dòng m t

ộ .

biên d c

ị h:

D c

ị h một lượt toàn b

ộ ch ng

ươ trình vi t

ế b ng

ằ ngôn ng

ữ b c

ậ cao sang ngôn ng

ữ b c

ậ th p

ấ , đ

ể chu n

ẩ b ị

thực hi n

ệ sau này.

mã ngu n

ồ :

Chư ng

ơ trình

ở d ng

ạ ngôn ng

ữ b c

ậ cao tr c

ướ khi đ c

ượ biên d c

ị h.

mã đ i

ố t n

ượ g:

Sản ph m

ẩ đ u

ầ ra c a

ủ trình biên d c

ị h sau khi nó đã d c

ị h ch ng

ươ trình.

chương trình ch y:

ạ

Tên khác đ t

ặ cho mã đ i

ố tư ng

ợ đã s n

ẵ sàng đ c

ượ th c

ự hi n.

ệ

d u

ấ nh c

ắ :

Các kí t

ự đ c

ượ hi n

ể thị b i

ở trình thông d c

ị h nh m

ằ th

ể hi n

ệ r ng

ằ nó đã s n

ẵ sàng nh n

ậ đ u

ầ vào t

ừ phía

người dùng.

văn l n

ệ h:

Chư ng

ơ trình đ c

ượ l u

ư trong file (th n

ườ g chính là ch ng

ươ trình s

ẽ đ c

ượ thông d c

ị h).

ch

ế đ

ộ t n

ươ g tác:

Cách dùng trình thông d c

ị h Python thông qua vi c

ệ gõ các câu l nh

ệ

và bi u

ể th c

ứ vào ch

ỗ d u

ấ nh c

ắ .

ch

ế đ

ộ văn l n

ệ h:

Cách dùng trình thông d c

ị h Python đ

ể đ c

ọ và th c

ự hi n

ệ các câu l nh

ệ

có trong m t

ộ văn l nh.

ệ

chương trình:

Danh sách nh ng

ữ ch ỉd n

ẫ th c

ự hi n

ệ tính toán.

thu t

ậ toán:

Quá trình t ng

ổ quát đ

ể gi i

ả m t

ộ l p

ớ các bài toán.

l i

ỗ :

Lỗi trong ch ng

ươ trình.

g

ỡ l i

ỗ :

Quá trình dò tìm và g

ỡ b

ỏ c

ả ba ki u

ể l i

ỗ trong l p

ậ trình.

cú pháp:

Cấu trúc c a

ủ một ch ng

ươ trình.

l i

ỗ cú pháp:

Lỗi trong ch ng

ươ trình mà làm cho quá trình phân tách không th

ể th c

ự hi n

ệ đ c

ượ (và h

ệ qu

ả là không

thể biên d c

ị h đ c

ượ ).

bi t

ệ l :

ệ

Lỗi đư c

ợ phát hi n

ệ khi ch ng

ươ trình đang ch y

ạ .

ng

ữ nghĩa:

Ý nghĩa c a

ủ ch ng

ươ trình.

l i

ỗ ngữ nghĩa:

Lỗi có trong ch ng

ươ trình mà khi n

ế cho ch ng

ươ trình th c

ự hi n

ệ công vi c

ệ ngoài ý đ nh

ị

c a

ủ ng i

ườ vi t

ế .

ngôn ng

ữ t

ự nhiên:

Ngôn ng

ữ b t

ấ kì đ c

ượ con ng i

ườ dùng, đ c

ượ tr i

ả qua s

ự ti n

ế hóa t

ự nhiên.

ngôn ng

ữ hình th c

ứ :

Ngôn ng

ữ b t

ấ kì đ c

ượ con ng i

ườ thi t

ế k

ế nh m

ằ m c

ụ đích c

ụ th ,

ể nh

ư vi c

ệ bi u

ể di n

ễ các ý t ng

ưở toán

h c

ọ ho c

ặ các ch n

ươ g trình máy tính; t t

ấ c

ả các ngôn ng

ữ l p

ậ trình đ u

ề là ngôn ng

ữ hình th c

ứ .

nguyên t :

ố

Một trong nh ng

ữ thành ph n

ầ c

ơ b n

ả trong c u

ấ trúc cú pháp c a

ủ m t

ộ ch ng

ươ trình, tư ng

ơ đư ng

ơ v i

ớ

một t

ừ trong ngôn ng

ữ t

ự nhiên.

phân tách:

Vi c

ệ ki m

ể tra một ch ng

ươ trình và phân tích c u

ấ trúc cú pháp.

lệnh print:

Câu l nh

ệ

khi n

ế cho k t

ế qu

ả đ c

ượ hi n

ể th ịlên màn hình.

1.7 Bài t p

ậ

BÀI T P

Ậ 1

Các nhà khoa h c

ọ máy tính thư ng

ờ có thói quen dùng nh ng

ữ t

ừ ti ng

ế Anh thông thư ng

ờ đ

ể

ch ỉnh ng

ữ th

ứ khác v i

ớ nghĩa ti ng

ế Anh thông d ng

ụ c a

ủ t

ừ đó. Ch ng

ẳ h n,

ạ trong ti ng

ế Anh,

“statement” và “comment” đ ng

ồ nghĩa v i

ớ nhau, nh ng

ư trong chư ng

ơ trình thì chúng khác

h n.

ẳ

Ph n

ầ thuật ngữ ở cu i

ố m i

ỗ chư ng

ơ nh m

ằ đi m

ể l i

ạ nh ng

ữ t

ừ và c m

ụ t

ừ có ý nghĩa riêng

trong ngành khoa h c

ọ máy tính. Khi b n

ạ th y

ấ nh ng

ữ t

ừ quen thu c

ộ , thì đ ng

ừ l

ờ đi coi nh

ư

đã bi t

ế nghĩa c a

ủ chúng nhé!

1. Theo thu t

ậ ngữ máy tính, s

ự khác bi t

ệ gi a

ữ câu l nh

ệ và chú thích nh

ư th

ế nào?

2. Nói một chương trình có tính kh

ả chuy n

ể nghĩa là gì?

3. Một chương trình ch y

ạ có nghĩa là gì?

BÀI T P

Ậ 2

Trước khi ti p

ế t c

ụ , b n

ạ hãy tìm hi u

ể cách biên d c

ị h và ch y

ạ chư ng

ơ trình Java trong môi

trường l p

ậ trình c a

ủ mình. M t

ộ s

ố lo i

ạ môi trư ng

ờ cung c p

ấ s n

ẵ nh ng

ữ chư ng

ơ trình m u

ẫ

tựa như ví d

ụ

ở M c

ụ 1.5.

1. Gõ vào chư ng

ơ trình “Hello, World”, r i

ồ biên d c

ị h và ch y

ạ nó.

2. Thêm một câu l nh

ệ đ

ể in ra m t

ộ dòng ch

ữ th

ứ hai theo sau “Hello, World!”. Có th

ể là câu

đùa vui “How are you?” Hãy biên d c

ị h và ch y

ạ l i

ạ chư ng

ơ trình.

3. Thêm một chú thích vào (b t

ấ kì đâu) trong chư ng

ơ trình, biên d c

ị h l i

ạ , và ch y

ạ l i

ạ l n

ầ n a

ữ .

Lời chú thích m i

ớ ph i

ả không làm nh

ả hư ng

ở đ n

ế k t

ế qu .

ả

Bài t p

ậ này có v

ẻ l t

ặ v t

ặ , song đây chính là đi m

ể kh i

ở đ u

ầ cho nhi u

ề chư ng

ơ trình mà ta s

ẽ

làm vi c

ệ v i

ớ . Đ

ể ch c

ắ tay g

ỡ l i

ỗ , b n

ạ ph i

ả dùng th o

ạ môi trư ng

ờ l p

ậ trình c a

ủ mình. Trong

một số môi trư ng

ờ , r t

ấ d

ễ b ịm t

ấ d u

ấ chư ng

ơ trình đang ch y

ạ , và b n

ạ có th

ể r i

ơ vào trư ng

ờ

hợp đi gỡ lỗi một chư ng

ơ trình trong khi vô ý ch y

ạ chư ng

ơ trình khác. Vi c

ệ thêm vào (và

thay đổi) câu l nh

ệ in là m t

ộ cách đ n

ơ gi n

ả đ

ể đ m

ả b o

ả ch c

ắ chư ng

ơ trình đang làm vi c

ệ là

chương trình mà b n

ạ ch y

ạ .

BÀI T P

Ậ 3

Một ý tưởng hay là hãy ph m

ạ càng nhi u

ề l i

ỗ trong l p

ậ trình mà b n

ạ có th

ể hình dung đư c

ợ ,

để th y

ấ nh ng

ữ thông báo l i

ỗ nào mà trình biên d c

ị h đ a

ư ra. Đôi khi trình biên d c

ị h cho b n

ạ

biết chính xác sai

ở ch

ỗ nào, và b n

ạ ch ỉvi c

ệ s a

ủ nó. Nh ng

ư đôi khi các thông báo l i

ỗ l i

ạ

đánh l i

ạ hư ng

ớ . B n

ạ s

ẽ hình thành nên m t

ộ tr c

ự giác đ

ể phân bi t

ệ lúc nào thì tin c y

ậ trình

biên d c

ị h và lúc nào ph i

ả t

ự hình dung ra l i

ỗ .

1. Xóa bớt một trong các d u

ấ m

ở ngo c

ặ nh n.

ọ

2. Xóa bớt một trong các d u

ấ đóng ngo c

ặ nh n.

ọ

3. Thay vì main, hãy vi t

ế mian.

4. Xóa từ static.

5. Xóa từ public.

6. Xóa từ System.

7. Thay thế println b ng

ằ Println.

8. Thay thế println b ng

ằ print. Câu hỏi này đánh đ

ố

ở ch ,

ỗ đây là l i

ỗ logic ch

ứ không ph i

ả

lỗi cú pháp. Câu l nh

ệ System.out.print hoàn toàn h p

ợ l ,

ệ nh ng

ư nó có th

ể có ho c

ặ không

làm theo đi u

ề b n

ạ d

ự ki n.

ế

9. Xóa một trong số các ngo c

ặ tròn. Thêm vào m t

ộ ngo c

ặ tròn.

1.Đ nh

ị nghĩa này không đúng v i

ớ m i

ọ ngôn ng

ữ l p

ậ trình. M t

ộ ví d

ụ là các ngôn ng

ữ đ c

ặ t ,

ả

xemhttp://en.wikipedia.org/wiki/Declarative_programming. ↩

Ch

ng

ươ 2: Bi n

ế và ki u

ể

Trở về M c

ụ l c

ụ cuốn sách 2.1 Nói thêm về lệnh in

B n

ạ có thể tùy ý đ t

ặ bao nhiêu câu l nh

ệ vào trong main cũng được; ch ng

ẳ h n

ạ , để in nhi u

ề dòng:

class Hello {

// Generates some simple output.

public static void main(String[] args) {

System.out.println("Hello, world."); // in một dòng System.out.println("How are you?"); // in dòng nữa

}

}

Như ví d

ụ này đã cho th y

ấ , b n

ạ có th

ể đ t

ặ l i

ờ chú thích

ở cu i

ố dòng l nh

ệ , ho c

ặ đ t

ặ nó

ở riêng m t

ộ dòng.

Những c m

ụ từ đ t

ặ giữa hai d u

ấ nháy kép đư c

ợ g i

ọ là chu i

ỗ , vì chúng đư c

ợ hợp thành từ một dãy

(chuỗi) các kí t .

ự Chu i

ỗ có thể gồm b t

ấ kì tổ h p

ợ nào t

ừ các ch

ữ cái, ch

ữ s ,

ố d u

ấ câu, và các kí tự đ c

ặ

bi t

ệ khác.

println là tên gọi t t

ắ c a

ủ “print line,” vì sau m i

ỗ dòng nó thêm vào m t

ộ kí t

ự đ c

ặ bi t

ệ , gọi là newline, để

đ y

ẩ con trỏ xu ng

ố dòng ti p

ế theo trên màn hình. L n

ầ tới, khi println đư c

ợ g i

ọ , các ch

ữ m i

ớ s

ẽ xu t

ấ

hiện

ở dòng k

ế ti p.

ế

Để hiển th ịk t

ế quả t

ừ nhi u

ề l nh

ệ in trên cùng m t

ộ dòng, hãy dùng print:

class Hello {

// Phát sinh một số kết quả đơn giản.

public static void main(String[] args) {

System.out.print("Goodbye, ");

System.out.println("cruel world!");

}

}

Kết qu

ả xu t

ấ hi n

ệ trên cùng m t

ộ dòng là Goodbye, cruel world!. Có một dấu cách gi a

ữ t

ừ “Goodbye” và

d u

ấ nháy kép ti p

ế theo. D u

ấ cách này xu t

ấ hi n

ệ

ở kết qu ,

ả vì v y

ậ nó nh

ả hưởng đến hành vi c a

ủ chư ng

ơ

trình.

Những d u

ấ cách xu t

ấ hi n

ệ ngoài c p

ặ d u

ấ nháy kép thì nói chung không nh

ả hư ng

ở gì đ n

ế hành vi c a

ủ

chương trình. Ch n

ẳ g h n,

ạ tôi đã có th

ể vi t

ế :

class Hello {

public static void main(String[] args) {

System.out.print("Goodbye, ");

System.out.println("cruel world!");

}

}

Chương trình này sẽ biên d c

ị h và ch y

ạ đư c

ợ thông su t

ố nh

ư chư ng

ơ trình ban đ u

ầ . D u

ấ ng t

ắ

ở cu i

ố

dòng (d u

ấ newline) cũng không nh

ả hưởng tới hành vi c a

ủ chư ng

ơ trình, vì v y

ậ tôi cũng có th

ể đã vi t

ế

thành:

class Hello { public static void main(String[] args) {

System.out.print("Goodbye, "); System.out.println

("cruel world!");}}

Chương trình này cũng ho t

ạ đ ng

ộ đư c

ợ , nh ng

ư nó tr

ở nên ngày càng khó đ c

ọ . Các d u

ấ ng t

ắ dòng và d u

ấ

cách r t

ấ có ích trong vi c

ệ b

ố trí hình th c

ứ c a

ủ chư ng

ơ trình, làm chư ng

ơ trình d

ễ đ c

ọ và dễ đ nh

ị vị lỗi

hơn.

2.2 Biến

Một trong nh ng

ữ tính năng m nh

ạ nh t

ấ c a

ủ m t

ộ ngôn ng

ữ l p

ậ trình là kh

ả năng thao tác v i

ớ các biến.

Bi n

ế là một tên g i

ọ tham chi u

ế đ n

ế m t

ộ giá trị. Giá trị là nh ng

ữ th

ứ có th

ể in ra, l u

ư gi ,

ữ và (nh

ư ta s

ẽ

th y

ấ sau này) thao tác tính toán đư c

ợ . Các chu i

ỗ mà ta đã in đ n

ế gi

ờ ("Hello, World.", "Goodbye, ", v.v.)

đều là nh ng

ữ giá tr .ị

Để lưu một giá tr ,ị b n

ạ ph i

ả t o

ạ ra m t

ộ bi n.

ế Vì nh ng

ữ giá tr ịta mu n

ố l u

ư tr

ữ

ở đây là các chu i

ỗ , nên ta

khai báo bi n

ế m i

ớ là m t

ộ chu i

ỗ

String bob;

Đây là câu l n

ệ h khai báo, vì nó khai báo r ng

ằ bi n

ế mang tên bob có ki u

ể String. Mỗi bi n

ế có m t

ộ ki u

ể

với tác d ng

ụ quy t

ế đ nh

ị lo i

ạ giá tr ịnào mà bi n

ế đó có th

ể l u

ư trữ đư c

ợ . Ch n

ẳ g h n,

ạ ki u

ể int có th

ể lưu

trữ các số nguyên, còn ki u

ể String lưu trữ chuỗi.

Một số ki u

ể có tên gọi b t

ắ đ u

ầ b ng

ằ ch

ữ in và m t

ộ s

ố ki u

ể thì b t

ắ đ u

ầ b n

ằ g ch

ữ thư ng

ờ . Ta s

ẽ h c

ọ ý

nghĩa c a

ủ s

ự phân bi t

ệ này v

ề sau, còn bây gi

ờ ch ỉc n

ầ l u

ư ý đ

ể vi t

ế đúng. Không có ki u

ể nào gọi

là Int hay string, và trình biên d c

ị h sẽ bác bỏ nếu b n

ạ c

ố g ng

ắ d ng

ự nên m t

ộ cái tên nh

ư v y

ậ .

Để t o

ạ nên một bi n

ế nguyên, cú pháp là int bob;, trong đó bob là tên gọi tùy ý mà b n ạ đ t

ặ cho bi n.

ế Nói

chung, b n

ạ s

ẽ mu n

ố đ t

ặ tên bi n

ế đ

ể ch ỉrõ m c

ụ tiêu dùng bi n

ế đó. Ch n

ẳ g h n,

ạ n u

ế th y

ấ các l nh

ệ khai

báo bi n

ế sau đây:

String firstName;

String lastName;

int hour, minute;

thì b n

ạ có th

ể đoán đư c

ợ r n

ằ g nh ng

ữ giá tr ịnào s

ẽ đư c

ợ l u

ư vào chúng. Ví d

ụ này cũng gi i

ớ thi u

ệ cú

pháp để khai báo nhi u

ề bi n

ế v i

ớ cùng ki u

ể : hour và second đều là số nguyên (kiểu int).

2.3 Lệnh gán

Bây gi

ờ khi đã t o

ạ nên các bi n,

ế ta mu n

ố l u

ư gi

ữ nh ng

ữ giá tr .ị Ta làm điều này v i

ớ lệnh gán.

bob = "Hello."; // cho bob giá trị "Hello."

hour = 11; // gán giá trị 11 vào hour

minute = 59; // đặt minute là 59

Ví d

ụ này có ba l nh

ệ gán, và các l i

ờ chú thích đi kèm cho th y

ấ ba cách khác nhau mà chúng ta đôi khi

nói v

ề câu l nh

ệ gán. Cách dùng từ có thể gây nh m

ầ l n,

ẫ song ý tưởng r t

ấ đơn gi n:

ả

• Khi khai báo m t

ộ bi n,

ế b n

ạ t o

ạ nên m t

ộ ch

ỗ l u

ư d

ữ li u

ệ đư c

ợ đ t

ặ tên.

• Khi gán cho m t

ộ bi n,

ế b n

ạ cho nó m t

ộ giá tr .ị

Một cách thông d n

ụ g đ

ể bi u

ể di n

ễ bi n

ế trên gi y

ấ là v

ẽ m t

ộ h p

ộ v i

ớ tên bi n

ế ghi bên ngoài và giá tr ịbi n

ế

ở beent rong. Hình dư i

ớ đây cho th y

ấ hi u

ệ ứng c a

ủ ba câu l nh

ệ gán này:

Một quy t c

ắ chung là bi n

ế ph i

ả có cùng ki u

ể v i

ớ giá tr ịmà b n

ạ gán cho nó. B n

ạ không th

ể l u

ư tr

ữ

một String vào trong minute hay một số nguyên vào bob.

M t

ặ khác, quy t c

ắ này cũng có th

ể gây nh m

ầ l n,

ẫ vì có r t

ấ nhiều cách đ

ể b n

ạ chuy n

ể giá tr ịt

ừ ki u

ể này

sang ki u

ể khác, và đôi khi Java cũng t

ự đ ng

ộ chuy n

ể đ i

ổ . Riêng bây gi

ờ thì b n

ạ nên nh

ớ quy t c

ắ chung,

và sau này ta s

ẽ nói v

ề nh ng

ữ ngo i

ạ l .

ệ

Một đi u

ề nữa dễ gây nh m

ầ đó là có nh ng

ữ chu i

ỗ trông giống như số nguyên nh ng

ư th c

ự ra l i

ạ không

ph i

ả . Ch ng

ẳ h n,

ạ bob có thể chứa chuỗi "123", vốn đư c

ợ t o

ạ thành t

ừ các kí tự 1, 2 và 3, nhưng nó không

ph i

ả là số 123.

bob = "123"; // hợp lệ

bob = 123; // không hợp lệ

2.4 In các biến

Để hiển th ịgiá trị c a

ủ một bi n,

ế b n

ạ có thể dùng println ho c

ặ print:

class Hello {

public static void main(String[] args) {

String firstLine;

firstLine = "Hello, again!";

System.out.println(firstLine);

}

}

Chương trình này t o

ạ ra ba bi n

ế firstLine, gán nó v i

ớ giá trị "Hello, again!" rồi in giá trị đó ra. Khi ta nói

“in một giá tr ,ị” điều này nghĩa là in giá trị c a

ủ bi n

ế đó. Để in tên c a

ủ một bi n,

ế b n

ạ ph i

ả đ t

ặ cái tên này

trong c p

ặ d u

ấ nháy kép. Ch ng

ẳ h n:

ạ System.out.println("firstLine");

Ví d

ụ như, b n

ạ có th

ể vi t

ế

String firstLine; firstLine = "Hello, again!";

System.out.print("The value of firstLine is ");

System.out.println(firstLine);

Kết qu

ả c a

ủ chư ng

ơ trình này là

The value of firstLine is Hello, again!

Tôi vui m ng

ừ thông báo v i

ớ b n

ạ r ng

ằ cú pháp c a

ủ l nh

ệ in m t

ộ bi n

ế thì gi ng

ố nhau b t

ấ k

ể ki u

ể c a

ủ bi n

ế

đó là gì.

int hour, minute;

hour = 11;

minute = 59;

System.out.print("The current time is ");

System.out.print(hour);

System.out.print(":");

System.out.print(minute);

System.out.println(".");

Kết qu

ả c a

ủ chư ng

ơ trình này là The current time is 11:59.

CẢNH BÁO: Đ

ể đ t

ặ nhi u

ề giá tr ịtrên cùng m t

ộ dòng, cách thông d n

ụ g là dùng nhi u

ề l nh

ệ print và ti p

ế

theo là println. Nhưng b n

ạ ph i

ả nh

ớ vi t

ế println ở cuối. Trong nhi u

ề môi trư ng

ờ l p

ậ trình, k t

ế qu

ả

c a

ủ print ch ỉlưu giữ mà không đư c

ợ hi n

ể th ịđ n

ế t n

ậ lúc println đư c

ợ g i

ọ , khi đó c

ả dòng s

ẽ xu t

ấ hi n

ệ

cùng lúc. N u

ế b n

ạ b

ỏ m t

ấ println, chương trình có th

ể k t

ế thúc mà không hi n

ể th ịk t

ế qu

ả đã đư c

ợ l u

ư

trữ!

2.5 Từ khoá

Cách đây vài m c

ụ , tôi đã nói r ng

ằ b n

ạ có thể đ t

ặ một tên tùy ý cho bi n,

ế nh ng

ư đi u

ề này không h n

ẳ là

đúng. Có nh ng

ữ t

ừ nh t

ấ đ nh

ị đư c

ợ dành riêng trong Java vì chúng đư c

ợ trình biên d c

ị h s

ử d n

ụ g đ

ể phân

tách c u

ấ trúc c a

ủ chư ng

ơ trình mà b n

ạ vi t

ế ; và n u

ế b n

ạ dùng nh ng

ữ t

ừ này đ t

ặ cho tên bi n

ế thì trình

biên d c

ị h s

ẽ bị l n.

ẫ Các t

ừ nh

ư v y

ậ , g i

ọ là t

ừ khóa, bao gồm có public, class, void, int, và nhi u ề t

ừ khác.

B n

ạ có thể xem danh sách đ y

ầ đủ

t i

ạ http://download.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html. Trang này, đư c

ợ Oracle cung c p,

ấ có đăng tài li u

ệ v

ề Java mà trong sách này tôi thường xuyên tham kh o

ả đ n.

ế

2.6 Toán tử

Toán tử là các kí hi u

ệ đ c

ặ bi t

ệ để bi u

ể di n

ễ các phép tính nh

ư c ng

ộ và nhân. H u

ầ h t

ế các toán t

ử c a

ủ

Java đ u

ề th c

ự hi n

ệ theo đúng dự đ nh

ị c a

ủ b n

ạ vì chúng là nh ng

ữ kí hi u

ệ toán h c

ọ thông d n

ụ g. Ch n

ẳ g

h n

ạ , toán t

ử c a

ủ phép c ng

ộ là +. Phép tr

ừ là -, phép nhân là *, và phép chia là /.

1+1 hour-1 hour*60 + minute minute/60

Các bi u

ể th c

ứ có th

ể ch a

ứ c

ả tên bi n

ế và con s .

ố Các bi n

ế đ u

ề đư c

ợ thay b ng

ằ giá tr ịc a

ủ chúng trư c

ớ khi

phép tính đư c

ợ th c

ự hi n.

ệ

Hơn nữa, dù phép tr

ừ và phép nhân làm đúng đi u

ề b n

ạ mu n,

ố song phép chia có th

ể làm b n

ạ ng c

ạ

nhiên. Ch ng

ẳ h n

ạ , chư ng

ơ trình này:

int hour, minute;

hour = 11;

minute = 59;

System.out.print("Number of minutes since midnight: "); System.out.println(hour*60 + minute);

System.out.print("Fraction of the hour that has passed: "); System.out.println(minute/60);

phát sinh ra k t

ế qu

ả này:

Number of minutes since midnight: 719

Fraction of the hour that has passed: 0

Dòng đ u

ầ tiên thì đúng nh

ư mong đ i

ợ , nh ng

ư dòng th

ứ hai th t

ậ kì qu c

ặ . Giá tr ịc a

ủ minute là 59, và 59

chia cho 60 b ng

ằ 0.98333, ch

ứ không ph i

ả là 0. V n

ấ đề ở đây là Java đã thực hi n

ệ phép chia nguyên.

Khi c

ả hai toán h n

ạ g đều là số nguyên (toán h n

ạ g là nh ng

ữ đ i

ạ lư ng

ợ mà toán t

ử th c

ự hi n

ệ tính toán),

thì k t

ế qu

ả cũng sẽ là m t

ộ s

ố nguyên, và theo quy đ nh

ị chung, phép chia nguyên làm tròn xu ng

ố , ngay

c

ả trong trường h p

ợ này khi giá tr ịsát v i

ớ s

ố nguyên phía trên h n.

ơ

Một cách làm khác là đi tính ph n

ầ trăm thay vì m t

ộ phân s :

ố

System.out.print("Percentage of the hour that has passed: "); System.out.println(minute*100/60);

Kết qu

ả là:

Percentage of the hour that has passed: 98

Một l n

ầ n a

ữ k t

ế quả l i

ạ đư c

ợ làm tròn xu ng

ố , nh ng

ư l n

ầ này đáp s

ố đã g n

ầ đúng h n.

ơ Đ

ể đư c

ợ k t

ế qu

ả

chính xác h n,

ơ ta có th

ể dùng m t

ộ ki u

ể bi n

ế khác, g i

ọ là d u

ấ ph y

ẩ đ ng

ộ , đ

ể l u

ư tr

ữ nh ng

ữ giá tr ịcó

ph n

ầ th p

ậ phân. Ta s

ẽ ti p

ế t c

ụ v n

ấ đ

ề này trong chư ng

ơ sau.

2.7 Th t

ứ t

ự hực hiện

Khi trong bi u

ể th c

ứ có nhi u

ề h n

ơ m t

ộ toán t ,

ử th

ứ t

ự đ nh

ị lư ng

ợ s

ẽ tuân theo quy t c

ắ u

ư tiên. Gi i

ả

thích đ y

ầ đủ quy t c

ắ u

ư tiên này có th

ể ph c

ứ t p,

ạ nh ng

ư đ

ể b t

ắ đ u

ầ , b n

ạ ch ỉc n

ầ nh :

ớ

• Các phép nhân và chia ph i

ả được thực hi n

ệ trư c

ớ cộng và tr .

ừ Vì v y

ậ 2*3-1 b ng

ằ 5 chứ không ph i

ả 4,

và 2/3-1 đư c

ợ -1, chứ không ph i

ả 1 (hãy nh

ớ r ng

ằ phép chia nguyên 2/3 b n

ằ g 0).

• Nếu các toán t

ử có cùng đ

ộ u

ư tiên thì chúng đư c

ợ đ nh

ị lư ng

ợ t

ừ trái sang ph i

ả . Vì v y

ậ , trong bi u

ể

thức minute*100/60, phép nhân đư c

ợ th c

ự hi n

ệ trư c

ớ , cho ra 5900/60, và cuối cùng là 98. N u

ế các

phép toán ch y

ạ t

ừ ph i

ả qua trái, k t

ế qu

ả đã thành 59*1 t c

ứ là 59, đi u

ề này là sai.

• B t

ấ cứ khi nào mu n

ố vư t

ợ quy t c

ắ u

ư tiên (hay khi b n

ạ không ch c

ắ quy t c

ắ này nh

ư th

ế nào), b n

ạ có th

ể

dùng c p

ặ ngo c

ặ đ n.

ơ Bi u

ể th c

ứ trong c p

ặ ngo c

ặ đ n

ơ đư c

ợ th c

ự hi n

ệ trư c

ớ , b i

ở v y

ậ 2 *(3-1) là 4. B n

ạ

cũng có th

ể dùng c p

ặ ngo c

ặ đ n

ơ đ

ể bi u

ể th c

ứ tr

ở nên d

ễ đ c

ọ , nh

ư v i

ớ (minute * 100) / 60, ngay c

ả

khi không có nó thì k t

ế qu

ả cũng không đ i

ổ .

2.8 Các thao tác v i

ớ chu i

ỗ

Nói chung, b n

ạ không th

ể th c

ự hi n

ệ các phép toán đ i

ố v i

ớ chu i

ỗ , ngay c

ả khi chu i

ỗ trông gi ng

ố nh

ư

những con số. Vì v y

ậ các bi u

ể th c

ứ sau đây đ u

ề không h p

ợ l :

ệ

bob - 1 "Hello"/123 bob * "Hello"

Ti n

ệ th ,

ể qua nh ng

ữ bi u

ể th c

ứ trên b n

ạ có phân bi t

ệ đư c

ợ li u

ệ bob là số nguyên hay chu i

ỗ không?

Không. Cách duy nh t

ấ để bi t

ế đư c

ợ ki u

ể c a

ủ bi n

ể là nhìn vào n i

ơ nó đư c

ợ khai báo.

Đi u

ề thú v ịlà toán tử + có tác d n

ụ g v i

ớ chu i

ỗ , nh ng

ư có l

ẽ không ho t

ạ đ ng

ộ theo cách b n

ạ mong đ i

ợ .

Với các String, toán tử + có nhi m

ệ vụn i

ố , nghĩa là ghép n i

ố ti p

ế hai toán h ng

ạ v i

ớ nhau. B i

ở v y

ậ "Hello,

" + "world." sẽ cho ra chu i

ỗ "Hello, world." còn bob + "ism" thì thêm đuôi ism vào b t ấ kì ch

ữ gì

mà bob lưu trữ, cách đặt tên này này th t

ậ ti n

ệ trong tay nh ng

ữ ngư i

ờ quen tính bài bác.

2.9 K t

ế h p

ợ

Đến giờ ta đã xem xét nh ng

ữ thành ph n

ầ c a

ủ ngôn ng

ữ l p

ậ trình—bi n,

ế bi u

ể th c

ứ , và câu l nh

ệ —m t

ộ

cách bi t

ệ l p,

ậ mà ch a

ư nói v

ề cách k t

ế h p

ợ chúng.

Một trong nh ng

ữ đ c

ặ đi m

ể có ích nh t

ấ c a

ủ ngôn ng

ữ l p

ậ trình là kh

ả năng t p

ậ h p

ợ nh ng

ữ thành ph n

ầ

nhỏ r i

ồ kết h p

ợ chúng l i

ạ . Ch ng

ẳ h n,

ạ ta bi t

ế cách tính nhân và bi t

ế dùng l nh

ệ in; nh

ư v y

ậ hóa ra là có

thể kết hợp chúng l i

ạ thành m t

ộ câu l nh

ệ :

System.out.println(17 * 3);

B t

ấ kì bi u

ể th c

ứ nào có s ,

ố chu i

ỗ , và bi n

ế đ u

ề có th

ể dùng trong l nh

ệ in. Ta đã th y

ấ m t

ộ ví d :

ụ

System.out.println(hour*60 + minute);

Nhưng b n

ạ cũng có th

ể đ t

ặ bi u

ể th c

ứ b t

ấ kì

ở v

ế ph i

ả c a

ủ m t

ộ l nh

ệ gán:

int percentage;

percentage = (minute * 100) / 60;

Ngay bây gi

ờ thì tính năng này xem ra ch a

ư có gì n

ấ tư ng

ợ , nh ng

ư ta s

ẽ th y

ấ nh ng

ữ ví d

ụ mà cách k t

ế

hợp này bi u

ể di n

ễ nh ng

ữ phép tính ph c

ứ t p

ạ m t

ộ cách g n

ọ gàng, ngăn n p.

ắ

CẢNH BÁO: V

ế trái c a

ủ m t

ộ l nh

ệ gán ph i

ả là m t

ộ tên bi n

ế , chứ không ph i

ả m t

ộ bi u

ể th c

ứ . Đó là vì v

ế

trái dùng đ

ể ch ỉđ n

ị h v ịtrí l u

ư gi

ữ k t

ế qu .

ả Các bi u

ể th c

ứ thì không th

ể hi n

ệ v ịtrí l u

ư gi

ữ này, mà ch ỉthể

hiện giá tr .ị Vì v y

ậ cách vi t

ế sau không h p

ợ l :

ệ minute+1 = hour;.

2.10 Thu t

ậ ngữ

bi n

ế :

Tên đ c

ượ tham chi u

ế đ n

ế m t

ộ giá tr .ị

giá tr :

ị

Một con s

ố ho c

ặ chu i

ỗ kí t

ự (ho c

ặ nh ng

ữ th

ứ khác sau này đ c

ượ đ t

ặ tên) mà l u

ư tr

ữ đ c

ượ vào trong

một bi n.

ế M i

ỗ giá trị thu c

ộ về m t

ộ kiểu.

kiểu:

M t

ộ t p

ậ h p

ợ g m

ồ các giá tr .ị Ki u

ể c a

ủ bi n

ế quy t

ế đ nh

ị nh ng

ữ giá tr ịnào có th

ể l u

ư tr

ữ trong

bi n

ế đó. Nh ng

ữ kiểu mà ta đã g p

ặ bao g m

ồ ki u

ể s

ố nguyên ( int trong Java) và chu i

ỗ

( String trong Java).

t

ừ khoá:

T

ừ dành riêng cho trình biên d c

ị h đ

ể phân tách m t

ộ ch ng

ươ trình. B n

ạ không th

ể dùng nh ng

ữ t

ừ

khoá nhưpublic, class và void để đặt tên bi n

ế .

lệnh khai báo:

Câu l nh

ệ

nh m

ằ t o

ạ ra m t

ộ bi n

ế m i

ớ và quy đ nh

ị

ki u

ể cho nó.

lệnh gán:

L nh

ệ để gán một giá trị cho m t

ộ bi n.

ế

bi u

ể th c

ứ :

T

ổ h p

ợ c a

ủ các bi n,

ế toán t ,

ử và giá tr ịnh m

ằ bi u

ể di n

ễ m t

ộ giá tr ịk t

ế qu

ả duy nh t

ấ . Bi u

ể th c

ứ cũng có

ki u

ể ; kiểu này đ c

ượ quy t

ế đ nh

ị b i

ở các toán t

ử và toán h ng

ạ .

toán t :

ử

Kí hi u

ệ dùng để bi u

ể di n

ễ m t

ộ phép tính đ n

ơ nh t

ấ nh

ư c ng

ộ , nhân, ho c

ặ n i

ố chu i

ỗ .

toán h n

ạ g:

Một trong nh ng

ữ giá tr ịmà toán t

ử th c

ự hi n

ệ v i

ớ .

u

ư tiên:

Th

ứ t

ự mà nh ng

ữ biểu th c

ứ bao g m

ồ nhi u

ề toán t

ử và toán h ng

ạ đ c

ượ đ nh

ị

l n

ượ g.

n i

ố :

Ghép n i

ố ti p

ế hai toán h ng

ạ .

kết h p:

ợ

Kh

ả năng ghép nh ng

ữ bi u

ể th c

ứ và câu l nh

ệ

đ n

ơ gi n

ả thành nh ng

ữ bi u

ể th c

ứ và câu l nh

ệ

ph c

ứ h p

ợ đ

ể

biểu di n

ễ g n

ọ gàng các thao tác tính toán.

2.11 Bài t p

ậ

BÀI TẬP 1

Nếu đang đọc quy n

ể sách này trên l p,

ớ b n

ạ có th

ể thích bài t p

ậ này: hãy tìm m t

ộ ngư i

ờ b n

ạ

để chơi trò “Stump the Chump”:

B t

ắ đ u

ầ từ một chư ng

ơ trình biên d c

ị h và ch y

ạ đư c

ợ tr n

ơ tru. T ng

ừ ngư i

ờ m t

ộ quay m t

ặ đi

trong lúc người kia gài m t

ộ l i

ỗ vào chư ng

ơ trình. Sau đó ngư i

ờ th

ứ nh t

ấ quay l i

ạ r i

ồ c

ố tìm

và sửa lỗi. N u

ế tìm đư c

ợ l i

ỗ mà không c n

ầ biên d c

ị h, s

ẽ đư c

ợ hai đi m

ể ; tìm đư c

ợ sau khi

biên d c

ị h thì đư c

ợ 1 đi m

ể ; và n u

ế không tìm đư c

ợ thì ngư i

ờ kia s

ẽ đư c

ợ m t

ộ đi m

ể .

BÀI TẬP 2

1. Hãy t o

ạ ra một chư ng

ơ trình có tên Date.java. Sao chép ho c

ặ gõ vào m t

ộ chư ng

ơ trình ki u

ể

như “Hello, World” rồi đảm b o

ả ch c

ắ r n

ằ g b n

ạ có th

ể biên d c

ị h và ch y

ạ đư c

ợ chư ng

ơ trình.

2. Làm theo ví dụ

ở M c

ụ 2.4, hãy vi t

ế m t

ộ chư ng

ơ trình đ

ể t o

ạ ra các

biến day, date, month và year . day sẽ chứa ngày trong tu n ầ còn date thì chứa ngày trong

tháng . Từng bi n

ế s

ẽ có ki u

ể gì? Hãy gán giá tr ịvào nh ng

ữ bi n

ế này đ

ể bi u

ể di n

ễ ngày hôm

nay.

3. In giá tr ịt ng

ừ bi n

ế trên m i

ỗ dòng riêng. Đây là m t

ộ bư c

ớ trung gian và r t

ấ c n

ầ đ

ể ki m

ể tra

r ng

ằ chư ng

ơ trình còn ho t

ạ đ ng

ộ n

ổ th a

ỏ .

4. Sửa chương trình đ

ể in ra ngày theo d ng

ạ chu n

ẩ Hoa Kỳ: Saturday, July 16, 2011.

5. Sửa l i

ạ chư ng

ơ trình l n

ầ n a

ữ đ

ể k t

ế qu

ả thu đư c

ợ là:

American format:

Saturday, July 16, 2011

European format:

Saturday 16 July, 2011

M c

ụ đích c a

ủ bài t p

ậ này là dùng phép n i

ố chu i

ỗ đ

ể hi n

ể th ịcác giá tr ịcó ki u

ể khác

nhau (int và String), đồng th i

ờ th c

ự hành kĩ năng phát tri n

ể d n

ầ chư ng

ơ trình qua vi c

ệ m i

ỗ

l n

ầ chỉ thêm vào một vài câu l nh

ệ .

BÀI TẬP 3

1. Hãy t o

ạ ra một chư ng

ơ trình m i

ớ có tên là Time.java. Từ giờ trở đi, tôi không nh c

ắ b n

ạ b t

ắ

đ u

ầ b n

ằ g vi c

ệ t o

ạ một chư ng

ơ trình nh

ỏ nh ng

ư ch y

ạ đư c

ợ ; song b n

ạ nên làm đi u

ề này.

2. Từ ví dụ

ở M c

ụ 2.6, hãy t o

ạ ra các bi n

ế có tên hour, minute và second, rồi gán cho chúng giá

tr ịbiểu di n

ễ g n

ầ đúng gi

ờ hi n

ệ t i

ạ . Dùng cách đ m

ế s

ố 24 gi ,

ờ theo đó 2 gi

ờ chi u

ề s

ẽ ng

ứ v i

ớ

giá trị c a

ủ hour b n

ằ g 14.

3. Làm cho chư ng

ơ trình tính toán r i

ồ in ra s

ố giây k

ể t

ừ n a

ử đêm.

4. Làm cho chư ng

ơ trình tính toán r i

ồ in ra s

ố giây t

ừ gi

ờ đ n

ế hết ngày hôm nay.

5. Làm cho chư ng

ơ trình tính toán r i

ồ in ra s

ố ph n

ầ trăm th i

ờ gian đã trôi qua trong ngày hôm

nay.

6. Thay đ i

ổ các giá tr ịc a

ủ hour, minute và second để ph n

ả ánh th i

ờ gian hi n

ệ t i

ạ (coi nh

ư có

thời gian trôi qua k

ể t

ừ l n

ầ ch y

ạ trư c

ớ ), và ki m

ể tra đ

ể đ m

ả b o

ả r ng

ằ chư ng

ơ trình ho t

ạ

động được với nhi u

ề giá trị khác nhau.

M c

ụ đích c a

ủ bài t p

ậ này là v n

ậ d n

ụ g m t

ộ s

ố phép toán, và b t

ắ đ u

ầ suy nghĩ v

ề nh ng

ữ d

ữ

liệu phức h p

ợ nh

ư th i

ờ gian trong ngày, v n

ố đư c

ợ bi u

ể di n

ễ b i

ở nhi u

ề giá tr .ị Đ ng

ồ th i

ờ ,

b n

ạ cũng có th

ể v p

ấ ph i

ả nhi u

ề v n

ấ đề khi tính ph n

ầ trăm v i

ớ các số int; đây chính là lí do

d n

ẫ đ n

ế vi c

ệ dùng s

ố có d u

ấ ph y

ẩ đ ng

ộ trong chư ng

ơ sau.

G I

Ợ Ý: có th

ể b n

ạ s

ẽ c n

ầ dùng thêm các bi n

ế đ

ể l u

ư gi

ữ t m

ạ th i

ờ nh ng

ữ giá tr ịtrong quá

trình tính toán. Các bi n

ế ki u

ể này, v n

ố đư c

ợ dùng trong tính toán nh ng

ư không bao gi

ờ

đư c

ợ in ra, đôi khi đư c

ợ g i

ọ là bi n

ế trung gian ho c

ặ bi n

ế t m

ạ .

Ch

ng

ươ 3: Ph ng

ươ

th c

ứ r ng

ỗ

Trở về M c

ụ l c

ụ cuốn sách 3.1 D u ph

ấ

y đ

ẩ

n

ộ g

Ở chương trước ta đã g p

ặ tr c

ụ tr c

ặ khi tính toán nh ng

ữ s

ố không nguyên. Ta đã s a

ử m t

ộ cách t m

ạ b

ợ

b n

ằ g việc tính số ph n

ầ trăm thay vì s

ố th p

ậ phân, nh ng

ư m t

ộ gi i

ả pháp t ng

ổ quát h n

ơ s

ẽ là dùng s

ố có

d u

ấ ph y

ẩ động, để bi u

ể di n

ễ đư c

ợ c

ả s

ố nguyên l n

ẫ s

ố có ph n

ầ th p

ậ phân. Trong Java, ki u

ể d u

ấ ph y

ẩ

động có tên double, là ch

ữ gọi tắt c a

ủ “double-precision” (đ

ộ chu n

ẩ xác kép).

B n

ạ có thể t o

ạ nên các bi n

ế ph y

ẩ đ ng

ộ r i

ồ gán giá tr ịcho chúng theo cú pháp gi ng

ố nh

ư ta đã làm v i

ớ

những ki u

ể d

ữ li u

ệ khác. Ch ng

ẳ h n:

ạ

double pi;

pi = 3.14159;

Việc khai báo m t

ộ bi n

ế đ ng

ồ th i

ờ gán giá tr ịcho nó cũng h p

ợ l :

ệ

int x = 1;

String empty = "";

double pi = 3.14159;

Cú pháp này r t

ấ thông d ng

ụ ; vi c

ệ k t

ế h p

ợ gi a

ữ khai báo và gán đôi khi còn đư c

ợ g i

ọ là phép kh i

ở t o

ạ .

M c

ặ dù các s

ố ph y

ẩ đ ng

ộ r t

ấ h u

ữ ích nh ng

ư chúng cũng là ngu n

ồ gây nên r c

ắ r i

ố , vì dư ng

ờ nh

ư có ph n

ầ

trùng nhau gi a

ữ các s

ố nguyên và s

ố ph y

ẩ đ ng

ộ . Ch ng

ẳ h n,

ạ n u

ế b n

ạ có giá trị 1, thì đó là số nguyên, s

ố

ph y

ẩ động, hay c

ả hai?

Java phân bi t

ệ giá tr ịs

ố nguyên 1 với giá tr ịph y

ẩ đ ng

ộ 1.0, dù r ng

ằ chúng có v

ẻ cùng là m t

ộ s .

ố Chúng

thu c

ộ v

ề hai ki u

ể d

ữ li u

ệ khác nhau, và nói ch t

ặ ch

ẽ thì b n

ạ không đư c

ợ phép gán giá tr ịki u

ể này cho

một bi n

ế ki u

ể khác. Ch n

ẳ g h n,

ạ câu l nh

ệ sau là h p

ợ l :

ệ

int x = 1.1;

vì bi n

ế

ở v

ế trái là int còn giá tr ị

ở v

ế ph i

ả là double. Nhưng r t

ấ d

ễ quên m t

ấ quy t c

ắ này, đ c

ặ bi t

ệ là vì

có nh ng

ữ n i

ơ mà Java s

ẽ t

ự đ ng

ộ chuy n

ể t

ừ m t

ộ ki u

ể này sang ki u

ể khác. Ch ng

ẳ h n:

ạ

double y = 1;

về lý thì không h p

ợ l ,

ệ nh ng

ư Java v n

ẫ cho phép đi u

ề này nh

ờ cách t

ự đ ng

ộ chuy n

ể đ i

ổ

từ int sang double. Sự dễ dãi này khá ti n

ệ l i

ợ , song có th

ể g p

ặ v n

ấ đ ,

ề ch ng

ẳ h n:

ạ

double y = 1 / 3;

B n

ạ có thể trông đ i

ợ r ng

ằ bi n

ế y nh n

ậ giá trị 0.333333, vốn là một giá trị ph y

ẩ động hoàn toàn h p

ợ l ,

ệ

song th c

ự ra nó nh n

ậ đư c

ợ 0.0. Lý do là bi u

ể th c

ứ v

ế ph i

ả là t ỉs

ố gi a

ữ hai s

ố nguyên, vì v y

ậ Java th c

ự

hiện phép chia nguyên, và cho giá tr ịs

ố nguyên b ng

ằ 0. Chuy n

ể thành d n

ạ g s

ố ph y

ẩ đ ng

ộ , k t

ế qu

ả

là 0.0.

Một cách gi i

ả quy t

ế v n

ấ đề này (khi b n

ạ đã hình dung ra) là làm cho v

ế ph i

ả tr

ở thành m t

ộ bi u

ể th c

ứ

chứa số ph y

ẩ đ ng

ộ :

double y = 1.0 / 3.0;

B ng

ằ cách này đã đ t

ặ y b ng

ằ 0.333333, như dự ki n.

ế

Các toán t

ử mà ta đã g p

ặ đ n

ế gi —

ờ c ng

ộ , tr ,

ừ nhân, và chia—cũng làm vi c

ệ đư c

ợ v i

ớ các giá tr ịd u

ấ ph y

ẩ

động, m c

ặ dù b n

ạ có thể th y

ấ thú v ịkhi bi t

ế đư c

ợ r ng

ằ c

ơ ch

ế bên trong thì khác h n

ẳ . Th c

ự ra, đa s

ố các

bộ vi xử lý đều có ph n

ầ m m

ề chuyên d n

ụ g đ

ể th c

ự hi n

ệ các phép tính có d u

ấ ph y

ẩ đ ng

ộ .

3.2 Chuy n đ

ể

i t

ổ ừ double sang int

Như tôi đã nói, Java quy đ i

ổ các số int thành double một cách t

ự động n u

ế th y

ấ c n

ầ thi t

ế , vì trong quá

trình chuy n

ể đ i

ổ không b ịm t

ấ thông tin. Ngư c

ợ l i

ạ , chuy n

ể từ double sang int l i

ạ c n

ầ ph i

ả làm tròn s .

ố

Java không t

ự đ ng

ộ làm vi c

ệ này, đ

ể đ m

ả b o

ả r ng

ằ b n,

ạ ngư i

ờ l p

ậ trình, cũng bi t

ế đư c

ợ r n

ằ g ph n

ầ th p

ậ

phân c a

ủ số s

ẽ b ịm t

ấ đi.

Cách đ n

ơ gi n

ả nh t

ấ đ

ể chuy n

ể m t

ộ giá tr ịs

ố ph y

ẩ đ ng

ộ sang s

ố nguyên là th c

ự hi n

ệ vi c

ệ định

kiểu (typecast). S

ở dĩ g i

ọ là đ nh

ị ki u

ể vì b n

ằ g cách đó ta có th

ể l y

ấ m t

ộ giá tr ịthu c

ộ ki u

ể này r i

ồ “ n

ấ

đ nh

ị ” nó thành ki u

ể khác (nh

ư vi c

ệ đ nh

ị hình b ng

ằ khuôn đúc kim lo i

ạ ).

Cú pháp c a

ủ đ nh

ị ki u

ể là đ t

ặ tên ki u

ể gi a

ữ c p

ặ ngo c

ặ tròn r i

ồ dùng nó nh

ư m t

ộ toán t .

ử Ch ng

ẳ h n

ạ ,

double pi = 3.14159;

int x = (int) pi;

Toán tử (int) có tác d n

ụ g chuy n

ể b t

ấ kì th

ứ gì đi sau nó thành m t

ộ s

ố nguyên, b i

ở v y

ậ x nh n

ậ giá tr ị

b n

ằ g 3.

Đ nh

ị ki u

ể có quy n

ề

u

ư tiên cao h n

ơ so v i

ớ các toán t

ử s

ố h c

ọ , b i

ở v y

ậ

ở ví d

ụ sau, trư c

ớ h t

ế giá tr ịc a

ủ

pi được chuy n

ể thành số nguyên, và k t

ế qu

ả s

ẽ là 60.0, ch

ứ không ph i

ả 62.

double pi = 3.14159;

double x = (int) pi * 20.0;

Việc chuy n

ể thành s

ố nguyên s

ẽ luôn làm tròn xu ng

ố , ngay c

ả khi ph n

ầ th p

ậ phân là 0.99999999. Cách

ho t

ạ động này (quy n

ề

u

ư tiên và vi c

ệ làm tròn) có th

ể khi n

ế cho vi c

ệ đ nh

ị ki u

ể d

ễ gây nên l i

ỗ .

3.3 Các phương thức Math

Khi làm toán, có l

ẽ b n

ạ đã th y

ấ các hàm nh

ư sin và log, đ ng

ồ th i

ờ cũng bi t

ế cách tính các bi u

ể th c

ứ nh

ư

sin(π/2) và log(1/ x). Đ u

ầ tiên, b n

ạ lư ng

ợ giá bi u

ể th c

ứ trong c p

ặ ngo c

ặ tròn, v n

ố đư c

ợ g i

ọ là đ i

ố số c a

ủ

hàm. Ti p

ế theo b n

ạ lư ng

ợ giá b n

ả thân hàm đó, b n

ằ g cách tra b ng

ả ho c

ặ tính toán.

Công đo n

ạ này có thể đư c

ợ áp d n

ụ g l p

ặ l i

ạ đ

ể lư ng

ợ giá nh ng

ữ bi u

ể th c

ứ ph c

ứ t p

ạ h n

ơ nh

ư

log(1/sin(π/2)). Đ u

ầ tiên, b n

ạ lư ng

ợ giá đ i

ố s

ố c a

ủ hàm đ ng

ứ trong cùng, r i

ồ lư ng

ợ giá b n

ả thân hàm

đó, và c

ứ nh

ư v y

ậ .

Java cung c p

ấ cho ta các hàm đ

ể th c

ự hi n

ệ nh ng

ữ phép toán thông d ng

ụ nh t

ấ . Nh ng

ữ hàm này đư c

ợ g i

ọ

là ph

n

ươ g th c

ứ . Các phư ng

ơ th c

ứ toán h c

ọ đư c

ợ kích ho t

ạ b ng

ằ cách dùng cú pháp tư ng

ơ t

ự nh

ư câu

lệnh print mà ta đã g p:

ặ

double root = Math.sqrt(17.0);

double angle = 1.5;

double height = Math.sin(angle);

Ví d

ụ đ u

ầ tiên đặt root b ng

ằ căn b c

ậ hai c a

ủ 17. Ví d

ụ th

ứ hai đi tìm sin c a

ủ giá trị angle, vốn là 1.5. Java

giả thiết r ng

ằ nh ng

ữ giá tr ịb n

ạ dùng v i

ớ sin và các hàm lư ng

ợ giác khác (cos, tan) đ u

ề tính theo radian.

Để chuy n

ể t

ừ độ sang radian, b n

ạ có th

ể chia cho 360 đ ng

ồ th i

ờ nhân v i

ớ 2π. Th t

ậ ti n

ệ là Java có cung

c p

ấ Math.PI:

double degrees = 90;

double angle = degrees * 2 * Math.PI / 360.0;

Lưu ý r n

ằ g chữ PI đều vi t

ế in toàn b .

ộ Java không nh n

ậ ra Pi, pi, hay pie.

Một phương th c

ứ h u

ữ d ng

ụ khác có trong l p

ớ Math là round, đ

ể làm tròn m t

ộ giá tr ịs

ố ph y

ẩ đ ng

ộ v

ề số

nguyên g n

ầ đó nh t

ấ r i

ồ tr

ả l i

ạ m t

ộ int.

int x = Math.round(Math.PI * 20.0);

Trong trư ng

ờ h p

ợ này phép nhân x y

ả ra đ u

ầ tiên, trư c

ớ khi phư ng

ơ th c

ứ đư c

ợ kích ho t

ạ . K t

ế qu

ả là 63

(được làm tròn lên t

ừ 62.8319).

3.4 K t

ế h p

ợ

Cũng nh

ư v i

ớ các hàm toán h c

ọ , nh ng

ữ phư ng

ơ th c

ứ trong Java có th

ể đư c

ợ kết h p

ợ l i

ạ , nghĩa là b n

ạ

có th

ể dùng một bi u

ể th c

ứ làm thành ph n

ầ trong bi u

ể th c

ứ khác. Ch n

ẳ g h n,

ạ b n

ạ có th

ể dùng b t

ấ kì

bi u

ể th c

ứ nào làm đ i

ố s

ố cho m t

ộ phư ng

ơ th c

ứ :

double x = Math.cos(angle + Math.PI/2);

Câu l nh

ệ này l y

ấ giá trị Math.PI, đem chia cho hai r i

ồ c ng

ộ k t

ế qu

ả thu đư c

ợ vào giá tr ịc a

ủ bi n

ế angle.

Ti p

ế theo, tổng này đư c

ợ truy n

ề làm tham s

ố cho cos. (PI là tên c a

ủ một bi n,

ế ch

ứ không ph i

ả m t

ộ

phương th c

ứ ; b i

ở v y

ậ mà không có đ i

ố s

ố nào, th m

ậ chí không có c

ả đ i

ố s

ố r ng

ỗ ()).

B n

ạ cũng có th

ể l y

ấ k t

ế qu

ả c a

ủ m t

ộ phư ng

ơ th c

ứ đ

ể truy n

ề làm đ i

ố s

ố cho phư ng

ơ th c

ứ khác:

double x = Math.exp(Math.log(10.0));

Trong Java, phư ng

ơ th c

ứ log luôn dùng c

ơ số b ng

ằ e, bởi v y

ậ câu l nh

ệ này tìm loga c

ơ số e c a

ủ 10 rồi

nâng e lên số mũ đó. K t

ế qu

ả đư c

ợ gán cho x; hi vọng r n

ằ g b n

ạ bi t

ế phép tính này đ

ể làm gì.

3.5 B su

ổ

ng những phư n

ơ g th c m

ứ

i

ớ

Đến bây gi ,

ờ chúng ta m i

ớ ch ỉdùng nh ng

ữ phư ng

ơ th c

ứ có s n

ẵ trong Java, song th t

ậ ra có th

ể t o

ạ ra

những phư ng

ơ th c

ứ m i

ớ . Ta đã th y

ấ một l i

ờ đ nh

ị nghĩa cho phư ng

ơ th c

ứ main. Phương thức tên

là main có ý nghĩa đ c

ặ bi t

ệ , song cú pháp c a

ủ nó cũng gi ng

ố nh

ư các phư ng

ơ th c

ứ khác:

public static void TÊN( DANH SÁCH THAM SỐ ) { CÁC CÂU LỆNH }

B n

ạ có thể l y

ấ tên b t

ấ kì đ

ể đ t

ặ cho phư ng

ơ th c

ứ m i

ớ , mi n

ễ là không ph i

ả main hay một t

ừ khóa Java

nào đó. Theo quy ư c

ớ , các phư ng

ơ th c

ứ Java b t

ắ đ u

ầ b n

ằ g ch

ữ thư ng

ờ và dùng cách vi t

ế in t ng

ừ ch

ữ đ u

ầ

c a

ủ từ (còn g i

ọ là “camel caps”), m t

ộ tên g i

ọ thú v ịđ

ể ch ỉnh ng

ữ cái tên ki u

ể

như jammingWordsTogetherLikeThis.

Danh sách các tham s

ố thì quy đ nh

ị nh ng

ữ thông tin (n u

ế có) mà b n

ạ ph i

ả cung c p

ấ khi dùng (hay kích

ho t

ạ ) phương thức m i

ớ này.

Tham số c a

ủ phư ng

ơ th c

ứ main là String[] args; đi u

ề này nghĩa là ai mu n

ố kích ho t

ạ main thì ph i

ả cung

c p

ấ một m ng

ả các chu i

ỗ (String) (ta s

ẽ bàn đ n

ế m ng

ả

ở Chư ng

ơ 12). Một số phư ng

ơ th c

ứ ta t p

ậ vi t

ế đ u

ầ

tay thì không có tham s

ố nào, vì v y

ậ cú pháp s

ẽ có d ng

ạ nh

ư sau:

public static void newLine() {

System.out.println("");

}

Phương th c

ứ này có tên newLine, và c p

ặ ngo c

ặ tròn không ch a

ứ gì đ ng

ồ nghĩa v i

ớ vi c

ệ phư ng

ơ th c

ứ này

không nh n

ậ tham s .

ố Nó ch ỉcó m t

ộ câu l nh

ệ , nh m

ằ in m t

ộ String rỗng, được bi u

ể th ịb i

ở "". Việc in

một String mà không có ch

ữ nào trong đó dư ng

ờ nh

ư là vi c

ệ vô ích, nh ng

ư vì println sẽ nh y

ả xuống

dòng dưới sau khi in, nên câu l nh

ệ này có tác d n

ụ g xu ng

ố dòng.

Trong main ta kích ho t

ạ phư ng

ơ th c

ứ m i

ớ này cũng gi ng

ố nh

ư cách ta kích ho t

ạ các phư ng

ơ th c

ứ c a

ủ

Java:

public static void main(String[] args) {

System.out.println("First line.");

newLine();

System.out.println("Second line.");

}

Kết qu

ả c a

ủ chư ng

ơ trình này là

First line.

Second line.

Lưu ý đ n

ế dòng tr ng

ố gi a

ữ hai dòng ch

ữ trên. Ta ph i

ả làm gì n u

ế mu n

ố hai dòng này cách nhau xa h n?

ơ

Ta có th

ể liên ti p

ế kích ho t

ạ phư ng

ơ th c

ứ m i

ớ này:

public static void main(String[] args) {

System.out.println("First line.");

newLine();

newLine();

newLine();

System.out.println("Second line.");

}

Ho c

ặ ta cũng có th

ể vi t

ế m t

ộ phư ng

ơ th c

ứ m i

ớ khác, có tên threeLine, đ

ể in ra ba dòng tr ng

ố :

public static void threeLine() {

newLine(); newLine(); newLine();

}

public static void main(String[] args) {

System.out.println("First line.");

threeLine();

System.out.println("Second line.");

}

B n

ạ có thể nh n

ậ th y

ấ vài đi u

ề sau t

ừ chư ng

ơ trình trên:

•Có thể kích hoạt cùng m t

ộ phư ng

ơ th c

ứ nhi u

ề l n.

ầ

•Trong một phư ng

ơ th c

ứ , b n

ạ có th

ể kích ho t

ạ m t

ộ phư ng

ơ th c

ứ khác.

Ở trư ng

ờ h p

ợ này, main kích

ho t

ạ threeLine còn threeLine thì kích hoạt newLine.

•Trong threeLine tôi đã vi t

ế ba câu l nh

ệ trên cùng m t

ộ dòng; đây là đi u

ề hoàn toàn h p

ợ l

ệ (hãy nh

ớ l i

ạ

r n

ằ g các dấu trống và d u

ấ xu ng

ố dòng thư ng

ờ không làm thay đ i

ổ ý nghĩa c a

ủ chư ng

ơ trình). M c

ặ dù ta

nên đ t

ặ m i

ỗ câu l nh

ệ trên m t

ộ dòng riêng, song đôi khi tôi v n

ẫ phá v

ỡ nguyên t c

ắ này.

Có th

ể b n

ạ s

ẽ t

ự hỏi t i

ạ sao l i

ạ phi n

ề ph c

ứ t o

ạ ra nh ng

ữ phư ng

ơ th c

ứ m i

ớ nh

ư v y

ậ . Có m t

ộ vài lí do, mà

hai lí do trong s

ố đó th

ể hi n

ệ qua ví d

ụ trên là:

1.Việc t o

ạ phương th c

ứ m i

ớ cho ta c

ơ h i

ộ đ t

ặ tên cho m t

ộ nhóm các câu l nh

ệ . Nh ng

ữ phư ng

ơ th c

ứ có

thể làm đơn gi n

ả chư ng

ơ trình qua vi c

ệ n

ẩ gi u

ấ nh ng

ữ thao tác tính toán ph c

ứ t p

ạ phía sau m t

ộ câu

lệnh đơn gi n

ả , và qua vi c

ệ dùng nh ng

ữ t

ừ ti ng

ế Anh thay cho mã l nh

ệ bí hi m

ể . Theo b n,

ạ cách vi t

ế nào

rõ ràng h n,

ơ newLine hay System.out.println("")?

2.Việc t o

ạ phương th c

ứ m i

ớ có th

ể rút ng n

ắ chư ng

ơ trình b ng

ằ cách lo i

ạ b

ỏ nh ng

ữ đo n

ạ mã l nh

ệ l p

ặ đi

l p

ặ l i

ạ . Ch n

ẳ g h n,

ạ đ

ể in chín dòng tr ng

ố liên ti p,

ế b n

ạ ch ỉc n

ầ kích ho t

ạ threeLine đúng ba l n

ầ .

Ở m c

ụ 7.6 ta sẽ quay tr

ở l i

ạ câu h i

ỏ này đ ng

ồ th i

ờ k

ể thêm m t

ộ s

ố l i

ợ ích khác c a

ủ vi c

ệ chia nh

ỏ chư ng

ơ

trình thành các phư ng

ơ th c

ứ .

3.6 L p v

ớ

à phư ng t

ơ

h c

ứ

Ch p

ắ nối l i

ạ nh ng

ữ đo n

ạ mã t

ừ m c

ụ trư c

ớ , ta có l i

ờ đ nh

ị nghĩa l p

ớ nh

ư sau:

class NewLine {

public static void newLine() {

System.out.println("");

}

public static void threeLine() {

newLine(); newLine(); newLine();

}

public static void main(String[] args) {

System.out.println("First line.");

threeLine();

System.out.println("Second line.");

}

}

Dòng th

ứ nh t

ấ cho bi t

ế r ng

ằ đó là l i

ờ đ nh

ị nghĩa m t

ộ l p

ớ m i

ớ có tên NewLine. L p

ớ là t p

ậ hợp các

phương th c

ứ có liên quan đ n

ế nhau. Trong trư ng

ờ h p

ợ này, l p

ớ v i

ớ tên g i

ọ NewLine có ch a

ứ 3 phư ng

ơ

thức tên là newLine, threeLine, và main.

Một lớp khác mà ta đã g p

ặ là l p

ớ Math. Nó gồm các phư ng

ơ th c

ứ có tên sqrt, sin, v.v. Khi kích ho t

ạ m t

ộ

phương th c

ứ toán học, ta ph i

ả nêu tên c a

ủ l p

ớ (Math) và tên c a

ủ phư ng

ơ th c

ứ . Đó là lý do mà v

ề cú

pháp, có đi m

ể khác bi t

ệ nh

ỏ gi a

ữ các phư ng

ơ th c

ứ Java và các phư ng

ơ th c

ứ mà ta vi t

ế :

Math.pow(2.0, 10.0);

newLine();

Câu l nh

ệ th

ứ nh t

ấ kích ho t

ạ phư ng

ơ th c

ứ pow trong l p

ớ Math (đ

ể đưa đối số th

ứ nh t

ấ lên lũy th a

ừ c p

ấ

c a

ủ đối số th

ứ hai). Câu l nh

ệ ti p

ế theo kích ho t

ạ phư ng

ơ th c

ứ newLine, mà Java gi

ả s

ử r ng

ằ nó có

ở

trong l p

ớ mà ta đang (t c

ứ là l p

ớ NewLine).

Nếu b n

ạ thử kích ho t

ạ nh m

ầ m t

ộ phư ng

ơ th c

ứ t

ừ l p

ớ khác, trình biên d c

ị h s

ẽ phát sinh m t

ộ l i

ỗ . Ch n

ẳ g

h n

ạ , nếu b n

ạ gõ vào:

pow(2.0, 10.0);

Trình biên d c

ị h s

ẽ nói ki u

ể nh ,

ư “Không th

ể tìm th y

ấ phư ng

ơ th c

ứ có tên pow trong l p

ớ NewLine.” Nếu

b n

ạ từng th y

ấ l i

ờ thông báo này và có l

ẽ đã t

ự h i

ỏ r ng

ằ t i

ạ sao nó ph i

ả tìm pow trong lời đ nh

ị nghĩa l p

ớ

c a

ủ b n,

ạ thì bây gi

ờ b n

ạ đã bi t

ế r i

ồ đó.

3.7 Chương trình có nhi u ph

ề

ư ng t

ơ

h c

ứ

Khi b n

ạ nhìn vào l i

ờ đ nh

ị nghĩa m t

ộ l p

ớ có ch a

ứ nhi u

ề phư ng

ơ th c

ứ , t t

ấ s

ẽ có xu hư ng

ớ mu n

ố đ c

ọ t

ừ

trên xuống dưới, nh ng

ư đi u

ề này d

ễ gây nh m

ầ l n

ầ , b i

ở đó không ph i

ả là thứ t

ự th c

ự hiện chương

trình.

Việc thực hi n

ệ (th c

ự thi) luôn b t

ắ đ u

ầ t

ừ câu l nh

ệ th

ứ nh t

ấ c a

ủ main, b t

ấ k

ể nó nằm đâu trong chư ng

ơ

trình (

ở ví d

ụ này thì tôi đã c

ố ý đ t

ặ

ở cu i

ố cùng). Nh ng

ữ câu l nh

ệ đư c

ợ th c

ự hi n

ệ l n

ầ lư t

ợ , theo th

ứ t ,

ự

đến khi b n

ạ g p

ặ một l i

ờ g i

ọ (kích ho t

ạ ) phư ng

ơ th c

ứ . Vi c

ệ kích ho t

ạ phư ng

ơ th c

ứ cũng gi ng

ố nh

ư l i

ố r

ẽ

khỏi luồng th c

ự thi chư ng

ơ trình. Thay vì đi ti p

ế đ n

ế câu l nh

ệ li n

ề k ,

ề b n

ạ chuy n

ể đ n

ế dòng l nh

ệ đ u

ầ

tiên được kích ho t

ạ , th c

ự hi n

ệ t t

ấ c

ả nh ng

ữ câu l nh

ệ

ở đó, r i

ồ quay l i

ạ và ti p

ế t c

ụ t i

ạ đi m

ể đã r

ẽ ngang.

Đi u

ề này nghe th t

ậ đ n

ơ gi n,

ả song b n

ạ v n

ẫ c n

ầ nh

ớ r ng

ằ m t

ộ phư ng

ơ th c

ứ có th

ể kích ho t

ạ phư ng

ơ

thức khác. B i

ở v y

ậ , khi ta đang

ở đo n

ạ gi a

ữ c a

ủ main, ta có th

ể buộc ph i

ả d i

ờ đi đ

ể th c

ự hi n

ệ nh ng

ữ câu

lệnh trong threeLine. Nh

ư trong khi th c

ự thi threeLine, có ba l n

ầ ta b ịgián đo n

ạ và ph i

ả d i

ờ đi và th c

ự

hiện newLine.

Về ph n

ầ mình, newLine kích ho t

ạ println, và t o

ạ thêm một lối r

ẽ n a

ữ . Th t

ậ may là Java r t

ấ khéo theo

dõi vị trí đang th c

ự thi, nên khi println hoàn thành, công vi c

ệ l i

ạ đư c

ợ tr

ả v

ề đúng ch

ỗ mà v a

ừ r i

ờ

khỏi newLine, và sau đó thì tr

ở l i

ạ threeLine, rồi sau cùng tr

ở l i

ạ main để chương trình có thể k t

ế thúc.

Xét v

ề khía c nh

ạ kĩ thu t

ậ , chư ng

ơ trình ch a

ư k t

ế thúc sau main. Thay vì v y

ậ , lu ng

ồ th c

ự thi tìm đ n

ế ch

ỗ

mà nó d i

ờ kh i

ỏ chư ng

ơ trình đã kích ho t

ạ main, tức là trình thông d c

ị h Java. Trình thông d c

ị h này đ m

ả

nhiệm các vi c

ệ nh

ư xóa c a

ử s

ổ và d n

ọ d p

ẹ nói chung, r i

ồ sau đó chương trình m i

ớ k t

ế thúc.

V y

ậ nghĩa lí c a

ủ toàn b

ộ nh ng

ữ th

ứ l ng

ằ nh ng

ằ này là gì? Khi đ c

ọ m t

ộ chư ng

ơ trình, b n

ạ đ ng

ừ đ c

ọ t

ừ

trên xuống dưới, mà ph i

ả đ c

ọ theo lu ng

ồ th c

ự thi.

3.8 Tham s v

ố à đ i s

ố ố

Có những phư ng

ơ th c

ứ ta đã dùng yêu c u

ầ ph i

ả có đ i

ố số, vốn là nh ng

ữ giá tr ịmà b n

ạ c n

ầ cung c p

ấ đ

ể

có th

ể kích ho t

ạ đư c

ợ chúng. Ch ng

ẳ h n,

ạ đ

ể tìm sin c a

ủ m t

ộ s ,

ố b n

ạ ph i

ả cung c p

ấ s

ố đó. Nh

ư

v y

ậ , sin đã nh n

ậ đối số là một double. Đ

ể in ra một chu i

ỗ , b n

ạ ph i

ả cung c p

ấ chu i

ỗ đó, vì

v y

ậ println nh n

ậ đối số là một String.

L i

ạ có nh ng

ữ phư ng

ơ th c

ứ nh n

ậ nhi u

ề đ i

ố s ;

ố ch ng

ẳ h n,

ạ pow nh n

ậ hai double, đó là c

ơ số và số mũ.

Khi b n

ạ dùng m t

ộ phư ng

ơ th c

ứ , b n

ạ ph i

ả cung c p

ấ đ i

ố s .

ố Khi b n

ạ vi t

ế m t

ộ phư ng

ơ th c

ứ , b n

ạ cung c p

ấ

một danh sách các tham s

ố (hay tham bi n)

ế . M t

ộ tham số là một bi n

ế đ

ể ch a

ứ m t

ộ đ i

ố s .

ố Danh sách

các tham bi n

ế ch ỉđ nh

ị r n

ằ g c n

ầ ph i

ả có nh ng

ữ đ i

ố s

ố nào.

Ch ng

ẳ h n,

ạ printTwice ch ỉđ nh

ị một tham số duy nh t

ấ , s, vốn có ki u

ể String. Tôi đ t

ặ tên nó là s để gợi

nhớ r n

ằ g đó là một String, song tôi cũng có th

ể đ t

ặ b t

ấ kì tên bi n

ế h p

ợ l

ệ nào cho nó.

public static void printTwice(String s) {

System.out.println(s);

System.out.println(s);

}

Khi kích ho t

ạ printTwice, ta ph i

ả cung c p

ấ m t

ộ đ i

ố s

ố duy nh t

ấ có ki u

ể String.

printTwice("Don't make me say this twice!");

Khi b n

ạ kích ho t

ạ m t

ộ phư ng

ơ th c

ứ , đ i

ố s

ố mà b n

ạ cung c p

ấ đư c

ợ dùng đ

ể gán cho các tham s .

ố Trong

trường hợp này, đối số "Don’t make me say this twice!" đư c ợ gán cho tham số s. Quá trình này đư c

ợ g i

ọ

là truy n

ề tham số vì giá tr ịđư c

ợ truy n

ề t

ừ bên ngoài phư ng

ơ th c

ứ vào bên trong.

Một đ i

ố số có thể là bi u

ể th c

ứ b t

ấ kì, vì v y

ậ n u

ế b n

ạ có m t

ộ bi n

ế String thì có th

ể dùng chính bi n

ế này

làm đối số:

String argument = "Never say never.";

printTwice(argument);

Giá tr ịmà b n

ạ cung c p

ấ làm đ i

ố s

ố s

ẽ ph i

ả có cùng ki u

ể v i

ớ tham s .

ố Ch n

ẳ g h n,

ạ n u

ế b n

ạ th

ử dòng l nh

ệ

sau:

printTwice(17);

B n

ạ s

ẽ nh n

ậ được thông báo l i

ỗ ki u

ể nh

ư “cannot find symbol” (không tìm th y

ấ kí hi u

ệ ); thông báo này

không m y

ấ h u

ữ ích. Lí do là Java đang tìm m t

ộ phư ng

ơ th c

ứ có tên printTwice mà có th

ể nh n

ậ đối s

ố là

số nguyên. Vì ch n

ẳ g có phư ng

ơ th c

ứ nào nh

ư v y

ậ nên nó không th

ể tìm th y

ấ “kí hi u

ệ ” đó.

System.out.println ch p

ấ nh n

ậ đư c

ợ tham s

ố thu c

ộ ki u

ể d

ữ li u

ệ b t

ấ kì. Nh ng

ư phư ng

ơ th c

ứ này ch ỉlà

một ngo i

ạ l ;

ệ đ i

ạ đa s

ố các phư ng

ơ th c

ứ thì không d

ễ tính nh

ư v y

ậ .

3.9 Bi u đ

ể

n

ồ găn x p

ế

Các tham số và nh ng

ữ bi n

ế khác ch ỉt n

ồ t i

ạ trong phư ng

ơ th c

ứ riêng c a

ủ chúng. Trong ph m

ạ vi

c a

ủ main, không có cái gì g i

ọ là s. N u

ế b n

ạ th

ử dùng bi n

ế này, trình biên d c

ị h s

ẽ ph n

ả đ i

ố . Tư ng

ơ t ,

ự

trong printTwice không có th

ứ gì g i

ọ là argument c .

ả

Một cách theo dõi xem nh ng

ữ bi n

ế nào đư c

ợ s

ử d ng

ụ

ở đâu là dùng m t

ộ biểu đ

ồ ngăn x p

ế . Với ví d

ụ

trên, bi u

ể đồ ngăn x p

ế sẽ nh

ư sau:

Mỗi phương th c

ứ đ u

ề có m t

ộ h p

ộ màu xám g i

ọ là khung., trong đó ch a

ứ các tham s

ố và bi n

ế c a

ủ

phương th c

ứ . Tên c a

ủ phư ng

ơ th c

ứ đư c

ợ ghi bên ngoài khung. Nh

ư thư ng

ờ l ,

ệ giá tr ịc a

ủ m i

ỗ bi n

ế l i

ạ

được viết trong một hộp cùng v i

ớ tên bi n

ế ghi bên c nh

ạ .

3.10 Phương thức có nhi u t

ề

ham số

Có một lý do thư ng

ờ gây ra l i

ỗ khi l p

ậ trình: đó chính là cú pháp đ

ể miêu t

ả và kích ho t

ạ phư ng

ơ th c

ứ

gồm nhi u

ề tham số. Trư c

ớ h t

ế , hãy nh

ớ r ng

ằ b n

ạ ph i

ả khai báo ki u

ể c a

ủ t ng

ừ tham s .

ố Ch ng

ẳ h n

ạ

public static void printTime(int hour, int minute) {

System.out.print(hour);

System.out.print(":");

System.out.println(minute);

}

R t

ấ d

ễ b ịlôi cu n

ố theo cách vi t

ế int hour, minute, nhưng cách này ch ỉđúng v i

ớ vi c

ệ khai báo bi n,

ế ch

ứ

không ph i

ả v i

ớ danh sách tham s .

ố

Một lý do khác gây nh m

ầ l n

ẫ là b n

ạ không c n

ầ ph i

ả khai báo ki u

ể c a

ủ đ i

ố s .

ố Vi t

ế nh

ư dư i

ớ đây là sai!

int hour = 11;

int minute = 59;

printTime(int hour, int minute); // SAI!

Trong trư ng

ờ h p

ợ này, Java có th

ể t

ự bi t

ế ki u

ể c a

ủ hour và minute khi nhìn vào đo n

ạ khai báo c a

ủ

chúng. Ta không c n

ầ ph i

ả kèm thêm ki u

ể c a

ủ bi n

ế khi truy n

ề chúng làm đ i

ố s .

ố Cú pháp đúng ph i

ả là

printTime(hour, minute).

3.11 Các phương th c t

ứ r l

ả i k

ạ

t

ế quả

Một số phương th c

ứ ta đang dùng, nh

ư các phư ng

ơ th c

ứ c a

ủ l p

ớ Math, đ u

ề trả l i

ạ k t

ế quả. Nh ng

ữ

phương th c

ứ khác, nh

ư println và newLine, đều thực hi n

ệ một thao tác nh ng

ư không tr

ả l i

ạ k t

ế qu

ả

nào. Đi u

ề này n y

ả sinh m t

ộ s

ố câu h i

ỏ sau:

•Điều gì sẽ x y

ả ra n u

ế n u

ế b n

ạ kích ho t

ạ m t

ộ phư ng

ơ th c

ứ mà không làm gì v i

ớ k t

ế qu

ả (nghĩa là b n

ạ

không gán nó vào m t

ộ bi n

ế hay không dùng k t

ế qu

ả này làm b

ộ ph n

ậ trong m t

ộ bi u

ể th c

ứ l n

ớ h n)

ơ ?

•Đi u

ề gì s

ẽ x y

ả ra n u

ế b n

ạ dùng m t

ộ phư ng

ơ th c

ứ print như một ph n

ầ c a

ủ bi u

ể th c

ứ l n

ớ h n,

ơ ch n

ẳ g

h n

ạ System.out.println("boo!") + 7?

•Ta có th

ể vi t

ế nh ng

ữ phư ng

ơ th c

ứ đ

ể tr

ả l i

ạ giá tr ịkhông, hay ch ỉloanh quanh v i

ớ nh ng

ữ phư ng

ơ th c

ứ

kiểu như newLine và printTwice?

Lời gi i

ả đáp đ i

ố v i

ớ câu h i

ỏ th

ứ ba là “Có, b n

ạ có th

ể vi t

ế nh ng

ữ phư ng

ơ th c

ứ đ

ể tr

ả l i

ạ giá tr ,ị” mà ta s

ẽ

th y

ấ cách làm sau m t

ộ vài chư ng

ơ n a

ữ . Tôi s

ẽ đ

ể cho b n

ạ t

ự tr

ả l i

ờ hai câu h i

ỏ còn l i

ạ b ng

ằ cách th c

ự

hành tr c

ự ti p.

ế Th t

ậ ra, b t

ấ kì lúc nào b n

ạ đ t

ặ ra câu h i

ỏ v

ề s

ự h p

ợ l

ệ hay không h p

ợ l

ệ c a

ủ thao tác

trong Java, thì m t

ộ cách hay đ

ể tìm hi u

ể là đi h i

ỏ trình biên d c

ị h.

3.12 Thu t

ậ ngữ

kh i

ở t o

ạ :

Câu l nh

ệ

nh m

ằ khai báo m t

ộ bi n

ế đ n

ồ g th i

ờ gán giá tr ịcho nó.

d u

ấ ph y

ẩ đ n

ộ g:

M t

ộ kiểu của bi n

ế (ho c

ặ giá trị) có th

ể ch a

ứ c

ả s

ố có ph n

ầ th p

ậ phân l n

ẫ s

ố nguyên. Ki u

ể d u

ấ

ph y

ẩ đ ng

ộ mà ta sẽ dùng là double.

l p:

ớ

M t

ộ t p

ậ h p

ợ đ c

ượ đ t

ặ tên, có ch a

ứ các ph n

ươ g th c

ứ . Đ n

ế gi

ờ ta đã dùng l p

ớ Math và l p

ớ System,

và cũng vi t

ế đ c

ượ các l p

ớ có tên Hello và NewLine.

phư n

ơ g th c

ứ :

Một loạt nh ng

ữ câu l nh

ệ

nh m

ằ th c

ự hi n

ệ m t

ộ ch c

ứ năng có ích. Ph ng

ươ th c

ứ đư c

ợ đ t

ặ tên. Nó có th

ể

nh n

ậ ho c

ặ không nh n

ậ tham s ,

ố đ ng

ồ th i

ờ có thể trả l i

ạ ho c

ặ không tr

ả m t

ộ giá tr .ị

tham s :

ố

Một đ n

ơ v ịthông tin mà ph n

ươ g th c

ứ yêu c u

ầ trư c

ớ khi nó có th

ể đư c

ợ th c

ự hi n.

ệ Tham s

ố là các bi n:

ế

chúng ch a

ứ nh ng

ữ giá tr ịvà có ki u

ể riêng.

đ i

ố s :

ố

Giá tr ịmà b n

ạ cung c p

ấ khi b n

ạ kích ho t

ạ m t

ộ ph ng

ươ th c

ứ . Giá tr ịnày ph i

ả có cùng ki u

ể v i

ớ tham s

ố

tư ng

ơ ng

ứ .

khung:

Một cấu trúc (bi u

ể di n

ễ b i

ở kh i

ố ch

ữ nh t

ậ màu xám trong bi u

ể đ

ồ ngăn x p

ế ) có ch a

ứ các tham s

ố và

bi n

ế c a

ủ m t

ộ ph ng

ươ th c

ứ .

kích ho t

ạ :

Làm cho ph ng

ươ th c

ứ đư c

ợ th c

ự thi.

3.13 Bài t p

ậ

BÀI T P

Ậ 1

Hãy v

ẽ một khung ngăn x p

ế để bi u

ể di n

ễ tr ng

ạ thái chư ng

ơ trình

ở M c

ụ 3.10 khi main kích

ho t

ạ printTime v i

ớ các đối số 11 và 59.

BÀI T P

Ậ 2

M c

ụ đích c a

ủ bài t p

ậ này là luy n

ệ đ c

ọ mã l nh

ệ đ

ể đ m

ả b o

ả r n

ằ g b n

ạ hi u

ể đư c

ợ lu ng

ồ th c

ự thi c a

ủ

chương trình g m

ồ nhi u

ề phư ng

ơ th c

ứ khác nhau.

1. Kết qu

ả c a

ủ chư ng

ơ trình sau là gì? Hãy nói chính xác v ịtrí các d u

ấ tr ng

ố và các ch

ỗ xu ng

ố dòng. G I

Ợ

Ý: B t

ắ đ u

ầ b ng

ằ vi c

ệ di n

ễ t

ả b n

ằ g l i

ờ xem ping và baffle làm những gì khi chúng đư c

ợ kích ho t

ạ .

2. Hãy v

ẽ một bi u

ể đ

ồ ngăn x p

ế bi u

ể di n

ễ tr ng

ạ thái c a

ủ chư ng

ơ trình khi ping đư c

ợ kích ho t

ạ l n

ầ đầu.

public static void zoop() {

baffle();

System.out.print("You wugga ");

baffle();

}

public static void main(String[] args) {

System.out.print("No, I ");

zoop();

System.out.print("I ");

baffle();

}

public static void baffle() {

System.out.print("wug");

ping();

}

public static void ping() {

System.out.println(".");

}

BÀI T P

Ậ 3

M c

ụ đích c a

ủ bài t p

ậ này là đ m

ả b o

ả hi u

ể đư c

ợ cách vi t

ế và cách kích ho t

ạ phư ng

ơ th c

ứ nh n

ậ tham s .

ố

1. Hãy vi t

ế dòng đ u

ầ tiên c a

ủ m t

ộ phư ng

ơ th c

ứ có tên zool nh n

ậ vào ba tham s :

ố m t

ộ int và hai String.

2. Hãy vi t

ế một dòng l nh

ệ zool, truy n

ề làm tham s

ố các giá tr ịsau: 11, tên c a

ủ con thú c ng

ư l n

ầ đ u

ầ b n

ạ

nuôi, và tên c a

ủ dãy ph

ố mà b n

ạ s ng

ố th i

ờ th

ơ u

ấ .

BÀI T P

Ậ 4

M c

ụ đích c a

ủ bài t p

ậ này là l y

ấ đo n

ạ mã t

ừ m t

ộ bài t p

ậ trư c

ớ r i

ồ bao gói nó vào trong m t

ộ phư ng

ơ th c

ứ

có nh n

ậ tham s .

ố B n

ạ nên tìm m t

ộ l i

ờ gi i

ả hoàn ch nh

ỉ cho Bài t p

ậ 2 để b t ắ đầu.

1. Hãy vi t

ế một phư ng

ơ th c

ứ có tên printAmerican để nh n

ậ ngày, tháng, năm làm các tham s

ố r i

ồ in

chúng ra dư i

ớ d ng

ạ quy đ nh

ị c a

ủ M .

ỹ

2. Ki m

ể tra phư ng

ơ th c

ứ c a

ủ b n

ạ b ng

ằ cách kích ho t

ạ nó từ main rồi truy n

ề các đ i

ố s

ố phù h p.

ợ K t

ế qu

ả

ph i

ả trông giống nh

ư sau (ch ỉtr

ừ s

ố ngày có th

ể khác đi):

Saturday, July 16, 2011

3. Một khi b n

ạ đã g

ỡ lỗi xong cho printAmerican, hãy vi t

ế một phư ng

ơ th c

ứ khác có tên printEuropean để

in ra ngày tháng theo quy chu n

ẩ châu Âu.

Ch

ng

ươ 4: Câu l n

ệ h đi u

ề ki n

ệ và đ

ệ quy Java

Trở về M c

ụ l c

ụ cuốn sách 4.1 Toán t ch

ử

ia dư

Toán t

ử chia dư tính với các s

ố nguyên (cùng các bi u

ể th c

ứ s

ố nguyên) và cho k t

ế qu

ả là phần dư c a

ủ

phép chia s

ố th

ứ nh t

ấ cho s

ố th

ứ hai. Trong Java, toán t

ử chia d

ư có kí hi u

ệ là d u

ấ ph n

ầ trăm, %. Cú

pháp cũng gi ng

ố nh

ư các toán t

ử khác:

int quotient = 7 / 3;

int remainder = 7 % 3;

Với toán t

ử thứ nh t

ấ , chia nguyên, k t

ế qu

ả là 2. V i

ớ toán t

ử th

ứ hai ta đư c

ợ k t

ế qu

ả b ng

ằ 1. Nh

ư v y

ậ 7

chia cho 3 b ng

ằ 2 d

ư 1.

Toán t

ử số d

ư b t

ấ ng

ờ tr

ở nên có ích. Ch ng

ẳ h n

ạ , b n

ạ có th

ể ki m

ể tra xem m t

ộ s

ố có chia h t

ế cho s

ố

khác không: n u

ế x % y b ng

ằ không thì x chia h t

ế cho y.

Hơn nữa, b n

ạ còn có th

ể l c

ọ ra nh ng

ữ ch

ữ s

ố cu i

ố cùng bên ph i

ả t

ừ s

ố ban đ u

ầ . Ch ng

ẳ h n

ạ , x % 10 cho

ta số hàng đ n

ơ vị c a

ủ x (trong h

ệ th p

ậ phân). Tư ng

ơ t ,

ự x % 100 cho ta hai ch

ữ s

ố hàng ch c

ụ và đ n

ơ v .ị

4.2 Thực hi n l

ệ

nh

ệ

theo đi u k

ề

i n

ệ

Để viết được nh ng

ữ chư ng

ơ trình h u

ữ ích, chúng ta thư ng

ờ luôn ph i

ả ki m

ể tra nh ng

ữ đi u

ề ki n

ệ và thay

đổi bi u

ể hi n

ệ tư ng

ơ ng

ứ c a

ủ chư ng

ơ trình. Các câu l n

ệ h đi u

ề ki n

ệ cung c p

ấ cho ta kh

ả năng này.

D ng

ạ đ n

ơ gi n

ả nh t

ấ là l nh

ệ if:

if (x > 0) {

System.out.println("x la so duong");

}

Bi u

ể thức

ở trong c p

ặ ngo c

ặ tròn được gọi là điều ki n.

ệ N u

ế nó đư c

ợ tho

ả mãn thì đo n

ạ l nh

ệ bên trong

c p

ặ ngo c

ặ nhọn được th c

ự thi. N u

ế không, s

ẽ ch n

ẳ g có đi u

ề gì x y

ả ra.

Đi u

ề ki n

ệ có th

ể ch a

ứ b t

ấ kì toán t

ử so sánh nào, v n

ố đôi khi còn đư c

ợ g i

ọ là toán t

ử quan hệ:

x == y // x bằng y

x != y // x không bằng y

x > y // x is lớn hơn y

x < y // x nhỏ hơn y

x >= y // x lớn hơn hoặc bằng y

x <= y // x nhỏ hơn hoặc bằng y

M c

ặ dù có th

ể b n

ạ đã quen thu c

ộ v i

ớ nh ng

ữ phép toán này, cú pháp dùng trong Java v n

ẫ h i

ơ khác

những bi u

ể th c

ứ nh

ư =, ≠ và ≤. M t

ộ l i

ỗ thư ng

ờ m c

ắ ph i

ả là dùng m t

ộ d u

ấ = thay vì hai ==. Hãy nh

ớ

r n

ằ g = là toán t

ử gán, còn == là toán t

ử so sánh. Ngoài ra không có toán t

ử nào đư c

ợ vi t

ế là =< ho c

ặ =>.

Hai v

ế trong m t

ộ bi u

ể th c

ứ đi u

ề ki n

ệ ph i

ả có cùng ki u

ể d

ữ li u

ệ . B n

ạ ch ỉđư c

ợ phép so

sánh int v i

ớ ints ho c

ặ double v i

ớ double.

Hai toán tử == và != cũng làm vi c

ệ v i

ớ các chu i

ỗ kí t ,

ự nh ng

ư cách ho t

ạ đ ng

ộ c a

ủ chúng không gi ng

ố

như b n

ạ đã d

ự ki n.

ế Còn t t

ấ c

ả nh ng

ữ toán t

ử quan h

ệ khác thì không có tác d ng

ụ gì đ i

ố v i

ớ chu i

ỗ . Ta sẽ

xem cách so sánh chu i

ỗ

ở M c

ụ 8.10.

4.3 Thực hi n ch

ệ

n l

ọ

a

ự

D ng

ạ thứ hai c a

ủ th c

ự hi n

ệ teho đi u

ề ki n

ệ là thực hi n

ệ l nh

ệ theo l a

ự ch n,

ọ trong đó có hai kh

ả năng và

điều ki n

ệ được đặt ra đ

ể căn c

ứ vào đó mà l a

ự ch n

ọ th c

ự hi n

ệ m t

ộ trong hai. Cú pháp có d ng

ạ nh

ư sau:

if (x%2 == 0) {

System.out.println("x la so chan");

} else {

System.out.println("x la so le");

}

Nếu ph n

ầ dư c a

ủ phép chia x cho 2 là 0, thì chúng ta bi t

ế r n

ằ g x là số ch n,

ẵ và chư ng

ơ trình s

ẽ hi n

ể th ị

thông báo đi u

ề này. N u

ế đi u

ề ki n

ệ không đư c

ợ tho

ả mã thì l nh

ệ th

ứ hai s

ẽ đư c

ợ th c

ự hi n.

ệ Vì đi u

ề ki n

ệ

ho c

ặ là đư c

ợ thoả mãn, ho c

ặ không; nên luôn ch ỉcó m t

ộ trong hai phư ng

ơ án đư c

ợ th c

ự hi n.

ệ

Nhân ti n

ệ nói thêm, n u

ế b n

ạ có ý đ n

ị h thư ng

ờ xuyên ki m

ể tra tính ch n

ẵ l ,

ẻ có th

ể b n

ạ s

ẽ mu n

ố “gói”

đo n

ạ mã l nh

ệ này vào trong m t

ộ phư ng

ơ th c

ứ , nh

ư sau:

public static void printParity(int x) {

if (x%2 == 0) {

System.out.println("x la so chan");

} else {

System.out.println("x la so le");

}

}

Bây gi

ờ b n

ạ có m t

ộ phư ng

ơ th c

ứ tên là printParity để in ra thông báo thích h p

ợ cho m i

ỗ s

ố nguyên b n

ạ

cung c p

ấ cho nó. Trong main b n

ạ sẽ kích ho t

ạ phư ng

ơ th c

ứ này nh

ư sau:

printParity(17);

Hãy luôn nh

ớ r n

ằ g khi b n

ạ kích ho t

ạ một phương th c

ứ , thì không nh t

ấ thi t

ế ph i

ả khai báo các ki u

ể c a

ủ

đối số được cung c p.

ấ Java có th

ể hình dung ra ki u

ể d

ữ li u

ệ là gì. B n

ạ ph i

ả ki m

ề ch

ế đ

ể tránh vi t

ế

những l nh

ệ ki u

ể nh :

ư

int number = 17;

printParity(int number); // SAI!!!

4.4 Các đi u k

ề

i n x

ệ

âu chu i

ỗ

Đôi khi b n

ạ c n

ầ ph i

ả ki m

ể tra m t

ộ s

ố các đi u

ề ki n

ệ có liên quan và ch n

ọ trong m t

ộ s

ố nh ng

ữ hành

động. Một cách th c

ự hi n

ệ vi c

ệ này là xâu chu i

ỗ một lo t

ạ các if và else:

if (x > 0) {

System.out.println("x la so duong");

} else if (x < 0) {

System.out.println("x la so am");

} else {

System.out.println("x bang khong");

}

Việc xâu chuỗi nh

ư v y

ậ có th

ể dài tùy ý, m c

ặ dù chúng có th

ể khó đ c

ọ n u

ế đi quá đà. M t

ộ cách làm đ

ể

dễ đ c

ọ h n

ơ là s

ử d ng

ụ quy t c

ắ th t

ụ đ u

ầ dòng tiêu chu n,

ẩ nh

ư đã trình bày trong các ví d

ụ trên. n u

ế b n

ạ

giữ cho các câu l nh

ệ và các ngo c

ặ nh n

ọ đư c

ợ th n

ẳ g hàng v i

ớ nhua thì ít có kh

ả năng gây l i

ỗ cú pháp

hơn, và n u

ế có thì cũng d

ễ tìm th y

ấ h n.

ơ

4.5 Các đi u k

ề

i n l

ệ

ng gh

ồ

ép

Ngoài vi c

ệ xâu chu i

ỗ , b n

ạ còn có th

ể l ng

ồ ghép m t

ộ đi u

ề ki n

ệ bên trong đi u

ề ki n

ệ khác. Ta có th

ể vi t

ế

l i

ạ ví dụ trên nh

ư sau:

if (x == 0) {

System.out.println("x bang khong");

} else {

if (x > 0) {

System.out.println("x la so duong");

} else {

System.out.println("x la so am");

}

}

Bây gi

ờ thì câu l nh

ệ đi u

ề ki n

ệ bên ngoài có hai nhánh. Nhánh th

ứ nh t

ấ ch ỉch a

ứ m t

ộ l nh

ệ print, nhánh

thứ hai l i

ạ ch a

ứ m t

ộ câu l nh

ệ đi u

ề ki n

ệ khác, mà b n

ả thân nó l i

ạ có hai nhánh. Hai nhánh này đ u

ề ch a

ứ

những câu l nh

ệ print đơn gi n,

ả m c

ặ dù dĩ nhiên chúng có th

ể là nh ng

ữ câu l nh

ệ đi u

ề ki n

ệ khác.

Tuy cách vi t

ế th t

ụ vào trong làm cho c u

ấ trúc rõ ý, nh ng

ư các l nh

ệ đi u

ề ki n

ệ l ng

ồ ghép trở nên r t

ấ khó

để người đ c

ọ nhanh. Ta nên c

ố g ng

ắ tránh dùng chúng.

M t

ặ khác, d n

ạ g c u

ấ trúc l n

ồ g ghép này cũng thư ng

ờ th y

ấ , và sau này ta còn g p

ặ chúng, do v y

ậ b n

ạ

cũng làm quen v i

ớ nó.

4.6 Câu l nh

ệ

return

Câu l nh

ệ return cho phép b n

ạ k t

ế thúc vi c

ệ th c

ự thi c a

ủ m t

ộ phư ng

ơ th c

ứ trư c

ớ khi đ n

ế cu i

ố phư ng

ơ

thức đó. Một lí do dùng câu l nh

ệ này là n u

ế b n

ạ phát hi n

ệ ra đi u

ề ki n

ệ gây l i

ỗ :

public static void printLogarithm(double x) {

if (x <= 0.0) {

System.out.println("Yêu cau nhap vao so duong.");

return;

}

double result = Math.log(x);

System.out.println("Gia tri log cua x bang " + result);

}

Mã lệnh này đ n

ị h nghĩa m t

ộ phư ng

ơ th c

ứ có tên printLogarithm; nó nh n

ậ tham s

ố là m t

ộ double có

tên x. Phương thức này ki m

ể tra xem li u

ệ x có nhỏ h n

ơ ho c

ặ b n

ằ g 0 hay không, và trong trư ng

ờ h p

ợ

như v y

ậ thì in ra m t

ộ thông báo l i

ỗ r i

ồ dùng return để thoát kh i

ỏ phư ng

ơ th c

ứ . Lu ng

ồ th c

ự thi s

ẽ l p

ậ

tức trở l i

ạ chỗ g i

ọ phư ng

ơ th c

ứ đó và nh ng

ữ dòng còn l i

ạ c a

ủ phư ng

ơ th c

ứ s

ẽ không đư c

ợ th c

ự hi n.

ệ

Tôi đã dùng m t

ộ giá tr ịd u

ấ ph y

ẩ đ ng

ộ

ở bên v

ế ph i

ả c a

ủ đi u

ề ki n

ệ vì v

ế trái bi u

ể th c

ứ này là m t

ộ bi n

ế

ph y

ẩ động.

4.7 Chuy n đ

ể

ổi ki u

ể

B n

ạ có thể tự hỏi r ng

ằ làm sao chư ng

ơ trình c a

ủ ta có th

ể êm xuôi v i

ớ bi u

ể th c

ứ ki u

ể như "Gia tri log

cua x bang " + result, bởi một toán h ng

ạ là String còn toán h n

ạ g kia là double. Truong trư ng

ờ h p

ợ này

Java đã thông minh đ

ể thay ta chuy n

ể giá trị double thành String trước khi th c

ự hi n

ệ vi c

ệ ghép chu i

ỗ .

Mỗi khi b n

ạ th

ử “cộng” hai bi u

ể th c

ứ , mà m t

ộ trong s

ố đó là String, Java s

ẽ chuy n

ể đ i

ổ cái còn l i

ạ

thành String rồi mới th c

ự hi n

ệ ghép chu i

ỗ . B n

ạ nghĩ đi u

ề gì s

ẽ x y

ả ra n u

ế th c

ự hi n

ệ phép c ng

ộ gi a

ữ m t

ộ

số nguyên v i

ớ m t

ộ giá tr ịph y

ẩ đ ng

ộ ?

4.8 Đ q

ệ uy

Ở chương trước tôi đã nói r ng

ằ vi c

ệ m t

ộ phư ng

ơ th c

ứ kích ho t

ạ phư ng

ơ th c

ứ khác là h p

ợ l ,

ệ và a đã xét

vài ví d .

ụ Tôi ch a

ư đ

ề c p

ậ r ng

ằ m t

ộ phư ng

ơ th c

ứ kích ho t

ạ chính nó cũng h p

ợ l .

ệ M c

ặ dù b

ề ngoài thì có

thể điều này không rõ hay d

ở ra sao, nh ng

ư th c

ự ra đó chính là m t

ộ trong nh ng

ữ đ c

ặ đi m

ể hay nh t

ấ

trong l p

ậ trình.

Ch ng

ẳ h n,

ạ hãy xét phư ng

ơ th c

ứ sau:

public static void countdown(int n) {

if (n == 0) {

System.out.println("Bum!");

} else {

System.out.println(n);

countdown(n-1);

}

}

Phương th c

ứ có tên là countdown và nó nh n

ậ tham s

ố là m t

ộ s

ố nguyên. N u

ế tham số b n

ằ g 0 ho c

ặ âm,

chương trình s

ẽ in ra ch ,

ữ “Bùm!” Còn n u

ế không, nó s

ẽ in ra giá tr ịtham số và sau đó kích ho t

ạ m t

ộ

phương th c

ứ có tên countdown—nghĩa là chính nó—nh ng

ư truy n

ề vào đ i

ố số n-1.

Đi u

ề gì s

ẽ x y

ả ra khi ta kích ho t

ạ m t

ộ phư ng

ơ th c

ứ ki u

ể nh

ư th

ế này?

countdown(3);

Việc thực hi n

ệ countdown b t

ắ đầu với n=3, và do n lớn hơn 0, nó đ a

ư ra giá tr ị3, và r i

ồ g i

ọ chính nó…

Việc thực hi n

ệ countdown b t

ắ đầu với n=2, và do n lớn hơn 0, nó đ a

ư ra giá tr ị2, và r i

ồ g i

ọ chính nó…

Việc thực hi n

ệ countdown b t

ắ đầu với n=1, và do n lớn hơn 0, nó đ a

ư ra giá tr ị1, và r i

ồ g i

ọ chính nó…

Việc thực hi n

ệ countdown b t

ắ đầu với n=0, và do n không còn l n

ớ h n

ơ 0, nó đ a

ư ra dòng ch

ữ “Bùm!” và

rồi quay v .

ề

Phương th c

ứ countdown ứng với n=1 quay v .

ề

Phương th c

ứ countdown ứng với n=2 quay v .

ề

Phương th c

ứ countdown ứng với n=3 quay v .

ề

Và rồi b n

ạ tr

ở v

ề v i

ớ main. Nh

ư v y

ậ , toàn b

ộ k t

ế qu

ả đ u

ầ ra nh

ư sau:

3

2

1

Bum!

Ví d

ụ thứ hai là hãy xem l i

ạ các phư ng

ơ th c

ứ newLine và threeLine.

public static void newLine() {

System.out.println("");

}

public static void threeLine() {

newLine(); newLine(); newLine();

}

M c

ặ dù cách này có tác d ng

ụ , nh ng

ư s

ẽ không giúp ích đư c

ợ nhi u

ề trong trư ng

ờ h p

ợ ta c n

ầ in 2, ho c

ặ

106 dòng m i

ớ . M t

ộ cách làm hay h n

ơ là

public static void nLines(int n) {

if (n > 0) {

System.out.println("");

nLines(n-1);

}

}

Chương trình này tư ng

ơ t

ự như countdown; khi n còn l n

ớ h n

ơ 0, nó s

ẽ in ra m t

ộ dòng m i

ớ và sau đó sẽ

kích ho t

ạ chính nó đ

ể in thêm n -  1

dòng m i

ớ n a

ữ . Nh

ư v y

ậ s

ố dòng k t

ế qu

ả s

ẽ là 1 + (n-1), tức là

b n

ằ g n.

Khi một phư ng

ơ th c

ứ kích ho t

ạ chính nó, đi u

ề này g i

ọ là đệ quy, và nh ng

ữ phư ng

ơ th c

ứ đó có tính đ

ệ

quy.

4.9 Bi u đ

ể

n

ồ găn x p ch

ế

o các phư ng t

ơ

h c đ

ứ

q

ệ uy

Trong chương trư c

ớ , chúng ta đã dùng m t

ộ bi u

ể đ

ồ ngăn x p

ế đ

ể bi u

ể th ịtr n

ạ g thái c a

ủ m t

ộ chư ng

ơ

trình trong quá trình phư ng

ơ th c

ứ đư c

ợ kích ho t

ạ . Lo i

ạ bi u

ể đ

ồ này cũng ti n

ệ dùng cho vi c

ệ di n

ễ gi i

ả

một phương th c

ứ đệ quy.

Hãy nh

ơ r ng

ằ m i

ỗ khi phư ng

ơ th c

ứ đư c

ợ kích ho t

ạ , Java t o

ạ ra m t

ộ “khung” m i

ớ trong đó có ch a

ứ

phiên b n

ả m i

ớ c a

ủ các bi n

ế c c

ụ b

ộ và tham s

ố trong phư ng

ơ th c

ứ .

Hình v

ẽ này minh ho

ạ m t

ộ s

ơ đ

ồ ngăn x p

ế cho phư ng

ơ th c

ứ countdown khi gọi v i

ớ n = 3:

Có một khung dành cho main và bốn khung countdown, mỗi khung có m t ộ giá tr ịriêng cho tham

bi n

ế n. Đáy c a

ủ ngăn x p,

ế countdown v i

ớ n=0, đư c

ợ g i

ọ là tr n

ườ g h p

ợ c

ơ sở. Nó không th c

ự hi n

ệ l i

ờ

gọi đệ quy, do đó không có thêm khung countdown nào.

Khung ch a

ứ main thì rỗng vì main không ch a

ứ b t

ấ kì tham s

ố hay bi n

ế nào.

4.10 Thu t

ậ ngữ

toán t

ử module:

Toán t

ử dùng v i

ớ hai s

ố nguyên và tr

ả l i

ạ ph n

ầ d

ư trong phép chia gi a

ữ hai s

ố đó. Trong Java,

toán t

ử này đ c

ượ kí hi u

ệ b i

ở d u

ấ ph n

ầ trăm (%).

lệnh đi u

ề ki n

ệ :

Một kh i

ố l nh

ệ

có th

ể đư c

ợ th c

ự thi hay không tùy theo m t

ộ đi u

ề ki n

ệ nào đó.

xâu chu i

ỗ :

Cách n i

ố nhi u

ề l nh

ệ

đi u

ề ki n

ệ thành dãy liên t c

ụ .

lồng ghép:

Cách đ t

ặ m t

ộ l nh

ệ

đi u

ề ki n

ệ này vò trong m t

ộ ho c

ặ c

ả hai nhánh c a

ủ m t

ộ l nh

ệ

đi u

ề ki n

ệ khác.

định ki u:

ể

M t

ộ toán tử giúp chuy n

ể đ i

ổ t

ừ ki u

ể d

ữ li u

ệ này sang ki u

ể khác. Trong Java nó có d ng

ạ tên m t

ộ

ki u

ể dữ li u

ệ viết gi a

ữ c p

ặ ngo c

ặ tròn, như (int).

đệ quy:

Quá trình kích ho t

ạ chính ph ng

ươ th c

ứ đang đ c

ượ th c

ự thi.

tr

n

ườ g h p

ợ c

ơ s :

ở

M t

ộ điều ki n

ệ đ

ể cho ph ng

ươ th c

ứ đ

ệ quy không kích ho t

ạ đệ quy n a

ữ .

4.11 Bài t p

ậ

Bài t p

ậ 1 Hãy v

ẽ một bi u

ể đ

ồ ngăn x p

ế bi u

ể di n

ễ tr ng

ạ thái chư ng

ơ trình

ở M c

ụ 4.8 sau khi main kích ho t

ạ nLines v i

ớ tham số n=4, ngay trư c

ớ khi l n

ầ kích ho t

ạ cu i

ố cùng c a

ủ nLines tr

ả v .

ề

Bài t p

ậ 2 Bài t p

ậ này ôn l i

ạ lu ng

ồ th c

ự thi, b ng

ằ m t

ộ chư ng

ơ trình v i

ớ nhi u

ề phư ng

ơ th c

ứ . Hãy đ c

ọ

mã l nh

ệ dưới đây r i

ồ tr

ả l i

ờ nh ng

ữ câu h i

ỏ đi theo.

public class Buzz {

public static void baffle(String blimp) {

System.out.println(blimp);

zippo("ping", -5);

}

public static void zippo(String quince, int flag) {

if (flag < 0) {

System.out.println(quince + " zoop");

} else {

System.out.println("ik");

baffle(quince);

System.out.println("boo-wa-ha-ha");

}

}

public static void main(String[] args) {

zippo("rattle", 13);

}

}

1. Hãy vi t

ế số 1 kế bên câu l nh

ệ đ u

ầ tiên đư c

ợ th c

ự thi c a

ủ chư ng

ơ trình này. Hãy c n

ẩ th n

ậ đ

ể tách bi t

ệ

những th

ứ thu c

ộ v

ề câu l nh

ệ v i

ớ nh ng

ữ th

ứ khác.

2. Viết số 2 kế bệnh câu l nh

ệ th

ứ hai, và c

ứ nh

ư v y

ậ đ n

ế cu i

ố chư ng

ơ trình. N u

ế m t

ộ câu l nh

ệ đư c

ợ th c

ự

hiện nhi u

ề l n

ầ thì cu i

ố cùng ta có th

ể s

ẽ th y

ấ k t

ế qu

ả in ra ch a

ứ nhi u

ề con s

ố ghi bên c nh

ạ nó.

3. Giá tr ịc a

ủ tham số blimp khi baffle b ịkích ho t

ạ là gì?

4. Kết qu

ả c a

ủ chư ng

ơ trình này là gì?

Bài t p

ậ 3 Câu đầu trong l i

ờ bài hát “99 Bottles of Beer” là:

99 bottles of beer on the wall, 99 bottles of beer, ya’ take one down, ya’ pass it around, 98

bottles of beer on the wall.

Những câu ti p

ế theo cũng nh

ư v y

ậ ch ỉkhác là s

ố chai bia c

ứ gi m

ả d n

ầ đi m t

ộ , đ n

ế câu cu i

ố cùng:

No bottles of beer on the wall, no bottles of beer, ya’ can’t take one down, ya’ can’t pass it around, ’cause there are no more bottles of beer on the wall!

Và sau đó thì cu i

ố cùng bài hát cũng k t

ế thúc.

Hãy vi t

ế chư ng

ơ trình in ra toàn b

ộ l i

ờ bài hát “99 Bottles of Beer.” Chư ng

ơ trình này c n

ầ có m t

ộ

phương th c

ứ đ

ệ quy để gi i

ả quy t

ế ph n

ầ khó khăn, nh ng

ư có th

ể b n

ạ còn mu n

ố vi t

ế thêm nh ng

ữ phư ng

ơ

thức phụ trợ vi c

ệ phân chia nh ng

ữ tính năng c

ơ b n

ả c a

ủ chư ng

ơ trình.

Trong quá trình phát tri n

ể mã l nh

ệ , hãy th

ử ch y

ạ v i

ớ m t

ộ s

ố ít các câu hát, nh

ư “3 Bottles of Beer.”

M c

ụ đích c a

ủ bài t p

ậ này là ti p

ế nh n

ậ bài toán r i

ồ chia nh

ỏ nó thành nh ng

ữ bài toán con, và gi i

ả bài

toán con b ng

ằ cách vi t

ế nh ng

ữ phư ng

ơ th c

ứ đ n

ơ gi n.

ả

Bài t p

ậ 4 Kết qu

ả c a

ủ chư ng

ơ trình sau đây là gì?

public class Narf {

public static void zoop(String fred, int bob) {

System.out.println(fred);

if (bob == 5) {

ping("not ");

} else {

System.out.println("!");

}

}

public static void main(String[] args) {

int bizz = 5;

int buzz = 2;

zoop("just for", bizz);

clink(2*buzz);

}

public static void clink(int fork) {

System.out.print("It's ");

zoop("breakfast ", fork) ;

}

public static void ping(String strangStrung) {

System.out.println("any " + strangStrung + "more ");

}

}

Bài t p

ậ 5 Đ nh

ị lý cuối cùng c a

ủ Fermat phát bi u

ể r ng

ằ không có các s

ố nguyên a, b, và c nào tho

ả mãn

an + bn = cn

trừ trường h p

ợ n = 2.Vi t

ế một phương th c

ứ có tên là check_fermat nh n

ậ vào bốn tham s —

ố a, b, c và n

—rồi ki m

ể tra xem có tho

ả mãn đ nh

ị lý Fermat không. N u

ế n lớn hơn 2 và hoá ra an + bn = cn, thì chương trình s

ẽ in ra “Tr i

ờ , Fermat đã l m

ầ !” Còn n u

ế không thì chư ng

ơ trình s

ẽ in ra, “Không, v n

ẫ

không đúng”.

B n

ạ c n

ầ ph i

ả gi

ả s

ử r n

ằ g có m t

ộ phư ng

ơ th c

ứ tên là raiseToPow ; phương th c

ứ này nh n

ậ đ i

ố s

ố là hai số

nguyên r i

ồ nâng đ i

ố s

ố th

ứ nh t

ấ lên lũy th a

ừ s

ố th

ứ hai. Ch n

ẳ g h n:

ạ

int x = raiseToPow(2, 3);

sẽ gán giá trị 8 cho x, bởi 23 = 8.

Ch

ng

ươ 5: Grid World, ph n

ầ 1

Trở về M c

ụ l c

ụ cuốn sách 5.1 Kh i

ở động

Bây gi

ờ đã đ n

ế lúc ta b t

ắ đ u

ầ làm Nghiên c u

ứ c

ụ th

ể v

ề kì thi Khoa h c

ọ máy tính AP; nghiên c u

ứ này

xoay quanh m t

ộ chư ng

ơ trình có tên GridWorld. Đ u

ầ tiên, hãy cài đ t

ặ GridWorld; b n

ạ có th

ể t i

ả chư ng

ơ

trình này v

ề t

ừ H i

ộ đ ng

ồ tuy n

ể sinh Hoa

Kì: http://www.collegeboard.com/student/testing/ap/compsci_a/case.html.

Khi gi i

ả nén mã ngu n

ồ này, b n

ạ s

ẽ thu đư c

ợ m t

ộ th

ư m c

ụ mang tên GridWorldCode trong đó

chứa projects/firstProject, và b n

ả thân th

ư m c

ụ này l i

ạ ch a

ứ BugRunner.java.

Hãy sao chép t p

ậ tin BugRunner.java vào một th

ư m c

ụ khác r i

ồ nh p

ậ nó t

ừ môi trư ng

ờ phát tri n

ể mà

b n

ạ đang dùng. B n

ạ có th

ể tham kh o

ả hư ng

ớ

d n:

ẫ http://www.collegeboard.com/prod_downloads/student/testing/ap/compsci_a/ap07_gridworld

_installation_guide.pdf.

Một khi ch y

ạ BugRunner.java, b n

ạ hãy t i

ả B n

ả hư ng

ớ d n

ẫ th c

ự hành GridWorld

từ http://www.collegeboard.com/prod_downloads/student/testing/ap/compsci_a/ap07_gridworld_st

udmanual_appends_v3.pdf.

B n

ả hướng d n

ẫ th c

ự hành này có dùng nh ng

ữ thu t

ậ ng

ữ mà tôi ch a

ư trình bày. B i

ở v y

ậ đ

ể b n

ạ quen

được, sau đây là một danh sách gi i

ớ thi u

ệ tóm t t

ắ :

• Các thành ph n

ầ c a

ủ GridWorld, bao g m

ồ Bugs, Rocks và b n

ả thân Grid đ u

ề là nh ng

ữ đ i

ố t n

ượ g.

• Constructor là một phương th c

ứ đ c

ặ bi t

ệ để t o

ạ nên nh ng

ữ đ i

ố tư ng

ợ m i

ớ .

• L p

ớ là một t p

ậ hợp các đ i

ố tư ng

ợ ; m i

ỗ đ i

ố tư ng

ợ đ u

ề thu c

ộ m t

ộ l p

ớ nh t

ấ đ nh

ị .

• Đ i

ố tư ng

ợ còn đư c

ợ g i

ọ là th c

ự thể, vì nó thuộc v

ề m t

ộ l p.

ớ

• Thu c

ộ tính là một đơn v ịthông tin v

ề m t

ộ đ i

ố tư ng

ợ , ch ng

ẳ h n

ạ màu s c

ắ hay t a

ọ đ

ộ (v ịtrí) c a

ủ đ i

ố

tượng đó.

• Ph

n

ươ g th c

ứ truy c p

ậ là một phương th c

ứ nhằm tr

ả l i

ạ thu c

ộ tính c a

ủ m t

ộ đ i

ố tư ng

ợ .

• Ph

n

ươ g th c

ứ s a

ử đ i

ổ nhằm thay đ i

ổ thu c

ộ tính c a

ủ m t

ộ đ i

ố tư ng

ợ .

Bây gi

ờ b n

ạ đã có th

ể đ c

ọ đư c

ợ Ph n

ầ 1 c a

ủ cu n

ố Hư ng

ớ d n

ẫ th c

ự hành và làm các bài t p.

ậ

5.2 BugRunner

BugRunner.java chứa mã l nh

ệ sau:

import info.gridworld.actor.ActorWorld;

import info.gridworld.actor.Bug;

import info.gridworld.actor.Rock;

public class BugRunner {

public static void main(String[] args) {

ActorWorld world = new ActorWorld();

world.add(new Bug());

world.add(new Rock());

world.show();

}

}

Ba dòng đầu tiên là các câu l nh

ệ import; chúng li t

ệ kê các l p

ớ trong GridWorld đư c

ợ dùng đ n

ế

ở

chương trình này. B n

ạ có th

ể tìm tài li u

ệ cho nh ng

ữ l p

ớ này

t i

ạ http://www.greenteapress.com/thinkapjava/javadoc/gridworld/.

Cũng nh

ư nh ng

ữ chư ng

ơ trình khác ta đã g p,

ặ BugRunner đ nh

ị nghĩa l p

ớ có nhi m

ệ v

ụ cung c p

ấ phư ng

ơ

thức main. Dòng đ u

ầ tiên trong main t o

ạ ra một đ i

ố tư ng

ợ ActorWorld. Ở đây, new là từ khóa Java đ

ể

t o

ạ nên đối tư ng

ợ m i

ớ .

Hai dòng k t

ế ti p

ế t o

ạ ra m t

ộ Bug (con b )

ọ và m t

ộ Rock (t n

ả g đá), r i

ồ b

ổ sung chúng vào world (môi

trường). Dòng cuối cùng hi n

ể th ịmôi trư ng

ờ lên màn hình.

Hãy m

ở t p

ậ tin BugRunner.java để ch nh

ỉ s a

ử và thay dòng này:

world.add(new Bug());

b n

ằ g các dòng này:

Bug redBug = new Bug();

world.add(redBug);

Dòng đ u

ầ tiên gán Bug cho m t

ộ bi n

ế có tên redBug; ta có th

ể dùng redBug để kích ho t

ạ nh ng

ữ phư ng

ơ

thức c a

ủ Bug. hãy th

ử l nh

ệ này:

System.out.println(redBug.getLocation());

Chú ý: N u

ế b n

ạ ch y

ạ l nh

ệ này trư c

ớ khi b

ổ sung Bug vào world, thì kết qu

ả s

ẽ là null, bởi đối tư ng

ợ Bug

này ch a

ư có m t

ộ v ịtrí c

ụ th .

ể

Hãy kích ho t

ạ nh ng

ữ phư ng

ơ th c

ứ truy c p

ậ khác r i

ồ in ra các thu c

ộ tính c a

ủ con b

ọ v a

ừ t o

ạ ra. Kích

ho t

ạ các phư ng

ơ th c

ứ canMove, move và turn đồng thời đ m

ả b o

ả r n

ằ g b n

ạ nắm đư c

ợ tác d ng

ụ c a

ủ

chúng.

5.3 Bài t p

ậ

Bài t p

ậ 1

1. Hãy vi t

ế một phư ng

ơ th c

ứ có tên moveBug để nh n

ậ vào tham s

ố là con b

ọ r i

ồ kích ho t

ạ move. Ki m

ể tra

phương th c

ứ vừa vi t

ế ra b ng

ằ cách g i

ọ nó từ main.

2. Sửa chữa moveBug để nó kích ho t

ạ canMove rồi di chuy n

ể con b

ọ ch ỉkhi nó chuy n

ể đ ng

ộ đư c

ợ .

3. Sửa chữa moveBug để nó nh n

ậ một tham số là số nguyên n, rồi di chuy n

ể con bọ n l n

ầ (n u

ế có th )

ể .

4. Sửa chữa moveBug sao cho n u

ế con b

ọ không chuy n

ể đ ng

ộ đư c

ợ thì phư ng

ơ th c

ứ này s

ẽ kích ho t

ạ turn.

Bài t p

ậ 2

1. Lớp Math cung c p

ấ một phư ng

ơ th c

ứ mang tên random để tr

ả l i

ạ một số ph y

ẩ động gi a

ữ 0.0 và 1.0

(không bao g m

ồ 1.0).

2. Hãy vi t

ế một phư ng

ơ th c

ứ mang tên randomBug để nh n

ậ tham số là một Bug r i

ồ đ t

ặ hư ng

ớ c a

ủ con b

ọ

này là một trong nh ng

ữ giá tr ị0, 90, 180 ho c

ặ 270 theo xác su t

ấ b ng

ằ nhau, r i

ồ cho con b

ọ chuy n

ể đ ng

ộ

nếu nó có thể.

3. Sửa chữa randomBug để nh n

ậ vào số nguyên n rồi th c

ự hi n

ệ l p

ặ l i

ạ n l n

ầ thao tác trên.K t

ế qu

ả s

ẽ là

một quá trình “bư c

ớ ng u

ẫ nhiên”, mà b n

ạ có th

ể xem thêm

ở http://en.wikipedia.org/wiki/Random_walk.

4. Để quan sát quá trình bư c

ớ ng u

ẫ nhiên dài h n,

ơ b n

ạ có th

ể cho ActorWorld m t

ộ không gian r ng

ộ h n.

ơ

Ở trên đầu file BugRunner.java, hãy bổ sung câu l nh

ệ import sau:

import info.gridworld.grid.UnboundedGrid;

Bây gi ,

ờ hãy thay dòng l nh

ệ t o

ạ nên ActorWorld v i

ớ dòng l nh

ệ sau:

ActorWorld world = new ActorWorld(new UnboundedGrid());

B n

ạ có thể trình di n

ễ bư c

ớ ngẫu nhiên v i

ớ vài nghìn bư c

ớ di chuy n

ể (có th

ể ph i

ả kéo thanh trư t

ợ đ

ể tìm

con bọ).

Bài t p

ậ 3 GridWorld dùng các đ i

ố tư ng

ợ Color, v n

ố đư c

ợ đ nh

ị nghĩa trong m t

ộ th

ư vi n

ệ Java. B n

ạ có

thể đ c

ọ tài li u

ệ

ở http://download.oracle.com/javase/6/docs/api/java/awt/Color.html. Để t o ạ nên

nhiều con bọ v i

ớ các màu s c

ắ khác nhau, b n

ạ ph i

ả nh p

ậ Color:

import java.awt.Color;

Khi đó b n

ạ s

ẽ truy c p

ậ đư c

ợ các màu đã đ nh

ị s n

ẵ , như Color.blue, hay một màu m i

ớ nh

ư sau:

Color purple = new Color(148, 0, 211);

Hãy t o

ạ ra m t

ộ vài con b

ọ v i

ớ màu s c

ắ khác nhau. Ti p

ế theo, hãy vi t

ế m t

ộ phư ng

ơ th c

ứ có

tên colorBug để nh n

ậ tham số là một con b ,

ọ đ c

ọ vào t a

ọ đ

ộ c a

ủ nó, r i

ồ đ t

ặ màu.

Đ i

ố tư ng

ợ Location mà b n

ạ đã l y

ấ từ getLocation có ch a

ứ nh ng

ữ phư ng

ơ th c

ứ mang

tên getRow và getCol vốn tr

ả l i

ạ nh ng

ữ s

ố nguyên. VÌ v y

ậ b n

ạ có th

ể l y

ấ t a

ọ đ

ộ x c a

ủ con b

ọ nh

ư sau:

int x = bug.getLocation().getCol();

Hãy vi t

ế một phư ng

ơ th c

ứ có tên makeBugs để nh n

ậ vào một ActorWorld và m t

ộ s

ố nguyên n rồi t o

ạ

nên n con bọ có màu s c

ắ tùy thu c

ộ theo t a

ọ đ

ộ c a

ủ chúng. Hãy dùng s

ố th

ứ t

ự dòng đ

ể đi u

ề khi n

ể m c

ứ

s c

ắ đỏ và th

ứ t

ự cột đ

ể đi u

ề khi n

ể m c

ứ s c

ắ lam.

Ch

ng

ươ 6: Ph ng

ươ

th c

ứ tr

ả l i

ạ giá trị

Trở về M c

ụ l c

ụ cuốn sách 6.1 Những giá tr đ

ị ư c

ợ tr l

ả i

ạ

Một số phương th c

ứ mà ta đã dùng, nh

ư các hàm toán h c

ọ , có tr

ả l i

ạ k t

ế qu .

ả Nghĩa là, hi u

ệ ng

ứ t

ừ vi c

ệ

kích ho t

ạ phư ng

ơ th c

ứ là t o

ạ ra m t

ộ giá tr ịm i

ớ mà ta thư ng

ờ gán nó cho m t

ộ bi n

ế ho c

ặ dùng nh

ư m t

ộ

ph n

ầ hợp nên một bi u

ể th c

ứ l n

ớ h n.

ơ Ch n

ẳ g h n:

ạ

double e = Math.exp(1.0);

double height = radius * Math.sin(angle);

Nhưng cho đ n

ế gi

ờ t t

ấ c

ả nh ng

ữ phư ng

ơ th c

ứ mà t

ự tay vi t

ế đ u

ề là phư ng

ơ th c

ứ r n

ỗ g; theo nghĩa

những phư ng

ơ th c

ứ này không tr

ả l i

ạ giá tr ịnào. Khi b n

ạ kích ho t

ạ m t

ộ phư ng

ơ th c

ứ r ng

ố , nó thư ng

ờ

ch ỉt

ự được đ t

ặ trên m t

ộ dòng mà không có l nh

ệ gán nào c :

ả

countdown(3);

nLines(3);

Trong chương này ta vi t

ế nh ng

ữ phư ng

ơ th c

ứ tr

ả l i

ạ thông tin, mà tôi g i

ọ là phư ng

ơ th c

ứ tr

ả l i

ạ giá trị.

Ví d

ụ đ u

ầ tiên là area, một phương th c

ứ nh n

ậ vào tham s

ố là m t

ộ double, rồi tr

ả l i

ạ diện tích c a

ủ một

hình tròn v i

ớ bán kính cho trư c

ớ :

public static double area(double radius) {

double area = Math.PI * radius * radius;

return area;

}

Đi u

ề đ u

ầ tiên mà ta nh n

ậ th y

ấ là đo n

ạ đ u

ầ c a

ủ đ nh

ị nghĩa phư ng

ơ th c

ứ đã khác đi. Thay vì public static

void, vốn đ

ể chỉ một phương th c

ứ rỗng, ta th y

ấ public static double, có nghĩa là giá tr ịtr

ả về t

ừ phư ng

ơ

thức này là m t

ộ double. Tôi v n

ẫ ch a

ư gi i

ả thích ý nghĩa c a

ủ public static, song b n

ạ hãy kiên nh n.

ẫ

Dòng cuối là m t

ộ d n

ạ g m i

ớ c a

ủ câu l nh

ệ return trong đó bao g m

ồ m t

ộ giá tr ịtr

ả l i

ạ . Câu l nh

ệ này có

nghĩa là “t

ừ phư ng

ơ th c

ứ này hãy l p

ậ t c

ứ tr

ở v

ề và dùng bi u

ể th c

ứ kèm theo đây làm giá tr ịtr

ả l i

ạ .” Bi u

ể

thức mà b n

ạ đ t

ặ ra có th

ể ph c

ứ t p

ạ tùy ý, vì v y

ậ ta có th

ể vi t

ế phư ng

ơ th c

ứ sau m t

ộ cách g n

ọ h n:

ơ

public static double area(double radius) {

return Math.PI * radius * radius;

}

M t

ặ khác, nh ng

ữ bi n

ế t m

ạ th i

ờ như area thường giúp cho vi c

ệ g

ỡ lỗi đư c

ợ d

ễ dàng h n.

ơ Trong c i

ả hai

trường hợp, kiểu c a

ủ bi u

ể th c

ứ trong l nh

ệ return ph i

ả khớp v i

ớ ki u

ể c a

ủ phư ng

ơ th c

ứ . Nói cách khác,

khi b n

ạ khai báo r n

ằ g ki u

ể tr

ả l i

ạ là double, b n

ạ đã cam k t

ế r n

ằ g phư ng

ơ th c

ứ này cu i

ố cùng s

ẽ t o

ạ ra

một double. N u

ế b n

ạ thử return mà không kèm theo bi u

ể th c

ứ nào, ho c

ặ kèm theo bi u

ể th c

ứ nh ng

ư sai

kiểu, thì trình biên d c

ị h s

ẽ r y

ầ la b n.

ạ

Đôi khi c n

ầ ph i

ả có nhi u

ề l nh

ệ return, m i

ỗ l nh

ệ đ t

ặ

ở m t

ộ nhánh c a

ủ l nh

ệ đi u

ề ki n:

ệ

public static double absoluteValue(double x) {

if (x < 0) {

return -x;

} else {

return x;

}

}

Vì nh ng

ữ l nh

ệ return này

ở c u

ấ trúc đi u

ề ki n

ệ l a

ự ch n,

ọ cho nên ch ỉcó m t

ộ l nh

ệ đư c

ợ th c

ự thi. Dù r n

ằ g

hoàn toàn h p

ợ l

ệ n u

ế b n

ạ có nhi u

ề l nh

ệ return trong cùng m t

ộ phư ng

ơ th c

ứ , song b n

ạ c n

ầ ghi nh

ớ r ng

ằ

ngay khi một l nh

ệ return đư c

ợ th c

ự hi n,

ệ phư ng

ơ th c

ứ s

ẽ k t

ế thúc mà không th c

ự hi n

ệ b t

ấ c

ứ l nh

ệ nào

tiếp sau nó.

Mã lệnh xu t

ấ hi n

ệ sau dòng l nh

ệ return, hay nói chung, trong b t

ấ c

ứ ch

ỗ nào khác c a

ủ chư ng

ơ trình

mà không n m

ằ trong lu ng

ồ th c

ự hi n

ệ thì đư c

ợ g i

ọ là mã l n

ệ h ch t

ế . Một số trình biên d c

ị h sẽ c nh

ả báo

nếu có đo n

ạ l nh

ệ ch t

ế trong mã l nh

ệ b n

ạ vi t

ế nên.

Nếu b n

ạ đặt l nh

ệ return trong c u

ấ trúc đi u

ề ki n,

ệ thì ph i

ả đ m

ả b o

ả đư c

ợ r ng

ằ mỗi lu ng

ồ th c

ự hi n

ệ khả

dĩ đều d n

ẫ tới một l nh

ệ return. Ch ng

ẳ h n:

ạ

public static double absoluteValue(double x) {

if (x < 0) {

return -x;

} else if (x > 0) {

return x;

} // SAI!!

}

Chương trình này không h p

ợ l

ệ vì n u

ế x b n

ằ g 0, thì c

ả hai đi u

ề ki n

ệ không có đi u

ề ki n

ệ nào đư c

ợ tho

ả

mãn, và hàm s

ẽ k t

ế thúc mà không g p

ặ ph i

ả l nh

ệ return nào. Trình biên d c

ị h thư ng

ờ s

ẽ đ a

ư ra thông

báo ki u

ể như “return statement required in absoluteValue” (yêu c u ầ ph i

ả có l nh

ệ return trong

absoluteValue); l i

ờ thông báo này d

ễ gây nh m

ầ l n

ẫ vì trong đó b n

ạ đã vi t

ế hai l nh

ệ return r i

ồ .

6.2 Phát triển chư n

ơ g trình

Lúc này b n

ạ đã có th

ể nhìn vào toàn b

ộ phư ng

ơ th c

ứ Java r i

ồ cho bi t

ế chúng có nhi m

ệ v

ụ gì. Nh ng

ư

chưa ch c

ắ b n

ạ đã bi t

ế cách vi t

ế nên chúng. Tôi s

ẽ đ

ề xu t

ấ m t

ộ phư ng

ơ pháp gọi là phát tri n

ể tăng

d n

ầ .

Ở ví dụ này, giả d

ụ b n

ạ c n

ầ tìm kho n

ả g cách gi a

ữ hai đi m

ể cho b i

ở các to

ạ độ ( x 1, y 1) và ( x 2, y 2). Theo đ nh

ị nghĩa thông thư ng

ờ , kho ng

ả cách (distance) s

ẽ là:

√

distance = ————————————

( x 2 − x 1)2 +( y 2 − y 1)2

Bước đ u

ầ tiên là cân nh c

ắ xem m t

ộ hàm distance trong Java s

ẽ trông nh

ư th

ế nào. Nói cách khác, các

số liệu đầu vào (tham s )

ố và k t

ế qu

ả (giá tr ịtr

ả l i

ạ ) là gì?

Trong trư ng

ờ h p

ợ này, s

ố li u

ệ đ u

ầ vào mô t

ả hai đi m

ể ; ta có th

ể bi u

ể th ịchúng b ng

ằ b n

ố số double, dù

r n

ằ g sau này ta s

ẽ th y

ấ Java có ki u

ể đ i

ố tư ng

ợ Point mà ta có th

ể t n

ậ d ng

ụ . Giá trị c n

ầ tr

ả v

ề là kho n

ả g

cách, t c

ứ là s

ẽ thu c

ộ ki u

ể double.

Ta đã có th

ể phác th o

ả ngay ra hàm nh

ư sau:

public static double distance (double x1, double y1, double x2, double y2) {

return 0.0;

}

Câu l nh

ệ return 0.0; đóng vai trò gi

ữ ch

ỗ c n

ầ thi t

ế cho vi c

ệ biên d c

ị h chư ng

ơ trình. Đư ng

ơ nhiên, vào

lúc này nó ch a

ư phát huy tác d ng

ụ , song v n

ẫ đáng đ

ể ta th

ử biên d c

ị h nh m

ằ phát hi n

ệ ra l i

ỗ cú pháp,

nếu có, trư c

ớ khi vi t

ế thêm mã l nh

ệ .

Để kiểm tra phương th c

ứ m i

ớ vi t

ế này, ta ph i

ả kích ho t

ạ nó b ng

ằ các giá tr ịm u

ẫ . Đâu đó

ở trong main,

tôi s

ẽ ph i

ả vi t

ế l nh

ệ :

double dist = distance(1.0, 2.0, 4.0, 6.0);

Sở dĩ tôi ch n

ọ các tham s

ố này vì kho ng

ả cách ngang s

ẽ là 3 và kho ng

ả cách d c

ọ là 4, theo đó thì k t

ế qu

ả

sẽ b ng

ằ 5 (c nh

ạ huy n

ề c a

ủ m t

ộ tam giác có các c nh

ạ là 3-4-5). Khi th

ử nghi m

ệ m t

ộ hàm, b n

ạ nên bi t

ế

trước kết qu

ả đúng.

Một khi đã ki m

ể tra xong cú pháp c a

ủ l i

ờ đ nh

ị nghĩa hàm, ta có th

ể b t

ắ tay vào thêm mã l nh

ệ vào ph n

ầ

thân. Sau m i

ỗ l n

ầ thay đ i

ổ tăng d n,

ầ ta biên d c

ị h l i

ạ và ch y

ạ chư ng

ơ trình. N u

ế có l i

ỗ

ở b t

ấ kì bư c

ớ thay

đổi nào, ta s

ẽ bi t

ế ngay r ng

ằ ph i

ả nhìn vào đâu: chính là vào dòng l nh

ệ mà ta v a

ừ m i

ớ b

ổ sung.

Một bước làm hợp lí ti p

ế theo là tính các hi u

ệ số x 2 − x 1 và y 2 − y 1. Tôi l u ư tr

ữ các giá tr ịtrên vào nh ng

ữ

bi n

ế tạm th i

ờ có tên dx và dy.

public static double distance (double x1, double y1, double x2, double y2) {

double dx = x2 - x1;

double dy = y2 - y1;

System.out.println("dx is " + dx);

System.out.println("dy is " + dy);

return 0.0;

}

Tôi đã b

ổ sung hai l nh

ệ in vào sau đó đ

ể ta ki m

ể tra đư c

ợ nh ng

ữ giá tr ịtrung gian trư c

ớ khi ti p

ế t c

ụ .

Những giá tr ịnày ph i

ả b ng

ằ 3.0 và 4.0.

Một khi đã vi t

ế xong phư ng

ơ th c

ứ r i

ồ thì ta c n

ầ ph i

ả b

ỏ nh ng

ữ l nh

ệ in này đi. Các câu l nh

ệ nh

ư v y

ậ còn

có tên là dàn giáo vì nó có ích cho vi c

ệ xây d ng

ự chư ng

ơ trình nh ng

ư l i

ạ không ph i

ả là m t

ộ ph n

ầ trong

s n

ả phẩm cuối cùng.

Ti p

ế theo chúng ta tính các bình phư ng

ơ c a

ủ dx và dy. Ta đã có thể dùng phư ng

ơ th c

ứ Math.pow, nhưng

đem nhân t ng

ừ s

ố v i

ớ chính nó s

ẽ đ n

ơ gi n

ả h n.

ơ

public static double distance (double x1, double y1, double x2, double y2) {

double dx = x2 - x1;

double dy = y2 - y1;

double dsquared = dx*dx + dy*dy;

System.out.println("dsquared is " + dsquared); return 0.0;

}

Một l n

ầ n a

ữ , tôi biên d c

ị h r i

ồ ch y

ạ chư ng

ơ trình

ở giai đo n

ạ này và ki m

ể tra giá tr ịtrung gian (v n

ố ph i

ả

b n

ằ g 25.0).

Sau cùng, ta có th

ể dùng Math.sqrt để tính rồi tr

ả l i

ạ k t

ế qu .

ả

public static double distance (double x1, double y1, double x2, double y2) {

double dx = x2 - x1;

double dy = y2 - y1;

double dsquared = dx*dx + dy*dy;

double result = Math.sqrt(dsquared);

return result;

}

Từ main, ta có th

ể in và ki m

ể tra giá tr ịc a

ủ k t

ế qu .

ả

Sau này khi đã có kinh nghi m

ệ , b n

ạ s

ẽ vi t

ế và g

ỡ l i

ỗ nhi u

ề dòng l nh

ệ cùng lúc. Song dù sao đi n a

ữ , vi c

ệ

phát tri n

ể tăng d n

ầ s

ẽ giúp b n

ạ ti t

ế ki m

ệ nhi u

ề th i

ờ gian. Các đi m

ể c

ơ b n

ả c a

ủ quy trình này là:

• B t

ắ đầu v i

ớ một chư ng

ơ trình ch y

ạ đư c

ợ và thêm vào nh ng

ữ thay đ i

ổ nh .

ỏ B t

ấ c

ứ lúc nào khi g p

ặ l i

ỗ ,

b n

ạ sẽ phát hi n

ệ đư c

ợ ngay l i

ỗ đó

ở đâu.

• Dùng các bi n

ế t m

ạ đ

ể l u

ư gi

ữ các giá tr ịtrung gian, t

ừ đó b n

ạ có th

ể hi n

ể th ịvà ki m

ể tra chúng.

• Một khi chư ng

ơ trình đã ho t

ạ đ ng

ộ , b n

ạ có th

ể d

ỡ b

ỏ các đo n

ạ mã “dàn giáo”, ho c

ặ rút g n

ọ nhi u

ề câu

lệnh về một bi u

ể th c

ứ ph c

ứ h p,

ợ n u

ế vi c

ệ này không làm cho chư ng

ơ trình tr

ở nên khó đ c

ọ h n.

ơ

6.3 K t

ế h p

ợ phư n

ơ g thức

Một khi đã đ nh

ị nghĩa m t

ộ phư ng

ơ th c

ứ m i

ớ , b n

ạ có th

ể dùng nó nh

ư m t

ộ ph n

ầ c a

ủ bi u

ể th c

ứ l n,

ớ và

b n

ạ cũng có thể thi t

ế l p

ậ nh ng

ữ phư ng

ơ th c

ứ m i

ớ t

ừ các phư ng

ơ th c

ứ s n

ẵ có. Ch n

ẳ g h n,

ạ n u

ế ai đó cho

b n

ạ hai đi m

ể : m t

ộ là tâm đư ng

ờ tròn và m t

ộ đi m

ể trên đư ng

ờ tròn đó, r i

ồ yêu c u

ầ b n

ạ tính di n

ệ tích

hình tròn thì b n

ạ s

ẽ làm th

ế nào?

Giả sử như toạ độ c a

ủ tâm đi m

ể đư c

ợ l u

ư trong các bi n

ế xc và yc, to

ạ độ đi m

ể trên đư ng

ờ tròn

là xp và yp. Bư c

ớ đ u

ầ tiên s

ẽ là tìm bán kính c a

ủ đư ng

ờ tròn, v n

ố là kho ng

ả cách gi a

ữ hai đi m

ể đó. Th t

ậ

may là ta đã có m t

ộ phư ng

ơ th c

ứ , distance, đ

ể làm vi c

ệ này:

double radius = distance(xc, yc, xp, yp);

Bước ti p

ế theo là tìm di n

ệ tích c a

ủ m t

ộ đư ng

ờ tròn có bán kính đó, r i

ồ tr

ả l i

ạ k t

ế qu .

ả

double area = area(radius); return area;

Kết hợp hai bư c

ớ này vào trong cùng m t

ộ phư ng

ơ th c

ứ , ta thu đư c

ợ :

public static double circleArea (double xc, double yc, double xp, double yp) {

double radius = distance(xc, yc, xp, yp);

double area = area(radius);

return area;

}

Các bi n

ế t m

ạ th i

ờ radius và area có ích cho vi c

ệ phát tri n

ể và g

ỡ l i

ỗ chư ng

ơ trình, nh ng

ư m t

ộ khi

chương trình đã ho t

ạ đ ng

ộ t t

ố , ta có th

ể rút g n

ọ nó l i

ạ b ng

ằ cách k t

ế h p

ợ các l nh

ệ kích ho t

ạ phư ng

ơ

thức:

public static double circleArea (double xc, double yc, double xp, double yp) {

return area(distance(xc, yc, xp, yp));

}

6.4 Quá t i

ả toán tử

Có th

ể b n

ạ đã nh n

ậ th y

ấ r ng

ằ cả circleArea l n

ẫ area đều thực hi n

ệ nh ng

ữ tính năng tư ng

ơ t —t

ự ìm di n

ệ

tích hình tròn—nh ng

ư nh n

ậ các tham s

ố khác nhau. V i

ớ area, chúng ta ph i

ả cung c p

ấ bán kính; còn

với circleArea ta cung c p

ấ hai đi m

ể .

Nếu hai phư ng

ơ th c

ứ cùng làm m t

ộ vi c

ệ , l

ẽ t

ự nhiên là ta đ t

ặ chung m t

ộ tên cho c

ả hai. Vi c

ệ có nhi u

ề

phương th c

ứ cùng tên, v n

ố đư c

ợ g i

ọ là quá t i

ả (overloading), là đi u

ề h p

ợ l

ệ trong Java mi n

ễ sao các

dạng ph ng

ươ th c

ứ ph i

ả nh n

ậ nh ng

ữ tham s

ố khác nhau. Nh

ư v y

ậ ta có thể đ i

ổ tên circleArea:

public static double area (double x1, double y1, double x2, double y2) {

return area(distance(xc, yc, xp, yp));

}

Khi b n

ạ kích ho t

ạ m t

ộ phư ng

ơ th c

ứ quá t i

ả , Java s

ẽ bi t

ế đư c

ợ r n

ằ g b n

ạ mu n

ố dùng d ng

ạ phư ng

ơ th c

ứ

nào, qua vi c

ệ xem xét các đ i

ố s

ố mà b n

ạ cung c p.

ấ N u

ế b n

ạ vi t

ế :

double x = area(3.0);

thì Java sẽ đi tìm m t

ộ phư ng

ơ th c

ứ mang tên area mà nh n

ậ đối số là một double; do đó nó sẽ dùng

d ng

ạ thứ nhất, t c

ứ là hi u

ể đ i

ố s

ố nh

ư m t

ộ bán kính. Còn n u

ế b n

ạ vi t

ế :

double x = area(1.0, 2.0, 4.0, 6.0);

thì Java sẽ dùng d ng

ạ th

ứ hai c a

ủ area. Và lưu ý r n

ằ g th c

ự ra d n

ạ g area thứ hai đã kích ho t

ạ d ng

ạ th

ứ

nhất.

Nhi u

ề phương th c

ứ Java đư c

ợ qua t i

ả , nghĩa là có nhi u

ề d ng

ạ trong đó ch p

ấ nh n

ậ s

ố lư ng

ợ ho c

ặ ki u

ể

tham số khác nhau. Ch n

ẳ g h n,

ạ có nh ng

ữ d n

ạ g print và println ch p

ấ nh n

ậ một tham số thu c

ộ ki u

ể b t

ấ

kì. Trong l p

ớ Math, có m t

ộ d n

ạ g abs làm vi c

ệ v i

ớ double, đồng th i

ờ có một d n

ạ g dành cho int.

M c

ặ dù quá t i

ả là m t

ộ đ c

ặ đi m

ể h u

ữ ích, so b n

ạ hãy c n

ẩ th n

ậ khi dùng. B n

ạ có th

ể th t

ậ s

ự c m

ả th y

ấ lú

l n

ẫ n u

ế cố g ng

ắ g

ỡ lỗi m t

ộ d n

ạ g phư ng

ơ th c

ứ trong khi b n

ạ không ch

ủ ý kích ho t

ạ nó, mà là m t

ộ

phương th c

ứ khác cùng tên!

Và đi u

ề này làm tôi nh

ớ đ n

ế m t

ộ quy t c

ắ then ch t

ố trong g

ỡ l i

ỗ : hãy đ m

ả b o

ả ch c

ắ r n

ằ g phiên b n

ả

chương trình b n

ạ c n

ầ g

ỡ l i

ỗ chính là phiên b n

ả ch

n

ươ g trình b n

ạ đang ch y!

ạ

Một ngày nào đó có th

ể b n

ạ s

ẽ th y

ấ mình đang loay hoay s a

ử đi s a

ử l i

ạ chư ng

ơ trình, và c

ứ th y

ấ k t

ế qu

ả

v n

ẫ y nguyên nh

ư v y

ậ khi ch y

ạ l i

ạ . Đây là m t

ộ tín hi u

ệ c nh

ả báo r ng

ằ hi n

ệ b n

ạ không ch y

ạ phiên b n

ả

chương trình nh

ư đang nghĩ. Đ

ể ki m

ể tra l i

ạ , b n

ạ hãy th

ử thêm m t

ộ câu l nh

ệ print (ch ng

ẳ quan tr ng

ọ là

in thứ gì) và xem chư ng

ơ trình có bi u

ể hi n

ệ tư ng

ơ ng

ứ hay không.

6.5 Bi u t

ể h c

ứ logic

H u

ầ h t

ế các toán t

ử mà ta đã g p

ặ đ u

ề t o

ạ ra k t

ế qu

ả có cùng ki u

ể v i

ớ các toán h ng

ạ trong đó. L y

ấ ví d ,

ụ

toán tử + nh n

ậ hai số int rồi cũng t o

ạ ra m t

ộ số int, ho c

ặ hai số double rồi t o

ạ thành một double, v.v.

Những ngo i

ạ l

ệ mà ta g p,

ặ đó là các toán t

ử quan hệ, vốn để so sánh các int ho c

ặ float rồi trả

l i

ạ true ho c

ặ false. true và false là những giá tr ịđ c

ặ bi t

ệ trong Java; hai giá tr ịnày h p

ợ nên m t

ộ ki u

ể g i

ọ

là boolean. B n

ạ có th

ể nh

ớ l i

ạ r n

ằ g khi tôi đ nh

ị nghĩa m t

ộ ki u

ể , tôi có nói r n

ằ g đó là m t

ộ t p

ậ các giá tr .ị

Đ i

ố v i

ớ các số int, double hay chuỗi String, những t p

ậ h p

ợ nh

ư v y

ậ đều r t

ấ l n.

ớ Song v i

ớ boolean, t p

ậ

hợp này ch ỉch a

ứ hai giá tr .ị

Các bi u

ể th c

ứ boolean, hay bi u

ể th c

ứ logic, cùng các bi n

ế cũng ho t

ạ đ ng

ộ gi ng

ố nh

ư các bi u

ể th c

ứ và

bi n

ế thuộc ki u

ể khác:

boolean flag;

flag = true;

boolean testResult = false;

Ví d

ụ thứ nh t

ấ là một l i

ờ khai báo bi n

ế đ n

ơ gi n;

ả ví d

ụ th

ứ hai là m t

ộ l nh

ệ gán, còn ví d

ụ th

ứ ba là m t

ộ

lệnh kh i

ở t o

ạ .

Các giá trị true và false là những t

ừ khóa trong Java, vì v y

ậ chúng có th

ể xu t

ấ hi n

ệ v i

ớ màu ch

ữ khác tùy

theo môi trư ng

ờ phát tri n

ể tích h p

ợ mà b n

ạ đang dùng.

Kết qu

ả c a

ủ một toán t

ử đi u

ề ki n

ệ là m t

ộ giá tr ịboolean, b i

ở v y

ậ b n

ạ có th

ể l u

ư tr

ữ k t

ế qu

ả c a

ủ phép so

sánh vào một bi n:

ế

boolean evenFlag = (n%2 == 0); // đúng nếu n chẵn

boolean positiveFlag = (x > 0); // đúng nếu x dương

rồi l i

ạ dùng nó làm b

ộ ph n

ậ c a

ủ m t

ộ câu l nh

ệ đi u

ề ki n

ệ :

if (evenFlag) {

System.out.println("Khi tôi kiểm tra, n là số chẵn");

}

Một bi n

ế đư c

ợ dùng theo cách này có th

ể g i

ọ là m t

ộ bi n

ế d u

ấ hi u

ệ vì nó đánh d u

ấ cho s

ự có m t

ặ ho c

ặ

v n

ắ g m t

ặ c a

ủ một đi u

ề ki n

ệ nào đó.

6.6 Toán t l

ử ogic

Có ba toán t

ử logic trong Java: AND, OR và NOT, v n

ố đư c

ợ kí hi u

ệ b i

ở ba d u

ấ &&, || và !. Ý nghĩa c a

ủ

các toán t

ử này gi ng

ố nh

ư nghĩa các t

ừ tư ng

ơ ng

ứ trong ti ng

ế Anh. Ch ng

ẳ h n,

ạ x > 0 && x < 10 ch ỉđúng

khi x lớn hơn 0 và nhỏ hơn 10.

evenFlag || n%3 == 0 ch ỉđúng khi m t

ộ trong hai điều ki n

ệ là đúng; nghĩa

là evenFlag đúng hoặc số n chia h t

ế cho 3.

Sau cùng, toán tử not ph

ủ đ nh

ị một bi u

ể th c

ứ Boole. Do v y

ậ !evenFlag là đúng n u

ế như evenFlag là sai

—tức là n u

ế s

ố đã cho là l .

ẻ

Toán t

ử logic có th

ể làm đ n

ơ gi n

ả nh ng

ữ câu l nh

ệ đi u

ề ki n

ệ l ng

ồ ghép. Ch ng

ẳ h n

ạ , b n

ạ có th

ể vi t

ế l i

ạ

mã l nh

ệ dưới đây b ng

ằ m t

ộ câu l nh

ệ đi u

ề ki n

ệ đ n

ơ l

ẻ đư c

ợ không?

if (x > 0) {

if (x < 10) {

System.out.println("x là số dương gồm 1 chữ số.");

}

}

6.7 Phư n

ơ g thức logic

Các phương th c

ứ có th

ể tr

ả l i

ạ giá tr ịboolean cũng nh

ư các ki u

ể d

ữ li u

ệ khác; và đi u

ề này thư ng

ờ thu n

ậ

tiện cho vi c

ệ đem nh ng

ữ thao tác ki m

ể tra c t

ấ gi u

ấ vào trong phư ng

ơ th c

ứ . Ch n

ẳ g h n:

ạ

public static boolean isSingleDigit(int x) {

if (x >= 0 && x < 10) {

return true;

} else {

return false;

}

}

Phương th c

ứ này có tên là isSingleDigit. Thư ng

ờ thì ngư i

ờ ta hay đ t

ặ tên phư ng

ơ th c

ứ logic theo ki u

ể

như những câu h i

ỏ đúng/sai. Ki u

ể d

ữ li u

ệ tr

ả l i

ạ là boolean, như v y

ậ mỗi câu l nh

ệ return đ u

ề ph i

ả đ a

ư

ra một bi u

ể th c

ứ boolean.

B n

ả thân đo n

ạ mã l nh

ệ r t

ấ rõ nghĩa, m c

ặ dù nó dài h n

ơ m c

ứ c n

ầ thi t

ế . Hãy nh

ớ r n

ằ g bi u

ể th c

ứ x >= 0

&& x < 10 có ki u

ể boolean, b i

ở v y

ậ không có gì sai khi ta tr c

ự ti p

ế tr

ả l i

ạ nó đ ng

ồ th i

ờ tránh đư c

ợ câu

lệnh if:

public static boolean isSingleDigit(int x) {

return (x >= 0 && x < 10);

}

Từ main b n

ạ có thể kích ho t

ạ phư ng

ơ th c

ứ này theo cách thông thư ng

ờ :

boolean bigFlag = !isSingleDigit(17);

System.out.println(isSingleDigit(2));

Dòng đ u

ầ tiên đ t

ặ bigFlag là true ch ỉkhi 17 không ph i

ả số có một ch

ữ số. Dòng l nh

ệ thứ hai in

ra true bởi 2 là chỉ có m t

ộ ch

ữ s .

ố

Cách dùng hay g p

ặ nh t

ấ đ i

ố v i

ớ phư ng

ơ th c

ứ boole là trong các câu l nh

ệ đi u

ề ki n

ệ

if (isSingleDigit(x)) {

System.out.println("x nhỏ");

} else {

System.out.println("x lớn");

}

6.8 Nói thêm về đệ quy

Bây gi

ờ khi đã bi t

ế phư ng

ơ th c

ứ tr

ả l i

ạ giá tr ,ị ta có đư c

ợ m t

ộ ngôn ng

ữ l p

ậ trình Turing đ y

ầ đủ; theo

nghĩa là chúng ta s

ẽ tính đư c

ợ m i

ọ th

ứ có th

ể tính toán, trong đó “có th

ể tính toán” đư c

ợ đ nh

ị nghĩa

theo cách b t

ấ kì, mi n

ễ là h p

ợ lý. Ý tư ng

ở này đư c

ợ Alonzo Church và Alan Turing phát tri n,

ể b i

ở v y

ậ nó

còn mang tên lu n

ậ án Church-Turing. B n

ạ có th

ể đ c

ọ thêm thông tin

ởhttp://en.wikipedia.org/wiki/Turing_thesis.

Để c

ụ thể hoá tác d ng

ụ c a

ủ nh ng

ữ ki n

ế th c

ứ l p

ậ trình mà b n

ạ v a

ừ đư c

ợ h c

ọ , chúng ta hãy cùng l p

ậ m t

ộ

số hàm toán học theo cách đ

ệ quy. M t

ộ đ nh

ị nghĩa đ

ệ quy gi ng

ố nh

ư vi c

ệ đ n

ị h nghĩa vòng quanh; đi m

ể

tương đồng là trong ph n

ầ đ nh

ị nghĩa l i

ạ có tham chi u

ế đ n

ế s

ự v t

ậ đư c

ợ đ nh

ị nghĩa. Nh ng

ư cách đ nh

ị

nghĩa vòng quanh th c

ự s

ự thì không m y

ấ có tác d ng

ụ :

đệ quy:

một tính t

ừ để ch ỉmột ph ng

ươ th c

ứ mang tính đ

ệ quy.

B n

ạ h n

ẳ s

ẽ b c

ự mình khi th y

ấ m t

ộ đ nh

ị nghĩa ki u

ể nh

ư v y

ậ trong cu n

ố t

ừ đi n.

ể Ngư c

ợ l i

ạ , khi b n

ạ xem

đ nh

ị nghĩa v

ề hàm giai th a

ừ trong toán học, có th

ể b n

ạ s

ẽ th y

ấ :

0! = 1

n! = n ·( n−1)!

(Giai th a

ừ thư ng

ờ đư c

ợ kí hi u

ệ b i

ở d u

ấ !, xin đ ng

ừ nh m

ầ v i

ớ toán t

ử logic! với ý nghĩa NOT.) Đ nh

ị

nghĩa này phát bi u

ể r ng

ằ giai th a

ừ c a

ủ 0 là 1, và giai th a

ừ c a

ủ b t

ấ kì m t

ộ giá tr ịnào khác, n, thì

b n

ằ g n nhân v i

ớ giai th a

ừ c a

ủ n -  1.

Theo đó, 3! b ng

ằ 3 nhân v i

ớ 2!, vốn l i

ạ b n

ằ g 2 nhân v i

ớ 1!, vốn b n

ằ g

1 nhân v i

ớ 0!. Gộp tất c

ả l i

ạ , ta có 3! b ng

ằ 3 nhân 2 nhân 1 nhân 1, t c

ứ là b ng

ằ 6.

Nếu b n

ạ có th

ể phát bi u

ể m t

ộ đ nh

ị nghĩa có tính đ

ệ quy cho m t

ộ hàm nào đó thì b n

ạ cũng có th

ể vi t

ế

một phương th c

ứ Java đ

ể tính nó. Bư c

ớ đ u

ầ tiên là xác đ nh

ị các tham s

ố và ki u

ể d

ữ li u

ệ c a

ủ giá tr ịtr

ả

l i

ạ . Vì giai th a

ừ đư c

ợ đ nh

ị nghĩa cho các s

ố nguyên, nên phư ng

ơ th c

ứ c n

ầ vi t

ế s

ẽ nh n

ậ tham s

ố là s

ố

nguyên r i

ồ tr

ả l i

ạ cũng m t

ộ s

ố nguyên:

public static int factorial(int n) {

}

Nếu đối số b ng

ằ 0, chúng ta ch ỉc n

ầ tr

ả l i

ạ giá tr ị1:

public static int factorial(int n) {

if (n == 0) {

return 1;

}

}

Đó là trường h p

ợ c

ơ s .

ở

Nếu đi u

ề đó không x y

ả ra (đây chính là ph n

ầ hay nh t

ấ ), chúng ta th c

ự hi n

ệ l i

ờ g i

ọ đ

ệ quy đ

ể tính giai

thừa c a

ủ n -  1

và sau đó nhân nó v i

ớ n.

public static int factorial(int n) {

if (n == 0) {

return 1;

} else {

int recurse = factorial(n-1);

int result = n * recurse;

return result;

}

}

Luồng thực hi n

ệ c a

ủ chư ng

ơ trình này cũng gi ng

ố v i

ớ countdown trong M c

ụ 4.8. N u

ế ta kích

ho t

ạ factorial với giá tr ị3:

Vì 3 khác 0 nên ta ch n

ọ nhánh th

ứ hai và tính giai th a

ừ c a

ủ n-1…

Vì 2 khác 0 nên ta ch n

ọ nhánh th

ứ hai và tính giai th a

ừ c a

ủ n-1…

Vì 1 khác 0 nên ta ch n

ọ nhánh th

ứ hai và tính giai th a

ừ c a

ủ n-1…

Vì 0 bằng 0 nên ta chọn nhánh th

ứ nh t

ấ và tr

ả l i

ạ giá tr ị1 và không g i

ọ đ

ệ quy thêm l n

ầ nào n a

ữ .

Giá tr ịđược trả v ,

ề 1, đư c

ợ nhân v i

ớ n, vốn b n

ằ g 1, và k t

ế qu

ả được trả l i

ạ .

Giá tr ịđược trả v

ề (1) đư c

ợ nhân v i

ớ n, vốn b ng

ằ 2, và k t

ế qu

ả đư c

ợ tr

ả l i

ạ .

Giá tr ịđược trả v

ề (2) đư c

ợ nhân v i

ớ n, vốn b n

ằ g 3, và k t

ế quả, 6 tr

ở thành giá tr ịtr

ả v

ề c a

ủ hàm ng

ứ

với lúc b t

ắ đ u

ầ g i

ọ đ

ệ quy.

Sau đây là n i

ộ dung c a

ủ bi u

ể đ

ồ ngăn x p

ế khi m t

ộ lo t

ạ các phư ng

ơ th c

ứ đư c

ợ kích ho t

ạ :

Các giá trị trả l i

ạ nh

ư

ở đây đư c

ợ chuy n

ể v

ề ngăn x p.

ế

Lưu ý r n

ằ g

ở khung cu i

ố cùng, các bi n

ế đ a

ị phư ng

ơ recurse và result đều không tồn t i

ạ , vì

khi n=0, nhánh t o

ạ ra chúng không đư c

ợ th c

ự hi n.

ệ

6.9 Ni m t

ề

in

Việc dõi theo lu ng

ồ th c

ự hi n

ệ c a

ủ chư ng

ơ trình là m t

ộ cách đ c

ọ mã l nh

ệ , nh ng

ư b n

ạ s

ẽ nhanh chóng l c

ạ

vào mê cung. M t

ộ cách làm khác mà tôi g i

ọ là “ni m

ề tin” nh

ư sau. Khi b n

ạ dò đ n

ế ch

ỗ kích ho t

ạ phư ng

ơ

thức, thay vì vi c

ệ đi theo lu ng

ồ th c

ự hi n,

ệ hãy coi như là phương thức đó hoạt động t t

ố và tr

ả l i

ạ k t

ế quả

đúng.

Thật ra, b n

ạ đã t ng

ừ có “ni m

ề tin” này khi dùng các phư ng

ơ th c

ứ c a

ủ Java. M i

ỗ l n

ầ kích

ho t

ạ Math.cos hay System.out.println, b n

ạ không ki m

ể tra n i

ộ dung bên trong các phư ng

ơ th c

ứ

này. B n

ạ ch ỉvi c

ệ giả s

ử r ng

ằ chúng ho t

ạ đ ng

ộ đư c

ợ .

Cũng v i

ớ lý l

ẽ tư ng

ơ t

ự khi b n

ạ kích ho t

ạ các phư ng

ơ th c

ứ do mình vi t

ế nên. Ch n

ẳ g h n

ạ , trong M c

ụ 6.7,

chúng ta đã vi t

ế m t

ộ hàm tên là isSingleDigit để xác đ nh

ị xem m t

ộ s

ố có n m

ằ trong kho ng

ả t

ừ 0 đ n

ế

9 hay không. M t

ộ khi chúng ta t

ự thuy t

ế ph c

ụ r n

ằ g phư ng

ơ th c

ứ này đã vi t

ế đúng—b ng

ằ cách ki m

ể tra

và thử mã l nh

ệ —chúng ta có th

ể s

ử d n

ụ g phư ng

ơ th c

ứ mà không c n

ầ ph i

ả xem l i

ạ ph n

ầ mã l nh

ệ n a

ữ .

Đi u

ề tương t

ự cũng đúng v i

ớ các chư ng

ơ trình đ

ệ quy. Khi b n

ạ đ n

ế đi m

ể kích ho t

ạ đ

ệ quy, thay vì đi

theo luồng th c

ự hi n,

ệ b n

ạ c n

ầ coi r ng

ằ lời gọi đ

ệ quy ho t

ạ đ ng

ộ t t

ố (t c

ứ là cho k t

ế qu

ả đúng) và sau đó

tự hỏi mình “Gi

ả d

ụ nh

ư ta đã tìm đư c

ợ giai th a

ừ c a

ủ n−1, liệu ta có tính đư c

ợ giai th a

ừ c a

ủ n không?”

Trong trư ng

ờ h p

ợ này, rõ ràng là ta s

ẽ tính đư c

ợ , b ng

ằ cách nhân v i

ớ n.

Dĩ nhiên là sẽ có chút kì l

ạ trong vi c

ệ ta gi

ả s

ử r ng

ằ hàm ho t

ạ đ ng

ộ t t

ố khi ch a

ư vi t

ế xong nó, nh ng

ư

chính vì v y

ậ mà ta g i

ọ đó là ni m

ề tin!

6.10 Thêm m t

ộ ví dụ

Ví d

ụ thông d n

ụ g th

ứ hai để minh h a

ọ cho m t

ộ hàm toán toán h c

ọ đ

ệ quy là fibonacci, với cách đ nh

ị

nghĩa hàm nh

ư sau:

fibonacci(0) = 1

fibonacci(1) = 1

fibonacci( n) = fibonacci( n−1) + fibonacci( n−2); Chuy n

ể sang ngôn ng

ữ Java, ta vi t

ế đư c

ợ

public static int fibonacci(int n) {

if (n == 0 || n == 1) {

return 1;

} else {

return fibonacci(n-1) + fibonacci(n-2);

}

}

Nếu b n

ạ thử g ng

ắ theo lu ng

ồ th c

ự hi n

ệ

ở đây, ngay c

ả v i

ớ các giá tr ịnh

ỏ c a

ủ n, b n

ạ s

ẽ đau đầu ngay.

Nhưng b ng

ằ ni m

ề tin, n u

ế b n

ạ coi r n

ằ g c

ả hai l i

ờ g i

ọ đ

ệ quy đ u

ề ho t

ạ đ ng

ộ t t

ố , thì rõ ràng b n

ạ s

ẽ thu

được kết qu

ả đúng khi c ng

ộ chúng l i

ạ v i

ớ nhau.

6.11 Thu t

ậ ngữ

kiểu tr

ả l i

ạ :

Phần của l i

ờ khai báo ph ng

ươ th c

ứ , trong đó quy đ nh

ị

ki u

ể c a

ủ giá tr ịmà ph ng

ươ th c

ứ đó s

ẽ tr

ả l i

ạ .

giá tr ịtr

ả l i

ạ :

Giá tr ịđ c

ượ đ a

ư ra làm k t

ế quả c a

ủ vi c

ệ kích ho t

ạ ph ng

ươ th c

ứ .

đo n

ạ mã ch t

ế :

Phần ch ng

ươ trình không bao gi

ờ đ c

ượ th c

ự hi n,

ệ th ng

ườ là do nó xu t

ấ hi n

ệ sau m t

ộ câu

l nh

ệ return .

dàn giáo:

Mã l nh

ệ

đư c

ợ dùng trong giai đo n

ạ phát tri n

ể ch ng

ươ trình nh ng

ư b ịb

ỏ đi

ở phiên b n

ả ch ng

ươ trình

cu i

ố .

r n

ỗ g (void):

Một ki u

ể trả lại đặc bi t

ệ có

ở ph ng

ươ th c

ứ r n

ỗ g; nghĩa là ph ng

ươ th c

ứ không tr

ả l i

ạ giá tr ịnào.

quá t i

ả :

Vi c

ệ có nhi u

ề ph ng

ươ th c

ứ v i

ớ cùng tên g i

ọ nh ng

ư có các tham s

ố khác nhau. Khi b n

ạ kích ho t

ạ m t

ộ

ph ng

ươ th c

ứ quá t i

ả , Java sẽ bi t

ế đư c

ợ ph i

ả dùng d ng

ạ nào c a

ủ ph ng

ươ th c

ứ , căn c

ứ vào nh ng

ữ đ i

ố s

ố

mà b n

ạ cung c p

ấ . (Ti ng

ế Anh: “Overloading”)

boolean:

M t

ộ kiểu bi n

ế ch ỉch a

ứ hai giá trị true và false (đúng và sai).

d u

ấ hi u:

ệ

M t

ộ bi n

ế (thư ng

ờ v i

ớ kiểu boolean) để ghi l i

ạ thông tin về m t

ộ đi u

ề ki n

ệ ho c

ặ tr ng

ạ thái nào đó.

toán t

ử đi u

ề ki n

ệ :

Một toán t

ử dùng đ

ể so sánh hai giá tr ịr i

ồ t o

ạ ra m t

ộ giá tr ịboolean đ

ể ch ỉđ nh

ị quan h

ệ gi a

ữ hai toán

hạng nêu trên.

toán t

ử logic:

M t

ộ toán tử nh m

ằ k t

ế h p

ợ các giá tr ịboolean r i

ồ tr

ả l i

ạ cũng giá tr ịboolean.

6.12 Bài t p

ậ

Bài t p

ậ 1 Hãy vi t

ế một phương th c

ứ có tên isDivisible để nh n

ậ vào hai s

ố nguyên, n và m rồi trả

l i

ạ true nếu n chia h t

ế cho m và tr

ả l i

ạ false trong trường hợp còn l i

ạ .

Bài t p

ậ 2 Nhiều phép tính có th

ể đư c

ợ di n

ễ đ t

ạ ng n

ắ g n

ọ b ng

ằ phép “multadd” (nhân-c ng

ộ ), trong đó

l y

ấ ba toán h ng

ạ r i

ồ đi tính a*b + c. Thậm chí có b

ộ vi x

ử lý còn tích h p

ợ c

ả phép tính này đ i

ố v i

ớ nh ng

ữ

số ph y

ẩ động.

1. Hãy l p

ậ một chư ng

ơ trình m i

ớ có tên g i

ọ Multadd.java.

2. Viết một phương thức g i

ọ là multadd để l y

ấ tham số là ba số double rồi trả l i

ạ k t

ế quả c a

ủ phép nhân-

c ng

ộ giữa chúng.

3. Viết một phương thức main để kiểm tra multadd b ng

ằ cách kích ho t

ạ nó v i

ớ m t

ộ vài tham s

ố đ n

ơ gi n

ả

như 1.0, 2.0, 3.0.

4. Cũng trong main, hãy dùng multadd để tính các giá tr ịsau:

+

cos

sin

π

π

—

—

4

4

—————

2

log10 + log20

5. Hãy vi t

ế một phư ng

ơ th c

ứ có tên yikes để nh n

ậ tham số là một double r i

ồ dùng multadd để tính

√

x e−x + ————

1 − e−x

Gợi ý: đ

ể nâng e lên một số mũ, hãy dùng phư ng

ơ th c

ứ có tên Math.exp.

Trong câu h i

ỏ sau cùng, b n

ạ có c

ơ h i

ộ vi t

ế m t

ộ phư ng

ơ th c

ứ đ

ể kích ho t

ạ m t

ộ phư ng

ơ th c

ứ mà b n

ạ đã

viết trước đó. M i

ỗ khi làm nh

ư v y

ậ , b n

ạ nên c n

ẩ th n

ậ ki m

ể th

ử phư ng

ơ th c

ứ đ u

ầ trư c

ớ khi vi t

ế sang

phương th c

ứ th

ứ hai. N u

ế không, có thể b n

ạ s

ẽ r i

ơ vào trư ng

ờ h p

ợ ph i

ả g

ỡ l i

ỗ hai phư ng

ơ th c

ứ cùng

lúc, một công vi c

ệ r t

ấ khó khăn.

Một m c

ụ đích c a

ủ bài này là nh m

ằ luy n

ệ t p

ậ cách kh p

ớ m u

ẫ : đó là khi đư c

ợ cho m t

ộ bài toán c

ụ th ,

ể ta

c n

ầ nh n

ậ d ng

ạ nó trong s

ố m t

ộ t p

ậ h p

ợ các th

ể lo i

ạ bài toán.

Bài t p

ậ 3 Nếu có trong tay ba que g ,

ỗ có th

ể b n

ạ s

ẽ có ho c

ặ không x p

ế đư c

ợ thành hình tam giác.

Ch ng

ẳ h n,

ạ n u

ế m t

ộ que dài 12 inch còn hai que kia, m i

ỗ que ch ỉdài 1 inch, thì b n

ạ không th

ể kéo hai

đ u

ầ que ng n

ắ ch m

ạ nhau

ở gi a

ữ đư c

ợ . V i

ớ ba đo n

ạ th n

ẳ g có dài b t

ấ kì, có m t

ộ cách ki m

ể tra đ n

ơ gi n

ả

để xem li u

ệ chúng có x p

ế thành hình tam giác đư c

ợ không:

“Nếu có b t

ấ kì chi u

ề dài nào trong s

ố đó l n

ớ h n

ơ t ng

ổ hai chi u

ề dài còn l i

ạ , thì b n

ạ không

thể dựng thành hình tam giác. Trư ng

ờ h p

ợ còn l i

ạ , thì có th

ể đư c

ợ .”

Hãy vi t

ế một phư ng

ơ th c

ứ v i

ớ tên g i

ọ isTriangle, nh n

ậ vào đối số là ba s

ố nguyên, r i

ồ tr

ả

l i

ạ true ho c

ặ false, tùy theo kh

ả năng x p

ế thành hình tam giác b ng

ằ nh ng

ữ que có chi u

ề dài đã cho.

M c

ụ đích c a

ủ bài t p

ậ này là nh m

ằ áp d n

ụ g nh ng

ữ l nh

ệ đi u

ề ki n

ệ đ

ể vi t

ế nên m t

ộ phư ng

ơ th c

ứ tr

ả l i

ạ giá

trị.

Bài t p

ậ 4 Kết quả c a

ủ chư ng

ơ trình dư i

ớ đây là gì? M c

ụ đích c a

ủ bài t p

ậ này nh m

ằ đ m

ả b o

ả r n

ằ g b n

ạ

hiểu rõ các toán t

ử logic và lu ng

ồ th c

ự thi thông qua các phư ng

ơ th c

ứ tr

ả giá tr .ị

public static void main(String[] args) {

boolean flag1 = isHoopy(202);

boolean flag2 = isFrabjuous(202);

System.out.println(flag1);

System.out.println(flag2);

if (flag1 && flag2) {

System.out.println("ping!");

}

if (flag1 || flag2) {

System.out.println("pong!");

}

}

public static boolean isHoopy(int x) {

boolean hoopyFlag;

if (x%2 == 0) {

hoopyFlag = true;

} else {

hoopyFlag = false;

}

return hoopyFlag;

}

public static boolean isFrabjuous(int x) {

boolean frabjuousFlag;

if (x > 0) {

frabjuousFlag = true;

} else {

frabjuousFlag = false;

}

return frabjuousFlag;

}

Bài t p

ậ 5 Kho n

ả g cách gi a

ữ hai đi m

ể ( x 1, y 1) và ( x 2, y 2) thì b n ằ g

√

Distance = ————————————

(x2 − x1)2 +(y2 − y1)2

Hãy vi t

ế một phư ng

ơ th c

ứ có tên distance để nh n

ậ các tham s

ố g m

ồ b n

ố s

ố ph y

ẩ đ ng

ộ —x1, y1, x2 và y2

—rồi in ra kho n

ả g cách gi a

ữ hai đi m

ể này. B n

ạ c n

ầ gi

ả s

ử r ng

ằ đã có m t

ộ phư ng

ơ th c

ứ sumSquares để

tính và trả l i

ạ t ng

ổ các bình phư ng

ơ c a

ủ đ i

ố s .

ố Ch n

ẳ g h n

ạ dòng l nh

ệ :

double x = sumSquares(3.0, 4.0);

sẽ gán giá trị 25.0 cho x.

M c

ụ đích c a

ủ bài t p

ậ này là nh m

ằ vi t

ế m t

ộ phư ng

ơ th c

ứ m i

ớ có áp d ng

ụ phư ng

ơ th c

ứ s n

ẵ có. B n

ạ ch ỉ

c n

ầ vi t

ế một phương th c

ứ : distance. B n

ạ không đư c

ợ vi t

ế sumSquares hay main và cũng không kích

ho t

ạ distance.

Bài t p

ậ 6 M c

ụ đích c a

ủ bài t p

ậ này là dùng bi u

ể đ

ồ ngăn x p

ế đ

ể hi u

ể đư c

ợ trình t

ự th c

ự hi n

ệ m t

ộ

chương trình đ

ệ quy.

public class Prod {

public static void main(String[] args) {

System.out.println(prod(1, 4));

}

public static int prod(int m, int n) {

if (m == n) {

return n;

} else {

int recurse = prod(m, n-1);

int result = n * recurse;

return result;

}

}

}

1. Hãy v

ẽ một bi u

ể đ

ồ ngăn x p

ế cho th y

ấ tr ng

ạ thái c a

ủ chư ng

ơ trình ngay trư c

ớ khi th c

ự th

ể cu i

ố cùng

c a

ủ prod hoàn tất th c

ự thi. K t

ế qu

ả c a

ủ chư ng

ơ trình này là gì?

2. Gi i

ả thích ng n

ắ g n

ọ xem prod làm vi c

ệ gì.

3. Viết l i

ạ prod mà không dùng đ n

ế các bi n

ế t m

ạ recurse và result.

Bài t p

ậ 7 M c

ụ đích c a

ủ bài t p

ậ này là chuy n

ể t

ừ m t

ộ l i

ờ đ nh

ị nghĩa đ

ệ quy sang m t

ộ phư ng

ơ th c

ứ

Java. Hàm Ackerman đư c

ợ đ n

ị h nghĩa cho s

ố nguyên không âm nh

ư sau:

A(m, n) =

⎧

⎨

(1)

⎩

n+1

nếu m = 0

A( m− 1, 1)

nếu m > 0 và n = 0

A( m−1, A( m, n−1)) nếu m > 0 và n > 0.

Hãy vi t

ế một phư ng

ơ th c

ứ tên là ack để nh n

ậ tham số là hai số int rồi tính và trả l i

ạ giá tr ịc a

ủ hàm

Ackerman. Hãy ki m

ể tra phư ng

ơ th c

ứ v a

ừ vi t

ế b ng

ằ cách kích ho t

ạ nó từ main rồi in ra giá tr ịv a

ừ tr

ả

l i

ạ .

CẢNH BÁO: giá tr ịđư c

ợ tr

ả l i

ạ s

ẽ r t

ấ nhanh chóng tăng cao. B n

ạ ch ỉnên th

ử ch y

ạ v i

ớ các giá tr ịm và n

nhỏ (không l n

ớ quá 2).

Bài t p

ậ 8

1. Hãy t o

ạ nên m t

ộ chư ng

ơ trình có tên Recurse.java rồi gõ vào các phư ng

ơ th c

ứ sau:

// first: trả lại kí tự đầu tiên của String cho trước

public static char first(String s) {

return s.charAt(0);

}

// last: trả lại một String mới có chứa toàn bộ

// chỉ trừ kí tự đầu của String cho trước

public static String rest(String s) {

return s.substring(1, s.length());

}

// length: trả lại chiều dài của String cho trước

public static int length(String s) {

return s.length();

}

2. Hãy vi t

ế vài câu l nh

ệ trong main để kiểm tra t ng

ừ phư ng

ơ th c

ứ trên. Đ m

ả b o

ả ch c

ắ là chúng ho t

ạ đ ng

ộ

được, và ch c

ắ ch n

ắ là b n

ạ đã hi u

ể công d ng

ụ c a

ủ chúng là gì.

3. Viết một phương thức có tên printString để nh n

ậ tham số là một String đ ng

ồ th i

ờ in các ch

ữ cái trong

String đó, m i

ỗ ch

ữ cái trên m t

ộ dòng. Phư ng

ơ th c

ứ này ph i

ả là ki u

ể r ng

ỗ .

4. Viết một phương thức có tên printBackward có công d n

ụ g g n

ầ gi ng

ố printString ch ỉkhác là in String

theo chi u

ề ngư c

ợ l i

ạ (m i

ỗ kí t

ự trên m t

ộ dòng riêng).

5. Viết một phương thức có tên reverseString để nh n

ậ tham số là một String r i

ồ tr

ả l i

ạ giá tr ịlà m t

ộ String

mới. String m i

ớ này ph i

ả có đ y

ầ đ

ủ các ch

ữ cái nh

ư String đã nh p

ậ làm tham s ;

ố nh ng

ư l i

ạ x p

ế theo th

ứ

tự ngư c

ợ l i

ạ . Ch ng

ẳ h n

ạ , k t

ế qu

ả c a

ủ đo n

ạ mã l nh

ệ sau

String backwards = reverseString("Allen Downey");

System.out.println(backwards);

sẽ ph i

ả là

yenwoD nellA

Bài t p

ậ 9 Hãy vi t

ế một phương th c

ứ đ

ệ quy có tên power để nh n

ậ vào x và một số nguyên n rồi tr

ả

l i

ạ xn. Gợi ý: một đ nh

ị nghĩa đ

ệ quy đ i

ố v i

ớ phép tính này là xn = x · xn −1. Đồng thời, c n ầ nh

ớ r n

ằ g m i

ọ

số nâng lên lũy th a

ừ b c

ậ 0 đ u

ề b ng

ằ 1. Câu h i

ỏ khó t

ự ch n

ọ : b n

ạ có th

ể làm cho phư ng

ơ th c

ứ này hi u

ệ

quả hơn, trong trư ng

ờ h p

ợ n ch n,

ẵ b ng

ằ cách dùng công th c

ứ xn = ( xn/2 )2.

Bài t p

ậ 10 (Bài t p

ậ này đư c

ợ d a

ự trên trang 44 cu n

ố sách Structure and Interpretation of Computer

Programs c a

ủ Abelson và Sussman.) Kĩ thu t

ậ sau đây có tên g i

ọ Thu t

ậ toán Euclid vì nó xu t

ấ hi n

ệ trong

t p

ậ Cơ b n

ả c a

ủ Euclid (Cu n

ố s

ố 7, kho n

ả g năm 300 TCN). Có l

ẽ đây là thu t

ậ toán đáng k

ể t

ừ lâu đ i

ờ

nhất1. Quy trình tính toán đư c ợ d a

ự theo quan sát th y

ấ , n u

ế r là ph n

ầ dư trong phép chia a cho b, thì

các ư c

ớ s

ố chung c a

ủ a và b cũng b ng

ằ ư c

ớ s

ố chung c a

ủ b và r. Do v y

ậ ta có th

ể dùng phư ng

ơ trình

gcd(a, b) = gcd(b, r)

để liên ti p

ế rút g n

ọ bài toán tính ư c

ớ s

ố chung (GCD) v

ề bài toán tính GCD c a

ủ các c p

ặ s

ố nguyên ngày

càng nhỏ h n.

ơ Ch n

ẳ g h n,

ạ

gcd(36, 20) = gcd(20, 16) = gcd(16, 4) = gcd(4, 0) = 4

ng

ụ ý r ng

ằ GCD c a

ủ 36 và 20 thì b ng

ằ 4. Có th

ể th y

ấ r n

ằ g v i

ớ b t

ấ kì hai s

ố ban đ u

ầ nào, cách liên ti p

ế

rút gọn này cu i

ố cùng s

ẽ cho ta m t

ộ c p

ặ s

ố mà s

ố th

ứ hai b n

ằ g 0. Khi đó GCD s

ẽ b ng

ằ s

ố còn l i

ạ trong

c p.

ặ

Hãy vi t

ế một phư ng

ơ th c

ứ có tên gcd để nh n

ậ tham số là hai s

ố nguyên r i

ồ dùng Thu t

ậ toán Euclid đ

ể

tính và trả l i

ạ ư c

ớ s

ố chung l n

ớ nh t

ấ c a

ủ hai s .

ố

Ch

ng

ươ 7: Phép l p

ặ và vòng l p

ặ

7.1 Phép gán nhi u l

ề

n

ầ

B n

ạ có thể khi n

ế cho nhi u

ề l nh

ệ gán ch ỉt i

ớ cùng m t

ộ bi n;

ế mà hi u

ệ qu

ả c a

ủ nó là nh m

ằ thay th

ế giá tr ị

cũ b ng

ằ giá tr ịm i

ớ .

int liz = 5;

System.out.print(liz);

liz = 7;

System.out.println(liz);

Kết qu

ả c a

ủ chư ng

ơ trình này b n

ằ g 57, vì l n

ầ đầu tiên khi in liz bi n

ế này có giá tr ịb ng

ằ 5, còn l n

ầ th

ứ

hai thì bi n

ế có giá tr ịb ng

ằ 7.

Hình th c

ứ gán nhi u

ề l n

ầ như thế này là lí do mà tôi mô t

ả các bi n

ế nh

ư là h p

ộ ch a

ứ giá trị. Khi b n

ạ

gán một giá trị vào cho bi n,

ế b n

ạ thay đ i

ổ n i

ộ dung c a

ủ h p

ộ ch a

ứ , nh

ư

ở hình v

ẽ sau:

Khi có nhi u

ề phép gán đ i

ố v i

ớ cùng m t

ộ bi n,

ế thì r t

ấ chú tr ng

ọ vi c

ệ phân bi t

ệ gi a

ữ câu l nh

ệ gán và đ n

ẳ g

thức. Vì Java dùng d u

ấ = cho l nh

ệ gán nên ta b ịlôi cu n

ố vào vi c

ệ di n

ễ gi i

ả m t

ộ câu l nh

ệ như a = b là câu

lệnh đ ng

ẳ thức. Th t

ậ ra không ph i

ả v y

ậ !

Trư c

ớ h t

ế , đ ng

ẳ th c

ứ thì có tính giao hoán, còn l nh

ệ gán thì không. Ch ng

ẳ h n

ạ trong toán h c

ọ , n u

ế a = 7

thì 7 = a. Nhưng trong Java a = 7; l i

ạ là một l nh

ệ gán h p

ợ l ,

ệ còn 7 = a; thì không.

Hơn nữa, trong toán h c

ọ , m t

ộ đ ng

ẳ th c

ứ thì luôn đúng. N u

ế bây giờ a = b, thì a sẽ luôn b ng ằ b. Trong

Java, một l nh

ệ gán có th

ể làm cho hai bi n

ế b ng

ằ nhau, nh ng

ư không có gì b t

ắ bu c

ộ chúng b ng

ằ nhau

mãi!

int a = 5;

int b = a; // bây giờ thì a bằng b

a = 3; // a không còn bằng b nữa

Dòng l nh

ệ th

ứ ba đã thay đ i

ổ giá tr ịc a

ủ a mà không làm thay đ i

ổ giá tr ịc a

ủ b, vì v y

ậ chúng không còn

b n

ằ g nhau. Một số ngôn ngữ l p

ậ trình có dùng kí hi u

ệ khác cho phép gán, như <- ho c

ặ :=, đ

ể tránh s

ự

nhầm l n

ẫ này.

M c

ặ dù phép gán nhi u

ề l n

ầ thư ng

ờ có ích, so b n

ạ nên c n

ẩ th n

ậ khi dùng. N u

ế giá tr ịc a

ủ các bi n

ế thay

đổi thường xuyên thì có có th

ể khi n

ế cho mã l nh

ệ khó đ c

ọ và g

ỡ l i

ỗ .

7.2 Câu l nh

ệ

while

Máy tính thư ng

ờ đư c

ợ dùng đ

ể t

ự đ ng

ộ hóa các thao tác có tính l p

ặ l i

ạ . Th c

ự hi n

ệ nh ng

ữ thao tác l p

ặ l i

ạ

này mà không ph m

ạ l i

ỗ là đi u

ề mà máy tính làm t t

ố còn chúng ta làm r t

ấ d .

ở

Ta đã th y

ấ các phư ng

ơ th c

ứ như countdown và factorial trong đó dùng đệ quy đ

ể th c

ự hi n

ệ l p.

ặ Quá

trình này đư c

ợ g i

ọ là phép l p

ặ . Java có nh ng

ữ đ c

ặ đi m

ể ngôn ngữ giúp cho vi c

ệ vi t

ế các phư ng

ơ th c

ứ

nêu trên một cách dễ dàng h n.

ơ Ở chư ng

ơ này ta xem xét câu l nh

ệ while. V

ề sau (

ở M c

ụ 12.4) ta xét đ n

ế

câu l nh

ệ for.

Dùng câu l nh

ệ while, ta có th

ể vi t

ế l i

ạ countdown:

public static void countdown(int n) {

while (n > 0) {

System.out.println(n);

n = n-1;

}

System.out.println("Bum!");

}

G n

ầ như là b n

ạ có th

ể đọc đư c

ợ toàn b

ộ câu l nh

ệ while b n

ằ g tiếng Anh. L nh

ệ này di n

ễ t

ả là, “Khi n lớn

hơn không, hãy in giá tr ịc a

ủ n rồi giảm giá trị c a

ủ n xuống 1. Khi b n

ạ đ t

ạ đ n

ế không, hãy in ra t

ừ

‘Bum!”’

Theo cách quy c

ủ h n,

ơ lu ng

ồ th c

ự thi c a

ủ m t

ộ l nh

ệ while như sau:

1.Đ nh

ị giá đi u

ề ki n

ệ trong c p

ặ ngo c

ặ tròn, cho ra true ho c

ặ false.

2.Nếu đi u

ề ki n

ệ là sai, thì thoát kh i

ỏ l nh

ệ while rồi ti p

ế t c

ụ th c

ự thi câu l nh

ệ li n

ề sau.

3.Nếu đi u

ề ki n

ệ là đúng, thì th c

ự thi nh ng

ữ câu l nh

ệ trong ph m

ạ vi c p

ặ ngo c

ặ nh n,

ọ r i

ồ tr

ở l i

ạ bư c

ớ 1.

Ki u

ể luồng th c

ự thi này đư c

ợ g i

ọ là vòng l p

ặ vì bư c

ớ th

ứ ba vòng ngư c

ợ tr

ở lên đ u

ầ . Nh ng

ữ câu l nh

ệ

bên trong vòng l p

ặ đư c

ợ g i

ọ là thân c a

ủ vòng l p

ặ . N u

ế đi u

ề ki n

ệ là sai ngay l n

ầ đ u

ầ tiên qua vòng l p

ặ

thì nh ng

ữ câu l nh

ệ bên trong vòng l p

ặ không bao gi

ờ đư c

ợ th c

ự thi.

Ph n

ầ thân vòng l p

ặ c n

ầ ph i

ả thay đ i

ổ giá tr ịc a

ủ m t

ộ vài bi n

ế sao cho cu i

ố cùng thì đi u

ề ki n

ệ tr

ở nên sai

và vòng l p

ặ ch m

ấ d t

ứ . N u

ế không, vòng s

ẽ đư c

ợ l p

ặ l i

ạ mãi, và đư c

ợ g i

ọ là vòng l p

ặ vô h n

ạ . Một câu

chuy n

ệ đùa luôn đư c

ợ nh c

ắ đ n

ế trong gi i

ớ khoa h c

ọ máy tính là qua vi c

ệ nh n

ậ th y

ấ ch ỉd n

ẫ trên gói d u

ầ

gội đ u

ầ , “Xát, x

ả nư c

ớ , r i

ồ l p

ặ l i

ạ ,” chính là m t

ộ vòng l p

ặ vô h n.

ạ

Ở trường h p

ợ countdown, ta có th

ể ch ng

ứ minh r n

ằ g vòng l p

ặ s

ẽ k t

ế thúc n u

ế n là số dương. Còn trong

những trường hợp khác thì không d

ễ nói trư c

ớ :

public static void sequence(int n) {

while (n != 1) {

System.out.println(n);

if (n%2 == 0) { // n chẵn

n = n / 2;

} else { // n lẻ

n = n*3 + 1;

}

}

}

Đi u

ề ki n

ệ c a

ủ vòng l p

ặ này là n != 1, vì v y

ậ vòng l p

ặ s

ẽ ti p

ế di n

ễ đ n

ế t n

ậ khi n b ng

ằ 1, và đi u

ề này khi n

ế

cho đi u

ề ki n

ệ b ịsai đi.

T i

ạ mỗi vòng l p

ặ , chư ng

ơ trình in ra giá tr ịc a

ủ n rồi ki m

ể tra xem li u

ệ s

ố này ch n

ẵ hay l .

ẻ N u

ế ch n,

ẵ giá

trị c a

ủ n được chia cho 2. N u

ế l ,

ẻ giá tr ịđư c

ợ thay th

ế b i

ở 3 n+1. Ch ng

ẳ h n

ạ , n u

ế giá tr ịban đ u

ầ (t c

ứ đ i

ố

số được truyền vào sequence) b ng

ằ 3, thì k t

ế qu

ả là ta có dãy 3, 10, 5, 16, 8, 4, 2, 1.

Vì đôi khi n tăng và đôi khi gi m

ả , nên s

ẽ không có cách ch ng

ứ minh nào d

ễ th y

ấ ràng cu i

ố cùng n sẽ đ t

ạ

đến 1, hay chương trình s

ẽ k t

ế thúc. V i

ớ m t

ộ s

ố giá tr ịđ c

ặ bi t

ệ c a

ủ n, ta có th

ể ch ng

ứ minh đư c

ợ s

ự k t

ế

thúc đó. Ch n

ẳ g h n

ạ , n u

ế giá tr ịkh i

ở đ u

ầ là m t

ộ s

ố lũy th a

ừ c a

ủ hai, thì giá tr ịc a

ủ n sẽ luôn ch n

ẵ qua

mỗi l n

ầ l p

ặ , cho đ n

ế khi ta thu đư c

ợ 1. Ví d

ụ trư c

ớ s

ẽ k t

ế thúc v i

ớ m t

ộ dãy nh

ư v y

ậ v i

ớ giá tr ịban đ u

ầ

b n

ằ g 16.

Ngoài nh ng

ữ giá tr ịđ c

ặ bi t

ệ , thì m t

ộ câu h i

ỏ thú v ịlà li u

ệ ta có th

ể ch ng

ứ minh đư c

ợ r ng

ằ đo n

ạ chư ng

ơ

trình trên có k t

ế thúc v i

ớ tất cả những giá tr ịc a

ủ n hay không. Cho đ n

ế gi ,

ờ ch a

ư ai có th

ể ch ng

ứ minh

ho c

ặ bác b

ỏ nó! B n

ạ hãy tìm thêm thông tin ở http://en.wikipedia.org/wiki/Collatz_conjecture.

7.3 B ng

ả

s

ố li u

ệ

Một trong nh ng

ữ công vi c

ệ thích h p

ợ v i

ớ dùng vòng l p

ặ , đó là phát sinh ra b n

ả g s

ố li u

ệ . Trư c

ớ khi máy

tính trở nên phổ bi n,

ế m i

ọ ngư i

ờ đã ph i

ả tính tay các phép logarit, sin, cosin, và nh ng

ữ hàm toán h c

ọ

khác.

Để đơn gi n

ả hóa vi c

ệ này, sách toán thư ng

ờ in kèm nh ng

ữ b ng

ả dài li t

ệ kê giá tr ịcác hàm nói trên. Vi c

ệ

t o

ạ ra các b ng

ả nh

ư v y

ậ r t

ấ ch m

ậ và nhàm chán, và d

ễ m c

ắ ph i

ả nhi u

ề l i

ỗ .

Khi máy tính xu t

ấ hi n,

ệ đã có nh ng

ữ ph n

ả

ng

ứ ban đ u

ầ ki u

ể nh :

ư “Đi u

ề này th t

ậ tuy t

ệ ! Gi

ờ ta có th

ể

dùng máy tính đ

ể t o

ạ ra các b ng

ả , vì v y

ậ s

ẽ không có l i

ỗ .” Đi u

ề này tr

ở nên (g n

ầ nh

ư là) s

ự th t

ậ nh ng

ư

v n

ẫ ch a

ứ đ ng

ự t m

ầ nhìn h n

ạ h p.

ẹ Không lâu sau đó, máy tính và máy b

ỏ túi đã xu t

ấ hi n

ệ tràn lan và

b n

ả g số trở nên lỗi th i

ờ .

,

Ừ g n

ầ như v y

ậ . Có nh ng

ữ phép tính mà máy tính l y

ấ con s

ố t

ừ b n

ả g đ

ể có giá tr ịg n

ầ đúng, r i

ồ th c

ự hi n

ệ

tính toán nh m

ằ c i

ả thi n

ệ k t

ế qu

ả g n

ầ đúng này.

Ở trư ng

ờ h p

ợ khác, có nh ng

ữ l i

ỗ n m

ằ ngay

ở b ng

ả s ,

ố

được biết đến nhi u

ề nh t

ấ là b ng

ả mà máy Intel Pentium đã dùng đ

ể th c

ự hi n

ệ phép chia v i

ớ s

ố có d u

ấ

ph y

ẩ động.

M c

ặ dù b ng

ả loga không còn h u

ữ d ng

ụ nh

ư x a

ư , song nó v n

ẫ dùng đư c

ợ làm ví d

ụ v

ề tính l p.

ặ Chư ng

ơ

trình sau in ra m t

ộ dãy các s

ố

ở c t

ộ bên trái cùng v i

ớ giá tr ịlogarit c a

ủ chúng

ở c t

ộ ph i

ả :

double x = 1.0;

while (x < 10.0) {

System.out.println(x + " " + Math.log(x));

x = x + 1.0;

}

Kết qu

ả c a

ủ chư ng

ơ trình này là:

1.0 0.0

2.0 0.6931471805599453

3.0 1.0986122886681098

4.0 1.3862943611198906

5.0 1.6094379124341003

6.0 1.791759469228055

7.0 1.9459101490553132

8.0 2.0794415416798357

9.0 2.1972245773362196

Nhìn vào nh ng

ữ giá tr ịnày, b n

ạ có th

ể nói r ng

ằ phư ng

ơ th c

ứ log này dùng c

ơ s

ố nào?

Vì các lũy th a

ừ c a

ủ 2 r t

ấ quan tr ng

ọ trong ngành khoa h c

ọ máy tính, nên ta thư ng

ờ mu n

ố l y

ấ loga theo

cơ số 2. Đ

ể tính toán, ta có thể dùng bi u

ể th c

ứ :

log2 x = loge x / loge 2

Hãy thay câu l nh

ệ print b n

ằ g

System.out.println(x + " " + Math.log(x) / Math.log(2.0)); để cho ra

1.0 0.0

2.0 1.0

3.0 1.5849625007211563

4.0 2.0

5.0 2.321928094887362

6.0 2.584962500721156

7.0 2.807354922057604

8.0 3.0

9.0 3.1699250014423126

Có th

ể th y

ấ r ng

ằ 1, 2, 4, và 8 là các lũy th a

ừ c a

ủ 2 vì các giá tr ịlogarit c

ơ s

ố 2 c a

ủ chúng đ u

ề là nh ng

ữ s

ố

nguyên. N u

ế mu n

ố tìm logarit c a

ủ nh ng

ữ lũy th a

ừ khác c a

ủ 2, ta có th

ể s a

ử chư ng

ơ trình trên thành:

double x = 1.0;

while (x < 100.0) {

System.out.println(x + " " + Math.log(x) / Math.log(2.0)); x = x * 2.0;

}

Bây gi

ờ thay vì c ng

ộ thêm m t

ộ s

ố v i

ớ x trong mỗi vòng l p

ặ (đi u

ề này cho ra dãy c p

ấ s

ố c ng

ộ ), ta đem

nhân một giá tr ịv i

ớ x (thu đư c

ợ c p

ấ s

ố nhân). Kết qu

ả là:

1.0 0.0

2.0 1.0

4.0 2.0

8.0 3.0

16.0 4.0

32.0 5.0

64.0 6.0

B ng

ả logarit có th

ể không còn có ích n a

ữ , nh ng

ư v i

ớ nhà khoa h c

ọ máy tính, vi c

ệ nh

ớ đư c

ợ các lũy th a

ừ

c a

ủ hai nh t

ấ thi t

ế có ích! Khi nào r nh

ả r i

ỗ , b n

ạ hãy ghi nh

ớ các lũy th a

ừ c a

ủ hai đ n

ế t n

ậ 65536 (t c

ứ là

216).

7.4 B ng h

ả

ai chi u

ề

Trong một b n

ả g hai chi u

ề , b n

ạ đ c

ọ giá tr ị

ở đi m

ể giao c t

ắ gi a

ữ m t

ộ hàng v i

ớ m t

ộ c t

ộ . B ng

ả c u

ử chư ng

ơ

là một ví d

ụ đi n

ể hình. Giả s

ử b n

ạ mu n

ố in ra m t

ộ b ng

ả tính nhân v i

ớ các giá tr ịt

ừ 1 đ n

ế 6.

Một cách b t

ắ đầu n

ổ thỏa là vi t

ế m t

ộ vòng l p

ặ để in ra các b i

ộ s

ố c a

ủ 2 trên cùng m t

ộ dòng.

int i = 1;

while (i <= 6) {

System.out.print(2*i + " ");

i = i + 1;

}

System.out.println("");

Dòng đ u

ầ tiên kh i

ở t o

ạ m t

ộ bi n

ế có tên là i; nó đóng vai trò m t

ộ bi n

ế đ m

ế ho c

ặ bi n

ế vòng l p

ặ . Khi

vòng l p

ặ đư c

ợ th c

ự thi, giá tr ịc a

ủ i tăng từ 1 lên 6. Khi i b ng

ằ 7, vòng l p

ặ k t

ế thúc. M i

ỗ l n

ầ l p

ặ , chư ng

ơ

trình s

ẽ in ra giá tr ịc a

ủ 2*i, theo sau là ba dấu cách.

Một l n

ầ n a

ữ , dấu ph y

ẩ trong câu l nh

ệ print ngăn không cho xu ng

ố dòng. Sau khi vòng l p

ặ k t

ế thúc,

lệnh print thứ hai b t

ắ đ u

ầ một dòng m i

ớ . Vì ta dùng System.out.print, nên toàn b

ộ k t

ế qu

ả đư c

ợ ghi

trên một dòng.

Có những môi trư ng

ờ mà k t

ế qu

ả từ print được lưu l i

ạ mà ch a

ư hi n

ể th ịđ n

ế khi kích ho t

ạ println. Nếu

chương trình k t

ế thúc, mà b n

ạ quên kích ho t

ạ println, có th

ể b n

ạ s

ẽ không bao gi

ờ th y

ấ đư c

ợ k t

ế qu

ả

được lưu l i

ạ này.

Kết qu

ả c a

ủ chư ng

ơ trình là:

2 4 6 8 10 12

Mọi vi c

ệ đ n

ế gi

ờ ti n

ế tri n

ể t t

ố . Bư c

ớ ti p

ế theo là bao b c

ọ và khái quát hóa.

7.5 Bao bọc và khái quát hóa

Bao bọc là quá trình đ t

ặ m t

ộ đo n

ạ mã l nh

ệ vào trong m t

ộ phư ng

ơ th c

ứ ; vi c

ệ này cho phép ta t n

ậ d ng

ụ

được những ưu đi m

ể c a

ủ phư ng

ơ th c

ứ . Ta đã th y

ấ hai ví d

ụ v

ề bao b c

ọ , khi ta vi t

ế printParity ở M c

ụ

4.3 và isSingleDigit ở M c

ụ 6.7.

Khái quát hóa nghĩa là ch n

ọ l y

ấ m t

ộ đi u

ề c

ụ th ,

ể nh

ư công vi c

ệ in ra các bội số c a

ủ 2, r i

ồ làm cho nó trở

thành khái quát h n,

ơ ch n

ẳ g h n

ạ nh

ư in ra các b i

ộ s

ố c a

ủ m t

ộ s

ố nguyên b t

ấ kì.

Phương th c

ứ sau đây bao b c

ọ đo n

ạ mã l nh

ệ nói trên r i

ồ khái quát hóa nó đ

ể in ra các bội số c a

ủ n.

public static void printMultiples(int n) {

int i = 1;

while (i <= 6) {

System.out.print(n*i + " ");

i = i + 1;

}

System.out.println("");

}

Để bao bọc, ta ch ỉc n

ầ vi t

ế thêm dòng th

ứ nh t

ấ , t c

ứ là khai báo tên, tham s ,

ố và ki u

ể tr

ả l i

ạ . Đ

ể khái quát

hóa, ta ch ỉc n

ầ thay th

ế giá trị 2 bởi tham số n.

Nếu ta kích ho t

ạ phư ng

ơ th c

ứ này v i

ớ đ i

ố s

ố b ng

ằ 2, ta s

ẽ nh n

ậ đư c

ợ k t

ế qu

ả gi ng

ố nh

ư trư c

ớ . V i

ớ đ i

ố

số b n

ằ g 3, k t

ế qu

ả s

ẽ là:

3 6 9 12 15 18

Với đối số b ng

ằ 4, k t

ế qu

ả là:

4 8 12 16 20 24

Bây gi

ờ có th

ể b n

ạ đã đoán đư c

ợ cách in m t

ộ b ng

ả tính nhân b ng

ằ cách kích ho t

ạ printMultiples l p

ặ

l i

ạ v i

ớ nh ng

ữ đối s

ố khác nhau. Th c

ự ra, ta có th

ể dùng m t

ộ vòng khác đ

ể l p

ặ qua các hàng trong b ng

ả :

int i = 1;

while (i <= 6) {

printMultiples(i);

i = i + 1;

}

Trư c

ớ h t

ế , hãy l u

ư ý s

ự gi ng

ố nhau c a

ủ vòng l p

ặ này v i

ớ vòng l p

ặ bên trong printMultiples. Tất cả

những gì ta đã làm ch ỉlà vi c

ệ thay l nh

ệ print b n

ằ g một l i

ờ kích ho t

ạ phư ng

ơ th c

ứ .

Kết qu

ả c a

ủ chư ng

ơ trình này là

1 2 3 4 5 6

2 4 6 8 10 12

3 6 9 12 15 18

4 8 12 16 20 24

5 10 15 20 25 30

6 12 18 24 30 36

vốn là một b ng

ả tính nhân (h i

ơ lôi thôi). N u

ế b n

ạ không thích lôi thôi, thì Java s n

ẵ có nh ng

ữ phư ng

ơ

thức giúp b n

ạ ki m

ể soát ch t

ặ ch

ẽ h i

ơ đ nh

ị d n

ạ g c a

ủ k t

ế qu ;

ả song bây gi

ờ ta không đ

ề c p

ậ đ n

ế đi u

ề này.

7.6 Phư ng t

ơ

h c v

ứ

à bao b c

ọ

Ở M c

ụ 3.5 tôi đã li t

ệ kê vài lý do mà phư ng

ơ th c

ứ tr

ở nên có ích. Sau đây còn thêm m t

ộ s

ố lý do khác:

•B ng

ằ cách đ t

ặ tên cho m t

ộ dãy các câu l nh

ệ , b n

ạ có th

ể làm cho chư ng

ơ trình mình vi t

ế tr

ở nên d

ễ đ c

ọ

và gỡ lỗi h n.

ơ

•Việc chia một chư ng

ơ trình dài thành nhi u

ề phư ng

ơ th c

ứ cho phép b n

ạ phân chia các ph n

ầ c a

ủ chư ng

ơ

trình, ti n

ế hành g

ỡ l i

ỗ chúng m t

ộ cách đ c

ộ l p,

ậ r i

ồ ghép l i

ạ thành t ng

ổ th .

ể

•Phương th c

ứ cho phép c

ả đệ quy l n

ẫ l p

ặ l i

ạ .

•Các phương thức đư c

ợ thi t

ế k

ế t t

ố thì thư ng

ờ h u

ữ ích cho nhi u

ề chư ng

ơ trình khác nhau. M t

ộ khi đã

viết ra và gỡ lỗi xong m t

ộ phư ng

ơ th c

ứ , b n

ạ có th

ể tái s

ử d ng

ụ nó.

Để bi u

ể di n

ễ ti p

ế kĩ thu t

ậ bao b c

ọ , ta hãy l y

ấ đo n

ạ mã l nh

ệ

ở cu i

ố m c

ụ trư c

ớ r i

ồ b c

ọ nó vào trong m t

ộ

phương th c

ứ :

public static void printMultTable() {

int i = 1;

while (i <= 6) {

printMultiples(i); i = i + 1;

}

}

Quá trình mà tôi hi n

ệ đang gi i

ớ thi u

ệ đư c

ợ g i

ọ là bao b c

ọ và khái quát hóa. Ta phát tri n

ể mã l nh

ệ

b n

ằ g cách vi t

ế riêng nh ng

ữ dòng l nh

ệ vào main ho c

ặ vào phương th c

ứ khác. Khi mã l nh

ệ này th c

ự hi n

ệ

được, ta l y

ấ l i

ạ nó r i

ồ b c

ọ vào m t

ộ phư ng

ơ th c

ứ . R i

ồ b n

ạ khái quát hóa phư ng

ơ th c

ứ b n

ằ g cách b

ổ sung

các tham s .

ố

Lúc m i

ớ l p

ậ trình, đôi khi b n

ạ không bi t

ế cách chia chư ng

ơ trình thành các phư ng

ơ th c

ứ . Quy trình trên

giúp b n

ạ thi t

ế kế trong khi l p

ậ trình.

7.7 Các bi n đ

ế

a p

ị

hương

Có th

ể b n

ạ t

ự h i

ỏ b ng

ằ cách nào mà ta dùng đư c

ợ cùng m t

ộ bi n,

ế i, cả

trong printMultiples l n

ẫ printMultTable. Ch n

ẳ g ph i

ả nó s

ẽ gây r c

ắ r i

ố khi m t

ộ trong hai phư ng

ơ th c

ứ

thay đổi giá tr ịc a

ủ bi n

ế sao?

Lời gi i

ả đáp cho c

ả hai câu h i

ỏ trên đ u

ề là không,

vì i trong printMultiples và i trong printMultTable không ph i ả cùng một bi n.

ế Chúng có cùng tên g i

ọ ,

nhưng không tham chi u

ế đ n

ế cùng v ịtrí l u

ư tr ,

ữ và vi c

ệ thay đ i

ổ m t

ộ bi n

ế này s

ẽ không nh

ả hư ng

ở gì

tới bi n

ế kia.

Những bi n

ế đư c

ợ t o

ạ ra bên trong ph n

ầ đ nh

ị nghĩa phư ng

ơ th c

ứ đư c

ợ g i

ọ là biến đ a

ị phương, vì

chúng ch ỉt n

ồ t i

ạ bên trong phư ng

ơ th c

ứ đó. B n

ạ không th

ể truy c p

ậ bi n

ế đ a

ị phư ng

ơ t

ừ ngoài phư ng

ơ

thức “ch ”

ủ c a

ủ nó, và b n

ạ có th

ể tùy ý đ t

ặ nhi u

ề bi n

ế cùng tên, mi n

ễ là chúng không ph i

ả trong cùng

một hàm.

M c

ặ dù đi u

ề này có thể gây nh m

ầ l n,

ẫ song có nh ng

ữ lí do thích đáng đ

ể s

ử d ng

ụ l i

ạ các tên g i

ọ . Ch n

ẳ g

h n

ạ , các tên i, j và k thường đư c

ợ dùng làm bi n

ế l p.

ặ N u

ế b n

ạ tránh dùng chúng trong m t

ộ phư ng

ơ th c

ứ

ch ỉvì b n

ạ đã dùng chúng

ở n i

ơ khác, thì chư ng

ơ trình vi t

ế ra s

ẽ khó đ c

ọ h n.

ơ

7.8 Nói thêm v k

ề hái quát hóa

Xét một ví dụ khác v

ề khái quát hóa. Hãy hình dung r n

ằ g b n

ạ muốn có một chương trình đ

ể in ra b ng

ả

tính nhân v i

ớ kích thư c

ớ b t

ấ kì, ch

ứ không ch ỉ6 × 6. B n

ạ có thể thêm một tham s

ố vào printMultTable:

public static void printMultTable(int high) {

int i = 1;

while (i <= high) {

printMultiples(i);

i = i + 1;

}

}

Tôi đã thay giá tr ị6 b i

ở tham số high. Nếu tôi kích ho t

ạ printMultTable v i

ớ đ i

ố số 7, tôi s

ẽ đư c

ợ :

1 2 3 4 5 6

2 4 6 8 10 12

3 6 9 12 15 18

4 8 12 16 20 24

5 10 15 20 25 30

6 12 18 24 30 36

7 14 21 28 35 42

Th

ế này t m

ạ đư c

ợ , nh ng

ư có l

ẽ ta mu n

ố nh n

ậ đư c

ợ m t

ộ b ng

ả hình vuông h n

ơ (số cột và số hàng ph i

ả

b n

ằ g nhau). Đ

ể làm đi u

ề này, ta thêm m t

ộ tham s

ố n a

ữ vào printMultiples để c

ụ thể hóa xem b ng

ả có

bao nhiêu c t

ộ .

Ta g i

ọ tham s

ố này là high, nhằm cho th y

ấ các phư ng

ơ th c

ứ khác nhau hoàn toàn có th

ể ch a

ứ nh ng

ữ

tham bi n

ế có cùng tên (cũng nh

ư các bi n

ế đ a

ị phư ng

ơ ):

public static void printMultiples(int n, int high) {

int i = 1;

while (i <= high) {

System.out.print(n*i + " ");

i = i + 1;

}

System.out.println("");

}

public static void printMultTable(int high) {

int i = 1;

while (i <= high) {

printMultiples(i, high);

i = i + 1;

}

}

Lưu ý r n

ằ g khi thêm m t

ộ tham s

ố m i

ớ , ta ph i

ả s a

ử l i

ạ dòng đ u

ầ tiên, đ ng

ồ th i

ờ ta cũng ph i

ả s a

ử ch

ỗ

phương th c

ứ đư c

ợ kích ho t

ạ trong printMultTable. Đúng nh

ư d

ự ki n,

ế chư ng

ơ trình này phát sinh ra

b n

ả g vuông 7 × 7:

1 2 3 4 5 6 7

2 4 6 8 10 12 14

3 6 9 12 15 18 21

4 8 12 16 20 24 28

5 10 15 20 25 30 35

6 12 18 24 30 36 42

7 14 21 28 35 42 49

Khi b n

ạ khái quát quá m t

ộ phư ng

ơ th c

ứ theo cách thích h p,

ợ thư ng

ờ b n

ạ s

ẽ thu đư c

ợ chư ng

ơ trình v i

ớ

những tính năng mà b n

ạ ch a

ư lư ng

ờ trư c

ớ . Ch ng

ẳ h n

ạ , có th

ể b n

ạ nh n

ậ th y

ấ r ng

ằ b ng

ả nhân có tính đ i

ố

xứng, vì ab = ba, nên t t

ấ c

ả nh ng

ữ con s

ố trong b ng

ả đ u

ề xu t

ấ hi n

ệ l p

ặ hai l n

ầ . L

ẽ ra b n

ạ có th

ể ti t

ế

kiệm mực b n

ằ g cách ch ỉ in ra n a

ử b ng

ả thôi. Đ

ể làm đi u

ề này, ch ỉc n

ầ thay đ i

ổ m t

ộ dòng l nh

ệ

trong printMultTable. Hãy s a

ử l nh

ệ

printMultiples(i, high);

thành

printMultiples(i, i);

và thu đư c

ợ

1

2 4

3 6 9

4 8 12 16

5 10 15 20 25

6 12 18 24 30 36

7 14 21 28 35 42 49

Tôi s

ẽ đ

ể b n

ạ t

ự hình dung c

ơ ch

ế c a

ủ cách máy tính đã x

ử lí trong trư ng

ờ h p

ợ này.

7.9 Thu t

ậ ngữ

vòng l p:

ặ

Một câu l nh

ệ

đư c

ợ l p

ặ đi l p

ặ l i

ạ nhiều l n

ầ khi m t

ộ đi u

ề ki n

ệ nào đó đư c

ợ th a

ỏ mãn.

vòng l p

ặ vô h n

ạ :

Một vòng l p

ặ có điều ki n

ệ luôn luôn đúng.

ph n

ầ thân:

Nh ng

ữ câu l nh

ệ

bên trong vòng l p

ặ .

lặp:

Một lượt chạy (th c

ự thi) qua ph n

ầ thân vòng l p

ặ , bao g m

ồ c

ả vi c

ệ đ nh

ị giá đi u

ề ki n.

ệ

bao b c

ọ :

Vi c

ệ phân chia một ch ng

ươ trình l n,

ớ ph c

ứ t p

ạ thành nhi u

ề thành ph n

ầ (nh

ư ph ng

ươ th c

ứ ) r i

ồ cô l p

ậ

riêng các thành ph n

ầ (ch ng

ẳ h n,

ạ b ng

ằ cách dùng các bi n

ế đ a

ị ph ng

ươ ).

bi n

ế đ a

ị ph n

ươ g:

Một bi n

ế đư c

ợ khai báo bên trong m t

ộ ph ng

ươ th c

ứ ; bi n

ế này ch ỉt n

ồ t i

ạ trong ph ng

ươ th c

ứ đó. Nh ng

ữ

bi n

ế đ a

ị ph ng

ươ đ u

ề không truy c p

ậ đư c

ợ t

ừ ngoài ph ng

ươ th c

ứ c a

ủ nó, và không can thi p

ệ t i

ớ b t

ấ kì

ph ng

ươ th c

ứ nào khác.

khái quát hóa:

Vi c

ệ thay thế nh ng

ữ th

ứ c

ụ thể m t

ộ cách không c n

ầ thi t

ế (nh

ư m t

ộ giá tr ịkhông đ i

ổ ) b ng

ằ nh ng

ữ th

ứ

có tính khái quát thích h p

ợ (nh ng

ư m t

ộ bi n

ế ho c

ặ m t

ộ tham s )

ố . Vi c

ệ khái quát hóa khi n

ế cho mã l nh

ệ

linh ho t

ạ h n,

ơ dễ s

ử d ng

ụ l i

ạ h n

ơ , và đôi khi d

ễ vi t

ế h n

ơ .

phát tri n

ể ch n

ươ g trình:

M t

ộ quá trình đ

ể vi t

ế nên nh ng

ữ ch ng

ươ trình máy tính. Cho đ n

ế bây gi

ờ ta đã g p

ặ “phát tri n

ể

tăng d n”

ầ và “bao b c

ọ và khái quát hóa”.

7.10 Bài t p

ậ

Bài t p

ậ 1 Xét đo n

ạ mã l nh

ệ sau:

public static void main(String[] args) {

loop(10);

}

public static void loop(int n) {

int i = n;

while (i > 0) {

System.out.println(i);

if (i%2 == 0) {

i = i/2;

} else {

i = i+1;

}

}

}

1. Hãy k

ẻ một b ng

ả đ

ể ch ỉra giá tr ịc a

ủ các bi n

ế i và n trong quá trình th c

ự thi loop. B n

ả g chỉ đư c

ợ phép

chứa một cột cho m i

ỗ bi n

ế và m t

ộ hàng cho m i

ỗ vòng l p.

ặ

2. Kết qu

ả c a

ủ chư ng

ơ trình này là gì?

Bài t p

ậ 2 Giả sử b n

ạ có một số, a, và b n

ạ muốn tính căn b c

ậ hai c a

ủ nó. M t

ộ cách làm đi u

ề này là kh i

ở

đ u

ầ b ng

ằ một phỏng đoán s

ơ lư c

ợ v

ề đáp s ,

ố x0, và rồi c i

ả thi n

ệ ph ng

ỏ đoán này theo công th c

ứ sau:

x1 =(x0 + a/x0) / 2

Ch ng

ẳ h n,

ạ n u

ế ta mu n

ố tìm căn b c

ậ hai c a

ủ 9, và b t

ắ đ u

ầ v i

ớ x0 = 6, thì x1 =(6 + 9/6) /2 = 15/4 = 3.75,

giá tr ịnày đã sát h n.

ơ Ta có thể l p

ặ l i

ạ quy trình này, dùng x1 để tính ra x2, và cứ nh

ư v y

ậ . Trong trư ng

ờ

hợp này, x2 = 3.075 và x3 = 3.00091. Nh

ư v y

ậ nó h i

ộ t

ụ r t

ấ nhanh v

ề đáp s

ố đúng (v n

ố b ng

ằ 3).

Hãy vi t

ế một phư ng

ơ th c

ứ có tên squareRoot nh n

ậ vào tham s

ố là m t

ộ double và trả l i

ạ một giá tr ịx p

ấ

xỉ cho căn b c

ậ hai c a

ủ tham s

ố đó, theo kĩ thu t

ậ tính nêu trên. B n

ạ không đư c

ợ phép dùng Math.sqrt.

Với giá tr ịban đ u

ầ , b n

ạ nên l y

ấ a/2. Phương th c

ứ b n

ạ vi t

ế c n

ầ ph i

ả l p

ặ l i

ạ đ n

ế khi nó đ t

ạ đư c

ợ hai giá

trị ư c

ớ tính liên ti p

ế ch ỉsai khác nhau ch a

ư đ n

ế 0.0001; nói cách khác, là đ n

ế khi giá tr ịtuy t

ệ đ i

ố

c a

ủ xn − xn−1 nhỏ hơn 0.0001. B n

ạ có th

ể dùng Math.abs để tính giá trị tuy t

ệ đ i

ố này.

Bài t p

ậ 3

Ở Bài t p

ậ 9 ta đã vi t

ế một d n

ạ g đệ quy c a

ủ power, trong đó nh n

ậ m t

ộ bi n

ế double có

tên x cùng một bi n

ế nguyên n and rồi trả l i

ạ xn. Bây gi

ờ hãy vi t

ế m t

ộ phư ng

ơ th c

ứ l p

ặ đ

ể th c

ự hi n

ệ tính

toán nh

ư v y

ậ .

Bài t p

ậ 4 M c

ụ 6.8 có trình bày m t

ộ phư ng

ơ th c

ứ đ

ệ quy đ

ể tính hàm giai th a

ừ . Hãy vi t

ế m t

ộ d ng

ạ

tính l p

ặ cho factorial.

Bài t p

ậ 5 Một cách đ

ể tính ex là dùng khai tri n

ể chu i

ỗ vô h n

ạ

ex = 1 + x + x2 / 2! + x3 / 3! + x4 / 4! + …

Nếu bi n

ế vòng l p

ặ có tên i, thì số h n

ạ g thứ i s

ẽ là xi / i!.

1. Hãy vi t

ế một phư ng

ơ th c

ứ có tên myexp để tính tổng c a

ủ n số h n

ạ g đ u

ầ tiên trong dãy này. B n

ạ có th

ể

dùng phư ng

ơ th c

ứ factorial ở M c

ụ 6.8 ho c ặ dùng phiên b n

ả tính l p

ặ nh

ư

ở bài t p

ậ trư c

ớ .

2. B n

ạ có thể khi n

ế phư ng

ơ th c

ứ này hi u

ệ qu

ả h n

ơ nhi u

ề n u

ế nh n

ậ th y

ấ r ng

ằ

ở m i

ỗ l n

ầ l p,

ặ t

ử s

ố c a

ủ s

ố

h n

ạ g thì đúng b ng

ằ t

ử số c a

ủ s

ố h ng

ạ li n

ề trư c

ớ đó nhân v i

ớ x còn m u

ẫ số thì đúng b ng

ằ m u

ẫ c a

ủ s

ố

h n

ạ g trước đó nhân v i

ớ i. Hãy t n

ậ d n

ụ g k t

ế qu

ả c a

ủ quan sát này đ

ể tránh dùng

cả Math.pow l n

ẫ factorial, rồi ki m

ể tra r n

ằ g b n

ạ v n

ẫ có th

ể đ t

ạ đư c

ợ k t

ế qu

ả y h t

ệ .

3. Hãy vi t

ế một phư ng

ơ th c

ứ có tên check nh n

ậ vào một tham s ,

ố x, đ

ể in ra giá tr ị

c a

ủ x, Math.exp(x) và myexp(x) cho các giá trị x khác nhau. K t ế qu

ả ph i

ả có d n

ạ g nh

ư sau:

1.0 2.708333333333333 2.718281828459045

G I

Ợ Ý: b n

ạ có th

ể dùng String "\t" để in ra một d u

ấ tab gi a

ữ các c t

ộ trong b ng

ả .

4. Hãy thay đ i

ổ s

ố các s

ố h ng

ạ trong chu i

ỗ (chính là đ i

ố s

ố th

ứ hai mà check gửi đ n

ế myexp) rồi xem s

ự

nh

ả hưởng đ n

ế độ chính xác c a

ủ k t

ế qu .

ả Đi u

ề ch nh

ỉ giá tr ịnày đ n

ế khi giá tr ịư c

ớ tính phù h p

ợ v i

ớ đáp

số “đúng” khi x b n

ằ g 1.

5. Hãy vi t

ế một vòng l p

ặ trong main để kích ho t

ạ check với nh ng

ữ giá tr ị0.1, 1.0, 10.0, và 100.0. Đ

ộ chính

xác c a

ủ k t

ế quả s

ẽ thay đ i

ổ th

ế nào khi x bi n

ế đổi? So sánh s

ố ch

ữ s

ố gi ng

ố nhau thay vief hi u

ệ s

ố gi a

ữ

các giá tr ịđúng và giá tr ịư c

ớ tính đư c

ợ .

6. Thêm vào một vòng l p

ặ trong main nhằm ki m

ể tra myexp v i

ớ các giá tr ị-0.1, -1.0, -10.0, và -100.0. Hãy

nh n

ậ xét về độ chính xác.

Bài t p

ậ 6 Một cách đ

ể tính exp(−x2) là dùng khai tri n

ể chu i

ỗ vô h n

ạ

exp(−x2) = 1 − x2 + x4/2 − x6/6 + …

Nói cách khác, ta c n

ầ ph i

ả c ng

ộ các s

ố h n

ạ g l i

ạ , trong đó s

ố h n

ạ g th

ứ i b ng

ằ (−1)i x2i /i!. Hãy vi t

ế m t

ộ

phương th c

ứ có tên gauss nh n

ậ vào các đ i

ố số x và n rồi tr

ả l i

ạ tổng c a

ủ n số h ng

ạ đ u

ầ tiên trong chu i

ỗ

này. B n

ạ không đư c

ợ dùng cả factorial l n

ẫ pow.

Ch

ng

ươ 8: Chu i

ỗ kí tự

8.1 Kí tự

Trong Java cũng nh

ư các ngôn ng

ữ hư ng

ớ đ i

ố tư ng

ợ khác thì đ i

ố t n

ượ g là t p

ậ hợp nh ng

ữ d

ữ li u

ệ có

liên quan, cùng v i

ớ m t

ộ t p

ậ các phư ng

ơ th c

ứ . Nh ng

ữ phư ng

ơ th c

ứ nafyhoajt đ ng

ộ trên đ i

ố tư ng

ợ k

ể

trên, th c

ự hi n

ệ tính toán và đôi lúc thay đ i

ổ d

ữ li u

ệ trong đ i

ố tư ng

ợ đó.

String (chuỗi kí t )

ự là các đ i

ố tư ng

ợ , b i

ở v y

ậ b n

ạ có th

ể h i

ỏ “Có d

ữ li u

ệ nào đư c

ợ ch a

ứ trong m t

ộ đ i

ố

tượng String?” và “Có nh ng

ữ phư ng

ơ th c

ứ nào mà ta có th

ể kích ho t

ạ đư c

ợ t

ừ đ i

ố tư ng

ợ String?” Những

thành ph n

ầ trong m t

ộ đ i

ố tư ng

ợ String là các ch

ữ cái, hay t ng

ổ quát h n,

ơ là nh ng

ữ kí t .

ự Không ph i

ả

mọi kí t

ự đ u

ề là ch

ữ cái; còn nh ng

ữ kí t

ự là ch

ữ s ,

ố kí hi u

ệ , và các th

ứ khác. Đ

ể đ n

ơ gi n

ả tôi s

ẽ g i

ọ chúng

đều là các ch

ữ cái. Có nhi u

ề phư ng

ơ th c

ứ khác nhau, nh ng

ư trong sách này ch ỉdùng m t

ộ s

ố ít. Các

phương th c

ứ còn l i

ạ đư c

ợ chỉ d n

ẫ

ởhttp://download.oracle.com/javase/6/docs/api/java/lang/String.html.

Phương th c

ứ đ u

ầ tiên mà ta xét đ n

ế là charAt; phương thức này cho phép b n

ạ k t

ế xu t

ấ nh ng

ữ ch

ữ cái t

ừ

một String. char là ki u

ể bi n

ế dùng đư c

ợ đ

ể l u

ư tr

ữ t ng

ừ kí t

ự riêng l

ẻ (trái ngư c

ợ l i

ạ v i

ớ m t

ộ chu i

ỗ các

kí t )

ự .

char cũng ho t

ạ đ ng

ộ nh

ư các ki u

ể d

ữ li u

ệ khác ta đã g p:

ặ

char ltr = 'c';

if (ltr == 'c') {

System.out.println(ltr);

}

Những giá tr ịc a

ủ kí t

ự đ u

ề xu t

ấ hi n

ệ trong c p

ặ d u

ấ nháy đ n,

ơ như ’c’. Khác v i

ớ giá tr ịc a

ủ chu i

ỗ (xu t

ấ

hiện giữa c p

ặ dấu nháy kép), các giá tr ịkí t

ự ch ỉcó th

ể ch a

ứ m t

ộ ch

ữ cái ho c

ặ m t

ộ kí hi u

ệ .

Sau đây là cách dùng phư ng

ơ th c

ứ charAt:

String fruit = "banana";

char letter = fruit.charAt(1);

System.out.println(letter);

fruit.charAt() có nghĩa r ng

ằ tôi đang kích ho t

ạ phư ng

ơ th c

ứ charAt lên đối tượng có tên fruit. Tôi đang

truy n

ề đ i

ố số 1 vào phư ng

ơ th c

ứ này, t c

ứ là tôi đang mu n

ố bi t

ế ch

ữ cái đ u

ầ tiên c a

ủ chu i

ỗ là gì. K t

ế qu

ả

là một kí t ,

ự và đư c

ợ l u

ư vào trong m t

ộ char có tên letter. Khi tôi in ra giá tr ịc a

ủ letter, tôi b ịb t

ấ ng :

ờ

a

a không ph i

ả là ch

ữ cái đ u

ầ tiên c a

ủ "banana". Trừ khi b n

ạ nghiên c u

ứ khoa h c

ọ máy tính. Vì nh ng

ữ lí

do kĩ thu t

ậ mà gi i

ớ khoa h c

ọ máy tính đ u

ề đ m

ế t

ừ s

ố không. Ch

ữ cái th

ứ 0 c a

ủ "banana" là chữ b. Chữ

cái th

ứ 1 là a và thứ 2 là n.

Nếu b n

ạ muốn bi t

ế ch

ữ cái thứ 0 c a

ủ m t

ộ chu i

ỗ , b n

ạ ph i

ả truy n

ề tham s

ố là 0:

char letter = fruit.charAt(0);

8.2 Length

Phương th c

ứ ti p

ế theo đối v i

ớ String mà ta xét đ n

ế là length, vốn tr

ả l i

ạ số kí t

ự có trong chu i

ỗ . Ch ng

ẳ

h n:

ạ

int length = fruit.length();

length không nh n

ậ đ i

ố s

ố truy n

ề vào, và tr

ả l i

ạ m t

ộ s

ố nguyên, trong trư ng

ờ h p

ợ này b ng

ằ 6. L u

ư ý r ng

ằ

việc có một bi n

ế trùng tên v i

ớ phư ng

ơ th c

ứ là hoàn toàn h p

ợ l

ệ (m c

ặ dù đi u

ề này có th

ể gây nh m

ầ l n

ẫ

đối với ngư i

ờ đọc mã l nh

ệ ).

Để tìm ch

ữ cái cu i

ố cùng trong chu i

ỗ , b n

ạ có th

ể b ịxui khi n

ế đ

ể th

ử theo cách làm sau:

int length = fruit.length();

char last = fruit.charAt(length); // SAI!!

Cách này không có tác d n

ụ g. Lý do là không có ch

ữ cái th

ứ 6 nào trong "banana". Vì ta đã b t

ắ đ u

ầ đ m

ế

từ 0, nên sáu ch

ữ cái trong chu i

ỗ đư c

ợ đ m

ế t

ừ 0 t i

ớ 5. Đ

ể l y

ấ ch

ữ cái cu i

ố cùng, ta ph i

ả trừ length đi

một.

int length = fruit.length();

char last = fruit.charAt(length-1);

8.3 Duy t

ệ chu i

ỗ

Một công vi c

ệ thư ng

ờ làm v i

ớ m t

ộ chu i

ỗ là b t

ắ đ u

ầ t

ừ đi m

ể đ u

ầ c a

ủ chu i

ỗ , l n

ầ lư t

ợ ch n

ọ t ng

ừ kí t ,

ự

thực hi n

ệ một số thao tác đ i

ố v i

ớ ch

ữ cái đó, và công vi c

ệ đư c

ợ ti p

ế di n

ễ cho các ch

ữ cái còn l i

ạ đ n

ế h t

ế

chuỗi. Ki u

ể x

ử lý nh

ư th

ế này đư c

ợ g i

ọ là duyệt. Một cách t

ự nhiên để th c

ự hi n

ệ vi c

ệ duy t

ệ là dùng

vòng l p

ặ while:

int index = 0;

while (index < fruit.length()) {

char letter = fruit.charAt(index);

System.out.println(letter);

index = index + 1;

}

Vòng l p

ặ này để duy t

ệ chu i

ỗ và hi n

ể th ịt ng

ừ ch

ữ cái trên m t

ộ dòng riêng. L u

ư ý đi u

ề ki n

ệ l p

ặ là index

< fruit.length(), nghĩa là khi index b n

ằ g với chi u

ề dài c a

ủ chu i

ỗ , thì đi u

ề ki n

ệ b ịvi ph m

ạ , và ph n

ầ

thân c a

ủ vòng l p

ặ không đư c

ợ th c

ự hi n.

ệ Kí t

ự cu i

ố cùng đư c

ợ truy c p

ậ đ n

ế s

ẽ tư ng

ơ ng

ứ v i

ớ ch ỉ

số fruit.length()-1.

Tên c a

ủ bi n

ế vòng l p

ặ là index (có nghĩa là “ch ỉs ”)

ố . M t

ộ ch ỉsố là một bi n

ế hay giá tr ịđư c

ợ dùng để chỉ

đ nh

ị một thành viên c a

ủ m t

ộ t p

ậ h p

ợ đư c

ợ x p

ế th

ứ t ,

ự trong trư ng

ờ h p

ợ này là chu i

ỗ các kí t .

ự Ch ỉs

ố có

nhiệm v

ụ ch ỉđ nh

ị thành viên nào b n

ạ c n

ầ bi t

ế (vì v y

ậ mà nó có tên “ch ỉs ”)

ố .

8.4 Lỗi th c t

ự hi

Trở về M c

ụ 1.3.2 tôi đã nói t i

ớ các l i

ỗ th c

ự thi, nh ng

ữ l i

ỗ không xu t

ấ hi n

ệ đ n

ế t n

ậ khi chư ng

ơ trình b t

ắ

đ u

ầ ch n.

ạ Trong Java, nh ng

ữ l i

ỗ th c

ự thi đư c

ợ g i

ọ là các biệt lệ.

Có th

ể b n

ạ không th y

ấ nhi u

ề l i

ỗ th c

ự thi, song vì ta ch a

ư th c

ự hi n

ệ nhi u

ề thao tác có kh

ả năng gây nên

những l i

ỗ lo i

ạ này. Và bây gi

ờ ta s

ẽ gây l i

ỗ . N u

ế b n

ạ dùng phư ng

ơ th c

ứ charAt rồi cung c p

ấ m t

ộ ch ỉs

ố

là số âm ho c

ặ l n

ớ h n

ơ length-1, Java sẽ phát ra một bi t

ệ lệ. B n

ạ có th

ể hình dung vi c

ệ “phát” bi t

ệ l

ệ

cũng nh

ư phát ra m t

ộ c n

ơ gi n

ậ d .

ữ

Khi đi u

ề này x y

ả đ n

ế , Java in ra m t

ộ thông báo l i

ỗ có ghi ki u

ể bi t

ệ l

ệ và m t

ộ l n

ầ v t

ế ngăn x p

ế , trong

đó có bi u

ể th ịnh ng

ữ phư ng

ơ th c

ứ đang ho t

ạ đ ng

ộ khi có bi t

ệ l

ệ x y

ả ra. Sau đây là m t

ộ ví d :

ụ

public class BadString {

public static void main(String[] args) {

processWord("banana");

}

public static void processWord(String s) {

char c = getLastLetter(s);

System.out.println(c);

}

public static char getLastLetter(String s) {

int index = s.length(); // SAI!

char c = s.charAt(index);

return c;

}

}

Lưu ý r n

ằ g lỗi n m

ằ trong getLastLetter: ch ỉsố c a

ủ kí t

ự cu i

ố cùng đáng ra ph i

ả là s.length()-1. Sau đây là

kết quả b n

ạ thu đư c

ợ :

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 6

at java.lang.String.charAt(String.java:694)

at BadString.getLastLetter(BadString.java:24)

at BadString.processWord(BadString.java:18)

at BadString.main(BadString.java:14)

Sau đó chư ng

ơ trình k t

ế thúc. L n

ầ v t

ế ngăn x p

ế này có th

ể khó đ c

ọ , song nó ch a

ứ đ ng

ự r t

ấ nhi u

ề thông

tin.

8.5 Đ c t

ọ ài li u

ệ

Nếu b n

ạ truy c p

ậ đ n

ế http://download.oracle.com/javase/6/docs/api/java/lang/String.html và kích chuột vào charAt, b n

ạ s

ẽ xem đư c

ợ tài li u

ệ sau đây (ho c

ặ v i

ớ n i

ộ dung tư ng

ơ t )

ự :

public char charAt(int index)

Returns the char value at the specified index. An index ranges from 0 to length() - 1. The first char value of the sequence is at index 0, the next at index 1, and so on, as for array indexing.

Parameters: index - the index of the char value.

Returns: the char value at the specified index of this string.

The first char value is at index 0.

Throws: IndexOutOfBoundsException - if the index argument is

negative or not less than the length of this string.

Dòng đ u

ầ tiên là nguyên m u

ẫ c a

ủ phương th c

ứ , có nhi m

ệ v

ụ quy đ nh

ị tên c a

ủ phư ng

ơ th c

ứ , ki u

ể d

ữ

liệu c a

ủ các tham s

ố cũng nh

ư ki u

ể tr

ả l i

ạ .

Dòng ti p

ế theo miêu t

ả nh ng

ữ công vi c

ệ mà phư ng

ơ th c

ứ th c

ự hi n.

ệ Các dòng sau đó gi i

ả thích các tham

số và giá tr ịtr

ả l i

ạ . Trong trư ng

ờ h p

ợ này, vi c

ệ gi i

ả thích là quá th a

ừ , nh ng

ư tài li u

ệ luôn đư c

ợ thi t

ế k

ế

để phù hợp một d ng

ạ mẫu tiêu chu n

ẩ . Còn dòng cu i

ố cùng mô t

ả các bi t

ệ l

ệ mà phư ng

ơ th c

ứ này có th

ể

phát ra.

Có l

ẽ b n

ạ s

ẽ m t

ấ chút th i

ờ gian đ

ể làm quen v i

ớ ki u

ể tài li u

ệ th

ế này, nh ng

ư th i

ờ gian công s c

ứ b

ỏ ra

cũng đáng.

8.6 Phương thức indexOf

indexOf là phép ngh c

ị h đ o

ả c a

ủ charAt: charAt nh n

ậ vào một ch ỉs

ố r i

ồ tr

ả l i

ạ kí t

ự

ở v ịtrí ch ỉs

ố

đó; indexOf nh n

ậ một kí t

ự rồi tìm ch ỉs

ố mà kí t

ự đó xu t

ấ hi n.

ệ

charAt th t

ấ b i

ạ n u

ế chỉ số nằm ngoài ph m

ạ vi chu i

ỗ , khi đó phư ng

ơ th c

ứ này s

ẽ phát bi t

ệ

lệ. indexOf th t

ấ b i

ạ n u

ế kí t

ự không có m t

ặ trong chu i

ỗ , và tr

ả l i

ạ giá trị -1.

String fruit = "banana";

int index = fruit.indexOf('a');

Đo n

ạ mã l nh

ệ này tìm ch ỉs

ố c a

ủ ch

ữ cái ’a’ trong chuỗi. V i

ớ trư ng

ờ h p

ợ này, ch

ữ cái nêu trên xu t

ấ hi n

ệ

ba l n

ầ , nên ta ch a

ư th y

ấ ngay r ng

ằ indexOf nên làm gì. Nh ng

ư theo tài li u

ệ , thì phư ng

ơ th c

ứ này s

ẽ tr

ả

l i

ạ ch ỉsố c a

ủ l n

ầ xu t

ấ hi n

ệ đầu tiên.

Để tìm các l n

ầ xu t

ấ hi n

ệ ti p

ế theo, còn có m t

ộ d ng

ạ khác c a

ủ indexOf. Nó nh n

ậ vào m t

ộ đ i

ố s

ố thứ hai

quy đ nh

ị xem c n

ầ b t

ắ đ u

ầ tìm ki m

ế t

ừ v ịtrí nào trong chu i

ỗ . Đây là m t

ộ d n

ạ g quá t i

ả toán t ,

ử đ

ể bi t

ế

thêm chi ti t

ế , b n

ạ hãy xem M c

ụ 6.4.

Nếu ta kích ho t

ạ :

int index = fruit.indexOf('a', 2);

nó s

ẽ b t

ắ đ u

ầ

ở ch

ữ cái s

ố hai (chữ n đ u

ầ tiên) r i

ồ tìm chữ a thứ hai, vốn có ch ỉs

ố là 3. N u

ế tình c

ờ ch

ữ

cái đó xu t

ấ hi n

ệ ngay

ở ch ỉs

ố kh i

ở đ u

ầ , thì câu tr

ả l i

ờ chính là ch ỉs

ố đ u

ầ này. B i

ở v y

ậ

int index = fruit.indexOf('a', 5);

sẽ trả l i

ạ 5.

8.7 L p q

ặ

uay vòng và đ m

ế

Chương trình dưới đây đ m

ế s

ố l n

ầ xu t

ấ hi n

ệ c a

ủ chữ ’a’ trong một chuỗi:

String fruit = "banana";

int length = fruit.length();

int count = 0;

int index = 0;

while (index < length) {

if (fruit.charAt(index) == 'a') {

count = count + 1;

}

index = index + 1;

}

System.out.println(count);

Chương trình này cho th y

ấ m t

ộ cách vi t

ế quen tay thông d ng

ụ , đó là m t

ộ biến đ m

ế . Bi n

ế count đư c

ợ

khởi t o

ạ b ng

ằ không và sau đó tăng thêm m t

ộ ng

ứ v i

ớ m i

ỗ l n

ầ ta tìm th y

ấ m t

ộ chữ ’a’. Việc tăng ở đây

là chỉ tăng thêm một đ n

ơ v ;ị nó ngư c

ợ l i

ạ v i

ớ thao tác gi m

ả . Khi ta thoát kh i

ỏ vòng l p,

ặ count sẽ chứa

kết qu ,

ả đó là t ng

ổ s

ố các ch

ữ a.

8.8 Các toán tử tăng và gi m

ả

Tăng và gi m

ả là nh ng

ữ thao tác thông d n

ụ g đ n

ế n i

ỗ Java có nh ng

ữ toán t

ử riêng cho chúng. Toán tử +

+ c ng

ộ thêm một vào giá tr ịhi n

ệ th i

ờ c a

ủ m t

ộ int hay char. -- thì trừ đi một. Hai toán t

ử trên đ u

ề không

có tác d n

ụ g đ i

ố v i

ớ double, boolean hay String.

Về khía c nh

ạ kĩ thu t

ậ , s

ẽ hoàn toàn h p

ợ l

ệ n u

ế ta tăng m t

ộ bi n

ế r i

ồ đ ng

ồ th i

ờ s

ử d n

ụ g nó trong m t

ộ

bi u

ể th c

ứ . Ch n

ẳ g h n,

ạ b n

ạ có th

ể th y

ấ l nh

ệ ki u

ể nh

ư sau:

System.out.println(i++);

Nhìn vào câu l nh

ệ này, th t

ậ không rõ là li u

ệ vi c

ệ tăng s

ẽ ti n

ế hành trư c

ớ hay sau khi giá tr ịđư c

ợ in ra.

B i

ở vì nh ng

ữ bi u

ể th c

ứ th

ế này có xu hư ng

ớ gây nh m

ầ l n,

ẫ tôi khuyên b n

ạ nên h n

ạ ch

ế s

ử d ng

ụ chúng.

Thậm chí, đ

ể h n

ạ ch

ế h n

ơ n a

ữ , tôi s

ẽ không nói cho b n

ạ bi t

ế k t

ế qu

ả b ng

ằ bao nhiêu. N u

ế th c

ự s

ự

muốn bi t

ế , b n

ạ có th

ể th

ử xem.

B ng

ằ cách dùng toán t

ử tăng, ta có th

ể vi t

ế l i

ạ mã l nh

ệ đ m

ế ch :

ữ \

int index = 0;

while (index < length) {

if (fruit.charAt(index) == 'a') {

count++;

}

index++;

}

Một lỗi sai thư ng

ờ g p

ặ là vi t

ế l nh

ệ ki u

ể nh

ư sau:

index = index++; // SAI!!

Tuy nhiên, cách này l i

ạ h p

ợ l

ệ v

ề m t

ặ cú pháp, nên trình biên d c

ị h s

ẽ không c nh

ả báo b n.

ạ Hi u

ệ ng

ứ c a

ủ

lệnh này là gi

ữ nguyên giá tr ịc a

ủ index. Đây thư ng

ờ là một lỗi khó tìm ra.

Hãy nh ,

ớ b n

ạ có thể vi t

ế index = index+1, hay index++, nhưng đ ng

ừ trộn l n

ẫ hai cách vi t

ế này.

8.9 String có tính không đ i

ổ

Như đã đọc tài li u

ệ v

ề các phư ng

ơ th c

ứ c a

ủ String, có th

ể b n

ạ phát hi n

ệ ra hai phư ng

ơ

thức toUpperCase và toLowerCase. Hai phư ng

ơ th c

ứ này thư ng

ờ gây nh m

ầ l n,

ẫ vì chúng có tên g i

ọ nghe

như thể chúng có tác d n

ụ g thay đ i

ổ chu i

ỗ hi n

ệ có. Song th c

ự ra, ch ng

ẳ có phư ng

ơ th c

ứ nào nói chung và

hai phương th c

ứ này nói riêng, có th

ể thay đ i

ổ đư c

ợ chu i

ỗ , vì chu i

ỗ có tính không đ i

ổ .

Khi b n

ạ kích ho t

ạ toUpperCase đ i

ố v i

ớ một String, b n

ạ sẽ thu đư c

ợ một String m i

ớ làm k t

ế quả trả l i

ạ .

Ch ng

ẳ h n:

ạ

String name = "Alan Turing";

String upperName = name.toUpperCase();

Sau khi dòng l nh

ệ thứ hai đư c

ợ th c

ự thi, upperName sẽ chứa giá trị "ALAN TURING", còn name v n ẫ

chứa "Alan Turing".

8.10 String có tính không so sánh đư c

ợ

Ta thư ng

ờ c n

ầ so sánh hai chu i

ỗ đ

ể xem chúng có gi ng

ố nhau không, hay chu i

ỗ nào s

ẽ x p

ế trư c

ớ theo

thứ tự b ng

ả ch

ữ cái. Th t

ậ tuy t

ệ n u

ế ta s

ử d ng

ụ đư c

ợ các toán t

ử so sánh như == và >, song ta không thể

làm v y

ậ .

Để so sánh các String, ta ph i

ả dùng các phư ng

ơ th c

ứ equals và compareTo. Ch n

ẳ g h n:

ạ

String name1 = "Alan Turing";

String name2 = "Ada Lovelace";

if (name1.equals (name2)) {

System.out.println("hai tên này là một.");

}

int flag = name1.compareTo (name2);

if (flag == 0) {

System.out.println("Hai tên gọi này là một.");

} else if (flag < 0) {

System.out.println("tên 1 xếp trước tên 2.");

} else if (flag > 0) {

System.out.println("tên 2 xếp trước tên 1.");

}

Cú pháp

ở đây h i

ơ kì qu c

ặ . Đ

ể so sánh hai String, b n

ạ ph i

ả kích hoạt một phư ng

ơ th c

ứ lên m t

ộ chu i

ỗ

rồi truy n

ề chuỗi còn l i

ạ làm tham s .

ố

Giá tr ịtr

ả về từ equals th t

ậ d

ễ hi u

ể ; true nếu hai chuỗi có ch a

ứ cùng các kí t ,

ự và false trong trường hợp

còn l i

ạ .

Giá tr ịtr

ả về từ compareTo l i

ạ kì qu c

ặ . Đó là kho n

ả g cách gi a

ữ hai ch

ữ cái đ u

ầ tiên có s

ự khác bi t

ệ

ở hai

chuỗi. N u

ế hai chu i

ỗ b n

ằ g nhau thì kho ng

ả cách này b n

ằ g 0. N u

ế chu i

ỗ th

ứ nh t

ấ (chu i

ỗ mà ta kích ho t

ạ

phương th c

ứ lên) đ ng

ứ trư c

ớ theo th

ứ t

ự b ng

ả ch

ữ cái, thì kho ng

ả cách này có giá tr ịâm. Ngư c

ợ l i

ạ ,

kho n

ả g cách có giá tr ịdư ng

ơ . Trong trư ng

ờ h p

ợ này, giá tr ịtr

ả l i

ạ b n

ằ g 8, vì ch

ữ cái th

ứ hai c a

ủ “Ada” đi

trước chữ cái thứ hai c a

ủ “Alan” là 8 v ịtrí.

Để trọn vẹn, tôi cũng nói th t

ậ r ng

ằ vi c

ệ dùng toán tử == đ i

ố v i

ớ các Strings là h p

ợ lệ nhưng ít khi đúng

đắn. Tôi s

ẽ gi i

ả thích lí do trong M c

ụ 13.4; song bây gi ờ thì ch a

ư .

8.11 Thu t

ậ ngữ

đ i

ố t n

ượ g:

M t

ộ t p

ậ h p

ợ các d

ữ li u

ệ có liên quan cùng v i

ớ m t

ộ t p

ậ các ph ng

ươ th c

ứ ho t

ạ đ ng

ộ v i

ớ nó. Các đ i

ố

t ng

ượ mà ta dùng cho đ n

ế gi

ờ g m

ồ có String, Bug, Rock, và nh ng

ữ đ i

ố tư ng

ợ khác trong

GridWorld.

ch ỉs :

ố

Một bi n

ế hay giá trị đ c

ượ dùng đ

ể ch n

ọ m t

ộ trong các thành viên (ph n

ầ t )

ử c a

ủ m t

ộ t p

ậ h p

ợ đ c

ượ x p

ế

thứ tự, nh

ư ch n

ọ kí tự t

ừ m t

ộ chu i

ỗ .

bi t

ệ l :

ệ

M t

ộ l i

ỗ khi th c

ự thi ch ng

ươ trình.

phát:

Gây nên một bi t

ệ l .

ệ

lần v t

ế ngăn x p:

ế

Một bản báo cáo cho th y

ấ tr ng

ạ thái ch ng

ươ trình khi có bi t

ệ l

ệ x y

ả ra.occurs.

nguyên m u:

ẫ

Dòng đ u

ầ tiên c a

ủ m t

ộ ph ng

ươ th c

ứ , trong đó quy đ nh

ị tên, các tham s

ố và ki u

ể tr

ả l i

ạ .

duyệt:

Vi c

ệ l p

ặ qua t t

ấ c

ả m i

ọ ph n

ầ t

ử c a

ủ m t

ộ t p

ậ h p

ợ nh m

ằ th c

ự hi n

ệ m t

ộ công vi c

ệ t ng

ươ t

ự đ i

ố v i

ớ t ng

ừ

phần t .

ử

bi n

ế đ m

ế :

Một bi n

ế dùng đ

ể đếm th

ứ gì đó; bi n

ế này thư ng

ờ đ c

ượ kh i

ở t o

ạ b ng

ằ không sau đó tăng thêm.

tăng:

Vi c

ệ tăng giá tr ịc a

ủ bi n

ế thêm m t

ộ đ n

ơ v .ị Toán t

ử tăng trong Java là ++.

gi m

ả :

Vi c

ệ gi m

ả giá tr ịc a

ủ bi n

ế thêm đi đ n

ơ v .ị Toán t

ử gi m

ả trong Java là --.

8.12 Bài t p

ậ

Bài t p

ậ 1 Hãy vi t

ế một phư ng

ơ th c

ứ nh n

ậ vào m t

ộ String làm đối số rồi in t t

ấ c

ả các ch

ữ cái theo

chi u

ề ngược l i

ạ trên cùng m t

ộ dòng.

Bài t p

ậ 2 Hãy đọc nội dung l n

ầ v t

ế ngăn x p

ế

ở M c

ụ 8.4 rồi tr

ả lời nh ng

ữ câu h i

ỏ sau:

• Những lo i

ạ bi t

ệ l

ệ nào đã x y

ả ra, và nh ng

ữ bi t

ệ l

ệ này đư c

ợ đ nh

ị nghĩa trong các gói (package) nào?

• Giá tr ịnào c a

ủ ch ỉs

ố gây nên bi t

ệ l ?

ệ

• Phương th c

ứ nào phát ra bi t

ệ l ,

ệ và phư ng

ơ th c

ứ đó đư c

ợ đ nh

ị nghĩa

ở đâu?

• Phương th c

ứ nào kích ho t

ạ charAt?

• Trong BadString.java, charAt được kích ho t

ạ t i

ạ dòng s

ố m y

ấ ?

Bài t p

ậ 3 Hãy bao bọc đo n

ạ mã

ở M c

ụ 8.7 vào một phương th c ứ có tên countLetters, sau đó khái quát

hoá sao cho nó ch p

ấ nh n

ậ các đ i

ố s

ố là chu i

ỗ và ch

ữ cái c n

ầ đ m

ế . Ti p

ế theo, vi t

ế l i

ạ phư ng

ơ th c

ứ sao

cho nó s

ử d ng

ụ indexOf để đ nh

ị v ịcác ch

ữ a, thay vì ki m

ể tra t ng

ừ ch

ữ cái m t

ộ .

Bài t p

ậ 4 M c

ụ đích c a

ủ bài t p

ậ này là ôn l i

ạ phép bao b c

ọ và khái quát hoá.

1. Hãy bao b c

ọ đo n

ạ mã l nh

ệ sau, chuy n

ể đ i

ổ nó thành m t

ộ phư ng

ơ th c

ứ nh n

ậ vào đ i

ố s

ố là m t

ộ String

rồi trả l i

ạ giá tr ịcu i

ố cùng c a

ủ count.

2. Mô t

ả ng n

ắ gọn công d n

ụ g c a

ủ phư ng

ơ th c

ứ v a

ừ l p

ậ nên (mà không đi vào chi ti t

ế các bư c

ớ th c

ự hi n

ệ

như thế nào).

3. Bây gi

ờ khi b n

ạ đã khái quát hoá đ

ể mã l nh

ệ ho t

ạ đ ng

ộ đư c

ợ v i

ớ chu i

ỗ b t

ấ kì r i

ồ , b n

ạ còn có th

ể khái

quát hoá theo cách nào n a

ữ ?

String s = "((3 + 7) * 2)";

int len = s.length();

int i = 0;

int count = 0;

while (i < len) {

char c = s.charAt(i);

if (c == '(') {

count = count + 1;

} else if (c == ')') {

count = count - 1;

}

i = i + 1;

}

System.out.println(count);

Bài t p

ậ 5 M c

ụ đích c a

ủ bài t p

ậ này là khám phá nh ng

ữ ki u

ể d

ữ li u

ệ trong Java và đi n

ề vào m t

ộ s

ố

thông tin chi ti t

ế ch a

ư đư c

ợ đ

ề c p

ậ đ n

ế trong chư ng

ơ này.

1. Hãy t o

ạ nên m t

ộ chư ng

ơ trình m i

ớ có tên Test.java rồi vi t

ế một phương th c

ứ main có ch a

ứ nh ng

ữ bi u

ể

thức có k t

ế h p

ợ nhi u

ề ki u

ể d

ữ li u

ệ b ng

ằ toán tử +. Ch n

ẳ g h n,

ạ đi u

ề gì s

ẽ x y

ả ra n u

ế b n

ạ “c ng

ộ ”

một String và một char? Liệu nó có th c

ự hi n

ệ tính t ng

ổ hay k t

ế n i

ố ? Ki u

ể c a

ủ k t

ế qu

ả s

ẽ là gì? (B n

ạ xác

đ nh

ị được kiểu c a

ủ k t

ế quả nh

ư th

ế nào?)

2. Hãy sao chép l i

ạ và m

ở r ng

ộ b ng

ả dư i

ớ đây r i

ồ đi n

ề vào nó. Trong t ng

ừ ô giao c t

ắ gi a

ữ hai ki u

ể d

ữ li u

ệ ,

b n

ạ c n

ầ ph i

ả xác đ nh

ị xem li u

ệ có h p

ợ l

ệ n u

ế dùng toán tử + v i

ớ nh ng

ữ ki u

ể này không, phép toán nào

được thực hi n

ệ (cộng hay k t

ế n i

ố ), và ki u

ể k t

ế qu

ả s

ẽ là gì.

boolean char int String

boolean

char

int

String

3. Hãy tư ng

ở tư ng

ợ xem các nhà thi t

ế k

ế nên ngôn ng

ữ Java đã l a

ự ch n

ọ th

ế nào khi h

ọ đi n

ề vào b n

ả g

trên. Trong s

ố các ô đi n,

ề có bao nhiêu ô dư ng

ờ nh

ư là l a

ự ch n

ọ ch c

ắ ch n?

ắ Có bao nhiêu ô dư ng

ờ nh

ư

là lựa chọn tuỳ ý mà có vài phư ng

ơ án t t

ố nh

ư nhau? Có bao nhiêu ô có v

ẻ còn ch a

ứ đ ng

ự v n

ấ đ ?

ề

4. Sau đây là m t

ộ câu đ :

ố thông thư ng

ờ , câu l nh

ệ x++ đúng b ng

ằ x = x + 1. Nhưng n u

ế x là một char, thì

nó s

ẽ không còn đúng! Trong trư ng

ờ h p

ợ này, x++ là hợp l ,

ệ nh ng

ư x = x + 1 sẽ gây ra lỗi. Hãy th

ử l i

ạ và

xem thông báo l i

ỗ là gì, và sau đó xem li u

ệ b n

ạ có th

ể hình dung đư c

ợ đi u

ề gì đang di n

ễ ra không.

Bài t p

ậ 6 Kết qu

ả c a

ủ chư ng

ơ trình dư i

ớ đây là gì? B ng

ằ m t

ộ câu, hãy mô t

ả xem mystery làm gì (ch

ứ

không ph i

ả các bư c

ớ th c

ự hi n

ệ ra sao).

public class Mystery {

public static String mystery(String s) {

int i = s.length() - 1;

String total = "";

while (i >= 0 ) {

char ch = s.charAt(i);

System.out.println(i + " " + ch);

total = total + ch;

i--;

}

return total;

}

public static void main(String[] args) {

System.out.println(mystery("Allen"));

}

}

Bài t p

ậ 7 Một người b n

ạ cho b n

ạ xem phư ng

ơ th c

ứ sau đây và di n

ễ gi i

ả r ng

ằ n u

ế number là số có hai

chữ số b t

ấ kì, thì chư ng

ơ trình s

ẽ in các ch

ữ s

ố theo chi u

ề ngư c

ợ l i

ạ . Ngư i

ờ y

ấ kh n

ẳ g đ nh

ị r ng

ằ

nếu number là 17, thì phư ng

ơ th c

ứ s

ẽ cho ra k t

ế qu

ả b ng

ằ 71. Liệu người đó có đúng không? N u

ế không,

hãy gi i

ả thích chư ng

ơ trình th c

ự s

ự làm gì và s a

ử ch a

ữ đ

ể nó cho k t

ế qu

ả đúng.

int number = 17;

int lastDigit = number%10;

int firstDigit = number/10;

System.out.println(lastDigit + firstDigit);

Bài t p

ậ 8 Kết quả c a

ủ chư ng

ơ trình sau là gì?

public class Enigma {

public static void enigma(int x) {

if (x == 0) {

return;

} else {

enigma(x/2);

}

System.out.print(x%2);

}

public static void main(String[] args) {

enigma(5);

System.out.println("");

}

}

Hãy gi i

ả thích ng n

ắ g n

ọ b n

ằ g 4-5 t

ừ xem phư ng

ơ th c

ứ enigma thực sự làm đi u

ề gì.

Bài t p

ậ 9

1. Hãy l p

ậ một chư ng

ơ trình m i

ớ có tên Palindrome.java.

2. Viết một phương thức có tên first nh n

ậ vào một String r i

ồ tr

ả l i

ạ ch

ữ cái đ u

ầ tiên, và m t

ộ phư ng

ơ

thức last để tr

ả l i

ạ ch

ữ cái cu i

ố cùng.

3. Viết một phương thức có tên middle nh n

ậ vào một String r i

ồ tr

ả l i

ạ m t

ộ chu i

ỗ con có ch a

ứ m i

ọ th

ứ tr

ừ

hai ch

ữ cái đ u

ầ và cu i

ố . G i

ợ ý: hãy đ c

ọ tài li u

ệ v

ề phư ng

ơ th c

ứ substring trong l p

ớ String. Hãy ch y

ạ m t

ộ

vài phép th

ử đ

ể ch c

ắ r ng

ằ b n

ạ hi u

ể rõ cách ho t

ạ đ ng

ộ c a

ủ substring trước khi th

ử vi t

ế middle. Đi u

ề gì

sẽ x y

ả ra n u

ế b n

ạ kích ho t

ạ middle lên một chu i

ỗ ch ỉcó hai ch

ứ cái? M t

ộ ch

ữ cái? Không có ch

ữ cái

nào?

4. Cách đ nh

ị nghĩa thông thư ng

ờ c a

ủ m t

ộ palindrome là m t

ộ t

ừ mà đ c

ọ xuôi ngư c

ợ đ u

ề gi ng

ố nhau, ch n

ẳ g

h n

ạ “otto” và “palindromeemordnilap.” M t

ộ cách khác đ

ể đ nh

ị nghĩa m t

ộ thu c

ộ tính nh

ư th

ế baft là quy

đ nh

ị một cách ki m

ể tra thu c

ộ tính đó. Ch ng

ẳ h n,

ạ ta có th

ể nói “m t

ộ ch

ữ cái là m t

ộ palindrome, và m t

ộ

từ hai ch

ữ là một palindrome n u

ế hai ch

ữ cái c a

ủ nó gi ng

ố nhau, và m t

ộ t

ừ b t

ấ kì khác là m t

ộ

palindrome n u

ế ch

ữ cái đ u

ầ gi ng

ố ch

ữ cái cu i

ố và khúc gi a

ữ cũng là m t

ộ palindrome.” Hãy vi t

ế m t

ộ

phương th c

ứ đ

ệ quy có tên isPalindrome nh n

ậ vào một String và trả l i

ạ một boolean cho bi t

ế t

ừ đó có

ph i

ả là palindrome hay không.

5. Một khi b n

ạ đã có đo n

ạ mã để ki m

ể tra palindrome, hãy tìm cách đ n

ơ gi n

ả hoá nó b n

ằ g cách gi m

ả s

ố

điều ki n

ệ trong phép ki m

ể tra. G i

ợ ý: vi c

ệ l y

ấ đ nh

ị nghĩa chu i

ỗ r ng

ỗ cũng là palindrome có th

ể giúp ích.

6. Hãy vi t

ế ra trên gi y

ấ m t

ộ chi n

ế lư c

ợ có tính l p

ặ đ

ể ki m

ể tra palindrome. Có m t

ộ s

ố phư ng

ơ án kh

ả dĩ,

bởi v y

ậ b n

ạ hãy đảm b o

ả ch c

ắ ch n

ắ m t

ộ k

ế ho c

ạ h rõ ràng trư c

ớ khi b t

ắ đ u

ầ vi t

ế mã l nh

ệ .

7. Hãy t o

ạ l p

ậ chi n

ế lư c

ợ b n

ạ ch n

ọ thành m t

ộ phư ng

ơ th c

ứ có tên isPalindromeIter.

8. Câu hỏi ph :

ụ Ph

ụ l c

ụ B có mã l nh

ệ đ

ể đ c

ọ m t

ộ danh sách các t

ừ v ng

ự t

ừ m t

ộ file. Hãy đ c

ọ m t

ộ danh

sách các t

ừ r i

ồ in ra nh ng

ữ palindrome.

Bài t p

ậ 10 Một từ đư c

ợ gọi là “abecedarian” n u

ế các ch

ữ cái trong t

ừ đó xu t

ấ hi n

ệ theo th

ứ t

ự b ng

ả

chữ cái. Ch ng

ẳ h n,

ạ sau đây là t t

ấ c

ả nh ng

ữ t

ừ abecedarian g m

ồ 6 ch

ữ cái trong ti ng

ế Anh.

abdest, acknow, acorsy, adempt, adipsy, agnosy, befist, behint, beknow, bijoux, biopsy, cestuy, chintz, deflux, dehors, dehort, deinos, diluvy, dimpsy 1. Hãy miêu t

ả m t

ộ quy trình ki m

ể tra xem m t

ộ t

ừ (String) cho trư c

ớ là abecedarian hay không, n u

ế coi

r n

ằ g từ đó ch ỉg m

ồ các ch

ữ cái thư ng

ờ . Quy trình này có th

ể mang tính l p

ặ hay đ

ệ quy.

2. T o

ạ dựng quy trình trên thành m t

ộ phư ng

ơ th c

ứ mang tên isAbecedarian.

Bài t p

ậ 11 Một dupledrome là m t

ộ t

ừ ch ỉch a

ứ các ch

ữ cái ghép đôi, ch n

ẳ g h n

ạ nh

ư “llaammaa” hay

“ssaabb”. Tôi đ

ề ra gi

ả thi t

ế ràng trong ti ng

ế Anh thông d n

ụ g không h

ề có dupledrome nào. Đ

ể ki m

ể

chứng gi

ả thi t

ế đó, tôi mu n

ố có chư ng

ơ trình đ c

ọ l n

ầ lư t

ợ các t

ừ v ng

ự t

ừ m t

ộ cu n

ố t

ừ đi n

ể r i

ồ ki m

ể tra

xem t

ừ đó có ph i

ả là dupledrome hay không. Hãy vi t

ế m t

ộ phư ng

ơ th c

ứ mang tên isDupledrome nh n

ậ

vào một String r i

ồ tr

ả l i

ạ m t

ộ boolean đ

ể cho bi t

ế t

ừ đó có ph i

ả là dupledrome không.

Bài t p

ậ 12

1. Vòng gi i

ả mã Captain Crunch ho t

ạ đ ng

ộ b ng

ằ cách l y

ấ m i

ỗ ch

ữ cái trong m t

ộ chu i

ỗ r i

ồ c ng

ộ 13 vào nó.

Ch ng

ẳ h n,

ạ ’a’ tr

ở thành ’n’ và ’b’ tr

ở thành ’o’. Đ n

ế cu i

ố , các ch

ữ cái “quay vòng l i

ạ ”, b i

ở v y

ậ ’z’ tr

ở

thành ’m’. Hãy vi t

ế m t

ộ phư ng

ơ th c

ứ nh n

ậ vào m t

ộ String r i

ồ tr

ả l i

ạ m t

ộ String m i

ớ có ch a

ứ chu i

ỗ sau

mã hoá. B n

ạ c n

ầ coi ràng String ban đ u

ầ ch ỉch a

ứ các ch

ữ in, ch

ữ thư ng

ờ , d u

ấ cách, mà không có d u

ấ

ch m

ấ ph y

ẩ gì khác. Các ch

ữ thư ng

ờ thì đư c

ợ mã hoá thành ch

ữ thư ng

ờ , ch

ữ in thành ch

ữ in. B n

ạ không

được mã hoá các dấu cách.

2. Hãy khái quát hoá phư ng

ơ th c

ứ Captain Crunch sao cho thay vì c ng

ộ 13 vào t ng

ừ ch

ữ cái, nó có th

ể c ng

ộ

thêm b t

ấ kì số nào. Bây gi

ờ b n

ạ có th

ể mã hoá b n

ằ cách c ng

ộ 13 r i

ồ gi i

ả mã b ng

ằ cách c ng

ộ -13. Hãy thử

làm đi u

ề này.

Bài t p

ậ 13 Nếu b n

ạ đã gi i

ả các bài t p

ậ GridWorld trong Chư ng

ơ 5, có th

ể b n

ạ s

ẽ thích bài t p

ậ này.

M c

ụ đích là dùng toán lư ng

ợ giác đ

ể khi n

ế các con b

ọ (Bug) đu i

ổ b t

ắ l n

ẫ nhau. Hãy sao chép

file BugRunner.java thành ChaseRunner.java rồi nh p

ậ nó vào môi trư ng

ờ phát tri n

ể c a

ủ b n.

ạ Trư c

ớ khi

thay đổi b t

ấ c

ứ đi u

ề gì, hãy ki m

ể tra đ m

ả b o

ả r ng

ằ b n

ạ biên d c

ị h và ch y

ạ đư c

ợ chư ng

ơ trình.

• T o

ạ nên hai Bug, m t

ộ con màu đ

ỏ và m t

ộ màu xanh lam.

• Viết một phương thức mang tên distance nh n

ậ vào hai Bug r i

ồ tính kho ng

ả cách gi a

ữ chúng. Hãy nh

ớ

r n

ằ g b n

ạ có th

ể l y

ấ đư c

ợ to

ạ đ

ộ x c a

ủ m t

ộ Bug nh

ư sau:

int x = bug.getLocation().getCol();

• Viết một phương thức mang tên turnToward nh n

ậ vào hai Bug r i

ồ quay m t

ặ m t

ộ con hư ng

ớ đ n

ế con

kia. G I

Ợ Ý: dùng Math.atan2, nhưng hãy nh

ớ r ng

ằ k t

ế qu

ả theo đ n

ơ v ịradian, b i

ở v y

ậ b n

ạ ph i

ả chuy n

ể

sang độ. Ngoài ra, đ i

ố v i

ớ Bug, 0 đ

ộ là hư ng

ớ B c

ắ ch

ứ không ph i

ả hư ng

ớ Đông.

• Viết một phương thức mang tên moveToward nh n

ậ vào hai Bug, quay m t

ặ con th

ứ nh t

ấ v

ề phía con th

ứ

hai, rồi di chuy n

ể con th

ứ nh t

ấ , n u

ế có th .

ể

• Viết một phương thức mang tên moveBugs nh n

ậ hai Bug và m t

ộ s

ố nguyên n, rồi di chuy n

ể m t

ộ con

Bug v

ề phía con kia n l n

ầ . B n

ạ có thể vi t

ế phư ng

ơ th c

ứ này theo cách đ

ệ quy, ho c

ặ dùng m t

ộ vòng l p

ặ

while.

• Ki m

ể tra t ng

ừ phư ng

ơ th c

ứ v a

ừ vi t

ế

ở trên ngay khi b n

ạ phát tri n

ể chúng. Khi chúng đ u

ề ho t

ạ đ ng

ộ

được, hãy tìm mọi c

ơ h i

ộ c i

ả thi n.

ệ Ch ng

ẳ h n

ạ , n u

ế b n

ạ có mã l nh

ệ d

ư th a

ừ

trong distance và turnToward, thì b n

ạ có th

ể bao b c

ọ đo n

ạ mã l nh

ệ l p

ặ l i

ạ vào trong m t

ộ phư ng

ơ th c

ứ .

Ch

ng

ươ 9: Đ i

ố t ng

ượ có th

ể bi n

ế đ i

ổ

Trở về M c

ụ l c

ụ cuốn sách String là các đối tư ng

ợ , song chúng là đ i

ố tư ng

ợ không đi n

ể hình b i

ở lẽ

• Chúng không th

ể bi n

ế đ i

ổ .

• Chúng không có thu c

ộ tính.

• B n

ạ không b t

ắ bu c

ộ ph i

ả dùng new để t o

ạ nên một chuỗi m i

ớ .

Trong chương này, ta dùng hai đ i

ố tư ng

ợ thu c

ộ th

ư vi n

ệ Java, là đ i

ố tư ng

ợ Point và Rectangle (đi m

ể và

hình chữ nhật). Song trư c

ớ h t

ế , tôi mu n

ố nói rõ r n

ằ g nh ng

ữ đi m

ể và hình ch

ữ nh t

ậ này không ph i

ả là

những đối tư ng

ợ đồ hoạ xu t

ấ hi n

ệ trên mà hình. Chúng ch ỉlà nh ng

ữ giá tr ịcó ch a

ứ s

ố li u

ệ , cũng nh

ư

các int và double. Giống nh ng

ữ giá tr ịkhác, chúng đư c

ợ s

ử d n

ụ g bên trong chư ng

ơ trình đ

ể th c

ự hi n

ệ

tính toán.

9.1 Các gói chư n

ơ g trình

Các th

ư vi n

ệ Java đư c

ợ chia thành các gói, trong đó có java.lang là gói ch a ứ h u

ầ h t

ế các l p

ớ mà ta dùng

cho đ n

ế gi ,

ờ và java.awt, tên đ y

ầ đủ Abstract Window Toolkit (AWT), là gói ch a

ứ các l p

ớ g m

ồ c a

ử

sổ, nút b m

ấ , đồ ho ,

ạ v.v.

Để dùng một lớp được đ n

ị h nghĩa trong gói khác, b n

ạ ph i

ả nh p

ậ nó. Point và Rectangle n m

ằ trong

gói java.awt, bởi v y

ậ đ

ể nh p

ậ chúng ta làm nh

ư sau:

import java.awt.Point;

import java.awt.Rectangle;

T t

ấ c

ả câu l nh

ệ import đều xu t

ấ hi n

ệ

ở đi m

ể đ u

ầ chư ng

ơ trình, bên ngoài l i

ờ đ nh

ị nghĩa l p.

ớ

Các l p

ớ trong java.lang, như Math và String, đư c

ợ nh p

ậ một cách t

ự đ ng

ộ , b i

ở v y

ậ t

ừ trư c

ớ đ n

ế gi

ờ ta

chưa c n

ầ dùng đ n

ế câu l nh

ệ import nào.

9.2 Đối tư n

ợ g Point

Một đi m

ể là hai con s

ố (to

ạ đ )

ộ mà ta coi chúng h p

ợ nh t

ấ nh

ư m t

ộ đ i

ố tư ng

ợ đ n

ơ l .

ẻ Theo kí hi u

ệ toán

học, đi m

ể thường được vi t

ế trong c p

ặ ngo c

ặ tròn, v i

ớ d u

ấ ph y

ẩ phân cách gi a

ữ các to

ạ đ .

ộ Ch n

ẳ g h n

ạ ,

(0, 0) ch ỉđ nh

ị g c

ố to

ạ đ ,

ộ còn ( x, y) ch ỉđ nh

ị đi m

ể cách đi m

ể g c

ố x đơn v ịv

ề bên tay ph i

ả và y đơn vị lên

trên.

Trong Java, m t

ộ đi m

ể đư c

ợ bi u

ể di n

ễ b i

ở m t

ộ đ i

ố tư ng

ợ Point. Để t o

ạ nên một đi m

ể m i

ớ , b n

ạ ph i

ả

dùng đ n

ế new:

Point blank;

blank = new Point(3, 4);

Dòng th

ứ nh t

ấ là m t

ộ l i

ờ khai báo bi n

ế thông d n

ụ g: blank có ki u

ể Point. Dòng th

ứ hai kích ho t

ạ new,

quy đ nh

ị ki u

ể c a

ủ đ i

ố tư ng

ợ m i

ớ , và cung c p

ấ các đ i

ố s .

ố

Ở đây các đ i

ố s

ố là to

ạ đ

ộ c a

ủ đi m

ể m i

ớ , (3, 4).

Kết qu

ả c a

ủ new là một tham chi u

ế đến đi m

ể m i

ớ , vì v y

ậ blank chứa một tham chi u

ế đ n

ế đ i

ố tư ng

ợ

mới t o

ạ nên. Có m t

ộ cách tiêu chu n

ẩ đ

ể s

ơ đ

ồ hoá phép gán này, xem trên hình v .

ẽ

Như thường l ,

ệ tên bi n,

ế blank, được ghi bên ngoài ô và giá tr ịc a

ủ nó

ở trong ô. V i

ớ trư ng

ờ h p

ợ này, giá

trị là một tham chi u

ế , và đư c

ợ bi u

ể di n

ễ b i

ở m t

ộ mũi tên. Mũi tên này ch ỉđ n

ế đ i

ố tư ng

ợ mà ta tham

chi u

ế tới.

Ô lớn bi u

ể di n

ễ đối tư ng

ợ m i

ớ t o

ạ l p

ậ cùng v i

ớ hai giá tr ịbên trong. Các tên g i

ọ x và y là các tên

c a

ủ biến th c

ự thể.

Xét tổng th ,

ể t t

ấ c

ả các bi n,

ế giá tr ,ị và đ i

ố tư ng

ợ trong m t

ộ chư ng

ơ trình thì đư c

ợ g i

ọ là tr n

ạ g thái.

Những bi u

ể đồ nh

ư th

ế này, dùng đ

ể bi u

ể di n

ễ tr ng

ạ thái chư ng

ơ trình, đư c

ợ g i

ọ là biểu đ

ồ tr n

ạ g

thái. Khi chư ng

ơ trình ch y

ạ , tr n

ạ g thái c a

ủ nó thay đ i

ổ ; b i

ở v y

ậ b n

ạ nên coi bi u

ể đ

ồ tr ng

ạ thái nh

ư m t

ộ

nh

ả ch p

ụ t i

ạ một th i

ờ đi m

ể c

ụ thể trong quá trình th c

ự thi.

9.3 Các biến th c

ự thể

Những đ n

ơ v ịthông tin h p

ợ thành đ i

ố tư ng

ợ đư c

ợ g i

ọ là các bi n

ế th c

ự th

ể vì t ng

ừ đ i

ố tư ng

ợ , v n

ố là

một th c

ự thể cho ki u

ể c a

ủ nó, có m t

ộ b n

ả sao riêng c a

ủ bi n

ế th c

ự th

ể này.

Cũng giống nh

ư ngăn trư c

ớ [n i

ơ để CD, gi y

ấ t

ờ

ở gh

ế ng i

ồ phía trư c

ớ ] c a

ủ m t

ộ chi c

ế xe h i

ơ . M i

ỗ cái xe

là th c

ự th

ể c a

ủ ki u

ể “xe hơi,” và t ng

ừ chi c

ế xe có ngăn riêng c a

ủ nó. N u

ế b n

ạ yêu c u

ầ tôi l y

ấ đ

ồ t

ừ ngăn

trước c a

ủ xe hơi b n

ạ đang dùng, thì hãy cho tôi bi t

ế xe b n

ạ đang dùng là xe nào.

Tương tự như v y

ậ , n u

ế b n

ạ mu n

ố đ c

ọ m t

ộ giá tr ịt

ừ bi n

ế th c

ự th ,

ể b n

ạ ph i

ả ch ỉđ nh

ị đ i

ố tư ng

ợ mà b n

ạ

c n

ầ l y

ấ giá tr ịt

ừ đó.

Ở Java, đi u

ề này đư c

ợ th c

ự hi n

ệ b ng

ằ cách dùng “kí pháp d u

ấ ch m

ấ .”

int x = blank.x;

Bi u

ể thức blank.x nghĩa là “đ n

ế đối tư ng

ợ mà blank ch ỉt i

ớ , r i

ồ l y

ấ giá tr ịc a

ủ x.” Trong trường h p

ợ này

ta gán giá tr ịđó vào m t

ộ bi n

ế đ a

ị phư ng

ơ có tên là x. Không h

ề có xung đ t

ộ gì gi a

ữ bi n

ế đ a

ị phư ng

ơ

tên x này và bi n

ế th c

ự th

ể mang tên x. M c

ụ đích c a

ủ kí pháp d u

ấ ch m

ấ là đ

ể quy đ nh

ị rõ ràng xem

bi n

ế nào mà b n

ạ đang tham chi u

ế t i

ớ .

B n

ạ có thể dùng kí pháp d u

ấ ch m

ấ làm m t

ộ thành ph n

ầ trong b t

ấ kì bi u

ể th c

ứ Java nào, b i

ở v y

ậ các

bi u

ể th c

ứ sau đ u

ề h p

ợ l .

ệ

System.out.println(blank.x + ", " + blank.y);

int distance = blank.x * blank.x + blank.y * blank.y;

Dòng th

ứ nh t

ấ in ra 3, 4; dòng th

ứ hai tính giá tr ịc a

ủ 25.

9.4 Đối tư n

ợ g trong vai trò c a

ủ tham số

B n

ạ có thể truy n

ề đối tư ng

ợ nh

ư nh ng

ữ tham s

ố theo cách thông thư ng

ờ . Ch ng

ẳ h n:

ạ

public static void printPoint(Point p) {

System.out.println("(" + p.x + ", " + p.y + ")");

}

Phương th c

ứ này nh n

ậ m t

ộ đi m

ể làm đ i

ố s

ố r i

ồ in nó ra dư i

ớ đ nh

ị d ng

ạ tiêu chu n.

ẩ N u

ế b n

ạ kích ho t

ạ

printPoint(blank), nó s

ẽ in ra (3, 4). Thực t

ế là Java đã có s n

ẵ m t

ộ phư ng

ơ th c

ứ đ

ể in ra các Point. N u

ế

kích ho t

ạ System.out.println(blank), b n

ạ sẽ nh n

ậ được

java.awt.Point[x=3,y=4]

Đây là đ n

ị h d ng

ạ tiêu chu n

ẩ mà Java dùng đ

ể in các đ i

ố tư ng

ợ . Nó in ra tên c a

ủ ki u

ể d

ữ li u

ệ , ti p

ế theo là

các tên và giá tr ịc a

ủ nh ng

ữ bi n

ế th c

ự th .

ể

Một ví dụ thứ hai là ta có th

ể vi t

ế l i

ạ phư ng

ơ th c

ứ distance

ở M c

ụ 6.2 để nó nh n

ậ hai Point làm tham số

thay vì bốn double.

public static double distance(Point p1, Point p2) {

double dx = (double)(p2.x - p1.x);

double dy = (double)(p2.y - p1.y);

return Math.sqrt(dx*dx + dy*dy);

}

Các phép đ i

ổ ki u

ể d

ữ li u

ệ

ở đây đ u

ề không th t

ậ s

ự c n

ầ thi t

ế . Tôi ch ỉvi t

ế vào đ

ể t

ự nh c

ắ r n

ằ g các bi n

ế

thực thể trong một Point đều là các số nguyên.

9.5 Hình ch n

ữ h t

ậ

Rectangle (hình ch

ữ nh t

ậ ) cũng gi ng

ố nh

ư các đi m

ể , ch ỉkhác r n

ằ g chúng có b n

ố bi n

ế th c

ự

thể: x, y, width (bề rộng) và height (chi u

ề cao). Ngoài đi u

ề này ra thì nh ng

ữ th

ứ còn l i

ạ v n

ẫ y nguyên.

Ví d

ụ sau đây t o

ạ nên m t

ộ đ i

ố tư ng

ợ Rectangle rồi khi n

ế box tham chi u

ế đ n

ế nó.

Rectangle box = new Rectangle(0, 0, 100, 200);

Hình v

ẽ này mô t

ả hi u

ệ ng

ứ c a

ủ l nh

ệ gán nêu trên.

Nếu in box ra, b n

ạ nh n

ậ đư c

ợ

java.awt.Rectangle[x=0,y=0,width=100,height=200]

Một l n

ầ n a

ữ , đây là k t

ế qu

ả c a

ủ m t

ộ phư ng

ơ th c

ứ Java v n

ố bi t

ế cách in nh ng

ữ đ i

ố tư ng

ợ Rectangle.

9.6 Đối tư n

ợ g v i

ớ vai trò là kiểu đư c

ợ tr l

ả i

ạ

B n

ạ có thể vi t

ế nh ng

ữ phư ng

ơ th c

ứ tr

ả l i

ạ đ i

ố tư ng

ợ . Ch n

ẳ g h n

ạ , findCenter l y

ấ một Rectangle làm đối

số rồi trả l i

ạ một Point có ch a

ứ toạ đ

ộ c a

ủ tâm Rectangle:

public static Point findCenter(Rectangle box) {

int x = box.x + box.width/2;

int y = box.y + box.height/2;

return new Point(x, y);

}

Lưu ý r n

ằ g b n

ạ có th

ể dùng new để t o

ạ nên một đối tư ng

ợ m i

ớ , và r i

ồ l p

ậ t c

ứ dùng k t

ế qu

ả này làm giá

trị trả l i

ạ .

9.7 Đối tư n

ợ g có tính thay đ i

ổ

B n

ạ có thể thay đổi n i

ộ dung c a

ủ m t

ộ đ i

ố tư ng

ợ b ng

ằ cách vi t

ế l nh

ệ gán cho m t

ộ trong s

ố nh ng

ữ bi n

ế

thực thể c a

ủ nó. Ch ng

ẳ h n

ạ , để “d c

ị h chuy n”

ể m t

ộ hình ch

ữ nh t

ậ mà không làm thay đ i

ổ kích thư c

ớ c a

ủ

nó, b n

ạ có th

ể ch nh

ỉ s a

ử các giá trị x và y:

box.x = box.x + 50;

box.y = box.y + 100;

Kết qu

ả đư c

ợ bi u

ể di n

ễ trên hình:

Ta có th

ể bao b c

ọ đo n

ạ mã l nh

ệ trên vào m t

ộ phư ng

ơ th c

ứ r i

ồ khái quát hoá nó đ

ể d c

ị h chuy n

ể hình

chữ nh t

ậ đi m t

ộ kho n

ả g cách b t

ấ kì:

public static void moveRect(Rectangle box, int dx, int dy) {

box.x = box.x + dx;

box.y = box.y + dy;

}

Các bi n

ế dx và dy ch ỉđ nh

ị kho n

ả g cách d c

ị h chuy n

ể hình theo t ng

ừ hư ng

ớ riêng. Vi c

ệ kích ho t

ạ phư ng

ơ

thức này có nh

ả hư ng

ở làm thay đ i

ổ Rectangle được truyền vào dư i

ớ d ng

ạ tham s .

ố

Rectangle box = new Rectangle(0, 0, 100, 200);

moveRect(box, 50, 100);

System.out.println(box);

sẽ in ra java.awt.Rectangle[x=50,y=100,width=100,height=200].

Việc thay đổi các đ i

ố tư ng

ợ b ng

ằ cách truy n

ề chúng làm tham s

ố cho các phư ng

ơ th c

ứ m c

ặ dù có th

ể

hữu ích, song nó cũng có th

ể gây khó khăn cho vi c

ệ g

ỡ l i

ỗ vì không ph i

ả lúc nào cũng d

ễ th y

ấ là vi c

ệ

kích ho t

ạ một phư ng

ơ th c

ứ có thay đ i

ổ các đ i

ố s

ố c a

ủ nó hay không. V

ề sau, tôi s

ẽ th o

ả lu n

ậ nh ng

ữ u

ư

như c

ợ đi m

ể c a

ủ phong cách l p

ậ trình này.

Java có các phư ng

ơ th c

ứ thao tác v i

ớ Point và Rectangle. B n

ạ có th

ể đ c

ọ tài li u

ệ

ở http://download.oracle.com/javase/6/docs/api/java/awt/Point.html và http://download.oracle.com

/javase/6/docs/api/java/awt/Rectangle.html.

Ch ng

ẳ h n,

ạ translate có hi u

ệ ứng t a

ự như moveRect, song thay vì ph i

ả truy n

ề Rectangle làm đ i

ố s ,

ố b n

ạ

l i

ạ dùng kí pháp d u

ấ ch m

ấ :

box.translate(50, 100);

9.8 Aliasing

Hãy nh

ớ r ng

ằ khi b n

ạ gán m t

ộ đ i

ố tư ng

ợ vào cho m t

ộ bi n,

ế b n

ạ đang gán m t

ộ tham chiếu đến đối

tượng. Hoàn toàn có th

ể có nhi u

ề bi n

ế cùng tham chi u

ế t i

ớ m t

ộ đ i

ố tư ng

ợ . Ch ng

ẳ h n,

ạ đo n

ạ mã sau:

Rectangle box1 = new Rectangle(0, 0, 100, 200);

Rectangle box2 = box1;

t o

ạ nên một bi u

ể đồ tr n

ạ g thái trông nh

ư sau:

box1 và box2 cùng ch ỉđ n

ế m t

ộ đ i

ố tư ng

ợ . Nói cách khác, đ i

ố tư ng

ợ này có hai tên g i

ọ , box1 và box2.

Việc người nào đó dùng hai tên đư c

ợ g i

ọ là aliasing (dùng bí danh). V i

ớ đ i

ố tư ng

ợ cũng nh

ư v y

ậ .

Khi hai bi n

ế đư c

ợ dùng bí danh, b t

ấ kì s

ự thay đ i

ổ nào nh

ả hư ng

ở t i

ớ bi n

ế này thì cũng nh

ả hư ng

ở t i

ớ

bi n

ế kia. Ch n

ẳ g h n:

ạ

System.out.println(box2.width);

box1.grow(50, 50);

System.out.println(box2.width);

Dòng l nh

ệ th

ứ nh t

ấ in ra 100, vốn là b

ề rộng c a

ủ Rectangle đư c

ợ tham chi u

ế qua bi n

ế box2. Dòng th

ứ

hai kích ho t

ạ phư ng

ơ th c

ứ grow lên box1, đ

ể m

ở rộng Rectangle thêm 50 đi m

ể nh

ả theo m i

ỗ chi u

ề (hãy

đọc tài li u

ệ đ

ể bi t

ế thêm thông tin). Hi u

ệ ng

ứ đư c

ợ cho th y

ấ

ở hình v

ẽ dư i

ớ đây:

B t

ấ k

ể thay đ i

ổ nào th c

ự hi n

ệ đ i

ố v i

ớ box1 thì cũng nh

ả hư ng

ở đ n

ế box2. Do v y

ậ , giá tr ịđư c

ợ in ra b i

ở

dòng l nh

ệ thứ ba là 200, bề rộng c a

ủ hình ch

ữ nh t

ậ sau khi m

ở r ng

ộ . (Nói thêm, vi c

ệ các to

ạ đ

ộ c a

ủ

một Rectangle nh n

ậ giá tr ịâm là hoàn toàn h p

ợ l .

ệ )

Từ ví d

ụ đ n

ơ gi n

ả này b n

ạ có th

ể th y

ấ r n

ằ g mã l nh

ệ có ch a

ứ bí d n

ạ g nhanh chóng khi n

ế ta nh m

ầ l n

ầ và

có th

ể khó g

ỡ lỗi. Nói chung, nên tránh dùng bí danh ho c

ặ dùng th t

ậ c n

ẩ th n

ậ .

9.9 null

Khi b n

ạ t o

ạ nên m t

ộ bi n

ế đ i

ố tư ng

ợ , hãy nh

ớ r ng

ằ b n

ạ đang t o

ạ nên m t

ộ tham chiếu đến đối tượng.

Trư c

ớ khi b n

ạ khi n

ế cho m t

ộ bi n

ế ch ỉt i

ớ đ i

ố tư ng

ợ , thì giá tr ịc a

ủ bi n

ế v n

ẫ là null. null là một giá tr ịđ c

ặ

bi t

ệ (và cũng là m t

ộ t

ừ khoá trong Java) có nghĩa là “không có đ i

ố tư ng

ợ .”

Lời khai báo Point blank; thì tương đương v i

ớ l nh

ệ kh i

ở t o

ạ sau

Point blank = null;

và đư c

ợ bi u

ể di n

ễ b i

ở bi u

ể đ

ồ tr n

ạ g thái sau:

Giá trị null đư c

ợ bi u

ể thị b ng

ằ một hình vuông nh

ỏ không kèm theo mũi tên.

Nếu b n

ạ c

ố thử dùng một đối tư ng

ợ null, qua vi c

ệ truy c p

ậ m t

ộ bi n

ế th c

ự th

ể hay kích ho t

ạ m t

ộ

phương th c

ứ , thì Java s

ẽ phát m t

ộ bi t

ệ l

ệ có tên NullPointerException, in một thông báo l i

ỗ và k t

ế thúc

chương trình.

Point blank = null;

int x = blank.x; // NullPointerException

blank.translate(50, 50); // NullPointerException

M t

ặ khác, s

ẽ hoàn toàn h p

ợ l

ệ n u

ế ta truy n

ề m t

ộ đ i

ố tư ng

ợ null làm đ i

ố s

ố ho c

ặ nh n

ậ m t

ộ null làm giá

trị trả về. Th c

ự ra, đi u

ề này r t

ấ thông d n

ụ g, v i

ớ m c

ụ đích ch ng

ẳ h n

ạ là bi u

ể di n

ễ m t

ộ t p

ậ h p

ợ r ng

ỗ hay

để ch ỉmột đi u

ề ki n

ệ có l i

ỗ .

9.10 Thu dọn rác

Ở M c

ụ 9.8 ta đã nói v

ề nh ng

ữ gì đã x y

ả ra khi nhi u

ề bi n

ế cùng tham chi u

ế t i

ớ m t

ộ đ i

ố tư ng

ợ . Th

ế còn

điều gì s

ẽ x y

ả ra khi không có bi n

ế nào tham chi u

ế đ n

ế đ i

ố tư ng

ợ ? Ch ng

ẳ h n:

ạ

Point blank = new Point(3, 4);

blank = null;

Dòng th

ứ nh t

ấ t o

ạ ra m t

ộ đ i

ố tư ng

ợ Point mới r i

ồ khi n

ế cho blank tham chi u

ế đ n

ế nó. Dòng thứ hai s a

ử

chữa blank để cho, thay vì tham chi u

ế đ n

ế đ i

ố tư ng

ợ , nó không tham chi u

ế đ n

ế gì c

ả (hay tham chi u

ế

đến đ i

ố tư ng

ợ null).

Nếu không có ai tham chi u

ế đ n

ế đ i

ố tư ng

ợ , thì cũng ch ng

ả ai có th

ể đ c

ọ hay ghi giá tr ịb t

ấ kì nào t

ừ nó,

hay kích ho t

ạ m t

ộ phư ng

ơ th c

ứ lên nó. H

ệ qu

ả là, nó s

ẽ ng n

ừ g t n

ồ t i

ạ . Ta có th

ể v n

ẫ gi

ữ đ i

ố tư ng

ợ này

trong bộ nh ,

ớ song làm nh

ư v y

ậ ch ỉt n

ố dung lư ng

ợ ; b i

ở v y

ậ khi chư ng

ơ trình ch y

ạ , theo đ n

ị h kì h

ệ

thống s

ẽ tìm ki m

ế các đ i

ố tư ng

ợ lang thang r i

ồ thu h i

ồ l i

ạ nó, theo m t

ộ quá trình mang tên thu d n

ọ

rác. Sau này, dung lư ng

ợ nh

ớ b ịchi m

ế b i

ở đ i

ố tư ng

ợ s

ẽ v

ề tay ngư i

ờ dùng đ

ể ph c

ụ v

ụ đ i

ố tư ng

ợ m i

ớ .

B n

ạ không c n

ầ ph i

ả làm b t

ấ c

ứ đi u

ề gì đ

ể ti n

ế hành thu d n

ọ rác, và nói chung b n

ạ s

ẽ không nh n

ậ th c

ứ

được quá trình này. Song b n

ạ c n

ầ bi t

ế r ng

ằ quá trình luôn đư c

ợ ng m

ầ ch y

ạ m t

ộ cách đ nh

ị kì.

9.11 Các đối tư n

ợ g và kiểu nguyên th y

ủ

Trong Java có hai lo i

ạ ki u

ể d

ữ li u

ệ , ki u

ể nguyên th y

ủ và ki u

ể đ i

ố tư ng

ợ . Ki u

ể nguyên th ,

ủ

như int và boolean đều b t

ắ đầu b ng

ằ ch

ữ vi t

ế thư ng

ờ ; ki u

ể đ i

ố tư ng

ợ b t

ắ đ u

ầ b ng

ằ ch

ữ vi t

ế in. S

ự phân

bi t

ệ này r t

ấ có ích vì chúng nh c

ắ ta m t

ộ s

ố đi m

ể khác nhau gi a

ữ chúng:

• Khi khai báo m t

ộ bi n

ế nguyên th y

ủ , b n

ạ đư c

ợ m t

ộ dung lư ng

ợ l u

ư tr

ữ dành cho giá tr ịnguyên th y

ủ . Khi

b n

ạ khai báo m t

ộ bi n

ế đ i

ố tư ng

ợ , b n

ạ nh n

ậ đư c

ợ m t

ộ dung lư ng

ợ ch a

ứ tham chi u

ế t i

ớ đ i

ố tư ng

ợ . Đ

ể

giành đư c

ợ dung lư ng

ợ cho b n

ả thân đ i

ố tư ng

ợ đó, b n

ạ ph i

ả dùng đ n

ế new.

• Nếu b n

ạ không kh i

ở t o

ạ m t

ộ ki u

ể nguyên th y

ủ , thì nó s

ẽ đư c

ợ đi n

ề giá tr ịm c

ặ đ nh

ị tùy theo ki u

ể đó là

gì. Ch ng

ẳ h n,

ạ 0 với trường hợp int và false v i

ớ boolean. Giá tr ịm c

ặ đ nh

ị c a

ủ ki u

ể đ i

ố tư ng

ợ là null,

nghĩa là không có đ i

ố tư ng

ợ nào.

• Các bi n

ế nguyên th y

ủ tách bi t

ệ hoàn toàn, theo nghĩa b t

ấ c

ứ b n

ạ làm gì trong m t

ộ phư ng

ơ th c

ứ này s

ẽ

không nh

ả hư ng

ở đ n

ế m t

ộ bi n

ế

ở phư ng

ơ th c

ứ khác. Các bi n

ế đ i

ố tư ng

ợ thì l i

ạ c n

ầ ph i

ả khéo léo khi

thao tác vì chúng không đư c

ợ bi t

ệ l p

ậ nh

ư v y

ậ . N u

ế b n

ạ truy n

ề m t

ộ tham chi u

ế đ n

ế đ i

ố tư ng

ợ đ

ể làm

đối số, thì phương thức mà b n

ạ kích ho t

ạ có th

ể s

ẽ thay đ i

ổ đ i

ố tư ng

ợ , và trong trư ng

ờ h p

ợ này b n

ạ s

ẽ

th y

ấ hi u

ệ ng

ứ . Dĩ nhiên, đó có th

ể là đi u

ề hay, song b n

ạ c n

ầ nh n

ậ th c

ứ đư c

ợ vi c

ệ này.

Còn một đi m

ể khác bi t

ệ gi a

ữ ki u

ể nguyên th y

ủ và ki u

ể đ i

ố tư ng

ợ . B n

ạ không th

ể b

ổ sung ki u

ể nguyên

th y

ủ mới nào vào Java (tr

ứ khi b n

ạ là thanh viên trong h i

ộ đ ng

ồ tiêu chu n

ẩ ), nh ng

ư b n

ạ có th

ể t o

ạ nên

kiểu đối tượng m i

ớ ! B n

ạ s

ẽ bi t

ế cách làm nh

ư v y

ậ trong chư ng

ơ sau.

9.12 Thu t

ậ ngữ

gói:

Một tập h p

ợ các l p

ớ . Các l p

ớ Java đ c

ượ t

ổ ch c

ứ thành các gói.

AWT:

Abstract Window Toolkit, m t

ộ trong các gói Java l n

ớ nh t

ấ và thông d ng

ụ nh t

ấ .

th c

ự th :

ể

Ví dụ l y

ấ t

ừ m t

ộ thể lo i

ạ nào đó. Con mèo nhà tôi là m t

ộ th c

ự th

ể thu c

ộ th

ể lo i

ạ “đ ng

ộ v t

ậ h

ọ miêu.”

Mỗi đối t ng

ượ đ u

ề là th c

ự th

ể c a

ủ m t

ộ l p

ớ nào đó.

bi n

ế th c

ự th :

ể

Một trong số các đ n

ơ vị d

ữ li u

ệ đ c

ượ đặt tên đ

ể c u

ấ thành m t

ộ đ i

ố tư ng

ợ . T ng

ừ đ i

ố tư ng

ợ (th c

ự th )

ể

đều có b n

ả sao riêng các bi n

ế th c

ự th

ể trong l p

ớ mà nó thu c

ộ vào.

tham chi u:

ế

Một giá tr ịđ

ể chỉ đ nh

ị

m t

ộ đ i

ố tư ng

ợ . Trên s

ơ đ

ồ tr ng

ạ thái, m t

ộ tham chi u

ế xu t

ấ hi n

ệ dư i

ớ d ng

ạ hình

mũi tên.

aliasing (bí danh):

Tình tr ng

ạ khi có nhi u

ề bi n

ế cùng tham chi u

ế t i

ớ m t

ộ đ i

ố t ng

ượ .

thu d n

ọ rác:

Quá trình tìm các đ i

ố t ng

ượ không có tham chi u

ế và thu h i

ồ dung l ng

ượ b

ộ nh

ớ mà chúng chi m

ế gi .

ữ

tr n

ạ g thái:

Một hình th c

ứ di n

ễ t

ả đ y

ầ đ

ủ t t

ấ c

ả các bi n

ế và đ i

ố t ng

ượ cùng nh ng

ữ giá tr ịc a

ủ chúng t i

ạ m t

ộ th i

ờ

đi m

ể trong khi ch ng

ươ trình đư c

ợ th c

ự thi.

s

ơ đ

ồ tr n

ạ g thái:

M t

ộ hình nh

ả

“ch p

ụ l i

ạ ” tr ng

ạ thái c a

ủ ch ng

ươ trình.

9.13 Bài t p

ậ

Bài t p

ậ 1

1. Với chương trình sau đây, hãy v

ẽ m t

ộ s

ơ đ

ồ ngăn x p

ế cho th y

ấ các bi n

ế đ a

ị phư ng

ơ và các đ i

ố s

ố

c a

ủ main và riddle, rồi cho th y

ấ m i

ọ đ i

ố tư ng

ợ mà hai bi n

ế này ch ỉđ n.

ế

2. Kết qu

ả c a

ủ chư ng

ơ trình này là gì?

public static void main(String[] args) {

int x = 5;

Point blank = new Point(1, 2);

System.out.println(riddle(x, blank));

System.out.println(x); System.out.println(blank.x);

System.out.println(blank.y);

}

public static int riddle(int x, Point p) {

x = x + 7;

return x + p.x + p.y;

}

M c

ụ đích c a

ủ bài t p

ậ này là đ

ể đ m

ả b o

ả r ng

ằ b n

ạ hi u

ể c

ơ ch

ế truy n

ề đ i

ố tư ng

ợ làm tham s .

ố

Bài t p

ậ 2

1. Với chương trình sau, hãy v

ẽ m t

ộ bi u

ể đ

ồ ngăn x p

ế th

ể hi n

ệ tr n

ạ g thái c a

ủ chư ng

ơ trình ngay trư c

ớ

khi distance trả về. Hãy kèm theo t t

ấ c

ả các bi n

ế s

ố và tham s

ố cùng v i

ớ nh ng

ữ đ i

ố tư ng

ợ mà các bi n

ế

này tham chi u

ế t i

ớ .

2. Kết qu

ả c a

ủ chư ng

ơ trình này là gì?

public static double distance(Point p1, Point p2) {

int dx = p1.x - p2.x;

int dy = p1.y - p2.y;

return Math.sqrt(dx*dx + dy*dy);

}

public static Point findCenter(Rectangle box) {

int x = box.x + box.width/2;

int y = box.y + box.height/2;

return new Point(x, y);

}

public static void main(String[] args) {

Point blank = new Point(5, 8);

Rectangle rect = new Rectangle(0, 2, 4, 4);

Point center = findCenter(rect);

double dist = distance(center, blank);

System.out.println(dist);

}

Bài t p

ậ 3 Phương th c

ứ grow thuộc v

ề lớp Rectangle. Hãy đọc tài li u

ệ

ởhttp://download.oracle.com/javase/6/docs/api/java/awt/Rectangle.html#grow(int, int).

1. Kết qu

ả c a

ủ chư ng

ơ trình sau là gì?

2. Hãy v

ẽ một s

ơ đồ tr n

ạ g thái ch ỉra tr n

ạ g thái c a

ủ chư ng

ơ trình ngay trư c

ớ khi main kết thúc, trong đó

bao gồm t t

ấ c

ả nh ng

ữ bi n

ế đ a

ị phư ng

ơ cùng các đ i

ố tư ng

ợ mà nh ng

ữ bi n

ế này tham chi u

ế t i

ớ .

3.

Ở điểm cuối c a

ủ main, liệu p1 và p2 có cùng là bí danh không? T i

ạ sao (không)?

public static void printPoint(Point p) {

System.out.println("(" + p.x + ", " + p.y + ")");

}

public static Point findCenter(Rectangle box) {

int x = box.x + box.width/2;

int y = box.y + box.height/2;

return new Point(x, y);

}

public static void main(String[] args) {

Rectangle box1 = new Rectangle(2, 4, 7, 9);

Point p1 = findCenter(box1);

printPoint(p1);

box1.grow(1, 1);

Point p2 = findCenter(box1);

printPoint(p2);

}

Bài t p

ậ 4 Đến giờ có th

ể b n

ạ đang tư ng

ơ t

ư v

ề phư ng

ơ th c

ứ giai th a

ừ , nh ng

ư ta s

ẽ vi t

ế thêm m t

ộ d n

ạ g

mới.

1. Hãy t o

ạ một chư ng

ơ trình m i

ớ có tên Big.java rồi vi t

ế một d n

ạ g l p

ặ cho factorial.

2. In ra một b n

ả g các s

ố nguyên ch y

ạ t

ừ 0 đ n

ế 30 cùng v i

ớ giai th a

ừ c a

ủ chúng.

Ở t m

ầ kho n

ả g 15, có th

ể

b n

ạ sẽ th y

ấ k t

ế quả không còn đúng n a

ữ . T i

ạ sao v y

ậ ?

3. BigIntegers là các đ i

ố tư ng

ợ Java v i

ớ kh

ả năng bi u

ể di n

ễ nh ng

ữ s

ố nguyên l n

ớ tùy ý. Không có gi i

ớ h n

ạ

trên nào tr

ừ gi i

ớ h n

ạ kích thư c

ớ b

ộ nh

ớ và t c

ố đ

ộ x

ử lý. Hãy đ c

ọ tài li u

ệ v

ề BigIntegers

athttp://download.oracle.com/javase/6/docs/api/java/math/BigInteger.html.

4. Để dùng đư c

ợ BigIntegers, b n

ạ ph i

ả thêm dòng import java.math.BigInteger vào đ u

ầ chư ng

ơ trình c a

ủ

b n.

ạ

5. Có vài cách t o

ạ nên m t

ộ BigInteger, nh ng

ư tôi khuyên b n

ạ cách dùng valueOf. Đo n

ạ mã sau chuy n

ể đ i

ổ

một số nguyên thành BigInteger:

int x = 17;

BigInteger big = BigInteger.valueOf(x);

Hãy gõ đo n

ạ mã l nh

ệ này r i

ồ ch y

ạ th .

ử C

ố g n

ắ g in ra m t

ộ BigInteger.

6. Vì BigIntegers không ph i

ả là ki u

ể nguyên th y

ủ nên các toán t

ử toán h c

ọ thông thư ng

ờ không th

ể thao

tác v i

ớ chúng. Thay vào đó, ta ph i

ả dùng nh ng

ữ phư ng

ơ th c

ứ như add. Để cộng hai BigInteger, hãy kích

ho t

ạ add lên một số r i

ồ truy n

ề s

ố kia làm đ i

ố s .

ố Ch n

ẳ g h n:

ạ

BigInteger small = BigInteger.valueOf(17);

BigInteger big = BigInteger.valueOf(1700000000);

BigInteger total = small.add(big);

Hãy th

ử một số phư ng

ơ th c

ứ khác, như multiply và pow.

7. Chuy n

ể đổi factorial sao cho nó tính toán v i

ớ BigInteger r i

ồ tr

ả l i

ạ k t

ế qu

ả cũng là m t

ộ BigInteger. B n

ạ

có th

ể m c

ặ kệ tham số—nó v n

ẫ s

ẽ là m t

ộ s

ố nguyên.

8. Hãy th

ử in l i

ạ b ng

ả b ng

ằ phư ng

ơ th c

ứ giai th a

ừ mà b n

ạ v a

ừ s a

ử đ i

ổ . Li u

ệ nó có đúng đ n

ế 30 không?

B n

ạ có thể làm cho nó l n

ớ đ n

ế bao nhiêu? Tôi đã tính giai th a

ừ c a

ủ t t

ấ c

ả các s

ố t

ừ 0 đ n

ế 999, nh ng

ư vì

máy tính c a

ủ tôi khá ch m

ậ nên m t

ấ m t

ộ lúc. S

ố cu i

ố cùng, 999!, có t i

ớ 2565 ch

ữ s .

ố

Bài t p

ậ 5 Nhiều kĩ thu t

ậ mã hóa ph

ụ thu c

ộ vào kh

ả năng nâng các s

ố nguyên l n

ớ lên nh ng

ữ lũy th a

ừ

nguyên. Sau đây là m t

ộ phư ng

ơ th c

ứ th c

ự hi n

ệ m t

ộ kĩ thu t

ậ (tư ng

ơ đ i

ố ) nhanh đ

ể tính lũy th a

ừ s

ố

nguyên:

public static int pow(int x, int n) {

if (n == 0) return 1;

// tính x mũ n/2 bằng cách đệ quy

int t = pow(x, n/2);

// nếu n chẵn, kết quả là t bình phương

// nếu n lẻ, kết quả là t bình phương nhân với x

if (n%2 == 0) {

return t*t;

} else {

return t*t*x;

}

}

V n

ấ đ

ề với phư ng

ơ th c

ứ này là

ở ch

ỗ nó ch ỉho t

ạ đ ng

ộ đư c

ợ n u

ế k t

ế qu

ả nh

ỏ h n

ơ 2 t .

ỷ Hãy vi t

ế l i

ạ

phương th c

ứ đ

ể k t

ế quả là m t

ộ BigInteger. Tuy v y

ậ các tham s

ố v n

ẫ là s

ố nguyên.

B n

ạ có thể dùng các phư ng

ơ th c

ứ cho BigInteger là add và multiply, song đừng dùng pow, như v y ậ s

ẽ

ch ng

ẳ còn gì để làm.

Bài t p

ậ 6 Nếu b n

ạ thích đồ h a

ọ , bây gi

ờ đúng là lúc đ c

ọ đ n

ế Ph

ụ l c

ụ A rồi làm các bài t p ậ

ở đó.

Ch

ng

ươ 10: Grid World, ph n

ầ 2

Trở về M c

ụ l c

ụ bài vi t ế

Ph n

ầ 2 c a

ủ nghiên c u

ứ c

ụ thể GridWorld có s

ử d n

ụ g m t

ộ s

ố đ c

ặ đi m

ể mà ta ch a

ư t ng

ừ g p

ặ , vì v y

ậ b n

ạ sẽ

xem qua bây gi

ờ và seau này s

ẽ xem xét kĩ h n.

ơ Hãy nh

ớ l i

ạ r ng

ằ , b n

ạ có th

ể tìm tài li u

ệ cho các l p

ớ

GridWorld ở http://www.greenteapress.com/thinkapjava/javadoc/gridworld/.

Khi cài đ t

ặ GridWorld, b n

ạ s

ẽ có m t

ộ th

ư m c

ụ mang tên projects/boxBug, trong đó

chứa BoxBug.java, BoxBugRunner.java và BoxBug.gif.

Hãy sao chép nh ng

ữ file này vào th

ư m c

ụ hi n

ệ th i

ờ c a

ủ b n

ạ r i

ồ nh p

ậ chúng vào môi trư ng

ờ phát tri n.

ể

Có những ch ỉd n

ẫ trong tài li u

ệ sau mà b n

ạ có th

ể tham

kh o

ả : http://www.collegeboard.com/prod_downloads/student/testing/ap/compsci_a/ap07_gridworld

_installation_guide.pdf.

Sau đây là mã l nh

ệ l y

ấ từ BoxBugRunner.java:

import info.gridworld.actor.ActorWorld;

import info.gridworld.grid.Location;

import java.awt.Color;

public class BoxBugRunner {

public static void main(String[] args) {

ActorWorld world = new ActorWorld();

BoxBug alice = new BoxBug(6);

alice.setColor(Color.ORANGE);

BoxBug bob = new BoxBug(3);

world.add(new Location(7, 8), alice);

world.add(new Location(5, 5), bob);

world.show();

}

}

Ở đây mọi th

ứ có l

ẽ đều quen thu c

ộ , ngo i

ạ trừ Location, thuộc v

ề GridWorld, và đ i

ố tư ng

ợ này tư ng

ơ

đương v i

ớ java.awt.Point.

BoxBug.java chứa l i

ờ đ nh

ị nghĩa l p

ớ cho BoxBug.

public class BoxBug extends Bug {

private int steps;

private int sideLength;

public BoxBug(int length) { steps = 0; sideLength = length; }

}

Dòng đ u

ầ tiên nói r ng

ằ l p

ớ này m

ở r ng

ộ Bug, nghĩa là BoxBug là một d ng

ạ c a

ủ Bug.

Hai dòng k

ế ti p

ế là nh ng

ữ bi n

ế th c

ự th .

ể T ng

ừ con Bug có một bi n

ế tên là sideLength, để quy đ n

ị h kích

thước ô mà nó v

ẽ nên, và steps, để theo dõi xem con Bug này đi bao nhiêu bư c ớ r i

ồ .

Dòng ti p

ế theo đ nh

ị nghĩa m t

ộ constructor; đây là m t

ộ phư ng

ơ th c

ứ đ c

ặ bi t

ệ đ

ể kh i

ở t o

ạ bi n

ế th c

ự

thể. Khi b n

ạ t o

ạ nên m t

ộ Bug b n

ằ g cách kích ho t

ạ new, Java s

ẽ kích hoạt constructor này.

Tham số cho constructor này là chi u

ề dài c nh

ạ .

Hành vi c a

ủ Bug đư c

ợ đi u

ề khi n

ể b i

ở phư ng

ơ th c

ứ act. Sau đây là phư ng

ơ th c

ứ act c a

ủ BoxBug:

public void act() {

if (steps < sideLength && canMove()) {

move();

steps++;

} else {

turn();

turn();

steps = 0;

}

}

Nếu BoxBug có th

ể di chuy n,

ể và ch a

ư th c

ự hi n

ệ đ

ủ s

ố bư c

ớ đi theo yêu c u

ầ , thì nó s

ẽ di chuy n

ể và

đồng thời tăng bi n

ế steps.

Nếu nó đ ng

ụ ph i

ả tư ng

ờ ho c

ặ đi h t

ế m t

ộ c nh

ạ c a

ủ h p,

ộ thì con b

ọ s

ẽ quay 90 đ

ộ sang ph i

ả đ ng

ồ th i

ờ

ch nh

ỉ bi n

ế steps về 0.

Hãy ch y

ạ chư ng

ơ trình và xem nó làm gì. B n

ạ có th y

ấ đư c

ợ con b

ọ có hành vi nh

ư d

ự ki n

ế không?

10.1 Con m i

ố

Tôi đã vi t

ế ra m t

ộ l p

ớ có tên Termite để mở rộng Bug và bổ sung kh

ả năng tư ng

ơ tác v i

ớ nh ng

ữ bông

hoa. Đ

ể ch y

ạ đư c

ợ l p

ớ này, b n

ạ hãy t i

ả v

ề nh ng

ữ file sau r i

ồ nh p

ậ chúng vào môi trư ng

ờ phát tri n

ể đang

dùng:

http://thinkapjava.com/code/Termite.java

http://thinkapjava.com/code/Termite.gif

http://thinkapjava.com/code/TermiteRunner.java

http://thinkapjava.com/code/EternalFlower.java

Vì Termite mở rộng Bug, t t

ấ c

ả những phư ng

ơ th c

ứ c a

ủ Bug đều hoạt động đư c

ợ v i

ớ các Termite.

Nhưng Termite có thêm nh ng

ữ phư ng

ơ th c

ứ khác mà Bug không có.

/**

* Trả lại true nếu con mối có mang bông hoa.

*/

public boolean hasFlower();

/**

* Trả lại true nếu con mối quay mặt về phía bông hoa.

*/

public boolean seeFlower();

/**

* Tạo nên bông hoa trừ khi con mối đã có sẵn một bông.

*/

public void createFlower();

/**

* Bỏ lại bông hoa tại vị trí con mối đang đứng.

*

* Lưu ý: trên mỗi ô chỉ có được một vật, bởi vậy hiệu ứng

* của việc đánh rơi bông hoa sẽ được hoãn lại đến khi con mối di chuyển.

*/

public void dropFlower();

/**

* Ném bông hoa vào chỗ mà con mối đang hướng tới.

*/

public void throwFlower();

/**

* Nhặt bông hoa tại vị trí con mối hướng tới, nếu có,

* và nếu con mối chưa mang theo hoa.

*/

public void pickUpFlower();

Có những phư ng

ơ th c

ứ mà Bug cung c p

ấ một l i

ờ đ nh

ị nghĩa này và Termite l i

ạ cung c p

ấ cái khác. Trong

trường hợp như v y

ậ , phư ng

ơ th c

ứ Termite sẽ ghi đè lên phương thức Bug.

Ch ng

ẳ h n,

ạ Bug.canMove trả l i

ạ true nếu có một bông hoa

ở v ịtrí k

ế ti p,

ế b i

ở v y

ậ các có thể Bug có thể

giẫm lên Flower. Còn Termite.canMove sẽ tr

ả l i

ạ false nếu có b t

ấ kì đ i

ố tư ng

ợ nào khác

ở v ịtrí k

ế ti p,

ế

nên bi u

ể hi n

ệ c a

ủ Termite sẽ khác đi.

Một ví dụ khác, các đ i

ố tư ng

ợ con m i

ố có m t

ộ phiên b n

ả turn trong đó nh n

ậ tham s

ố là s

ố nguyên ch ỉ

độ góc. Sau cùng, đ i

ố tư ng

ợ con m i

ố córandomTurn, với tác d n

ụ g quay ng u

ẫ nhiên qua trái ho c

ặ ph i

ả

với góc quay 45 đ .

ộ

Sau đây là mã l nh

ệ t

ừ file TermiteRunner.java:

public class TermiteRunner {

public static void main(String[] args) {

ActorWorld world = new ActorWorld();

makeFlowers(world, 20);

Termite alice = new Termite();

world.add(alice);

Termite bob = new Termite();

bob.setColor(Color.blue);

world.add(bob);

world.show();

}

public static void makeFlowers(ActorWorld world, int n) {

for (int i = 0; i<n; i++) {

world.add(new EternalFlower());

}

}

}

Ở đây mọi th c

ứ có l

ẽ đ u

ề quen thu c

ộ . TermiteRunner t o

ạ nên một ActorWorld với

20 EternalFlowers và hai Termite.

Mỗi EternalFlower là một Flower ghi đè lên act sao cho các bông hoa không đư c ợ tô th m

ẫ đi.

public class EternalFlower extends Flower {

public void act() {

}

}

Nếu b n

ạ ch y

ạ TermiteRunner.java, b n

ạ s

ẽ th y

ấ hai con m i

ố di chuy n

ể ng u

ẫ nhiên quanh nh ng

ữ bông

hoa.

MyTermite.java gi i

ớ thi u

ệ nh ng

ữ phư ng

ơ th c

ứ tư ng

ơ tác v i

ớ các bông hoa. Sau đây là l i

ờ khai báo l p

ớ

này:

public class MyTermite extends Termite {

public void act() {

if (getGrid() == null)

return;

if (seeFlower()) {

pickUpFlower();

}

if (hasFlower()) {

dropFlower();

}

if (canMove()) {

move();

}

randomTurn();

}

}

MyTermite mở rộng Termite và ghi đè lên act. N u

ế MyTermite th y

ấ một bông hoa, nó s

ẽ nh t

ặ lên. N u

ế

có bông hoa r i

ồ , thì nó s

ẽ b

ỏ l i

ạ bông hoa này.

10.2 Con mối c a

ủ Langton

Con ki n

ế c a

ủ Langton là m t

ộ mô hình đ n

ơ gi n

ả v

ề bi u

ể hi n

ệ c a

ủ ki n

ế nh ng

ư hi n

ể th ịnh ng

ữ bi u

ể hi n

ệ

phức t p

ạ đáng ng c

ạ nhiên. Con ki n

ế s ng

ố trong m t

ộ lư i

ớ ô như GridWorld trong đó t ng

ừ ô có màu tr n

ắ g

ho c

ặ đen. Ki n

ế di chuy n

ể theo nh ng

ữ quy t c

ắ sau:

•Nếu con ki n

ế đ ng

ứ trên ô tr n

ắ g; nó quay sang ph i

ả , tô màu ô thành đen, r i

ồ ti n

ế bư c

ớ .

•Nếu con ki n

ế đ ng

ứ trên ô đen; nó quay sang trái, tô màu ô thành tr n

ắ g, r i

ồ ti n

ế bư c

ớ .

Vì nh ng

ữ quy lu t

ậ này r t

ấ đ n

ơ gi n

ả nên b n

ạ s

ẽ trông đ i

ợ r ng

ằ con ki n

ế này s

ẽ làm nh ng

ữ đi u

ề đ n

ơ gi n

ả

như ch y

ạ vòng quanh ho c

ặ l p

ặ l i

ạ m t

ộ m u

ẫ hình đ n

ơ gi n

ả . Song n u

ế ki n

ế ta b t

ắ đ u

ầ trên lư i

ớ ô toàn

màu tr ng

ắ thì nó sẽ đi h n

ơ 10000 bư c

ớ theo m t

ộ d ng

ạ m u

ẫ tư ng

ở nh

ư ng u

ẫ nhiên trư c

ớ khi vào m t

ộ

vòng l p

ặ g m

ồ 104 bư c

ớ .

B n

ạ có thể đ c

ọ thêm v

ề con ki n

ế Langton t i

ạ http://en.wikipedia.org/wiki/Langton_ant.

Thật không d

ễ l p

ậ nên con ki n

ế Langton trong GridWorld vì ta không th

ể đ t

ặ màu c a

ủ các ô. Song thay

vào đó, ta có th

ể dùng nh ng

ữ bông hoa đ

ể đánh d u

ấ ô. Có đi u

ề là ta không th

ể có đ ng

ồ th i

ờ c

ả ki n

ế l n

ẫ

hoa trên cùng m t

ộ ô, nên ta không hoàn toàn th c

ự hi n

ệ đúng đư c

ợ nh ng

ữ quy lu t

ậ v i

ớ con ki n.

ế

Thay vào đó ta s

ẽ t o

ạ nên m t

ộ con m i

ố có tên LangtonTermite, trong đó dùng seeFlower để kiểm tra xem ô trư c

ớ m t

ặ có bông hoa không, và n u

ế ô trư c

ớ m t

ặ có bông hoa, thì dùng pickUpFlower để hái nó,

và throwFlower để đ t

ặ hoa xuống ô k

ế ti p.

ế B n

ạ có th

ể s

ẽ mu n

ố đ c

ọ mã l nh

ệ c a

ủ nh ng

ữ phư ng

ơ th c

ứ

này đ

ể ch c

ắ r ng

ằ chúng làm gì.

10.3 Bài t p

ậ

Bài t p

ậ 1 Bây gi

ờ b n

ạ đã bi t

ế đ

ủ ki n

ế th c

ứ đ

ể làm bài t p

ậ trong cu n

ố Sách bài t p

ậ (Student Manual),

Ph n

ầ 2. Hãy làm nh ng

ữ bài này, r i

ồ xem ti p

ế nh ng

ữ bài lý thú dư i

ớ đây.

Bài t p

ậ 2 M c

ụ đích c a

ủ bài t p

ậ này là khám phá bi u

ể hi n

ệ c a

ủ các con m i

ố khi tư ng

ơ tác v i

ớ nh ng

ữ

bông hoa. Hãy s a

ử ch a

ữ TermiteRunner.java để t o

ạ nên nh ng

ữ MyTermite thay vì các Termite. Sau đó

ch y

ạ l i

ạ . MyTermite sẽ ch y

ạ vòng quanh một cách ngẫu nhiên, làm d c

ị h chuy n

ể nh ng

ữ bông hoa. T ng

ổ

số bông hoa ph i

ả không đ i

ổ (k

ể c

ả nh ng

ữ mông mà MyTermite đang giữ). Trong cu n

ố “Termites,

Turtles and Traffic Jams”, Mitchell Resnick đã mô t

ả m t

ộ mô hình đ n

ơ gi n

ả cho bi u

ể hi n

ệ c a

ủ con m i

ố :

• Nếu b n

ạ th y

ấ bông hoa, hãy nh t

ặ nó lên. Tr

ừ khi b n

ạ đã có hoa r i

ồ ; trong trư ng

ờ h p

ợ này thì v t

ứ b

ỏ

bông hoa hi n

ệ có.

• Ti n

ế bư c

ớ , n u

ế có th .

ể

• Quay sang trái ho c

ặ ph i

ả m t

ộ cách ng u

ẫ nhiên.

Hãy s a

ử ch a

ữ MyTermite.java để thực hi n

ệ mô hình này. Theo b n

ạ thì thay đ i

ổ trên s

ẽ có hi u

ệ ng

ứ gì

đối với bi u

ể hi n

ệ c a

ủ các MyTermite?

Hãy th

ử ch y

ạ chư ng

ơ trình. M t

ộ l n

ầ n a

ữ , t ng

ổ s

ố bông hoa không đ i

ổ , nh ng

ư d n

ầ d n

ầ hoa s

ẽ t

ụ l i

ạ

thành một số ít các đ ng

ố , nhi u

ề khi ch ỉlà m t

ộ đ ng

ố .

Bi u

ể hi n

ệ này là m t

ộ thu c

ộ tính n i

ổ , mà b n

ạ có thể tham kh o

ả

ở http://en.wikipedia.org/wiki/Emergence. Các con MyTermite tuân theo nh ng ữ quy t c

ắ đ n

ơ gi n

ả ch ỉ

b n

ằ g thông tin quy mô nh ,

ỏ song k t

ế qu

ả s

ẽ là s

ự t

ổ ch c

ứ có quy mô l n.

ớ

Hãy th

ử nghi m

ệ v i

ớ nh ng

ữ quy t c

ắ khác nhau và xem chúng có tác đ ng

ộ gì lên h

ệ th ng

ố . Nh ng

ữ thay

đổi nhỏ có th

ể gây nên k t

ế qu

ả không lư ng

ờ trư c

ớ !

Bài t p

ậ 3

1. Sao chép l i

ạ file Termite.java rồi đ t

ặ tên thành LangtonTermite và sao

chép TermiteRunner.java thành LangtonRunner.java. Hãy s a

ử ch a

ữ sao cho nh ng

ữ đ nh

ị nghĩa l p

ớ có

tên trùng v i

ớ tên file, và do đó LangtonRunner t o

ạ nên một LangtonTermite.

2. Nếu b n

ạ t o

ạ một file tên là LangtonTermite.gif, GridWorld sẽ dùng nó đ

ể bi u

ể di n

ễ cho Termite c a

ủ

b n.

ạ B n

ạ có th

ể t i

ả v

ề nh ng

ữ nh

ả côn trùng đ p

ẹ

từ http://www.cksinfo.com/animals/insects/realisticdrawings/index.html. Để chuy n ể chúng về d n

ạ g

GIF, b n

ạ có th

ể dùng m t

ộ ng

ứ d ng

ụ nh

ư ImageMagick.

3. Sửa chữa act để thực hi n

ệ nh ng

ữ quy t c

ắ tư ng

ơ t

ự cho ki n

ế Langton. Hãy th

ử nh ng

ữ quy t c

ắ khác nhau,

và v i

ớ c

ả hai góc quay 45 và 90 đ .

ộ Hãy tìm nh ng

ữ quy t c

ắ đ

ể ch y

ạ đư c

ợ nhi u

ề ô nh t

ấ trư c

ớ khi con m i

ố

b t

ắ đầu ch y

ạ vòng.

4. Để cho mối có đ

ủ ch

ỗ ch y

ạ , b n

ạ có th

ể n i

ớ r ng

ộ lư i

ớ ô hay chuy n

ể sang dùng m t

ộ UnboundedGrid.

5. T o

ạ nên nhi u

ề con LangtonTermite rồi xem chúng tư ng

ơ tác nh

ư th

ế nào.

Ch

ng

ươ 11: T

ự t o

ạ nên nh ng

ữ đ i

ố t ng

ượ riêng

Trở về M c

ụ l c

ụ cuốn sách 11.1 L i đ

ờ

nh

ị

nghĩa l p v

ớ

à các ki u đ

ể

i t

ố ư n

ợ g

Trở về t n

ậ M c

ụ 1.5 khi chúng ta đ n

ị h nghĩa l p

ớ Hello, ta đồng th i

ờ t o

ạ nên m t

ộ ki u

ể đ i

ố tư ng

ợ có

tên Hello. Ta không t o

ạ nên bi n

ế nào thu c

ộ ki u

ể Hello này, và cũng không dùng new để t o

ạ ra đối

tượng Hello nào, song vi c

ệ đó là hoàn toàn có th !

ể

Ví d

ụ đó ch n

ẳ g có m y

ấ tác d ng

ụ minh h a

ọ , b i

ở không lý gì đ

ể ta t o

ạ ra m t

ộ đ i

ố tư ng

ợ Hello như v y

ậ , và

dù có t o

ạ nên thì cũng ch ng

ả đ

ể làm gì. Trong chư ng

ơ này, ta s

ẽ xét đ n

ế nh ng

ữ đ nh

ị nghĩa l p

ớ đ

ể t o

ạ

nên các ki u

ể đ i

ố tư ng

ợ có ích.

Sau đây là nh ng

ữ ý tư ng

ở quan tr ng

ọ nh t

ấ trong chư ng

ơ :

•Việc đ nh

ị nghĩa m t

ộ l p

ớ m i

ớ đ ng

ồ th i

ờ cũng t o

ạ nên m t

ộ đ i

ố tư ng

ợ m i

ớ cùng tên.

•Lời đ nh

ị nghĩa l p

ớ cũng gi ng

ố nh

ư m t

ộ b n

ả m u

ẫ cho các đ i

ố tư ng

ợ : nó quy đ nh

ị nh ng

ữ bi n

ế th c

ự th

ể

nào mà đ i

ố tư ng

ợ đó ch a

ứ đ ng

ự , và nh ng

ữ phư ng

ơ th c

ứ nào có th

ể ho t

ạ đ ng

ộ v i

ớ chúng.

•M i

ỗ đ i

ố tư ng

ợ thu c

ộ v

ề m t

ộ ki u

ể đ i

ố tư ng

ợ nào đó; nh

ư v y

ậ , nó là m t

ộ th c

ự th

ể c a

ủ m t

ộ l p

ớ nào đó.

•Khi b n

ạ kích ho t

ạ new để t o

ạ nên một đối tư ng

ợ , Java kích ho t

ạ m t

ộ phư ng

ơ th c

ứ đ c

ặ bi t

ệ có tên

là constructor để khởi t o

ạ các bi n

ế th c

ự th .

ể B n

ạ c n

ầ cung c p

ấ m t

ộ ho c

ặ nhi u

ề constructor trong l i

ờ

đ nh

ị nghĩa l p.

ớ

•Các phương thức thao tác trên m t

ộ ki u

ể đư c

ợ đ n

ị h nghĩa trong l i

ờ đ nh

ị nghĩa l p

ớ cho ki u

ể đó.

Sau đây là m t

ộ s

ố v n

ấ đ

ề v

ề l i

ờ đ nh

ị nghĩa l p:

ớ

•Tên l p

ớ (và do đó, tên c a

ủ ki u

ể đ i

ố tư ng

ợ ) nên b t

ắ đ u

ầ bàng m t

ộ ch

ữ in, đ

ể phân bi t

ệ chúng v i

ớ các

kiểu nguyên th y

ủ và nh ng

ữ tên bi n.

ế

•B n

ạ thường đ t

ặ một l i

ờ đ nh

ị nghĩa l p

ớ vào trong m i

ỗ file, và tên c a

ủ file ph i

ả gi ng

ố nh

ư tên c a

ủ l p,

ớ

với ph n

ầ m

ở r ng

ộ .java. Ch n

ẳ g h n,

ạ l p

ớ Time đư c

ợ đ nh

ị nghĩa trong file có tên Time.java.

•

Ở b t

ấ kì chương trình nào, luôn có m t

ộ l p

ớ đư c

ợ giao làm l p

ớ kh i

ở đ n

ộ g. Lớp kh i

ở động ph i

ả ch a

ứ

một phương th c

ứ mang tên main, đó là n i

ơ mà vi c

ệ th c

ự thi chư ng

ơ trình b t

ắ đ u

ầ . Các l p

ớ khác cũng có

thể chứa phư ng

ơ th c

ứ cùng tên main, song phương th c

ứ đó s

ẽ không đư c

ợ th c

ự thi t

ừ đ u

ầ .

Khi đã nêu nh ng

ữ v n

ấ đ

ề này r i

ồ , ta hãy xét m t

ộ ví d

ụ v

ề l p

ớ do ngư i

ờ dùng đ nh

ị nghĩa, l p

ớ Time.

11.2 Time

Một động lực chung cho vi c

ệ t o

ạ nên ki u

ể đ i

ố tư ng

ợ , đó là đ

ể gói g n

ọ nh ng

ữ d

ữ li u

ệ liên quan vào trong

một đ i

ố tư ng

ợ để ta có th

ể coi nh

ư m t

ộ đ n

ơ v ịduy nh t

ấ . Ta đã g p

ặ hai ki u

ể nh

ư v y

ậ , đó

là Point và Rectangle.

Một ví dụ khác, mà ta s

ẽ t

ự tay l p

ậ nên, là Time, để bi u

ể di n

ễ gi

ờ đồng h .

ồ D

ữ li u

ệ đư c

ợ gói trong m t

ộ

đối tượng Time bao g m

ồ có s

ố gi ,

ờ s

ố phút, và s

ố giây. B i

ở m i

ỗ đ i

ố tư ng

ợ Time đều ch a

ứ nh ng

ữ d

ữ li u

ệ

này, nên ta c n

ầ bi n

ế th c

ự thể đ

ể l u

ư gi

ữ chúng.

Bước đ u

ầ tiên là xác đ n

ị h xem t ng

ừ bi n

ế ph i

ả thu c

ộ ki u

ể gì. Dư ng

ờ nh

ư rõ ràng là hour (giờ)

và minute (phút) đ u

ề ph i

ả là nh ng

ữ s

ố nguyên. Đ

ể cho v n

ấ đ

ề đư c

ợ thú v ịh n,

ơ ta hãy đ t

ặ second (giây)

là một double.

Các bi n

ế th c

ự th

ể đư c

ợ đ nh

ị nghĩa

ở đo n

ạ đ u

ầ c a

ủ l i

ờ khai báo l p,

ớ bên ngoài b t

ấ kì l i

ờ khai báo phư ng

ơ

thức nào khác, nh

ư sau:

class Time {

int hour, minute;

double second;

}

Đo n

ạ mã này t

ự b n

ả thân nó đã là l i

ờ khai báo l p

ớ h p

ợ l .

ệ S

ơ đ

ồ tr n

ạ g thái cho m t

ộ đ i

ố tư ng

ợ Time sẽ

trông nh

ư sau:

Sau khi khai báo các bi n

ế th c

ự th ,

ể bư c

ớ ti p

ế theo là đ nh

ị nghĩa m t

ộ constructor cho l p

ớ m i

ớ này.

11.3 Constructor

Các constructor có nhi m

ệ v

ụ kh i

ở t o

ạ các bi n

ế th c

ự th .

ể Cú pháp c a

ủ constructor cũng gi ng

ố nh

ư c a

ủ các

phương th c

ứ khác, tr

ừ ba đi m

ể sau:

•Tên c a

ủ constructor ph i

ả gi ng

ố nh

ư tên l p.

ớ

•Constructor không có ki u

ể tr

ả v

ề và cũng không có giá tr ịtr

ả v .

ề

•Từ khoá static được b

ỏ qua.

Sau đây là m t

ộ ví d

ụ cho l p

ớ Time:

public Time() {

this.hour = 0;

this.minute = 0;

this.second = 0.0;

}

Ở chỗ mà b n

ạ trông đ i

ợ m t

ộ ki u

ể tr

ả v ,

ề gi a

ữ public and Time, l i

ạ không có gì c .

ả Đi u

ề đó cho th y

ấ cách

mà chúng ta (và trình biên d c

ị h n a

ữ ) có th

ể phân bi t

ệ đư c

ợ r ng

ằ đây là m t

ộ constructor.

Constructor này không nh n

ậ tham s

ố nào. M i

ỗ dòng c a

ủ constructor kh i

ở t o

ạ m t

ộ bi n

ế th c

ự th

ể cho

một giá tr ịm c

ặ đ nh

ị (trong trư ng

ờ h p

ợ này là n a

ử đêm). Cái tên this là một từ khóa đ c

ặ bi t

ệ đ

ể tham

chi u

ế tới đối tư ng

ợ mà ta đang t o

ạ nên. B n

ạ có th

ể dùng this theo cách giống nh

ư dùng tên c a

ủ b t

ấ kì

đối tượng nào khác. Ch ng

ẳ h n,

ạ b n

ạ có th

ể đ c

ọ và ghi các bi n

ế th c

ự th

ể c a

ủ this, và cũng truy n

ề

được this với vai trò tham s

ố đ n

ế nh ng

ữ phư ng

ơ th c

ứ khác.

Nhưng b n

ạ không khai báo cái this này và cũng không th

ể gán giá tr ịcho nó. this đư c

ợ t o

ạ b i

ở h

ệ thống;

tất c

ả những gì b n

ạ ph i

ả làm đó là kh i

ở t o

ạ các bi n

ế th c

ự th

ể c a

ủ nó.

Một lỗi thường g p

ặ khi vi t

ế ra constructor là vi c

ệ đ a

ư câu l nh

ệ return vào cuối. Hãy ki m

ề ch ,

ế tránh

làm vi c

ệ này.

11.4 Thêm các constructor

Constructor có th

ể đư c

ợ ch ng

ồ ch t

ấ [xem thêm ph n

ầ "Quá t i

ả "], cũng nh

ư các phư ng

ơ th c

ứ khác, theo

nghĩa b n

ạ có th

ể có nhi u

ề constructor v i

ớ các tham s

ố khác nhau. Java bi t

ế rõ c n

ầ ph i

ả kích ho t

ạ

constructor nào b ng

ằ cách kh p

ớ nh ng

ữ tham s

ố c a

ủ new với các tham s

ố c a

ủ constructor.

Việc có constructor không nh n

ậ đ i

ố s

ố (như trên) là hoàn toàn bình thư ng

ờ , cũng nh

ư constructor nh n

ậ

một danh sách tham s

ố gi ng

ố h t

ệ v i

ớ danh sách các bi n

ế th c

ự th .

ể Ch n

ẳ g h n:

ạ

public Time(int hour, int minute, double second) {

this.hour = hour;

this.minute = minute;

this.second = second;

}

Các tên và ki u

ể c a

ủ nh ng

ữ tham s

ố cũng gi ng

ố v i

ớ tên và ki u

ể c a

ủ các bi n

ế th c

ự th .

ể T t

ấ c

ả nh ng

ữ gì mà

constructor này làm ch ỉlà sao chép thông tin t

ừ các tham s

ố sang các bi n

ế th c

ự th .

ể

Nếu xem tài li u

ệ về Point và Rectangle, b n

ạ s

ẽ th y

ấ r ng

ằ c

ả hai l p

ớ này đ u

ề có nh ng

ữ constructor ki u

ể

như trên. Vi c

ệ ch ng

ồ ch t

ấ constructor cho phép linh ho t

ạ t o

ạ nên đ i

ố tư ng

ợ trư c

ớ r i

ồ sau đó m i

ớ đi n

ề

vào ph n

ầ trống, ho c

ặ đ

ể thu th p

ậ toàn b

ộ thông tin trư c

ớ khi l p

ậ ra đ i

ố tư ng

ợ .

Đi u

ề này nghe thì có v

ẻ không đáng quan tâm, song th c

ự ra thì khác. Vi c

ệ vi t

ế nh ng

ữ constructor là quá

trình máy móc, bu n

ồ t .

ẻ M t

ộ khi b n

ạ đã vi t

ế đư c

ợ hai constructor r i

ồ , b n

ạ s

ẽ th y

ấ r ng

ằ mình có th

ể vi t

ế

chúng nhanh chóng ch ỉqua vi c

ệ trông vào danh sách các bi n

ế th c

ự th .

ể

11.5 T o

ạ nên đ i

ố tư ng m

ợ

i

ớ

M c

ặ dù trông gi ng

ố nh

ư phư ng

ơ th c

ứ , song constructor không bao gi

ờ đư c

ợ kích ho t

ạ tr c

ự ti p.

ế Thay vì

v y

ậ , khi b n

ạ kích ho t

ạ new, h

ệ thống s

ẽ huy đ ng

ộ dung lư ng

ợ b

ộ nh

ớ cho đ i

ố tư ng

ợ m i

ớ và kích ho t

ạ

constructor này.

Chương trình sau gi i

ớ thi u

ệ hai cách làm đ

ể l p

ậ thành và kh i

ở t o

ạ các đ i

ố tư ng

ợ Time:

class Time {

int hour, minute;

double second;

public Time() {

this.hour = 0;

this.minute = 0;

this.second = 0.0;

}

public Time(int hour, int minute, double second) {

this.hour = hour;

this.minute = minute;

this.second = second;

}

public static void main(String[] args) {

// một cách lập thành và khởi tạo đối tượng Time Time t1 = new Time();

t1.hour = 11;

t1.minute = 8;

t1.second = 3.14159;

System.out.println(t1);

// một cách khác để thực hiện việc tương tự

Time t2 = new Time(11, 8, 3.14159);

System.out.println(t2);

}

}

Trong main, l n

ầ đ u

ầ tiên kích ho t

ạ new, ta không c p

ấ cho đ i

ố s

ố nào, b i

ở v y

ậ Java kích ho t

ạ constructor

thứ nh t

ấ . Vài dòng phía dư i

ớ th c

ự hi n

ệ gán giá tr ịcho các bi n

ế th c

ự th .

ể

L n

ầ thứ hai kích ho t

ạ new, ta c p

ấ các đ i

ố s

ố kh p

ớ v i

ớ các tham s

ố c a

ủ constructor th

ứ hai. Cách kh i

ở t o

ạ

bi n

ế thực th

ể này g n

ọ gàng h n

ơ và hi u

ệ qu

ả h n

ơ m t

ộ chút, song cách làm này có th

ể khó đ c

ọ , b i

ở nó

không rõ ràng là giá tr ịnào đư c

ợ gán cho bi n

ế th c

ự th

ể nào.

11.6 In các đ i t

ố ư n

ợ g

Kết qu

ả c a

ủ chư ng

ơ trình nêu trên là:

Time@80cc7c0

Time@80cc807

Khi Java in giá tr ịc a

ủ ki u

ể đ i

ố tư ng

ợ do ngư i

ờ dùng đ nh

ị nghĩa, nó s

ẽ in tên ki u

ể cùng m t

ộ mã th p

ậ l c

ụ

phân đ c

ặ bi t

ệ riêng c a

ủ t ng

ừ đ i

ố tư ng

ợ . Mã này b n

ả thân nó ch ng

ẳ có ý nghĩa gì; th c

ự t

ế nó khác nhau

tuỳ máy tính và th m

ậ chí tuỳ c

ả nh ng

ữ l n

ầ ch y

ạ chư ng

ơ trình. Nh ng

ư có th

ể nó giúp ích cho vi c

ệ g

ỡ l i

ỗ ,

trong trường hợp b n

ạ muốn theo dõi t ng

ừ đ i

ố tư ng

ợ riêng r .

ẽ

Để in các đ i

ố tư ng

ợ theo cách có ý nghĩa h n

ơ đ i

ố v i

ớ ngư i

ờ dùng (ch

ứ không ph i

ả đ i

ố v i

ớ l p

ậ trình

viên), b n

ạ có th

ể vi t

ế m t

ộ phư ng

ơ th c

ứ v i

ớ tên g i

ọ ki u

ể như printTime:

public static void printTime(Time t) {

System.out.println(t.hour + ":" + t.minute + ":" + t.second);

}

Hãy so sánh phư ng

ơ th c

ứ này v i

ớ phiên b n

ả printTime ở M c

ụ 3.10.

Kết qu

ả c a

ủ phư ng

ơ th c

ứ này, n u

ế ta truy n

ề t1 ho c

ặ t2 làm đối số, s

ẽ là 11:8:3.14159. M c

ặ dù ta có th

ể

nh n

ậ ra đây là gi

ờ đ ng

ồ h ,

ồ nh ng

ư cách vi t

ế này không h

ề theo chu n

ẩ quy đ nh

ị . Ch ng

ẳ h n

ạ , n u

ế s

ố phút

ho c

ặ số giây nh

ỏ h n

ơ 10, ta sẽ luôn d

ự ki n

ể r ng

ằ có số 0 đi trư c

ớ . Ngoài ra, có th

ể ta còn mu n

ố b

ỏ ph n

ầ

th p

ậ phân c a

ủ số giây đi. Nói cách khác, ta mu n

ố k t

ế qu

ả ki u

ể như 11:08:03.

Trong đa s

ố nh ng

ữ ngôn ng

ữ l p

ậ trình, có nhi u

ề cách đ n

ơ gi n

ả đ

ể đi u

ề khi n

ể đ nh

ị d ng

ạ đ u

ầ ra cho k t

ế

quả số. Trong Java thì không có cách đ n

ơ gi n

ả nào.

Java có nh ng

ữ công c

ụ m nh

ạ dành cho vi c

ệ in d

ữ li u

ệ đư c

ợ đ nh

ị d n

ạ g nh

ư gi

ờ đ ng

ồ h

ồ và ngày tháng,

đồng thời cũng có công c

ụ đ

ể di n

ễ gi i

ả d

ữ li u

ệ vào đư c

ợ đ nh

ị d ng

ạ . Song th t

ậ không may là nh ng

ữ công

c

ụ như v y

ậ không d

ễ s

ử d n

ụ g, nên tôi s

ẽ b

ỏ qua chúng trong khuôn kh

ổ cu n

ố sách này. N u

ế mu n,

ố b n

ạ

có th

ể xem qua tài li u

ệ c a

ủ l p

ớ Date trong gói java.util.

11.7 Các thao tác v i đ

ớ

i t

ố ư ng

ợ

Trong một vài m c

ụ ti p

ế theo, tôi s

ẽ gi i

ớ thi u

ệ ba d ng

ạ phư ng

ơ th c

ứ ho t

ạ đ ng

ộ trên các đ i

ố tư ng

ợ :

hàm thu n

ầ tuý:

Nh n

ậ các đ i

ố t n

ượ g làm tham s

ố nh ng

ư không thay đ i

ổ chúng. Giá tr ịtr

ả l i

ạ thu c

ộ ki u

ể nguyên thu

ỷ

hoặc m t

ộ đ i

ố t n

ượ g m i

ớ t o

ạ ra bên trong ph ng

ươ th c

ứ này.

phư n

ơ g th c

ứ s a

ử đ i

ổ :

Nhận đ i

ố s

ố là các đ i

ố t ng

ượ r i

ồ s a

ử đ i

ổ m t

ộ vài, ho c

ặ t t

ấ c

ả nh ng

ữ đ i

ố t ng

ượ đó. Th ng

ườ tr

ả l i

ạ

đ i

ố t ng

ượ r ng

ỗ (void).

phư n

ơ g th c

ứ đi n

ề :

Một trong các đ i

ố số là đ i

ố t ng

ượ “tr ng

ố tr n

ơ ” s

ẽ đư c

ợ ph ng

ươ th c

ứ đi n

ề thông tin vào. V

ề m t

ặ kĩ

thu t

ậ , đây cũng chính là m t

ộ dang ph ng

ươ th c

ứ s a

ử đ i

ổ .

Với một phương th c

ứ cho trư c

ớ ta thư ng

ờ có th

ể vi t

ế nó dư i

ớ d n

ạ g hàm thu n

ầ túy, phư ng

ơ th c

ứ s a

ử đ i

ổ

hay phương th c

ứ đi n.

ề Tôi s

ẽ bàn thêm v

ề u

ư như c

ợ đi m

ể c a

ủ t ng

ừ hình th c

ứ m t

ộ .

11.8 Các hàm thu n t

ầ

úy

Một phương th c

ứ đư c

ợ coi là hàm thu n

ầ túy n u

ế nh

ư k t

ế qu

ả ch ỉph

ụ thu c

ộ vào các đ i

ố s ,

ố và phư ng

ơ

thức này không có hi u

ệ ng

ứ ph

ụ nh

ư thay đ i

ổ m t

ộ đ i

ố s

ố ho c

ặ in ra thông tin gì. k t

ế qu

ả duy nh t

ấ c a

ủ

việc kích ho t

ạ m t

ộ hàm thu n

ầ túy, đó là giá tr ịtr

ả l i

ạ .

Một ví dụ là isAfter, đ

ể so sánh hai đ i

ố tư ng

ợ Time rồi tr

ả l i

ạ một boolean để ch ỉđ nh

ị xem li u

ệ toán

h n

ạ g thứ nh t

ấ có x p

ế trư c

ớ toán h ng

ạ th

ứ hai hay không:

public static boolean isAfter(Time time1, Time time2) {

if (time1.hour > time2.hour)

return true;

if (time1.hour < time2.hour)

return false;

if (time1.minute > time2.minute)

return true;

if (time1.minute < time2.minute)

return false;

if (time1.second > time2.second)

return true;

return false;

}

Kết qu

ả c a

ủ phư ng

ơ th c

ứ này s

ẽ là gì n u

ế hai th i

ờ gian đã cho b n

ằ g nhau? Li u

ệ đó có ph i

ả là k t

ế qu

ả

phù hợp đối v i

ớ phư ng

ơ th c

ứ này không? N u

ế b n

ạ vi t

ế tài li u

ệ cho phư ng

ơ th c

ứ này, li u

ệ b n

ạ có đ

ề c p

ậ

rõ đ n

ế trư ng

ờ h p

ợ đó không?

Ví d

ụ thứ hai là addTime, phương thức tính tổng hai th i

ờ gian. Ch n

ẳ g h n,

ạ n u

ế bây gi

ờ là 9:14:30, và

người làm bánh c n

ầ 3 gi

ờ 35 phút, thì b n

ạ có th

ể dùng addTime để hình dung ra khi nào bánh ra lò.

Sau đây là b n

ả s

ơ th o

ả c a

ủ phư ng

ơ th c

ứ này; nó ch a

ư th t

ậ đúng:

public static Time addTime(Time t1, Time t2) {

Time sum = new Time();

sum.hour = t1.hour + t2.hour;

sum.minute = t1.minute + t2.minute;

sum.second = t1.second + t2.second;

return sum;

}

M c

ặ dù phư ng

ơ th c

ứ này tr

ả l i

ạ m t

ộ đ i

ố tư ng

ợ Time, song nó không ph i

ả là constructor. B n

ạ c n

ầ xem

l i

ạ và so sánh cú pháp c a

ủ m t

ộ phư ng

ơ th c

ứ d ng

ạ này v i

ớ cú pháp c a

ủ m t

ộ constructor, vì chúng d

ễ gây

nhầm l n.

ẫ

Sau đây là m t

ộ ví d

ụ v

ề cách dùng phư ng

ơ th c

ứ . N u

ế như currentTime chứa th i

ờ gian hi n

ệ t i

ạ

và breadTime chứa th i

ờ gian c n

ầ đ

ể ngư i

ờ th

ợ nư ng

ớ bánh, thì b n

ạ có th

ể dùng addTime để hình dung

ra khi nào s

ẽ nư ng

ớ xong bánh.

Time currentTime = new Time(9, 14, 30.0);

Time breadTime = new Time(3, 35, 0.0);

Time doneTime = addTime(currentTime, breadTime);

printTime(doneTime);

Kết qu

ả c a

ủ chư ng

ơ trình, 12:49:30.0, là đúng. Mặt khác, cũng có nh ng

ữ trư ng

ờ h p

ợ mà k t

ế qu

ả không

đúng. B n

ạ có đoán đư c

ợ m t

ộ trư ng

ờ h p

ợ nh

ư v y

ậ không?

V n

ấ đ

ề là

ở chỗ phư ng

ơ th c

ứ này không x

ử lý đư c

ợ tình hu ng

ố khi s

ố giây ho c

ặ s

ố phút c ng

ộ l i

ạ vư t

ợ

quá 60. Trong trư ng

ờ h p

ợ đó, ta ph i

ả “nh ”

ớ s

ố giây còn d

ư vào c t

ộ s

ố phút, ho c

ặ nh

ớ s

ố phút d

ư vào c t

ộ

giờ.

Sau đây là m t

ộ d n

ạ g đúng c a

ủ phư ng

ơ th c

ứ này.

public static Time addTime(Time t1, Time t2) {

Time sum = new Time();

sum.hour = t1.hour + t2.hour;

sum.minute = t1.minute + t2.minute;

sum.second = t1.second + t2.second;

if (sum.second >= 60.0) {

sum.second -= 60.0;

sum.minute += 1;

}

if (sum.minute >= 60) {

sum.minute -= 60;

sum.hour += 1;

}

return sum;

}

M c

ặ dù cách này đúng, song chư ng

ơ trình b t

ắ đ u

ầ dài dòng. Sau này tôi s

ẽ g i

ợ ý m t

ộ gi i

ả pháp khác

ng n

ắ hơn nhi u

ề .

Đo n

ạ mã l nh

ệ trên gi i

ớ thi u

ệ hai toán t

ử mà ta ch a

ư t ng

ừ g p

ặ , += và -=. Những toán t

ử này cho ta vi t

ế

ng n

ắ gọn l nh

ệ tăng ho c

ặ gi m

ả bi n.

ế Chúng cũng g n

ầ gi ng

ố như ++ và --, ch ỉkhác

ở ch

ỗ (1) chúng làm

việc được c

ả với double l n

ẫ int, và (2) lư ng

ợ tăng ho c

ặ gi m

ả không nh t

ấ thi t

ế b ng

ằ 1. Câu

lệnh sum.second -= 60.0; tương đương với sum.second = sum.second - 60; 11.9 Phư ng t

ơ

h c s

ứ

a đ

ử

i

ổ

Xét một ví dụ v

ề phư ng

ơ th c

ứ s a

ử đ i

ổ , phư ng

ơ th c

ứ increment, nhằm tăng thêm một số giây cho trư c

ớ

vào một đ i

ố tư ng

ợ Time. Một l n

ầ n a

ữ , ta có b n

ả nháp phư ng

ơ th c

ứ này nh

ư sau:

public static void increment(Time time, double secs) {

time.second += secs;

if (time.second >= 60.0) {

time.second -= 60.0;

time.minute += 1;

}

if (time.minute >= 60) {

time.minute -= 60;

time.hour += 1;

}

}

Dòng đ u

ầ tiên th c

ự hi n

ệ thao tác c

ơ b n;

ả nh ng

ữ dòng còn l i

ạ đ

ể x

ử lý các trư ng

ờ h p

ợ ta đã xét.

Liệu phương thức này có đúng không? Đi u

ề gì s

ẽ x y

ả ra n u

ế đ i

ố số secs lớn hơn nhi u

ề so v i

ớ 60? Trong

trường hợp như v y

ậ , tr

ừ đi 60 m t

ộ l n

ầ là ch a

ư đ ;

ủ ta ph i

ả ti p

ế t c

ụ tr

ừ đ n

ế khi second nhỏ hơn 60. Ta có

thể làm đi u

ề này b n

ằ g cách thay các l nh

ệ if b n

ằ g các l nh

ệ while:

public static void increment(Time time, double secs) {

time.second += secs;

while (time.second >= 60.0) {

time.second -= 60.0;

time.minute += 1;

}

while (time.minute >= 60) {

time.minute -= 60;

time.hour += 1;

}

}

Gi i

ả pháp này đúng đ n,

ắ nh ng

ư ch a

ư hi u

ệ qu

ả l m

ắ . B n

ạ có th

ể nghĩ ra l i

ờ gi i

ả nào không c n

ầ đ n

ế tính

l p

ặ hay không?

11.10 Các phương th c đ

ứ

i n

ề

Thay vì vi c

ệ t o

ạ nên đ i

ố tư ng

ợ m i

ớ m i

ỗ khi addTime được kích ho t

ạ , ta có th

ể yêu c u

ầ chư ng

ơ trình g i

ọ

hãy cung c p

ấ m t

ộ đ i

ố tư ng

ợ n i

ơ màaddTime lưu kết quả. Hãy so sánh đo n

ạ mã sau v i

ớ phiên b n

ả trư c

ớ :

public static void addTimeFill(Time t1, Time t2, Time sum) {

sum.hour = t1.hour + t2.hour;

sum.minute = t1.minute + t2.minute;

sum.second = t1.second + t2.second;

if (sum.second >= 60.0) {

sum.second -= 60.0;

sum.minute += 1;

}

if (sum.minute >= 60) {

sum.minute -= 60;

sum.hour += 1;

}

}

Kết qu

ả đư c

ợ l u

ư trong sum, nên ki u

ể tr

ả v

ề là void.

Các phương th c

ứ s a

ử đ i

ổ và phư ng

ơ th c

ứ đi n

ề đ u

ề hi u

ệ qu

ả vì chúng không ph i

ả t o

ạ nên đ i

ố tư ng

ợ m i

ớ .

Nhưng chúng l i

ạ gây khó khăn trong vi c

ệ cô l p

ậ các ph n

ầ khác nhau c a

ủ chư ng

ơ trình; trong nh ng

ữ d

ự

án l n

ớ chúng có th

ể gây nên l i

ỗ r t

ấ khó tìm ra.

Các hàm thu n

ầ túy giúp ta qu n

ả lý tính ch t

ấ ph c

ứ t p

ạ c a

ủ nh ng

ữ d

ự án l n,

ớ ph n

ầ là nh

ờ ngăn không cho

những lo i

ạ l i

ỗ nh t

ấ đ nh

ị không th

ể x y

ả ra. H n

ơ n a

ữ , hàm thu n

ầ túy còn thích h p

ợ v i

ớ nh ng

ữ ki u

ể l p

ậ

trình ghép và l ng

ồ . Và vì k t

ế qu

ả c a

ủ hàm thu n

ầ túy ch ỉph

ụ thu c

ộ vào tham s ,

ố ta có th

ể tăng t c

ố cho

nó b ng

ằ cách l u

ư gi

ữ nh ng

ữ giá tr ịđã tính toán t

ừ trư c

ớ .

Tôi g i

ợ ý r n

ằ g b n

ạ nên vi t

ế hàm thu n

ầ túy m i

ỗ lúc th y

ấ đư c

ợ , và ch ỉdùng đ n

ế phư ng

ơ th c

ứ s a

ử đ i

ổ khi

th y

ấ rõ u

ư đi m

ể vư t

ợ trội.

11.11 L p k

ậ

h

ế o ch

ạ và phát tri n t

ể

ăng d n

ầ

Trong chương trình này tôi gi i

ớ thi u

ệ m t

ộ quá trình phát tri n

ể chư ng

ơ trình v i

ớ tên g i

ọ l p

ậ nguyên

m u

ẫ nhanh1. Với từng phư ng ơ th c

ứ , tôi vi t

ế m t

ộ b n

ả s

ơ th o

ả để th c

ự hi n

ệ tính toán c

ơ b n,

ả r i

ồ ki m

ể

tra nó v i

ớ m t

ộ vài trư ng

ờ h p,

ợ s a

ử nh ng

ữ l i

ỗ b t

ắ g p

ặ đư c

ợ .

Cách ti p

ế c n

ậ này có th

ể hi u

ệ qu ,

ả song nó có th

ể d n

ẫ đ n

ế mã l nh

ệ ph c

ứ t p

ạ m t

ộ cách không c n

ầ thi t

ế —

vì nó x

ử lý quá nhi u

ề trư ng

ờ h p

ợ đ c

ặ bi t

ệ —và cũng kém tin c y

ậ —vì th t

ậ khó t

ự thuy t

ế ph c

ụ r n

ằ g b n

ạ đã

tìm th y

ấ tất cả những l i

ỗ trong chư ng

ơ trình.

Một cách khác là xem xét kĩ h n

ơ v n

ấ đ

ề nh m

ằ tìm m u

ấ ch t

ố có th

ể giúp vi c

ệ l p

ậ trình d

ễ dàng h n.

ơ

Trong trư ng

ờ h p

ợ này đi m

ể m u

ấ ch t

ố bên trong là: Time thực ra là một s

ố có ba ch

ữ s

ố trong h

ệ c

ơ s

ố

60! Số giây, second, là hàng đ n

ơ v ,ị s

ố phút, minute, là hàng 60, còn s

ố gi ,

ờ hour, là hàng 3600.

Khi ta vi t

ế addTime và increment, thực ch t

ấ là ta đang tính c ng

ộ

ở h

ệ 60; đó là lý do t i

ạ sao ta ph i

ả

“nhớ” từ hàng này sang hàng khác.

Một cách ti p

ế c n

ậ khác đ i

ố v i

ớ t ng

ổ th

ể bài toán là chuy n

ể Time thành double rồi l i

ợ d n

ụ g kh

ả năng

tính toán c a

ủ máy đ i

ố v i

ớ double. Sau đây là m t

ộ phư ng

ơ th c

ứ chuy n

ể đ i

ổ Time thành double:

public static double convertToSeconds(Time t) {

int minutes = t.hour * 60 + t.minute;

double seconds = minutes * 60 + t.second;

return seconds;

}

Bây gi

ờ tất c

ả nh ng

ữ gì ta c n

ầ là cách chuy n

ể từ double sang đối tượng Time. Ta có thể vi t

ế một phư ng

ơ

thức để thực hi n

ệ đi u

ề này, song có l

ẽ h p

ợ lý h n

ơ la vi t

ế m t

ộ constructor th

ứ ba:

public Time(double secs) {

this.hour =(int)(secs / 3600.0);

secs -= this.hour * 3600.0;

this.minute =(int)(secs / 60.0);

secs -= this.minute * 60;

this.second = secs;

}

Constructor này h i

ơ khác nh ng

ữ constructor khác; nó bao g m

ồ nh ng

ữ tính toán bên c nh

ạ phép gán cho

các bi n

ế th c

ự th .

ể

Có th

ể b n

ạ ph i

ả suy nghĩ đ

ể t

ự thuy t

ế ph c

ụ b n

ả thân r n

ằ g kĩ thu t

ậ mà tôi dùng đ

ể chuy n

ể t

ừ h

ệ c

ơ s

ố

này sang c

ơ s

ố kia là đúng. Nh ng

ư m t

ộ khi b n

ạ đã b ịthuy t

ế ph c

ụ r i

ồ , ta có th

ể dùng nh ng

ữ phư ng

ơ th c

ứ

này đ

ể vi t

ế l i

ạ addTime:

public static Time addTime(Time t1, Time t2) {

double seconds = convertToSeconds(t1) + convertToSeconds(t2); return new Time(seconds);

}

Mã lệnh trên ng n

ắ h n

ơ phiên b n

ả g c

ố , và d

ễ th y

ấ h n

ơ h n

ẳ r n

ằ g mã l nh

ệ này đúng đ n

ắ (v i

ớ gi

ả thi t

ế

thường lệ r n

ằ g những phư ng

ơ th c

ứ nó kích ho t

ạ cũng đ u

ề đúng). Vi c

ệ vi t

ế l i

ạ increment theo cách

tương tự được dành cho b n

ạ nh

ư một bài t p.

ậ

11.12 Khái quát hóa

Trong ch ng

ừ m c

ự nào đó, vi c

ệ chuy n

ể đ i

ổ qua l i

ạ gi a

ữ các h

ệ c

ơ s

ố 60 và 10 khó h n

ơ vi c

ệ x

ử lý th i

ờ gian

đơn thu n

ầ . Vi c

ệ chuy n

ể h

ệ c

ơ s

ố thì tr u

ừ tư ng

ợ h n,

ơ còn tr c

ự giác c a

ủ ta x

ử lý th i

ờ gian t t

ố h n.

ơ

Nhưng n u

ế ta có hi u

ể bi t

ế sâu đ

ể coi th i

ờ gian nh

ư các s

ố trong h

ệ 60, và đ u

ầ t

ư công s c

ứ vi t

ế nh ng

ữ

phương th c

ứ chuy n

ể đ i

ổ (convertToSeconds và constructor th

ứ ba), ta s

ẽ thu đư c

ợ m t

ộ chư ng

ơ trình

ng n

ắ hơn, d

ễ đọc và g

ỡ l i

ỗ , đ ng

ồ th i

ờ đáng tin c y

ậ h n.

ơ

Việc bổ sung các đ c

ặ tính sau này cũng d

ễ dàng h n.

ơ Hãy tư ng

ở tư ng

ợ ta c n

ầ tr

ừ hai đ i

ố tư ng

ợ Time để

tìm ra kho n

ả g th i

ờ gian gi a

ữ chúng. Cách làmth c

ự hi n

ệ tính tr

ừ có nh .

ớ Nh ng

ư dùng phư ng

ơ th c

ứ đ

ể

chuy n

ể đổi sẽ d

ễ h n

ơ nhi u

ề .

Đi u

ề trớ trêu là, đôi khi vi c

ệ làm cho bài toán khó h n

ơ (tổng quát h n)

ơ l i

ạ khi n

ế cho d

ễ dàng h n

ơ (ít

trường hợp đ c

ặ bi t

ệ , ít kh

ả năng gây ra l i

ỗ ).

11.13 Thu t

ậ toán

Khi b n

ạ vi t

ế một l i

ờ gi i

ả t ng

ổ quát cho m t

ộ l p

ớ các bài toán, thay vì tìm l i

ờ gi i

ả riêng cho m t

ộ bài toán

riêng l ,

ẻ b n

ạ đã vi t

ế m t

ộ thu t

ậ toán. Th t

ậ không d

ễ đ nh

ị nghĩa thu t

ậ ng

ữ này, b i

ở v y

ậ tôi s

ẽ c

ố g n

ắ g

thử vài cái ti p

ế c n

ậ khác nhau.

Trư c

ớ h t

ế , hãy xét m t

ộ s

ố th

ứ không ph i

ả là thu t

ậ toán. Khi b n

ạ h c

ọ tính nhân gi a

ữ hai s ,

ố có l

ẽ b n

ạ đã

ghi nhớ b n

ả cửu chư ng

ơ . Th t

ậ ra, b n

ạ đã h c

ọ thu c

ộ lòng 100 l i

ờ gi i

ả c

ụ th ,

ể b i

ở v y

ậ ki n

ế th c

ứ này th c

ự

sự không ph i

ả là thu t

ậ toán.

Nhưng n u

ế b n

ạ “lư i

ờ bi ng

ế ,” có th

ể b n

ạ đã h c

ọ h i

ỏ đư c

ợ m y

ấ m o

ẹ v t

ặ . Ch ng

ẳ h n,

ạ đ

ể tính tính c a

ủ m t

ộ

số n với 9, b n

ạ có thể vi t

ế n−1 là chữ số thứ nhất và 10− n là chữ số thứ hai. M o ẹ này là l i

ờ gi i

ả t ng

ổ quát

để nhân một số dư i

ớ mư i

ờ b t

ấ kì v i

ớ 9. Đó chính là thu t

ậ toán!

Tương tự, những kĩ thu t

ậ b n

ạ h c

ọ đ

ể c ng

ộ có nh ,

ớ tr

ừ có nh ,

ớ và phép chia s

ố l n

ớ đ u

ề là nh ng

ữ thu t

ậ

toán. Một trong nh ng

ữ đ c

ặ đi m

ể c a

ủ thu t

ậ toán là chúng không c n

ầ trí thông minh đ

ể th c

ự hi n.

ệ Chúng

ch ỉlà nh ng

ữ c

ơ ch

ế máy móc trong đó t ng

ừ bư c

ớ n i

ố ti p

ế nhau theo m t

ộ lo t

ạ nh ng

ữ nguyên t c

ắ đ n

ơ

gi n

ả .

Theo ý ki n

ế c a

ủ tôi, th t

ậ đáng ng i

ạ khi th y

ấ r n

ằ g chúng ta dành quá nhi u

ề th i

ờ gian trên l p

ớ đ

ể h c

ọ cách

thực hi n

ệ nh ng

ữ thu t

ậ toán mà, nói th ng

ẳ ra là, không c n

ầ trí thông minh gì c .

ả M t

ặ khác, quá trình

thiết k

ế nh ng

ữ thu t

ậ toán l i

ạ thú v ,ị đ y

ầ th

ử thách trí tu ,

ệ và là ph n

ầ trung tâm c a

ủ vi c

ệ mà ta g i

ọ là l p

ậ

trình.

Có những vi c

ệ mà con ngư i

ờ làm theo l

ẽ t

ự nhiên, ch ng

ẳ khó khăn hay ph i

ả suy nghĩ gì, l i

ạ là nh ng

ữ thứ

khó bi u

ể di n

ễ b ng

ằ thu t

ậ toán nh t

ấ . Vi c

ệ hi u

ể ngôn ng

ữ là m t

ộ ví d

ụ đi n

ể hình. Chúng ta ai cũng làm

v y

ậ , nh ng

ư đ n

ế nay ch a

ư ai gi i

ả thích đư c

ợ r ng

ằ ta làm v y

ậ bằng cách nào, ít nhất là bi u

ể di n

ễ dư i

ớ

d ng

ạ thu t

ậ toán.

B n

ạ s

ẽ sớm có c

ơ hội thi t

ế k

ế nh ng

ữ thu t

ậ toán đ n

ơ gi n

ả cho nhi u

ề bài toán khác nhau.

11.14 Thu t

ậ ngữ

l p:

ớ

Trư c

ớ đây, tôi đã đ nh

ị

nghĩa l p

ớ là m t

ộ t p

ậ h p

ợ các ph ng

ươ th c

ứ có liên quan. Trong ch ng

ươ này ta

còn đ c

ượ biết r ng

ằ l i

ờ đ nh

ị

nghĩa l p

ớ cũng đ ng

ồ th i

ờ là m t

ộ b n

ả m u

ẫ c a

ủ m t

ộ ki u

ể đ i

ố tư ng

ợ m i

ớ .

th c

ự th :

ể

Thành viên c a

ủ m t

ộ l p

ớ . M i

ỗ đ i

ố tư ng

ợ đ u

ề là th c

ự th

ể c a

ủ m t

ộ l p

ớ nào đó.

constructor:

Một ph ng

ươ th c

ứ đ c

ặ bi t

ệ để kh i

ở t o

ạ các bi n

ế th c

ự th

ể c a

ủ m t

ộ đ i

ố t ng

ượ m i

ớ l p

ậ nên.

l p

ớ kh i

ở đ n

ộ g:

L p

ớ có ch a

ứ ph ng

ươ th c

ứ main n i

ơ b t

ắ đ u

ầ vi c

ệ th c

ự thi ch ng

ươ trình.

hàm thu n

ầ túy:

Ph ng

ươ th c

ứ mà kết qu

ả chỉ ph

ụ thu c

ộ vào các tham s

ố c a

ủ nó, và không gây hi u

ệ ng

ứ ph

ụ nào ngoài

vi c

ệ trả l i

ạ m t

ộ giá trị.

phư n

ơ g th c

ứ s a

ử đ i

ổ :

Ph ng

ươ th c

ứ làm thay đ i

ổ m t

ộ hay nhi u

ề đ i

ố t ng

ượ nh n

ậ làm tham s ,

ố và thư ng

ờ tr

ả l i

ạ void.

phư n

ơ g th c

ứ đi n

ề :

Ki u

ể ph ng

ươ th c

ứ nh n

ậ tham s

ố là m t

ộ đ i

ố tư ng

ợ “tr ng

ố không” và đi n

ề vào nh ng

ữ bi n

ế th c

ự th

ể c a

ủ

nó thay vì vi c

ệ phát sinh m t

ộ giá tr ịtr

ả l i

ạ .

thu t

ậ toán:

M t

ộ lo t

ạ nh ng

ữ ch ỉd n

ẫ nh m

ằ gi i

ả m t

ộ l p

ớ các bài toán theo m t

ộ quá trình máy móc.

11.15 Bài t p

ậ

Bài t p

ậ 1 Trong trò ch i

ơ trên bàn có tên Scrabble2, mỗi mi ng ế vuông đ

ể x p

ế lên bàn s

ẽ ch a

ứ m t

ộ ch

ữ

cái, để xêm nên các t

ừ có nghĩa, và đ ng

ồ th i

ờ có m t

ộ đi m

ể s ;

ố t

ừ đó ta tính đư c

ợ đi m

ể cho các t

ừ khác

nhau.

1. Hãy vi t

ế một đ nh

ị nghĩa l p

ớ có tên Tile để bi u

ể di n

ễ các mi ng

ế vuông Scrabble. Các bi n

ế th c

ự th

ể s

ẽ

gồm một kí tự có tên letter và một số nguyên có tên value.

2. Hãy vi t

ế một constructor đ

ể nh n

ậ các tham số letter và value rồi khởi t o

ạ các bi n

ế th c

ự th .

ể

3. Viết một phương thức có tên printTile để nh n

ậ tham số là một đối tư ng

ợ Tile rồi in ra các bi n

ế th c

ự th

ể

dưới đ nh

ị d ng

ạ mà ngư i

ờ thư ng

ờ có th

ể đ c

ọ đư c

ợ .

4. Viết một phương thức có tên testTile để t o

ạ nên một đối tư ng

ợ Tile có ch

ữ cái Z và giá trị 10, rồi

dùng printTile để in ra tr n

ạ g thái c a

ủ đ i

ố tư ng

ợ này.

M c

ụ đích c a

ủ bài t p

ậ này là đ

ể luy n

ệ t p

ậ ph n

ầ c

ơ ch

ế t o

ạ nên m t

ộ l i

ờ đ n

ị h nghĩa l p

ớ và mã l nh

ệ đ

ể ki m

ể

tra nó.

Bài t p

ậ 2 Hãy vi t

ế một đ nh

ị nghĩa l p

ớ c a

ủ Date, một ki u

ể đ i

ố tư ng

ợ bao g m

ồ ba s

ố nguyên

là year, month và day. Lớp này c n

ầ ph i

ả có hai constructor. Constructor th

ứ nh t

ấ không nh n

ậ tham s

ố

nào. Constructor th

ứ hai nh n

ậ các tham s

ố mang tên year, month và day, rồi dùng chúng đ

ể kh i

ở t o

ạ

các bi n

ế th c

ự th .

ể Hãy vi t

ế m t

ộ phư ng

ơ th c

ứ main để t o

ạ nên một đối tư ng

ợ Date mới có tên birthday.

Đ i

ố tư ng

ợ m i

ớ này đ

ể ch a

ứ ngày sinh nh t

ậ c a

ủ b n.

ạ Có th

ể dùng constructor nào cũng đư c

ợ .

Bài t p

ậ 3 Phân số là số có thể bi u

ể đi n

ễ đư c

ợ dư i

ớ d n

ạ g t ỉs

ố gi a

ữ hai s

ố nguyên. Ch ng

ẳ h n,

ạ 2/3 là

một phân số, và b n

ạ cũng có th

ể coi 7 là m t

ộ phân s

ố v i

ớ m u

ẫ s

ố ng m

ầ đ nh

ị b ng

ằ 1.

Ở bài t p

ậ này, b n

ạ

sẽ viết một l i

ờ đ nh

ị nghĩa l p

ớ cho các phân s .

ố

1. L p

ậ một chương trình m i

ớ có tên Rational.java để đ nh

ị nghĩa một l p

ớ tên là Rational. Một đối

tượng Rational ph i

ả có hai bi n

ế th c

ự thể s

ố nguyên đ

ể l u

ư tr

ữ t

ử s

ố và m u

ẫ s .

ố

2. Viết một constructor không nh n

ậ tham s

ố nào đ

ể đ t

ặ t

ử s

ố b n

ằ g 0 và m u

ẫ s

ố b n

ằ g 1.

3. Viết một phương thức có tên printRational để nh n

ậ vào đ i

ố s

ố là m t

ộ đ i

ố tư ng

ợ Rational r i

ồ in nó ra

theo đ nh

ị d ng

ạ h p

ợ lý.

4. Viết một phương thức main để l p

ậ nên một đối tư ng

ợ m i

ớ có ki u

ể là Rational, đ t

ặ các bi n

ế th c

ự th

ể c a

ủ

nó b ng

ằ giá tr ịc

ụ th ,

ể r i

ồ in đ i

ố tư ng

ợ này ra.

5. Đến đây, b n

ạ đã có m t

ộ chư ng

ơ trình t i

ố thi u

ể có th

ể ch y

ạ th

ử đư c

ợ . Hãy ch y

ạ đ

ể ki m

ể tra nó, và g

ỡ l i

ỗ ,

nếu c n.

ầ

6. Viết một constructor th

ứ hai cho l p

ớ này có nh n

ậ vào hai đ i

ố s

ố r i

ồ s

ử d n

ụ g chúng đ

ể kh i

ở t o

ạ các bi n

ế

thực th .

ể

7. Hãy vi t

ế một phư ng

ơ th c

ứ có tên negate để đ o

ả dấu c a

ủ phân số. Phư ng

ơ th c

ứ này ph i

ả là m t

ộ phân

thức sửa đ i

ổ , và vì v y

ậ c n

ầ ph i

ả tr

ả l i

ạ void. Hãy vi t

ế thêm dòng l nh

ệ trong main để kiểm tra phương

thức mới này.

8. Viết một phương thức có tên invert để ngh c

ị h đ o

ả số b ng

ằ cách tráo đ i

ổ t

ử s

ố và m u

ẫ s .

ố Hãy vi t

ế thêm

dòng l nh

ệ trong main để kiểm tra phương th c

ứ m i

ớ này.

9. Viết một phương thức có tên toDouble để chuy n

ể đổi phân s

ố thành m t

ộ s

ố double (s

ố d u

ấ ph y

ẩ đ ng

ộ )

rồi trả l i

ạ k t

ế quả. Phư ng

ơ th c

ứ này là m t

ộ hàm thu n

ầ tuý; nó không thay đ i

ổ đ i

ố tư ng

ợ . Nh

ư thư ng

ờ l ,

ệ

hãy ki m

ể tra phư ng

ơ th c

ứ m i

ớ vi t

ế .

10.Viết một phương th c

ứ có tên reduce để rút gọn một phân s

ố v

ề d n

ạ g t i

ố gi n

ả b ng

ằ cách tìm ư c

ớ s

ố

chung l n

ớ nhất c a

ủ t

ử s

ố và m u

ẫ s

ố r i

ồ cùng chia c

ả t

ử l n

ẫ m u

ẫ cho ư c

ớ chung này. Phư ng

ơ th c

ứ nêu

trên ph i

ả là một hàm thu n

ầ tuý; nó không đư c

ợ phép thay đ i

ổ các bi n

ế th c

ự th

ể c a

ủ đ i

ố tư ng

ợ mà nó

được kích ho t

ạ lên. Đ

ể tính ư c

ớ s

ố chung l n

ớ nh t

ấ , hãy xem Bài t p

ậ 10 c a

ủ Chương 8).

11.Viết một phương thức có tên add để nh n

ậ hai đối số là hai Rational r i

ồ tr

ả l i

ạ m t

ộ đ i

ố tư ng

ợ Rational

mới. Đối tư ng

ợ đư c

ợ tr

ả l i

ạ ph i

ả ch a

ứ t ng

ổ c a

ủ các đ i

ố s .

ố có vài cách th c

ự hi n

ệ phép c ng

ộ này. B n

ạ có

thể dùng b t

ấ kì cách nào, nh ng

ư hãy đ m

ả b o

ả r ng

ằ k t

ế qu

ả c a

ủ phép tính ph i

ả đư c

ợ rút g n

ọ sao cho t

ử

và mẫu không có ư c

ớ s

ố chung nào khác (ngoài 1).

M c

ụ đích c a

ủ bài t p

ậ này là nh m

ằ vi t

ế m t

ộ l i

ờ đ nh

ị nghĩa hàm có ch a

ứ nhi u

ề lo i

ạ phư ng

ơ th c

ứ , bao g m

ồ

constructors, phư ng

ơ th c

ứ s a

ử đ i

ổ , và hàm thu n

ầ tuý.

1

Cái mà tôi g i

ọ là “nguyên m u

ẫ nhanh” (rapid prototyping) ở đây r t

ấ gi ng

ố v i

ớ cách phát tri n

ể

d a

ự trên kiểm thử (test-driven development, TDD); s

ự khác bi t

ệ là

ở ch

ỗ TDD thư ng

ờ d a

ự trên

ki m

ể thử t

ự đ ng

ộ . Xem http://en.wikipedia.org/wiki/Test-driven_development.

2

Scrabble là m t

ộ nhãn hi u

ệ đã đăng kí

ở Hoa Kì và Canada, thu c

ộ v

ề cty Hasbro Inc., và

ở các n c

ướ

còn l i

ạ trên th

ế gi i

ớ , thì thu c

ộ v

ề J.W. Spear & Sons Limited

ở Maidenhead, Berkshire, Anh Qu c

ố , công

ty nhánh c a

ủ Mattel Inc.

Ch

ng

ươ 12: M ng

ả

Trở về M c

ụ l c

ụ cuốn sách M n

ả g là một t p

ậ hợp các giá tr ịtrong đó m i

ỗ giá tr ịđư c

ợ xác đ nh

ị b i

ở m t

ộ ch ỉs .

ố B n

ạ có th

ể l p

ậ nên

các m n

ả g int, m ng

ả double, hay m n

ả g ch a

ứ b t

ấ kì ki u

ể d

ữ li u

ệ nào khác, nh ng

ư các giá tr ịtrong cùng

một m n

ả g ph i

ả có ki u

ể gi ng

ố nhau.

Về m t

ặ cú pháp, các ki u

ể m ng

ả trông gi ng

ố nh

ư các ki u

ể d

ữ li u

ệ khác trong Java ch ỉtr

ừ đ c

ặ đi m

ể : theo

sau là []. Ch ng

ẳ h n

ạ , int[] là ki u

ể “m ng

ả các s

ố nguyên” còn double[] là ki u

ể “m n

ả g các s

ố ph y

ẩ đ ng

ộ .”

B n

ạ có thể khai báo các bi n

ế v i

ớ nh ng

ữ ki u

ể nh

ư v y

ậ theo cách thông thư ng

ờ :

int[] count;

double[] values;

Trư c

ớ khi b n

ạ kh i

ở t o

ạ các bi n

ế này, chúng đư c

ợ đ t

ặ về null. Đ

ể tự tay t o

ạ các m ng

ả , hãy dùng new.

count = new int[4];

values = new double[size];

Lệnh gán th

ứ nh t

ấ khi n

ế cho count tham chi u

ế đ n

ế m t

ộ m ng

ả g m

ồ 4 s

ố nguyên; l nh

ệ th

ứ hai tham

chi u

ế khi n

ế values tham chi u

ế đ n

ế m t

ộ m ng

ả các double. Số ph n

ầ tử trong values phụ thuộc vào size.

B n

ạ có thể dùng b t

ấ kì bi u

ể th c

ứ nguyên nào đ

ể làm kích thư c

ớ m n

ả g.

Hình v

ẽ sau cho th y

ấ cách bi u

ể di n

ễ m ng

ả trong s

ơ đ

ồ tr n

ạ g thái:

Các số l n

ớ ghi bên trong các ô là nh ng

ữ phần tử c a

ủ m n

ả g. Các con s

ố nh

ỏ bên ngoài h p

ộ là nh ng

ữ ch ỉ

số dùng đ

ể xác đ nh

ị t ng

ừ ô. Khi b n

ạ huy đ ng

ộ m t

ộ m ng

ả các int, những ph n

ầ t

ử c a

ủ chúng đ u

ề đư c

ợ

khởi t o

ạ b ng

ằ không.

12.1 Truy c p

ậ các ph n

ầ tử

Để lưu các giá tr ịtrong m ng

ả , hãy dùng toán tử [] operator. Ch n

ẳ g h n,

ạ count[0] tham chi u

ế đ n

ế ph n

ầ

tử “thứ không” c a

ủ m ng

ả , còn count[1] tham chi u

ế đ n

ế ph n

ầ t

ử “th

ứ m t

ộ ”. B n

ạ có thể dùng toán

tử [] b t

ấ cứ đâu trong một bi u

ể th c

ứ :

count[0] = 7;

count[1] = count[0] * 2;

count[2]++;

count[3] -= 60;

T t

ấ c

ả đó đ u

ề là nh ng

ữ phép gán h p

ợ l .

ệ Sau đây là k t

ế qu

ả c a

ủ đo n

ạ mã trên:

Những ph n

ầ t

ử c a

ủ m n

ả g đư c

ợ đánh s

ố t

ừ 0 t i

ớ 3, nghĩa là không có ph n

ầ t

ử nào mang ch ỉs

ố 4. Đi u

ề

này r t

ấ quen thu c

ộ , b i

ở ta đã th y

ấ đi u

ề tư ng

ơ t

ự trong ch ỉs

ố c a

ủ String. Dù v y

ậ , vi c

ệ vư t

ợ quá ph m

ạ vi

c a

ủ m n

ả g v n

ẫ là ki u

ể l i

ỗ thư ng

ờ g p,

ặ b ng

ằ cách đó phát ra bi t

ệ lệArrayOutOfBoundsException.

B n

ạ có thể dùng b t

ấ kì bi u

ể th c

ứ nào làm ch ỉs

ố cũng đư c

ợ , mi n

ễ là nó có ki u

ể int. Một trong nh ng

ữ

cách thông d ng

ụ nh t

ấ để đánh ch ỉs

ố c a

ủ m n

ả g là dùng bi n

ế vòng l p.

ặ Ch n

ẳ g h n:

ạ

int i = 0;

while (i < 4) {

System.out.println(count[i]); i++;

}

Đây là một vòng l p

ặ while tiêu chu n

ẩ đ

ể đ m

ế t

ừ 0 lên 4, và khi bi n

ế l p

ặ i b n

ằ g 4, đi u

ề ki n

ệ l p

ặ s

ẽ không

thỏa mãn và vòng l p

ặ k t

ế thúc. Nh

ư v y

ậ , ph n

ầ thân vòng l p

ặ ch ỉđư c

ợ th c

ự thi khi i là 0, 1, 2 và 3.

Mỗi l n

ầ qua vòng l p

ặ ta dùng i làm chỉ số trong m n

ả g, đ

ể in ra ph n

ầ t

ử thứ i. Hình th c

ứ duy t

ệ m ng

ả này

r t

ấ thông d n

ụ g.

12.2 Sao chép m n

ả g

Khi b n

ạ sao chép m t

ộ bi n

ế m ng

ả , hãy nh

ớ r ng

ằ b n

ạ đang sao chép tham chi u

ế t i

ớ m n

ả g. Ví d :

ụ

double[] a = new double [3];

double[] b = a;

Đo n

ạ mã l nh

ệ này t o

ạ nên m t

ộ m n

ả g ba số double, rồi đặt hai bi n

ế khác nhau để tham chi u

ế t i

ớ nó.

Trường hợp này cũng là m t

ộ d ng

ạ trùng tên (aliasing).

B t

ấ kì thay đ i

ổ nào đ i

ố v i

ớ m t

ộ trong hai m ng

ả đ u

ề đư c

ợ ph n

ả ánh trên m ng

ả còn l i

ạ . Thư ng

ờ thì đây

không ph i

ả là đi u

ề b n

ạ mu n;

ố mà b n

ạ mu n

ố huy đ ng

ộ m t

ộ m n

ả g m i

ớ r i

ồ sao chép các ph n

ầ t

ử t

ừ m ng

ả

này sang m ng

ả kia.

double[] b = new double [3];

int i = 0;

while (i < 4) {

b[i] = a[i]; i++;

}

12.3 M n

ả g và đ i

ố tư n

ợ g

M ng

ả giống v i

ớ đối tư ng

ợ

ở nhi u

ề đi m

ể :

• Khi khai báo m t

ộ bi n

ế m n

ả g, b n

ạ nh n

ậ đư c

ợ tham chi u

ế đ n

ế m n

ả g.

• B n

ạ ph i

ả dùng new để tự t o

ạ ra m ng

ả .

• Khi truy n

ề m n

ả g làm đ i

ố s ,

ố b n

ạ truy n

ề m t

ộ tham chi u

ế , nghĩa là phư ng

ơ th c

ứ đư c

ợ kích ho t

ạ có th

ể

thay đổi nội dung c a

ủ m n

ả g.

Một số đ i

ố tư ng

ợ mà ta đã xét, như Rectangle, tương đồng với m ng

ả

ở ch

ỗ chúng cũng là t p

ậ h p

ợ các

giá tr .ị V y

ậ n y

ả sinh câu h i

ỏ , “M n

ả g b n

ố s

ố nguyên thì khác m t

ộ đ i

ố tư ng

ợ Rectangle

ở ch

ỗ nào?”

Nếu b n

ạ quay v

ề đ nh

ị nghĩa c a

ủ “m n

ả g” t

ừ đ u

ầ chư ng

ơ , b n

ạ s

ẽ th y

ấ m t

ộ khác bi t

ệ : các ph n

ầ t

ử c a

ủ

m ng

ả đư c

ợ xác đ nh

ị b ng

ằ ch ỉs ,

ố còn các ph n

ầ t

ử c a

ủ đ i

ố tư ng

ợ xác đ nh

ị b ng

ằ tên.

Một khác bi t

ệ n a

ữ là các ph n

ầ t

ử trong m n

ả g ph i

ả có cùng ki u

ể . Còn đ i

ố tư ng

ợ có th

ể ch a

ứ nh ng

ữ bi n

ế

thực thể khác ki u

ể nhau.

12.4 Vòng l p

ặ for

Các vòng l p

ặ mà ta đã dùng đ u

ề có m t

ộ s

ố đi m

ể chung. Chúng đ u

ề b t

ắ đ u

ầ b ng

ằ vi c

ệ kh i

ở t o

ạ m t

ộ bi n;

ế

chúng đ u

ề có m t

ộ phép ki m

ể tra, hay đi u

ề ki n,

ệ ph

ụ thu c

ộ vào bi n

ế đó; và bên trong vòng l p

ặ thì chúng

thực hi n

ệ tác đ ng

ộ nh t

ấ đ nh

ị đ n

ế bi n

ế đó, nh

ư tăng giá tr .ị

D ng

ạ vòng l p

ặ này thông d ng

ụ đ n

ế n i

ỗ còn m t

ộ l nh

ệ l p

ặ khác, g i

ọ là for, để diễn đ t

ạ một cách gọn gàng

hơn. Cú pháp chung c a

ủ nó nh

ư sau:

for (KHỞI TẠO; ĐIỀU KIỆN; GIA TĂNG) {

PHẦN THÂN

}

Lệnh này tư ng

ơ đương v i

ớ

KHỞI TẠO;

while (ĐIỀU KIỆN) {

PHẦN THÂN

GIA TĂNG

}

ngo i

ạ trừ nó gọn gàng h n

ơ vì đã đ t

ặ t t

ấ c

ả nh ng

ữ câu l nh

ệ liên quan đ n

ế l p

ặ vào m t

ộ ch ,

ỗ và do đó d

ễ

đọc hơn. Ch ng

ẳ h n:

ạ

for (int i = 0; i < 4; i++) {

System.out.println(count[i]);

}

thì tương đương v i

ớ

int i = 0;

while (i < 4) {

System.out.println(count[i]);

i++;

}

12.5 Chiều dài c a

ủ m n

ả g

T t

ấ c

ả m n

ả g đều có m t

ộ bi n

ế th c

ự th

ể tên là length. Ch n

ẳ g c n

ầ nói thì b n

ạ cũng bi t

ế , bi n

ế này ch a

ứ

chi u

ề dài c a

ủ m ng

ả (s

ố ph n

ầ t )

ử . Nên l y

ấ giá tr ịnày làm gi i

ớ h n

ạ trên c a

ủ vòng l p

ặ thay vì m t

ộ giá tr ịc

ố

đ nh

ị . Làm nh

ư v y

ậ , n u

ế nh

ư kích thư c

ớ c a

ủ m n

ả g thay đ i

ổ thì b n

ạ s

ẽ không ph i

ả dò l i

ạ c

ả chư ng

ơ trình

để thay đổi các vòng l p;

ặ chư ng

ơ trình s

ẽ ch y

ạ đư c

ợ đúng v i

ớ m i

ọ kích c

ỡ m ng

ả khác nhau.

for (int i = 0; i < a.length; i++) {

b[i] = a[i];

}

L n

ầ cuối cùng mà ph n

ầ thân c a

ủ vòng l p

ặ đư c

ợ th c

ự thi, i sẽ là a.length - 1, ch ỉsố c a

ủ ph n

ầ t

ử cu i

ố .

Khi i b n

ằ g với a.length, đi u

ề ki n

ệ s

ẽ không th a

ỏ mãn và ph n

ầ th n

ầ s

ẽ không đư c

ợ th c

ự thi. Đây là đi u

ề

tốt, vì s

ẽ có bi t

ệ l

ệ đư c

ợ phát ra. Đo n

ạ mã này gi

ả thi t

ế r ng

ằ m ng

ả b ph i

ả có b ng

ằ s

ố ph n

ầ t ,

ử ho c

ặ

nhiều hơn so v i

ớ a.

12.6 S n

ố g u n

ẫ

hiên

Đa số các chư ng

ơ trình máy tính đ u

ề làm cùng m t

ộ công vi c

ệ m i

ỗ khi nó đư c

ợ th c

ự thi; chư ng

ơ trình

như v y

ậ đư c

ợ gọi là có tính t t

ấ đ n

ị h. Thông thư ng

ờ , t t

ấ đ nh

ị là tính ch t

ấ t t

ố , vì ta luôn trông đ i

ợ cùng

một phép tính sẽ ch ỉcho m t

ộ k t

ế qu .

ả Song có nh ng

ữ chư ng

ơ trình ng

ứ d ng

ụ mà ta mu n

ố k t

ế qu

ả ph i

ả

không đoán trư c

ớ đư c

ợ . M t

ộ ví d

ụ hi n

ể nhiên là các trò ch i

ơ đi n

ệ t ,

ử song cũng có nh ng

ữ ng

ứ d n

ụ g khác

nữa.

Để một chương trình th c

ự sự phi t t

ấ đ n

ị h hóa ra l i

ạ không d

ễ chút nào, song ít nh t

ấ v n

ẫ có nh ng

ữ cách

làm chư ng

ơ trình có v

ẻ nh

ư phi t t

ấ đ nh

ị . M t

ộ cách làm trong s

ố đó là vi c

ệ phát sinh nh ng

ữ s

ố ng u

ẫ

nhiên và dùng nó đ

ể quy đ nh

ị k t

ế qu

ả c a

ủ chư ng

ơ trình. Java có m t

ộ phư ng

ơ th c

ứ đ

ể phát sinh ra các

số giả ng u

ẫ nhiên, vốn không th c

ự s

ự ng u

ẫ nhiên, nh ng

ư s

ẽ dùng đư c

ợ cho m c

ụ đích ta c n.

ầ

Hãy đ c

ọ tài li u

ệ v

ề phư ng

ơ th c

ứ random trong l p

ớ Math. Giá tr ịtr

ả l i

ạ là m t

ộ doublenằm gi a

ữ 0.0 và

1.0. Chính xác là, nó l n

ớ h n

ơ ho c

ặ b ng

ằ 0.0 và nh

ỏ h n

ơ 1.0. M i

ỗ l n

ầ kích ho t

ạ random b n

ạ sẽ nh n

ậ

được con số ti p

ế theo trong dãy s

ố gi

ả ng u

ẫ nhiên. Đ

ể th y

ấ đư c

ợ m t

ộ m u

ẫ c a

ủ dãy ng u

ẫ nhiên, hãy ch y

ạ

vòng l p

ặ sau:

for (int i = 0; i < 10; i++) {

double x = Math.random();

System.out.println(x);

}

Để phát sinh một số double giữa 0.0 và một giới h n

ạ trên như high, b n

ạ có th

ể nhân x với high.

12.7 M n

ả g các số ng u n

ẫ

hiên

B ng

ằ cách nào đ

ể phát sinh m t

ộ s

ố nguyên ng u

ẫ nhiên gi a

ữ low và high? Nếu phương

thức randomInt b n

ạ viết đã chính xác, thì m i

ỗ giá tr ịtrong kho n

ả g từ low lên đ n

ế high-1 ph i

ả có cùng

xác su t

ấ xuất hi n.

ệ N u

ế b n

ạ phát sinh m t

ộ dãy s

ố r t

ấ dài, thì m i

ỗ giá tr ịph i

ả xu t

ấ hi n

ệ ít nh t

ấ là có s

ố

l n

ầ x p

ấ x ỉnhau.

Một cách ki m

ể tra phư ng

ơ th c

ứ v a

ừ vi t

ế là phát inh r t

ấ nhi u

ề s

ố ng u

ẫ nhiên, l u

ư tr

ữ chúng vào m t

ộ

m ng

ả , rồi đ m

ế số l n

ầ t ng

ừ giá tr ịxu t

ấ hi n.

ệ

Phương th c

ứ sau nh n

ậ m t

ộ đ i

ố s

ố duy nh t

ấ là kích thư c

ớ c a

ủ m ng

ả . Phư ng

ơ th c

ứ có nhi m

ệ v

ụ huy đ ng

ộ

một m n

ả g số nguyên m i

ớ , đi n

ề vào nh ng

ữ giá tr ịng u

ẫ nhiên, r i

ồ tr

ả l i

ạ tham chi u

ế đ n

ế m ng

ả m i

ớ đi n.

ề

public static int[] randomArray(int n) {

int[] a = new int[n];

for (int i = 0; i<a.length; i++) {

a[i] = randomInt(0, 100);

}

return a;

}

Ki u

ể tr

ả l i

ạ là int[], nghĩa là phư ng

ơ th c

ứ này tr

ả l i

ạ m t

ộ m n

ả g các s

ố nguyên. Đ

ể ki m

ể tra phư ng

ơ th c

ứ

này, th t

ậ ti n

ệ n u

ế có m t

ộ phư ng

ơ th c

ứ đ

ể in ra n i

ộ dung c a

ủ m n

ả g.

public static void printArray(int[] a) {

for (int i = 0; i<a.length; i++) {

System.out.println(a[i]);

}

}

Đo n

ạ mã sau đây phát sinh m t

ộ m n

ả g r i

ồ in nó ra:

int numValues = 8;

int[] array = randomArray(numValues);

printArray(array);

Trên máy tính c a

ủ tôi, k t

ế qu

ả là

27

6

54

62

54

2

44

81

trông th t

ậ là ng u

ẫ nhiên. K t

ế qu

ả c a

ủ b n

ạ có th

ể s

ẽ khác đi.

Nếu đây là nh ng

ữ đi m

ể thi (và n u

ế v y

ậ thì đi m

ể th t

ậ t )

ệ , giáo viên có th

ể bi u

ể di n

ễ k t

ế qu

ả trư c

ớ l p

ớ

dưới d n

ạ g một histogram, vốn là một t p

ậ h p

ợ nh ng

ữ bi n

ế đếm đ

ể theo dõi s

ố l n

ầ m i

ỗ giá tr ịxu t

ấ

hiện.

Với đi m

ể thi, có th

ể ta dành ra 10 bi n

ế đ m

ế đ

ể theo dõi bao nhiêu h c

ọ sinh đ t

ạ đi m

ể đ u

ầ 9 (90 – 99),

bao nhiêu đ t

ạ đi m

ể đ u

ầ 8, v.v. M t

ộ s

ố m c

ụ ti p

ế theo s

ẽ dành cho vi c

ệ phát tri n

ể mã l nh

ệ t o

ạ ra

histogram.

12.8 Đ m

ế

Một cách ti p

ế c n

ậ hay đ n

ế nh ng

ữ bài toán nh

ư th

ế này là nghĩ v

ề nh ng

ữ phư ng

ơ th c

ứ đ n

ơ gi n,

ả d

ễ vi t

ế ,

rồi k t

ế h p

ợ chúng l i

ạ thành l i

ờ gi i

ả . Quá trình này đư c

ợ g i

ọ là phát tri n

ể t

ừ d i

ướ lên.

Xem http://en.wikipedia.org/wiki/Top-down_and_bottom-up_design.

Thật không d

ễ th y

ấ đi m

ể kh i

ở đ u

ầ c a

ủ quá trình, nh ng

ư m t

ộ cách h p

ợ lý là tìm ki m

ế nh ng

ữ bài toán

nhỏ khớp v i

ớ một d n

ạ g m u

ẫ mà b n

ạ đã bi t

ế trư c

ớ .

Ở M c

ụ 8.7 ta đã th y

ấ một vòng l p

ặ duy t

ệ qua m t

ộ chu i

ỗ r i

ồ đ m

ế s

ố l n

ầ xu t

ấ hi n

ệ m t

ộ ch

ữ cái cho trư c

ớ .

B n

ạ có thể coi chư ng

ơ trình này nh

ư m t

ộ ví d

ụ v

ề m t

ộ m u

ẫ có tên g i

ọ “duy t

ệ và đ m

ế .” Nh ng

ữ y u

ế t

ố t o

ạ

nên d ng

ạ mẫu này là:

• Một t p

ậ hợp ho c

ặ t p

ậ d

ữ li u

ệ có thể duy t

ệ đư c

ợ , nh

ư m t

ộ m n

ả g ho c

ặ chu i

ỗ .

• Một phép thử mà b n

ạ có th

ể áp d n

ụ g cho t ng

ừ ph n

ầ t

ử trong t p

ậ đó.

• Một con trỏ để theo dõi xem có bao nhiêu ph n

ầ t

ử đ t

ạ đư c

ợ phép th

ử này.

Trong trư ng

ờ h p

ợ đang xét, t p

ậ h p

ợ là m t

ộ m n

ả g các s

ố nguyên. Phép th

ử là li u

ệ r ng

ằ m t

ộ đi m

ể s

ố cho

trước có rơi vào một kho ng

ả giá tr ịcho trư c

ớ hay không.

Sau đây là m t

ộ phư ng

ơ th c

ứ có tên inRange để đếm số ph n

ầ tử trong m ng

ả r i

ơ vào m t

ộ kho n

ả g cho

trước. Các tham số bao g m

ồ m ng

ả và hai s

ố nguyên đ

ể quy đ n

ị h gi i

ớ h n

ạ dư i

ớ và trên c a

ủ kho ng

ả này.

public static int inRange(int[] a, int low, int high) {

int count = 0;

for (int i = 0; i < a.length; i++) {

if (a[i] >= low && a[i] < high)

count++;

}

return count;

}

Tôi đã không c

ụ th

ể hóa r n

ằ g li u

ệ vi c

ệ giá tr ịnào đó đúng b ng

ằ low ho c

ặ high thì s

ẽ được coi là r i

ơ vào

kho n

ả g hay không, nh ng

ư t

ừ mã l nh

ệ b n

ạ có th

ể th y

ấ r n

ằ g low được coi là r i

ơ vào trong còn high thì

không. Đi u

ề này giúp ta tránh đư c

ợ vi c

ệ đ m

ế ph n

ầ t

ử hai l n

ầ .

Bây gi

ờ ta có th

ể đ m

ế s

ố đi m

ể trong nh ng

ữ kho n

ả g c n

ầ quan tâm:

int[] scores = randomArray(30);

int a = inRange(scores, 90, 100);

int b = inRange(scores, 80, 90);

int c = inRange(scores, 70, 80);

int d = inRange(scores, 60, 70);

int f = inRange(scores, 0, 60);

12.9 Histogram

Mã lệnh này có s

ự l p

ặ l i

ạ , nh ng

ư cũng ch p

ấ nh n

ậ đư c

ợ khi có ít kho ng

ả khác nhau. Nh ng

ư th

ử tư ng

ở

tượng nếu ta muốn theo dõi s

ố l n

ầ xu t

ấ hi n

ệ c a

ủ t ng

ừ đi m

ể s ,

ố nghĩa là 100 giá tr ịcó th .

ể Lúc đó li u

ệ

b n

ạ còn muốn vi t

ế mã l nh

ệ n a

ữ không?

int count0 = inRange(scores, 0, 1);

int count1 = inRange(scores, 1, 2);

int count2 = inRange(scores, 2, 3);

...

int count3 = inRange(scores, 99, 100);

Tôi không nghĩ v y

ậ . Đi u

ề mà ta th c

ự s

ự mong mu n

ố là cách đ

ể l u

ư tr

ữ 100 s

ố nguyên, t t

ố nh t

ấ là cách

mà ta dùng đư c

ợ ch ỉs

ố đ

ể truy c p

ậ đ n

ế t ng

ừ giá tr .ị G i

ợ ý: dùng m n

ả g.

D ng

ạ m u

ẫ đ m

ế cũng tư ng

ơ t

ự b t

ấ k

ể vi c

ệ ta dùng m t

ộ bi n

ế đ m

ế hay m t

ộ m n

ả g các bi n

ế đ m

ế . Trong

trường hợp sau này, ta kh i

ở t o

ạ m ng

ả bên ngoài vòng l p.

ặ Sau đó, trong vòng l p

ặ , ta kích

ho t

ạ inRange và lưu l i

ạ giá tr :ị

int[] counts = new int[100];

for (int i = 0; i < counts.length; i++) {

counts[i] = inRange(scores, i, i+1);

}

Ở đây ch ỉcó m t

ộ đi u

ề m o

ẹ m c

ự : chúng ta dùng bi n

ế l p

ặ v i

ớ hai tác d ng

ụ : làm ch ỉs

ố bên trong m ng

ả , và

làm tham số cho inRange.

12.10 L i

ờ gi i

ả “m t

ộ lư t

ợ ”

Mã lệnh nói trên ho t

ạ đ ng

ộ đư c

ợ , song không hi u

ệ qu

ả nh

ư kh

ả năng mà l

ẽ ra nó ph i

ả làm đư c

ợ . M i

ỗ

l n

ầ đo n

ạ chương trình kích ho t

ạ inRange, nó duy t

ệ toàn b

ộ m n

ả g. Khi s

ố các kho ng

ả giá tr ịnhi u

ề lên,

sẽ có rất nhi u

ề l n

ầ duy t

ệ .

Sẽ tốt hơn n u

ế chỉ ch y

ạ một lư t

ợ qua m ng

ả , và v i

ớ m i

ỗ giá tr ,ị ta đi tính xem nó r i

ơ vào kho n

ả g nào.

Ti p

ế theo ta có thể tăng bi n

ế đ m

ế thích h p.

ợ

Ở ví d

ụ này, phép tính đó là nh

ỏ nh t

ặ , b i

ở vì ta có th

ể dùng

b n

ả thân giá trị đó làm ch ỉs

ố cho m ng

ả các bi n

ế đ m

ế .

Sau đây là đo n

ạ mã đ

ể duy t

ệ m t

ộ m n

ả g các đi m

ể s

ố và phát sinh ra histogram.

int[] counts = new int[100];

for (int i = 0; i < scores.length; i++) {

int index = scores[i];

counts[index]++;

}

12.11 Thu t

ậ ngữ

m n

ả g:

Một tập h p

ợ các giá tr ,ị trong đó nh ng

ữ giá tr ịnày ph i

ả cùng ki u

ể , và m i

ỗ giá tr ịđư c

ợ xác đ nh

ị b ng

ằ

một ch ỉs .

ố

ph n

ầ t :

ử

M t

ộ trong s

ố các giá tr ịthu c

ộ m ng

ả . Toán tử [] đ c

ượ dùng đ

ể l a

ự ch n

ọ ph n

ầ t .

ử

ch ỉs :

ố

Một bi n

ế nguyên ho c

ặ giá tr ịnguyên đ

ể ch ỉđ nh

ị m t

ộ ph n

ầ t

ử c a

ủ m ng

ả .

t t

ấ đ n

ị h:

Một ch ng

ươ trình th c

ự hi n

ệ đúng m t

ộ công vi c

ệ m i

ỗ khi nó đư c

ợ kích ho t

ạ .

gi

ả ng u

ẫ nhiên:

Một dãy con s

ố trông có v

ẻ ng u

ẫ nhiên, song th c

ự ra là s n

ả ph m

ẩ c a

ủ nh ng

ữ phép tính t t

ấ đ nh

ị .

histogram:

M t

ộ m ng

ả các s

ố nguyên trong đó t ng

ừ s

ố nguyên đ

ể đ m

ế s

ố các giá tr ịr i

ơ vào m t

ộ kho ng

ả

nh t

ấ đ nh.

ị

12.12 Bài t p

ậ

Bài t p

ậ 1 Hãy vi t

ế một phư ng

ơ th c

ứ có tên cloneArray để nh n

ậ vào tham s

ố là m t

ộ m ng

ả các s

ố

nguyên, t o

ạ ra m t

ộ m n

ả g m i

ớ cùng kích thư c

ớ , sao chép các ph n

ầ t

ử t

ừ m n

ả g đ u

ầ sang m ng

ả m i

ớ t o

ạ ,

rồi trả l i

ạ một tham chi u

ế đ n

ế m n

ả g m i

ớ .

Bài t p

ậ 2 Viết một phương thức có tên randomDouble nh n

ậ vào hai s

ố ph y

ẩ đ ng

ộ , low và high, rồi trả

l i

ạ một số ph y

ẩ động ngẫu nhiên, x, sao cho low ≤ x < high.

Bài t p

ậ 3 Viết một phương thức có tên randomInt nh n

ậ vào hai đ i

ố s ,

ố low và high, rồi trả l i

ạ một số

nguyên ngẫu nhiên từ low đến high, nhưng không kể high.

Bài t p

ậ 4 Bao b c

ọ mã l nh

ệ trong M c

ụ 12.10 vào một phư ng

ơ th c

ứ có tên makeHist để nh n

ậ một m ng

ả

các đi m

ể số r i

ồ tr

ả l i

ạ m t

ộ histogram các giá tr ịtrong m n

ả g.

Bài t p

ậ 5 Viết một phương th c

ứ có tên areFactors để nh n

ậ vào một số nguyên, n, và một m ng

ả các s

ố

nguyên, và tr

ả l i

ạ true nếu các số trong m ng

ả đ u

ề là ư c

ớ s

ố c a

ủ n (nghĩa là n chia h t

ế cho tất c

ả nh ng

ữ

ph n

ầ tử này). G I

Ợ Ý: Xem bài t p

ậ 8.1.

Bài t p

ậ 6 Viết một phương th c

ứ nh n

ậ tham s

ố g m

ồ m t

ộ m ng

ả nh ng

ữ s

ố nguyên và m t

ộ s

ố nguyên tên

là target, rồi tr

ả l i

ạ ch ỉs

ố đ u

ầ tiên n i

ơ mà target xu t

ấ hiện trong m ng

ả , n u

ế có, ho c

ặ -1 n u

ế không.

Bài t p

ậ 7 Có những l p

ậ trình viên ph n

ả đ i

ố quy t c

ắ chung r ng

ằ các bi n

ế và phư ng

ơ th c

ứ ph i

ả đư c

ợ đ t

ặ

tên có nghĩa. Thay vào đó, h

ọ nghĩ r n

ằ g các bi n

ế và phư ng

ơ th c

ứ ph i

ả đ t

ặ tên là các lo i

ạ hoa qu .

ả V i

ớ

từng phương thức sau đây, hãy vi t

ế m t

ộ câu mô t

ả ý tư ng

ở , nhi m

ệ v

ụ c a

ủ phư ng

ơ th c

ứ . V i

ớ m i

ỗ bi n,

ế

hãy xác đ n

ị h vai trò c a

ủ nó.

public static int banana(int[] a) {

int grape = 0;

int i = 0;

while (i < a.length) {

grape = grape + a[i];

i++;

}

return grape;

}

public static int apple(int[] a, int p) {

int i = 0;

int pear = 0;

while (i < a.length) {

if (a[i] == p)

pear++;

i++;

}

return pear;

}

public static int grapefruit(int[] a, int p) {

for (int i = 0; i<a.length; i++) {

if (a[i] == p)

return i;

}

return -1;

}

M c

ụ đích c a

ủ bài t p

ậ này là th c

ự hành đ c

ọ mã l nh

ệ và nh n

ậ ra nh ng

ữ d ng

ạ m u

ẫ tính toán mà ta đã g p

ặ .

Bài t p

ậ 8

1. Kết qu

ả c a

ủ chư ng

ơ trình sau là gì?

2. Hãy v

ẽ bi u

ể đ

ồ ngăn x p

ế đ

ể cho th y

ấ tr ng

ạ thái chư ng

ơ trình ngay trư c

ớ khi mus tr

ả v .

ề

3. Di n

ễ đ t

ạ b n

ằ g l i

ờ m t

ộ cách ng n

ắ g n

ọ nhi m

ệ v

ụ c a

ủ mus.

public static int[] make(int n) {

int[] a = new int[n];

for (int i = 0; i < n; i++) {

a[i] = i+1;

}

return a;

}

public static void dub(int[] jub) {

for (int i = 0; i < jub.length; i++) {

jub[i] *= 2;

}

}

public static int mus(int[] zoo) {

int fus = 0;

for (int i = 0; i < zoo.length; i++) {

fus = fus + zoo[i];

}

return fus;

}

public static void main(String[] args) {

int[] bob = make(5);

dub(bob);

System.out.println(mus(bob));

}

Bài t p

ậ 9 Nhiều d n

ạ g m u

ẫ đ

ể duy t

ệ m n

ả g mà ta đã g p

ặ cũng có th

ể đư c

ợ vi t

ế theo cách đ

ệ quy. Đó

không ph i

ả là cách thư ng

ờ dùng, nh ng

ư là m t

ộ bài t p

ậ h u

ữ ích.

1. Hãy vi t

ế một phư ng

ơ th c

ứ có tên maxInRange, nh n

ậ vào một m ng

ả s

ố nguyên mà m t

ộ kho n

ả g ch ỉs

ố

(lowIndex và highIndex), rồi tìm giá tr ịl n

ớ nh t

ấ trong m ng

ả , nh ng

ư ch ỉxét nh ng

ữ ph n

ầ t

ử

giữa lowIndex và highIndex, k

ể cả hai đầu này. Phư ng

ơ th c

ứ ph i

ả đư c

ợ vi t

ế theo cách đ

ệ quy. N u

ế chi u

ề

dài c a

ủ kho ng

ả b ng

ằ 1, nghĩa là n u

ế lowIndex == highIndex, thì ta bi t

ế ngay r ng

ằ ph n

ầ t

ử duy nh t

ấ

trong kho ng

ả ph i

ả là giá tr ịl n

ớ nh t

ấ . Do đó đây là trư ng

ờ h p

ợ c

ơ s .

ở N u

ế có nhi u

ề ph n

ầ t

ử trong

kho n

ả g, thì ta có thể chia m n

ả g làm đôi, tìm c c

ự đ i

ạ trên m i

ỗ ph n,

ầ r i

ồ sau đó l y

ấ giá tr ịl n

ớ h n

ơ trong

số hai c c

ự đ i

ạ tìm đư c

ợ .

2. Các phương th c

ứ như maxInRange có thể gây lúng túng khi dùng. Đ

ể tìm ph n

ầ t

ử l n

ớ nh t

ấ trong m ng

ả ,

ta ph i

ả cung c p

ấ m t

ộ kho n

ả g bao g m

ồ toàn b

ộ m n

ả g đó.

double max = maxInRange(array, 0, a.length-1);

Hãy vi t

ế một phư ng

ơ th c

ứ có tên max nh n

ậ tham số là một m ng

ả r i

ồ dùng maxInRange để tìm và tr

ả

l i

ạ giá tr ịl n

ớ nhất. Các phư ng

ơ th c

ứ như max đôi khi còn đư c

ợ g i

ọ là phư n

ơ g th c

ứ gói b c

ọ vì chúng

cung c p

ấ một l p

ớ khái ni m

ệ xung quanh m t

ộ phư ng

ơ th c

ứ l ng

ủ c ng

ủ và giúp nó d

ễ dùng. Phư ng

ơ th c

ứ

mà thực s

ự th c

ự hi n

ệ tính toán đư c

ợ g i

ọ là ph n

ươ g th c

ứ tr

ợ giúp.

3. Hãy vi t

ế một phiên b n

ả find theo cách đ

ệ quy và dùng đ n

ế d ng

ạ m u

ẫ gói b c

ọ -tr

ợ giúp. find c n

ầ ph i

ả

nh n

ậ một m n

ả g các s

ố nguyên và m t

ộ s

ố nguyên m c

ụ tiêu. Nó c n

ầ ph i

ả tr

ả l i

ạ ch ỉs

ố c a

ủ v ịtrí đ u

ầ tiên

t i

ạ đó xu t

ấ hi n

ệ số nguyên m c

ụ tiêu, ho c

ặ tr

ả l i

ạ -1 n u

ế không xu t

ấ hi n.

ệ

Bài t p

ậ 10 Một cách không hi u

ệ qu

ả l m

ắ để s p

ắ x p

ế các ph n

ầ t

ử trong m n

ả g là tìm ph n

ầ t

ử l n

ớ nh t

ấ

rồi đ i

ổ chỗ nó cho ph n

ầ t

ử th

ứ nh t

ấ , sau đó tìm ph n

ầ t

ử l n

ớ th

ứ hai r i

ồ đ i

ổ ch

ỗ v i

ớ ph n

ầ t

ử th

ứ hai, và

cứ như v y

ậ . Cách này g i

ọ là s p

ắ xếp ch n

ọ (xem http://vi.wikipedia.org/wiki/S p_

ắ x p

ế _ch n

ọ ).

1. Hãy vi t

ế một phư ng

ơ th c

ứ mang tên indexOfMaxInRange nh n

ậ vào một m n

ả g số nguyên, tìm ph n

ầ t

ử

lớn nhất trong kho ng

ả cho trư c

ớ , r i

ồ tr

ả l i

ạ ch ỉs

ố c a

ủ nó. B n

ạ có th

ể s a

ử l i

ạ phiên b n

ả maxInRange hay

b n

ạ có thể vi t

ế từ đ u

ầ một phiên b n

ả tư ng

ơ tác v i

ớ máy.

2. Viết một phương thức có tên swapElement nh n

ậ một m ng

ả số nguyên cùng hai ch ỉs ,

ố r i

ồ đ i

ổ ch

ỗ hai

ph n

ầ tử t i

ạ các ch ỉs

ố đó.

3. Viết một phương thức có tên selectionSort nh n

ậ vào một m n

ả g các s

ố nguyên và trong đó

dùngindexOfMaxInRange cùng swapElement để xếp m ng

ả từ nhỏ đ n

ế l n.

ớ

Bài t p

ậ 11 Viết một phương thức có tên letterHist nh n

ậ một chuỗi làm tham s

ố r i

ồ tr

ả l i

ạ histogram

c a

ủ các ch

ữ cái trong chu i

ỗ . Ph n

ầ t

ử th

ứ không c a

ủ histogram c n

ầ ph i

ả ch a

ứ s

ố ch

ữ a trong chu i

ỗ (c

ả

chữ in và thư ng

ờ ); ph n

ầ t

ử th

ứ 25 c n

ầ ph i

ả ch a

ứ s

ố ch

ữ z. L i

ờ gi i

ả c a

ủ b n

ạ ch ỉđư c

ợ duy t

ệ chu i

ỗ này

đúng một l n

ầ .

Bài t p

ậ 12 Một từ được gọi là “doubloon” n u

ế trong t

ừ đó, m i

ỗ ch

ữ cái xu t

ấ hi n

ệ đúng hai l n.

ầ Ch n

ẳ g

h n

ạ , các t

ừ sau đây là doubloon mà tôi đã tìm th y

ấ trong cu n

ố t

ừ đi n.

ể

Abba, Anna, appall, appearer, appeases, arraigning, beriberi, bilabial, boob, Caucasus, coco, Dada, deed, Emmett, Hannah, horseshoer, intestines, Isis, mama, Mimi, murmur, noon, Otto, papa, peep, reappear, redder, sees, Shanghaiings, Toto Hãy vi t

ế một phư ng

ơ th c

ứ có tên isDoubloon để tr

ả l i

ạ true nếu từ đã cho là m t

ộ doubloon và false nếu

không ph i

ả .

Bài t p

ậ 13 Hai từ là t

ừ đ o

ả (anagram) n u

ế nh

ư chúng có ch a

ứ cùng nh ng

ữ ch

ữ cái (đ ng

ồ th i

ờ cùng s

ố

lượng từng chữ). Ch n

ẳ g h n,

ạ “stop” là t

ừ đ o

ả c a

ủ “pots” còn “allen downey” là c m

ụ t

ừ đ o

ả c a

ủ “well

annoyed.” Hãy vi t

ế m t

ộ phư ng

ơ th c

ứ nh n

ậ vào hai String r i

ồ tr

ả l i

ạ true nếu như các String là t

ừ đ o

ả

c a

ủ nhau. Thêm ph n

ầ th

ử thách: b n

ạ ch ỉđư c

ợ đ c

ọ các ch

ữ cái c a

ủ nh ng

ữ String này đúng m t

ộ l n.

ầ

Bài t p

ậ 14 Trong trò ch i

ơ Scrabble, m i

ỗ ngư i

ờ ch i

ơ có m t

ộ t p

ậ h p

ợ các mi n

ế g vuông v i

ớ các ch

ữ cái

ghi trên đó, và m c

ụ tiêu c a

ủ chò tr i

ơ là dùng nh ng

ữ ch

ữ cái đó ghép thành t

ừ có nghĩa. H

ệ th ng

ố tính

điểm khá ph c

ứ t p,

ạ song thư ng

ờ thì các t

ừ dài có giá tr ịcao h n

ơ các t

ừ ng n.

ắ Gi

ả d

ụ r ng

ằ b n

ạ đư c

ợ cho

trước các ch

ữ cái dư i

ớ d n

ạ g m t

ộ chu i

ỗ , như "quijibo" và b n

ạ nh n

ậ được một chuỗi khác để ki m

ể tra,

như "jib". Hãy vi t

ế một phư ng

ơ th c

ứ có tên canSpell nh n

ậ vào hai chu i

ỗ r i

ồ tr

ả l i

ạ true nếu t p

ậ h p

ợ các

miếng vuông x p

ế đư c

ợ thành t

ừ có nghĩa. B n

ạ có th

ể có nhi u

ề mi n

ế g ghi ch

ữ gi ng

ố nhau, nh ng

ư ch ỉ

được dùng m i

ỗ mi ng

ế m t

ộ l n

ầ . Thêm ph n

ầ th

ử thách: b n

ạ ch ỉđư c

ợ đ c

ọ các ch

ữ cái c a

ủ nh ng

ữ String

này đúng m t

ộ l n

ầ .

Bài t p

ậ 15 Th c

ự ra trong Scrabble, còn nh ng

ữ mi n

ế g vuông tr ng

ắ có th

ể đư c

ợ dùng đ

ể bi u

ể di n

ễ ch

ữ

cái tùy ý. Hãy suy nghĩ m t

ộ thu t

ậ toán cho canSpell xử lý được trường hợp ch

ữ tùy ý nh

ư v y

ậ . Đ ng

ừ b n

ậ

tâm đ n

ế nh ng

ữ chi ti t

ế th c

ự hi n

ệ nh

ư b ng

ằ cách nào có th

ể bi u

ể di n

ễ nh ng

ữ ch

ữ tùy ý đó. Ch ỉc n

ầ di n

ễ

đ t

ạ thuật toán b n

ằ g lời, b ng

ằ gi

ả mã, ho c

ặ b ng

ằ Java.

Ch

ng

ươ 13: M ng

ả

ch a

ứ các đ i

ố tư ng

ợ

Trở về M c

ụ l c

ụ cuốn sách 13.1 Con đư n

ờ g phía trư c

ớ

Ở ba chương k

ế ti p

ế ta s

ẽ phát tri n

ể các chư ng

ơ trình ch i

ơ bài tây và v i

ớ nh ng

ữ c

ỗ bài. Trư c

ớ khi đi vào

chi ti t

ế , sau đây là khái quát nh ng

ữ bư c

ớ đi:

1. Trong chương này ta s

ẽ đ nh

ị nghĩa m t

ộ l p

ớ Card rồi vi t

ế các phư ng

ơ th c

ứ để ho t

ạ đ ng

ộ v i

ớ đ i

ố

tượng Card và m ng

ả ch a

ứ Card.

2. Trong Chư ng

ơ 14 ta sẽ t o

ạ l p

ậ một l p

ớ Deck rồi vi t

ế các phư ng

ơ th c

ứ ho t

ạ đ ng

ộ v i

ớ các đ i

ố tư ng

ợ Deck.

3. Trong Chư ng

ơ 15 tôi s

ẽ trình bày về l p

ậ trình hư ng

ớ đ i

ố tư ng

ợ (OOP) và ta s

ẽ chuy n

ể đ i

ổ các

lớp Card và Deck sang một phong cách gi ng

ố nh

ư hư ng

ớ đ i

ố tư ng

ợ h n.

ơ

Tôi nghĩ r ng

ằ ti n

ế bư c

ớ theo ki u

ể này khi n

ế cho con đư ng

ờ đi d

ễ dàng h n;

ơ song như c

ợ đi m

ể là ta s

ẽ

th y

ấ nhi u

ề phiên b n

ả c a

ủ cùng đo n

ạ mã l nh

ệ , vì v y

ậ có th

ể gây nh m

ầ l n

ẫ . N u

ế đư c

ợ , b n

ạ có th

ể t i

ả v

ề

mã l nh

ệ cho t ng

ừ chư ng

ơ trong khi làm. Mã l nh

ệ trong chư ng

ơ này

ở

đây: http://thinkapjava.com/code/Card1.java.

13.2 Các đối tư n

ợ g Card

Nếu b n

ạ ch a

ư quen v i

ớ bài tây, thì gi

ờ là lúc thích h p

ợ đ

ể ki m

ể m t

ộ b ,

ộ k o

ẻ nh ng

ữ gì trong chư ng

ơ này

sẽ không có nhi u

ề ý nghĩa. Ho c

ặ b n

ạ hãy đ c

ọ l y

ấ http://en.wikipedia.org/wiki/Playing_card.

Có 52 lá bài trong m t

ộ b ,

ộ m i

ỗ lá bài thu c

ộ v

ề m t

ộ trong b n

ố ch t

ấ và m t

ộ trong 13 b c

ậ . Các ch t

ấ g m

ồ

Pích, C ,

ơ Rô, và Nhép (theo th

ứ t

ự gi m

ả d n

ầ trong trò bridge). Các b c

ậ g m

ồ có A, 2, 3, 4, 5, 6, 7, 8, 9, 10,

J, Q, và K. Tùy theo trò ch i

ơ mà b n

ạ quân A có th

ể cao h n

ơ K ho c

ặ th p

ấ h n

ơ 2.

Nếu b n

ạ muốn đ nh

ị nghĩa m t

ộ đ i

ố tư ng

ợ m i

ớ đ

ể bi u

ể di n

ễ cho lá bài, rõ ràng các thu c

ộ tính ph i

ả

là: rank (b c

ậ ) và suit (chất). Còn vi c

ệ ch n

ọ ki u

ể d

ữ li u

ệ cho các thu c

ộ tính l i

ạ không hi n

ể nhiên. M t

ộ

kh

ả năng là dùng các chu i

ỗ g m

ồ nh ng

ữ t

ừ như "Spade" (Pích) cho ch t

ấ và "Queen" cho b c

ậ . Một v n

ấ

đề đ t

ặ ra v i

ớ cách làm này là s

ẽ không d

ễ so sánh xem lá bài nào có b c

ậ ho c

ặ ch t

ấ cao h n.

ơ

Một cách khác là dùng s

ố nguyên để đánh số cho các b c

ậ và ch t

ấ .

Ở đây, “đánh s ”

ố không có nghĩa là ý

mã hóa ho c

ặ d c

ị h thông đi p

ệ ra d n

ạ g m t

ậ mã nh

ư nhi u

ề ngư i

ờ thư ng

ờ nghĩ. Mà đ i

ố v i

ớ nhà khoa h c

ọ

máy tính, “đánh s ”

ố nghĩa là “l p

ậ một phép ánh x

ạ t

ừ con s

ố đ n

ế d

ữ li u

ệ c n

ầ bi u

ể th .ị” Ch ng

ẳ h n:

ạ

Spades (Pích)

↦ 3

Hearts (Cơ)

↦ 2

Diamonds (Rô) ↦ 1

Clubs (Nhép)

↦ 0

Mã số này giúp so sánh các lá bài d

ễ h n;

ơ vì ch t

ấ cao h n

ơ đư c

ợ ánh x

ạ đ n

ế s

ố l n

ớ h n,

ơ và ta có th

ể so

sánh ch t

ấ b ng

ằ cách so các mã s

ố c a

ủ chúng. Ánh xạ đ i

ố v i

ớ b c

ậ thì khá d

ễ th y

ấ ; m i

ỗ b c

ậ s

ố thì ánh x

ạ

đến chính s

ố nguyên tư ng

ơ ng

ứ , còn v i

ớ các b c

ậ ch :

ữ

J ↦ 11

Q ↦ 12

K ↦ 13

Ở đây tôi dùng kí hi u

ệ toán h c

ọ đ

ể bi u

ể di n

ễ ánh x

ạ là do ánh x

ạ không ph i

ả là m t

ộ ph n

ầ c a

ủ chư ng

ơ

trình. Đó là m t

ộ ph n

ầ c a

ủ khâu thi t

ế k

ế chư ng

ơ trình, nh ng

ư không xu t

ấ hi n

ệ m t

ộ cách c

ụ th

ể trên mã

lệnh. Lời đ nh

ị nghĩa l p

ớ cho ki u

ể Card sẽ như sau:

class Card {

int suit, rank;

public Card() {

this.suit = 0;

this.rank = 0;

}

public Card(int suit, int rank) {

this.suit = suit;

this.rank = rank;

}

}

Như thường l ,

ệ tôi cung c p

ấ hai constructor: m t

ộ cái nh n

ậ m i

ỗ tham s

ố ng

ứ v i

ớ t ng

ừ bi n

ế th c

ự th ;

ể cái

kia thì không nh n

ậ tham s

ố nào.

Để t o

ạ nên một đối tư ng

ợ bi u

ể di n

ễ lá bài 3 Nhép, ta kích ho t

ạ new:

Card threeOfClubs = new Card(0, 3);

Đ i

ố số th

ứ nh t

ấ , 0 biểu thị ch t

ấ Nhép.

13.3 Phư n

ơ g thức printCard

Khi b n

ạ t o

ạ nên m t

ộ l p

ớ m i

ớ , bư c

ớ đ u

ầ tiên là khai báo các bi n

ế th c

ự th

ể và vi t

ế các constructor. Bư c

ớ

thứ hai là vi t

ế nh ng

ữ phư ng

ơ th c

ứ tiêu chu n

ẩ mà t ng

ừ đ i

ố tư ng

ợ đ u

ề nên có, g m

ồ m t

ộ phư ng

ơ th c

ứ đ

ể

in đối tư ng

ợ ra, và m t

ộ ho c

ặ hai phư ng

ơ th c

ứ đ

ể so sánh các đ i

ố tư ng

ợ . Ta hãy b t

ắ đ u

ầ v i

ớ printCard.

Để in ra đ i

ố tư ng

ợ Card theo cách mà m i

ọ ngư i

ờ d

ễ đ c

ọ , ta c n

ầ ánh x

ạ t

ừ mã s

ố đ n

ế các b c

ậ và ch t

ấ

tương ứng. Một cách làm t

ự nhiên là dùng m n

ả g ch a

ứ các chu i

ỗ . B n

ạ có th

ể t o

ạ m t

ộ m n

ả g các chu i

ỗ

theo cách giống nh

ư đã t o

ạ ra m ng

ả ch a

ứ nh ng

ữ ki u

ể d

ữ li u

ệ nguyên thu :

ỷ

String[] suits = new String[4];

Sau đó ta có th

ể đ t

ặ giá tr ịc a

ủ các ph n

ầ t

ử trong m ng

ả này.

suits[0] = "Clubs";

suits[1] = "Diamonds";

suits[2] = "Hearts";

suits[3] = "Spades";

Việc t o

ạ ra một m ng

ả và kh i

ở t o

ạ các ph n

ầ t

ử trong nó là m t

ộ thao tác thư ng

ờ g p

ặ đ n

ế n i

ỗ Java cung

c p

ấ luôn một cú pháp đ c

ặ bi t

ệ cho nó:

String[] suits = { "Clubs", "Diamonds", "Hearts", "Spades" }; Câu l nh

ệ này tư ng

ơ đư ng

ơ v i

ớ các l nh

ệ khai báo, huy đ ng

ộ và gán. S

ơ đ

ồ tr ng

ạ thái cho m ng

ả này s

ẽ

như sau:

Các ph n

ầ t

ử c a

ủ m ng

ả này là nh ng

ữ tham chi u

ế đến các chuỗi, thay vì là b n

ả thân các chu i

ỗ .

Bây gi

ờ ta c n

ầ m t

ộ m n

ả g các chu i

ỗ khác đ

ể gi i

ả mã các b c

ậ c a

ủ lá bài:

String[] ranks = { "narf", "Ace", "2", "3", "4", "5", "6", "7", "8", "9",

"10", "Jack", "Queen", "King" }; Lý do có m t

ặ "narf" là đ

ể đứng vào ch

ỗ ph n

ầ t

ử th

ứ không c a

ủ m ng

ả , v n

ố ch n

ẳ g bao gi

ờ đư c

ợ dùng đ n

ế

(hay l

ẽ ra không có). Các b c

ậ h p

ợ lý ch ỉcó t

ừ 1–13. Đ

ể tránh ph n

ầ t

ử thư ng

ờ này, ta đã có th

ể b t

ắ đ u

ầ t

ừ

0, nhưng vi c

ệ ánh x

ạ s

ẽ t

ự nhiên h n

ơ n u

ế ta mã hóa 2 là 2, và 3 là 3, v.v.

Với các m n

ả g này, ta có th

ể ch n

ọ đư c

ợ String thích h p

ợ b ng

ằ cách dùng ch ỉs

ố là suit và rank. Trong

phương th c

ứ printCard,

public static void printCard(Card c) {

String[] suits = { "Clubs", "Diamonds", "Hearts", "Spades" }; String[] ranks = { "narf", "Ace", "2", "3", "4", "5", "6", "7", "8", "9",

"10", "Jack", "Queen", "King" }; System.out.println(ranks[c.rank] + " of " + suits[c.suit]);

}

bi u

ể th c

ứ suits[c.suit] có nghĩa là “dùng bi n

ế th c

ự thể suit từ đối tư ng

ợ c làm ch ỉsố trong m ng

ả có

tên suits, rồi chọn chuỗi thích h p.

ợ ” K t

ế qu

ả c a

ủ đo n

ạ mã này

Card card = new Card(1, 11);

printCard(card);

là Jack of Diamonds.

13.4 Phư n

ơ g thức sameCard

Từ “same” (giống nhau, cùng) là m t

ộ trong nh ng

ữ hi n

ệ tư ng

ợ ngôn ng

ữ trong ti ng

ế Anh mà có v

ẻ ngoài

quá rõ ràng, nh ng

ư khi b n

ạ suy nghĩ thì s

ẽ th y

ấ còn có nhi u

ề đi u

ề h n

ơ b n

ạ ch

ờ đón ban đ u

ầ .

Ch ng

ẳ h n,

ạ n u

ế nói r ng

ằ “Chris và tôi có cùng (lo i

ạ ) xe,” thì tôi mu n

ố nói r ng

ằ hai chi c

ế xe cùng nhãn

hiệu, song là hai chi c

ế khác nhau. Còn n u

ế nói “Chris và tôi có cùng m ,

ẹ ” thì ý r n

ằ g m

ẹ c u

ậ ta và m

ẹ tôi

cùng là một ngư i

ờ . B i

ở v y

ậ ý nghĩa c a

ủ “cùng” thì l i

ạ khác nhau tùy theo ng

ữ c nh

ả .

Khi nói v

ề các đ i

ố tư ng

ợ , ta cũng g p

ặ s

ự m p

ậ m

ờ tư ng

ơ t .

ự Ch n

ẳ g h n,

ạ n u

ế hai Card như nhau, thì li u

ệ

có nghĩa là chúng có cùng d

ữ li u

ệ (b c

ậ và ch t

ấ ), hay đó th c

ự ra cùng là m t

ộ đ i

ố tư ng

ợ Card?

Để xem li u

ệ có ph i

ả hai tham chi u

ế cùng ch ỉđ n

ế m t

ộ đ i

ố tư ng

ợ hay không, ta dùng toán tử ==. Ch ng

ẳ

h n:

ạ

Card card1 = new Card(1, 11);

Card card2 = card1;

if (card1 == card2) {

System.out.println("card1 và card2 giống hệt nhau.");

}

Các tham chi u

ế đ n

ế cùng đ i

ố tư ng

ợ thì gi n

ố g h t

ệ nhau. Còn các tham chi u

ế đ n

ế các đ i

ố tư ng

ợ v i

ớ d

ữ

liệu như nhau thì sẽ t

n

ươ g đ n

ồ g v i

ớ nhau.

Để kiểm tra sự tương đồng, người ta thư ng

ờ vi t

ế một phư ng

ơ th c

ứ có tên g i

ọ ki u

ể như sameCard.

public static boolean sameCard(Card c1, Card c2) {

return(c1.suit == c2.suit && c1.rank == c2.rank);

}

Sau đây là m t

ộ ví d

ụ để t o

ạ nên hai đ i

ố tư ng

ợ có d

ữ li u

ệ gi ng

ố nhau, r i

ồ dùng sameCard để kiểm tra

xem li u

ệ chúng có tư ng

ơ đ ng

ồ không:

Card card1 = new Card(1, 11);

Card card2 = new Card(1, 11);

if (sameCard(card1, card2)) {

System.out.println("card1 and card2 tuong dong nhau.");

}

Nếu các tham chi u

ế gi ng

ố nhau thì chúng tư ng

ơ đ ng

ồ . Song n u

ế chúng tư ng

ơ đ ng

ồ thì ch a

ư ch c

ắ chúng

đã giống h t

ệ nhau.

Ở đây, card1 và card2 tương đồng nhưng không giống h t

ệ , cho nên s

ơ đ

ồ tr ng

ạ thái s

ẽ nh

ư sau:

Sơ đồ này sẽ trông th

ế nào n u

ế card1 và card2 giống hệt nhau?

Ở M c

ụ 8.10, tôi đã nói r ng

ằ b n

ạ không nên dùng toán tử == đối với String vì nó sẽ không ho t ạ đ ng

ộ

theo ý mình. Thay vì vi c

ệ so sánh n i

ộ dung c a

ủ các String (so sánh tư ng

ơ đồng), nó l i

ạ đi ki m

ể tra xem

hai String này có ph i

ả cùng đ i

ố tư ng

ợ (gi ng

ố h t

ệ ) không.

13.5 Phư n

ơ g th c

ứ compareCard

Với những ki u

ể nguyên th y

ủ , các toán t

ử đi u

ề ki n

ệ so sánh hai giá tr ịr i

ồ quy t

ế đ nh

ị xem cái nào l n

ớ hay

nhỏ hơn các kia. Nh ng

ữ toán t

ử nh

ư v y

ậ (< và > cùng nh ng

ữ cái khác) không ho t

ạ đ ng

ộ đư c

ợ v i

ớ ki u

ể

đối tượng. V i

ớ các chu i

ỗ , Java cung c p

ấ m t

ộ phư ng

ơ th c

ứ compareTo. Còn v i

ớ Cards thì ta ph i

ả t

ự vi t

ế

phương th c

ứ riêng, mà ta s

ẽ g i

ọ là compareCard. Sau này, ta s

ẽ dùng phư ng

ơ th c

ứ này đ

ể s p

ắ x p

ế m t

ộ

c

ỗ bài.

Có những t p

ậ h p

ợ đư c

ợ x p

ế th

ứ t

ự hoàn toàn, theo nghĩa là b n

ạ có th

ể so sánh hai ph n

ầ t

ử b t

ấ kì trong

đó đ

ể bi t

ế được ph n

ầ t

ử nào l n

ớ h n.

ơ L i

ạ có nh ng

ữ t p

ậ h p

ợ không s p

ắ x p

ế đư c

ợ , theo nghĩa là ch n

ẳ g có

nghĩa lý gì đ

ể nói r ng

ằ ph n

ầ t

ử này l n

ớ h n

ơ ph n

ầ t

ử kia. Các s

ố nguyên và s

ố ph y

ẩ đ ng

ộ là lo i

ạ th

ứ t

ự

hoàn toàn. Còn các lo i

ạ trái cây là không có th

ứ t ,

ự vì v y

ậ mà ta không th

ể so sánh táo v i

ớ cam đư c

ợ .

Trong Java, ki u

ể boolean là không th

ứ t ;

ự ta không th

ể nói r n

ằ g true lớn hơn false.

T p

ậ hợp các lá bài thì l i

ạ ph n

ầ nào đư c

ợ x p

ế th

ứ t ,

ự có nghĩa r ng

ằ đôi khi ta có th

ể so sánh lá bài và đôi

khi không. Ch n

ẳ g h n,

ạ tôi bi t

ế r ng

ằ cây 3 Nhép thì cao h n

ơ 2 Nhép và 3 Rô thì cao h n

ơ 3 Nhép. Nh ng

ư

lá bài nào h n,

ơ 3 Nhép hay 2 Rô? M t

ộ lá thì có b c

ậ cao h n,

ơ nh ng

ư lá kia thì có ch t

ấ cao h n.

ơ

Để làm cho các lá bài so sánh đư c

ợ v i

ớ nhau, ta ph i

ả quy t

ế đ nh

ị xem th

ứ nào quan tr ng

ọ h n,

ơ b c

ậ hay

ch t

ấ . Cách l a

ự ch n

ọ là tùy ý, nh ng

ư khi b n

ạ mua m t

ộ c

ỗ bài m i

ớ , thì các qu n

ấ Nhép đư c

ợ x p

ế c nh

ạ

nhau, sau đó là các quân Rô, r i

ồ c

ứ nh

ư v y

ậ . B i

ở th

ế ta hãy coi r n

ằ g ch t

ấ thì quan tr ng

ọ h n.

ơ

Khi đã quy t

ế đ nh

ị nh

ư v y

ậ , ta có th

ể vi t

ế compareCard. Phương thức này nh n

ậ tham s

ố là hai Card rồi

trả l i

ạ 1 n u

ế lá bài th

ứ nh t

ấ h n,

ơ -1 n u

ế lá bài th

ứ hai h n,

ơ và 0 n u

ế chúng tư ng

ơ đ ng

ồ .

Trư c

ớ tiên, ta so sánh ch t

ấ :

if (c1.suit > c2.suit) return 1;

if (c1.suit < c2.suit) return -1;

Nếu hai câu l nh

ệ trên ch n

ẳ g có câu l nh

ệ nào đúng, thì các ch t

ấ ph i

ả b ng

ằ nhau, và ta ph i

ả so sánh b c

ậ :

if (c1.rank > c2.rank) return 1;

if (c1.rank < c2.rank) return -1;

Nếu l i

ạ ch ng

ẳ có câu nào đúng, thì hai b c

ậ ph i

ả b ng

ằ nhau, và vì v y

ậ ta ph i

ả tr

ả l i

ạ 0.

13.6 M n

ả g các lá bài

Đến giờ ta đã th y

ấ một vài ví d

ụ v

ề phép h p

ợ (kh

ả năng k t

ế h p

ợ nh ng

ữ đ c

ặ đi m

ể c a

ủ ngôn ng

ữ l p

ậ trình

theo nhi u

ề cách b

ố trí khác nhau). M t

ộ trong nh ng

ữ ví d

ụ đ u

ầ tiên ta b t

ắ g p

ặ là vi c

ệ dùng phép kích

ho t

ạ phương th c

ứ nh

ư là m t

ộ ph n

ầ c a

ủ bi u

ể th c

ứ . M t

ộ ví d

ụ khác là c u

ấ trúc l ng

ồ ghép g m

ồ các câu

lệnh: b n

ạ có th

ể đ t

ặ một l nh

ệ if bên trong m t

ộ vòng l p

ặ while, hay bên trong m t

ộ l nh

ệ if khác, v.v.

Khi đã bi t

ế đư c

ợ d n

ạ g nh

ư v y

ậ , và đã h c

ọ đư c

ợ v

ề m ng

ả và đ i

ố tư ng

ợ , thì có l

ẽ b n

ạ ch ng

ẳ ng c

ạ nhiên

khi đư c

ợ bi t

ế r ng

ằ ta có th

ể t o

ạ nên m ng

ả ch a

ứ nh ng

ữ đ i

ố tư ng

ợ . Và b n

ạ có th

ể đ nh

ị nghĩa nh ng

ữ đ i

ố

tượng có bi n

ế thực thể là các m n

ả g; b n

ạ có th

ể l p

ậ nên nh ng

ữ m n

ả g ch a

ứ m ng

ả khác; b n

ạ có th

ể đ nh

ị

nghĩa đ i

ố tư ng

ợ ch a

ứ đ i

ố tư ng

ợ khác, v.v. Trong hai chư ng

ơ ti p

ế theo, ta s

ẽ th y

ấ nh ng

ữ ví d

ụ v

ề cách

kết hợp nh

ư v y

ậ trên c

ơ s

ở các đ i

ố tư ng

ợ Card.

Ví d

ụ này t o

ạ nên m t

ộ m n

ả g g m

ồ 52 quân bài:

Card[] cards = new Card[52];

Sau đây là s

ơ đ

ồ tr n

ạ g thái cho đ i

ố tư ng

ợ này:

M ng

ả hi n

ệ t i

ạ có ch a

ứ các tham chi u

ế đến đ i

ố tư ng

ợ ; nó không ch a

ứ b n

ả thân các đ i

ố tư ng

ợ Card.

Những ph n

ầ t

ử này đ u

ề đư c

ợ kh i

ở t o

ạ vềnull. B n

ạ có thể truy c p

ậ t ng

ừ ph n

ầ t

ử trong m n

ả g theo cách

thông thường:

if (cards[0] == null) {

System.out.println("Chưa có quân bài nào!");

}

Nhưng n u

ế b n

ạ cố th

ử truy c p

ấ các bi n

ế th c

ự th

ể c a

ủ nh ng

ữ Card chưa tồn t i

ạ , b n

ạ s

ẽ nh n

ậ đư c

ợ bi t

ệ

lệ NullPointerException.

cards[0].rank; // NullPointerException

Nhưng đó l i

ạ là cú pháp đúng đ

ể truy c p

ậ rank (b c

ậ ) c a

ủ lá bài “th

ứ không” trong c .

ỗ Đây là m t

ộ ví d

ụ

khác c a

ủ phép h p,

ợ b n

ằ g cách k t

ế h p

ợ cú pháp truy c p

ậ ph n

ầ t

ử c a

ủ m ng

ả và truy c p

ậ m t

ộ bi n

ế th c

ự thể

c a

ủ đối tư ng

ợ .

Cách d

ễ nhất để đi n

ề nh ng

ữ đ i

ố tư ng

ợ Card đ y

ầ vào cỗ bài là vi t

ế nh ng

ữ vòng l p

ặ for l ng

ồ ghép (nghĩa

là vòng l p

ặ này đ t

ặ trong vòng l p

ặ khác):

int index = 0;

for (int suit = 0; suit <= 3; suit++) {

for (int rank = 1; rank <= 13; rank++) {

cards[index] = new Card(suit, rank);

index++;

}

}

Vòng l p

ặ ngoài cùng đ m

ế các ch t

ấ t

ừ 0 t i

ớ 3. V i

ớ t ng

ừ ch t

ấ , vòng l p

ặ trong đ m

ế các b c

ậ t

ừ 1 đ n

ế 13. Vì

vòng l p

ặ ngoài ch y

ạ 4 l n,

ầ và vòng l p

ặ trong ch y

ạ 13 l n,

ầ nên ph n

ầ thân đư c

ợ th c

ự hi n

ệ 52 l n.

ầ

Tôi đã dùng index để theo dõi lá bài ti p

ế theo s

ẽ c n

ầ ph i

ả đ t

ặ vào đâu trong c

ỗ bài. S

ơ đ

ồ tr n

ạ g thái sau

đây cho th y

ấ cỗ bài nh

ư thế nào sau khi hai lá bài đ u

ầ tiên đư c

ợ huy đ ng

ộ :

13.7 Phư n

ơ g thức printDeck

Khi làm vi c

ệ v i

ớ m n

ả g, cách ti n

ệ l i

ợ là có m t

ộ phư ng

ơ th c

ứ đ

ể in ra n i

ộ dung. Ta đã vài l n

ầ th y

ấ đư ng

ợ

d ng

ạ mẫu cho vi c

ệ duy t

ệ m n

ả g, b i

ở v y

ậ phư ng

ơ th c

ứ sau s

ẽ quen thu c

ộ đ i

ố v i

ớ b n:

ạ

public static void printDeck(Card[] cards) {

for (int i = 0; i < cards.length; i++) {

printCard(cards[i]);

}

}

Vì cards có ki u

ể là Card[], nên một ph n

ầ t

ử c a

ủ cards thì có ki u

ể là Card. Bởi v y

ậ cards[i] là một đối số

hợp lệ cho printCard.

13.8 Tìm ki m

ế

Phương th c

ứ ti p

ế theo mà tôi s

ẽ vi t

ế là findCard, đ

ể tìm ki m

ế trong m t

ộ m ng

ả ch a

ứ Card, xem li u

ệ r ng

ằ

m ng

ả này có ch a

ứ m t

ộ lá bài c

ụ th

ể hay không. Phư ng

ơ th c

ứ này cho tôi m t

ộ c

ơ h i

ộ bi u

ể di n

ễ hai thu t

ậ

toán: tìm ki m

ế tuy n

ế tính và tìm ki m

ế phân đôi.

Tìm ki m

ế tuy n

ế tính th t

ậ d

ễ hi u

ể ; ta duy t

ệ c

ả c

ỗ bài r i

ồ so sánh t ng

ừ lá bài v i

ớ lá mà ta đang tìm. N u

ế

th y

ấ , ta s

ẽ tr

ả về ch ỉs

ố t i

ạ đó lá bài xu t

ấ hi n.

ệ N u

ế không có trong c

ỗ bài, ta tr

ả v

ề -1.

public static int findCard(Card[] cards, Card card) {

for (int i = 0; i< cards.length; i++) {

if (sameCard(cards[i], card)) {

return i;

}

}

return -1;

}

Các đối số c a

ủ findCard là card và cards. Dường như th t

ậ kì qu c

ặ khi có m t

ộ bi n

ế cùng tên v i

ớ ki u

ể d

ữ

liệu (bi n

ế card thuộc ki u

ể Card). Ta có th

ể nh n

ậ th y

ấ s

ự khác bi t

ệ vì bi n

ế b t

ắ đ u

ầ b ng

ằ ch

ữ cái thư ng

ờ .

Phương th c

ứ này tr

ả l i

ạ ngay khi nó phát hi n

ệ ra lá bài c n

ầ tìm, ncos nghĩa là ta không c n

ầ ph i

ả duy t

ệ cả

c

ỗ bài n u

ế đã tìm đư c

ợ lá bài ta c n.

ầ Còn n u

ế ta đ n

ế đi m

ể cu i

ố vòng l p,

ặ ta bi t

ế r ng

ằ lá bài đó không có

trong cỗ.

Nếu các quân bài trong c

ỗ không đư c

ợ s p

ắ x p,

ế thì ch ng

ẳ có cách tìm ki m

ế nào nhanh h n

ơ cách này. Ta

ph i

ả nhìn t ng

ừ lá bài m t

ộ , b i

ở n u

ế không ta s

ẽ không ch c

ắ r ng

ằ quân bài mong mu n

ố không

ở đó.

Nhưng khi b n

ạ tra t

ừ trong m t

ộ cu n

ố t

ừ đi n,

ể b n

ạ l i

ạ không tìm tuy n

ế tính qua t ng

ừ t

ừ m t

ộ , b i

ở l

ẽ các

từ đ u

ề đư c

ợ x p

ế th

ứ t

ự r i

ồ . Do v y

ậ , có kh

ả năng b n

ạ s

ẽ dùng m t

ộ thu t

ậ toán tư ng

ơ t

ự nh

ư tìm ki m

ế chia

đôi:

1. B t

ắ đầu

ở một ch

ỗ gi a

ữ cu n

ố t

ừ đi n.

ể

2. Chọn một từ trên trang đó r i

ồ so sánh v i

ớ t

ừ c n

ầ tra.

3. Nếu b n

ạ tìm th y

ấ t

ừ c n

ầ tra thì d ng

ừ l i

ạ .

4. Nếu từ c n

ầ tra x p

ế sau t

ừ th y

ấ đư c

ợ trên trang, thì hãy l t

ậ đ n

ế m t

ộ ch

ỗ nào đó phía sau c a

ủ cu n

ố t

ừ

điển, rồi tr

ở l i

ạ bư c

ớ 2.

5. Nếu từ c n

ầ tra x p

ế trư c

ớ t

ừ th y

ấ đư c

ợ trên trang, thì hãy l t

ậ đ n

ế m t

ộ ch

ỗ nào đó phía trư c

ớ c a

ủ cu n

ố t

ừ

điển, rồi tr

ở l i

ạ bư c

ớ 2.

Nếu b n

ạ đã tìm đ n

ế ch

ỗ mà có hai t

ừ li n

ề k

ề nhau trong m t

ộ trang, và t

ừ c n

ầ tra l i

ạ n m

ằ gi a

ữ hai t

ừ đó,

thì có thể k t

ế lu n

ậ r ng

ằ t

ừ c n

ầ tra không có trong cu n

ố t

ừ đi n.

ể

Quay tr

ở l i

ạ v i

ớ c

ỗ bài, n u

ế ta bi t

ế r n

ằ g các lá bài đã đư c

ợ x p

ế th

ứ t ,

ự thì ta có th

ể vi t

ế m t

ộ phiên b n

ả

khác findCard, nhưng ch y

ạ nhanh h n.

ơ Cách t t

ố nh t

ấ đ

ể vi t

ế phư ng

ơ th c

ứ tìm ki m

ế chia đôi là dùng

cách đ

ệ quy, b i

ở vi c

ệ chia đôi v

ề b n

ả ch t

ấ là mang tính đ

ệ quy.

Một mẹo là vi t

ế một phương th c

ứ có tên findBisect trong đó nh n

ậ vào tham s

ố là hai ch ỉs ,

ố low và high,

quy đ nh

ị đo n

ạ trong m n

ả g c n

ầ đư c

ợ tìm ki m

ế (bao g m

ồ cả low và high).

1. Để tìm ki m

ế trên m ng

ả , hãy ch n

ọ m t

ộ ch ỉs

ố gi a

ữ low và high (g i

ọ nó là mid) rồi so sánh nó v i

ớ lá bài

c n

ầ tìm.

2. Nếu b n

ạ đã tìm th y

ấ nó thì d ng

ừ l i

ạ .

3. Nếu lá bài t i

ạ mid cao hơn lá bài c n

ầ tìm, thì tìm ki m

ế trong kho ng

ả từ low đến mid-1.

4. Nếu lá bài t i

ạ mid th p

ấ hơn lá bài c n

ầ tìm, thì tìm ki m

ế trong kho n

ả g từ mid+1 đến high.

Các bước 3 và 4 trông gi ng

ố nh ng

ữ l i

ờ g i

ọ đ

ệ quy đ n

ế m c

ứ đáng ng .

ờ Sau đây là toàn b

ộ ý tư ng

ở khi

chuy n

ể thành mã l nh

ệ Java:

public static int findBisect(Card[] cards, Card card, int low, int high) {

// CẦN LÀM: một trường hợp cơ sở

int mid = (high + low) / 2;

int comp = compareCard(cards[mid], card);

if (comp == 0) {

return mid;

} else if (comp > 0) {

return findBisect(cards, card, low, mid-1);

} else {

return findBisect(cards, card, mid+1, high);

}

}

Mã lệnh này có ch a

ứ ph n

ầ c t

ố lõi c a

ủ phép tìm ki m

ế chia đôi, song v n

ẫ thi u

ế m t

ộ ph n

ầ trong tr ng

ọ , đó

là lý do mà tôi đã ghi chú “C N

Ầ LÀM”. Nh

ư đã vi t

ế , phư ng

ơ th c

ứ này s

ẽ l p

ặ đ

ệ quy mãi mãi n u

ế nh

ư lá

bài không có trong c .

ỗ Ta c n

ầ m t

ộ trư ng

ờ h p

ợ c

ơ b n

ả đ

ể x

ử lý tình hu ng

ố này.

Nếu high nhỏ hơn low, thì không có lá bài nào gi a

ữ chúng, b i

ở v y

ậ ta s

ẽ k t

ế lu n

ậ r ng

ằ lá bài c n

ầ tìm

không có trong c .

ỗ N u

ế ta x

ử lý đư c

ợ trư ng

ờ h p

ợ đó, thì phư ng

ơ th c

ứ s

ẽ ho t

ạ đ ng

ộ đúng:

public static int findBisect(Card[] cards, Card card, int low, int high) {

System.out.println(low + ", " + high);

if (high < low) return -1;

int mid = (high + low) / 2;

int comp = compareCard(cards[mid], card);

if (comp == 0) {

return mid;

} else if (comp > 0) {

return findBisect(cards, card, low, mid-1);

} else {

return findBisect(cards, card, mid+1, high);

}

}

Tôi đã b

ổ sung m t

ộ l nh

ệ in đ

ể có th

ể theo dõi đư c

ợ m t

ộ lo t

ạ nh ng

ữ l n

ầ kích ho t

ạ đ

ệ quy. Tôi đã th

ử

đo n

ạ mã sau:

Card card1 = new Card(1, 11);

System.out.println(findBisect(cards, card1, 0, 51));

và nh n

ậ đư c

ợ k t

ế qu

ả dư i

ớ đây:

0, 51

0, 24

13, 24

19, 24

22, 24

23

Sau đó tôi l p

ậ m t

ộ lá bài không có trong c

ỗ (15 Rô), và th

ử c

ố tìm nó. Tôi đã nh n

ậ đư c

ợ k t

ế qu :

ả

0, 51

0, 24

13, 24

13, 17

13, 14

13, 12

-1

Những phép th

ử này không ch ng

ứ minh đư c

ợ r ng

ằ chư ng

ơ trình đúng đ n.

ắ Th c

ự t

ế là bao nhiêu ki m

ể

thử cũng không thể ch ng

ứ minh đư c

ợ tính đúng đ n

ắ nói trên. Song qua vi c

ệ xem xét m t

ộ vài trư ng

ờ

hợp và ki m

ể tra mã l nh

ệ , b n

ạ có th

ể t

ự thuy t

ế ph c

ụ b n

ả thân.

Số l n

ầ kích ho t

ạ đ

ệ quy thư ng

ờ t

ừ 6 đ n

ế 7, vì v y

ậ ta ch ỉkích ho t

ạ compareCard có 6 ho c

ặ 7 l n

ầ thôi, so

với t n

ậ 52 l n

ầ n u

ế tìm ki m

ế tuy n

ế tính. Nói chung, phép chia đôi thì nhanh h n

ơ nhi u

ề so v i

ớ tìm ki m

ế

tuyến tính, và cò nhanh n a

ữ v i

ớ các m ng

ả l n.

ớ

Có hai lỗi thư ng

ờ g p

ặ trong chư ng

ơ trình đ

ệ quy, đó là quên đ a

ư vào trư ng

ờ h p

ợ c

ơ s

ở và vi t

ế l i

ờ g i

ọ đ

ệ

quy song không bao gi

ờ d n

ẫ đ n

ế trư ng

ờ h p

ợ c

ơ s .

ở L i

ỗ sai nào cũng d n

ẫ đ n

ế đ

ệ quy vô h n,

ạ và bi t

ệ

lệ StackOverflowException sẽ đư c

ợ phát ra. (Hãy hình dung m t

ộ s

ơ đ

ồ ngăn x p

ế cho m t

ộ phư ng

ơ th c

ứ

đệ quy không bao gi

ờ k t

ế thúc.)

13.9 Cỗ bài và cỗ bài con

Sau đây là nguyên m u

ẫ (xem M c

ụ 8.5) c a

ủ findBisect:

public static int findBisect(Card[] deck, Card card, int low, int high) Ta có th

ể coi cards, low, và high ch ỉlà một thông số quy đ nh

ị m t

ộ c

ỗ bài con. Cách suy nghĩ này r t

ấ

thông d n

ụ g, và đôi khi đư c

ợ g i

ọ làtham s

ố tr u

ừ t n

ượ g. Ở đây, “trừu tượng” có nghĩa là th

ứ mà đúng

ra không có m t

ặ trên mã l nh

ệ chư ng

ơ trình, nh ng

ư l i

ạ di n

ễ t

ả tính năng c a

ủ chư ng

ơ trình theo c p

ấ đ

ộ ý

tưởng cao hơn.

Ch ng

ẳ h n,

ạ khi b n

ạ kích ho t

ạ m t

ộ phư ng

ơ th c

ứ r i

ồ truy n

ề vào m t

ộ m n

ả g cùng v i

ớ các gi i

ớ

h n

ạ low và high, không có gì ngăn c n

ả ươ c

ợ phư ng

ơ th c

ứ đã kích ho t

ạ kh i

ỏ truy c p

ậ ph n

ầ c a

ủ m ng

ả

nằm ngoài ph m

ạ vi gi i

ớ h n

ạ nói trên. B i

ở v y

ậ th t

ậ ra b n

ạ không g i

ử m t

ộ t p

ậ con c a

ủ c

ỗ bài; b n

ạ đang

gửi toàn b

ộ c

ỗ bài. Nh ng

ư mi n

ễ là b

ộ ph n

ậ ti p

ế nh n

ậ (t c

ứ là ph n

ầ n i

ộ dung phư ng

ơ th c

ứ ) tuân theo lu t

ậ

ch i

ơ , thì ta có th

ể coi r ng

ằ đó chính là m t

ộ c

ỗ bài con.

Hình th c

ứ suy nghĩ này, trong đó chư ng

ơ trình có hàm ý cao xa h n

ơ là nh ng

ữ câu mã l nh

ệ , chính là m t

ộ

ph n

ầ quan tr ng

ọ trong t

ư duy nhà khoa h c

ọ máy tính. T

ừ “tr u

ừ tư ng

ợ ” đã xu t

ấ hi n

ệ quá nhi u

ề trong

nhiều ngữ c nh

ả khác nhau và đi u

ề này khi n

ế cho ý nghĩa c a

ủ nó b ịloãng đi. M c

ặ dù v y

ậ , tr u

ừ

t

n

ượ g chính là một ý tư ng

ở tr ng

ọ tâm trong ngành khoa h c

ọ máy tính (cũng nh

ư nhi u

ề ngành khác).

Một đ nh

ị nghĩa khái quát h n

ơ cho “tr u

ừ tư ng

ợ ” là “Quá trình mô hình hóa m t

ộ h

ệ th ng

ố ph c

ứ t p

ạ b n

ằ g

diễn gi i

ả được gi n

ả hóa, nh m

ằ lư c

ợ đi nh ng

ữ chi ti t

ế không liên quan đ ng

ồ th i

ờ n m

ắ b t

ắ đư c

ợ nh ng

ữ

động thái mà ta c n

ầ quan tâm.”

13.10 Thu t

ậ ngữ

mã hóa:

Vi c

ệ bi u

ể di n

ễ m t

ộ t p

ậ h p

ợ các giá tr ịb ng

ằ m t

ộ t p

ậ h p

ợ các giá tr ịkhác, b ng

ằ vi c

ệ thi t

ế l p

ậ m t

ộ ánh

xạ gi a

ữ chúng.

gi n

ố g h t

ệ :

Sự bằng nhau gi a

ữ các tham chi u

ế . Hai tham chi u

ế ch ỉđ n

ế cùng m t

ộ đ i

ố tư ng

ợ trong b

ộ nh .

ớ

t

n

ươ g đ n

ồ g:

Sự bằng nhau gi a

ữ các giá tr .ị Hai tham chi u

ế ch ỉđ n

ế hai đ i

ố t ng

ượ ch a

ứ d

ữ li u

ệ gi ng

ố nhau.

tham s

ố tr u

ừ t n

ượ g:

Một tập h p

ợ gồm các tham s

ố hoạt đ ng

ộ cùng nhau nh

ư m t

ộ tham s

ố th ng

ố nh t

ấ .

tr u

ừ tượng:

Quá trình di n

ễ gi i

ả m t

ộ ch ng

ươ trình (hay th

ứ khác)

ở m t

ộ c p

ấ đ

ộ cao h n

ơ so v i

ớ nh ng

ữ gì đư c

ợ

viết dư i

ớ d ng

ạ mã l nh.

ệ

13.11 Bài t p

ậ

Bài t p

ậ 1 Hãy gói b c

ọ mã l nh

ệ trong M c

ụ 13.5 vào một phương th c

ứ . Sau đó ch nh

ỉ s a

ử nó đ

ể b c

ậ c a

ủ

Át cao h n

ơ K.

Bài t p

ậ 2 Hãy gói b c

ọ mã l nh

ệ thi t

ế l p

ậ c

ỗ bài

ở M c

ụ 13.6 vào trong một phư ng

ơ th c

ứ có

tên makeDeck không nh n

ậ tham s

ố nào và tr

ả l i

ạ m t

ộ m ng

ả đã đi n

ề đ y

ầ đ

ủ nh ng

ữ lá bài (Card).

Bài t p

ậ 3 Trong trò ch i

ơ Blackjack, m c

ụ tiêu là l y

ấ đư c

ợ m t

ộ nhóm cây bài có t ng

ổ đi m

ể b ng

ằ 21.

Đi m

ể c a

ủ nhóm bài b ng

ằ t ng

ổ các đi m

ể trên nh ng

ữ cây bài. Đi m

ể cho nh ng

ữ quân Át b ng

ằ 1, cho nh ng

ữ

quân bài m t

ặ ngư i

ờ b ng

ằ 10, và nh ng

ữ quân khác thì đi m

ể đúng b ng

ằ b c

ậ . Ch ng

ẳ h n

ạ , nhóm ba quân

bài (Ace, 10, Jack, 3) có t ng

ổ đi m

ể là 1 + 10 + 10 + 3 = 24. Hãy vi t

ế một phương th c

ứ có

tên handScore nh n

ậ vào đối ó

ố là m t

ộ m n

ả g nh ng

ữ lá bài r i

ồ tr

ả l i

ạ t ng

ổ đi m

ể .

Bài t p

ậ 4 Trong trò ch i

ơ Poker, m t

ộ “dây” (flush) là m t

ộ nhóm lá bài có t

ừ 5 lá tr

ở lên cùng ch t

ấ . M t

ộ

nhóm bài có th

ể ch a

ứ bao nhiêu lá bài cũng đư c

ợ .

1. Hãy vi t

ế một phư ng

ơ th c

ứ có tên suitHist nh n

ậ tham số là một m ng

ả g m

ồ nh ng

ữ Card r i

ồ tr

ả l i

ạ m t

ộ

histogram các ch t

ấ trong nhóm. L i

ờ gi i

ả c a

ủ b n

ạ ch ỉđư c

ợ duy t

ệ m ng

ả đúng m t

ộ l n

ầ .

2. Hãy vi t

ế một phư ng

ơ th c

ứ hasFlush nh n

ậ tham số là một m n

ả g nh ng

ữ Card r i

ồ tr

ả l i

ạ true nếu nhóm

bài có ch a

ứ dây, và false nếu không.

Bài t p

ậ 5 Làm vi c

ệ v i

ớ nh ng

ữ cây bài s

ẽ hay h n

ơ n u

ế b n

ạ hi n

ể th ịđư c

ợ chúng lên màn hình. N u

ế b n

ạ

chưa t ng

ừ th

ử nh ng

ữ ví d

ụ đ

ồ h a

ọ

ở Ph

ụ l c

ụ A, bây gi

ờ có thể s

ẽ là lúc thích h p.

ợ Trư c

ớ h t

ế , hãy t i

ả

về http://thinkapjava.com/code/CardTable.java và http://thinkapjava.com/code/cardset.zip vào cùng một thư m c

ụ . Sau đó, gi i

ả nén cardset.zip, vốn có ch a

ứ một th

ư m c

ụ con cardset-oxymoron với tất cả

hình c a

ủ nh ng

ữ quân bài. (Lưu ý r n

ằ g bi n

ế cardset trong CardTable.main chính là tên c a

ủ th

ư m c

ụ này.)

Ch y

ạ CardTable.java và b n

ạ có th

ể th y

ấ hình nh

ả m t

ộ c

ỗ bài tr i

ả ra trên bàn màu xanh. B n

ạ có th

ể dùng

lớp này để kh i

ở đầu l p

ậ nên nh ng

ữ trò ch i

ơ bài riêng.

Ch

ng

ươ 14: Đ i

ố tư ng

ợ

ch a

ứ các m ng

ả

Trở về M c

ụ l c

ụ cuốn sách CẢNH BÁO: Trong chư ng

ơ này, ta ti n

ế thêm m t

ộ bư c

ớ n a

ữ v

ề l p

ậ hư ng

ớ đ i

ố tư ng

ợ nh ng

ư v n

ẫ ch a

ư h n

ẳ

đến đư c

ợ đó. B i

ở v y

ậ , nhi u

ề ví d

ụ v n

ẫ ch a

ư đúng gi ng

ọ Java, nghĩa là ch a

ư ph i

ả mã l nh

ệ Java chu n

ẩ .

Hình th c

ứ trung chuy n

ể này (hi v ng

ọ r ng

ằ ) s

ẽ giúp b n

ạ h c

ọ , nh ng

ư th c

ự t

ế tôi không vi t

ế mã l nh

ệ nh

ư

thế này.

B n

ạ có thể t i

ả v

ề mã l nh

ệ cho chư ng

ơ này t :

ừ http://thinkapjava.com/code/Card2.java.

14.1 L p

ớ Deck

Ở chương trước, ta đã làm vi c

ệ v i

ớ m t

ộ m n

ả g các đ i

ố tư ng

ợ , nh ng

ư cũng đ

ề c p

ậ r ng

ằ hoàn toàn có th

ể

có đ i

ố tư ng

ợ có ch a

ứ bi n

ế th c

ự th

ể là m ng

ả . Trong chư ng

ơ này, ta t o

ạ ra m t

ộ đ i

ố tư ng

ợ Deck có chứa

một m n

ả g nh ng

ữ đ i

ố tư ng

ợ Card.

Lời đ nh

ị nghĩa l p

ớ s

ẽ trông nh

ư sau:

class Deck {

Card[] cards;

public Deck(int n) {

this.cards = new Card[n];

}

}

Ở đây, constructor kh i

ở t o

ạ bi n

ế th c

ự th

ể là m t

ộ m ng

ả nh ng

ữ lá bài, nh ng

ư nó không t o

ạ nên lá bài nào.

Sau đây là s

ơ đ

ồ tr n

ạ g thái cho th y

ấ Deck mà không có lá bài nào kèm theo:

Dưới đây là m t

ộ constructor không có đ i

ố s

ố đ

ể t o

ạ nên m t

ộ c

ỗ bài 52 lá r i

ồ đi n

ề đ y

ầ nh ng

ữ đ i

ố

tượng Card vào nó:

public Deck() {

this.cards = new Card[52];

int index = 0;

for (int suit = 0; suit <= 3; suit++) {

for (int rank = 1; rank <= 13; rank++) {

cards[index] = new Card(suit, rank);

index++;

}

}

}

Phương th c

ứ này tư ng

ơ t

ự như makeDeck; ta chỉ vi c

ệ thay đ i

ổ cú pháp đ

ể nó tr

ở thành m t

ộ constructor.

Để kích ho t

ạ nó, ta dùng new:

Deck deck = new Deck();

Bây gi

ờ vi c

ệ đ t

ặ các phư ng

ơ th c

ứ thu c

ộ v

ề các đ i

ố tư ng

ợ Deck vào trong l i

ờ đ nh

ị nghĩa l p

ớ Deck là hợp

lý. Khi xem xét nh ng

ữ phư ng

ơ th c

ứ mà ta đã vi t

ế cho đ n

ế gi ,

ờ d

ễ th y

ấ m t

ộ ng

ứ c

ử viên đó

là printDeck (M c

ụ 13.7). Sau đây là dáng v

ẻ c a

ủ nó, đư c

ợ vi t

ế l i

ạ đ

ể ho t

ạ đ ng

ộ v i

ớ Deck:

public static void printDeck(Deck deck) {

for (int i = 0; i < deck.cards.length; i++) {

Card.printCard(deck.cards[i]);

}

}

Một sự thay đổi là ki u

ể c a

ủ tham s ,

ố từ Card[] sang Deck.

Thay đổi th

ứ hai là ta không còn dùng đư c

ợ deck.length để l y

ấ chi u

ề dài c a

ủ m n

ả g, b i

ở gi

ờ đây deck đã

là một đối tượng Deck, chứ không ph i

ả m t

ộ m n

ả g. Nó ch a

ứ m t

ộ m n

ả g, nh ng

ư nó không ph i

ả là m n

ả g.

B i

ở v y

ậ ta ph i

ả vi t

ế deck.cards.length để kết xu t

ấ đư c

ợ m n

ả g t

ừ đ i

ố tư ng

ợ Deck rồi l y

ấ chi u

ề dài c a

ủ

m ng

ả này.

Với lý do tư ng

ơ t ,

ự ta ph i

ả dùng deck.cards[i] để truy c p

ậ một ph n

ầ t

ử c a

ủ m ng

ả , thay vì ch ỉvi t

ế deck[i].

Sự thay đổi cu i

ố cùng là vi c

ệ kích ho t

ạ printCard ph i

ả nói rõ r n

ằ g printCard đư c

ợ đ nh

ị nghĩa trong

lớp Card.

14.2 Tráo bài

Trong ph n

ầ l n

ớ các trò ch i

ơ bài tây, b n

ạ c n

ầ ph i

ả tráo c

ỗ bài; nghĩa là x p

ế bài theo m t

ộ tr t

ậ t

ự ng u

ẫ

nhiên.

Ở M c

ụ 12.6 ta đã th y

ấ cách phát sinh s

ố ng u

ẫ nhiên, song th t

ậ không d

ễ th y

ấ cách áp d ng

ụ đ

ể

tráo cỗ bài.

Một kh

ả năng là mô ph ng

ỏ cách con ngư i

ờ tráo bài, thư ng

ờ là chia c

ỗ bài làm đôi r i

ồ ch n

ọ bài đan xen

từ từng ph n

ầ . B i

ở ngư i

ờ thư ng

ờ không thể tráo chính xác theo cách này đư c

ợ , nên sau ch ng

ừ 7 l n

ầ l p

ặ

l i

ạ thao tác thì c

ỗ bài dư ng

ờ nh

ư đã hoàn toàn ng u

ẫ nhiên. Song m t

ộ chư ng

ơ trình máy tính thì l i

ạ có

đ c

ặ đi m

ể luôn trộn bài th t

ậ hoàn h o

ả nên k t

ế qu

ả s

ẽ không th t

ậ ng u

ẫ nhiên. Th c

ự t

ế là, sau 8 l n

ầ tr n,

ộ

máy s

ẽ làm cho c

ỗ bài v

ề nguyên tr n

ạ g. B n

ạ có th

ể xem thông tin thêm

ở http://en.wikipedia.org/wiki/Faro_shuffle.

Một thuật toán trộn bài h p

ợ lý h n

ơ là trong m i

ỗ l n

ầ duy t

ệ ch ỉl t

ậ m t

ộ lá bài, và m i

ỗ l n

ầ l p

ặ thì ch n

ọ l y

ấ

hai lá bài r i

ồ đ i

ổ ch

ỗ chúng.

Sau đây là phác th o

ả cách ho t

ạ đ ng

ộ c a

ủ thu t

ậ toán này. Đ

ể phác h a

ọ chư ng

ơ trình, tôi k t

ế h p

ợ câu l nh

ệ

Java v i

ớ ngôn ngữ nói, mà đôi khi đư c

ợ g i

ọ là gi

ả mã:

for (int i = 0; i < deck.cards.length; i++) {

// chọn một số nằm giữa 1 và deck.cards.length-1

// đổi chỗ lá bài thứ i và lá bài ngẫu nhiên được chọn

}

Đi u

ề hay

ở gi

ả mã là nó thư ng

ờ làm rõ nh ng

ữ phư ng

ơ th c

ứ nào mà b n

ạ s p

ắ c n

ầ có. Trong trư ng

ờ h p

ợ

này, ta c n

ầ một th

ứ như randomInt, đ

ể chọn một số nguyên ng u

ẫ nhiên gi a

ữ low và high,

và swapCards để nh n

ậ vào hai ch ỉs

ố r i

ồ đ i

ổ ch

ỗ hai lá bài

ở v ịtrí các ch ỉs

ố đó.

Quá trình này—vi t

ế gi

ả mã trư c

ớ r i

ồ m i

ớ vi t

ế phư ng

ơ th c

ứ th c

ự hi n

ệ sau—đư c

ợ g i

ọ là phát tri n

ể t

ừ

trên xu n

ố g (xem http://en.wikipedia.org/wiki/Top-down_and_bottom-up_design).

14.3 S p

ắ xếp

Bây gi

ờ khi đã làm c

ỗ bài l n

ẫ lung tung lên, ta c n

ầ m t

ộ cách khi n

ế nó tr

ở l i

ạ tr t

ậ t .

ự Có m t

ộ thu t

ậ toán

s p

ắ xếp giống v i

ớ thu t

ậ toán tr n

ộ đ n

ế không ng .

ờ Nó đư c

ợ g i

ọ là s p

ắ xếp ch n

ọ bởi nó ho t

ạ đ ng

ộ d a

ự

trên vi c

ệ duy t

ệ m ng

ả l p

ặ đi l p

ặ l i

ạ và m i

ỗ l n

ầ duy t

ệ thì ch n

ọ l y

ấ lá bài th p

ấ nh t

ấ còn l i

ạ .

Trong l n

ầ l p

ặ th

ứ nh t

ấ , ta tìm l y

ấ lá bài th p

ấ nh t

ấ r i

ồ đ i

ổ ch

ỗ cho lá bài

ở v ịtrí th

ứ 0. Trong l n

ầ l p

ặ

thứ i, ta tìm l y

ấ lá bài th p

ấ nh t

ấ bên ph i

ả v ịtrí i rồi đ i

ổ chỗ nó cho lá bài thứ i.

Sau đây là gi

ả mã cho cách s p

ắ x p

ế ch n:

ọ

for (int i = 0; i < deck.cards.length; i++) {

// tìm lấy lá bài thấp nhất tại vị trí i, hoặc bên phải chỗ đó

// đổi chỗ lá bài thứ i với lá bài thấp nhất tìm được }

Một l n

ầ n a

ữ , giả mã giúp cho vi c

ệ thi t

ế k

ế các ph n

ươ g th c

ứ tr

ợ giúp. Trong trư ng

ờ h p

ợ này, ta có thể

dùng l i

ạ swapCards, bởi v y

ậ ta ch ỉc n

ầ có m t

ộ phư ng

ơ th c

ứ m i

ớ , có tên indexLowestCard, đ

ể nh n

ậ một

m ng

ả nh ng

ữ lá bài và m t

ộ ch ỉs

ố n i

ơ c n

ầ b t

ắ đ u

ầ tìm ki m

ế .

14.4 Cỗ bài con

V y

ậ ta nên bi u

ể di n

ễ m t

ộ ph n

ầ bài hay m t

ộ d ng

ạ t p

ậ con c a

ủ c

ỗ bài đ

ủ nh

ư th

ế nào? M t

ộ kh

ả năng là

t o

ạ nên một l p

ớ m i

ớ có tên Hand, và nó có thể m

ở r ng

ộ Deck. Một kh

ả năng khác, nh

ư tôi trình bày

ở

đây, là bi u

ể di n

ễ m t

ộ ph n

ầ bài b ng

ằ đ i

ố tư ng

ợ Deck nhưng có ít h n

ơ 52 lá bài.

Ta có th

ể muốn một phư ng

ơ th c

ứ , subdeck, đ

ể nh n

ậ một c

ỗ bài và m t

ộ kho n

ả g ch ỉs ,

ố r i

ồ tr

ả l i

ạ m t

ộ c

ỗ

bài m i

ớ ch a

ứ t p

ậ con nh ng

ữ lá bài đã ch ỉđ nh

ị :

public static Deck subdeck(Deck deck, int low, int high) {

Deck sub = new Deck(high-low+1);

for (int i = 0; i<sub.cards.length; i++) {

sub.cards[i] = deck.cards[low+i];

}

return sub;

}

Chiều dài c a

ủ c

ỗ bài con là high-low+1 bởi c

ả lá bài th p

ấ (low) l n

ẫ cao (high) đ u

ề đư c

ợ tính vào. Cách

tính có thể gây nh m

ầ l n,

ẫ và d n

ẫ đ n

ế l i

ỗ “l c

ệ h m t

ộ ”. Cách tránh l i

ỗ này t t

ố nh t

ấ thư ng

ờ là v

ẽ hình minh

họa.

Vì ta đã cung c p

ấ new vào một đ i

ố s ,

ố nên contructor đư c

ợ kích ho t

ạ s

ẽ là cái đ u

ầ tiên, v n

ố ch ỉhuy đ ng

ộ

m ng

ả mà không huy đ ng

ộ b t

ấ kì lá bài nào. Bên trong vòng l p

ặ for, cỗ bài con đư c

ợ đi n

ề đ y

ầ nh ng

ữ b n

ả

sao tham chi u

ế t

ừ c

ỗ bài l n.

ớ

Dưới đây là s

ơ đ

ồ tr ng

ạ thái c a

ủ c

ỗ bài con đư c

ợ t o

ạ nên b ng

ằ nh ng

ữ tham số low=3 và high=7. K t

ế quả

là một ph n

ầ bài g m

ồ 5 lá đư c

ợ chung v i

ớ c

ỗ bài ban đ u

ầ ; nghĩa là theo cách đ t

ặ bí danh (alias).

Cách đ t

ặ bí danh này thư ng

ờ không ph i

ả ý tư ng

ở hay, b i

ở nh ng

ữ thay đ i

ổ trong m t

ộ c

ỗ bài con l i

ạ đư c

ợ

thể hiện ở những cỗ khác; đây không ph i

ả là đ ng

ộ thái mà b n

ạ trông đ i

ợ

ở nh ng

ữ b

ộ bài th t

ậ . Song n u

ế

các lá bài là đ i

ố tư ng

ợ không thay đ i

ổ đư c

ợ , thì vi c

ệ đ t

ặ bí danh ít nguy hi m

ể h n.

ơ Trong trư ng

ờ h p

ợ

này, có l

ẽ ch n

ẳ g có lý do nào đ

ể thay đ i

ổ b c

ậ hay ch t

ấ c a

ủ lá bài. Thay vì v y

ậ , ta có th

ể m i

ỗ lúc l i

ạ t o

ạ ra

một lá bài r i

ồ coi nó nh

ư m t

ộ đ i

ố tư ng

ợ không thay đ i

ổ đư c

ợ . B i

ở v y

ậ , đ i

ố v i

ớ Card, việc đ t

ặ bí danh là

lựa chọn h p

ợ lý.

14.5 Tráo bài và chia bài

Ở M c

ụ 14.2, tôi đã vi t

ế gi

ả mã cho thu t

ậ toán tr n

ộ bài. Coi nh

ư ta đã có m t

ộ phư ng

ơ

thức shuffleDeck nh n

ậ tham số là một cỗ bài r i

ồ tr n

ộ nó lên, ta có th

ể s

ử d ng

ụ nó đ

ể chia thành nhi u

ề

ph n

ầ bài:

Deck deck = new Deck();

shuffleDeck(deck);

Deck hand1 = subdeck(deck, 0, 4);

Deck hand2 = subdeck(deck, 5, 9);

Deck pack = subdeck(deck, 10, 51);

Mã lệnh này đặt 5 lá bài đ u

ầ tiên vào ph n

ầ th

ứ nh t

ấ , 5 lá bài k

ế ti p

ế vào ph n

ầ th

ứ hai, và ph n

ầ còn l i

ạ

giữ

ở cỗ.

Khi b n

ạ hình dung cách chia bài, b n

ạ có nghĩ r n

ằ g ta nên chia vòng tròn nh

ư đánh bài th t

ậ không? Tôi

cũng nghĩ v

ề đi u

ề này, song nh n

ậ th y

ấ r ng

ằ v i

ớ chư ng

ơ trình máy tính thì nh

ư v y

ậ không c n

ầ thi t

ế . Quy

t c

ắ chia vòng tròn ch ỉđ

ể gi m

ả thi u

ể kh

ả năng tráo bài ch a

ư kĩ và đ

ể cho ngư i

ờ chia khó ch i

ơ ăn gian

hơn. Hai đi u

ề này không thành v n

ấ đề đ i

ố v i

ớ máy tính.

Ví d

ụ này là l i

ờ nh c

ắ h

ở h u

ữ ích v

ề m t

ộ trong nh ng

ữ nguy hi m

ể c a

ủ phép n

ẩ d

ụ trong kĩ thu t

ậ : đôi khi ta

quy đ nh

ị nh ng

ữ h n

ạ ch

ế không c n

ầ thi t

ế lên máy tính, ho c

ặ trông ch

ờ nh ng

ữ tính năng không có s n,

ẵ

bởi ta đã không suy nghĩ khi m

ở r ng

ộ m t

ộ hình nh

ả n

ẩ d

ụ vư t

ợ quá gi i

ớ h n

ạ c a

ủ nó r i

ồ .

14.6 S p

ắ x p

ế tr n

ộ

Ở M c

ụ 14.3, ta đã th y

ấ m t

ộ thu t

ậ toán s p

ắ x p

ế đ n

ơ gi n

ả nh ng

ư hóa ra không hi u

ệ qu .

ả Đ

ể s p

ắ

xếp n ph n

ầ tử, nó ph i

ả duy t

ệ m ng

ả n l n,

ầ và mỗi l n

ầ duy t

ệ t n

ố m t

ộ kho ng

ả th i

ờ gian t ỉl

ệ v i

ớ n. Do đó,

thời gian tổng cộng sẽ tỉ l

ệ v i

ớ n 2.

Trong m c

ụ này tôi phác th o

ả m t

ộ thu t

ậ toán hi u

ệ qu

ả h n,

ơ có tên g i

ọ s p

ắ x p

ế tr n

ộ . Đ

ể s p

ắ x p

ế n ph n

ầ

tử, phương pháp này t n

ố m t

ộ th i

ờ gian t ỉl

ệ v i

ớ n log n. Như v y

ậ có v

ẻ ch a

ư n

ấ tư ng

ợ l m

ắ , song khi n lớn

lên, hi u

ệ số giữa n 2 và n log n có thể s

ẽ r t

ấ l n.

ớ Hãy thử vài giá tr ịc a

ủ n xem sao.

Ý tưởng cơ b n

ả phía sau phép s p

ắ x p

ế tr n

ộ là th

ế này: N u

ế b n

ạ có 2 ph n

ầ bài, t ng

ừ ph n

ầ đã đư c

ợ s p

ắ

xếp rồi, thì r t

ấ d

ễ (và nhanh chóng) đ

ể tr n

ộ ghép chúng thành m t

ộ c

ỗ bài duy nh t

ấ đư c

ợ s p

ắ x p

ế đúng.

Hãy th

ử làm đi u

ề này v i

ớ m t

ộ c

ỗ bài xem sao:

1. Hình thành hai ph n

ầ bài v i

ớ m i

ỗ ph n

ầ kho n

ả g 10 lá r i

ồ s p

ắ x p

ế chúng đ

ể cho khi đ t

ặ ng a

ử m t

ặ lên thì

các lá bài th p

ấ

ở trên. Đ t

ặ hai ph n

ầ bài này trư c

ớ m t

ặ b n.

ạ

2. So sánh hai lá bài

ở trên cùng c a

ủ m i

ỗ ph n

ầ r i

ồ ch n

ọ lá bài th p

ấ h n.

ơ L t

ậ úp nó r i

ồ đ a

ư nó vào ph n

ầ bài

riêng đư c

ợ s p

ắ x p.

ế

3. L p

ặ l i

ạ bư c

ớ Hai đ n

ế khi m t

ộ ph n

ầ bài đã h t

ế . Sau đó l y

ấ nh ng

ữ lá bài còn l i

ạ r i

ồ thêm vào ph n

ầ bài

được s p

ắ x p.

ế

Kết qu

ả ta s

ẽ đư c

ợ m t

ộ ph n

ầ bài chung đư c

ợ x p

ế đúng. Sau đây là cách làm b n

ằ g gi

ả mã:

public static Deck merge(Deck d1, Deck d2) {

// tạo nên một cỗ bài đủ lớn chứa hết các quân bài

Deck result = new Deck(d1.cards.length + d2.cards.length);

// dùng chỉ số i để theo dõi vị trí hiện tại trên

// phần bài thứ nhất, và chỉ số j cho phần bài thứ hai

int i = 0;

int j = 0;

// chỉ số k duyệt theo phần bài được xếp đúng

for (int k = 0; k < result.cards.length; k++) {

// nếu d1 rỗng thì d2 thắng; nếu d2 rỗng, d1 thắng;

// nếu không, đi so sánh hai lá bài

// thêm lá bài thắng vào phần bài được xếp đúng

}

return result;

}

Cách hay nh t

ấ đ

ể ki m

ể tra merge là l p

ậ nên và tr n

ộ m t

ộ c

ỗ bài, dùng phư ng

ơ th c

ứ subdeck đ

ể hình

thành nên hai ph n

ầ bài (nh )

ỏ , r i

ồ dùng th

ủ t c

ụ sort t

ừ chư ng

ơ trư c

ớ đ

ể s p

ắ x p

ế hai n a

ử . Sau đó b n

ạ có

thể truyền hai n a

ử này vào merge để xem phư ng

ơ th c

ứ m i

ớ này có ho t

ạ đ ng

ộ không.

Nếu b n

ạ có th

ể làm cho m i

ọ th

ứ nh

ư trên ho t

ạ đ ng

ộ đư c

ợ , hãy th

ử m t

ộ phiên b n

ả mergeSort đơn gi n:

ả

public static Deck mergeSort(Deck deck) {

// tìm điểm giữa của cỗ bài

// chia cỗ bài thành hai phần nhỏ

// xếp phần nhỏ bằng sortDeck

// trộn hai nửa rồi trả lại kết quả

}

Sau đó, n u

ế nh

ư b n

ạ làm cho phư ng

ơ th c

ứ ho t

ạ đ ng

ộ đư c

ợ , s

ẽ có cái hay! Đi u

ề kì di u

ệ v

ề s p

ắ x p

ế tr n

ộ

là nó có tính đ

ệ quy.

Ở lúc mà b n

ạ b t

ắ đ u

ầ s p

ắ x p

ế các ph n

ầ bài, t i

ạ sao ph i

ả kích ho t

ạ phư ng

ơ

thức sort cũ và ch m

ậ ch p?

ạ Sao không kích ho t

ạ phư ng

ơ th c

ứ mergeSort mới toanh, đang đư c

ợ vi t

ế ?

Đây không ch ỉlà m t

ộ ý tư ng

ở t t

ố , mà cần thiết ph i

ả đ t

ạ đư c

ợ u

ư th

ế v

ề hi u

ệ năng c a

ủ chư ng

ơ trình mà

tôi đã h a

ứ . Nh ng

ư để chư ng

ơ trình ho t

ạ đ ng

ộ , b n

ạ c n

ầ ph i

ả có m t

ộ trư ng

ờ h p

ợ c

ơ s .

ở N u

ế không, đ

ệ

quy sẽ mãi mãi. M t

ộ trư ng

ờ h p

ợ c

ơ s

ở đ n

ơ gi n

ả là m t

ộ ph n

ầ bài v i

ớ 0 ho c

ặ 1 lá bài. N u

ế

như mergesort nh n

ậ được một ph n

ầ bài nh

ỏ nh

ư v y

ậ , thì nó có th

ể tr

ả l i

ạ k t

ế qu

ả y nguyên, b i

ở ph n

ầ

bài nhỏ này đã đư c

ợ s p

ắ x p.

ế

Phiên b n

ả đ

ệ quy c a

ủ mergesort có th

ể sẽ trông nh

ư sau:

public static Deck mergeSort(Deck deck) {

// nếu cỗ bài chỉ gồm 0 hoặc 1 lá bài, thì trả lại nó

// tìm ra điểm giữa của cỗ bài

// chia cỗ bài thành hai phần bài

// sắp xếp các phần bài này bằng mergesort

// trộn ghép lại hai nửa rồi trả lại kết quả

}

Như thường l ,

ệ có hai cách nghĩ v

ề chư ng

ơ trình đ

ệ quy: B n

ạ có th

ể nghĩ qua toàn b

ộ lu ng

ồ th c

ự thi,

hay b n

ạ có thể d a

ự vào “ni m

ề tin” (xem M c

ụ 6.9). Tôi đã xây d ng

ự ví d

ụ này đ

ể khuy n

ế khích b n

ạ t

ư

duy theo ni m

ề tin nh

ư v y

ậ .

Khi dử d n

ụ g sortDeck để s p

ắ xếp các ph n

ầ bài, b n

ạ không th y

ấ b ịthôi thúc ph i

ả theo lu ng

ồ th c

ự thi,

ph i

ả không? B n

ạ ch ỉvi c

ệ gi

ả s

ử r ng

ằ nó ho t

ạ đ ng

ộ đư c

ợ vì b n

ạ đã g

ỡ l i

ỗ cho nó r i

ồ . ,

Ồ t t

ấ c

ả nh ng

ữ đi u

ề

mà b n

ạ đã làm cho mergeSort trở nên đ

ệ quy là thay thế m t

ộ thu t

ậ toán s p

ắ x p

ế này v i

ớ thu t

ậ toán

khác. Không có lý do gì đ

ể đ c

ọ chư ng

ơ trình khác đi c .

ả

Thực ra, b n

ạ ph i

ả nghĩ m t

ộ chút m i

ớ l p

ậ đư c

ợ trư ng

ờ h p

ợ c

ơ s

ở đúng đ n

ắ và đ m

ả b o

ả r n

ằ g cu i

ố cùng

b n

ạ sẽ đ t

ạ đ n

ế trường h p

ợ c

ơ s

ở này. Song ngoài đi u

ề đó ra, vi c

ệ vi t

ế nên phiên b n

ả đ

ệ quy h n

ẳ s

ẽ

không còn v n

ấ đ

ề n a

ữ . Chúc b n

ạ may m n!

ắ

14.7 Biến l p

ớ

Đến giờ ta đã th y

ấ nh ng

ữ bi n

ế đ a

ị phư ng

ơ , v n

ố đư c

ợ khai báo bên trong phư ng

ơ th c

ứ , và bi n

ế th c

ự th ,

ể

vốn được khai báo

ở l i

ờ đ nh

ị nghĩa l p,

ớ thư ng

ờ đi trư c

ớ các đ nh

ị nghĩa phư ng

ơ th c

ứ .

Các bi n

ế đ a

ị phư ng

ơ đư c

ợ t o

ạ nên khi m t

ộ phư ng

ơ th c

ứ đư c

ợ kích ho t

ạ và phá h y

ủ khi phư ng

ơ th c

ứ k t

ế

thúc. Các bi n

ế th c

ự th

ể đư c

ợ t o

ạ nên khi b n

ạ t o

ạ nên m t

ộ đ i

ố tư ng

ợ ; các bi n

ế này b ịphá h y

ủ khi đ i

ố

tượng b ịthu hồi rác b

ộ nh .

ớ

Bây gi

ờ là lúc bi t

ế về biến l p

ớ . Giống như bi n

ế th c

ự th ,

ể bi n

ế l p

ớ đư c

ợ đ nh

ị nghĩa trong m t

ộ l i

ờ đ n

ị h

nghĩa l p

ớ trư c

ớ nh ng

ữ đ nh

ị nghĩa phư ng

ơ th c

ứ , song chúng đư c

ợ nh n

ậ di n

ệ b n

ằ g t

ừ khóa static. Chúng

được t o

ạ nên khi chư ng

ơ trình kh i

ở đ u

ầ và còn t n

ồ t i

ạ đ n

ế t n

ậ khi chư ng

ơ trình k t

ế thúc.

B n

ạ có thể tham chi u

ế t i

ớ biên th c

ự th

ể t

ừ b t

ấ kì đâu bên trong l i

ờ khai báo l p.

ớ Nh ng

ữ bi n

ế l p

ớ thư ng

ờ

được dùng đ

ể l u

ư các giá tr ịh ng

ằ s

ố c n

ầ thi t

ế

ở nhi u

ề ch .

ỗ

L y

ấ ví d ,

ụ sau đây là m t

ộ phiên b n

ả c a

ủ Card trong đó suits và ranks là những bi n

ế l p:

ớ

class Card {

int suit, rank;

static String[] suits = { "Clubs", "Diamonds", "Hearts", "Spades" }; static String[] ranks = { "narf", "Ace", "2", "3", "4", "5", "6", "7", "8", "9",

"10", "Jack", "Queen", "King" }; public static void printCard(Card c) {

System.out.println(ranks[c.rank] + " of " + suits[c.suit]);

}

}

Bên trong printCard ta có th

ể tham chi u

ế t i

ớ suits và ranks như thể chúng là các bi n

ế đ a

ị phư ng

ơ .

14.8 Thu t

ậ ngữ

gi

ả mã:

Một cách thi t

ế kế ch ng

ươ trình b ng

ằ cách vi t

ế các b n

ả nháp k t

ế h p

ợ ngôn ng

ữ nói và Java.

phư n

ơ g th c

ứ tr

ợ giúp:

Th ng

ườ là m t

ộ ph ng

ươ th c

ứ nh

ỏ ch ng

ẳ làm nhi u

ề đi u

ề có ích, song ph ng

ươ th c

ứ này tr

ợ giúp m t

ộ

ph ng

ươ th c

ứ khác có ích h n.

ơ

bi n

ế l p:

ớ

M t

ộ bi n

ế đ c

ượ khai báo trong l p

ớ theo d ng

ạ static; luôn ch ỉcó m t

ộ b n

ả sao c a

ủ bi n

ế này t n

ồ t i

ạ .

14.9 Bài t p

ậ

Bài t p

ậ 1 M c

ụ đích c a

ủ bài t p

ậ này là thi hành các thu t

ậ toán tráo bài và s p

ắ x p

ế trong chư ng

ơ .

1. Hãy t i

ả v

ề mã l nh

ệ cho chư ng

ơ này từ http://thinkapjava.com/code/Card2.java rồi nh p ậ nó vào môi

trường phát tri n

ể đang dùng. Tôi đã cung c p

ấ ph n

ầ khung c a

ủ nh ng

ữ phư ng

ơ th c

ứ mà b n

ạ s

ẽ vi t

ế , do

v y

ậ mà chương trình s

ẽ đư c

ợ biên d c

ị h thông su t

ố . Nh ng

ư khi ch y

ạ , nó s

ẽ in các dòng thông báo cho

bi t

ế r n

ằ g nh ng

ữ phư ng

ơ th c

ứ r ng

ỗ ch a

ư làm vi c

ệ đư c

ợ . Khi b n

ạ hoàn thành h t

ế các phư ng

ơ th c

ứ này,

những l i

ờ thông báo đó sẽ bi n

ế m t

ấ .

2. Nếu đã làm Bài t p

ậ 3 trong Chư ng

ơ 12, b n

ạ đã vi t

ế randomInt. N u

ế không, bây gi

ờ hãy vi t

ế phư ng

ơ

thức này rồi thêm vào mã l nh

ệ đ

ể ki m

ể tra.

3. Hãy vi t

ế một phư ng

ơ th c

ứ có thên swapCards để nh n

ậ vào một c

ỗ bài (m n

ả g ch a

ứ nh ng

ữ quân bài)

cùng hai ch ỉs ,

ố r i

ồ đ i

ổ ch

ỗ hai lá bài

ở nh ng

ữ v ịtrí đó. G I

Ợ Ý: phư ng

ơ th c

ứ này ph i

ả đ i

ổ ch

ỗ tham

chi u

ế , ch

ứ không ph i

ả n i

ộ dung c a

ủ các đ i

ố tư ng

ợ . Vi c

ệ này nhanh h n

ơ ; đ ng

ồ th i

ờ cũng x

ử lý đúng

trường hợp các lá bài cùng tham chi u

ế đ n

ế m t

ộ đ i

ố tư ng

ợ (t c

ứ “đ t

ặ bí danh”).

4. Viết một phương thức có tên shuffleDeck để dùng thu t

ậ toán trong M c

ụ 14.2. Có th

ể b n

ạ s

ẽ muốn dùng

phương th c

ứ randomInt từ Bài t p

ậ 3 Chư ng

ơ 12.

5. Viết một phương thức có tên indexLowestCard để dùng phương th c ứ compareCard nh m

ằ tìm ki m

ế lá

bài th p

ấ nh t

ấ trong m t

ộ kho n

ả g cho trư c

ớ c a

ủ c

ỗ bài (từ lowIndex đến highIndex, kể c

ả hai đ u

ầ ).

6. Viết một phương thức có tên sortDeck để s p

ắ xếp cỗ bài t

ừ th p

ấ lên cao.

7. Dùng giả mã trong M c

ụ 14.6, hãy vi t

ế phư ng

ơ th c

ứ có tên merge. Đảm b o

ả r ng

ằ b n

ạ ki m

ể tra nó trư c

ớ

khi dùng nó làm m t

ộ ph n

ầ trong mergeSort.

8. Viết một d n

ạ g đ n

ơ gi n

ả c a

ủ mergeSort, d n

ạ g chia c

ỗ bài làm đôi, r i

ồ dùng sortDeck để s p

ắ x p

ế hai n a

ử ,

và dùng merge để t o

ạ nên cỗ bài m i

ớ , s p

ắ x p

ế đúng.

9. Viết một d n

ạ g đ

ệ quy hoàn ch nh

ỉ c a

ủ mergeSort. Nhớ r n

ằ g sortDeck là một phương th c

ứ s a

ử đ i

ổ

còn mergeSort là một hàm; nh

ư v y

ậ chúng đư c

ợ kích ho t

ạ theo cách khác nhau:

sortDeck(deck); // sửa đổi cỗ bài sẵn có

deck = mergeSort(deck); // thay thế cỗ bài cũ bằng cỗ mới

Ch

ng

ươ 15: L p

ậ trình h ng

ướ

đ i

ố tư ng

ợ

Trở về M c

ụ l c

ụ cuốn sách 15.1 Các ngôn ngữ và phong cách l p t

ậ rình

Có nhi u

ề ngôn ng

ữ l p

ậ trình khác nhau, và không kém m y

ấ v

ề s

ố lư ng

ợ là các phong cách l p

ậ trình (còn

gọi là mẫu hình). Nh ng

ữ chư ng

ơ trình mà ta đã vi t

ế đ n

ế gi

ờ đ u

ề thu c

ộ phong cách thủ t c

ụ , bởi chú ý

được dồn vào vi c

ệ quy đ n

ị h các th

ủ t c

ụ tính toán.

Đa số các chư ng

ơ trình Java đ u

ề hướng đ i

ố t n

ượ g, có nghĩa là t p

ậ trung v

ề nh ng

ữ đ i

ố tư ng

ợ và tư ng

ơ

tác giữa chúng. Sau đây là m t

ộ s

ố đ c

ặ tính c a

ủ l p

ậ trình hư ng

ớ đ i

ố tư ng

ợ :

•Đ i

ố tư ng

ợ thư ng

ờ bi u

ể di n

ễ cho nh ng

ữ th c

ự th

ể ngoài đ i

ờ . Trong chư ng

ơ trư c

ớ , vi c

ệ t o

ạ nên

lớp Deck là một bước hướng tới l p

ậ trình hư ng

ớ đ i

ố tư ng

ợ .

•Đa số các phư ng

ơ th c

ứ là phư ng

ơ th c

ứ đ i

ố tư ng

ợ (nh

ư nh ng

ữ phư ng

ơ th c

ứ mà ta kích ho t

ạ lên

các Strings) thay vì các phư ng

ơ th c

ứ l p

ớ (nh

ư các phư ng

ơ th c

ứ Math). Nh ng

ữ phư ng

ơ th c

ứ mà đ n

ế gi

ờ

ta đã vi t

ế v n

ẫ là phư ng

ơ th c

ứ l p.

ớ

Ở chư ng

ơ này ta s

ẽ vi t

ế m t

ộ s

ố phư ng

ơ th c

ứ đ i

ố tư ng

ợ .

•Các đối tư ng

ợ cô l p

ậ kh i

ỏ nhau b ng

ằ cách h n

ạ ch

ế nh ng

ữ cách th c

ứ tư ng

ơ tác gi a

ữ chúng, đ c

ặ bi t

ệ

b n

ằ g cách ngăn không cho chúng truy c p

ậ các bi n

ế th c

ự th

ể mà không kích ho t

ạ các phư ng

ơ th c

ứ .

•Các lớp được tổ ch c

ứ trong cây gia đình,

ở đó nh ng

ữ l p

ớ m i

ớ thì m

ở r ng

ộ t

ừ l p

ớ cũ, qua vi c

ệ b

ổ sung

những phư ng

ơ th c

ứ m i

ớ và thay th

ế phư ng

ơ th c

ứ s n

ẵ có.

Ở chương này tôi chuy n

ể chư ng

ơ trình Card ở chương trước, từ phong cách th

ủ t c

ụ sang hư ng

ớ đ i

ố

tượng. B n

ạ có th

ể t i

ả về mã l nh

ệ t

ừ chư ng

ơ này t i

ạ http://thinkapjava.com/code/Card3.java.

15.2 Các phư ng t

ơ

h c

ứ đ i t

ố ư n

ợ g và phư ng t

ơ

h c l

ứ

p

ớ

Có hai ki u

ể phư ng

ơ th c

ứ trong Java, g i

ọ là phư n

ơ g th c

ứ l p

ớ và ph n

ươ g th c

ứ đ i

ố t n

ượ g. Phương

thức lớp dễ nh n

ậ th y

ấ b i

ở có t

ừ khóastatic ngay trên dòng đ u

ầ . Còn b t

ấ kì phư ng

ơ th c

ứ nào không có từ

khóa static này thì đ u

ề là phư ng

ơ th c

ứ đ i

ố tư ng

ợ .

Dù ch a

ư vi t

ế đư c

ợ phư ng

ơ th c

ứ đ i

ố tư ng

ợ nào, song ta đã kích ho t

ạ m t

ộ s

ố phư ng

ơ th c

ứ nh

ư v y

ậ . M i

ỗ

khi b n

ạ kích ho t

ạ m t

ộ phư ng

ơ th c

ứ “lên” m t

ộ đ i

ố tư ng

ợ , thì đó chính là phư ng

ơ th c

ứ đ i

ố tư ng

ợ . Ch n

ẳ g

h n

ạ , charAt và những phư ng

ơ th c

ứ khác mà ta kích ho t

ạ lên nh ng

ữ đ i

ố tư ng

ợ String đều là các phư ng

ơ

thức đối tượng.

B t

ấ cứ th

ứ gì vi t

ế đư c

ợ là phư ng

ơ th c

ứ l p

ớ cũng có th

ể đư c

ợ vi t

ế thành phư ng

ơ th c

ứ đ i

ố tư ng

ợ , và

ngược l i

ạ . Song đôi khi, s

ẽ có m t

ộ cách vi t

ế t

ự nhiên h n

ơ cách kia.

Ch ng

ẳ h n,

ạ sau đây là printCard viết dưới d n

ạ g phương th c

ứ l p:

ớ

public static void printCard(Card c) {

System.out.println(ranks[c.rank] + " of " + suits[c.suit]);

}

Còn sau đây, nó đư c

ợ vi t

ế l i

ạ thành phư ng

ơ th c

ứ đ i

ố tư ng

ợ :

public void print() {

System.out.println(ranks[rank] + " of " + suits[suit]);

}

Sau đây là nh ng

ữ thay đ i

ổ :

1.Tôi đã xóa từ static.

2.Tôi thay đ i

ổ tên c a

ủ phư ng

ơ th c

ứ đ

ể gi ng

ố v i

ớ gi ng

ọ đ c

ọ Java h n.

ơ

3.Tôi bỏ tham số đi.

4.Bên trong một phư ng

ơ th c

ứ đ i

ố tư ng

ợ , b n

ạ có th

ể tham chi u

ế đ n

ế các bi n

ế th c

ự th

ể nh

ư th

ể chúng là

những bi n

ế đ a

ị phư ng

ơ , vì v y

ậ tôi đ i

ổ c.rank thành rank, và tương tự v i

ớ suit.

Đây là cách kích ho t

ạ phư ng

ơ th c

ứ m i

ớ này:

Card card = new Card(1, 1);

card.print();

Khi b n

ạ kích ho t

ạ m t

ộ phư ng

ơ th c

ứ lên m t

ộ đ i

ố tư ng

ợ thì đ i

ố tư ng

ợ đó tr

ở thành đ i

ố t n

ượ g hi n

ệ

hành, còn đư c

ợ gọi là this. Bên trong print, từ khóa this tham chi u

ế đ n

ế lá bài mà phư ng

ơ th c

ứ đư c

ợ

kích ho t

ạ lên đó.

15.3 Phương thức toString

Từng ki u

ể đối tư ng

ợ đ u

ề có m t

ộ phư ng

ơ th c

ứ mang tên toString để trả l i

ạ một chu i

ỗ bi u

ể di n

ễ cho đ i

ố

tượng đó. Khi b n

ạ in ra đ i

ố tư ng

ợ b ng

ằ l nh

ệ print ho c

ặ println, Java s

ẽ kích ho t

ạ phư ng

ơ

thức toString c a

ủ đối tượng này.

Phiên b n

ả m c

ặ đ nh

ị c a

ủ toString trả l i

ạ một chuỗi có ch a

ứ ki u

ể c a

ủ đ i

ố tư ng

ợ và m t

ộ s

ố nh n

ậ di n

ệ duy

nhất (xem M c

ụ 11.6). Khi b n

ạ đ nh

ị nghĩa m t

ộ ki u

ể đ i

ố tư ng

ợ m i

ớ , b n

ạ có thể s a

ử đè lên hành vi m c

ặ

đ nh

ị này b n

ằ g cách cung c p

ấ m t

ộ phư ng

ơ th c

ứ m i

ớ ch a

ứ hành vi mà b n

ạ mu n.

ố

Ch ng

ẳ h n,

ạ sau đây là m t

ộ phư ng

ơ th c

ứ toString đ i

ố v i

ớ Card:

public String toString() {

return ranks[rank] + " of " + suits[suit];

}

Ki u

ể tr

ả l i

ạ là String, theo l

ẽ t

ự nhiên; và phư ng

ơ th c

ứ này không nh n

ậ tham s

ố nào. B n

ạ có th

ể kích

ho t

ạ toString theo lối thông thư ng

ờ :

Card card = new Card(1, 1);

String s = card.toString();

ho c

ặ b n

ạ cũng có thể kích ho t

ạ gián ti p

ế nó thông qua println:

System.out.println(card);

15.4 Phương thức equals

Ở M c

ụ 13.4 ta đã nói v

ề hai hình th c

ứ cân b n

ằ g: s

ự gi ng

ố h ,

ệ nghĩa là hai bi n

ế cùng tham chi u

ế t i

ớ m t

ộ

đối tượng, và sự tương đương, tức là hai bi n

ế có cùng giá tr .ị

Toán tử == kiểm tra s

ự giống h t

ệ , nh ng

ư không có toán t

ử nào đ

ể ki m

ể tra s

ự tư ng

ơ đ ng

ồ , b i

ở “tư ng

ơ

đồng” th

ế nào thì còn ph

ụ thu c

ộ vào ki u

ể c a

ủ đ i

ố tư ng

ợ n a

ữ . Thay vì v y

ậ , các đ i

ố tư ng

ợ l i

ạ cung c p

ấ

một phương th c

ứ có tên equals để đ nh

ị nghĩa s

ự tư ng

ơ đ ng

ồ này.

Các l p

ớ trong Java cung c p

ấ nh ng

ữ phư ng

ơ th c

ứ equals để làm đi u

ề đúng đ n.

ắ Nh ng

ư v i

ớ nh ng

ữ ki u

ể

do ngư i

ờ dùng đ nh

ị nghĩa thì cách ng

ứ x

ử m c

ặ đ nh

ị c a

ủ phư ng

ơ th c

ứ này cũng ch ng

ẳ khác gì s

ự gi ng

ố

hệt; đây không ph i

ả là đi u

ề b n

ạ mong mu n.

ố

Đ i

ố v i

ớ Card ta đã có một phư ng

ơ th c

ứ để ki m

ể tra s

ự tư ng

ơ đ ng

ồ :

public static boolean sameCard(Card c1, Card c2) {

return (c1.suit == c2.suit && c1.rank == c2.rank);

}

B i

ở v y

ậ tất c

ả nh ng

ữ đi u

ề ta c n

ầ làm là vi t

ế l i

ạ nó dư i

ớ d n

ạ g m t

ộ phư ng

ơ th c

ứ cho đ i

ố tư ng

ợ :

public boolean equals(Card c2) {

return (suit == c2.suit && rank == c2.rank);

}

Một l n

ầ n a

ữ , tôi đã b

ỏ đi t

ừ khóa static cũng nh

ư thông số đ u

ầ , c1. Sau đây là cách kích ho t

ạ phư ng

ơ

thức mới này:

Card card = new Card(1, 1);

Card card2 = new Card(1, 1);

System.out.println(card.equals(card2));

Bên trong equals, card là đối tượng hi n

ệ hành còn card2 là tham số, c2. Đối v i

ớ nh ng

ữ phư ng

ơ th c

ứ

ho t

ạ động trên hai đ i

ố tư ng

ợ có cùng ki u

ể , đôi khi tôi dùng h n

ẳ t

ừ khóa this đồng thời gọi tham s

ố kia

là that:

public boolean equals(Card that) {

return (this.suit == that.suit && this.rank == that.rank);

}

Tôi nghĩ r ng

ằ theo cách này, mã l nh

ệ s

ẽ d

ễ đ c

ọ h n.

ơ

15.5 Nh ng đ

ữ

i u k

ề

ì qu c v

ặ

à l i sa

ỗ

i

Nếu b n

ạ có các phư ng

ơ th c

ứ đ i

ố tư ng

ợ và l p

ớ đ i

ố tư ng

ợ

ở bên trong cùng m t

ộ l p,

ớ thì th t

ậ d

ễ nh m

ầ l n

ẫ .

Một cách thông thư ng

ờ đ

ể t

ổ ch c

ứ l i

ờ đ nh

ị nghĩa l p

ớ là đ t

ặ t t

ấ c

ả nh ng

ữ constructor

ở đ u

ầ , theo sau là

tất c

ả những phương th c

ứ đối tư ng

ợ và ti p

ế theo là phư ng

ơ th c

ứ l p.

ớ

B n

ạ có thể có một phư ng

ơ th c

ứ đối tư ng

ợ trùng tên v i

ớ phư ng

ơ th c

ứ l p,

ớ mi n

ễ là chúng không có cùng

số lượng cũng nh

ư ki u

ể các tham s .

ố Gi ng

ố các hình th c

ứ quá t i

ả (overloading) khác, Java quy t

ế đ nh

ị

xem c n

ầ kích ho t

ạ d n

ạ g nào b n

ằ g cách nhìn vào nh ng

ữ tham s

ố mà b n

ạ cung c p.

ấ

Bây gi

ờ khi đã bi t

ế ý nghĩa c a

ủ t

ừ khóa static, có l

ẽ b n

ạ đã hình dung ra đư c

ợ r n

ằ g main là một phương

thức lớp, nghĩa là không có m t

ộ “đ i

ố tư ng

ợ hi n

ệ th i

ờ ” n i

ơ nó đư c

ợ kích ho t

ạ . Vì không có đ i

ố tư ng

ợ

hiện thời trong m t

ộ phư ng

ơ th c

ứ l p,

ớ nên s

ẽ có l i

ỗ khi dùng t

ừ khóa this. Nếu b n

ạ thử thì s

ẽ nh n

ậ đư c

ợ

một thông báo l i

ỗ ki u

ể nh

ư “Undefined variable: this.”

Đ ng

ồ th i

ờ , b n

ạ cũng không th

ể tham chi u

ế đ n

ế nh ng

ữ bi n

ế th c

ự th

ể mà không dùng kí pháp d u

ấ ch m

ấ

l n

ẫ cung c p

ấ một tên đ i

ố tư ng

ợ . N u

ế th

ử làm, b n

ạ s

ẽ nh n

ậ m t

ộ thông báo l i

ỗ nh

ư “non-static variable…

cannot be referenced from a static context.” Nói “non-static variable” nghĩa là bi n ế th c

ự th

ể (“instance

variable.”)

15.6 Thừa kế

Đ c

ặ đi m

ể ngôn ng

ữ thư ng

ờ g n

ắ v i

ớ l p

ậ trình hư ng

ớ đ i

ố tư ng

ợ nh t

ấ là tính th a

ừ kế. Th a

ừ k

ế là kh

ả

năng đ nh

ị nghĩa đư c

ợ m t

ộ l p

ớ m i

ớ là phiên b n

ả s a

ử đ i

ổ t

ừ m t

ộ l p

ớ s n

ẵ có. M

ở r ng

ộ hình nh

ả ví von

này, l p

ớ s n

ẵ có đôi khi còn đư c

ợ g i

ọ là l p

ớ cha mẹ và lớp m i

ớ đư c

ợ g i

ọ là l p

ớ con.

Ưu điểm cơ b n

ả c a

ủ đ c

ặ đi m

ể này là b n

ạ có th

ể b

ổ sung đư c

ợ nh ng

ữ phư ng

ơ th c

ứ và bi n

ế th c

ự th

ể mà

không c n

ầ s a

ử đ i

ổ l p

ớ cha m .

ẹ Đi u

ề này đ c

ặ bi t

ệ h u

ữ ích đ i

ố v i

ớ các l p

ớ Java, vì b n

ạ có mu n

ố cũng

ch ng

ẳ thể s a

ử đổi đư c

ợ chúng.

Nếu b n

ạ đã làm các bài t p

ậ GridWorld r i

ồ (

ở các Chư ng

ơ 5 và 10), b n ạ s

ẽ th y

ấ một số ví d

ụ v

ề th a

ừ k :

ế

public class BoxBug extends Bug {

private int steps;

private int sideLength;

public BoxBug(int length) {

steps = 0;

sideLength = length;

}

}

BoxBug extends Bug nghĩa là BoxBug là một lo i

ạ Bug mới đựa k

ế th a

ừ nh ng

ữ phư ng

ơ th c

ứ và bi n

ế th c

ự

thể c a

ủ Bug. Ngoài ra:

•Lớp con có th

ể có thêm các bi n

ế th c

ự th

ể khác. Trong ví d

ụ này, các BoxBug có steps và sideLength.

•Lớp con có th

ể có thêm các phư ng

ơ th c

ứ khác. Trong ví d

ụ này, các BoxBug có thêm một constructor

nh n

ậ vào tham s

ố nguyên.

•Lớp con có thể ghi đè lên một phương th c

ứ th a

ừ hư ng

ở t

ừ l p

ớ cha m .

ẹ Trong ví d

ụ này, l p

ớ con cung

c p

ấ phương th c

ứ act (không ch ỉra

ở đây), đ

ể ghi đè lên phư ng

ơ th c

ứ act c a

ủ lớp cha m .

ẹ

Nếu b n

ạ đã làm các bài t p

ậ v

ề đ

ồ h a

ọ

ở Ph

ụ l c

ụ A, b n

ạ còn th y

ấ m t

ộ ví d

ụ n a

ữ :

public class MyCanvas extends Canvas {

public void paint(Graphics g) {

g.fillOval(100, 100, 200, 200);

}

}

MyCanvas là một ki u

ể m i

ớ c a

ủ Canvas, ch ng

ẳ có thêm phư ng

ơ th c

ứ hay bi n

ế th c

ự th

ể nào, song nó ghi

đè lên paint.

Nếu b n

ạ ch a

ư t ng

ừ làm bài nào trong s

ố đó thì gi

ờ đã là lúc r i

ồ !

15.7 C u t

ấ

rúc th a k

ừ

l

ế p

ớ

Trong Java, t t

ấ c

ả m i

ọ l p

ớ đ u

ề m

ở r ng

ộ t

ừ m t

ộ l p

ớ nào đó khác. L p

ớ c

ơ b n

ả nh t

ấ đư c

ợ g i

ọ là Object. Nó

không ch a

ứ bi n

ế th c

ự th

ể nào, nh ng

ư có cung c p

ấ các phư ng

ơ th c

ứ equals và toString, cùng nh ng

ữ

phương th c

ứ khác.

Nhi u

ề lớp mở rộng Object, gồm c

ả h u

ầ h t

ế những l p

ớ ta đã vi t

ế và nhi u

ề l p

ớ Java khác,

như java.awt.Rectangle. B t

ấ kì l p

ớ nào không nói rõ tên l p

ớ cha m

ẹ ra, thì đ u

ề m c

ặ đ nh

ị là th a

ừ hư ng

ở

từ Object.

Tuy v y

ậ , một số chu i

ỗ th a

ừ kế thì dài h n.

ơ Ch ng

ẳ h n,

ạ javax.swing.JFrame mở rộng java.awt.Frame,

đến lượt nó l i

ạ mở r ng

ộ Window, đến lượt nó m

ở rộng Container, đến lượt nó m

ở rộng Component,

đến lượt nó m

ở r ng

ộ Object. B t

ấ k

ể chuỗi này có dài nh

ư th

ế nào thì Object v n

ẫ là “tổ tiên” chung c a

ủ

tất c

ả các l p.

ớ

“Cây gia đình” c a

ủ các l p

ớ đư c

ợ g i

ọ là th a

ừ k

ế l p.

ớ Object thường xu t

ấ hiện ở trên cùng, và t t

ấ c

ả nh ng

ữ

lớp “con” thì đư c

ợ x p

ế dư i

ớ . Ch n

ẳ g h n

ạ , n u

ế b n

ạ nhìn vào tài l u

ệ c a

ủ JFrame, b n

ạ s

ẽ th y

ấ r ng

ằ ph n

ầ

c a

ủ sự thừa kế cho ra JFrame.

15.8 Thi t

ế k h

ế ư ng đ

ớ

i t

ố ư ng

ợ

Thừa kế là một đ c

ặ đi m

ể quan tr ng

ọ . Có nh ng

ữ chư ng

ơ trình s

ẽ tr

ở nên r t

ấ ph c

ứ t p

ạ n u

ế không di n

ễ

đ t

ạ được một cách g n

ọ gàng, đ n

ơ gi n

ả b ng

ằ đ c

ặ đi m

ể nói trên. H n

ơ n a

ữ , th a

ừ k

ế có th

ể giúp t n

ậ d n

ụ g

l i

ạ mã l nh

ệ , vì b n

ạ có th

ể ch nh

ỉ l i

ạ theo ý thích cách ng

ứ x

ử c a

ủ nh ng

ữ l p

ớ s n

ẵ có mà không c n

ầ s a

ử đ i

ổ

chúng.

M t

ặ khác, th a

ừ k

ế có th

ể làm cho chư ng

ơ trình r t

ấ khó đ c

ọ . Khi b n

ạ th y

ấ m t

ộ l i

ờ kích ho t

ạ phư ng

ơ

thức, th t

ậ khó để hình dung ra phư ng

ơ th c

ứ nào đư c

ợ kích ho t

ạ .

Ngoài ra, nhi u

ề th

ứ có th

ể th c

ự hi n

ệ b ng

ằ cách th a

ừ k

ế cũng có th

ể làm đư c

ợ ho c

ặ th m

ậ chí t t

ố h n

ơ mà

không dùng cách này. Cách làm thay th

ế thư ng

ờ g p

ặ là t n

ổ g h p

ợ , trong đó các đ i

ố tư ng

ợ đư c

ợ k t

ế h p

ợ

từ những đối tư ng

ợ có s n,

ẵ qua đó b

ổ sung thêm tính năng mà không c n

ầ th a

ừ k .

ế

Việc thi t

ế k

ế nên nh ng

ữ đ i

ố tư ng

ợ và m i

ố liên h

ệ gi a

ữ chúng là ch

ủ đ

ề nghiên c u

ứ c a

ủ thi t

ế k

ế hướng

đ i

ố t n

ượ g, một lĩnh vực nằm ngoài ph m

ạ vi cu n

ố sách này. Song n u

ế b n

ạ quan tâm, tôi s

ẽ g i

ợ ý b n

ạ

đọc quy n

ể Head First Design Patterns, c a

ủ nhà xu t

ấ b n

ả O’Reilly Media.

15.9 Thu t

ậ ngữ

phư n

ơ g th c

ứ đ i

ố t n

ượ g:

M t

ộ ph ng

ươ th c

ứ đ c

ượ kích ho t

ạ lên m t

ộ đ i

ố t ng

ượ , đ ng

ồ th i

ờ ho t

ạ đ ng

ộ trên đ i

ố t ng

ượ đó. Các

ph n

ươ g th c

ứ đ i

ố t ng

ượ thì không có ch a

ứ t

ừ khóa static.

phư n

ơ g th c

ứ l p:

ớ

M t

ộ ph ng

ươ th c

ứ có từ khóa static. Ph n

ươ g th c

ứ l p

ớ không đ c

ượ kích ho t

ạ trên đ i

ố t ng

ượ và

chúng không có đ i

ố tư ng

ợ hi n

ệ hành.

đ i

ố t n

ượ g hi n

ệ hành:

Đ i

ố tư ng

ợ mà trên đó m t

ộ ph ng

ươ th c

ứ đ i

ố tư ng

ợ đ c

ượ kích ho t

ạ . Bên trong ph ng

ươ th c

ứ , đ i

ố

t ng

ượ hi n

ệ hành đư c

ợ tham chi u

ế đ n

ế b ng

ằ this.

ng m

ầ :

Th

ứ đ c

ượ lướt qua không nói đ n,

ế hay đư c

ợ ng

ụ ý. Bên trong m t

ộ ph ng

ươ th c

ứ đ i

ố tư ng

ợ , b n

ạ có th

ể

tham chiếu đ n

ế nh ng

ữ bi n

ế th c

ự th

ể m t

ộ cách ng m

ầ (nghĩa là không nh c

ắ đ n

ế tên đ i

ố t ng

ượ ).

t

n

ườ g minh:

Th

ứ đ c

ượ ghi rõ ra. Bên trong m t

ộ ph ng

ươ th c

ứ l p

ớ , t t

ấ c

ả nh ng

ữ tham chi u

ế đ n

ế bi n

ế th c

ự th

ể

ph i

ả đ c

ượ viết tư ng

ờ minh.

15.10 Bài t p

ậ

Bài t p

ậ 1 T i

ả v

ề các

file http://thinkapjava.com/code/CardSoln2.java và http://thinkapjava.com/code/CardSoln3.java.

File CardSoln2.java chứa l i

ờ gi i

ả nh ng

ữ bài t p

ậ c a

ủ chư ng

ơ trư c

ớ . Nó ch ỉdùng các phư ng

ơ th c

ứ l p

ớ (tr

ừ

các constructor). CardSoln3.java cũng ch a

ứ chư ng

ơ trình này, nh ng

ư đa s

ố các phư ng

ơ th c

ứ đ u

ề là

phương th c

ứ đ i

ố tư ng

ợ . Tôi v n

ẫ đ

ể nguyênmerge mà không thay đ i

ổ vì tôi nghĩ nó là phư ng

ơ th c

ứ l p

ớ

thì s

ẽ dễ đ c

ọ h n.

ơ Hãy chuy n

ể merge thành một phương th c

ứ đ i

ố tư ng

ợ , và chuy n

ể mergeSort một

cách tương ứng. B n

ạ thích phiên b n

ả merge nào h n?

ơ

Bài t p

ậ 2 Hãy chuy n

ể phư ng

ơ th c

ứ l p

ớ sau đây thành phư ng

ơ th c

ứ đ i

ố tư ng

ợ .

public static double abs(Complex c) {

return Math.sqrt(c.real * c.real + c.imag * c.imag);

}

Bài t p

ậ 3 Hãy chuy n

ể phư ng

ơ th c

ứ l p

ớ sau đây thành phư ng

ơ th c

ứ đ i

ố l p

ớ .

public boolean equals(Complex b) {

return(real == b.real && imag == b.imag);

}

Bài t p

ậ 4 Bài t p

ậ này là s

ự ti p

ế n i

ố theo Bài t p

ậ 3 c a

ủ Chư ng

ơ 11. M c

ụ đích là nh m

ằ th c

ự hành cú pháp

c a

ủ những phư ng

ơ th c

ứ đ i

ố tư ng

ợ và làm quen v i

ớ nh ng

ữ thông báo l i

ỗ có liên quan.

1. Hãy chuy n

ể các phư ng

ơ th c

ứ trong l p

ớ Rational từ phương thức l p

ớ sang phư ng

ơ th c

ứ đ i

ố tư ng

ợ , đ ng

ồ

thời thực hi n

ệ nh ng

ữ chuy n

ể đ i

ổ c n

ầ thi t

ế trong main.

2. Cố ý m c

ắ một số lỗi. Th

ử kích ho t

ạ các phư ng

ơ th c

ứ l p

ớ nh

ư th

ể chúng là phư ng

ơ th c

ứ đ i

ố tư ng

ợ , và

ngược l i

ạ . Hãy th

ử tìm hi u

ể xem th

ế nào là h p

ợ l

ệ và th

ế nào không, và hi u

ể thông báo l i

ỗ b n

ạ nh n

ậ

được khi mọi vi c

ệ rối lên.

3. Hãy nghĩ về u

ư và như c

ợ đi m

ể c a

ủ các phư ng

ơ th c

ứ l p

ớ và phư ng

ơ th c

ứ đ i

ố tư ng

ợ ? Cách nào (thư ng

ờ )

viết gọn hơn? Cách nào di n

ễ đ t

ạ tính toán m t

ộ cách t

ự nhiên h n

ơ (ho c

ặ xét công b n

ằ g, nh ng

ữ ki u

ể phép

tính nào có th

ể đư c

ợ di n

ễ đ t

ạ m t

ộ cách t

ự nhiên nh t

ấ theo m i

ỗ phong cách)?

Bài t p

ậ 5 M c

ụ đích c a

ủ bài t p

ậ này là vi t

ế m t

ộ chư ng

ơ trình đ

ể phát sinh ra nh ng

ữ ph n

ầ bài poker

ng u

ẫ nhiên r i

ồ phân lo i

ạ chúng, đ

ể ta ư c

ớ tính đư c

ợ xác su t

ấ c a

ủ các d ng

ạ ph n

ầ bài khác nhau. N u

ế b n

ạ

không ch i

ơ poker, b n

ạ có th

ể đ c

ọ v

ề nó

ở đây http://en.wikipedia.org/wiki/List_of_poker_hands.

1. B t

ắ đầu b n

ằ g http://thinkapjava.com/code/CardSoln3.java rồi đảm b o ả ch c

ắ r ng

ằ b n

ạ biên d c

ị h và

ch y

ạ được chư ng

ơ trình.

2. Hãy vi t

ế l i

ờ đ nh

ị nghĩa cho m t

ộ l p

ớ có tên PokerHand (ph n

ầ bài), m

ở r ng

ộ t

ừ Deck.

3. Viết một phương thức trong Deck có tên deal để t o

ạ ra một PokerHand, chuy n

ể các lá bài t

ừ c

ỗ bài vào

ph n

ầ bài, rồi trả l i

ạ ph n

ầ bài này.

4. Trong main, hãy dùng shuffle và deal để phát sinh và in ra b n ố PokerHand, mỗi ph n

ầ bài g m

ồ 5 lá. B n

ạ

có thu đư c

ợ k t

ế qu

ả t t

ố không?

5. Viết một phương thức PokerHand có tên hasFlush để trả l i ạ một giá tr ịboolean đ

ể ch ỉđ nh

ị xem li u

ệ

ph n

ầ bài này có m t

ộ flush (5 lá đ ng

ồ ch t

ấ ) hay không.

6. Viết một phương thức có tên hasThreeKind để ch ỉđ nh

ị xem li u

ệ ph n

ầ bài có b

ộ ba hay không.

7. Viết một vòng l p

ặ đ

ể phát sinh ra vài nghìn ph n

ầ bài r i

ồ ki m

ể tra xem chúng có ch a

ứ 5 lá đ ng

ồ ch t

ấ , hay

bộ ba không. Ư c

ớ tính xác su t

ấ đ

ể nh n

ậ đư c

ợ m t

ộ trong hai d ng

ạ ph n

ầ bài k

ể trên. Hãy so sánh k t

ế qu

ả

thu được với các xác su t

ấ ở http://en.wikipedia.org/wiki/List_of_poker_hands.

8. Viết các phương thức đ

ể ki m

ể tra cho nh ng

ữ d ng

ạ ph n

ầ bài khác. Có d n

ạ g d ,

ễ có d n

ạ g khó. Đôi khi b n

ạ

sẽ th y

ấ c n

ầ vi t

ế một vài phư ng

ơ th c

ứ tr

ợ giúp ph c

ụ v

ụ cho nhi u

ề phép ki m

ể tra khác nhau.

9. Có những trò ch i

ơ poker mà ngư i

ờ ch i

ơ l y

ấ 7 lá bài, r i

ồ ch n

ọ ra 5 lá bài đ p

ẹ nh t

ấ . Hãy s a

ử l i

ạ chư ng

ơ

trình c a

ủ b n

ạ đ

ể phát sinh ra các ph n

ầ bài 7 lá r i

ồ tính l i

ạ nh ng

ữ xác su t

ấ nêu trên.

Ch

ng

ươ 16: GridWorld, ph n

ầ 3

Trở về M c

ụ l c

ụ cuốn sách Nếu b n

ạ ch a

ư làm bài t p

ậ trong các Chư ng

ơ 5 và 10, b n

ạ hãy nên làm đi trư c

ớ khi đ c

ọ chư ng

ơ này. Xin

được nh c

ắ l i

ạ , b n

ạ có th

ể tìm tài li u

ệ v

ề các l p

ớ GridWorld

ở http://www.greenteapress.com/thinkapjava/javadoc/gridworld/.

Ph n

ầ 3 c a

ủ cu n

ố Hư ng

ớ d n

ẫ sinh viên v

ề GridWorld trình bày nh ng

ữ l p

ớ c u

ấ thành GridWorld và các

mối tương tác gi a

ữ chúng. Đây là m t

ộ ví d

ụ v

ề thi t

ế k

ế hư ng

ơ đ i

ố tư ng

ợ và làm m t

ộ c

ơ h i

ổ đ

ể ta bàn

lu n

ậ những v n

ấ đ

ề thi t

ế k

ế hư ng

ớ đ i

ố tư ng

ợ .

Nhưng trư c

ớ khi b n

ạ đ c

ọ cu n

ố Hư ng

ớ d n

ẫ sinh viên, sau đây có thêm m t

ộ s

ố đi u

ề mà b n

ạ c n

ầ bi t

ế .

16.1 ArrayList

GridWorld s

ử d ng

ụ java.util.ArrayList, một đối tượng g n

ầ giống v i

ớ m ng

ả . Đó là m t

ộ t p

ậ h p

ợ , tức là

đối tượng đ

ể ch a

ứ nh ng

ữ đ i

ố tư ng

ợ khác. Java cung c p

ấ nh ng

ữ t p

ậ h p

ợ khác v i

ớ nhi u

ề tính năng khác

nhau, nh ng

ư đ

ể dùng GridWorld ta ch ỉc n

ầ đ n

ế các ArrayList.

Để th y

ấ một ví d ,

ụ hãy t i

ả

về http://thinkapjava.com/code/BlueBug.java và http://thinkapjava.com/code/BlueBugRunner.java. B

lueBug là một con bọ di chuy n

ể ng u

ẫ nhiên và đi tìm các t n

ả g đá. N u

ế nó th y

ấ m t

ộ t n

ả g đá, con b

ọ s

ẽ

làm t n

ả g đá hóa màu xanh.

Sau đây là cách ho t

ạ đ ng

ộ c a

ủ BlueBug. Khi act đư c

ợ kích ho t

ạ , BlueBug l y

ấ vị trí c a

ủ nó cùng m t

ộ tham

chi u

ế đ n

ế lư i

ớ :

Location loc = getLocation();

Grid<Actor> grid = getGrid();

Ki u

ể dữ li u

ệ n m

ằ trong c p

ặ ngo c

ặ góc (<>) là một tham s

ố ki u

ể để quy đ nh

ị n i

ộ dung c a

ủ grid. Nói

cách khác, grid không chỉ là một Grid, mà nó là Grid có chứa nh ng ữ Actor.

Bước ti p

ế theo là thu l y

ấ nh ng

ữ v ịtrí lân c n

ậ v i

ớ ch

ỗ hi n

ệ t i

ạ . Grid cung c p

ấ một phư ng

ơ th c

ứ ch ỉđ

ể

làm vi c

ệ này:

ArrayList<Actor> neighbors = grid.getNeighbors(loc);

Kết qu

ả tr

ả l i

ạ từ getNeighbors là một ArrayList gồm các Actor. Phương thức size trả l i ạ chi u

ề dài

c a

ủ ArrayList, và get thì chọn l y

ấ một ph n

ầ t .

ử B i

ở v y

ậ ta có th

ể in ra nh ng

ữ v ịtrí lân c n

ậ nh

ư sau.

for (int i = 0; i < neighbors.size(); i++) {

Actor actor = neighbors.get(i);

System.out.println(actor);

}

Việc duy t

ệ một ArrayList là thao tác thông d n

ụ g đ n

ế n i

ỗ có m t

ộ cú pháp đ c

ặ bi t

ệ dành cho nó: vòng

lặp for-each. Bởi v y

ậ ta có th

ể vi t

ế :

for (Actor actor : neighbors) {

System.out.println(actor);

}

Ta bi t

ế r ng

ằ các lân c n

ậ đ u

ề là nh ng

ữ Actor, song l i

ạ không bi t

ế ki u

ể c a

ủ chúng là gì: t ng

ừ lân c n

ậ có thể

là Bug, Rock, v.v. Đ

ể tìm t n

ả g đá (Rock), ta s

ử d ng

ụ toán tử instanceof, vốn đ

ể ki m

ể tra xem li u

ệ m t

ộ

đối tượng có là th c

ự th

ể c a

ủ m t

ộ l p

ớ hay không.

for (Actor actor : neighbors) {

if (actor instanceof Rock) {

actor.setColor(Color.blue);

}

}

Để làm cho toàn b

ộ ho t

ạ đ ng

ộ đư c

ợ , ta c n

ầ ph i

ả nh p

ậ nh ng

ữ l p

ớ c n

ầ dùng đ n:

ế

import info.gridworld.actor.Actor;

import info.gridworld.actor.Bug;

import info.gridworld.actor.Rock;

import info.gridworld.grid.Grid;

import info.gridworld.grid.Location;

import java.awt.Color;

import java.util.ArrayList;

16.2 Giao diện

GridWorld cũng s

ử d ng

ụ các giao di n

ệ c a

ủ Java, b i

ở v y

ậ tôi mu n

ố gi i

ả thích ý nghĩa c a

ủ chúng. “Giao

diện” có nhi u

ề nghĩa trong nh ng

ữ ng

ữ c nh

ả khác nhau, nh ng

ư trong Java, thu t

ậ ng

ữ này dùng đ

ể ch ỉ

một đ c

ặ đi m

ể cụ th

ể c a

ủ ngôn ng :

ữ giao di n

ệ là m t

ộ l i

ờ đ nh

ị nghĩa l p

ớ mà trong đó các phư ng

ơ th c

ứ

không có ph n

ầ thân.

Trong l i

ờ đ nh

ị nghĩa l p

ớ thông thư ng

ờ , m i

ỗ phư ng

ơ th c

ứ có m t

ộ nguyên m u

ẫ và m t

ộ ph n

ầ thân (xem

M c

ụ 8.5). Nguy n

ễ m u

ẫ còn đư c

ợ g i

ọ làph n

ầ quy đ n

ị h bởi nó quy đ nh

ị tên, các thông s ,

ố và ki u

ể tr

ả l i

ạ

c a

ủ phương th c

ứ đó. Ph n

ầ thân đư c

ợ g i

ọ là ph n

ầ th c

ự hi n

ệ bởi nó th c

ự hi n

ệ ph n

ầ quy đ nh

ị trên.

Trong một giao di n

ệ Java, các phư ng

ơ th c

ứ không có ph n

ầ thân, b i

ở v y

ậ giao di n

ệ ch ỉquy đ nh

ị các

phương th c

ứ mà không th c

ự hi n

ệ chúng.

Ch ng

ẳ h n,

ạ java.awt.Shape là một giao di n

ệ v i

ớ các nguyên m u

ẫ cho contains, intersects, cùng một số

phương th c

ứ khác. java.awt.Rectangle cung c p

ấ ph n

ầ th c

ự hi n

ệ c a

ủ nh ng

ữ phư ng

ơ th c

ứ này, b i

ở v y

ậ ta

nói r ng

ằ “Rectangle th c

ự hi n

ệ Shape.” Th c

ự ra, dòng đ u

ầ tiên c a

ủ l i

ờ đ nh

ị nghĩa l p

ớ Rectangle là:

public class Rectangle extends Rectangle2D implements Shape, Serializable Rectangle th a

ừ k

ế các phư ng

ơ th c

ứ từ Rectangle2D và cung c p

ấ ph n

ầ th c

ự hi n

ệ cho các phư ng

ơ th c

ứ

trong Shape và Serializable.

Trong GridWorld, l p

ớ Location th c

ự hi n

ệ giao di n

ệ java.lang.Comparable b ng

ằ cách cung

c p

ấ compareTo, vốn tương tự v i

ớ compareCards ở M c

ụ 13.5. GridWorld cũng đ nh

ị nghĩa m t

ộ giao di n

ệ

mới, Grid, để quy đ n

ị h các phư ng

ơ th c

ứ mà m t

ộ Grid c n

ầ ph i

ả cung c p.

ấ Đ ng

ồ th i

ờ , GridWorld cũng

bao gồm hai ph n

ầ th c

ự hi n,

ệ BoundedGrid và UnboundedGrid.

Quyển hướng d n

ẫ có dùng ch

ữ vi t

ế t t

ắ API, mà ch

ữ đ y

ầ đ

ủ là “application programming interface”

(giao di n

ệ l p

ậ trình ng

ứ d n

ụ g). API là m t

ộ t p

ậ h p

ợ các phư ng

ơ thwusc dành s n

ẵ cho b n,

ạ ngư i

ờ l p

ậ

trình ng

ứ d ng

ụ , đ

ể s

ử d n

ụ g. Hãy

xemhttp://en.wikipedia.org/wiki/Application_programming_interface.

16.3 public và private

Hãy nh

ớ l i

ạ t

ừ Chư ng

ơ 1, tôi đã nói r ng

ằ tôi s

ẽ gi i

ả thích t i

ạ sao phư ng

ơ th c

ứ main l i

ạ có từ

khóa public chứ? Rốt cu c

ộ , đã đ n

ế lúc c n

ầ gi i

ả thích r i

ồ .

public nghĩa là phư ng

ơ th c

ứ đư c

ợ xét có th

ể đư c

ợ kích ho t

ạ t

ừ nh ng

ữ phư ng

ơ th c

ứ khác. L a

ự ch n

ọ còn

l i

ạ là private, có nghĩa là phư ng

ơ th c

ứ đang xét ch ỉcó th

ể kích ho t

ạ đư c

ợ trong l p

ớ mà nó đư c

ợ đ nh

ị

nghĩa.

Các bi n

ế th c

ự th

ể cũng có th

ể là public ho c

ặ private, với k t

ế quả tư ng

ơ t :

ự m t

ộ bi n

ế th c

ự th

ể private ch ỉ

có th

ể truy c p

ậ đư c

ợ t

ừ bên trong l p

ớ mà nó đư c

ợ đ nh

ị nghĩa.

Lý do c

ơ b n

ả cho vi c

ệ đ t

ặ nh ng

ữ phư ng

ơ th c

ứ và bi n

ế th c

ự th

ể dư i

ớ d n

ạ g private là nh m

ằ h n

ạ ch

ế s

ự

tương tác giữa các l p

ớ đ

ể có th

ể gi

ữ m c

ứ đ

ộ ph c

ứ t p

ạ

ở m c

ứ ch p

ấ nh n

ậ đư c

ợ .

Ch ng

ẳ h n,

ạ l p

ớ Location gi

ữ các bi n

ế th c

ự th

ể dư i

ớ d n

ạ g private. Nó có các phư ng

ơ th c

ứ truy

c p

ậ getRow là getCol, nhưng l i

ạ không cung c p

ấ phư ng

ơ th c

ứ nào đ

ể s a

ử đ i

ổ các bi n

ế th c

ự th .

ể H

ệ qu

ả

là, các đ i

ố tư ng

ợ Location đ u

ề không th

ể bi n

ế đ i

ổ , theo nghĩa r n

ằ g chúng đ u

ề có th

ể đư c

ợ chia s

ẻ mà ta

không lo chúng b c

ộ l

ộ đ ng

ộ thái không mong đ i

ợ do xu t

ấ hi n

ệ bí danh (alias).

Việc đ t

ặ các phư ng

ơ th c

ứ dư i

ớ d n

ạ g private giúp ta gi

ữ cho API đư c

ợ đ n

ơ gi n

ả . Các l p

ớ thư ng

ờ kèm

theo những phư ng

ơ th c

ứ tr

ợ giúp v n

ố đư c

ợ dùng đ

ể th c

ự hi n

ệ các phư ng

ơ th c

ứ khác, song n u

ế đ

ể cho

những phư ng

ơ th c

ứ này tham gia vào trong API public có th

ể s

ẽ không c n

ầ thi t

ế và d

ễ gây l i

ỗ .

Các phương th c

ứ và bi n

ế th c

ự thể private là đ c

ặ đi m

ể ngôn ng

ữ giúp cho l p

ậ trình viên đ m

ả b o

ả đư c

ợ

sự bao b c

ọ d

ữ li u

ệ , theo nghĩa là các đ i

ố tư ng

ợ thu c

ộ l p

ớ này thì đư c

ợ cô l p

ậ kh i

ỏ nh ng

ữ l p

ớ khác.

16.4 Trò ch i

ơ Life

Nhà toán h c

ọ John Conway đã phát minh ra “Trò ch i

ơ Life,” mà ông g i

ọ là m t

ộ “trò ch i

ơ không ngư i

ờ ”

vì ch n

ẳ g c n

ầ có ngư i

ờ ch i

ơ đ

ể l a

ự ch n

ọ chi n

ế thu t

ậ hay ra quy t

ế đ nh

ị . Sau khi thi t

ế l p

ậ đi u

ề ki n

ệ ban

đ u

ầ , b n

ạ chỉ việc xem trò ch i

ơ t

ự nó phát tri n.

ể Nh ng

ư đi u

ề này hóa ra còn hay h n

ơ so v i

ớ tho t

ạ nghe;

b n

ạ có thể đọc thêm ở http://en.wikipedia.org/wiki/Conways_Game_of_Life.

M c

ụ đích c a

ủ bài t p

ậ này là th c

ự hi n

ệ trò ch i

ơ Life trong GridWorld. “Bàn c ”

ờ chính là là lư i

ớ ô, và

những “quân c ”

ờ chính là đ i

ố tư ng

ợ Rock (viên đá).

Trò ch i

ơ đư c

ợ ti n

ế hành theo t ng

ừ lư t

ợ , hay t ng

ừ b c

ướ th i

ờ gian.

Ở lúc b t

ắ đ u

ầ một bư c

ớ th i

ờ gian,

từng viên đá có tr n

ạ g thái “s ng

ố ” ho c

ặ “ch t

ế ”. Trên màn hình, màu s c

ắ c a

ủ viên đá này th

ể hi n

ệ tr ng

ạ

thái c a

ủ nó. Tr n

ạ g thái c a

ủ t ng

ừ viên đá l i

ạ ph

ụ thu c

ộ vào tr n

ạ g thái c a

ủ nh ng

ữ viên lân c n

ậ với nó.

Mỗi viên đá có 8 viên lân c n,

ậ tr

ừ nh ng

ữ viên n m

ằ d c

ọ theo c nh

ạ c a

ủ lư i

ớ ô. Sau đây là lu t

ậ ch i

ơ :

• Nếu một viên đá ch t

ế có đúng 3 viên lân c n,

ậ thì nó s

ẽ s ng

ố l i

ạ ! N u

ế không, thì nó v n

ẫ ch t

ế .

• Nếu một viên đá s ng

ố có 2 ho c

ặ 3 viên lân c n,

ậ thì nó v n

ẫ s ng

ố . Còn không thì nó ch t

ế đi.

Từ quy t c

ắ này s

ẽ có m t

ộ vài h

ệ qu :

ả N u

ế t t

ấ c

ả viên đá đ u

ề ch t

ế r i

ồ , thì ch ng

ẳ có viên nào s ng

ố l i

ạ . N u

ế

lúc đ u

ầ b n

ạ có m i

ỗ m t

ộ viên đá s ng

ố , thì nó s

ẽ ch t

ế đi. Nh ng

ư n u

ế có 4 viên c nh

ạ nhau x p

ế thành hình

vuông thì chúng s

ẽ gi

ữ cho nhau còn s ng

ố , b i

ở v y

ậ đây là m t

ộ c u

ấ trúc b n

ề v ng

ữ .

Đa số các c u

ấ hình đ n

ơ gi n

ả lúc đ u

ầ sẽ nhanh chóng ch

ế đi, ho c

ặ đ t

ạ đ n

ế m t

ộ c u

ấ hình n

ổ đ nh

ị . Song

cũng có m t

ộ ít đi u

ề ki n

ệ ban đ u

ầ cho th y

ấ đ

ộ ph c

ứ t p

ạ đáng k .

ể M t

ộ trong nh ng

ữ đi u

ề ki n

ệ đ u

ầ nh

ư v y

ậ

là r-pentomino: b t

ắ đ u

ầ ch ỉv i

ớ 5 viên đá, c u

ấ hình này ch y

ạ su t

ố 1103 bư c

ớ th i

ờ gian r i

ồ k t

ế thúc

ở m t

ộ

c u

ấ hình b n

ề v ng

ữ v i

ớ 116 viên đá s ng

ố (xem http://www.conwaylife.com/wiki/R-pentomino).

Các m c

ụ ti p

ế sau đây là nh ng

ữ g i

ợ ý đ

ể th c

ự hi n

ệ trò ch i

ơ Life trong GridWorld. B n

ạ có th

ể t i

ả v

ề l i

ờ

gi i

ả c a

ủ tôi

t i

ạ http://thinkapjava.com/code/LifeRunner.java và http://thinkapjava.com/code/LifeRock.java.

16.5 LifeRunner

Hãy sao l i

ạ m t

ộ b n

ả file BugRunner.java rồi đ t

ặ tên thành LifeRunner.java, sau đó bổ sung nh ng

ữ

phương th c

ứ v i

ớ nguyên m u

ẫ nh

ư sau:

/**

* Lập nên một lưới ô cho trò chơi Life, cùng cấu hình r-pentomino. */

public static void makeLifeWorld(int rows, int cols)

/**

* Xếp các viên đá LifeRock lên lưới ô. */

public static void makeRocks(ActorWorld world)

Phương th c

ứ makeLifeWorld c n

ầ ph i

ả t o

ạ nên m t

ộ Grid ch a

ứ các Actor cùng m t

ộ ActorWorld, sau đó

kích ho t

ạ makeRocks, đ n

ế lượt phương thức này s

ẽ ph i

ả đ t

ặ m t

ộ LifeRock vào mỗi ô trong Grid.

16.6 LifeRock

Hãy sao l i

ạ m t

ộ b n

ả c a

ủ file BoxBug.java rồi đ t

ặ tên là LifeRock.java. Lớp LifeRock ph i

ả mở rộng

từ Rock. Hãy bổ sung thêm m t

ộ phư ng

ơ th c

ứ act ch ng

ẳ đ

ể làm gì c .

ả Bây gi

ờ mã l nh

ệ ph i

ả ch y

ạ thông

được và b n

ạ s

ẽ th y

ấ một Grid ch a

ứ đ y

ầ Rock.

Để theo dõi tr n

ạ g thái c a

ủ nh ng

ữ viên đá này, b n

ạ có th

ể b

ổ sung m t

ộ bi n

ế th c

ự th

ể m i

ớ , ho c

ặ b n

ạ có

thể dùng màu s c

ắ (Color) c a

ủ Rock đ

ể bi u

ể th ịtr n

ạ g thái. B ng

ằ cách nào đi n a

ữ , hay vi t

ế nh ng

ữ phư ng

ơ

thức có các nguyên m u

ẫ sau đây:

/**

* Trả về true nếu viên đá còn sống. */

public boolean isAlive()

/**

* Làm cho viên đá sống lại. */

public void setAlive()

/**

* Làm viên đá chết đi. */

public void setDead()

Hãy vi t

ế một constructor đ

ể kích ho t

ạ setDead rồi kh ng

ẳ đ nh

ị ch c

ắ r n

ằ g t t

ấ c

ả viên đá đ u

ề ch t

ế .

16.7 C p

ậ nh t

ậ đ n

ồ g th i

ờ

Trong trò ch i

ơ Life, t t

ấ c

ả viên đá đ u

ề đư c

ợ c p

ậ nh t

ậ m t

ộ cách đ ng

ồ th i

ờ ; nghĩa là t ng

ừ viên đá đ u

ề

kiểm tra tr ng

ạ thái c a

ủ các viên lân c n

ậ trư c

ớ khi nh ng

ữ viên lân c n

ậ này thay đ i

ổ tr ng

ạ thái. N u

ế

không, động thái c a

ủ h

ệ th ng

ố s

ẽ còn ph

ụ thu c

ộ vào th

ứ t

ự c a

ủ phép c p

ậ nh t

ậ n a

ữ .

Để thực hi n

ệ c p

ậ nh t

ậ đ ng

ồ th i

ờ , tôi g i

ợ ý r n

ằ g b n

ạ nên vi t

ế m t

ộ phư ng

ơ th c

ứ act gồm có hai khâu.

Ở

khâu thứ nh t

ấ , tất c

ả viên đá ph i

ả đ m

ế s

ố lân c n

ậ v i

ớ nó r i

ồ ghi l i

ạ k t

ế qu .

ả Và

ở khâu th

ứ hai, t t

ấ c

ả

viên đá c p

ậ nh t

ậ tr ng

ạ thái c a

ủ chúng.

Phương th c

ứ act tôi đã vi t

ế trông nh

ư sau:

/**

* Kiểm tra xem ta đang ở khâu nào và gọi phương thức tương ứng.

* Chuyển đến khâu tiếp theo. */

public void act() {

if (phase == 1) {

numNeighbors = countLiveNeighbors();

phase = 2;

} else {

updateStatus();

phase = 1;

}

}

phase và numNeighbors là các bi n

ế th c

ự th .

ể Và sau đây là nh ng

ữ nguyên m u

ẫ

cho countLiveNeighbors và updateStatus:

/**

* Đếm số viên đá lân cận còn sống. */

public int countLiveNeighbors()

/**

* Cập nhật trạng thái viên đá (sống hoặc chết) dựa trên

* số các viên lân cận với nó. */

public void updateStatus()

Hãy b t

ắ đ u

ầ v i

ớ m t

ộ phiên b n

ả đ n

ơ gi n

ả c a

ủ updateStatus ch ỉđ

ể chuy n

ể viên đá s ng

ố thành ch t

ế và

ngược l i

ạ . Bây gi

ờ hãy ch y

ạ chư ng

ơ trình r i

ồ kh n

ẳ g đ nh

ị r ng

ằ viên đá đã đ i

ổ màu. C

ứ hai bư c

ớ trong

World (môi trư ng

ờ ) thì tư ng

ơ ng

ứ v i

ớ m t

ộ bư c

ớ th i

ờ gian trong trò ch i

ơ Life.

Bây gi

ờ hãy đi n

ề n i

ộ dung vào ph n

ầ thân c a

ủ các phư ng

ơ

thức countLiveNeighbors và updateStatus theo lu t

ậ ch i

ơ và xem h

ệ th ng

ố có đ ng

ộ thái gi ng

ố nh

ư ta d

ự

liệu hay không.

16.8 Đi u k

ề

iện đ u

ầ

Để thay đổi đi u

ề ki n

ệ đ u

ầ , b n

ạ có thể dùng các menu b t

ậ c a

ủ GridWorld đ

ể đ t

ặ tr n

ạ g thái c a

ủ các viên

đá b ng

ằ cách kích ho t

ạ setAlive. Ho c

ặ b n

ạ cũng có th

ể vi t

ế các phư ng

ơ th c

ứ đ

ể t

ự đ ng

ộ hóa quy trình.

Trong LifeRunner, hãy bổ sung một phư ng

ơ th c

ứ có tên makeRow để t o

ạ nên c u

ấ hình ban đ u

ầ

với n viên đá sống li n

ề nhau cùng m t

ộ hàng

ở gi a

ữ lư i

ớ ô. Đi u

ề gì s

ẽ x y

ả ra v i

ớ các giá tr ịkhác nhau

c a

ủ n?

Hãy bổ sung m t

ộ phư ng

ơ th c

ứ có tên makePentomino để t o

ạ nên một r-pentomino

ở chính gi a

ữ lư i

ớ ô.

C u

ấ hình ban đầu ph i

ả có d n

ạ g nh

ư sau:

Nếu b n

ạ ch y

ạ c u

ấ hình này trong nhi u

ề bư c

ớ , nó s

ẽ lan t a

ỏ đ n

ế cu i

ố lư i

ớ ô. B n

ố đư ng

ờ biên c a

ủ lư i

ớ ô

đã làm thay đ i

ổ đ ng

ộ thái c a

ủ h

ệ th ng

ố . Đ

ể th y

ấ đư c

ợ s

ự phát tri n

ể toàn v n

ẹ c a

ủ r-pentomino, thì lư i

ớ ô

ph i

ả đủ lớn. B n

ạ có thể ph i

ả th

ử nghi m

ệ đ

ể tìm ra kích c

ỡ lư i

ớ ô thích h p;

ợ và tùy thu c

ộ vào t c

ố đ

ộ máy

tính đang dùng, công vi c

ệ này có th

ể m t

ấ th i

ờ gian.

Trang web v

ề trò ch i

ơ có mô t

ả nh ng

ữ đi u

ề ki n

ệ đ u

ầ khác mà cho ta k t

ế qu

ả thú v ị

(http://www.conwaylife.com/). Hãy ch n ọ l y

ấ đi u

ề ki n

ệ đ u

ầ mà b n

ạ

a

ư thích r i

ồ th c

ự hi n

ệ nó.

Còn có nh ng

ữ bi n

ế th

ể c a

ủ trò ch i

ơ Life v i

ớ lu t

ậ ch i

ơ khác nhau. Hãy th

ử ch i

ơ m t

ộ bi n

ế th

ể trong s

ố đó

để xem có gì hay.

16.9 Bài t p

ậ

Bài t p

ậ 1 Khởi đầu b ng

ằ một b n

ả sao c a

ủ BlueBug.java, b n

ạ hãy vi t

ế một l i

ờ đ nh

ị nghĩa l p

ớ cho m t

ộ

kiểu đối tượng Bug mới có kh

ả năng tìm ki m

ế và ăn nh ng

ữ đóa hoa.

Ở đây, “ăn” bông hoa có th

ể đư c

ợ

thực hi n

ệ b n

ằ g kích ho t

ạ removeSelfFromGrid lên nó.

Bài t p

ậ 2 Bây gi

ờ b n

ạ bi t

ế h t

ế nh ng

ữ gì c n

ầ bi t

ế đ

ể đ c

ọ Ph n

ầ 3 c a

ủ Cu n

ố hư ng

ớ d n

ẫ sinh viên v

ề

GridWorld r i

ồ làm các bài t p

ậ .

Bài t p

ậ 3 Nếu b n

ạ đã thi t

ế l p

ậ trò ch i

ơ Life, b n

ạ đã hoàn toàn s n

ẵ sàng làm Ph n

ầ 4 c a

ủ cu n

ố Hư ng

ớ

d n

ẫ sinh viên v

ề GridWorld. Hãy đ c

ọ nó r i

ồ làm các bài t p.

ậ

Chúc m ng

ừ , b n

ạ đã h c

ọ xong!

Phụ lục A: Đồ h a

ọ

Trở về M c

ụ l c

ụ cuốn sách A.1 Đ h

ồ ọa Java 2 chi u

ề

Phụ l c

ụ này đ a

ư ra các ví d

ụ và bài t p

ậ minh h a

ọ cho tính năng đ

ồ h a

ọ trong Java. Có m t

ộ s

ố cách t o

ạ

nên đồ họa trong Java; cách đ n

ơ gi n

ả nh t

ấ là dùng java.awt.Graphics. Sau đây là m t

ộ ví d

ụ hoàn ch nh

ỉ :

import java.awt.Canvas;

import java.awt.Graphics;

import javax.swing.JFrame;

public class MyCanvas extends Canvas {

public static void main(String[] args) {

// tạo một khung (frame)

JFrame frame = new JFrame();

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// thêm một nền vẽ (canvas)

Canvas canvas = new MyCanvas();

canvas.setSize(400, 400);

frame.getContentPane().add(canvas);

// hiển thị khung

frame.pack();

frame.setVisible(true);

}

public void paint(Graphics g) {

// vẽ hình tròn

g.fillOval(100, 100, 200, 200);

}

}

B n

ạ có thể t i

ả đo n

ạ mã l nh

ệ này v

ề từ http://thinkapjava.com/code/MyCanvas.java.

Những dòng l nh

ệ đ u

ầ có nhi m

ệ v

ụ nh p

ậ các l p

ớ mà ta c n

ầ từ java.awt và javax.swing.

MyCanvas mở rộng Canvas, nghĩa là một đ i

ố tư ng

ợ MyCanvas là một ki u

ể Canvas mà cung c p

ấ các

phương th c

ứ đ

ể v

ẽ nh ng

ữ đối tư ng

ợ đ

ồ h a

ọ .

Trong main, ta đã

1.T o

ạ nên một JFrame, vốn là một cửa sổ có th

ể ch a

ứ n n

ề v

ẽ (canvas), nút b m

ấ (buttons), trình đ n

ơ

(menu), cùng các thành ph n

ầ c a

ử s

ổ khác;

2.T o

ạ nên MyCanvas, n

ấ đ n

ị h bề rộng và chi u

ề cao c a

ủ nó, r i

ồ thêm nó lên khung, sau đó

3.Hiển th ịkhung này lên màn hình.

paint là một phương th c

ứ đ c

ặ biêt đư c

ợ kích ho t

ạ khi MyCanvas c n

ầ được v .

ẽ N u

ế b n

ạ ch y

ạ mã l nh

ệ

này, b n

ạ s

ẽ th y

ấ một hình tròn đen trên n n

ề xám.

A.2 Các phư ng t

ơ

h c

ứ Graphics

Để vẽ lên n n

ề Canvas, b n

ạ kích ho t

ạ các phư ng

ơ th c

ứ thu c

ộ đ i

ố tư ng

ợ Graphics. Ví d

ụ trư c

ớ đây s

ử

d ng

ụ fillOval. Các phư ng

ơ th c

ứ khác g m

ồ có drawLine, drawRect v.v. B n

ạ có th

ể đọc tài li u

ệ c a

ủ nh ng

ữ

phương th c

ứ này ở http://download.oracle.com/javase/6/docs/api/java/awt/Graphics.html.

Sau đây là nguyên m u

ẫ c a

ủ fillOval:

public void fillOval(int x, int y, int width, int height)

Các tham số quy đ nh

ị m t

ộ hình bao, vốn là hình ch

ữ nh t

ậ bao l y

ấ hình trái xoan đư c

ợ v

ẽ (xem phía

dưới). B n

ả thân hình bao thì không đư c

ợ v

ẽ lên.

x và y quy đ nh

ị v ịtrí góc trái bên trên c a

ủ hình bao trong hệ t a

ọ độ đồ họa.

A.3 H t

ệ ọa độ

Có th

ể b n

ạ đã quen thu c

ộ v i

ớ t a

ọ đ

ộ Đ -

ề các trong không gian hai chi u

ề ; trong đó m i

ỗ v ịtrí đư c

ợ xác

đ nh

ị b n

ằ g một tọa độ x (kho ng

ả cách d c

ọ tr c

ụ x) và m t

ộ t a

ọ đ

ộ y. Theo quy ư c

ớ , các t a

ọ đ

ộ Đ -

ề các tăng

d n

ầ qua bên ph i

ả và lên phía trên, nh

ư

ở hình v

ẽ sau.

Theo quy ư c

ớ , h

ệ th ng

ố đ

ồ h a

ọ máy tính s

ử d n

ụ g m t

ộ h

ệ t a

ọ đ

ộ trong đó g c

ố

ở góc trái trên, và hư ng

ớ

dương c a

ủ tr c

ụ y chỉ xu ng

ố . Java tuân theo quy ư c

ớ này.

Các tọa độ đ u

ề đư c

ợ đo b ng

ằ đi m

ể nh

ả ; m i

ỗ đi m

ể nh

ả tư ng

ơ ng

ứ v i

ớ m t

ộ ch m

ấ trên màn hình. M t

ộ

màn hình thư ng

ờ có b

ề r ng

ộ kho ng

ả 1000 đi m

ể nh

ả . Các t a

ọ đ

ộ đ u

ề luôn là s

ố nguyên. N u

ế mu n

ố

dùng một giá tr ịph y

ẩ đ ng

ộ đ

ể làm t a

ọ đ ,

ộ b n

ạ ph i

ả làm tròn giá tr ịnày (xem M c

ụ 3.2).

A.4 Màu s c

ắ

Để chọn màu c a

ủ m t

ộ hình, b n

ạ hãy kích ho t

ạ setColor lên đối tượng đồ họa:

g.setColor(Color.red);

setColor thay đổi màu hi n

ệ hành; m i

ọ th

ứ đư c

ợ v

ẽ đ u

ề b ng

ằ màu hi n

ệ hành.

Color.red là một giá trị cho b i

ở l p

ớ Color; để dùng màu này b n

ạ ph i

ả nh p

ậ java.awt.Color. Các màu khác

gồm có:

black blue cyan darkGray gray lightGray

magenta orange pink red white yellow

B n

ạ có thể t o

ạ nên nh ng

ữ màu khác b ng

ằ cách ch ỉđ nh

ị các thành ph n

ầ đ ,

ỏ l c

ụ , lam (RGB).

Xemhttp://download.oracle.com/javase/6/docs/api/java/awt/Color.html.

B n

ạ có thể đi u

ề khi n

ể màu n n

ề c a

ủ Canvas b n

ằ g cách kích ho t

ạ Canvas.setBackground.

A.5 Chu t

ộ Mickey

Giả dụ ta muốn v

ẽ một chú chu t

ộ Mickey. Ta có th

ể dùng hình oval nh

ư v a

ừ v

ẽ làm khuôn m t

ặ , sau đó

thêm vào đôi tai. Đ

ể làm cho mã l nh

ệ d

ễ đ c

ọ h n,

ơ hãy dùng Rectangle (hình ch

ữ nhật) đ

ể bi u

ể di n

ễ các

hình bao.

Sau đây là m t

ộ phư ng

ơ th c

ứ nh n

ậ vào m t

ộ Rectangle r i

ồ kích ho t

ạ fillOval.

public void boxOval(Graphics g, Rectangle bb) {

g.fillOval(bb.x, bb.y, bb.width, bb.height);

}

Và sau đây là m t

ộ phư ng

ơ th c

ứ đ

ể v

ẽ Mickey:

public void mickey(Graphics g, Rectangle bb) {

boxOval(g, bb);

int dx = bb.width/2;

int dy = bb.height/2;

Rectangle half = new Rectangle(bb.x, bb.y, dx, dy);

half.translate(-dx/2, -dy/2);

boxOval(g, half);

half.translate(dx*2, 0);

boxOval(g, half);

}

Dòng th

ứ nh t

ấ v

ẽ khuôn m t

ặ . Ba dòng ti p

ế theo t o

ạ nên m t

ộ hình ch

ữ nh t

ậ nh

ỏ h n

ơ làm đôi tai. Ta d c

ị h

chuy n

ể hình ch

ữ nhật này lên trên và bên trái đ

ể t o

ạ thành tai th

ứ nh t

ấ , sau đó d c

ị h sang ph i

ả làm tai

thứ hai.

Kết qu

ả trông sẽ nh

ư sau:

B n

ạ có thể t i

ả mã l nh

ệ v

ề từ http://thinkapjava.com/code/Mickey.java.

A.6 Thu t

ậ ngữ

t a

ọ đ :

ộ

Một bi n

ế hay giá trị quy đ nh

ị

v ịtrí trong m t

ộ c a

ử s

ổ đ

ồ h a

ọ hai chi u

ề .

đi m

ể ảnh:

Đ n

ơ v ịđo t a

ọ đ .

ộ

hình bao:

M t

ộ cách thông thư ng

ờ quy đ nh

ị

t a

ọ đ

ộ c a

ủ m t

ộ vùng ch

ữ nh t

ậ .

A.7 Bài t p

ậ

Bài t p

ậ 1 Vẽ lá cờ Nh t

ậ B n,

ả một hình tròn đ

ỏ trên n n

ề tr ng

ắ có b

ề r ng

ộ h n

ơ so v i

ớ chi u

ề cao.

Bài t p

ậ 2 Sửa l i

ạ Mickey.java để vẽ những đôi tai trên c

ả đôi tai, r i

ồ tai m i

ớ trên tai này, và c

ứ nh

ư v y

ậ

đến khi tai nh

ỏ nh t

ấ có b

ề r ng

ộ ch ỉ3 đi m

ể nh

ả . K t

ế qu

ả dư ng

ờ nh

ư gi ng

ố Hư u

ơ Mickey:

Gợi ý: b n

ạ chỉ được bổ sung hay s a

ử đ i

ổ m t

ộ vài dòng l nh

ệ .

B n

ạ có thể t i

ả v

ề một l i

ờ gi i

ả từ http://thinkapjava.com/code/MickeySoln.java.

Bài t p

ậ 3

1. T i

ả về http://thinkapjava.com/code/Moire.java rồi nh p ậ nó vào môi trư ng

ờ phát tri n

ể hi n

ệ hành.

2. Đ c

ọ phương th c

ứ paint và phác th o

ả công d n

ụ g mà b n

ạ phán đoán. Bây gi

ờ ch y

ạ phư ng

ơ th c

ứ này. B n

ạ

có th y

ấ k t

ế quả nh

ư dự đoán không? M t

ộ l i

ờ gi i

ả thích cho đi u

ề này có th

ể xem

ở http://en.wikipedia.org/wiki/Moire_pattern.

3. Sửa l i

ạ chư ng

ơ trình đ

ể kho ng

ả cách gi a

ữ các đư ng

ờ tròn r ng

ộ ra ho c

ặ h p

ẹ l i

ạ . Xem có gì trong hình

nh

ả .

4. Sửa l i

ạ chư ng

ơ trình đ

ể các đư ng

ờ tròn đ ng

ồ tâm đư c

ợ v

ẽ t

ừ tâm màn hình, nh

ư

ở hình dư i

ớ , bên trái.

Kho ng

ả cách gi a

ữ các đư ng

ờ tròn c n

ầ ph i

ả đ

ủ nh

ỏ đ

ể th y

ấ đư c

ợ s

ự giao hòa Moiré .

5. Hãy vi t

ế một phư ng

ơ th c

ứ có tên radial để vẽ một lo t

ạ các đư ng

ờ th n

ẳ g đ ng

ồ quy nh

ư

ở hình (ph i

ả ),

nhưng ph i

ả đ

ủ sát nhau đ

ể t o

ạ nên m t

ộ d n

ạ g m u

ẫ Moiré.

6. G n

ầ như mọi lo i

ạ d ng

ạ m u

ẫ đ

ồ h a

ọ cũng có th

ể t o

ạ nên d ng

ạ m u

ẫ giao hòa ki u

ể Moiré. Hãy ngh c

ị h ch i

ơ

và quan sát s n

ả ph m

ẩ b n

ạ t o

ạ nên.

Phụ lục B: Đ u

ầ vào và đ u

ầ ra trong Java

Trở về M c

ụ l c

ụ cuốn sách B.1 Đối tư ng S

ợ

ystem

Lớp System cung c p

ấ các phư ng

ơ th c

ứ và đ i

ố tư ng

ợ thu nh n

ậ đ u

ầ vào t

ừ bàn phím, in dòng ch

ữ lên màn

hình, và th c

ự hi n

ệ vào ra (input/output, I/O) đ i

ố v i

ớ file. System.out là đối tư ng

ợ đ

ể hi n

ể th ịlên màn

hình. Khi b n

ạ kích ho t

ạ print và println, b n

ạ đã kích ho t

ạ chúng từ System.out.

Thậm chí b n

ạ có th

ể dùng chính System.out để in ra System.out:

System.out.println(System.out);

Kết qu

ả là:

java.io.PrintStream@80cc0e5

Khi Java in ra m t

ộ đ i

ố tư ng

ợ , nó in ra ki u

ể c a

ủ đ i

ố tư ng

ợ này (PrintStream) cùng v i

ớ gói mà ki u

ể đó

được đ nh

ị nghĩa (java.io), và một s

ố nh n

ậ di n

ệ duy nh t

ấ cho đ i

ố tư ng

ợ này. Trên máy tính tôi dùng, s

ố

nh n

ậ di n

ệ nói trên là 80cc0e5, nhưng v n

ẫ v i

ớ mã l nh

ệ này mà b n

ạ ch y

ạ thì có th

ể s

ẽ nh n

ậ đư c

ợ k t

ế qu

ả

khác.

Cũng có một đối tư ng

ợ có tên System.in cho phép ta nh n

ậ đ u

ầ vào t

ừ bàn phím. Tuy v y

ậ không may là

đối tượng trên không giúp cho vi c

ệ l y

ấ d

ữ li u

ệ bàn phím d

ễ dàng cho l m

ắ .

B.2 Đ u

ầ vào t bàn p

ừ

hím

Trư c

ớ h t

ế , b n

ạ ph i

ả dùng System.in để t o

ạ nên một InputStreamReader mới.

InputStreamReader in = new InputStreamReader(System.in);

Sau đó b n

ạ dùng in để t o

ạ nên một BufferedReader mới:

BufferedReader keyboard = new BufferedReader(in);

Sau cùng, b n

ạ có thể kích ho t

ạ readLine lên keyboard, đ

ể l y

ấ k t

ế qu

ả đ u

ầ vào t

ừ bàn phím r i

ồ chuy n

ể

nó thành một String.

String s = keyboard.readLine();

System.out.println(s);

Ch ỉcó một v n

ấ đ .

ề Có th

ể xu t

ấ hi n

ệ tr c

ụ tr c

ặ khi b n

ạ kích ho t

ạ readLine, và chúng có th

ể phát bi t

ệ

lệ IOException. Một phương th c

ứ phát ra bi t

ệ l

ệ ph i

ả bao g m

ồ bi t

ệ l

ệ này trong ph n

ầ nguyên m u

ẫ c a

ủ

phương th c

ứ đó, nh

ư sau:

public static void main(String[] args) throws IOException {

// phần thân của main

}

B.3 Đ u

ầ vào t f

ừ ile

Sau đây là m t

ộ chư ng

ơ trình đ c

ọ vào các dòng trong m t

ộ file r i

ồ in nh ng

ữ dòng đó ra:

import java.io.*;

public class Words {

public static void main(String[] args) throws FileNotFoundException, IOException

{

processFile("words.txt");

}

public static void processFile(String filename) throws FileNotFoundException, IOException {

FileReader fileReader = new FileReader(filename);

BufferedReader in = new BufferedReader(fileReader);

while (true) {

String s = in.readLine();

if (s == null)

break;

System.out.println(s);

}

}

}

Dòng đ u

ầ tiên làm nhi m

ệ v

ụ nh p

ậ java.io, gói chương trình có ch a

ứ FileReader, BufferedReader, và

ph n

ầ còn l i

ạ trong th

ư m c

ụ th a

ừ k

ế l p

ớ đ

ể th c

ự hi n

ệ nh ng

ữ công vi c

ệ gi n

ả đ n

ơ thông thư ng

ờ . D u

ấ * có

nghĩa là nó s

ẽ nh p

ậ vào toàn b

ộ các l p

ớ trong gói chư ng

ơ trình này.

Sau đây cũng là chư ng

ơ trình đó đư c

ợ vi t

ế l i

ạ b ng

ằ ngôn ng

ữ Python:

for word in open('words.txt'):

print word

Tôi không đùa. T ng

ừ đó đã đ

ủ m t

ộ chư ng

ơ trình, v i

ớ tính năng tư ng

ơ t .

ự

B.4 B t

ắ bi t

ệ lệ

Ở ví dụ trư c

ớ , processFile có thể phát nh ng

ữ bi t

ệ lệ FileNotFoundException và IOException. Và

vì main gọi đ n

ế processFile, nó ph i

ả khai báo cùng nh ng

ữ bi t

ệ l

ệ đó. Trong m t

ộ chư ng

ơ trình l n

ớ

hơn, main có th

ể khai báo t ng

ừ bi t

ệ l

ệ có m t

ặ .

Một cách làm khác là b t

ắ bi t

ệ lệ này b ng

ằ câu l nh

ệ try. Sau đây là m t

ộ ví d :

ụ

public static void main(String[] args) {

try {

processFile("words.txt");

}

catch (Exception ex) {

System.out.println("Cách này không có tác dụng. Sau đây là lý do:"); ex.printStackTrace();

}

}

C u

ấ trúc này tư ng

ơ t

ự nh

ư m t

ộ l nh

ệ if. Nếu “nhánh” thứ nh t

ấ ch y

ạ mà không gây ra m t

ộ bi t

ệ l

ệ nào, thì

nhánh th

ứ hai s

ẽ đư c

ợ b

ỏ qua.

Nếu như nhánh th

ứ nh t

ấ gây nên m t

ộ bi t

ệ l ,

ệ thì lu ng

ồ th c

ự thi s

ẽ nh y

ả đ n

ế nhánh th

ứ hai, v n

ố đ

ể x

ử lý

điều ki n

ệ bi t

ệ l

ệ (b ng

ằ cách nói “sai r i

ồ ” theo m t

ộ cách l c

ị h thi p)

ệ . Trong trư ng

ờ h p

ợ này nó in ra m t

ộ

thông báo l i

ỗ cùng v i

ớ k t

ế qu

ả l n

ầ d u

ấ ngăn x p.

ế

B n

ạ có thể t i

ả đo n

ạ mã l nh

ệ này v

ề từ http://thinkapjava.com/code/Words.java và danh sách t ừ v ng

ự

ở http://thinkapjava.com/code/words.txt. Hãy đảm b o ả ch c

ắ r ng

ằ hai file này đ t

ặ trong cùng th

ư m c

ụ .

(Nếu b n

ạ dùng môi trư ng

ờ phát tri n

ể tích h p

ợ nh

ư NetBeans ho c

ặ Eclipse, hãy đ m

ả b o

ả r n

ằ g file

words.txt nằm trong th

ư m c

ụ d

ự án hi n

ệ th i

ờ .)

Bây gi

ờ hãy đi làm các Bài t p

ậ 9, 10, 11 c a

ủ Chư ng

ơ 10 – Chu i

ỗ kí t .

ự

Phụ lục C: Phát tri n

ể ch ng

ươ trình

Trở về M c

ụ l c

ụ cuốn sách C.1 Các chi n l

ế ư c

ợ

Trong cu n

ố sách tôi đã trình bày nh ng

ữ chi n

ế lư c

ợ khác nhau đ

ể phát tri n

ể chư ng

ơ trình, b i

ở v y

ậ gi

ờ

đây tôi mu n

ố t p

ậ h p

ợ chúng l i

ạ . N n

ế t n

ả g c a

ủ t t

ấ c

ả chi n

ế lư c

ợ này cùng là phát tri n

ể tăng d n

ầ , vốn

như sau:

1.L y

ấ đi m

ể khởi đ u

ầ là chư ng

ơ trình ch y

ạ đư c

ợ , ch ỉth c

ự hi n

ệ m t

ộ đ ng

ộ tác d

ễ th y

ấ , ch n

ẳ g h n

ạ in d

ữ

liệu nào đó.

2.Mỗi lúc chỉ bổ sung thêm m t

ộ ít dòng l nh

ệ , và c

ứ thay đ i

ổ m t

ộ l n

ầ l i

ạ ph i

ả ki m

ể tra chư ng

ơ trình.

3.L p

ặ l i

ạ công đo n

ạ đ n

ế khi chư ng

ơ trình th c

ự hi n

ệ đư c

ợ vi c

ệ d

ự ki n.

ế

Sau mỗi thay đ i

ổ , chư ng

ơ trình ph i

ả cho k t

ế qu

ả nhìn th y

ấ đư c

ợ đ

ể ki m

ể tra đo n

ạ mã l nh

ệ m i

ớ b

ổ sung.

Cách ti p

ế c n

ậ l p

ậ trình nh

ư th

ế này có th

ể ti t

ế ki m

ệ cho ta nhi u

ề th i

ờ gian.

B i

ở m i

ỗ lúc b n

ạ ch ỉthêm có m t

ộ vài dòng l nh

ệ , nên r t

ấ d

ễ tìm ra các l i

ỗ cú pháp. Và vì m i

ỗ phiên b n

ả

chương trình l i

ạ t o

ạ nên k t

ế qu

ả nhìn th y

ấ đư c

ợ , nên b n

ạ liên t c

ụ ki m

ể tra mô hình nh n

ậ th c

ứ c a

ủ mình

về cách chư ng

ơ trình ho t

ạ đ ng

ộ . N u

ế mô hình nh n

ậ th c

ứ b ịsai, b n

ạ s

ẽ đ i

ố m t

ặ v i

ớ mâu thu n

ẫ (và có c

ơ

hội sửa ch a

ữ mô hình đó) trư c

ớ khi vi t

ế ra nhi u

ề dòng l nh

ệ sai.

Thử thách c a

ủ vi c

ệ phát tri n

ể tăng d n

ầ là không d

ễ hình dung ra con đư ng

ờ d n

ẫ t

ừ kh i

ở đi m

ể đ n

ế ch

ỗ

chương trình hoàn thi n

ệ và đún đ n.

ắ Đ

ể giúp cho đi u

ề này, có m t

ộ vài chi n

ế lư c

ợ ta có th

ể ch n

ọ l a

ự :

Đóng gói và khái quát hoá:

N u

ế bạn ch a

ư bi t

ế cách chia bài toán thành các ph ng

ươ th c

ứ , thì hãy vi t

ế mã l nh

ệ trong main,

r i

ồ tìm nh ng

ữ bó l nh

ệ rõ r t

ệ đ

ể gói chúng vào m t

ộ ph ng

ươ th c

ứ , r i

ồ khái quát hoá m t

ộ cách phù

h p

ợ .

L p

ậ nguyên m u

ẫ nhanh:

N u

ế b n

ạ đã bi t

ế c n

ầ vi t

ế ph ng

ươ th c

ứ gì, song ch a

ư bi t

ế cách vi t

ế nó th

ế nào, thì hãy b t

ắ tay vi t

ế m t

ộ

bản nháp đ

ể x

ử lý tr ng

ườ h p

ợ đ n

ơ gi n

ả nh t

ấ , sau đó th

ử nó v i

ớ nh ng

ữ trư ng

ờ h p

ợ khác, v a

ừ vi t

ế v a

ừ

m

ở r ng

ộ và s a

ử l i

ỗ .

H

n

ướ g t

ừ d i

ướ lên:

Bắt đ u

ầ b ng

ằ vi c

ệ viết nh ng

ữ ph ng

ươ th c

ứ đ n

ơ gi n,

ả r i

ồ ghép chúng l i

ạ thành l i

ờ gi i

ả .

H

n

ướ g t

ừ trên xu n

ố g:

Dùng gi

ả mã để thiết k

ế c u

ấ trúc c a

ủ bài toán r i

ồ nh n

ậ di n

ệ nh ng

ữ ph ng

ươ th c

ứ mà b n

ạ c n.

ầ Sau đó

vi t

ế các ph ng

ươ th c

ứ r i

ồ thay th

ế gi

ả mã v i

ớ mã th t

ậ .

Trong quá trình phát tri n,

ể b n

ạ có th

ể c n

ầ ph i

ả d n

ự g “dàn giáo”. Ch ng

ẳ h n

ạ , m i

ỗ l p

ớ c n

ầ ph i

ả có m t

ộ

phương th c

ứ toString để cho phép b n

ạ in ra tr n

ạ g thái c a

ủ m t

ộ đ i

ố tư ng

ợ dư i

ớ d n

ạ g ngư i

ờ đ c

ọ đư c

ợ .

Phương th c

ứ này r t

ấ có ích cho vi c

ệ g

ỡ l i

ỗ , song thư ng

ờ không thu c

ộ v

ề chư ng

ơ trình hoàn thi n.

ệ

C.2 Các hình th c

ứ th t

ấ b i

ạ

Nếu b n

ạ đang ph i

ả m t

ấ quá nhi u

ề th i

ờ gian vào vi c

ệ g

ỡ l i

ỗ , có th

ể là do b n

ạ đang dùng m t

ộ chi n

ế lư c

ợ

phát tri n

ể không hi u

ệ qu .

ả Sau đây là nh ng

ữ hình th c

ứ th t

ấ b i

ạ mà tôi thư ng

ờ g p

ặ nh t

ấ (và cũng đôi khi

m c

ắ ph i

ả ):

Phát tri n

ể không tăng d n

ầ :

N u

ế nh

ư b n

ạ đang vi t

ế nhi u

ề dòng l nh

ệ

cùng lúc mà không biên d c

ị h và ch y

ạ th ,

ử thì b n

ạ đang t

ự

chu c

ố l y

ấ phi n

ề ph c

ứ . Có l n

ầ tôi h i

ỏ m t

ộ sinh viên xem bài t p

ậ làm đ n

ế đâu r i

ồ , c u

ậ ta tr

ả l i

ờ , “Tuy t

ệ !

Em đã vi t

ế h t

ế ch ng

ươ trình r i

ồ . Gi

ờ ch ỉvi c

ệ g

ỡ l i

ỗ thôi.”

Bám ch t

ặ l y

ấ mã l n

ệ h sai:

N u

ế b n

ạ viết ra nhi u

ề dòng l nh

ệ

m t

ộ lúc mà không biên d c

ị h và ki m

ể tra ch ng

ươ trình, thì có th

ể b n

ạ

còn không g

ỡ l i

ỗ đ c

ượ n a

ữ . Đôi khi chi n

ế thu t

ậ duy nh t

ấ là (than ôi!) xoá đi mã l nh

ệ

sai r i

ồ làm l i

ạ t

ừ

đầu (b ng

ằ chi n

ế thu t

ậ tăng d n)

ầ . Nh ng

ư ng i

ườ m i

ớ l p

ậ trình thư ng

ờ có tình c m

ả g n

ắ bó v i

ớ mã l nh

ệ

họ viết ra, dù cho mã l nh

ệ

này không ho t

ạ đ ng

ộ đư c

ợ . Cách duy nh t

ấ đ

ể thoát kh i

ỏ cái b y

ẫ này là ph i

ả

tàn nh n.

ẫ

L p

ậ trình b c

ướ ng u

ẫ nhiên:

Đôi khi tôi h n

ướ g d n

ẫ sinh viên mà d n

ườ g nh

ư h

ọ l p

ậ trình ki u

ể ng u

ẫ nhiên. H

ọ s a

ử m t

ộ ch

ỗ trong

ch ng

ươ trình, ch y

ạ , nh n

ậ l y

ấ thông báo l i

ỗ , r i

ồ l i

ạ s a

ử , l i

ạ ch y

ạ , v.v. V n

ấ đ

ề là không h

ề có m i

ố liên h

ệ

rõ ràng nào gi a

ữ k t

ế qu

ả ch ng

ươ trình và ch

ỗ s a

ử đ i

ổ đó. N u

ế b n

ạ nh n

ậ đ c

ượ thông báo l i

ỗ , thì hãy

dành th i

ờ gian đ

ể đ c

ọ nó. T ng

ổ quát h n

ơ , hãy dành th i

ờ gian suy nghĩ.

Phó m c

ặ cho trình biên d c

ị h:

Các thông báo l i

ỗ đ u

ề có ích, song không ph i

ả lúc nào chúng cũng đúng. Ch ng

ẳ h n,

ạ n u

ế thông báo ghi

là, “Semi-colon expected on line 13,” (thi u

ế m t

ộ d u

ấ ch m

ấ ph y

ẩ

ở dòng 13), thì đi u

ề này nghĩa là có l i

ỗ

cú pháp

ở g n

ầ dòng 13. Song cách gi i

ả quy t

ế không ph i

ả lúc nào cũng là đi n

ề d u

ấ ch m

ấ ph y

ẩ vào dòng

13. Đ ng

ừ phó m c

ặ ch ng

ươ trình c a

ủ mình cho trình biên d c

ị h.

Chương ti p

ế theo sẽ trình bày thêm các g i

ợ ý v

ề cách g

ỡ l i

ỗ hi u

ệ qu .

ả

Phụ lục D: Gỡ lỗi

Trở về M c

ụ l c

ụ cuốn sách Chiến thuật gỡ l i

ỗ hay nh t

ấ còn tuỳ thu c

ộ vào lo i

ạ l i

ỗ b n

ạ m c

ắ ph i

ả :

• Lỗi cú pháp t o

ạ ra b i

ở trình biên d c

ị h, nh m

ằ ch ỉđ nh

ị có tr c

ụ tr c

ặ trong cú pháp c a

ủ chư ng

ơ trình.

Ch ng

ẳ h n:

ạ b

ỏ m t

ấ d u

ấ ch m

ấ ph y

ẩ

ở cu i

ố câu l nh

ệ .

• Các bi t

ệ l

ệ đư c

ợ t o

ạ ra n u

ế có đi u

ề gì tr c

ụ tr c

ặ khi chư ng

ơ trình đang ch y

ạ . Ch n

ẳ g h n:

ạ m t

ộ vòng đ

ệ quy

vô h n

ạ cuối cùng s

ẽ gây nên bi t

ệ lệ StackOverflowException.

• Lỗi logic khi n

ế cho chư ng

ơ trình th c

ự hi n

ệ vi c

ệ làm sai. Ch n

ẳ g h n,

ạ m t

ộ bi u

ể th c

ứ có th

ể không đư c

ợ

tính toán đúng theo trình t

ự mà b n

ạ đ nh

ị li u

ệ , cho ra k t

ế qu

ả không lư ng

ờ trư c

ớ .

Các m c

ụ ti p

ế sau đây đư c

ợ x p

ế theo ki u

ể l i

ỗ ; có nh ng

ữ kĩ thu t

ậ x

ử lý dùng đư c

ợ cho nhi u

ề lo i

ạ l i

ỗ khác

nhau.

D.1 Lỗi cú pháp

Hình th c

ứ g

ỡ lỗi hay nh t

ấ là

ở đó b n

ạ không ph i

ả làm gì, b i

ở ngay t

ừ đ u

ầ b n

ạ đã tránh m c

ắ ph i

ả l i

ỗ .

Trong m c

ụ trư c

ớ , tôi đã đ

ề xu t

ấ nh ng

ữ chi n

ế lư c

ợ phát tri n

ể đ

ể gi m

ả thi u

ể l i

ỗ và t o

ạ đi u

ề ki n

ệ phát

hiện sớm lỗi khi m c

ắ ph i

ả chúng. Đi m

ể m u

ấ ch t

ố là l y

ấ m t

ộ chư ng

ơ trình ch y

ạ đư c

ợ làm đi m

ể kh i

ở

đ u

ầ , và m i

ỗ lúc ch ỉthêm r t

ấ ít mã l nh

ệ . Khi có l i

ỗ , b n

ạ s

ẽ bi t

ế rõ là l i

ỗ này n m

ằ

ở đâu.

Dù v y

ậ , b n

ạ có th

ể sẽ r i

ơ vào m t

ộ trong nh ng

ữ tình hu ng

ố sau. V i

ớ m i

ỗ tình hu ng

ố , tôi l i

ạ có đ

ề xu t

ấ

cách x

ử lý thích h p.

ợ

TRÌNH BIÊN D C

Ị H BÀY RA LA LI T

Ệ NH N

Ữ G THÔNG BÁO L I

Ỗ .

Nếu trình biên d c

ị h có báo đ n

ế 100 l i

ỗ đi n a

ữ , thì đi u

ề này cũng không có nghĩa là chư ng

ơ trình b n

ạ có

100 lỗi. Mỗi khi trình biên d c

ị h g p

ặ m t

ộ l i

ỗ , nó thư ng

ờ đi ch c

ệ h ra kh i

ỏ lu ng

ồ th c

ự thi m t

ộ quãng. Nó

sẽ cố g ng

ắ h i

ồ ph c

ụ và ti p

ế t c

ụ theo lu ng

ồ th c

ự thi sau l i

ỗ đ u

ầ tiên, nh ng

ư đôi khi nó thông báo nh ng

ữ

lỗi đáng ng .

ờ

Ch ỉcó thông báo l i

ỗ đ u

ầ tiên m i

ớ đáng tin c y

ậ . Tôi g i

ợ ý r ng

ằ b n

ạ s a

ử t ng

ừ l i

ỗ m t

ộ , r i

ồ biên d c

ị h l i

ạ

chương trình. B n

ạ có th

ể th y

ấ m t

ộ d u

ấ ch m

ấ ph y

ẩ có th

ể “s a

ử đư c

ợ ” 100 l i

ỗ .

TÔI ĐANG GẶP MỘT LỖI BIÊN D C

Ị H TH T

Ậ KÌ QUẶC VÀ NÓ CH N

Ẳ G BI N

Ế ĐI.

Trư c

ớ h t

ế , hãy đọc kĩ thông báo l i

ỗ này. Thông báo đư c

ợ vi t

ế b n

ằ g ngôn ng

ữ chuyên d ng

ụ và r t

ấ ng n

ắ

ng i

ủ , song thường n

ẩ ch a

ứ m t

ộ thông tin c t

ố lõi.

Nếu không có gì khác, thông báo s

ẽ cho b n

ạ bi t

ế tr c

ụ tr c

ặ x y

ả ra

ở đâu trong chư ng

ơ trình. Th c

ự ra, nó

cho b n

ạ bi t

ế trình biên d c

ị h đang

ở đâu khi phát hi n

ệ th y

ấ l i

ỗ , ch

ứ không nh t

ấ thi t

ế là n i

ơ có l i

ỗ . Hãy

dùng thông tin thu nh n

ậ t

ừ trình biên d c

ị h nh

ư m t

ộ ch ỉd n,

ẫ song n u

ế b n

ạ không th y

ấ l i

ỗ theo hư ng

ớ

ch ỉd n

ẫ đó thì hãy m

ở r ng

ộ vi c

ệ tìm ki m

ế ra.

Nói chung l i

ỗ s

ẽ n m

ằ

ở trư c

ớ v ịtrí thông báo l i

ỗ , song cũng có nh ng

ữ trư ng

ờ h p

ợ mà l i

ỗ n m

ằ

ở n i

ơ khác

h n

ẳ . Ch ng

ẳ h n

ạ , n u

ế b n

ạ nh n

ậ đư c

ợ thông báo l i

ỗ

ở m t

ộ l i

ờ kích ho t

ạ phư ng

ơ th c

ứ , thì có khi l i

ỗ th c

ự

sự l i

ạ nằm

ở l i

ờ đ nh

ị nghĩa phư ng

ơ th c

ứ .

Nếu b n

ạ ch a

ư nhanh chóng tìm ra đư c

ợ l i

ỗ , thì hãy l y

ấ h i

ơ th t

ậ sâu r i

ồ nhìn r ng

ộ ra c

ả chư ng

ơ trình.

Hãy đảm b o

ả ch c

ắ r ng

ằ chư ng

ơ trình đư c

ợ vi t

ế th t

ụ đ u

ầ dòng đúng chu n;

ẩ đi u

ề này giúp ta phát hi n

ệ

lỗi cú pháp d

ễ dàng h n.

ơ

Bây gi ,

ờ hãy tìm ki m

ế nh ng

ữ l i

ỗ d

ễ m c

ắ ph i

ả :

1. Ki m

ể tra tất cả nh ng

ữ c p

ặ ngo c

ặ tròn và ngo c

ặ nh n

ọ ph i

ả cân x ng

ứ và đư c

ợ l ng

ồ ghép đúng th

ứ t .

ự T t

ấ

c

ả lời đ nh

ị nghĩa phư ng

ơ th c

ứ ph i

ả đư c

ợ l ng

ồ trong m t

ộ l i

ờ đ nh

ị nghĩa l p.

ớ T t

ấ c

ả các câu l nh

ệ c a

ủ

chương trình ph i

ả đ t

ặ trong đ nh

ị nghĩa phư ng

ơ th c

ứ .

2. Hãy nh

ớ r ng

ằ vi t

ế ch

ữ in thì khác v i

ớ ch

ữ thư ng

ờ .

3. Ki m

ể tra dấu chấm ph y

ẩ

ở cu i

ố câu l nh

ệ (và không có d u

ấ ch m

ấ ph y

ẩ theo sau ngo c

ặ nh n)

ọ .

4. Hãy đảm b o

ả ch c

ắ r ng

ằ m i

ỗ chu i

ỗ kí t

ự trong mã l nh

ệ ph i

ả có đôi d u

ấ nháy kép. Đ m

ả b o

ả ch c

ắ r ng

ằ

b n

ạ dùng nháy kép cho chu i

ỗ và nháy đ n

ơ cho kí t .

ự

5. Với từng câu l nh

ệ gán, hãy đ m

ả b o

ả r n

ằ g ki u

ể d

ữ li u

ệ

ở bên v

ế trái cũng gi ng

ố nh

ư ki u

ể v

ế ph i

ả . Hãy

đ m

ả b o

ả r ng

ằ bi u

ể th c

ứ bên v

ế trái là m t

ộ tên bi n

ế ho c

ặ đ i

ố tư ng

ợ nào khác mà b n

ạ có th

ể gán giá tr ị

vào cho nó (nh

ư m t

ộ ph n

ầ t

ử c a

ủ m ng

ả ).

6. Với từng l n

ầ kích ho t

ạ phư ng

ơ th c

ứ , hãy đ m

ả b o

ả r ng

ằ các đ i

ố s

ố đư c

ợ cung c p

ấ đã x p

ế đúng v ịtrí, và

có đúng ki u

ể , và đ i

ố tư ng

ợ mà b n

ạ đang kích ho t

ạ phư ng

ơ th c

ứ lên cũng có đúng ki u

ể .

7. Nếu b n

ạ đang kích ho t

ạ m t

ộ phư ng

ơ th c

ứ tr

ả giá tr ,ị hãy đ m

ả b o

ả ch c

ắ r ng

ằ b n

ạ thao tác v i

ớ giá tr ịtr

ả

về này. N u

ế b n

ạ kích ho t

ạ m t

ộ phư ng

ơ th c

ứ r ng

ỗ , hãy đ m

ả b o

ả ch c

ắ r n

ằ g mình không thử làm gì v i

ớ

kết qu .

ả

8. Nếu b n

ạ đang kích ho t

ạ m t

ộ phư ng

ơ th c

ứ đ i

ố tư ng

ợ , hãy ch c

ắ r ng

ằ b n

ạ đang kích ho t

ạ nó v i

ớ m t

ộ đ i

ố

tượng đúng ki u

ể . N u

ế b n

ạ đang kích ho t

ạ m t

ộ phư ng

ơ th c

ứ l p

ớ t

ừ bên ngoài phư ng

ơ th c

ứ mà nó đư c

ợ

đ nh

ị nghĩa, hãy đ m

ả b o

ả ch c

ắ r n

ằ g b n

ạ đã ch ỉđ n

ị h tên l p

ớ này.

9. Bên trong một phư ng

ơ th c

ứ đ i

ố tư ng

ợ , b n

ạ có th

ể tham chi u

ế t i

ớ các bi n

ế th c

ự th

ể mà không quy đ n

ị h

đối tượng nào. N u

ế b n

ạ th

ử làm đi u

ề này trong m t

ộ phư ng

ơ th c

ứ l p,

ớ b n

ạ s

ẽ nh n

ậ đư c

ợ thông báo ki u

ể

như, “Tham chi u

ế tĩnh t i

ớ bi n

ế không tĩnh.”

Nếu không có gi i

ả pháp nào k

ể trên phát huy tác d n

ụ g, hãy xem m c

ụ k

ế ti p

ế …

TÔI KHÔNG TH B

Ể IÊN D C

Ị H ĐƯ C

Ợ CHƯ N

Ơ G TRÌNH DÙ ĐÃ C G

Ố

N

Ắ G MỌI CÁCH.

Nếu như trình biên d c

ị h nói r n

ằ g có l i

ỗ mà b n

ạ không nhìn th y

ấ , thì có kh

ả năng là do b n

ạ và trình biên

d c

ị h không cùng nhìn vào đo n

ạ mã l nh

ệ . Hãy ki m

ể tra môi trư ng

ờ phát tri n

ể đang dùng đ

ể đ m

ả b o

ả

ch c

ắ r n

ằ g chư ng

ơ trình b n

ạ đang so n

ạ th o

ả chính là chư ng

ơ trình đang đư c

ợ biên d c

ị h. N u

ế b n

ạ còn

chưa ch c

ắ ch n,

ắ hãy th

ử c

ố tình đ a

ư vào m t

ộ l i

ỗ cú pháp ngay

ở đ u

ầ chư ng

ơ trình. Bây gi

ờ hãy biên d c

ị h

l i

ạ . N u

ế trình biên d c

ị h v n

ẫ không tìm th y

ấ l i

ỗ m i

ớ đó, thì có l

ẽ b n

ạ đã thi t

ế l p

ậ môi trư ng

ờ tích h p

ợ sai

quy cách.

Nếu b n

ạ đã ki m

ể tra mã l nh

ệ m t

ộ lư t

ợ r i

ồ , và ch c

ắ ch n

ắ là trình biên d c

ị h đang làm vi c

ệ v i

ớ đúng mã

lệnh mình so n

ạ th o

ả , thì đã đ n

ế lúc dùng phư ng

ơ pháp “tuy t

ệ v ng

ọ ”: g

ỡ l i

ỗ b n

ằ g cách chia đôi.

• Hãy t o

ạ một b n

ả sao c a

ủ file hi n

ệ hành. N u

ế b n

ạ đang so n

ạ file Bob.java, hãy l p

ậ b n

ả sao có

tên Bob.java.old.

• Xóa b t

ớ một n a

ử mã l nh

ệ t

ừ file Bob.java. Th

ử biên d c

ị h l i

ạ .

• Nếu giờ đây chư ng

ơ trình biên d c

ị h đư c

ợ thì b n

ạ bi t

ế r ng

ằ l i

ỗ n m

ằ

ở n a

ử kia. Hãy ph c

ụ h i

ồ l i

ạ n a

ử v a

ừ

xóa r i

ồ l p

ặ l i

ạ cách th .

ử

• Nếu chương trình v n

ẫ không biên d c

ị h n i

ổ , thì l i

ỗ sai ph i

ả n m

ằ

ở n a

ử còn l i

ạ này. Hãy xóa đi m t

ộ n a

ử

số mã l nh

ệ rồi l p

ặ l i

ạ cách th .

ử

• Một khi b n

ạ đã tìm th y

ấ và s a

ử đư c

ợ l i

ỗ , thì hãy d n

ầ d n

ầ ph c

ụ h i

ồ l i

ạ ph n

ầ mã l nh

ệ đã xóa, t ng

ừ ít t ng

ừ

ít một.

Quá trình này th t

ậ l m

ộ c m

ộ , nh ng

ư th t

ậ ra là nhanh h n

ơ so v i

ớ b n

ạ nghĩ; và cách này cũng r t

ấ đáng tin

c y

ậ .

TÔI ĐÃ LÀM THEO CH D

Ỉ ẪN C A

Ủ TRÌNH BIÊN D C

Ị H MÀ V N

Ẫ CH A

Ư CÓ TÁC D N

Ụ G.

Một số thông báo c a

ủ trình biên d c

ị h l i

ạ có đo n

ạ l i

ờ khuyên nh ,

ủ ch ng

ẳ h n

ạ “class Golfer must be

declared abstract. It does not define int compareTo(java.lang.Object) from interface java.lang.Comparable.” (l p

ớ Golfer ph i

ả đư c

ợ khai báo là tr u

ừ tư ng

ợ . Nó không đ nh

ị nghĩa int

compareTo(java.lang.Object) t

ừ trong interface java.lang.Comparable.) Nghe có v

ẻ nh

ư trình biên d c

ị h

đang b o

ả b n

ạ khai báo Golfer là l p

ớ tr u

ừ tư ng

ợ , và n u

ế b n

ạ đ c

ọ cách này thì có l

ẽ ch n

ẳ g hi u

ể đó là gì

ho c

ặ cách làm th

ế nào.

Thật may là, trình biên d c

ị h đã sai. Trong trư ng

ờ h p

ợ này, gi i

ả pháp là đ m

ả b o

ả r ng

ằ Golfer có một

phương th c

ứ mang tên compareTo để nh n

ậ tham số là một Object.

Đừng đ

ể trình biên d c

ị h d t

ắ mũi b n.

ạ Các thông báo l i

ỗ cho b n

ạ ch ng

ứ c

ớ là đã có tr c

ụ tr c

ặ , nh ng

ư cách

kh c

ắ ph c

ụ mà nó chúng đ a

ư ra đ u

ề không đáng tin c y

ậ .

D.2 Lỗi thực thi

CHƯ N

Ơ G TRÌNH TÔI VI T

Ế B ỊTREO.

Nếu một chư ng

ơ trình d ng

ừ l i

ạ và hình nh

ư không làm gì, ta nói r ng

ằ nó đã bị treo. Thư ng

ờ thì đi u

ề

này nghĩa là nó m c

ắ ph i

ả m t

ộ vòng l p

ặ vô h n

ạ ho c

ặ đ

ệ quy vô h n

ạ .

• Nếu có một vòng l p

ặ c

ụ th

ể mà b n

ạ nghi ng

ờ có v n

ấ đ ,

ề hãy thêm m t

ộ l nh

ệ print ngay trư c

ớ vòng l p,

ặ

để in ra “tien vao vong lap” và m t

ộ l nh

ệ khác ngay sau vòng l p,

ặ in ra “thoat khoi vong lap”. Ch y

ạ

chương trình. N u

ế b n

ạ th y

ấ đư c

ợ thông đi p

ệ th

ứ nh t

ấ mà không th y

ấ cái th

ứ hai thì đã có m t

ộ vòng l p

ặ

vô h n

ạ . Xem ti p

ế m c

ụ “Vòng l p

ặ vô h n”

ạ dư i

ớ đây.

•

Ở h u

ầ hết trường h p,

ợ đệ quy vô h n

ạ s

ẽ làm cho chư ng

ơ trình ch y

ạ m t

ộ lúc và sau đó phát ra bi t

ệ l

ệ

StackOverflowException. Nếu đi u

ề này x y

ả ra, hãy xem ti p

ế m c

ụ “Đ

ệ quy vô h n”

ạ sau đây. Nếu b n

ạ

không g p

ặ bi t

ệ l

ệ StackOverflowException này nh ng

ư nghi ng

ờ r ng

ằ có v n

ấ đ

ề x y

ả ra v i

ớ m t

ộ phư ng

ơ

thức ho c

ặ hàm đệ quy, b n

ạ v n

ẫ có thể s

ử d ng

ụ các kĩ thu t

ậ trong m c

ụ “Đ

ệ quy vô h n”.

ạ

• Nếu cách này cũng không có tác d ng

ụ thì có th

ể là b n

ạ ch a

ư hi u

ể lu ng

ồ th c

ự hi n

ệ c a

ủ chư ng

ơ trình. Hãy

đọc ti p

ế m c

ụ “Luồng th c

ự thi” bên dư i

ớ .

VÒNG LẶP VÔ HẠN

Nếu b n

ạ nghĩ r ng

ằ b n

ạ có m t

ộ vòng l p

ặ vô h n

ạ và cho r n

ằ g mình đã bi t

ế đư c

ợ vòng l p

ặ nào gây ra v n

ấ

đề, thì hãy thêm m t

ộ l nh

ệ print t i

ạ đi m

ể cuối vòng l p

ặ và in ra giá tr ịcác bi n

ế trong đi u

ề ki n

ệ cùng v i

ớ

giá tr ịc a

ủ đi u

ề ki n.

ệ

Ch ng

ẳ h n:

ạ

while (x > 0 && y < 0) {

// thao tác gì đó với x

// thao tác gì đó với y

System.out.println("x: " + x);

System.out.println("y: " + y);

System.out.println("điều kiện: " + (x > 0 && y < 0));

}

Bây gi

ờ khi ch y

ạ chư ng

ơ trình, b n

ạ s

ẽ th y

ấ ba dòng k t

ế qu

ả v i

ớ m i

ỗ l n

ầ ch y

ạ qua vòng l p.

ặ L n

ầ cu i

ố

cùng ch y

ạ qua vòng l p

ặ đi u

ề ki n

ệ s

ẽ ph i

ả là false. N u

ế vòng l p

ặ ti p

ế t c

ụ ch y

ạ , b n

ạ s

ẽ nhìn đư c

ợ các giá

trị c a

ủ x và y, và có thể hình dung đư c

ợ t i

ạ sao chúng không đư c

ợ c p

ậ nh t

ậ đúng.

ĐỆ QUY VÔ H N

Ạ

Trong nhi u

ề trư ng

ờ h p,

ợ m t

ộ vòng l p

ặ đ

ệ quy s

ẽ khi n

ế chư ng

ơ trình phát bi t

ệ

lệ StackOverflowException. Nhưng n u

ế chư ng

ơ trình ch m

ậ ch p

ạ có th

ể nó s

ẽ t n

ố nhi u

ề th i

ờ gian đ

ể b ị

đ y

ầ ngăn x p.

ế

Nếu b n

ạ nghi ng

ờ r n

ằ g m t

ộ hàm ho c

ặ phư ng

ơ th c

ứ nào đó gây ra đ

ệ quy vô h n,

ạ hãy b t

ắ đàu ki m

ể tra

để ch c

ắ r ng

ằ có m t

ộ trư ng

ờ h p

ợ c

ơ s .

ở Nói cách khác, c n

ầ ph i

ả có đi u

ề ki n

ệ nào đó đ

ể khi n

ế cho hàm

ho c

ặ phương th c

ứ tr

ả v

ề mà không g i

ọ đ

ệ quy n a

ữ . N u

ế không, b n

ạ c n

ầ ph i

ả nghĩ l i

ạ thu t

ậ toán và tìm

ra một trường hợp c

ơ s .

ở

Nếu có một trư ng

ờ h p

ợ c

ơ s

ở nh ng

ư chư ng

ơ trình dư ng

ờ nh

ư không đ t

ạ đ n

ế đó, thì hãy thêm câu

lệnh print vào đi m

ể đ u

ầ c a

ủ hàm ho c

ặ phư ng

ơ th c

ứ đ

ể in ra các tham bi n.

ế Bây gi

ờ khi ch y

ạ chư ng

ơ

trình, b n

ạ s

ẽ th y

ấ m t

ộ ít dòng k t

ế qu

ả m i

ỗ l n

ầ hàm ho c

ặ phư ng

ơ th c

ứ đư c

ợ g i

ọ đ n,

ế và s

ẽ th y

ấ giá tr ị

các tham s .

ố N u

ế tham s

ố không thay đ i

ổ v i

ớ xu hư ng

ớ v

ề trư ng

ờ h p

ợ c

ơ s ,

ở b n

ạ s

ẽ th y

ấ đư c

ợ t i

ạ sao.

LU N

Ồ G TH C

Ự THI

Nếu b n

ạ không ch c

ắ ch n

ắ v

ề lu ng

ồ th c

ự hi n

ệ trong chư ng

ơ trình, hãy thêm các câu l nh

ệ print vào

điểm đầu c a

ủ mỗi hàm v i

ớ thông báo ki u

ể nh

ư “b t

ắ đ u

ầ phư ng

ơ th c

ứ foo”, trong đó foo là tên phương

thức.

Bây gi

ờ khi ch y

ạ chư ng

ơ trình, nó sẽ in ra m t

ộ d u

ấ v t

ế c a

ủ m i

ỗ phư ng

ơ th c

ứ khi đư c

ợ kích ho t

ạ đ n.

ế

B n

ạ cũng có th

ể in ra nh ng

ữ đ i

ố s

ố mà t ng

ừ phư ng

ơ th c

ứ nh n

ậ đư c

ợ . Khi ch y

ạ chư ng

ơ trình, hãy ki m

ể

tra xem các giá tr ịnày h p

ợ lý không, và ki m

ể tra m t

ộ trong nh ng

ữ l i

ỗ thư ng

ờ m c

ắ ph i

ả nh t

ấ —cung c p

ấ

các đ i

ố s

ố sai th

ứ t .

ự

KHI CH Y

Ạ CHƯ N

Ơ G TRÌNH TÔI NH N

Ậ ĐƯ C

Ợ M T

Ộ BI T

Ệ L .

Ệ

Khi có bi t

ệ l

ệ x y

ả ra, Java s

ẽ in m t

ộ thông báo trong đó có tên c a

ủ bi t

ệ l ,

ệ dòng l nh

ệ có v n

ấ đ ,

ề và m t

ộ

l n

ầ dấu v t

ế trên ngăn x p

ế (stack trace). B n

ả thân cái l n

ầ v t

ế này ch a

ứ thông tin v

ề phư ng

ơ th c

ứ đang

được ch y

ạ , và phư ng

ơ th c

ứ kích ho t

ạ nó, r i

ồ phư ng

ơ th c

ứ kích ho t

ạ phư ng

ơ th c

ứ đó, và c

ứ nh

ư v y

ậ .

Bước đ u

ầ tiên là ki m

ể tra v ịtrí trong chư ng

ơ trình n i

ơ mà l i

ỗ xu t

ấ hi n,

ệ đ ng

ồ th i

ờ th

ử hình dung đi u

ề gì

đã x y

ả ra.

NullPointerException:

Bạn c

ố g ng

ắ truy c p

ậ m t

ộ bi n

ế th c

ự th

ể ho c

ặ kích ho t

ạ m t

ộ ph ng

ươ th c

ứ trên đ i

ố t ng

ượ mà b n

ả

thân nó đang là null. Bạn c n

ầ ph i

ả hình dung ra bi n

ế nào là null r i

ồ hình dung xem b ng

ằ cách

nào d n

ẫ đ n

ế hi n

ệ t ng

ượ đó. Hãy nh

ớ r ng

ằ khi khai báo m t

ộ bi n

ế v i

ớ m t

ộ ki u

ể đ i

ố t ng

ượ , thì ban

đầu nó v n

ẫ là null đ n

ế t n

ậ khi b n

ạ gán giá tr ịcho. Ch ng

ẳ h n,

ạ đo n

ạ mã sau gây ra bi t

ệ l

ệ

NullPointerException:

Point blank;

System.out.println(blank.x);

ArrayIndexOutOfBoundsException:

Ch ỉs

ố mà b n

ạ đang dùng đ

ể truy c p

ậ m t

ộ m ng

ả đã l n

ớ h n

ơ array.length-1. N u

ế b n

ạ tìm đ c

ượ v ị

trí l i

ỗ , hãy thêm vào câu l nh

ệ print vào ngay tr c

ướ l i

ỗ này đ

ể hi n

ể th ịgiá tr ịc a

ủ ch ỉs

ố cùng v i

ớ

chi u

ề dài c a

ủ m ng

ả . Li u

ệ m ng

ả này có kích th c

ướ đúng ch a

ư ? Ch ỉs

ố có đúng không? Bây gi

ờ

tìm ng c

ượ l i

ạ d c

ọ ch ng

ươ trình và xem m ng

ả này cùng v i

ớ ch ỉs

ố đó b t

ắ ngu n

ồ t

ừ đâu. Hãy tìm

l nh

ệ

gán g n

ầ nh t

ấ và xem nó có th c

ự hi n

ệ đúng không. N u

ế không có cái nào là tham s ,

ố thì hãy

đ n

ế ch

ỗ ph n

ươ g th c

ứ đ c

ượ kích hoạt và xem các giá tr ịnày đ n

ế t

ừ đâu.

StackOverFlowException:

Xem “Đ

ệ quy vô h n.

ạ ”

FileNotFoundException:

Đi u

ề này nghĩa là Java không tìm th y

ấ file c n

ầ thi t

ế . N u

ế b n

ạ đang dùng m t

ộ môi trư ng

ờ phát tri n

ể

d a

ự trên các d

ự án, nh

ư Eclipse, thì có kh

ả năng là b n

ạ s

ẽ ph i

ả nh p

ậ file đó vào trong d

ự án đang m .

ở

Còn không thì hãy đ m

ả b o

ả ch c

ắ r ng

ằ file đó t n

ồ t i

ạ và đ ng

ườ d n

ẫ đ n

ế nó đ c

ượ ghi đúng. V n

ấ đ

ề này

tuỳ thu c

ộ vào h

ệ th ng

ố file trên máy tính c a

ủ b n,

ạ b i

ở v y

ậ có th

ể khó dò tìm.

ArithmeticException:

Bi t

ệ l

ệ phát ra khi có tr c

ụ tr c

ặ v i

ớ phép toán s

ố h c

ọ , th n

ườ g là phép chia cho s

ố không.

TÔI ĐÃ THÊM VÀO QUÁ NHI U

Ề L N

Ệ H PRINT Đ N

Ế N I

Ỗ BÂY GI

Ờ NG P

Ậ TRÀN K T

Ế QU Đ

Ả

U

Ầ RA.

Một trong nh ng

ữ v n

ấ đ

ề khi dùng l nh

ệ print để gỡ lỗi là vi c

ệ b n

ạ có thể b ịchìm trong k t

ế qu

ả ra. Có

hai cách ti p

ế t c

ụ : đ n

ơ gi n

ả hóa đ u

ầ ra ho c

ặ đ n

ơ gi n

ả hóa chư ng

ơ trình.

Để gi n

ả hóa k t

ế qu

ả đ u

ầ ra, b n

ạ c n

ầ xóa b

ỏ ho c

ặ đ a

ư vào chú thích nh ng

ữ dòng l nh

ệ print vốn không

có tác d n

ụ g, ho c

ặ k t

ế h p

ợ chúng l i

ạ , ho c

ặ s a

ử đ n

ị h d ng

ạ đ u

ầ ra đ

ể d

ễ hi u

ể h n.

ơ

Để gi n

ả hóa chư ng

ơ trình, có vài cách làm đư c

ợ . Trư c

ớ h t

ế , hãy gi m

ả quy mô c a

ủ bài toán xu ng

ố . Ch n

ẳ g

h n

ạ , nếu b n

ạ c n

ầ tìm ki m

ế trong m ng

ả , hãy làm v i

ớ m t

ộ m n

ả g nhỏ. Nếu chương trình nh n

ậ đầu vào t

ừ

phía người dùng, hãy cho nh ng

ữ d

ữ li u

ệ vào đ n

ơ gi n

ả mà gây ra l i

ỗ .

Đ ng

ồ th i

ờ hãy d n

ọ d p

ẹ chư ng

ơ trình. Hãy b

ỏ nh ng

ữ đo n

ạ mã ch t

ế và t

ổ ch c

ứ l i

ạ chư ng

ơ trình đ

ể nó

càng d

ễ đọc càng t t

ố . Ch ng

ẳ h n,

ạ n u

ế b n

ạ nghi r ng

ằ v n

ấ đ

ề n m

ằ

ở m t

ộ đo n

ạ n m

ằ sâu trong chư ng

ơ

trình, hãy th

ử vi t

ế l i

ạ nó v i

ớ c u

ấ trúc đ n

ơ gi n

ả h n.

ơ N u

ế b n

ạ nghi ng

ờ r ng

ằ có m t

ộ phư ng

ơ th c

ứ l n,

ớ

hãy thử ch

ẻ nhỏ thành nh ng

ữ phư ng

ơ th c

ứ nh

ỏ và ki m

ể tra l n

ầ lư t

ợ .

Thông thường quá trình tìm ra trư ng

ờ h p

ợ th

ử đ n

ơ gi n

ả nh t

ấ s

ẽ d n

ẫ b n

ạ đ n

ế đi m

ể gây l i

ỗ . Ch n

ẳ g h n,

ạ

nếu b n

ạ th y

ấ chư ng

ơ trình ch y

ạ đư c

ợ trong trư ng

ờ h p

ợ s

ố ph n

ầ t

ử trong m n

ả g là ch n

ẵ nh ng

ư không

được khi số ph n

ầ tử là l ,

ẻ thì đi u

ề đó s

ẽ là d u

ấ v t

ế cho th y

ấ đi u

ề gì đang di n

ễ ra.

Việc tổ ch c

ứ l i

ạ m t

ộ đo n

ạ mã có th

ể giúp b n

ạ phát hi n

ệ nh ng

ữ l i

ỗ nh .

ỏ N u

ế b n

ạ th c

ự hi n

ệ s a

ử đ i

ổ mà

nghĩ r ng

ằ nó không nh

ả hư ng

ở gì đ n

ế chư ng

ơ trình, và lúc có nh

ả hư ng

ở thì đó s

ẽ là bài h c

ọ cho b n.

ạ

D.3 Lỗi logic

CHƯ N

Ơ G TRÌNH TÔI VI T

Ế RA KHÔNG HOẠT Đ N

Ộ G ĐÚNG.

Lỗi logic r t

ấ khó tìm, vì trình biên d c

ị h và h

ệ th ng

ố lúc th c

ự thi không cung c p

ấ thông tin gì v

ề s

ự tr c

ụ

tr c

ặ . Ch ỉcó b n

ạ m i

ớ bi t

ế r ng

ằ chư ng

ơ trinh c n

ầ ph i

ả th c

ự hi n

ệ đi u

ề gì.

Bước đ u

ầ tiên là t o

ạ l p

ậ m t

ộ k t

ế n i

ố gi a

ữ n i

ộ dung chư ng

ơ trình và bi u

ể hi n

ệ mà b n

ạ quan sát đư c

ợ .

B n

ạ c n

ầ giả thiết v

ề đi u

ề th t

ậ s

ự mà chư ng

ơ trình đang th c

ự hi n.

ệ B n

ạ c n

ầ tự h i

ỏ mình nh ng

ữ đi u

ề sau:

• Có đi u

ề gì mà chư ng

ơ trình c n

ầ ph i

ả làm nh ng

ư dư ng

ờ nh

ư nó không làm hay không? Hãy tìm ra đo n

ạ

mã l nh

ệ thực hi n

ệ tính năng đó và ch c

ắ r ng

ằ nó đư c

ợ th c

ự thi khi b n

ạ nghĩ r ng

ằ l

ẽ ra nó ph i

ả ch y

ạ .

• Có đi u

ề gì đang di n

ễ ra mà l

ẽ ra không nên có nó? Hãy tìm đo n

ạ mã trong chư ng

ơ trình mà th c

ự hi n

ệ

tính năng đó r i

ồ xem li u

ệ nó có đư c

ợ th c

ự khi trong khi đáng l

ẽ thì không.

• Có đo n

ạ mã nào t o

ạ ra m t

ộ hi u

ệ ng

ứ mà không nh

ư b n

ạ mong đ i

ợ không? Hãy ch c

ắ r n

ằ g b n

ạ hi u

ể đư c

ợ

đo n

ạ mã nghi v n

ấ , đ c

ặ bi t

ệ khi nó liên quan đ n

ế vi c

ệ kích ho t

ạ phư ng

ơ th c

ứ Java. Hãy đ c

ọ tài li u

ệ v

ề

những phư ng

ơ th c

ứ , r i

ồ th

ử b ng

ằ nh ng

ữ trư ng

ờ h p

ợ ki m

ể tra đ n

ơ gi n.

ả Có khi chúng l i

ạ không làm vi c

ệ

mà b n

ạ nghĩ r n

ằ g chúng s

ẽ làm.

Để l p

ậ trình, b n

ạ ph i

ả có m t

ộ mô hình tư ng

ở tư ng

ợ v

ề cách th c

ứ ho t

ạ đ ng

ộ c a

ủ chư ng

ơ trình. N u

ế b n

ạ

viết một chương trình mà không th c

ự hi n

ệ đúng vi c

ệ b n

ạ mong đ i

ợ , thì thư ng

ờ là v n

ấ đ

ề không n m

ằ

ở

chương trình; nó n m

ằ

ở mô hình tư ng

ở tư ng

ợ c a

ủ b n.

ạ

Cách tốt nh t

ấ đ

ể s a

ử mô hình tư ng

ở tư ng

ợ cho đúng là chia chư ng

ơ trình thành nh ng

ữ b

ộ ph n

ậ (thư ng

ờ

là các l p

ớ và phư ng

ơ th c

ứ ) r i

ồ ki m

ể tra ch y

ạ th

ử t ng

ừ b

ộ ph n

ậ m t

ộ cách đ c

ộ l p

ậ . M t

ộ khi b n

ạ th y

ấ s

ự

khác bi t

ệ gi a

ữ mô hình và th c

ự t ,

ế b n

ạ s

ẽ có th

ể gi i

ả quy t

ế v n

ấ đ .

ề

Sau đây là m t

ộ s

ố l i

ỗ logic thông thư ng

ờ c n

ầ ph i

ả ki m

ể tra:

• Luôn nh

ớ r ng

ằ phép chia nguyên làm tròn xu ng

ố . N u

ế b n

ạ mu n

ố c

ả ph n

ầ th p

ậ phân, hãy dùng

số double.

• Số ph y

ẩ động ch ỉlà g n

ầ đúng, nên b n

ạ đ ng

ừ l

ệ thu c

ộ vào đ

ộ chính xác tuy t

ệ đ i

ố .

• Nói chung, hãy dùng s

ố nguyên cho nh ng

ữ th

ứ đ m

ế đư c

ợ và dùng s

ố ph y

ẩ đ ng

ộ cho th

ứ đo đư c

ợ .

• Nếu b n

ạ dùng toán t

ử gán (=) thay vì toán t

ử b n

ằ g (==) trong đi u

ề ki n

ệ c a

ủ m t

ộ l nh

ệ if, while, ho c

ặ for,

b n

ạ có thể s

ẽ nh n

ậ một bi u

ể th c

ứ v

ề m t

ặ cú pháp thì đúng nh ng

ư v

ề ng

ữ nghĩa thì sai.

• Khi b n

ạ áp d n

ụ g toán t

ử b ng

ằ (==) với đối tư ng

ợ , nó s

ẽ ki m

ể tra identity. N u

ế b n

ạ có ý mu n

ố ki m

ể tra

độ tương đương, hãy dùng phư ng

ơ th c

ứ equals.

• Đ i

ố v i

ớ các ki u

ể d

ữ li u

ệ do ngư i

ờ dùng đ nh

ị nghĩa, equals sẽ kiểm tra identity. N u

ế b n

ạ mu n

ố m t

ộ kí

hiệu khác cho tư ng

ơ đ ng

ồ , b n

ạ ph i

ả ghi đè lên nó.

• Kế thừa có thể d n

ẫ đ n

ế nh ng

ữ l i

ỗ logic r t

ấ chi li, b i

ở b n

ạ có th

ể ch y

ạ mã l nh

ệ đư c

ợ k

ế th a

ừ mà không

nh n

ậ ra nó. Hãy xem m c

ụ “Lu ng

ồ th c

ự thi”

ở trên.

TÔI CÓ MỘT BI U

Ể TH C

Ứ L N

Ớ VÀ GAI GÓC MÀ CH N

Ẳ G HO T

Ạ Đ N

Ộ G THEO S MO

Ự

NG Đ I

Ợ .

Việc vi t

ế nh ng

ữ bi u

ể th c

ứ ph c

ứ t p

ạ cũng t t

ố mi n

ễ là chúng d

ễ đ c

ọ , nh ng

ư chúng có th

ể làm vi c

ệ g

ỡ l i

ỗ

g p

ặ khó khăn. Thông thư ng

ờ nên ch

ẻ nh

ỏ m t

ộ bi u

ể th c

ứ thành m t

ộ lo t

ạ các l nh

ệ gán cho nh ng

ữ bi n

ế

tạm thời.

Ch ng

ẳ h n:

ạ

rect.setLocation(rect.getLocation().translate( -rect.getWidth(),

-rect.getHeight()));

Có th

ể được vi t

ế l i

ạ thành

int dx = -rect.getWidth();

int dy = -rect.getHeight();

Point location = rect.getLocation();

Point newLocation = location.translate(dx, dy);

rect.setLocation(newLocation);

D ng

ạ mã l nh

ệ chi ti t

ế thì d

ễ đ c

ọ h n

ơ vì tên bi n

ế cho ta b n

ả thân đã giúp gi i

ả thích rõ thêm, và cũng d

ễ

gỡ lỗi hơn vì b n

ạ có th

ể ki m

ể tra ki u

ể c a

ủ nh ng

ữ bi n

ế trung gian cùng vi c

ệ hi n

ể th ịgiá tr ịc a

ủ chúng.

Một v n

ấ đ

ề khác có th

ể x y

ả ra v i

ớ nh ng

ữ bi u

ể th c

ứ l n

ớ là th

ứ t

ự th c

ự hi n

ệ phép tính có th

ể không nh

ư

b n

ạ mong muốn. Ch n

ẳ g h n,

ạ đ

ể lư ng

ợ giá bi u

ể th c

ứ x / 2π , có th

ể b n

ạ đã vi t

ế :

double y = x / 2 * Math.PI;

Đi u

ề này không đúng vì các phép nhân và chia có cùng th

ứ t

ự u

ư tiên và đư c

ợ lư ng

ợ giá t

ừ trái sang

ph i

ả . Vì v y

ậ bi u

ể th c

ứ này s

ẽ tính x π /

2

.

Một cách hay để g

ỡ lỗi bi u

ể th c

ứ là thêm vào nh ng

ữ c p

ặ ngo c

ặ đ n

ơ đ

ể giúp cho th

ứ t

ự lư ng

ợ giá đư c

ợ rõ

ràng:

double y = x / (2 * Math.PI);

Phiên b n

ả này thì đúng đ n,

ắ và d

ễ đ c

ọ h n

ơ đ i

ố v i

ớ ngư i

ờ không ghi nh

ớ th

ứ t

ự th c

ự hi n

ệ phép toán.

PHƯ N

Ơ G THỨC TÔI ĐÃ VI T

Ế KHÔNG TR L

Ả

I

Ạ GIÁ TR N

Ị H D

Ư

K

Ự I N

Ế .

Nếu b n

ạ vi t

ế một câu l nh

ệ return (tr

ả v )

ề v i

ớ m t

ộ bi u

ể th c

ứ ph c

ứ t p,

ạ thì b n

ạ đã không có c

ơ h i

ộ in ra

giá tr ịnày trư c

ớ khi tr

ả nó v .

ề M t

ộ l n

ầ n a

ữ , b n

ạ có th

ể dùng bi n

ế t m

ạ . Ch n

ẳ g h n,

ạ thay vì

public Rectangle intersection(Rectangle a, Rectangle b) {

return new Rectangle( Math.min(a.x, b.x), Math.min(a.y, b.y), Math.max(a.x+a.width, b.x+b.width)-Math.min(a.x, b.x) Math.max(a.y+a.height, b.y+b.height)-Math.min(a.y, b.y) );

}

b n

ạ đã có th

ể vi t

ế

public Rectangle intersection(Rectangle a, Rectangle b) {

int x1 = Math.min(a.x, b.x);

int y2 = Math.min(a.y, b.y);

int x2 = Math.max(a.x+a.width, b.x+b.width);

int y2 = Math.max(a.y+a.height, b.y+b.height);

Rectangle rect = new Rectangle(x1, y1, x2-x1, y2-y1);

return rect;

}

Giờ thì b n

ạ đã có c

ơ h i

ộ hi n

ể th ịb t

ấ kì bi n

ế trung gian nào trư c

ớ khi tr

ả v .

ề Và b ng

ằ cách dùng

l i

ạ x1 cùng y1, b n

ạ cũng làm mã l nh

ệ g n

ọ h n

ơ

CÂU L N

Ệ H PRINT MÀ TÔI VI T

Ế CH N

Ẳ G LÀM ĐƯ C

Ợ GÌ CẢ

Nếu b n

ạ dùng phư ng

ơ th c

ứ println, k t

ế qu

ả đ u

ầ ra sẽ hi n

ệ lên ngay; nh ng

ư n u

ế b n

ạ dùng print (ít nh t

ấ

là có nh ng

ữ môi trư ng

ờ phát tri n

ể nh

ư v y

ậ ), k t

ế qu

ả s

ẽ đư c

ợ l u

ư l i

ạ mà không hi n

ệ lên cho đ n

ế t n

ậ khi

có dấu xuống dòng ti p

ế theo. N u

ế chư ng

ơ trình k t

ế thúc mà không in ra m t

ộ dòng m i

ớ thì có th

ể b n

ạ

ch ng

ẳ còn nhìn th y

ấ đư c

ợ k t

ế qu

ả l u

ư l i

ạ n a

ữ .

Nếu b n

ạ nghi ng

ờ là đã có đi u

ề này x y

ả ra, hãy chuy n

ể m t

ộ s

ố ho c

ặ t t

ấ c

ả các l nh

ệ print trong chương

trình thành println.

THẬT S T

Ự ÔI RẤT, R T

Ấ VƯ N

Ớ G M C

Ắ VÀ C N

Ầ ĐƯ C

Ợ GIÚP Đ .

Ỡ

Trư c

ớ h t

ế , hãy th

ử r i

ờ kh i

ỏ máy tính trong vài phút. Máy tính phát ra sóng t

ừ gây nh

ả hư ng

ở đ n

ế não,

với các tri u

ệ ch ng

ứ sau:

• Cáu gi n.

ậ

• Tin tưởng vào l c

ự siêu nhiên (“máy tính này ghét tôi”) và nh ng

ữ o

ả tư ng

ở (“chư ng

ơ trình ch ỉch y

ạ khi tôi

đội ngược mũ”).

• L p

ậ trình bước ngẫu nhiên (n

ỗ l c

ự l p

ậ trình b ng

ằ cách vi t

ế t t

ấ c

ả các trư ng

ờ h p

ợ chư ng

ơ trình có th

ể có

và chọn ra một phiên b n

ả ho t

ạ đ ng

ộ đúng).

Nếu b n

ạ tự th y

ấ mình m c

ắ ph i

ả m t

ộ trong s

ố các tri u

ệ ch ng

ứ trên, hãy đ ng

ứ d y

ậ và đi d o

ạ . Khi đã tĩnh

tâm h n

ẳ , hãy nghĩ l i

ạ chư ng

ơ trình. Nó đang làm đi u

ề gì? Đâu là các nguyên nhân gây ra bi u

ể hi n

ệ đó?

L n

ầ cuối cùng chư ng

ơ trình c n

ọ ch y

ạ đư c

ợ là lúc nào, và sau đó b n

ạ th c

ự hi n

ệ nh ng

ữ đi u

ề gì?

Đôi khi phát hi n

ệ l i

ỗ ch ỉlà v n

ấ đ

ề th i

ờ gian. Tôi thư ng

ờ tìm th y

ấ l i

ỗ trong lúc r i

ờ xa kh i

ỏ máy tính và để

trí óc khuây kh a

ỏ . M t

ộ s

ố n i

ơ t t

ố nh t

ấ đ

ể thoát kh i

ỏ máy g m

ồ có trên tàu, khi đi t m

ắ , và trư c

ớ khi đi

ng .

ủ

KHÔNG, TÔI TH T

Ậ S M

Ự U N

Ố GIÚP Đ .

Ỡ

Đi u

ề đó x y

ả ra. Ngay c

ả nh ng

ữ l p

ậ trình viên gi i

ỏ nh t

ấ đôi lúc cũng b ịbí. Đôi khi b n

ạ làm m t

ộ chư ng

ơ

trình lâu quá đ n

ế n i

ỗ không th

ể phát hi n

ệ ra l i

ỗ . Tìm m t

ộ ngư i

ờ có góc nhìn khác chính là đi u

ề c n

ầ

thiết.

Trư c

ớ khi yêu c u

ầ giúp đ ,

ỡ b n

ạ hãy chu n

ẩ b ịkĩ. Chư ng

ơ trình ph i

ả càng đ n

ơ gi n

ả càng t t

ố , và hãy phân

tích trên d

ữ li u

ệ đ u

ầ vào nh

ỏ nh t

ấ có th

ể gây l i

ỗ . B n

ạ c n

ầ có các l nh

ệ print ở những vị trí thích h p

ợ (và

kết quả đầu ra ph i

ả dễ hi u

ể ). B n

ạ c n

ầ hi u

ể rõ v n

ấ đ

ề đ

ể có th

ể di n

ễ đ t

ạ nó m t

ộ cách ng n

ắ g n.

ọ

Khi đưa ngư i

ờ đ n

ế giúp, hãy ch c

ắ ch n

ắ r n

ằ g b n

ạ cung c p

ấ đ

ủ thông tin mà h

ọ c n:

ầ

• Nếu có thông báo l i

ỗ , thông báo đó là gì và nó ch ỉđ nh

ị ph n

ầ nào trong chư ng

ơ trình?

• Việc cu i

ố cùng mà b n

ạ thao tác trư c

ớ khi l i

ỗ này x y

ả ra là gì? Nh ng

ữ dòng l nh

ệ nào b n

ạ v a

ừ m i

ớ vi t

ế

g n

ầ đây nh t

ấ , hay trư ng

ờ h p

ợ ch y

ạ th

ử g n

ầ đây nh t

ấ m i

ớ b ịth t

ấ b i

ạ là gì?

• B n

ạ đã th

ử nh ng

ữ bi n

ệ pháp gì r i

ồ , và thu ho c

ạ h đư c

ợ gì?

Đến khi b n

ạ gi i

ả thích đư c

ợ khúc m c

ắ cho ngư i

ờ ta, có th

ể b n

ạ s

ẽ th y

ấ k t

ế qu .

ả Hi n

ệ tư ng

ợ này thư ng

ờ

g p

ặ đ n

ế n i

ỗ ngư i

ờ ta g i

ợ ý m t

ộ kĩ thu t

ậ g

ỡ l i

ỗ có tên “v tị cao su.” Sau đây là cách ho t

ạ đ ng

ộ :

1. Mua một con v tị cao su chu n

ẩ .

2. Khi b n

ạ th c

ự s

ự đã vư ng

ớ m c

ắ trong l p

ậ trình, hãy đ t

ặ con v tị cao su trư c

ớ m t

ặ r i

ồ nói, “V tị i

ơ , tao đang

vướng m c

ắ đây. Hoàn c nh

ả là nh

ư th

ế này…”

3. Trình bày v n

ấ đ

ề cho con v tị.

4. Tìm th y

ấ hư ng

ớ gi i

ả quy t

ế .

5. Cám ơn con v tị cao su.

Tôi không h

ề nói đùa. Hãy xem http://en.wikipedia.org/wiki/Rubber_duck_debugging.

TÔI ĐÃ TÌM THẤY LỖI RỒI!

Khi b n

ạ tìm th y

ấ l i

ỗ , thông thư ng

ờ cách s a

ử s

ẽ là hi n

ể nhiên. Nh ng

ư không ph i

ả luôn luôn nh

ư v y

ậ . Đôi

khi cái mà có v

ẻ nh

ư l i

ỗ l i

ạ là m t

ộ d u

ấ hi u

ệ cho th y

ấ b n

ạ ch a

ư hi u

ể chư ng

ơ trình vi t

ế ra, ho c

ặ là có m t

ộ

lỗi trong thuật toán b n

ạ dùng. V i

ớ nh ng

ữ trư ng

ờ h p

ợ này, b n

ạ có th

ể s

ẽ ph i

ả nghĩ l i

ạ thu t

ậ toán, hay

ch nh

ỉ l i

ạ mô hình nh n

ậ th c

ứ c a

ủ mình. Hãy dành th i

ờ gian r i

ờ xa máy tính, đ

ể suy nghĩ, t

ự tính tay các

phép thử, ho c

ặ v

ẽ s

ơ đ

ồ bi u

ể di n

ễ bài toán.

Sau khi s a

ử xong l i

ỗ , b n

ạ đ ng

ừ chuy n

ể sang l i

ỗ m i

ớ . Hãy nghĩ một lát xem v a

ừ r i

ồ là lo i

ạ l i

ỗ gì, t i

ạ sao

b n

ạ m c

ắ ph i

ả lỗi này, làm th

ế nào mà l i

ỗ đã l

ộ di n,

ệ và đáng ra b n

ạ có th

ể tìm l i

ỗ này nhanh h n

ơ b ng

ằ

cách nào. L n

ầ sau khi b n

ạ th y

ấ đi u

ề tư ng

ơ t ,

ự có th

ể b n

ạ s

ẽ chóng phát hi n

ệ ra l i

ỗ h n.

ơ

Document Outline

- Think Java: Cách suy nghĩ như nhà khoa học máy tính

- Phiên bản 5.1.2

- Mục lục

- Chương 0. Lời nói đầu

- Lý do mà tôi viết cuốn sách này

- Triết lý ẩn sau cuốn sách

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

- Kì thi Computer Science AP

- Sách phát hành tự do

- À, còn về tiêu đề

- Danh sách bạn đọc đã đóng góp nội dung

- Chương 1: Lối đi của chương trình máy tính

- 1.1 Ngôn ngữ lập trình là gì?

- 1.2 Chương trình là gì?

- 1.3 Gỡ lỗi là gì?

- 1.3.1 LỖI CÚ PHÁP

- 1.3.2 LỖI THỰC THI

- 1.3.3 LỖI LOGIC VÀ NGỮ NGHĨA

- 1.3.4 GỠ LỖI THỬ NGHIỆM

- 1.4 Ngôn ngữ hình thức và ngôn ngữ tự nhiên

- 1.5 Chương trình đầu tiên

- 1.6 Thuật ngữ

- 1.7 Bài tập

- BÀI TẬP 1

- BÀI TẬP 2

- BÀI TẬP 3

- Chương 2: Biến và kiểu

- 2.1 Nói thêm về lệnh in

- 2.2 Biến

- 2.3 Lệnh gán

- 2.4 In các biến

- 2.5 Từ khoá

- 2.6 Toán tử

- 2.7 Thứ tự thực hiện

- 2.8 Các thao tác với chuỗi

- 2.9 Kết hợp

- 2.10 Thuật ngữ

- 2.11 Bài tập

- BÀI TẬP 1

- BÀI TẬP 2

- BÀI TẬP 3

- Chương 3: Phương thức rỗng

- 3.1 Dấu phẩy động

- 3.2 Chuyển đổi từ double sang int

- 3.3 Các phương thức Math

- 3.4 Kết hợp

- 3.5 Bổ sung những phương thức mới

- 3.6 Lớp và phương thức

- 3.7 Chương trình có nhiều phương thức

- 3.8 Tham số và đối số

- 3.9 Biểu đồ ngăn xếp

- 3.10 Phương thức có nhiều tham số

- 3.11 Các phương thức trả lại kết quả

- 3.12 Thuật ngữ

- 3.13 Bài tập

- BÀI TẬP 1

- BÀI TẬP 2

- BÀI TẬP 3

- BÀI TẬP 4

- Chương 4: Câu lệnh điều kiện và đệ quy Java

- 4.1 Toán tử chia dư

- 4.2 Thực hiện lệnh theo điều kiện

- 4.3 Thực hiện chọn lựa

- 4.4 Các điều kiện xâu chuỗi

- 4.5 Các điều kiện lồng ghép

- 4.6 Câu lệnh return

- 4.7 Chuyển đổi kiểu

- 4.8 Đệ quy

- 4.9 Biểu đồ ngăn xếp cho các phương thức đệ quy

- 4.10 Thuật ngữ

- 4.11 Bài tập

- Chương 5: Grid World, phần 1

- 5.1 Khởi động

- 5.2 BugRunner

- 5.3 Bài tập

- Chương 6: Phương thức trả lại giá trị

- 6.1 Những giá trị được trả lại

- 6.2 Phát triển chương trình

- 6.3 Kết hợp phương thức

- 6.4 Quá tải toán tử

- 6.5 Biểu thức logic

- 6.6 Toán tử logic

- 6.7 Phương thức logic

- 6.8 Nói thêm về đệ quy

- 6.9 Niềm tin

- 6.10 Thêm một ví dụ

- 6.11 Thuật ngữ

- 6.12 Bài tập

- Chương 7: Phép lặp và vòng lặp

- 7.1 Phép gán nhiều lần

- 7.2 Câu lệnh while

- 7.3 Bảng số liệu

- 7.4 Bảng hai chiều

- 7.5 Bao bọc và khái quát hóa

- 7.6 Phương thức và bao bọc

- 7.7 Các biến địa phương

- 7.8 Nói thêm về khái quát hóa

- 7.9 Thuật ngữ

- 7.10 Bài tập

- Chương 8: Chuỗi kí tự

- 8.1 Kí tự

- 8.2 Length

- 8.3 Duyệt chuỗi

- 8.4 Lỗi thực thi

- 8.5 Đọc tài liệu

- 8.6 Phương thức indexOf

- 8.7 Lặp quay vòng và đếm

- 8.8 Các toán tử tăng và giảm

- 8.9 String có tính không đổi

- 8.10 String có tính không so sánh được

- 8.11 Thuật ngữ

- 8.12 Bài tập

- Chương 9: Đối tượng có thể biến đổi

- 9.1 Các gói chương trình

- 9.2 Đối tượng Point

- 9.3 Các biến thực thể

- 9.4 Đối tượng trong vai trò của tham số

- 9.5 Hình chữ nhật

- 9.6 Đối tượng với vai trò là kiểu được trả lại

- 9.7 Đối tượng có tính thay đổi

- 9.8 Aliasing

- 9.9 null

- 9.10 Thu dọn rác

- 9.11 Các đối tượng và kiểu nguyên thủy

- 9.12 Thuật ngữ

- 9.13 Bài tập

- Chương 10: Grid World, phần 2

- 10.1 Con mối

- 10.2 Con mối của Langton

- 10.3 Bài tập

- Chương 11: Tự tạo nên những đối tượng riêng

- 11.1 Lời định nghĩa lớp và các kiểu đối tượng

- 11.2 Time

- 11.3 Constructor

- 11.4 Thêm các constructor

- 11.5 Tạo nên đối tượng mới

- 11.6 In các đối tượng

- 11.7 Các thao tác với đối tượng

- 11.8 Các hàm thuần túy

- 11.9 Phương thức sửa đổi

- 11.10 Các phương thức điền

- 11.11 Lập kế hoạch và phát triển tăng dần

- 11.12 Khái quát hóa

- 11.13 Thuật toán

- 11.14 Thuật ngữ

- 11.15 Bài tập

- Chương 12: Mảng

- 12.1 Truy cập các phần tử

- 12.2 Sao chép mảng

- 12.3 Mảng và đối tượng

- 12.4 Vòng lặp for

- 12.5 Chiều dài của mảng

- 12.6 Số ngẫu nhiên

- 12.7 Mảng các số ngẫu nhiên

- 12.8 Đếm

- 12.9 Histogram

- 12.10 Lời giải “một lượt”

- 12.11 Thuật ngữ

- 12.12 Bài tập

- Chương 13: Mảng chứa các đối tượng

- 13.1 Con đường phía trước

- 13.2 Các đối tượng Card

- 13.3 Phương thức printCard

- 13.4 Phương thức sameCard

- 13.5 Phương thức compareCard

- 13.6 Mảng các lá bài

- 13.7 Phương thức printDeck

- 13.8 Tìm kiếm

- 13.9 Cỗ bài và cỗ bài con

- 13.10 Thuật ngữ

- 13.11 Bài tập

- Chương 14: Đối tượng chứa các mảng

- 14.1 Lớp Deck

- 14.2 Tráo bài

- 14.3 Sắp xếp

- 14.4 Cỗ bài con

- 14.5 Tráo bài và chia bài

- 14.6 Sắp xếp trộn

- 14.7 Biến lớp

- 14.8 Thuật ngữ

- 14.9 Bài tập

- Chương 15: Lập trình hướng đối tượng

- 15.1 Các ngôn ngữ và phong cách lập trình

- 15.2 Các phương thức đối tượng và phương thức lớp

- 15.3 Phương thức toString

- 15.4 Phương thức equals

- 15.5 Những điều kì quặc và lỗi sai

- 15.6 Thừa kế

- 15.7 Cấu trúc thừa kế lớp

- 15.8 Thiết kế hướng đối tượng

- 15.9 Thuật ngữ

- 15.10 Bài tập

- Chương 16: GridWorld, phần 3

- 16.1 ArrayList

- 16.2 Giao diện

- 16.3 public và private

- 16.4 Trò chơi Life

- 16.5 LifeRunner

- 16.6 LifeRock

- 16.7 Cập nhật đồng thời

- 16.8 Điều kiện đầu

- 16.9 Bài tập

- Phụ lục A: Đồ họa

- A.1 Đồ họa Java 2 chiều

- A.2 Các phương thức Graphics

- A.3 Hệ tọa độ

- A.4 Màu sắc

- A.5 Chuột Mickey

- A.6 Thuật ngữ

- A.7 Bài tập

- Phụ lục B: Đầu vào và đầu ra trong Java

- B.1 Đối tượng System

- B.2 Đầu vào từ bàn phím

- B.3 Đầu vào từ file

- B.4 Bắt biệt lệ

- Phụ lục C: Phát triển chương trình

- C.1 Các chiến lược

- C.2 Các hình thức thất bại

- Phụ lục D: Gỡ lỗi

- D.1 Lỗi cú pháp

- TRÌNH BIÊN DỊCH BÀY RA LA LIỆT NHỮNG THÔNG BÁO LỖI.

- TÔI ĐANG GẶP MỘT LỖI BIÊN DỊCH THẬT KÌ QUẶC VÀ NÓ CHẲNG BIẾN ĐI.

- TÔI KHÔNG THỂ BIÊN DỊCH ĐƯỢC CHƯƠNG TRÌNH DÙ ĐÃ CỐ GẮNG MỌI CÁCH.

- TÔI ĐÃ LÀM THEO CHỈ DẪN CỦA TRÌNH BIÊN DỊCH MÀ VẪN CHƯA CÓ TÁC DỤNG.

- D.2 Lỗi thực thi

- CHƯƠNG TRÌNH TÔI VIẾT BỊ TREO.

- VÒNG LẶP VÔ HẠN

- ĐỆ QUY VÔ HẠN

- LUỒNG THỰC THI

- KHI CHẠY CHƯƠNG TRÌNH TÔI NHẬN ĐƯỢC MỘT BIỆT LỆ.

- TÔI ĐÃ THÊM VÀO QUÁ NHIỀU LỆNH PRINT ĐẾN NỖI BÂY GIỜ NGẬP TRÀN KẾT QUẢ ĐẦU RA.

- D.3 Lỗi logic

- CHƯƠNG TRÌNH TÔI VIẾT RA KHÔNG HOẠT ĐỘNG ĐÚNG.

- TÔI CÓ MỘT BIỂU THỨC LỚN VÀ GAI GÓC MÀ CHẲNG HOẠT ĐỘNG THEO SỰ MONG ĐỢI.

- PHƯƠNG THỨC TÔI ĐÃ VIẾT KHÔNG TRẢ LẠI GIÁ TRỊ NHƯ DỰ KIẾN.

- CÂU LỆNH PRINT MÀ TÔI VIẾT CHẲNG LÀM ĐƯỢC GÌ CẢ

- THẬT SỰ TÔI RẤT, RẤT VƯỚNG MẮC VÀ CẦN ĐƯỢC GIÚP ĐỠ.

- KHÔNG, TÔI THẬT SỰ MUỐN GIÚP ĐỠ.

- TÔI ĐÃ TÌM THẤY LỖI RỒI!

Table of Contents

Think Java: Cách suy nghĩ như nhà khoa học máy tính

Phiên bản 5.1.2

Mục lục

Chương 0. Lời nói đầu

Lý do mà tôi viết cuốn sách này

Triết lý ẩn sau cuốn sách

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

Kì thi Computer Science AP

Sách phát hành tự do

À, còn về tiêu đề

Danh sách bạn đọc đã đóng góp nội dung

Chương 1: Lối đi của chương trình máy tính

1.1 Ngôn ngữ lập trình là gì?

1.2 Chương trình là gì?

1.3 Gỡ lỗi là gì?

1.3.1 LỖI CÚ PHÁP

1.3.2 LỖI THỰC THI

1.3.3 LỖI LOGIC VÀ NGỮ NGHĨA

1.3.4 GỠ LỖI THỬ NGHIỆM

1.4 Ngôn ngữ hình thức và ngôn ngữ tự nhiên

1.5 Chương trình đầu tiên

1.6 Thuật ngữ

1.7 Bài tập

BÀI TẬP 1

BÀI TẬP 2

BÀI TẬP 3

Chương 2: Biến và kiểu

2.1 Nói thêm về lệnh in

2.2 Biến

2.3 Lệnh gán

2.4 In các biến

2.5 Từ khoá

2.6 Toán tử

2.7 Thứ tự thực hiện

2.8 Các thao tác với chuỗi

2.9 Kết hợp

2.10 Thuật ngữ

2.11 Bài tập

BÀI TẬP 1

BÀI TẬP 2

BÀI TẬP 3

Chương 3: Phương thức rỗng

3.1 Dấu phẩy động

3.2 Chuyển đổi từ double sang int

3.3 Các phương thức Math

3.4 Kết hợp

3.5 Bổ sung những phương thức mới

3.6 Lớp và phương thức

3.7 Chương trình có nhiều phương thức

3.8 Tham số và đối số

3.9 Biểu đồ ngăn xếp

3.10 Phương thức có nhiều tham số

3.11 Các phương thức trả lại kết quả

3.12 Thuật ngữ

3.13 Bài tập

BÀI TẬP 1

BÀI TẬP 2

BÀI TẬP 3

BÀI TẬP 4

Chương 4: Câu lệnh điều kiện và đệ quy Java

4.1 Toán tử chia dư

4.2 Thực hiện lệnh theo điều kiện

4.3 Thực hiện chọn lựa

4.4 Các điều kiện xâu chuỗi

4.5 Các điều kiện lồng ghép

4.6 Câu lệnh return

4.7 Chuyển đổi kiểu

4.8 Đệ quy

4.9 Biểu đồ ngăn xếp cho các phương thức đệ quy

4.10 Thuật ngữ

4.11 Bài tập

Chương 5: Grid World, phần 1

5.1 Khởi động

5.2 BugRunner

5.3 Bài tập

Chương 6: Phương thức trả lại giá trị

6.1 Những giá trị được trả lại

6.2 Phát triển chương trình

6.3 Kết hợp phương thức

6.4 Quá tải toán tử

6.5 Biểu thức logic

6.6 Toán tử logic

6.7 Phương thức logic

6.8 Nói thêm về đệ quy

6.9 Niềm tin

6.10 Thêm một ví dụ

6.11 Thuật ngữ

6.12 Bài tập

Chương 7: Phép lặp và vòng lặp

7.1 Phép gán nhiều lần

7.2 Câu lệnh while

7.3 Bảng số liệu

7.4 Bảng hai chiều

7.5 Bao bọc và khái quát hóa

7.6 Phương thức và bao bọc

7.7 Các biến địa phương

7.8 Nói thêm về khái quát hóa

7.9 Thuật ngữ

7.10 Bài tập

Chương 8: Chuỗi kí tự

8.1 Kí tự

8.2 Length

8.3 Duyệt chuỗi

8.4 Lỗi thực thi

8.5 Đọc tài liệu

8.6 Phương thức indexOf

8.7 Lặp quay vòng và đếm

8.8 Các toán tử tăng và giảm

8.9 String có tính không đổi

8.10 String có tính không so sánh được

8.11 Thuật ngữ

8.12 Bài tập

Chương 9: Đối tượng có thể biến đổi

9.1 Các gói chương trình

9.2 Đối tượng Point

9.3 Các biến thực thể

9.4 Đối tượng trong vai trò của tham số

9.5 Hình chữ nhật

9.6 Đối tượng với vai trò là kiểu được trả lại

9.7 Đối tượng có tính thay đổi

9.8 Aliasing

9.9 null

9.10 Thu dọn rác

9.11 Các đối tượng và kiểu nguyên thủy

9.12 Thuật ngữ

9.13 Bài tập

Chương 10: Grid World, phần 2

10.1 Con mối

10.2 Con mối của Langton

10.3 Bài tập

Chương 11: Tự tạo nên những đối tượng riêng

11.1 Lời định nghĩa lớp và các kiểu đối tượng

11.2 Time

11.3 Constructor

11.4 Thêm các constructor

11.5 Tạo nên đối tượng mới

11.6 In các đối tượng

11.7 Các thao tác với đối tượng

11.8 Các hàm thuần túy

11.9 Phương thức sửa đổi

11.10 Các phương thức điền

11.11 Lập kế hoạch và phát triển tăng dần

11.12 Khái quát hóa

11.13 Thuật toán

11.14 Thuật ngữ

11.15 Bài tập

Chương 12: Mảng

12.1 Truy cập các phần tử

12.2 Sao chép mảng

12.3 Mảng và đối tượng

12.4 Vòng lặp for

12.5 Chiều dài của mảng

12.6 Số ngẫu nhiên

12.7 Mảng các số ngẫu nhiên

12.8 Đếm

12.9 Histogram

12.10 Lời giải “một lượt”

12.11 Thuật ngữ

12.12 Bài tập

Chương 13: Mảng chứa các đối tượng

13.1 Con đường phía trước

13.2 Các đối tượng Card

13.3 Phương thức printCard

13.4 Phương thức sameCard

13.5 Phương thức compareCard

13.6 Mảng các lá bài

13.7 Phương thức printDeck

13.8 Tìm kiếm

13.9 Cỗ bài và cỗ bài con

13.10 Thuật ngữ

13.11 Bài tập

Chương 14: Đối tượng chứa các mảng

14.1 Lớp Deck

14.2 Tráo bài

14.3 Sắp xếp

14.4 Cỗ bài con

14.5 Tráo bài và chia bài

14.6 Sắp xếp trộn

14.7 Biến lớp

14.8 Thuật ngữ

14.9 Bài tập

Chương 15: Lập trình hướng đối tượng

15.1 Các ngôn ngữ và phong cách lập trình

15.2 Các phương thức đối tượng và phương thức lớp

15.3 Phương thức toString

15.4 Phương thức equals

15.5 Những điều kì quặc và lỗi sai

15.6 Thừa kế

15.7 Cấu trúc thừa kế lớp

15.8 Thiết kế hướng đối tượng

15.9 Thuật ngữ

15.10 Bài tập

Chương 16: GridWorld, phần 3

16.1 ArrayList

16.2 Giao diện

16.3 public và private

16.4 Trò chơi Life

16.5 LifeRunner

16.6 LifeRock

16.7 Cập nhật đồng thời

16.8 Điều kiện đầu

16.9 Bài tập

Phụ lục A: Đồ họa

A.1 Đồ họa Java 2 chiều

A.2 Các phương thức Graphics

A.3 Hệ tọa độ

A.4 Màu sắc

A.5 Chuột Mickey

A.6 Thuật ngữ

A.7 Bài tập

Phụ lục B: Đầu vào và đầu ra trong Java

B.1 Đối tượng System

B.2 Đầu vào từ bàn phím

B.3 Đầu vào từ file

B.4 Bắt biệt lệ

Phụ lục C: Phát triển chương trình

C.1 Các chiến lược

C.2 Các hình thức thất bại

Phụ lục D: Gỡ lỗi

D.1 Lỗi cú pháp

TRÌNH BIÊN DỊCH BÀY RA LA LIỆT NHỮNG THÔNG BÁO LỖI.

TÔI ĐANG GẶP MỘT LỖI BIÊN DỊCH THẬT KÌ QUẶC VÀ NÓ CHẲNG BIẾN ĐI.

TÔI KHÔNG THỂ BIÊN DỊCH ĐƯỢC CHƯƠNG TRÌNH DÙ ĐÃ CỐ GẮNG MỌI CÁCH.

TÔI ĐÃ LÀM THEO CHỈ DẪN CỦA TRÌNH BIÊN DỊCH MÀ VẪN CHƯA CÓ TÁC DỤNG.

D.2 Lỗi thực thi

CHƯƠNG TRÌNH TÔI VIẾT BỊ TREO.

VÒNG LẶP VÔ HẠN

ĐỆ QUY VÔ HẠN

LUỒNG THỰC THI

KHI CHẠY CHƯƠNG TRÌNH TÔI NHẬN ĐƯỢC MỘT BIỆT LỆ.

TÔI ĐÃ THÊM VÀO QUÁ NHIỀU LỆNH PRINT ĐẾN NỖI BÂY GIỜ NGẬP TRÀN KẾT QUẢ ĐẦU RA.

D.3 Lỗi logic

CHƯƠNG TRÌNH TÔI VIẾT RA KHÔNG HOẠT ĐỘNG ĐÚNG.

TÔI CÓ MỘT BIỂU THỨC LỚN VÀ GAI GÓC MÀ CHẲNG HOẠT ĐỘNG THEO SỰ MONG ĐỢI.

PHƯƠNG THỨC TÔI ĐÃ VIẾT KHÔNG TRẢ LẠI GIÁ TRỊ NHƯ DỰ KIẾN.

CÂU LỆNH PRINT MÀ TÔI VIẾT CHẲNG LÀM ĐƯỢC GÌ CẢ

THẬT SỰ TÔI RẤT, RẤT VƯỚNG MẮC VÀ CẦN ĐƯỢC GIÚP ĐỠ.

KHÔNG, TÔI THẬT SỰ MUỐN GIÚP ĐỠ.

TÔI ĐÃ TÌM THẤY LỖI RỒI!