Nếu có bất kỳ nội dung nào liên quan còn thiếu,hãy tạo issues cho nó, tôi sẽ theo dõi và cải thiện。
MIT License
Copyright (c) 2023 QuocHung
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Java được biết đến là ngôn ngữ lập trình bậc cao, hướng đối tượng và giúp bảo mật mạnh mẽ, và còn được định nghĩa là một Platform. Java được phát triển bởi Sun Microsystems, do James Gosling khởi xướng và ra mắt năm 1995. Java vẫn được sử dụng rất nhiều trong các dự án công nghệ mới. Tên ban đầu của Java là OAK, sau đó được Sun Microsystem đổi tên vào năm 1995 và tập trung phát triển các sản phẩm theo trend www (world wide web). Năm 2009, Java được mua lại bởi Oracle.
Các nguyên tắc thiết kế hướng đối tượng – SOLID
SOLID nghĩa là gì
Nguyên tắc SOLID là một phương pháp tiếp cận hướng đối tượng trong thiết kế cấu trúc phần mềm được sử dụng trong Java. Robert C. Martin là người đã đưa ra ý tưởng này (còn được biết đến với tên Uncle Bob). Năm nguyên tắc này đã làm thay đổi toàn bộ lĩnh vực lập trình hướng đối tượng, cũng như cách các phần mềm được viết ra. Nguyên tắc SOLID cũng đảm bảo rằng phần mềm có tính chất mô-đun (dễ tái sử dụng và dùng trong nhiều vị trí), dễ hiểu, dễ gỡ lỗi và dễ refactor (tái cấu trúc, cập nhật).
S: Single responsibility principle – Nguyên tắc một chức năng
O: Open-closed principle – Nguyên tắc đóng và mở
L: Liskov substitution principle – Nguyên tắc thay thế
I: Interface segregation principle – Nguyên tắc chia nhỏ
D: Dependency inversion principle – Nguyên tắc đảo ngược phụ thuộc
Lí do nên áp dụng các nguyên tắc SOLID
Clean: Nguyên tắc SOLID giúp code clean, dễ nhìn hơn và chuẩn hoá format của code để nhiều người hiểu hơn.
Dễ bảo trì: Code dễ bảo trì, sửa lỗi hơn.
Tính co giãn: Dễ dàng refactor, tái cấu trúc lại code. Dễ dàng phát triển các tính năng mới sau này
Tối ưu: Giảm bớt các code dư thừa.
Kiểm nghiệm: Viết unit test dễ hơn
Dễ đọc: Giúp code đọc dễ hiểu hơn
Độc lập: Code hoạt động độc lập, ít phụ thuộc các phần khác, giảm thiểu lỗi
Tái sử dụng: Code được chia nhỏ và độc lập như các module, dễ dàng sử dụng lại.
SOLID trong Java
Nguyên tắc 1: Single responsibility principle – Nguyên tắc một chức năng
Nguyên tắc này được phát biểu như sau:
Một class chỉ nên giữ 1 trách nhiệm duy nhất, chỉ có thể sửa đổi class với 1 lý do duy nhất.
A class should have one and only one reason to change, meaning that a class should have only one job.
Theo nguyên lí này, mỗi class chỉ nên có một vai trò duy nhất. Tức là bạn có thể để 1 class có rất nhiều chức năng, làm đủ thứ, với nhiều method khác nhau. Tuy nhiên việc nhét toàn bộ chức năng vào 1 class khiến code khó bảo trì, khó hiểu hơn, và xử lí một phần nhỏ của cả một class chứa rất nhiều chức năng này có thể làm lỗi toàn bộ các chức năng khác.
Hãy thử xem một class sau:
Việc cho toàn bộ các phương thức gộp vào 1 class NguoiChoi như này đã vi phạm quy tắc, thực hiện rất nhiều thay đổi chỉ trong 1 class như lấy dữ liệu từ database, chuyển sang json để trả về, di chuyển nhân vật, …. Sau này khi nâng cấp thêm chức năng, class này ngày càng phình to ra. Khiến cho việc bảo trì, nâng cấp, test, …. trở lên khó khăn hơn sau này.
Thay vì vậy, ta có thể chuyển thành như sau
Lúc này mỗi class sẽ độc lập hơn và các luồng hoạt động cũng sẽ rõ ràng hơn, khi có lỗi xảy ra hay cần nâng cấp chức năng, bạn có thể dễ dàng sửa đổi vào các class trong 1 luồng chứ không phải thay đổi hay thêm mọi thứ vào 1 class và khiến chúng phình to hơn nữa.
Tuy số lượng class nhiều hơn những việc sửa chữa sẽ đơn giản hơn, dễ dàng tái sử dụng hơn, class ngắn hơn nên cũng ít bug hơn.
Một số ví dụ về nguyên tắc SRP cần xem xét có thể cần được tách riêng bao gồm: Persistence, Validation, Notification, Error Handling, Logging, Class Instantiation, Formatting, Parsing, Mapping, …
Nguyên tắc 2: Open-closed principle – Nguyên tắc đóng và mở
Nguyên tắc này được phát biểu như sau:
Có thể thoải mái mở rộng 1 class, nhưng không được sửa đổi bên trong class đó.
Objects or entities should be open for extension, but closed for modification.
Nghe qua thấy nguyên lý có sự mâu thuẫn do thường chúng ta thấy rằng dễ mở rộng là phải dễ thay đổi, đằng nay dễ mở rộng nhưng không cho thay đổi. Thực sự theo nguyên lý này, chúng ta không được thay đổi hiện trạng của các lớp có sẵn, nếu muốn thêm tính năng mới, thì hãy mở rộng class cũ bằng cách kế thừa để xây dựng class mới. Làm như vậy sẽ tránh được các tình huống làm hỏng tính ổn định của chương trình đang có.
Theo nguyên tắc này, sau khi thiết kế một class với một số chức năng nhất định, cần đảm bảo các chức năng này hoạt động trơn tru trong tương lai, tránh sửa đổi thêm sau này. Như vậy, class luôn “đóng – closed” cho các sửa đổi vào các chức năng đã được thiết kế trước, nhưng lại phải “mở – open” để mở rộng tính năng hơn, để mở thì có 1 số cách phổ biến như:
Tạo ra một class kế thừa
Viết lại chức năng hàm đó từ class cha
Nâng cấp chức năng/hàm của class cha ở class con
Lấy ví dụ như sau:
Với cách thiết kế như trên, khi ta có các class con kế thừa từ class cha NguoiChoi, và cần kiểm tra xem class con có hệ là gì, hay ví dụ ta cần tạo thêm nhiều class con khác tương tự, ta lại phải thêm nhiều if else vào class gốc. Thay vào đó, ta nên thiết kế như sau:
Lúc này, khi cần nâng cấp thêm nhiều hệ mới cho hệ thống, ta chỉ cần tạo các class con và sử dụng chức năng của class chính, không cần thực hiện trực tiếp vào class chính nữa.
Lợi ích của nguyên lý này là đôi khi chúng ta cần sử dụng các class từ các nguồn thư viện thứ 3, hoặc từ chính các thư viện có sẵn trong Java. Chúng ta có thể dễ dàng extend và tạo các class con mới kế thừa từ class cha để phục vụ cho một mục đích, chức năng mới của dự án, mà không cần quá lo lắng về class cha sẽ bị lỗi do ta đã không sửa đổi chúng.
Tuy nhiên, việc kế thừa class cha có thể dẫn tới việc chức năng các class con lại quá khác nhau và không có chung ý nghĩa, nên chú ý vào ý nghĩa của các chức năng, tránh tạo ra quá nhiều class dẫn xuất. Mặc dù những sửa đổi nhỏ trong class thường không ảnh hưởng, chúng ta cũng cần phải test cẩn thận. Và đó là lý do chính tại sao chúng ta cần phải viết test case cho các chức năng, để có thể nhận thấy hành vi không mong muốn xảy ra trong code.
Lúc này, ta có thể sử dụng interface như các bản thiết kế cha để có thể làm các chức năng mở rộng sau này, việc sử dụng interface cũng giúp code đạt thêm tính “Loose coupling” – “liên kết lỏng” hơn và tránh sự phụ thuộc quá chặt chẽ vào các class.
Nguyên tắc 3: Liskov substitution principle – Nguyên tắc thay thế
Barbara Liskov đã đưa ra nguyên tắc Liskov Substitution Principle (LSP) này. Nguyên tắc này cho rằng: trong kế thừa, các class con, class kế thừa phải luôn có thể thay thế được class cha. Tức là, nếu class A kế thừa từ class B, thì mình luôn có thể sử dụng class A thay cho class B mà các chức năng không bị thay đổi.
Lấy ví dụ về hình vuông và hình chữ nhật
Như trong toán học được dạy ở các cấp dưới, ta hay được nghe là “hình vuông cũng là hình chữ nhật”, Nhìn ví dụ trên ta thấy mọi tính toán đều rất hợp lý. Do hình vuông có 2 cạnh bằng nhau, mỗi khi set độ dài 1 cạnh thì ta set luôn độ dài của cạnh còn lại bằng cách viết đè phương thức set chiều cao và set chiều rộng.
Tuy nhiên, class HinhVuong sau khi kế thừa class HinhChuNhat đã làm thay đổi các đặc tính vốn có của HinhChuNhat, dẫn đến vi phạm LSP. Thử với một ví dụ như sau
Rõ ràng, lúc này ta khai báo một object class HinhChuNhat theo HinhVuong, set chiều cao và chiều rộng, nhưng do ta đã ghi đè hàm set chiều cao chiều rộng nên chiều cao chiều rộng bị cập nhật thành 10, và tính diện tích ra là 10×10 = 100, rõ ràng không đúng vì hình chữ nhật đúng ra diện tích là 5×10 = 50, hay có thể nói là: Class HinhVuong không thể dùng thay thế cho class HinhChuNhat
Những vi phạm về nguyên lý LSP
Các lớp dẫn xuất có các phương thức ghi đè phương thức của lớp cha nhưng với chức năng hoàn toàn khác.
Các lớp dẫn xuất có phương thức ghi đè phương thức của lớp cha là một phương thức rỗng.
Các phương thức bắt buộc kế thừa từ lớp cha ở lớp dẫn xuất nhưng không được sử dụng.
Phát sinh ngoại lệ trong phương thức của lớp dẫn xuất.
Đây là nguyên lý… dễ bị vi phạm nhất, nguyên nhân chủ yếu là do sự thiếu kinh nghiệm khi thiết kế class. Thuông thường, design các class dựa theo đời thật: hình vuông là hình chữ nhật, file nào cũng là file. Tuy nhiên, không thể bê nguyên văn mối quan hệ này vào code. Hãy nhớ 1 điều:
Trong thực tế, A là B (hình vuông là hình chữ nhật) không có nghĩa là class A nên kế thừa class B. Chỉ cho class A kế thừa class B khi class A thay thế được cho class B.
Nguyên lý này ẩn giấu trong hầu hết mọi đoạn code, giúp cho code linh hoạt và ổn định mà ta không hề hay biết. Ví dụ như trong Java, ta có thể chạy hàm foreach với List, ArrayList, LinkedList bởi vì chúng cùng kế thừa interface Iterable. Các class List, ArrayList, … đã được thiết kế đúng LSP, chúng có thể thay thế cho Iterable mà không làm hỏng tính đúng đắn của chương trình.
Theo đó, để sửa vấn đề hình vuông – hình chữ nhật trên, ta nên để chúng cùng kế thừa một class Shape như sau
Lúc này việc set các chiều cao và chiều rộng thì chỉ class con mới có, và không vi phạm nguyên tắc LSP.
Việc thiết kế áp dụng theo nguyên tắc LSP giúp chúng ta giảm bớt quá lạm dụng việc kế thừa trong class. Ý nghĩa của các chức năng không được thay đổi để có thể sử dụng ở nhiều phạm vi khác nhau hơn.
Nguyên tắc 4: Interface segregation principle – Nguyên tắc chia nhỏ
Nguyên tắc này được phát biểu như sau:
Thay vì dùng 1 interface lớn, ta nên tách thành nhiều interface nhỏ, với nhiều mục đích cụ thể.
Many client-specific interfaces are better than one general-purpose interface.
Theo nguyên tắc ISP, một class con khi implement các interface thì không nên bị bắt buộc implement các phương thức mà mình không sử dụng bao giờ. Theo cách hiểu trên, nguyên tắc này sẽ ưu tiên việc chia nhỏ các interface ra thành các phương thức sử dụng cho các mục đích đặc thù hơn, tránh sử dụng cả một interface lớn.
Hay nói một cách khác, khi ta implement một interface trong 1 class, mà có 1 vài phương thức mình cứ phải kế thừa dù cũng không cần thiết không phải một cách hay. Ngắn gọn là: Không một client nào nên bị bắt buộc phải kế thừa một phương thức nào đó mà nó không dùng
Hãy tưởng tượng chúng ta có 1 interface lớn, khoảng 100 methods. Việc implements sẽ khá cực khổ, ngoài ra còn có thể dư thừa vì 1 class không cần dùng hết 100 method. Khi tách interface ra thành nhiều interface nhỏ, gồm các method liên quan tới nhau, việc implement và quản lý sẽ dễ hơn.
Như vậy, việc class Bike implement interface Vehicle khiến class Bike phải viết lại cả hàm openDoor() mở cửa, dù xe đạp thì không có cửa, và thường thì ta sẽ phải để nó rỗng. Như vậy khiến code bị dư thừa và nếu mở rộng ra thì các class con ngày càng bị phình to, khó bảo trì hơn
Việc áp dụng nguyên tắc trên giúp code dễ đọc và dễ quản lí bảo trì hơn. Giảm bớt code dư thừa và chỉ phải viết các phương thức cần thiết.
Nguyên tắc 5: Dependency inversion principle – Nguyên tắc đảo ngược phụ thuộc
Lấy ví dụ:
Như ta thấy, các thiết bị như tai nghe dùng cổng 3.5mm, điện thoại Android dùng dây sạc TypeC, điện thoại IOS dùng dây sạc Lightning, cổng cắm của Camera cũng khác, …
Vậy khi ta làm dây sạc, dây kết nối cho các máy này. Ta có chọn trước là nó sẽ dùng cho thiết bị nào không? Rõ ràng là không, các dây sạc này (các module cấp thấp) không quy định là nó dùng cho module cấp cao nào, mà chính các thiết bị như máy ảnh, điện thoại, tai nghe mới quy định nó dùng module cấp thấp nào.
Nguyên tắc này được phát biểu như sau:
Các module cấp cao không nên phụ thuộc vào các modules cấp thấp. Cả 2 nên phụ thuộc vào abstraction.
Interface (abstraction) không nên phụ thuộc vào chi tiết, mà ngược lại. ( Các class giao tiếp với nhau thông qua interface, không phải thông qua implementation.)
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend upon details. Details should depend upon abstractions.
Ví dụ, ta đang thiết kế một hệ thống thanh toán bằng ngân hàng như sau:
Ví dụ lúc này, ta cần thêm phương thức thanh toán bằng tiền mặt, cần có thêm một số tham số thì sao?
Ta thấy lúc này ta lại phải sửa đổi ở module cấp cao (highlevel module) là CuaHang, thêm if else để xử lí phương thức mới, mà sau này, nếu thêm các phương thức mới nữa, ta lại cứ phải thêm rất nhiều if else vào cái class lớn này.
Nó đã vi phạm 2 nguyên tắc là nguyên tắc (Nguyên tắc đảo ngược phụ thuộc) vì một class level cao hơn lại khai báo các chi tiết của class level bé hơn, hơn nữa lại còn sai về (Nguyên tắc một chức năng) vì đã khai báo nhiều chức năng hơn trong class lớn. Đúng ra class lớn chỉ nên thực hiện thanh toán thôi, còn cụ thể thanh toán thế nào thì phải là class khác.
Áp dụng nguyên tắc Dependency inversion principle – Nguyên tắc đảo ngược phụ thuộc
Lúc này các module cấp cao high-level là CuaHang đã có một interface ở giữa là PhuongThucThanhToan với các chức năng của các lớp cấp thấp (low-level module) như ThanhToanTienMat, ThanhToanNganHang. Ta đã đảo ngược sự phụ thuộc.
Như vậy, khi ta muốn thêm các lớp thanh toán khác như PayPal, Thẻ tín dụng, ví điện tử,…. Ta chỉ cần viết thêm các class con khác kế thừa từ interface PhuongThucThanhToan, chứ không cần động gì vào các code cũ này nữa.
Team mình tham gia – JadeG gồm 5 thành viên đã giành vị trí Top 2 cho Track Fintech – Trợ lý ảo tài chính thông minh
Đây là lần đầu mình tham gia một sự kiện hackathon, cùng nhau làm việc, ăn ngủ, nằm sàn lạnh để cố gắng đạt được kết quả. Trước khi đi thì mình nghĩ hackathon sẽ mở cho đại đa số các bạn sinh viên nên đề thi sẽ khá là dễ, nhưng lúc công bố thành viên thì shock ngang luôn, rất nhiều anh chị sinh viên năm 4-5 sắp ra trường, có cả các anh chị đang đi làm tại các công ty lớn. Phần chuẩn bị của Junction từ đồ ăn, các buổi khai mạc workshop cũng rất chuyên nghiệp, làm mình cũng thấy có phần bất ngờ với cuộc thi lớn đến vậy.
Chuẩn bị trước kì thi:
Trước kì thi với các hint từ ban tổ chức về một trợ lý ảo, nhóm mình cũng đã lập xong và có các buổi meeting để thảo luận trước ý tưởng. Với ý tưởng ban đầu là một chat bot hỗ trợ chuyển tiền cơ bản, kèm thêm các chức năng cho quán ăn có thể tạo, … dạng như một ứng dụng Shopee Food.
Các nội dung bọn mình liệt kê ra ở khâu chuẩn bị
Dù nói là track thi về công nghệ tài chính, nhưng yêu cầu lại là xây dựng một trợ lý ảo về A.I, và thực sự không có ai trong nhóm biết A.I cả =)))
Ngày 1:
Đa số các nội dung trong ngày đầu tiên là buổi khai mạc, công bố đề thi, các sự kiện workshop bên lề. Do mới đặt chân lên Viettel Academy nên nhóm mình chạy lung tung đi chơi là chính =)))
Buổi khai mạc của Junction X Hackathon Hanoi 2023
Khi tới phòng thi mình mới biết nhiều nhóm khác đã chuẩn bị cả sản phẩm, model A.I, … và đến đây chỉ hoàn thiện thêm. Còn mình chỉ có một file Google Doc với vài phác hoạ cơ bản, cả nhóm rất sốc với tiến độ của các team khác. Mọi người bảo nhau là đến đây ăn bánh của BTC là vui rồi :3
Phòng thi Fintech
Do điều kiện của cuộc thi nên đêm đầu tiên nhóm mình đã phải ngủ lại luôn tại phòng, trong lúc ngủ mình vẫn thấy các nhóm khác đang miệt mài code, nên khi đến 4-5h sáng mình lại phải ngồi dậy làm tiếp ._.
Ngày 2:
Ngày 2 là thời gian chính của cuộc thi, sau khi đã có các bản nội dung mới cho ứng dụng từ đề thi chính thức ở ngày 1. Nhóm mình đã ngay lập tức đi vào khâu triển khai ứng dụng thực tế.
Đến tối còn có một bạn trong phòng đến xem Tarot :vv
Sau khi nghe ý tưởng của nhóm mình, các anh chị Mentor cũng đã giúp đỡ rất nhiều và cho nhóm mình nhiều lời khuyên về cách cải tiến sản phẩm, hướng đi sát với đề thi hơn. Nhưng cũng đồng nghĩa nhiều phần nhóm mình cần đập đi xây lại..
Ngày 3:
Ngày 3 cuối cùng chỉ còn khoảng 12h tiếng để chuẩn bị và hạn deadline là 12h trưa.
Sau khi nộp bài thì các anh chị mentor có gọi nhóm mình lên để thuyết trình thêm về ý tưởng của team.
Trong lúc thuyết trình thì 2 anh chị mentor cứ bảo “Tiếp đi em”, mình cũng đã nghĩ “Thôi chắc là đi về rồi :v”
Bằng nhiều lý do may mắn, đội mình đã giành được Top 2 Track Fintech ._.
P-Connect is an Android app written in Java, developed by quochungcyou, made during ProGApp competition in one month. It provides a comprehensive experience with its user-friendly UI/UX, smooth animations, and top performance. With fast loading times and an elegant design, P-Connect offers a plethora of features such as the latest headlines, chat functions, and even a small dating app. Additionally, the code is clean and organized with an MVC structure to ensure maximum efficiency.
Prerequisites
To run this software, you need an editor with java support, java – version 11 or higher,android-studio
Install java 11 using the commands: sudo apt updatesudo apt install openjdk-11-jre-headless
MIT License
Copyright (c) 2023 QuocHung
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Swing trong Java là một bộ công cụ Giao diện Người dùng Đồ họa (GUI) bao gồm các thành phần GUI. Swing cung cấp một bộ widget và gói phong phú để tạo ra các thành phần GUI tinh vi cho các ứng dụng Java. Swing là một phần của Java Foundation Classes (JFC), là một API để lập trình Java GUI cung cấp GUI.
Thư viện Java Swing được xây dựng dựa trên Bộ công cụ tiện ích con trừu tượng Java ( AWT ), một bộ công cụ GUI phụ thuộc vào nền tảng cũ hơn. Bạn có thể sử dụng các thành phần lập trình GUI đơn giản của Java như nút, hộp văn bản, v.v., từ thư viện và không phải tạo các thành phần từ đầu. Tuy nhiên, nó lại khác với AWT ở chỗ bộ công cụ này thuộc loại nền tảng độc lập, bao gồm các thành phần nhẹ và phức tạp hơn AWT.
Gói javax.swing cung cấp các lớp cho java swing API như JButton, JTextField, JTextArea, JRadioButton, JCheckbox, JMenu, JColorChooser, etc..
Sử dụng
Java Swing được dùng để hỗ trợ tạo giao diện đồ hoạ người dùng (với Java).
Bộ công cụ này cung cấp các bộ điều khiển nâng cao như thanh trượt, colorpicker, Tree, TabbedPane và bảng điều khiển,..
Swing có những đặc điểm:
Độc lập với thiết bị.
Có thể tuỳ chỉnh, mở rộng.
Khá nhẹ.
Có thể cấu hình.
Các lớp và phân tầng Java Swing
Các phương thức thường gặp ở lớp Component
Phương thức
Mô tả
public void add(Component c)
thêm một thành phần vào thành phần khác.
public void setSize(int width, int height)
thiết lập kích thước của thành phần.
public void setLayout(LayoutManager m)
thiết lập trình quản lý bố cục (layout) cho thành phần.
public void setVisible(boolean b)
thiết lập khả năng hiển thị của thành phần. Nó theo mặc định là false (ẩn)
Một số thành phần cơ bản
JButton – Nút bấm
Nó được dùng để tạo ra một nút (button) có tên.
Việc sử dụng ActionListener sẽ dẫn đến một số hành động khi nút được nhấn.
Nó kế thừa lớp AbstractButton và độc lập với nền tảng.
JTextField – Ô nhập
Nó kế thừa lớp JTextComponent và dùng để cho phép chỉnh sửa dòng đơn.
JScrollBar – Thanh cuộn
JPanel – Thành phần chứa
Kế thừa lớp JComponent, cung cấp không gian cho một ứng dụng (có thể đính kèm bất kỳ thành phần nào khác).
Một Package (gói) trong Java là một nhóm các class, interface và các package con tương tự, liên quan đến nhau. Chúng ta có thể coi package giống như là một folder.
Các package trong Java được sử dụng để tránh việc xung đột trong khi đặt tên, để kiểm soát truy cập, giúp bạn tìm kiếm và sử dụng các class, interface… một các dễ dàng hơn.
Phân loại
a. Các package có sẵn trong Java API:
java.lang: Chứa các lớp hỗ trợ ngôn ngữ (ví dụ: lớp được định nghĩa các kiểu dữ liệu nguyên thủy, các phép toán). Package này được import tự động.
java.io: Chứa lớp để hỗ trợ input / output (I/O)
java.util: Chứa các lớp tiện ích thực hiện các cấu trúc dữ liệu như danh sách liên kết, dictionary và hỗ trợ cho các hoạt động date / time.
java.applet: Chứa các lớp để tạo Applet.
java.awt: Chứa các class để triển khai các thành phần cho giao diện người dùng đồ họa (ví dụ như button, menu,…).
java.net: Chứa các lớp để hỗ trợ các thao tác trong mạng (network).
b. Package do người dùng tự định nghĩa
Lợi thế của việc sử dụng Package
Package được sử dụng để phân loại lớp và interface giúp dễ dàng bảo trì.
Package cung cấp bảo vể truy cập
Package khắc phục được việc đặt trùng tên.
Triển khai Package
Nếu tên package là traidat.vietnam.hanoi, khi đó có 3 thư mục là: traidat, vietnam, hanoi. Package traidat chứa subpackage – package con vietnam, sau đó package vietnam lại chứa subpackage là hanoi
Tên package thường được viết thường hết các chữ cái, và ghi rõ nghĩa của các class nằm trong package. VD package “math” chứa các class toán học, …
Để có thể sử dụng các phương thức, … của class TenClass này. Ta có thể gọi
Exception trong Java
Định Nghĩa
Exception (ngoại lệ) là một tình trạng bất thường. Trong java, ngoại lệ là một sự kiện làm gián đoạn luồng bình thường của chương trình. Nó là một đối tượng được ném ra tại runtime.
VD: Một chiếc ô tô đang chạy bình thường trên đường, thì bỗng nhiên dừng lại – chương trình dừng lại (RTE – Run Time Error), lúc này do ô tô hết xăng không chạy được nữa, vậy việc “hết xăng” là một ngoại lệ – sự bất thường bỗng xảy ra trong chương trình
Các loại Exception
Checked Exceptions: Các Exceptions là lớp extends từ lớp Throwable ngoại trừ RuntimeException và Error. Các Checked Exception được kiểm tra tại compile-time (Lúc chương trình được biên dịch)
Unchecked Exception: Các lớp extends từ RuntimeException được gọi là Unchecked Exception, ví dụ: ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException,… Các Exception này thường xảy ra khi lỗi đó không lường trước được.
Error: Đây là các lỗi không thể cứu chữa được, không thể làm gì khi nó xảy ra được nữa (VD: Hết ram, …)
VD: Khi ta chuẩn bị đi ra ngoài, ta sợ trời có thể mưa nên đã phòng sẵn một cái ô.
Việc trời mưa ta đã lường trước được, nên gọi là Checked Exception, và ta đã khai báo “cái ô” để chuẩn bị trước.
Tuy nhiên có một số vấn đề khác ta không lường được, ví dụ có một vũng nước trên đường, có một cái ô tô chắn không ra khỏi nhà (Các vấn đề phải thực thi chương trình, đi ra ngoài mới có thể gặp)
Checked Exceptions
IOException: Ngoại lệ liên quan đến file input / output
SQLException: Ngoại lệ liên quan đến cú pháp SQL
DataAccessException: Ngoại lệ liên quan đến việc truy cập CSDL
ClassNotFoundException: Bị ném khi JVM không thể tìm thấy một lớp mà nó cần, do lỗi dòng lệnh, sự cố đường dẫn hoặc tệp, class bị thiếu…
InstantiationException: Ngoại lệ khi cố gắng tạo đối tượng của một abstract class hoặc interface
UnChecked Exceptions
NullPointerException: Ngoại lệ bị ném ra khi cố gắng truy cập một đối tượng có biến tham chiếu có giá trị hiện tại là null
ArrayIndexOutOfBound: Ngoại lệ khi cố gắng truy cập một phần tử vượt quá độ dài của mảng
IllegalArgumentException: Ngoại lệ bị ném ra khi một phương thức nhận được một đối số được định dạng khác với phương thức mong đợi.
IllegalStateException: Ngoại lệ bị ném ra khi trạng thái của môi trường không phù hợp với hoạt động cố gắng thực hiện, ví dụ: Sử dụng Scanner đã bị đóng.
NumberFormatException: Ngoại lệ bị ném khi một phương thức chuyển đổi một Chuỗi thành số nhưng không thể chuyển đổi.
ArithmeticException: Lỗi số học, chẳng hạn như chia cho 0.
Xử lí Exception
Khối lệnh try-catch:
Lưu ý: Bạn có thể sử dụng nhiều khối catch với một khối try duy nhất. (Xử lí nhiều lỗi khi thử làm gì đó)
Khối lệnh finally:
Khối lệnh finally trong java được sử dụng để thực thi các lệnh quan trọng như đóng kết nối, đóng cả stream,…
Khối lệnh finally trong java luôn được thực thi cho dù có ngoại lệ xảy ra hay không hoặc gặp lệnh return trong khối try.
Quy tắc:
Đối với mỗi khối try, có thể có không hoặc nhiều khối catch, nhưng chỉ có một khối finally.
Khối finally sẽ không được thực thi nếu chương trình bị thoát (bằng cách gọi System.exit() hoặc xảy ra một lỗi không thể tránh khiến chương trình bị chết).
Custom Exception
Chúng ta có thể khai báo 1 class mới và extends Exception để trở thành 1 ngoại lệ checked
Chúng ta có thể khai báo 1 class mới và extends RuntimeException để trở thành 1 ngoại lệ unchecked
Tính đa hình (Polymorphism) là một trong bốn tính chất cơ bản của OOP. Trong lập trình, thuật ngữ này dùng để ám chỉ đến việc một biến, một hàm hoặc một phương thức có thể tồn tại ở nhiều dạng khác nhau. Đa hình là hiện tượng mà các đối tượng thuộc các class khác nhau có thể biểu diễn cùng một thông điệp theo các cách khác nhau.
Ví dụ:
Một người A có thể là một học sinh, đồng thời là thành viên câu lạc bộ, đồng thời là nhân viên bán thời gian quán café.
Một hành động “làm việc” nếu cho học sinh sẽ là học tập, cho kế toán sẽ là “tính toán”, …
Lập trình viên có thể tận dụng Tính đa hình trong OOP vào những trường hợp sau:
Khi các lớp con cần dùng phương thức của lớp cha để bổ sung cho một phương thức khác.
Khi một lớp cần có nhiều phương thức cùng tên nhưng khác tham số (parameter).
Tính đa hình trong OOP gồm có 2 loại:
Runtime Polymorphism (Đa hình thời gian chạy)
Compile Time Polymorphism (Đa hình thời gian biên dịch)
Theo đó , tính đa hình cho phép một phương thức thực thi những hành vi khác nhau theo hai hướng: sử dụng phương thức ghi đè (method overriding) hoặc phương thức nạp chồng (method overloading).
Đa hình thời gian chạy là trường hợp một đối tượng bị ràng buộc với chức năng của chúng ngay tại thời gian chương trình đang chạy. Đa hình thời gian chạy sử dụng phương thức ghi đè.
Đa hình thời gian biên dịch là trường hợp một đối tượng bị ràng buộc với chức năng của chúng ngay tại thời gian chương trình đang biên dịch. Đa hình thời gian biên dịch sử dụng phương thức nạp chồng.
Phương thức ảo, từ khóa Virtual
Một số tài liệu có viết công dụng của Virtual Function như sau:
“Virtual Function là để khai báo một function ở class cha (base class) mà sau đó các class kế thừa (derived class) có thể override function đó”
Các hàm ảo sẽ cho phép chúng ta tạo một danh sách các con trỏ lớp cơ sở và các phương thức của bất kỳ lớp dẫn xuất nào mà không cần biết loại đối tượng của lớp dẫn xuất.
Khi khai báo hàm ảo với từ khóa virtual nghĩa là hàm này sẽ được gọi theo loại đối tượng được trỏ (hoặc tham chiếu), chứ không phải theo loại của con trỏ (hoặc tham chiếu). Và điều này dẫn đến kết quả khác nhau:
Nếu không khai báo hàm ảo virtual trình biên dịch sẽ gọi hàm tại lớp cở sở base (lớp cha)
Nếu dùng hàm ảo virtual trình biên dịch sẽ gọi hàm tại lớp dẫn xuất derived (lớp kế thừa)
Phương thức thuần ảo, lớp ảo
Hàm thuần ảo (pure virtual function) được sử dụng khi:
Không cần sử dụng hàm này trong lớp cơ sở, chỉ phục vụ cho lớp dẫn xuất
Lớp dẫn xuất bắt buộc phải định nghĩa lại hàm thuần ảo (Nạp chồng)
Ví dụ: Chúng ta có một lớp cơ sở là Shape. Các lớp dẫn xuất của lớp Shape là Triangle, Square và Circle. Chúng ta muốn tính diện tích của các hình này.
Chúng ta có thể tạo ra một hàm thuần ảo có tên là calculateArea() trong lớp Shape. Các lớp Triangle, Square và Circle phải định nghĩa lại hàm calculateArea() với công thức tính diện tích khác nhau cho mỗi hình.
Lớp ảo
Có một vấn đề khi một lớp cơ sở được kế thừa bởi nhiều lớp dẫn xuất. Ví dụ, xét tình huống các lớp kế thừa theo sơ đồ như sau:
Lớp B và Lớp C kế thừa từ lớp A. Chúng trở thành A (B) và A (C). Lúc này, nếu ta lại cho D kế thừa từ B và C, ta vô tình tạo ra tới 2 con đường kế thừa về 1 điểm đích.
D kế thừa thông qua B kế thừa A
D kế thừa thông qua C kế thừa A
Điều này sẽ khiến trình biên dịch mơ hồ và không biết nên đi theo con đường nào và tạo ra lỗi.
Thay vì kế thừa thông thường, ta sẽ định nghĩa B và C là các lớp ảo, việc sử dụng lớp ảo sẽ tiết kiệm không gian và tránh việc trùng lặp kế thừa.
Nếu kế thừa thông thường, khi tạo class D kế thừa đồng thời B và C, ta thực chất tạo ra 2 bản sao class A
Nếu cho class B và class C thành virtual, thì khi tạo class C chúng ta sẽ dùng chung 1 bản class A.
Hệ thống UML Class Diagram (Biểu đồ Class) là một cách dùng hình ảnh để khởi tạo và biểu diễn một hệ thống hướng đối tượng.
Tìm hiểu về Diagram UML: Access Modifier, Composition, Aggregation, Cardinality.
Access Modifier:
Trong C++ chúng ta có 3 nhãn phạm vi (access modifier) thì uml sẽ kí hiệu như sau
Dấu + : public
Dấu – : private
Dấu # : protected
Composition, Aggregation
Ví dụ:
Người đang tiếp xúc với pet, pet cũng tiếp xúc với người (Sự kết hợp – association)
Cái đuôi là một thành phần của con chó hoặc con mèo (aggregation composition – Thành phần)
Mèo là một kiểu con của pet (Kế thừa)
Aggregation là kiểu khi mà các lớp con được độc lập và không phụ thuộc vào lớp cha. Khi lớp cha bị xóa thì lớp con vẫn tồn tại.
Composition bị phụ thuộc vào lớp cha.
Ví dụ:
Class ô tô và Class bánh xe. Class bánh xe vẫn là một sự tồn tại “có ý nghĩa” kể cả không có Class ô tô, class bánh xe vẫn có thể dùng cho class xe đạp, class xe máy, …
=> Aggregation là kiểu khi mà các lớp con được độc lập và không phụ thuộc vào lớp cha. Khi lớp cha bị xóa thì lớp con vẫn tồn tại.
Class người và class tay, chân, đầu. Nếu thiếu class người thì gần như những class còn lại đều tồn tại “không có ý nghĩa”, vì chúng không thể sử dụng vào đâu khác cả.
Cardinality
Sử dụng để thể hiện quan hệ về số lượng giữa các đối tượng được tạo từ các class trong class diagram
0…1: 0 hoặc 1
n : Bắt buộc có n
0…* : 0 hoặc nhiều
1…* : 1 hoặc nhiều
m…n: có tối thiểu là m và tối đa là n
-> VD ảnh: Công ty chỉ có một, còn nhân viên công ty thì là 1 hoặc * (nhiều – không giới hạn)
Tính kế thừa (Inheritance) là một trong bốn tính chất cơ bản của Lập trình hướng đối tượng (OOP).
Kế thừa có thể được định nghĩa là quá trình mà một lớp (class) có được các thuộc tính của một lớp khác. Các thuộc tính đó có thể là một phương thức (method) hoặc một trường (field) nào đó. Có nghĩa là nếu lớp A kế thừa lớp B thì lớp A sẽ có những thuộc tính và phương thức của lớp B.
Lớp được thừa hưởng những thuộc tính và phương thức từ lớp khác được gọi là dẫn xuất (Derived Class) hay lớp Con (Subclass) và các lớp bị lớp khác kế thừa được gọi là lớp cơ sở (Base Class) hoặc lớp cha (Parent Class).
Cú pháp kế thừa
Đơn kế thừa, đa kế thừa
Đơn kế thừa
Đơn kế thừa (single inheritance) là một class con kế thừa duy nhất từ một class cha. Ví dụ như class sinh viên chỉ kế thừa duy nhất từ class con người.
Khai báo:
Tính chất dẫn xuất trong đơn kế thừa
Lớp dẫn xuất
Lớp dẫn xuất
Lớp dẫn xuất
Lớp cơ sở
Public
Private
Protected
Private
Không kế thừa
Không kế thừa
Không kế thừa
Protected
Protected
Private
Protected
Public
Public
Private
Protected
public: Nếu kế thừa ở dạng này, sau khi kế thừa, tất cả các thành viên dạng public lớp cha sẽ public ở lớp con, dạng protected ở lớp cha vẫn sẽ là protected ở lớp con.
protected: Nếu dùng protected thì sau khi kế thừa, tất cả các thành viên dạng public lớp cha sẽ trở thành protected tại lớp con.
private: Trường hợp ta sử dụng private, thì sau khi kế thừa, tất cả các thành viên dạng public và protected ở lớp cha sẽ thành private tại lớp con.
Đa kế thừa
Đa kế thừa (multiple inheritance) nghĩa là thay vì một class dẫn xuất kế thừa từ một class cơ sở, class dẫn xuất này có thể có kế thừa từ nhiều class cơ sở khác nhau. Ví dụ như con cái thì sẽ kế thừa đặc điểm từ cả bố và mẹ của chúng.
Khai báo:
Khi thừa kế từ nhiều class cơ sở, bạn thấy sẽ có một vấn đề phát sinh chính là khi lớp cơ sở có phương thức trùng tên, khi gọi phương thức sẽ xảy ra sự mơ hồ. Sự mơ hồ nghĩa là trình biên dịch không biết bạn đang gọi phương thức từ class dẫn xuất nào. Để giải quyết vấn đề này, ta có thể sử dụng toán tử phạm vi :: để chỉ rõ phương thức ở class nào. Ví dụ:
Function Overloading & Operator Overloading
Ngôn ngữ C++ cho phép xác định nhiều hơn một định nghĩa cho một tên hàm hoặc một toán tử trong cùng phạm vi, được gọi tương ứng là Nạp chồng hàm và Nạp chồng toán tử.
Một khai báo nạp chồng là một khai báo mà đã được khai báo cùng tên như một khai báo được khai báo trước đó trong cùng phạm vi, ngoại trừ rằng: cả hai khai báo có các tham số khác nhau và định nghĩa khác nhau
Nạp chồng hàm
Kỹ thuật này cho phép sử dụng cùng một tên gọi cho các hàm “giống nhau” (có cùng mục đích). Nhưng khác nhau về kiểu dữ liệu tham số hoặc số lượng tham số.
Ví dụ: Nạp chồng hàm cho phép ta khai báo và định nghĩa các hàm sau với cùng một tên gọi.
Nạp chồng toán tử
.Nạp chồng toán tử (overload operator) là bạn định nghĩa lại toán tử đã có trên kiểu dữ liệu người dùng tự định nghĩa để dể dàng thể hiện các câu lệnh trong chương trình.
Ví dụ như bạn định nghĩa phép cộng cho kiểu dữ liệu phân số thì sẽ thực hiện cộng hai phân số rồi trả về một phân số mới. So với việc thực hiện gọi hàm, việc overload toán tử sẽ làm cho câu lệnh ngắn gọn, dễ hiểu hơn.
Cú pháp:
=> Như đã giới thiệu, bản chất việc dùng toán tử là lời gọi hàm, do đó chúng ta overload toán tử cũng giống overload hàm, vậy chúng ta sẽ overload hàm nào? Chúng ta sẽ overload hàm có tên là operator @, với @ là toán tử cần overload (+, -, *, /…), kiểu trả về của hàm chính là lớp đó.
Nạp chồng toán tử 2 ngôi:
Function Overriding
Trong kế thừa, khi lớp con khai báo phương thức có tên trùng với phương thức ở lớp cha thì phương thức của lớp cha sẽ bị thay thế bởi phương thức ở lớp con.
Hàm Friend
Hàm bạn của một lớp không phải là hàm thành viên nên nó không phụ thuộc vào lớp và có thể định nghĩa ở trong hoặc ngoài lớp.
Hàm bạn có thể truy cập trực tiếp các thành viên private và một lớp có thể có nhiều hàm bạn.
Cú pháp khai báo hàm bạn đơn giản là thêm từ khóa friend trước hàm bình thường ta vẫn sử dụng.
Collection trong java là một root interface trong hệ thống cấp bậc Collection. Java Collection cung cấp nhiều interface (Set, List, Queue, Deque,…) và các lớp (ArrayList, Vector, LinkedList, PriorityQueue, HashSet, LinkedHashSet, TreeSet,…)
Collections
Collections trong java là một khuôn khổ cung cấp một kiến trúc để lưu trữ và thao tác tới nhóm các đối tượng. Tất cả các hoạt động mà bạn thực hiện trên một dữ liệu như tìm kiếm, phân loại, chèn, xóa,… có thể được thực hiện bởi Java Collections.
Hệ thống cấp bậc Collection
Gói java.util chứa tất cả các lớp và interface của Collection
Các phương thức
Iterable interface chứa dữ liệu thành viên Iterator interface.
Giao tiếp Iterator cung cấp phương tiện để lặp đi lặp lại các thành phần từ đầu đến cuối của một collection.
Ngoài ra, ta còn có thể làm việc với Collection thông qua Iterator Interface.
Phương thức
Mô tả
public boolean hasNext()
Nó trả về true nếu iterator còn phần tử kế tiếp phần tử đang duyệt.
public object next()
Nó trả về phần tử hiện tại và di chuyển con trỏ trỏ tới phần tử tiếp theo.
public void remove()
Nó loại bỏ phần tử cuối được trả về bởi Iterator. Nó hiếm khi được sử dụng.
Một số method của Interface Collection. Các method này sẽ được các Interface con kế thừa lại:
Phương thức
Mô tả
boolean add(Object element)
Được sử dụng để chèn một phần tử vào collection.
boolean addAll(Collection c)
Được sử dụng để chèn các phần tử collection được chỉ định vào collection gọi phương thức này.
boolean remove(Object element)
Được sử dụng để xóa phần tử từ collection.
boolean removeAll(Collection c)
Được sử dụng để xóa tất cả các phần tử của collection được chỉ định từ collection gọi phương thức này.
boolean retainAll(Collection c)
Được sử dụng để xóa tất cả các thành phần từ collection gọi phương thức này ngoại trừ collection được chỉ định.
int size()
Trả lại tổng số các phần tử trong collection.
void clear()
Loại bỏ tổng số của phần tử khỏi collection.
boolean contains(Object element)
Được sử dụng để tìm kiếm phần tử.
boolean containsAll(Collection c)
Được sử dụng để tìm kiếm collection được chỉ định trong collection.
Iterator iterator()
Trả về một iterator.
Object[] toArray()
Chuyển đổi collection thành mảng (array).
boolean isEmpty()
Kiểm tra nếu collection trống.
boolean equals(Object element)
So sanh 2 collection.
int hashCode()
Trả về số hashcode của collection.
Collections chỉ chứa static method. Một số method của collections:
Phương thức
Mô tả
void sort()
sắp xếp collections
min(), max()
trả về phần tử nhỏ nhất /lớn nhất trong Collection
int binarySearch()
tìm kiếm nhị phân một giá trị
void reverse()
đảo ngược collections
void copy()
Sao chép tất cả các phần tử từ một danh sách này sang một danh sách khác.
int frequency()
Trả về số lượng các phần tử có trong bộ sưu tập được chỉ định bằng đối tượng được chỉ định.
int indexOfSubList()
Trả về vị trí bắt đầu của lần xuất hiện đầu tiên của danh sách mục tiêu được chỉ định trong danh sách nguồn quy định, hoặc -1 nếu không tìm thấy đối tượng chỉ định.
CÁC COLLECTION THƯỜNG GẶP
List
List là một interface trong java. Nó chứa các phương thức để chèn và xóa các phần tử dựa trên chỉ số index.
Khai báo của interface List trong Java:
Các method của List thường dùng:
Phương thức
Mô tả
void add(int index, Object element)
Nó được sử dụng để chèn các phần tử vào list tại chỉ số index.
boolean addAll(int index, Collection c)
Nó được sử dụng để chèn tất cả các yếu tố của c vào danh sách tại chỉ số index.
object get(int index)
Nó được sử dụng để trả về đối tượng được lưu trữ tại chỉ số index trong list.
object set(int index, Object element)
Nó được sử dụng để gán phần tử cho vị trí được chỉ định index trong list.
object remove(int index)
Nó được sử dụng để xóa các phần tử tại vị trí có chỉ số index và trả về phần tử đã xóa.
ListIterator listIterator()
Nó được sử dụng để trả về một Iterator mà bắt đầu từ phần tử đầu tiên của list.
ListIterator listIterator(int index)
Nó được sử dụng để trả về một Iterator mà phần tử bắt đầu từ chỉ số index chỉ định.
ArrayList
Lớp ArrayList trong java là một lớp kế thừa lớp AbstractList và triển khai của List Interface nên nó sẽ có một vài đặc điểm và phương thức tương đồng với List.
ArrayList được sử dụng như một mảng động để lưu trữ các phần tử.
Những đặc điểm của ArrayList:
Lớp ArrayList trong java có thể chứa các phần tử trùng lặp.
Lớp ArrayList duy trì thứ tự của phần tử được thêm vào.
Lớp ArrayList là không đồng bộ (non-synchronized).
Lớp ArrayList cho phép truy cập ngẫu nhiên vì nó lưu dữ liệu theo chỉ mục.
Lớp ArrayList trong java, thao tác chậm vì cần nhiều sự dịch chuyển nếu bất kỳ phần tử nào bị xoá khỏi danh sách.
Khởi tạo ArrayList:
Các method của ArrayList thường dùng:
Phương thức
Mô tả
boolean add(Object o)
Nó được sử dụng để nối thêm phần tử được chỉ định vào cuối một danh sách.
void add(int index, Object element)
Nó được sử dụng để chèn phần tử element tại vị trí index vào danh sách.
boolean addAll(Collection c)
Nó được sử dụng để nối tất cả các phần tử trong collection c vào cuối của danh sách, theo thứ tự chúng được trả về bởi bộ lặp iterator.
boolean addAll(int index, Collection c)
Nó được sử dụng để chèn tất cả các phần tử trong collection c vào danh sách, bắt đầu từ vị trí index.
void retainAll(Collection c)
Nó được sử dụng để xóa những phần tử không thuộc collection c ra khỏi danh sách.
void removeAll(Collection c)
Nó được sử dụng để xóa những phần tử thuộc collection c ra khỏi danh sách.
int indexOf(Object o)
Nó được sử dụng để trả về chỉ mục trong danh sách với sự xuất hiện đầu tiên của phần tử được chỉ định, hoặc -1 nếu danh sách không chứa phần tử này.
int lastIndexOf(Object o)
Nó được sử dụng để trả về chỉ mục trong danh sách với sự xuất hiện cuối cùng của phần tử được chỉ định, hoặc -1 nếu danh sách không chứa phần tử này.
Object[] toArray()
Nó được sử dụng để trả về một mảng chứa tất cả các phần tử trong danh sách này theo đúng thứ tự.
Object[] toArray(Object[] a)
Nó được sử dụng để trả về một mảng chứa tất cả các phần tử trong danh sách này theo đúng thứ tự.
Object clone()
Nó được sử dụng để trả về một bản sao của ArrayList.
void clear()
Nó được sử dụng để xóa tất cả các phần tử từ danh sách này.
void trimToSize()
Nó được sử dụng để cắt dung lượng của thể hiện ArrayList này là kích thước danh sách hiện tại.
boolean contains(element)
Kết quả trả về là true nếu tìm thấy element trong danh sách, ngược lại trả về false.
Như tìm hiểu bên trên, ta thấy ArrayList và Vector gần giống nhau. Tuy nhiên, ta có thể so sánh một vài sự khác biệt như sau:
ArrayList
Vector
ArrayList là non-synchronized.
Vector là synchronized.
ArrayList là nhanh hơn vì nó là non-synchronized.
Vector là chậm hơn vì nó là synchronized. Tức là, trong môi trường đa luồng, các thread giữ nó ở trong trạng thái runnable hoặc non-runnable cho đến khi thread hiện tại giải phóng đối tượng đó.
ArrayList được duyệt bởi Iterator.
Vector được duyệt bởi Enumeration và Iterator.
Map
Trong java, map được sử dụng để lưu trữ và truy xuất dữ liệu theo cặp key và value. Mỗi cặp key và value được gọi là mục nhập (entry). Map trong java chỉ chứa các giá trị key duy nhất. Map rất hữu ích nếu bạn phải tìm kiếm, cập nhật hoặc xóa các phần tử trên dựa vào các key.
Các phương thức hữu ích của Map interface
Phương thức
Mô tả
Object put(Object key, Object value)
Nó được sử dụng để chèn một mục nhập trong map hiện tại.
void putAll(Map map)
Nó được sử dụng để chèn map chỉ định vào map hiện tại.
Object remove(Object key)
Nó được sử dụng để xóa một mục nhập của key được chỉ định.
Object get(Object key)
Nó được sử dụng để trả lại giá trị cho khoá được chỉ định.
boolean containsKey(Object key)
Nó được sử dụng để tìm kiếm key được chỉ định từ map hiện tại.
Set keySet()
Nó được sử dụng để trả đối tượng Set có chứa tất cả các keys.
Set entrySet()
Nó được sử dụng để trả lại đối tượng Set có chứa tất cả các keys và values.
Map.Entry Interface
Entry là một interface con của Map. Vì vậy, chúng ta được truy cập nó bằng tên Map.Entry. Nó cung cấp các phương pháp để truy xuất các key và value.
Các phương thức của Map.Entry interface
Phương thức
Mô tả
Object getKey()
Nó được dùng để lấy key.
Object getValue()
Nó được sử dụng để lấy value.
Phân biệt List và ArrayList
List là một interface – ArrayList là một class thuộc framework Collection
List kế thừa từ Collection – ArrayList kế thừa AbstractArrayList và implement List
List lưu các phần tử theo thứ tự vị trí, ArrayList như một mảng động có thể thêm xoá phần tử
Sắp xếp trong Java
Sắp xếp bằng cách tạo hàm compare.to sử dụng giao diện Comparable để sắp xếp
Sắp xếp bằng cách sử dụng Comparator để sắp xếp tiện dụng hơn