CHÀO! Khi bạn tiến bộ qua CodeGym, bạn đã nhiều lần gặp phải các kiểu nguyên thủy. Dưới đây là danh sách ngắn những gì chúng ta biết về họ:
- Chúng không phải là đối tượng và đại diện cho một giá trị được lưu trữ trong bộ nhớ
- Có một số loại
- Số nguyên: byte , short , int , long
- Số dấu phẩy động (phân số): float và double
- Giá trị logic: boolean
- Các giá trị tượng trưng (để biểu thị các chữ cái và số): char
-
Mỗi loại có phạm vi giá trị riêng:
loại nguyên thủy |
Kích thước trong bộ nhớ |
Phạm vi giá trị |
byte |
8 bit |
-128 đến 127 |
ngắn |
16 bit |
-32768 đến 32767 |
than |
16 bit |
0 đến 65536 |
int |
32 bit |
-2147483648 đến 2147483647 |
dài |
64 bit |
-9223372036854775808 đến 9223372036854775807 |
trôi nổi |
32 bit |
(2 mũ -149) đến ((2 - (2 mũ -23)) * 2 mũ 127) |
gấp đôi |
64 bit |
(-2 mũ 63) đến ((2 mũ 63) - 1) |
boolean |
8 (khi được sử dụng trong mảng), 32 (nếu không được sử dụng trong mảng) |
đúng hay sai |
Nhưng ngoài việc có các giá trị khác nhau, chúng còn khác nhau về dung lượng mà chúng chiếm trong bộ nhớ. Một
int chiếm nhiều hơn một byte. Và một
dài lớn hơn một ngắn. Dung lượng bộ nhớ mà người nguyên thủy chiếm giữ có thể được so sánh với búp bê lồng nhau của Nga:
Mỗi búp bê lồng nhau đều có sẵn không gian bên trong. Búp bê làm tổ càng lớn thì càng có nhiều không gian. Một con búp bê làm tổ lớn (
dài ) sẽ dễ dàng chứa một con búp bê nhỏ hơn
int . Nó dễ dàng phù hợp và bạn không cần phải làm gì khác. Trong Java, khi làm việc với nguyên thủy, điều này được gọi là chuyển đổi ngầm định. Hay nói cách khác, nó được gọi là mở rộng.
Mở rộng trong Java
Đây là một ví dụ đơn giản về chuyển đổi mở rộng:
public class Main {
public static void main(String[] args) {
int bigNumber = 10000000;
byte littleNumber = 16;
bigNumber = littleNumber;
System.out.println(bigNumber);
}
}
Ở đây chúng tôi gán một giá trị byte cho một biến
int . Việc gán thành công mà không gặp bất kỳ sự cố nào: giá trị được lưu trữ trong một byte chiếm ít bộ nhớ hơn giá trị mà một
int có thể chứa. Con búp bê làm tổ nhỏ (giá trị byte) dễ dàng nằm gọn bên trong con búp bê làm tổ lớn ( biến
int ). Sẽ là một vấn đề khác nếu bạn cố gắng làm ngược lại, tức là đặt một giá trị lớn vào một biến mà phạm vi của nó không thể chứa được loại dữ liệu lớn như vậy. Với những con búp bê làm tổ thực sự, con số đơn giản là không phù hợp. Với Java, nó có thể, nhưng có nhiều sắc thái. Hãy thử đặt một
int vào một biến
ngắn :
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = bigNumber;
System.out.println(bigNumber);
}
Lỗi! Trình biên dịch hiểu rằng bạn đang cố gắng làm điều gì đó bất thường bằng cách nhét một con búp bê lồng nhau lớn (
int ) vào trong một con búp bê nhỏ (
short ). Trong trường hợp này, lỗi biên dịch là một cảnh báo từ trình biên dịch: "Này, bạn có
hoàn toàn chắc chắn rằng bạn muốn làm điều này không?" Nếu bạn chắc chắn, thì bạn nói với trình biên dịch:
"Mọi thứ đều ổn. Tôi biết mình đang làm gì!" Quá trình này được gọi là chuyển đổi loại rõ ràng hoặc thu hẹp.
Thu hẹp trong Java
Để thực hiện chuyển đổi thu hẹp, bạn cần chỉ rõ loại mà bạn muốn chuyển đổi giá trị của mình sang. Nói cách khác, bạn cần trả lời câu hỏi của trình biên dịch:
"Chà, bạn muốn đặt con búp bê làm tổ lớn này vào cái nào trong số những con búp bê làm tổ nhỏ này?" Trong trường hợp của chúng tôi, nó trông như thế này:
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = (short) bigNumber;
System.out.println(littleNumber);
}
Chúng tôi chỉ ra rõ ràng rằng chúng tôi muốn đặt một
int vào một biến
ngắn và chúng tôi sẽ chịu trách nhiệm. Thấy rằng một loại hẹp hơn đã được chỉ định rõ ràng, trình biên dịch sẽ thực hiện chuyển đổi. Kết quả là gì? Đầu ra bảng điều khiển:
-27008 Điều đó hơi bất ngờ. Tại sao chính xác chúng ta đã nhận được điều đó? Trên thực tế, tất cả đều rất đơn giản. Ban đầu, giá trị là 10000000. Nó được lưu trữ trong một biến
int , chiếm 32 bit. Đây là đại diện nhị phân của nó:
Chúng tôi viết giá trị này vào một biến
ngắn , chỉ có thể lưu trữ 16 bit! Theo đó, chỉ 16 bit đầu tiên của số của chúng tôi sẽ được chuyển đến đó. Phần còn lại sẽ bị loại bỏ. Kết quả là biến short nhận giá trị như sau
mà ở dạng thập phân bằng -27008 Đó là lý do tại sao trình biên dịch yêu cầu bạn "xác nhận" bằng cách chỉ ra một chuyển đổi thu hẹp rõ ràng sang một loại cụ thể. Đầu tiên, điều này cho thấy rằng bạn đang chịu trách nhiệm về kết quả. Và thứ hai, nó cho trình biên dịch biết cần phân bổ bao nhiêu dung lượng khi quá trình chuyển đổi diễn ra. Xét cho cùng, trong ví dụ trước, nếu chúng ta gán một giá trị int cho biến byte thay vì short
, thì chúng ta sẽ chỉ có 8 bit tùy ý sử dụng chứ không phải 16 và kết quả sẽ khác. Các loại phân số (
float và
double ) có quy trình riêng để thu hẹp chuyển đổi. Nếu bạn thử chuyển một số nhóm thành một loại số nguyên, phần phân số sẽ bị loại bỏ.
public static void main(String[] args) {
double d = 2.7;
long x = (int) d;
System.out.println(x);
}
Đầu ra bảng điều khiển:
2
than
Bạn đã biết rằng
char được sử dụng để hiển thị các ký tự riêng lẻ.
public static void main(String[] args) {
char c = '!';
char z = 'z';
char i = '8';
}
Nhưng loại dữ liệu này có một số tính năng quan trọng cần hiểu. Hãy xem lại bảng phạm vi giá trị:
loại nguyên thủy |
Kích thước trong bộ nhớ |
Phạm vi giá trị |
byte |
8 bit |
-128 đến 127 |
ngắn |
16 bit |
-32768 đến 32767 |
than |
16 bit |
0 đến 65536 |
int |
32 bit |
-2147483648 đến 2147483647 |
dài |
64 bit |
-9223372036854775808 đến 9223372036854775807 |
trôi nổi |
32 bit |
(2 mũ -149) đến ((2 - (2 mũ -23)) * 2 mũ 127) |
gấp đôi |
64 bit |
(-2 mũ 63) đến ((2 mũ 63) - 1) |
boolean |
8 (khi được sử dụng trong mảng), 32 (nếu không được sử dụng trong mảng) |
đúng hay sai |
Phạm vi từ 0 đến 65536 được chỉ định cho loại
char . Nhưng điều đó có nghĩa gì? Xét cho cùng, một
ký tự không chỉ đại diện cho các số mà còn cả các chữ cái, dấu chấm câu… Vấn đề là trong Java các giá trị
ký tự được lưu trữ ở định dạng Unicode. Chúng ta đã gặp Unicode trong một trong các bài học trước. Bạn có thể nhớ rằng Unicode là một tiêu chuẩn mã hóa ký tự bao gồm các ký hiệu của hầu hết các ngôn ngữ viết trên thế giới. Nói cách khác, đó là một danh sách các mã đặc biệt đại diện cho gần như mọi ký tự trong bất kỳ ngôn ngữ nào. Toàn bộ bảng Unicode rất lớn, và tất nhiên, bạn không cần phải học thuộc lòng. Đây là một phần nhỏ của nó:
Điều chính là hiểu cách các ký tự được lưu trữ và nhớ rằng nếu bạn biết mã cho một ký tự cụ thể, bạn luôn có thể tạo ký tự đó trong chương trình của mình. Hãy thử với một số số ngẫu nhiên:
public static void main(String[] args) {
int x = 32816;
char c = (char) x ;
System.out.println(c);
}
Đầu ra của bảng điều khiển: 耰 Đây là định dạng được sử dụng để lưu trữ
ký tự trong Java. Mỗi biểu tượng tương ứng với một số: mã số 16 bit (hai byte). Trong Unicode, 32816 tương ứng với ký tự tiếng Trung 耰. Hãy lưu ý điểm sau đây. Trong ví dụ này, chúng tôi đã sử dụng một biến
int . Nó chiếm 32 bit trong bộ nhớ, trong khi
char chiếm 16. Ở đây chúng tôi chọn
int , vì số của chúng tôi (32816) sẽ không vừa với
short . Mặc dù kích thước của
char (giống như
short ) là 16 bit, nhưng không có số âm trong phạm vi
char , vì vậy phần "dương" của
charphạm vi lớn gấp đôi (65536 thay vì 32767 cho loại
ngắn ). Chúng ta có thể sử dụng
int miễn là mã của chúng ta ở dưới 65536. Nhưng nếu bạn tạo một giá trị
int lớn hơn 65536, thì nó sẽ chiếm hơn 16 bit. Và điều này sẽ dẫn đến việc thu hẹp chuyển đổi
char c = (char) x;
các bit thừa sẽ bị loại bỏ (như đã thảo luận ở trên) và kết quả sẽ khá bất ngờ.
Các tính năng đặc biệt của việc thêm ký tự và số nguyên
Hãy xem xét một ví dụ bất thường:
public class Main {
public static void main(String[] args) {
char c = '1';
int i = 1;
System.out.println(i + c);
}
}
Đầu ra của bảng điều khiển:
50 O_О Điều đó có ý nghĩa như thế nào? 1+1. 50 đến từ đâu?! Bạn đã biết rằng
char
các giá trị được lưu trữ trong bộ nhớ dưới dạng các số trong phạm vi từ 0 đến 65536 và các số này là biểu diễn Unicode của một ký tự.
Khi chúng ta thêm một
ký tự và một số loại số nguyên,
ký tự đó được chuyển đổi thành số Unicode tương ứng. Trong mã của chúng tôi, khi chúng tôi thêm 1 và '1', ký hiệu '1' được chuyển thành mã riêng của nó, là 49 (bạn có thể xác minh điều này trong bảng ở trên). Do đó, kết quả là 50. Một lần nữa, hãy lấy người bạn cũ 耰 của chúng ta làm ví dụ và thử thêm nó vào một số nào đó.
public static void main(String[] args) {
char c = '耰';
int x = 200;
System.out.println(c + x);
}
Kết quả bảng điều khiển:
33016 Chúng tôi đã phát hiện ra rằng 耰 tương ứng với 32816. Và khi cộng số này với 200, chúng tôi nhận được kết quả: 33016. :) Như bạn có thể thấy, thuật toán ở đây khá đơn giản, nhưng bạn đừng quên nó .