[Tự học lập trình Java] Biến và các kiểu dữ liệu nguyên thủy trong Java

 

Biến (Variables) và kiểu dữ liệu.

Các đối tượng được lưu trữ trạng thái trong các thuộc tính. Tuy nhiên trong ngôn ngữ lập trình Java, chúng được gọi là các biến. Trong mục này sẽ trình bày các mối quan hệ, vai trò và những quy ước khi sử dụng tên biến, các kiểu dữ liệu cơ bản (Dữ liệu nguyên thủy, kiểu chuỗi, mảng), giá trị mặc định…

Java Programming - Tinhoccoban.net


  Mục lục seri các bài viết hướng dẫn tự học lập trình Java:

Trong chương 1, chúng ta đã biết, một đối tượng được lưu trữ bởi các thuộc tính. Biến cũng giống như vậy, trước hết nó là một đối tượng. Ví dụ:

int cadence = 0;

int speed = 0;

int gear = 1;

Trong phần định nghĩa một đối tượng, chúng ta đã được giới thiệu các trường (thuộc tính). Tuy nhiên hẳn sẽ còn một vài câu hỏi lien quan như: Các vai trò và các quy ước với các tên thuộc tính là gì? Bên trong từ khóa int hoặc các kiều dữ liệu khác hàm chứa điều gì? Các trường dữ liệu đó có được khởi gán khi chúng ta định nghĩa biến. Các biến được khởi gán giá trị mặc định nếu chúng không được khởi tạo rõ ràng. Chúng ta sẽ tìm hiểu các câu trả lời trong chương này, tuy nhiên trước đó chúng ta sẽ tìm hiểu một vài khái niệm công nghệ trước khi đi tiếp.

Trong ngôn ngữ lập trình Java, các khái niệm thuộc tính hoặc biến đều được sử dụng, nhưng với những lập trình viên mới thì hai khái niệm này nó như là giống nhau.

Trong ngôn ngữ lập trình Java định nghĩa các loại biến sau:

 Instance Variables: Biến (Không phải biến tĩnh) khái niệm của loại biến này được định nghĩa là không phải biến tĩnh, loại biến này khi định nghĩa thì không cần sử dụng từ khóa static. Biến không tĩnh được biết đến chính là Instance Variables bởi vì các giá trị của biến là duy nhất cho mỗi thể hiện (instance) của một lớp (mỗi đối tượng của một lớp khác nhau là khác nhau) ví dụ thuộc tính currentSpeed  của một chiếc xe đạp sẽ khác với thuộc tính currentSpeed  của một chiếc xe khác. Đôi khi cũng sẽ gây nhầm lẫn đối với các lập trình viên mới.

Class Variables (Static Fields): Biến tĩnh: Một biến bất kỳ được của loại này được định nghĩa với từ khóa static nói lên rằng trình biên dịch sẽ chỉ lấy một bản copy của biến này để dùng cho tất cả các trường hợp sử dụng biến bất kể biến đó được dùng bao nhiêu lần. Ví dụ: định nghĩa một trường là các bánh răng của một loại xe đạp được định nghĩa bởi tử khóa static thì kể từ đó, con số này là cố định. Như đoạn code:

static int numGears = 6;

Đoạn code này sẽ tạo ra một trường tĩnh. Thêm nữa, từ khóa final có thể được thêm vào để biểu thị số bánh răng này là không bao giờ thay đổi trong suốt chương trình.

 Local Varialbes Tương tự như một đối tượng được lưu trữ trạng thái trong các thuộc tính (trường), một phương thức sẽ thường lưu trữ tạm thời trong các biến cục bộ (Local Variables). Cú pháp khai báo biến cục bộ tương tự như khai báo các biến khác. Ví dụ:

int count = 0;

 Ở đây không có từ khóa đặc biệt để khai báo biến cục bộ, và nó chỉ được sử dụng trong phần mà biến đó được khai báo (thường là trong các phương thức). Biến cục bộ không được truy cập từ ngoài lớp hoặc phương thức nó khai báo.

 Parameters: Biến tham số. Chúng ta xem xét ví dụ về biến tham chiếu, cả trong lớp Bicycle và trong hàm main cho ứng dụng “Hello world”, hàm main được viết như sau:

 public static void main(String[] args)

Ở đây biến args là một biến tham số. Điều quan trọng cần nhớ đó là biến tham số luôn luôn là biến và không phải là thuộc tính.

Có thể nói rằng, vấn đề chính được đưa ra bàn ở đây là các thuộc tính và các biến. Nếu chúng ta nói thuộc tính chung chung (bao gồm biến cục bộ và biến tham số) thì chúng ta có thể nói là thuộc tính (trường). Nhưng nếu bàn tính áp dụng thì có thể nói tất cả đều là biến. Trong trường hợp này phân loại ra sẽ có các mục (trường tĩnh, biến cục bộ, v.v..) là phù hợp nhất. Nhưng thỉnh thoảng, ta xem nó như là thành viên. Một kiểu thuộc tính, các phương thức các kiểu lồng nhau có thể được gọi chung là các thành viên.

Hiểu một cách đơn giản: Biến là vùng nhớ được đặt tên có kích thước bằng với kích thước của kiểu dữ liệu.

Định danh:

Tất cả các ngôn ngữ lập trình đều có đặt ra các quy tắc và quy ước cho việc đặt tên. Ngôn ngữ lập trình Java cũng không ngoại lệ. Các quy tắc và quy ước cho việc đặt tên biến có thể tóm lại như sau:

Tên biến phân biệt chữ hoa và chữ thường. Một biến có thể được tạo thành từ các chữ cái unicode, dấu đô la ‘$’ và dấu gạch dưới ‘_’ tuy nhiên không được bắt đầu bằng dấu đô la ‘$’ hoặc gạch dưới ‘_’ và không giới hạn độ dài. Thêm nữa, Java đã quy định dấu đô la không được sử dụng trong tên biến. Bạn có thể tìm được một vài tình huống sử dụng tên tự động sẽ bao gồm dấu đô la, nhưng tên biến thì nên tránh. Tương tự quy ước đã tồn tại ký tự gạch dưới được bắt đầu tên biến, nhưng khuyên không nên sử dụng. Khoảng trắng trong tên biến là không được phép.

Dãy ký tự, số, ký tự đô la hoặc ký tự gạch dưới. Quy ước (phổ dụng) áp dụng. Khi chọn tên biến, nên sử dụng cả từ, tránh các từ viết tắt khó hiểu. Hãy tạo nên các dòng code dễ đọc và dễ hiểu. Trong nhiều trường hợp chúng ta có thể dử dụng các từ văn bản mô tả để đặt tên, các thuộc tính cadencespeed, gear chẳng hạn, đặt tên biến khó hiểu là c,s,g cho các thuôc tính kia. Có thể chọn từ mang tính gợi ý.

Nếu tên được chọn bao gồm một từ, có thể sử dụng toàn bộ đánh vần của từ đó, nếu có từ 2 từ trở lên, hãy viết hoa chữ cái đầu tiên của các từ tiếp theo. Ví dụ: gearRatio, currentGear, nếu biến chứa giá trị là các hằng số thì có thể viết hoa toàn bộ biến đó. Ví dụ

final int NUM_GEARS = 6

Kiểu dữ liệu nguyên thủy.

Trong ngôn ngữ lập trình Java có kiểu biến tĩnh, những biến mà phải định nghĩa trước khi sử dụng. Liên quan đến kiểu biến, tên biến. Ví dụ:

int gear = 1;

Trong ví dụ trên, tên biến là ‘gear’ có kiểu dữ liệu là kiểu số, khởi gán giá trị ban đầu bằng “1”. Quyết định kiểu dữ liệu cho một biến và giá trị của nó bao gồm các phép toán thực thi trên đó. Ngoài kiều int, ngôn ngữ lập trình Java hỗ trợ 7 kiểu dữ liệu nguyên thủy khác. Mỗi kiều dữ liệu này được định nghĩa trước bởi ngôn ngữ là từ khóa đặt. Các giá trị nguyên thủy không chia sẻ được với nhau. Tám kiểu dữ liệu nguyên thủy được hỗ trợ trong Java là: byte, short, int, long, float, double, boolean.

Kiểu byte: Kiểu dữ liệu byte là kiểu dữ liệu có dấu và có kích thước 8-bit. Giá trị nhỏ nhất từ -128 và giá trị lớn nhất là 127. Kiểu dữ liệu này là tiện ích tiết kiệm bộ nhớ trong các mảng lớn. Kiểu này có thể được sử dụng thay thế cho kiểu int.

Kiểu short: Kiểu dữ liệu short là kiểu dữ liệu có dấu và có kích thước 16-bit. Giá trị nhỏ nhất của kiểu này là -32 768 và giá trị lớn nhất mà nó có thể biểu diễn được là 32767. Cũng giống với kiểu byte, bạn cũng có thể dùng kiểu này để tiết kiệm bộ nhớ cho các mảng lớn, là một giải pháp quan trọng trong việc tiết kiệm bộ nhớ.

Kiểu int: Mặc định, kiểu dữ liệu int là kiểu dữ liệu có dấu và có kích thước 32-bit, giá trị nhỏ nhất mà nó biểu diễn được là -231 và giá trị lớn nhất mà nó biểu diễn được là 231-1. Từ Java SE 8 trở đi bạn có thể sử dụng kiểu dữ liệu này để biểu diễn kiểu dữ liệu số nguyên không dấu. Tức là giá trị nhỏ nhất là 0 và giá trị lớn nhất mà nó biểu diễn được là 232-1. Sử dụng lớp Interger là lớp sử dụng kiểu dữ liệu int, là số nguyên không dấu. Lớp số nguyên này có được nhiểu thông tin hơn. Các phương thức tĩnh như compareUnsigneddivideUnsigned vân vân đã được thêm lớp số nguyên Interger hỗ trợ các phép toán cho các số nguyên không dấu.

Tám kiểu dữ liệu nguyên thủy trong Java

Kiểu long: Kiểu long là kiểu dữ liệu có kích thước 64-bit. Kiểu long có dấu, biểu diễn được các số từ  -263 đến 263-1. Từ Java SE 8 trở đi, bạn có thể sử dụng kiểu dữ liệu này cho số nguyên không dấu 64-bit, có thể biểu diễn được các số từ 0 đến 264-1. Sử dụng kiểu dữ liệu này khi bạn cần phạm vi giá trị lớn hơn so với phạm vi giá trị của kiểu int. Lớp Long, bao gồm các phương thức như compareUnsigneddivideUnsigned vân vân để hỗ trợ các phép toán cho số nguyên không dấu long.

Kiểu double: Kiểu dữ liệu double biểu diễn chính xác sau dấu phẩy được754 số. Chúng ta không bàn đến phạm vi giá trị của nó ở đây. Nhưng trong Java, khi sử dụng các số thập phân, thì mặc định kiểu dữ liệu này được chọn. Các lớp có sử dụng kiểu dữ liệu này có thể kế đến các lớp đặc biệt như: Floating-Point Types, Formats, và Values.

Kiểu boolean: Kiểu dữ liệu boolean là kiểu dữ liệu chỉ bao gồm 2 giá trị true và false. Sử dụng kiểu dữ liệu này để làm cờ đơn giản như điều kiện true/flase. Kiểu dữ liệu này có kích thước 1-bit.

Kiểu char: Kiểu dữ liệu char là kiểu dữ liệu không dấu Unicode 16-bit. Phạm vi biểu diễn của kiểu dữ liệu này là từ '\u0000'(hoặc 0) đến '\uffff' (hoặc 65,535).

Ngoài tám kiểu dữ liệu nguyên thủy kể trên, ngôn ngữ lập trình Java cũng đặc biệt cung cấp một kiểu dữ liệu kiểu chuỗi nằm trong lớp java.lang.String. Chuỗi ký tự không bao gồm các dấu phẩy động, đối tượng của lớp String, ví dụ:

String s = "this is a string"

Các đối tượng của lớp String là không thay đổi, có nghĩa là một khi được tạo ra, giá trị của nó không thể thay đổi. Lớp String không thuộc kiểu dữ liệu nguyên thủy nhưng nó được đặc biệt nhắc tới vì nó hỗ trợ cho ngôn ngữ lập trình một cách tương tự dữ liệu nguyên thủy.

Các giá trị mặc định của kiểu dữ liệu nguyên thủy.


Các giá trị mặc định của kiểu dữ liệu nguyên thủy - tinhoccoban.net


Không cần khởi gán các giá trị khi định nghĩa các biến. Các biến (fields) được định nghĩa mà không khởi tạo sẽ nhận các giá trị mặc định khi biên dịch. Các giá trị này ở trong bảng giá trị mặc định. Có thể nói mặc định là không (zero) hoặc null, phụ thuộc vào từng kiểu dữ liệu. Dựa vào các giá trị mặc định, tuy nhiên nó xác định phong cách lập trình không tốt. Tóm lại các giá trị mặc định cho các biến phụ thuộc vào các kiểu dữ liệu như trong bảng giá trị mặc định.

Các biến cục bộ địa phương (Local variables) thì khác, trình biên dịch không bao giờ gán giá trị mặc định cho một biến chưa được khởi tạo giá trị ban đầu. Nếu bạn không gán giá trị khởi tạo cho các giá trị ban đầu cho các biến cục bộ thì cần phải gán giá chị cho chúng trước khi sử dụng. Nếu không kết quả sẽ là quá trình biên dịch chương trình sẽ bị lỗi.

Literals

Bạn có thể nhận thấy rằng từ khóa new không được sử dụng để khởi tạo các giá trị cho biến có kiểu dữ liệu nguyên thủy. Kiểu dữ liệu nguyên thủy là một kiểu dữ liệu đặc biệt được xây dưng cho ngôn ngữ lập trình. Chúng không phải là đối tượng được tạo ra từ các lớp (class). Một literal là một mã nguồn được cố định giá trị, các literal trực tiếp biểu diễn trong mã nguồn của bạn mà không cần tính toán. Giống như đoạn mã nguồn phía dưới đây:

boolean result = true;
char capitalC = 'C';
byte b = 100;
short s = 10000;
int i = 100000;

Literal dạng số (Integer Literals)

Một literal dạng số có kiểu dữ liệu là long nếu nó có kết thúc là L hoặc l, trong trường hợp còn lại thì nó có kiểu dữ liệu là int. Được khuyến khích sử dụng chữ viết hoa L, bởi vì chữ viết thường l đôi khi được nhầm lẫn với số 1.

Toàn bộ các giá trị kiểu byte, short, int và long có thể được tạo ra từ các literal kiểu int. Các giá trị của kiểu dữ liệu long vượt ra ngoài phạm vi giá trị kiểu int có thể được tạo ra bởi các literal kiểu long. Các literal dạng số có thể được thể hiện qua qua hệ thống số sau:

·        Số thập phân: Dựa trên 10 chữ số từ 0 đến 9, đây là số được sử dụng hàng ngày.

·        Số hexa. 16 số bao gồm các số từ 0 đến 9 và các ký tự A đến F.

·        Số nhị phân: 2 số. Bao gồm các số 0 và 1.

Mục đích lập trình nói chung, hệ thống số thập phân là hệ thống duy nhất bạn thường sử dụng. Tuy nhiên nếu bạn cần sử dụng các hệ thống số khác thì cần thêm vào tiền tố 0x để xác định hệ hexa và 0b để các định hệ nhị phân.

// Số 26 kiểu thập phân
int decVal = 26;
// Số 26 kiểu hexa
int hexVal = 0x1a;
// Số 26 kiểu nhị phân
int binVal = 0b11010;

Các Literal dạng số thực (Floating-Point Literals)

Số thực literal có kiểu dữ liệu là float nếu kết thúc số là chữ F hoặc f, tương tự số literal có kiểu dữ liệu là double nếu kết thúc số có thêm D hoặc d.

Các kiểu dấu chấm động (float và double) cũng thể hiện sử dụng chữ E hoặc e (thể hiện số khoa học), F hoặc f (literal số thực 32-bit), và D hoặc d (literal số thực 64-bit), đó là những điều mặc định.

double d1 = 123.4;
// tương tự giá trị d1, nhưng trong thể hiện số khoa học.
double d2 = 1.234e2;
float f1  = 123.4f;

Các Literal dạng chuỗi và ký tự.

Các Literals kiểu char và kiểu String có thể bao gồm bất kỳ các mã Unicode (UTF-16) nào. Nếu như hệ thống và bộ soạn thảo của bạn cho phép, bạn có thể sử dụng các ký tự trực tiếp trong code của bạn hoặc không.

Ngôn ngữ lập trình Java cũng hỗ trợ một vài ký tự đăc biệt cho charString \b (backspace), \t (tab), \n (line feed), \f (form feed), \r (carriage return), \" (double quote), \' (single quote), and \\ (backslash).

Cũng có một ký tự literal đặc biệt là null, có thể bạn cần sử dụng giá trị này cho các kiểu tham chiếu. null có thể được gán cho bất kỳ biến nào ngoại trừ các biến có kiểu dữ liệu nguyên thủy. Bạn có thể làm việc với giá trị null bằng cách kiểm tra giá trị của biến. Do vậy null thường được sử dụng trong lập trình để kiểm tra một vài đối tượng không xác định.

Cuối cùng, các giá trj đặc biệt của các literal được gọi là một lớp literal được sắp xếp bằng cách lấy tên một lớp và thêm “.class” vào. Ví dụ String.class, điều này thể hiện đối tượng thể hiện cho chính kiểu đó.

Sử dụng các ký tự gạch dưới cho các Literal dạng số.

Từ Java SE 7 trở đi, bất kỳ một số nào có các ký tự gạch dưới, có thể xuất hiện bất cứ đâu giữa các số trong Literal dạng số. Tính năng này cho phép bạn phân tách các nhóm chữ số trong dãy literal dạng số và nâng cao hiệu quả đọc code của bạn.

Ví dụ, nếu code cảu bạn bao gồm các số với rất nhiều số thập phân, bạn có thể sử dụng các dấu gạch dưới để phân tách các số thập phân thành các nhóm 3 chứ xố, tương tự bạn đánh dấu câu như dấu phẩy, dấu cách hoặc khoảng trắng.

Ví dụ sau sẽ thể hiện cách này và sử dụng các dấu gạch dưới cho Literal dạng số.

long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi =  3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;

Bạn có thể thay thế các dấu gạch dưới giữa các số, nhưng bạn không thể thay thế dấu gạch dưới đó bằng các khoảng trắng:

-         Ở vị trí bắt đầu và vị trí kết thúc của số.

-         Liền kề dấu chấm của số thập phân trong Literal dạng số thực.

-         Ngay trước chữ F hoặc L.

Ví dụ sau thể hiện các vị trí mà dấu gạch dưới hợp lệ và không hợp lệ trong các Literal dạng số:

// Invalid: không thể đặt dấu gạch dưới
// liền kề dầu chấm của số thập phân
float pi1 = 3_.1415F;
// Invalid: không thể đặt dấu gạch dưới 
// liền kề dấu chấm của số thập phân
float pi2 = 3._1415F;
// Invalid: không thể đặt dấu gạch dưới
// ngay trước ký tự L thể hiện loại số.
long socialSecurityNumber1 = 999_99_9999_L; 
// OK (literal thập phân)
int x1 = 5_2;
// Invalid: Không thể đặt dấu gạch dưới
// ở vị trí kết thúc Literal
int x2 = 52_;
// OK (Literal thập phân)
int x3 = 5_______2; 
// Invalid: không thể đặt dấu gạch dưới
// giữa ký các ký tự 0x thể hiện số hexa
int x4 = 0_x52;
// Invalid: không thể đặt dấu gạch dưới
// tại vị trí bắt đầu số.
int x5 = 0x_52;
//OK (hexadecimal literal)
int x6 = 0x5_2; 
//Invalid: không thể đặt dấu gạch dưới
//tại vị trí kết thúc
int x7 = 0x52_;

Mới hơn Cũ hơn

Biểu mẫu liên hệ