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
Facebook là một mạng xã hội phổ biến bậc nhất tại Việt Nam. Mọi người thường xuyên chia sẻ ảnh lên Facebook như một thói quen hàng ngày. Tuy nhiên có một vấn đề mà ai cũng thấy khó chịu là ảnh tải lên Facebook thường bị giảm chất lượng thấy rõ.
Bài viết này sẽ hướng dẫn cách tối ưu nhất có thể việc bị giảm chất lượng ảnh khi tải lên Facebook.
Tại sao Facebook lại giảm chất lượng ảnh tải lên?
Vì lượng ảnh tải lên Facebook từng phút từng giây có dung lượng rất lớn. Với ảnh có chất lượng giảm đi và dung lượng nhẹ hơn, Facebook sẽ cho người dùng tốc độ khi load các bài viết trên ứng dụng/web nhanh hơn, đồng thời giảm bớt chi phí lưu trữ lượng lớn ảnh như vậy. Việc nén ảnh này được thực hiện tự động khi bạn up ảnh lên.
Ảnh tải lên Facebook được hỗ trợ có chiều ngang cạnh phổ thông là 720px, 960px hoặc 2048px. Các ảnh có kích thước khác đều bị co lại theo kích thước tiêu chuẩn, điều này làm chất lượng ảnh giảm rõ rệt.
Giảm Facebook nén ảnh với file ảnh JPEG/JPG
Mỗi khi bạn tải ảnh lên, Facebook mặc định sẽ nén ảnh của bạn, nên không có cách nào chống được điều đó cả. Tuy nhiên có vài cách để giảm bớt việc nén ảnh đó
Đảm bảo ảnh bạn tải lên có cạnh dài lớn nhất là 720, 960 hoặc 2048px. Facebook sẽ không co kích thước ảnh với các kích cỡ ảnh này, việc này giúp ảnh của bạn sắc nét hơn nhiều khi tải lên.
Ví dụ sử dụng phần mềm Adobe Photoshop 2022
Sử dụng chức năng File/ Export/ Save For Web (Legacy)
Chỉnh các thông số như sau: (Cạnh nhiều nhất: 720/960/2048, PNG-24, Embed Color Profile, Convert to sRGB
Ấn Save và kiểm tra thành quả!
So sánh kết quả
Tham khảo: https://www.naturettl.com/upload-photos-facebook-best-quality-possible/
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)
Ở những chương trình code bình thường, code của chúng ta như một vector vậy, chúng chỉ là một dãy các dòng lệnh sẽ được chạy tuần tự từ đầu đến cuối. Ngoại lệ là các hàm và dữ liệu sẽ được tách khỏi vector đó và có thể gọi chúng giữa vector để tạo nên kết quả.
Vậy OOP – Lập trình hướng đối tượng là gì? Nếu nhìn vào cuộc sống thực tế, tất cả thứ bạn thấy xung quanh đều là các đối tượng (Object) , object sẽ luôn có 2 thành phần chính
Các đặc tính của chúng. (VD: cân nặng, chiều cao, kích cỡ, hình dáng, màu sắc, …)
Các “hành động” chúng có thể bị tương tác hoặc có thể tương tác (Quyển sách bị “mở”, người “đi”, …) (Hàm)
Lập trình hướng đối tượng cho chúng ta khả năng tạo ra các đối tượng liên kết chặt chẽ với nhau và hoạt động như những khối hộp có thể sử dụng lại
VD: Bạn cần tạo một con game thế giới mở, người chơi có thể đi lại trong thế giới.
VD bạn cần tạo ra một ngôi nhà, ngôi nhà được cấu thành từ : bức tường, vật gia dụng, sơn, …. Bạn không thể mỗi nơi lại gọi hết các bức tường, vật gia dụng, sơn, … khác nhau ra, mà chúng ta sẽ có một Lớp – Ngôi nhà chứa tất cả đặc tính chúng ta cần như màu sắc, kích cỡ, và các thuộc tính này sẽ khác nhau mỗi nơi, để có thể sử dụng lại
Class và Object
Class là một lớp chứa các thuộc tính, chức năng. và Object – đối tượng là một vật thể được tạo ra từ một lớp Class đó.
struct NgayThang { int nam {}; int thang {}; int ngay {}; };
Đây là một lớp ngày tháng có 3 thuộc tính : ngày tháng năm, các lớp bây giờ sẽ là những thời gian khác nhau trong năm
NgayThang tet = 1/1/2022
NgayThang valentine = 4/2/2022
Con trỏ this?
This là một con trỏ cho phép chúng ta truy cập các thành phần, đặc tính của class
Ví dụ ta đang xây dựng một mạng xã hội với Class, và có một lớp NguoiDung
struct NguoiDung { int taikhoan {}; int matkhau {};};
Ta không thể cho phép người sử dụng khác in ra mật khẩu, tài khoản của một người dùng bất kì
cout << NguoiDung.matkhau;
=> Không cho phép truy cập các phần tử bí mật.
Nhưng ta vẫn cần cho phép người dùng có thể lấy ra mật khẩu khi đăng nhập, đăng xuất, quên mật khẩu, … nhưng mà lại không thể truy cập các phần tử bí mật.
NguoiDung endcontest;
cout << endcontest.matkhau; -> Không được
endcontest.dangnhap();
// nhưng
void NguoiDung::dangnhap() const {
string matkhau;
cin >> matkhau;
if (matkhau == this.matkhau) cout << “dang nhap”;
}
Ta đã ứng dụng con trỏ this để gọi ra mật khẩu, trong khi không thể truy cập trực tiếp.
Các đặc tính của OOP
Tính đóng gói (Encapsulation):
(Điều này giống ví dụ về this bên trên)
Là cách để che dấu những tính chất xử lý bên trong của đối tượng, những đối tượng khác không thể tác động trực tiếp làm thay đổi trạng thái chỉ có thể tác động thông qua các method public của đối tượng đó.
xem cách thể hiện bằng code dưới đây : class hinhchunhat
height và width ở đây chính là các tính chất (properties) của đối tượng class hinhchunhat
tinhdientich() là method được public nhằm mục đích tương tác với các đối tượng khác. Tạo một class Program với method static để run, xem cách tương tác và thay đổi tính chất của đối tượng thông qua các method public như nào:
Ta thấy ta sẽ không thể truy cập các thuộc tính height, width. Nhưng vẫn có thể sử dụng các hàm/method để truy cập chúng.
Tính kế thừa (Inheritance):
Là kỹ thuật cho phép kế thừa lại những tính năng mà một đối tượng khác đã có, giúp tránh việc code lặp dư thừa mà chỉ xử lý công việc tương tự.
Kế thừa một cấp (Single level Inheritance): Với một class cha và một class con
Ví dụ ta có một class đồ điện tử, chúng có các thuộc tính như: số vi mạch, lượng điện sử dụng, hiệu điện thế, cường độ dòng điện ,…. Các thiết bị như điện thoại, tai nghe, … vẫn dùng chúng, nhưng lại có thêm một số thuộc tính riêng khác, nên thay vì phải tạo lại tất cả thuộc tính đó cho từng class điện thoại, tai nghe mới. Ta sẽ gọi Điện thoại là lớp kế thừa của đồ điện tử, và thừa hưởng mọi thuộc tính, chức năng của đồ điện tử.
Tính đa hình (Polymorphism):
Là một đối tượng thuộc các lớp khác nhau có thể hiểu cùng một thông điệp theo cách khác nhau.
Ví dụ đa hình trong thực tế: Mình có 2 con vật: chó, mèo hai con vật này khi nhận được mệnh lệnh là “hãy kêu” thì chó kêu “gâu gâu”, mèo kêu “meo meo”.
Ví dụ trên cả 2 con vật đều hiểu chung một thông điệp “hãy kêu” và thực hiện theo cách riêng của chúng.
Tính trừu tượng (Abstraction):
Abstraction (Tính trừu tượng) là một khả năng mà chương trình có thể bỏ qua sự phức tạp bằng cách tập trung vào cốt lõi của thông tin cần xử lý.
Điều đó có nghĩa, bạn có thể xử lý một đối tượng bằng cách gọi tên một phương thức và thu về kết quả xử lý, mà không cần biết làm cách nào đối tượng đó được các thao tác trong class.
Ví dụ: bạn có thể nấu cơm bằng nồi cơm điện bằng cách rất đơn giản là ấn công tắc nấu, mà không cần biết là bên trong cái nồi cơm điện đó đã làm thế nào mà gạo có thể nấu thành cơm.
Nhãn phạm vi
Nhãn public
Từ khóa public được dùng để tạo các thành phần “public – công khai” (Cho dữ liệu hoặc hàm)
Các thành phần được tạo public có thể truy cập từ bất cứ chỗ nào trong phần mềm
Nhãn private
Từ khóa public được dùng để tạo các thành phần “private – bí mật” (Cho dữ liệu hoặc hàm)
Các phần tử private chỉ có thể truy cập trong class hoặc class friend
Nhãn protected
Từ khóa public được dùng để tạo các thành phần “protected – bảo mật” (Cho dữ liệu hoặc hàm)
Các thành phần protected chỉ có thể truy cập trong class và các class kế thừa của nó.
Tổng quát
Kiểu
Trong chính class
Class kế thừa
Bên ngoài
public
Yes
Yes
Yes
private
Yes
No
No
protected
Yes
Yes
No
Hàm khởi tạo và hàm hủy
Hàm khởi tạo là một hàm đặc biệt trong lớp. Hàm này được gọi tự động khi một đối tượng được tạo ra. Hàm khởi tạo sẽ khởi tạo giá trị cho các thuộc tính của đối tượng. Trong C++, một hàm khởi tạo có đặc điểm sau:
− Tên hàm khởi tạo trùng với tên của lớp.
− Hàm khởi tạo không có kiểu dữ liệu trả về (kể cả void).
− Hàm khởi tạo có thể là public, private hoặc protected. Hàm private có thể truy cập từ lớp friend, protected có thể gọi từ lớp kế thừa.
− Hàm khởi tạo có thể có đối số hoặc không có đối số.
− Trong một lớp có thể có nhiều hàm khởi tạo (cùng tên nhưng khác đối số).
Hàm khởi tạo mặc định (default constructor)
Hàm khởi tạo mà không có đối số nào thì được gọi là hàm khởi tạo mặc định. Hàm này thường dùng gán giá trị mặc định cho các thuộc tính trong lớp.
Trong ví dụ bên dưới, hàm Circle() là một hàm khởi tạo mặc định và tự đặt r = 1 nếu chưa cài r.
Lưu ý: Nếu lớp không có hàm khởi tạo nào, trình biên dịch sẽ cung cấp một hàm khởi tạo mặc định không đối số và không code trong nó.
Nếu trong lớp đã có ít nhất một hàm khởi tạo thì hàm khởi tạo mặc định do trình biên dịch cung cấp sẽ không còn nữa. Khi đó, bạn phải sử dụng các hàm khởi tạo được định nghĩa trong lớp nếu không sẽ gây ra lỗi.
Hàm huỷ sẽ tự động được gọi trước khi giải phóng một đối tượng để giải phóng vùng nhớ trước khi đối tượng được hủy bỏ. Hàm hủy có các đặc điểm sau:
− Mỗi lớp chỉ có một hàm hủy.
− Hàm hủy không có kiểu, không có giá trị trả về và không có đối số.
− Tên hàm huỷ cùng tên với tên lớp và có một dấu ngã (~) ngay trước tên.
Getter và Setter
Là các hàm dùng để set (đặt) hoặc get (lấy) dữ liệu
Static
Static trong C++ là một toán tử có tác dụng chỉ định một biến hoặc hàm thành viên trong class tồn tại ở dạng tĩnh.
Dạng tĩnh ở đây có ý nghĩa, vùng bộ nhớ dùng để lưu trữ các dữ liệu này sẽ là bất biến, không thay đổi.
Bằng việc sử dụng static trong class C++, chúng ta sẽ có được biến static và hàm static, là các thành viên được lưu tại các vùng bộ nhớ bất biến. Vì ở dạng tĩnh nên chúng sẽ tồn tại duy nhất trong class. Chúng có thể sử dụng kể cả không có đối tượng trong class
6.1. Biến static
Để tạo biến static trong class C++, chúng ta thêm toán tử static vào đằng trước tên biến khi khai báo biến trong class như sau. Lưu ý là access modifier của biến static phải ở dạng public để cho phép truy cập nó từ ngoài phạm vi class.
Ưu điểm lớn nhất của biến static đó chính là chúng ta có thể sử dụng trực tiếp nó mà không cần phải tạo ra đối tượng (instance) từ class. Tuy nhiên do không tạo ra instance dẫn đến việc giá trị ban đầu của biến static cũng không được khởi tạo, nên khi dùng biến static mà không tạo ra đối tượng, chúng ta cần phải khởi tạo giá trị cho nó ở bên ngoài phạm vi class.
Ví dụ:
Giống như ví dụ trên, do sNum là biến static nên chúng ta có thể trực tiếp sử dụng giá trị của nó mà không cần phải tạo ra đối tượng từ class. Tuy nhiên biến num thì chỉ là biến thành viên bình thường nên chúng ta không thể sử dụng trực tiếp nó vì lỗi sẽ xảy ra.
6.2. Hàm static
Để tạo hàm static trong class C++, chúng ta thêm toán tử static vào đằng trước tên hàm khi khai báo hàm trong class như sau. Lưu ý là access modifier của hàm static phải ở dạng public để cho phép truy cập nó từ ngoài phạm vi class.
Lưu ý: đối với các hàm static thì các biến sử dụng bên trong phải là biến static
Ví dụ:
Kỹ thuật chia tách file trong C++
Headers file
Khi các chương trình phát triển ngày càng lớn (và sử dụng nhiều file hơn), Việc khai báo các hàm bạn muốn sử dụng được định nghĩa trong cùng một file sẽ trở nên ngày càng tẻ nhạt và làm cho file đó trở lên nhiều dòng code, khó kiểm soát. Sẽ tốt hơn nếu bạn có thể đặt tất cả các khai báo của mình ở một nơi và sau đó định nghĩa chúng khi bạn cần nó.
Viết một file header
Ví dụ chúng ta có hai tệp, add.cpp và main.cpp, trông giống như thế này:
Trong ví dụ này, chúng ta đã sử dụng một khai báo để trình biên dịch sẽ biết định danh add là gì khi biên dịch main.cpp. Chúng ta có thể thấy việc thêm thủ công cho mọi hàm bạn muốn sử dụng trong một file khác khá nhiều và phức tạp.
Hãy viết một file header để giảm bớt gánh nặng này. Viết một file header rất dễ dàng, vì các file header chỉ bao gồm hai phần:
Các tiền chỉ thị trong file header.
Nội dung thực tế của file header, phải là khai báo cho tất cả các định danh mà chúng ta muốn các file khác có thể nhìn thấy.
Sử dụng hậu tố .h khi đặt tên file header
Các file header thường được ghép nối với các file code, với file header cung cấp các khai báo cho file code tương ứng. Vì file header của chúng ta sẽ chứa một khai báo cho các hàm được định nghĩa trong add.cpp, nên chúng ta sẽ gọi file header mới là add.h.
Nếu một file header được ghép nối với một file code (ví dụ: add.h với add.cpp), cả hai sẽ có cùng tên (add).
File add.h
Để sử dụng file header này trong main.cpp, chúng ta phải #include nó (sử dụng dấu ngoặc kép, không phải dấu ngoặc nhọn).
main.cpp
Quy tắc đặt tên biến trong OOP C++
Luôn sử dụng tiếng Anh để đặt tên hàm và biến.
Ví dụ:
/* Bad */
const hoTen = “Trạng Tí”
const banBe = [“Sửu Ẹo”, “Dần Béo”, “Cả Mẹo”]
/* Good */
const fullName = “Trạng Tí”
const friends = [“Sửu Ẹo”, “Dần Béo”, “Cả Mẹo”]
Quy ước đặt tên
Nếu team của bạn chọn quy ước đặt tên là camelCase, hãy sử dụng camelCase cho toàn bộ dự án, nếu bạn qua một team khác chuộng snake_case hơn, hãy tuân thủ nghiêm ngặt. Cho dù là quy ước nào thì điều quan trọng nhất chính là tính nhất quán.
/* Bad */
const page_count = 5
const isUser = true
/* Good */
const pageCount = 5
const isUser = true
Nguyên tắc S-I-D
Short (ngắn gọn): tên không được dài, không phải mất thời gian để gõ và nhớ.
Intuitive (tự nhiên): tên khi đọc lên phải cho cảm giác xuôi tai, gần gũi với văn nói.
Descriptive (súc tích): tên phải mô tả được ý nghĩa, tác dụng của nó, bằng cách hiệu quả nhất.
/* Bad */
const totalNumberOfPublishedArticles = 10 // tên quá dài
const a = 5 // “a” không mô tả được số 5 để làm gì
const isDisplayable = a > 5 // “isDisplayable” nghe không tự nhiên lắm
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
Khi nói về một chương trình Java, do đây là một ngôn ngữ được tạo ra với thiên hướng “Hướng đối tượng” rất lớn, nên chương trình Java có thể tóm tắt bằng việc một tập hợp các vật thể – object tương tác với nhau bằng các hàm, thông số, …
Object – Vật thể: Chứa thông số và các hàm. VD Object Máy tính có thông số CPU, Ram, dung lượng máy, .. có các hàm tương tác như: lướt web, bật máy, …
Class – Lớp: Là một bản gốc chứa các thông số và các hàm mà vật thể được tạo lên
Method – Hàm: Là các hàm tương tác với 1 object
Trước nhất, một cấu trúc chương trình cơ bản trong Java sẽ trông như sau:
Các lưu ý về cú pháp trong Java:
Quan trọng viết hoa: Tức là Hello và hello sẽ khác nhau trong Java
Tên file: Tên một file thường trùng tên với class trong file đó
Hàm Main(): Trong mỗi class luôn cần có method main(), sẽ là thứ đầu tiên được chạy của hàm đó
Nhập xuất
Để nhập vào các dữ liệu từ input phía người dùng trong Java, chúng ta sẽ sử dụng lớp Scanner có sẵn trong Java để nhập vào dữ liệu.
Đầu tiên cần khai báo và import thư viện Scanner
Khởi tạo một object Scanner trong chương trình để đảm nhận việc lấy dữ liệu
Ở đây ta đã lấy dữ liệu cho một biến int – tương tự như C, là một kiểu dữ liệu lưu số nguyên bằng hàm nextInt().
Cú pháp:
(data-type) (variable-name) = scan.next…();
Ta cần thay trong dấu “…” bằng phương thức ta muốn:
Phương thức
Mô tả
nextByte()
Đọc một số nguyên kiểu byte
nextShort()
Đọc một số nguyên kiểu short
nextInt()
Đọc một số nguyên kiểu int
nextLong()
Đọc một số nguyên kiểu long
nextFloat()
Đọc một số kiểu float
nextDouble()
Đọc một số kiểu double
next()
Đọc một string kết thức trước một ký tự trắng
nextLine()
Đọc một line of text (kết thúc bằng phím Enter)
Ví dụ: Nhập một string.
Trong Java cũng gặp tình trạng bị trôi lệnh khi nhập 1 string ngay sau khi nhập 1 số. Cách sử lý là dùng thêm 1 lần nhập scan.nextLine() trước khi nhập string.
Để in ra dữ liệu trong Java
Sử dụng System.out.println();
Xuất kết quả ra màn hình đồng thời con trỏ chuột nhảy xuống dòng tiếp theo
Sử dụng System.out.print();
Xuất kết quả ra màn hình nhưng con trỏ chuột không xuống dòng.
Sử dụng System.out.printf();
Xuất ra màn hình kết quả đồng thời có thể định dạng được kết quả đó nhờ vào các đối số thích hợp. (đặc tả)
Giống trong C và CPP.
Ví dụ chương trình nhập vào a, b, c và in ra a+b+c
Biến
Khai báo: Data-type Variable-name = giá trị;
Biến trong Java có 3 loại, mỗi loại nằm ở vị trí riêng:
Biến thực thể (instance variable): nằm trong class, không thuộc method nào. Biến này thuộc về các thực thể (instance – object) được tạo ra từ class.
Biến tĩnh (static variable): tương tự biến thực thể, nhưng có từ khóa static để đánh dấu biến thuộc về class, không phải object.
Biến cục bộ (local variable): được khai báo trong method.
Toán tử
Các toán tử trong java tương tự như C++:
Toán tử tăng giảm (increment, decrement): a++, ++a, a–, –a
Toán tử thuận và đối (position, negation): +a, -a
Toán tử số học (arithmetic): a + b, a – b, a * b, a / b (chia nguyên), a % b (chia dư)
Toán tử ba ngôi (ternary): a > b ? a : b và có thể lồng nhau như (a > 0) ? “Dương” : (a < 0) ? “Âm” : “Số không”
Toán tử gán (assignment): phép gán a = 5 và phép gán kết hợp như a += 5, a -= 3
Toán tử quan hệ (relational): So sánh bằng a == 5, khác a != 5, lớn a > 5, bé a < 5, lớn hơn hoặc bằng a >= 5, bé hơn hoặc bằng a <= 5.
Toán tử logic (thực hiện trên boolean): phép and a && b, or a || b và not !a
Toán tử thao tác bit (bitwise): gồm and 10 & 3, or 10 | 3 và not !10. Các phép bitwise thực hiện trên số nguyên, và kí hiệu chỉ gồm 1 dấu.
Toán tử dịch chuyển bit (bit shifting): phép dịch trái x << y (nhân 2^y), dịch phải điền cùng dấu x >> y (chia nguyên 2^y) và dịch phải điền 0 (zero filled – chia nguyên lấy trị tuyệt đối cho 2^y) x >>> y.
Câu lệnh rẽ nhánh if else
Lệnh if else tương tự như trong C++. Nếu điều kiện trong if đúng thì thực hiện lệnh, nếu không thì đi tiếp hoặc thực hiện lệnh trong else (nếu có).
Ngoài ra ta có thể thay if else bằng toán tử 3 ngôi hoặc switch-case với cấu trúc giống như C++.
Vòng lặp
While loop
Vòng lặp while kiểm tra điều kiện, nếu đúng thì thực hiện lệnh, sau đó quay lại kiểm tra điều kiện lần nữa,… cho tới khi điều kiện sai thì dừng.
Do while loop
Lặp do while khác với while chút xíu, là do while sẽ thực hiện lệnh trước rồi mới check điều kiện. Do đó, lệnh luôn được thực hiện ít nhất một lần.
Cả hai vòng lặp do while và while cần tránh lặp vô tận.
For loop
Lệnh lặp for gồm 3 phần trong ngoặc tròn:
Phần init dùng khởi tạo biến đếm
Phần condition chỉ định điều kiện lặp tiếp
Phần increment dùng tăng, giảm biến đếm, để tới lúc nào đó điều kiện trở thành false.
Java có một vòng lặp khác, gọi là for each nhưng vẫn dùng từ khóa for, nhưng theo cú pháp khác.
Mảng – Array
Cần import thư viện Array để sử dụng
Khai báo mảng: Data-type Array-name
Truy cập một phần tử trong mảng: Tên mảng[vị trí] – giống với C++ a[x]
Bằng các cú pháp nhập xuất tương tự C++, có thể triển khai sắp xếp, làm việc trên mảng
Wrapper Class
Lớp Wrapper sẽ giúp chúng ta chuyển đổi qua lại giữa một kiểu dữ liệu nguyên thủy sang kiểu dữ liệu đối tượng và ngược lại.
Kiểu nguyên thủy
Kiểu Wrapper
boolean
Boolean
char
Character
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
int a = 5;
a.ham()
Integer a = 5; a.ham()
Chuyển đổi một kiểu nguyên thủy sang kiểu Wrapper của nó người ta gọi là Boxing. Ngược lại, khi bạn chuyển từ một kiểu Wrapper sang kiểu nguyên thủy của nó người ta gọi là Unboxing.
Một số cấu trúc khác bên trong ngôn ngữ Java, như ArrayList hay Vector đều chứa đựng các tập hợp kiểu dữ liệu đối tượng thay vì kiểu nguyên thủy, nên việc biết và vận dụng các lớp Wrapper là một bắt buộc.
Ngoài ra thì kiểu dữ liệu đối tượng sẽ thích hợp hơn trong việc thực thi đa luồng (multithreading) và đồng bộ hóa (synchronization).
Các phương thức với Wrapper class:
…Value(): giúp chuyển đổi một giá trị của lớp Wrapper nào đó về kiểu dữ liệu nguyên thủy (unboxing).
parse…(“”): Tham số truyền vào cho phương thức là một chuỗi, kết quả nhận được là một giá trị nguyên thủy tương ứng với chuỗi truyền vào.
toString(): chuyển đổi từ liểu dữ liệu Wrapper thành string.
String Class
String không phải kiểu dữ liệu nguyên thuỷ, mà một đối tượng của class String.
Cần import thư viện
Class String chứa các hàm có chức năng tương đồng với kiểu dữ liệu chuỗi của các ngôn ngữ khác như C++, Python, có thể kể đến vài hàm chính như:
length() : Trả về độ dài chuỗi
charAt(i): Kí tự ở vị trí i ;
trim(): Bỏ đi khoảng trắng hai đầu
replace(): Thay đổi hết các đoạn chuỗi con thành đoạn chuỗi con mới
Và rất nhiều hàm khác được tích hợp sẵn
Math Class
Là lớp chứa các phương thức, hỗ trợ Toán Học trong Java, tương tự C++, có rất nhiều hàm được dùng phổ biến như:
Pow : Luỹ thừa
Sqrt: Lấy căn
Sin, cos, tan: Lượng giác
Floor, Ceil: Làm tròn
Và nhiều hàm hỗ trợ khác cho các công việc đặc thù.
Regex
Thuật ngữ Regex viết tắt của Regular expression. Nó là một chuỗi ký tự khác nhau diễn tả một mẫu tìm kiếm cụ thể. Nó cũng được gọi là Rational expression.
Nó được dùng để tìm kiếm và thao tác trên chuỗi văn bản. Nói một cách dễ hiểu là bạn có thể tìm một một mẫu dễ dàng và thay thế chúng bằng những mẫu phù hợp với sự giúp đỡ của biểu thức chính quy.
Pattern Class: (Lớp khuôn mẫu)
Đây là phiên bản biên dịch của một biểu thức chính quy. Nó được sử dụng để xác định một khuôn mẫu cho các biểu thức chính quy.
Lớp này có phương thức Compile(), ta sẽ truyền Xâu cần so khớp vào trong phương thức này, và nó sẽ trả về 1 đối tượng Pattern.
No.
Phương thức
Mô tả
1
static Pattern compile(String regex)
biên dịch regex đã cho và trả về thể hiện của Pattern.
Nó biên dịch biểu thức chính quy và tìm kiếm các chuỗi con từ chuỗi input phù hợp với mẫu regex.
4
String[] split(CharSequence input)
chia chuỗi input đã cho thành mảng các kết quả trùng khớp với mẫu đã cho.
5
String pattern()
trả về mẫu regex.
Matcher Class – Lớp so sánh
Lớp Matcher thực thi interface MatchResult. Nó được sử dụng để thực hiện các hoạt động so khớp trên một chuỗi ký tự.
Thực hiện chức năng So khớp chính.
Ta sẽ có được 1 đối tượng Matcher khi gọi tới phương thức matcher() trên một đối tượng Pattern.
Ta truyền Xâu đầu vào – Xâu cần so khớp vào matcher() và xem xem nó có chứa mẫu mong muốn xuất hiện.
No.
Phương thức
Mô tả
1
boolean matches()
kiểm tra xem biểu thức chính quy có khớp với mẫu hay không.
2
boolean find()
tìm biểu thức tiếp theo khớp với mẫu.
3
boolean find(int start)
tìm biểu thức tiếp theo khớp với mẫu từ số bắt đầu đã cho.
4
String group()
trả về chuỗi con phù hợp.
5
int start()
trả về vị trí bắt đầu của chuỗi con phù hợp.
6
int end()
trả về vị trí kết thúc của chuỗi con phù hợp.
7
int groupCount()
trả về tổng số các chuỗi con phù hợp.
Cú pháp Regex
No.
Biểu thức chính quy
Mô tả
1
.
Khớp (match) với bất kỳ ký tự nào
2
^regex
Biểu thức chính quy phải khớp tại điểm bắt đầu
3
regex$
Biểu thức chính quy phải khớp ở cuối dòng.
4
[abc]
Thiết lập định nghĩa, có thể khớp với a hoặc b hoặc c.
5
[abc][vz]
Thiết lập định nghĩa, có thể khớp với a hoặc b hoặc c theo sau là v hay z.
6
[^abc]
Khi dấu ^ xuất hiện như là nhân vật đầu tiên trong dấu ngoặc vuông, nó phủ nhận mô hình. Điều này có thể khớp với bất kỳ ký tự nào ngoại trừ a hoặc b hoặc c.
7
[a-d1-7]
Phạm vi: phù hợp với một chuỗi giữa a và điểm d và con số từ 1 đến 7.
8
X |∣ Z
Tìm X hoặc Z.
9
XZ
Tìm X và theo sau là Z.
10
$
Kiểm tra kết thúc dòng.
11
\d
Số bất kỳ, viết ngắn gọn cho [0-9]
12
\D
Ký tự không phải là số, viết ngắn gon cho [^0-9]
13
\s
Ký tự khoảng trắng, viết ngắn gọn cho [ \t\n\x0b\r\f]
14
\S
Ký tự không phải khoản trắng, viết ngắn gọn cho [^\s]
15
\w
Ký tự chữ, viết ngắn gọn cho [a-zA-Z_0-9]
16
\W
Ký tự không phải chữ, viết ngắn gọn cho [^\w]
17
\S+
Một số ký tự không phải khoảng trắng (Một hoặc nhiều)
18
\b
Ký tự thuộc a-z hoặc A-Z hoặc 0-9 hoặc , viết ngắn gọn cho [a-zA-Z0-9].
19
*∗
Xuất hiện 0 hoặc nhiều lần, viết ngắn gọn cho {0,}
20
++
Xuất hiện 1 hoặc nhiều lần, viết ngắn gọn cho {1,}
21
??
Xuất hiện 0 hoặc 1 lần, ? viết ngắn gọn cho {0,1}.
22
\{ X \}{X}
Xuất hiện X lần, {}
23
\{ X, Y \}{X,Y}
Xuất hiện trong khoảng X tới Y lần.
24
*?∗?
* có nghĩa là xuất hiện 0 hoặc nhiều lần, thêm ? phía sau nghĩa là tìm kiếm khớp nhỏ nhất.
Class và Object – Java OOP
Encapsulation (Tính đóng gói)
Tính đóng gói trong java là kỹ thuật ẩn giấu thông tin không liên quan và hiện thị ra thông liên quan. Mục đích chính của đóng gói trong java là giảm thiểu mức độ phức tạp phát triển phần mềm. Tức là thiết kế để các thuộc tính và phương thức thuộc về (bên trong) một lớp.
Với các access modifier, tính đóng gói sẽ có thể giúp ngăn chặn những lớp bên ngoài truy cập, thay đổi thuộc tính và phương thức của một lớp. Từ đó, giúp cho việc che giấu dữ liệu, để bảo vệ trạng thái bên trong của một đối tượng. Hơn nữa, việc ẩn giấu các biến thì các lớp sẽ không chia sẻ thông tin với nhau được. Điều này làm giảm số lượng khớp nối có thể có trong một ứng dụng.
Ví dụ: Các biến của class đều ở private và chỉ truy cập được qua các phương thức public.
Tính kế thừa
Tính kế thừa trong Java là một cơ chế trong đó một đối tượng có được tất cả các thuộc tính và hành vi của một đối tượng cha.
Khi bạn kế thừa từ một class có sẵn, bạn có thể tái sử dụng các phương thức và trường của class cha. Hơn nữa, bạn có thể thêm các phương thức và trường mới trong class hiện tại.
Sử dụng tính kế thừa, ta có thể thực hiện Method Overriding, từ đó xuất hiện tính Đa hình trong runtime.
Phân loại:
Đơn kế thừa.
Kế thừa nhiều cấp.
Kế thừa thứ bậc.
Đa kế thừa và Kế thừa hỗn hợp không được hỗ trợ thông qua Class trong Java, nhưng vẫn được hỗ trợ thông qua Interface.
Cú pháp: sử dụng từ khóa extends
Ngoài ra còn có từ khóa super để tham chiếu trực tiếp đến đối tượng của lớp cha gần nhất.
Sử dụng từ khóa super.xxx để gọi đến phương thức xxx của lớp cha gần nhất.
Sử dụng super() để gọi trực tiếp constructor (hàm tạo) của lớp cha gần nhất.
Polymorphism (Tính đa hình).
Đa hình là ta có thể thực hiện một hành động bằng nhiều cách khác nhau.
Có hai kiểu của đa hình trong java, đó là đa hình lúc biên dịch (compile) và đa hình lúc thực thi (runtime). Chúng ta có thể thực hiện đa hình trong java bằng cách method overriding (ghi đè phương thức) và method overloading (nạp chồng phương thức).
Ghi đè phương thức: method overriding – ghi đè method ở lớp cha trong lớp con, ta chỉ cần viết code thực thi khác của method đó ở trong lớp con là được.
Nạp chồng phương thức : method overloading – Trong một class có thẻ có nhiều method cùng tên nhưng khác nhau tham số truyền vào và dữ liệu trả về, cách hoạt động khác nhau.
Abstract Classes (Lớp trừu tượng).
Một phương thức được khai báo là abstract và không có code thực thi thì đó là phương thức trừu tượng, (giống virtual trong C++), được khai báo với từ khóa abstract ở trước.
Lớp trừu tượng thường được dùng để kế thừa. Và lớp trừu tượng không thể tạo ra instance.
Lớp abstract là lớp có các abstract method (Phương thức trừu tượng) (Có thể có hàm không trừu tượng)
Phương thức trừu tượng (abstract method)
Một phương thức được khai báo là abstract và không có trình triển khai thì đó là phương thức trừu tượng.
Nếu muốn một lớp chứa một phương thức cụ thể nhưng bạn muốn triển khai thực sự phương thức đó để được quyết định bởi các lớp con, thì bạn có thể khai báo phương thức đó trong lớp cha ở dạng abstract.
Interface
Là một bản thiết kế của một lớp. Nó chỉ có các phương thức trừu tượng. Interface là một kỹ thuật để thu được tính trừu tượng hoàn toàn và đa kế thừa trong Java. Nó không thể được khởi tạo giống như lớp trừu tượng.
Một interface khác với một class ở một số điểm sau đây:
Không thể khởi tạo interface, interface không có Constructor
Phương thức interface đều phải là abstract (Khác lớp trừu tượng vẫn có thể có phương thức không trừu tượng)
Tất cả trường interface đều là static hoặc final
Interface chỉ có thể kế thừa từ interface
Modifiers
Có hai loại Modifier trong Java, đó là: Access Modifier và Non-access Modifier.
Tương tự OOP trong C++, trong Java có 4 phạm vi truy cập của Access Modifier như sau:
private
default
protected
public
Access Modifier
Trong lớp
Trong package
Ngoài package bởi lớp con
Ngoài package
Private
Y
N
N
N
Default
Y
Y
N
N
Protected
Y
Y
Y
N
Public
Y
Y
Y
Y
Lưu ý:
Constructor cần để public để có thể thực hiện tính Kế thừa.
Nếu không khai báo Access Modifier, thì nó mặc định là default.
Protected access modifier được truy cập bên trong package và bên ngoài package nhưng phải kế thừa.
Ngoài ra có thêm final dùng để hạn chế người dùng:
final variable: không thể thay đổi giá trị (hằng số)
Chào các bạn, mình là Nguyễn Quốc Hưng. Tại thời điểm cuối cập nhật bài viết này (9/2023), mình là sinh viên năm 3 ngành CNTT CLC của PTIT. Sau một năm học trong ngành này, mình hi vọng những chia sẻ của mình có thể phần nào giúp các bạn hiểu rõ hơn về ngành Công nghệ thông tin (CLC) của trường.
KÌ THI XÉT TUYỂN
Những ngành có thể tham gia kì thi lên CLC:
Điện tử viễn thông
An toàn thông tin
Điện tử
Công nghệ thông tin
Khoa học máy tính
… Có thể sẽ có các ngành mới mỗi năm trường thêm
Để chuyển lên ngành CLC, đầu tiên bạn sẽ cần thi một kì thi tiếng anh vì ngành CNTT CLC để liên quan khá nhiều đến tiếng anh. Bài thi dùng để xét tuyển sẽ là TOEFL ITP do IIG hợp tác với trường tổ chức.
Theo như thời điểm mình thi, thì khoảng 360-400 điểm (Bạn có thể tham khảo quy đổi bên dưới) đã đủ để đỗ, và tổng sinh viên một khóa sẽ khoảng 200 sinh viên (5 lớp). Nếu bạn có chứng chỉ tiếng anh đổi điểm sẵn, bạn sẽ được phân vào lớp E1,E2 với chương trình học khá nhàn ở năm 1 và năm 2. (Do năm 1 năm 2 ngành CLC có khoảng 4 kíp tiếng anh một tuần – 8 tiếng) và nếu bạn đã có chứng chỉ thì sẽ được nghỉ hết các môn đó.
Nếu bạn ở các khoa điện tử viễn thông, điện tử có chương trình học ban đầu thường hướng nhiều về phần cứng hơn, nhưng sau khi thi lên ngành CNTT CLC, bạn sẽ chuyển hoàn toàn chương trình sang Công nghệ thông tin CLC khá giống với ngành Công nghệ thông tin bình thường.
Đầu tiên, các môn chuyên ngành (lập trình) và toán sẽ được dạy bằng tiếng anh. Bài giảng tiếng anh, thi bằng tiếng anh, thầy cô một số cũng dạy bằng tiếng anh nhưng đa số vẫn là tiếng việt. Tuy nhiên tiếng anh khá là nhẹ, nên bạn không cần quá lo lắng về vấn đề này. Dù các bài tập, kì thi đều là tiếng anh, nhưng bạn hoàn toàn vẫn có thể học từ các tài liệu tiếng việt và thi bình thường.
Các môn chuyên ngành hệ thường tại năm 1, năm 2
Kì 1: Tin học cơ sở 1 : Word, Excel, Powerpoint, máy tính, …
Kì 2: Tin học cơ sở 2: Lập trình C
Kì 3: Ngôn ngữ lập trình C++, Toán rời rạc 1
Kì 4: Cấu trúc dữ liệu và giải thuật
Các môn chuyên ngành hệ CLC tại năm 1, năm 2
Kì 1: Introduction to Programming: Lập trình C + Word Excel PowerPoint
Kì 2: Programming with C++: Lập trình C++
Kì 3: Toán rời rạc 1, Data Structure and Algorithm (Cấu trúc dữ liệu và giải thuật)
Như chương trình trên, bạn sẽ được tiếp cận với code sớm hơn hệ thường 1 kì. Điều này mang lại lợi thế khá lớn cho các bạn tham gia vào các câu lạc bộ học thuật, các kì thi trong trường
Ý kiến cá nhân: Việc được tiếp cận các môn code sớm cho mình lợi thế khá lớn khi tham gia các câu lạc bộ trong trường và các kì thi.
Các đề thi thường được dễ hơn hệ thường nên bạn sẽ nhẹ nhàng hơn để tập trung vào môn chuyên ngành.
Điểm của CLC cũng thường nhỉnh hơn khá rõ. (Môn giải tích của CLC còn cho phép mang tài liệu tham khảo vào phòng thi do thi tiếng anh)
Làm đồ án của ngành CLC chỉ cần 2.6 GPA, trong khi hệ thường là 2.9.
Môn tiếng anh tại ngành cũng được học khá nhiều (8 tín), nên nếu bạn đổi điểm tiếng anh sau này thì toàn bộ môn này là 10, buff khá nhiều điểm gpa so với hệ thường.
CƠ SỞ VẬT CHẤT – GIẢNG DẠY
Cho đến thời điểm hiện tại của bài viết (9/2023):
Hệ CLC sẽ học ở tòa A1, và hệ thường học ở tòa A2
Điều hòa của CLC sẽ nhiều hơn và có trong cả sảnh.
Các bạn dự định học cao, thạc sĩ, … thì khá dễ vào lab riêng của CLC, chỉ cần thể hiện tốt và liên hệ trực tiếp với thầy cô giảng dạy để xin vào đội làm lab.
Bạn phải đóng x1.25-2 tiền học phí của mọi môn. Kể cả những thứ bạn không nhận được hơn gì cả (VD: Tiền học phí quốc phòng)
Wifi Free mạnh hơn tòa A2 của hệ thường
Nhà vệ sinh đẹp hơn A2
Ghế công thái học, trong lớp nhiều ổ điện hơn A2.
Thầy cô dạy đa số là trưởng khoa, top trong trường, ở hệ thường sẽ cần tranh đấu để có slot học, tại CLC bạn sẽ được phân bổ tự động
Có nhiều hội thảo tiếng anh
CIE PTIT – Đào tạo quốc tế có vẻ được trường khá quan tâm, nên trong tương lai mình nghĩ cơ sở vật chất, chất lượng sẽ được ưu tiên cải thiện nhiều hơn