Trong bài viết này mình sẽ tổng hợp những câu hỏi phỏng vấn Java SE - Section Java Basics cho đối tượng Fresher
Java SE 8
JDK | JRE | JVM |
---|---|---|
Java Development Kit | Java Runtime Environment | Java Virtual Machine |
JDK là môi trường phát triển ứng dụng Java, bao gồm các tool hỗ trợ development, testing và môi trường thực thi ứng dụng Java.
Có thể nói rằng JDK = JRE + compiler, debugger and development tool |
JRE là môi trường thực thi ứng dụng Java, bất kỳ machine nào muốn thực thi ứng dụng Java đều cần cài đặt JRE
Có thể nói rằng JRE = JVM + libraries |
JVM còn gọi là máy ảo Java là các thành phần nền tảng giúp Java quản lý tài nguyên hệ thống, thực thi chương trình |
Static variable | Instance variable | Local variable |
---|---|---|
Là biến được khai báo bên ngoài method cùng với từ khóa static |
Là biến được khai báo bên ngoài method không dùng từ khóa static |
Là biến được khai báo bên trong method không dùng từ khóa static |
Phạm vi sử dụng toàn bộ class được khai báo và bên ngoài class (phụ thuộc vào access modifier) | Phạm vi sử dụng block scope, chỉ được dùng trong block {} được khai báo | |
Giá trị của biến phụ thuộc vào class mà biến được khai báo. Thông thường truy cập thông qua ClassName.staticVariableName |
Giá trị của biến phụ thuộc vào instance (object). Thông thường truy cập thông qua reference.instanceVariable |
- |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class VariableDemo { static int number1 = 10; // a static variable int number2 = 20; // an instance variable public static void main(String[] args) { // Access static variable by class name System.out.println(VariableDemo.number1); // Access instance variable by reference VariableDemo variableDeclare = new VariableDemo(); System.out.println(variableDeclare.number2); { int number3 = 30; // a local variable; // Access local variable in block scope System.out.println(number3); } // Access local variable out of Scope System.out.println(number3); // COMPILE ERROR } } |
Reference | Object |
---|---|
- Reference là một variable có tên và dùng với mục đích access content của một object - Một reference có thể assigned đến một reference khác, truyền vào method như tham số hoặc được return từ method - Tất cả reference đều có size bằng nhau bất kề kiểu dữ liệu là gì. Size 32 bits cho một 32 bits JVM và 64 bits cho một 64 bits JVM |
- Object được lưu trong bộ nhớ Heap và không có tên - Không có cách nào access content của một Object ngoại trừ thông qua reference - Mỗi Object sẽ có size khác nhau tùy thuộc vào lượng data nó lưu trữ - Object không thể assigned vào một object khác cũng như không thể truyền vào method như tham số hoặc được return từ method |
# | Stack memory | Heap memory |
---|---|---|
Lưu trữ |
|
Object |
Cơ chế free memory |
|
Các Object không còn được sử dụng để xóa khỏi bộ nhớ tự động bởi Garbage Collector. |
Tốc độ truy cập | Nhanh hơn Heap | Chậm hơn Stack |
Space size | Limit size phụ thuộc vào OS | Không limit, có thể config. Thông thường sẽ lơn hơn Stack |
Khi bộ nhớ không đủ để allocate |
Throw ra lỗi java.lang.StackOverFlowError
|
Throw ra lỗi java.lang.OutOfMemoryError
|
Garbage collection là quá trình tự động dọn dẹp bộ nhớ Heap của Java, nó sẽ tìm đến những object không còn được sử dụng để xóa khỏi bộ nhớ Heap. Một object sẽ trở thành mục tiêu dọn dẹp của GC khi 1 trong 2 điều sau xảy ra:
Pass by value | Pass by reference |
---|---|
Tham số truyền vào method sẽ được copy ra một bản sao và tất cả các thao tác dữ liệu bên trong method sẽ cập nhật vào bản sao đó. Vì thế mà mọi sự thay đổi bên trong method sẽ không ảnh hưởng đến giá trị của biến ban đầu bên ngoài method được gọi. | Tham số truyền vào method và giá trị biến bên ngoài method cùng là reference trỏ đến một object. Do đó tất cả thao tác liên quan đến object được thực hiện bên trong method được gọi sẽ ảnh hưởng đến giá trị của biến bên ngoài method |
Trong java luôn luôn là pass by value dù tham số có data type là primitive hay reference |
1 2 3 4 5 6 7 8 9 10 11 12 | public static void main(String[] args) { int number = 10; // changeNumber() được gọi bên dưới đã thay đổi giá bị biến number = 11 bên trong nó // Tuy nhiên sau khi print number vẫn ra giá trị là 10. // Do cơ chế pass by value không thay đối giá trị biến number đã được khởi tạo ở main() changeNumber(number); System.out.println(number); // Method } public static void changeNumber(int number) { number = 20; } |
Line số 4 khai báo student.mark
= 9, sau đó thay đổi student.mark
bên trong method changeMark
tại line 10. Nếu khẳng định Java là pass by value thì print student.mark
tại line 6 đáng ra giá trị vẫn là 9 vì không đổi, tuy nhiên lại là 8. Điều này gây confuse và cảm tưởng rằng không đúng với lý thuyết pass by value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class PassByValueReferenceVariable { public static void main(String[] args) { Student student = new Student(); student.mark = 9; changeMark(student); System.out.println(student.mark); // 8 } public static void changeMark(Student student) { student.mark = 8; } } class Student { int mark; } |
Tuy nhiên với ví dụ bên dưới trong method changeMark()
, ta không thay đổi mark của đối tượng student
thông qua reference, mà ta assigned reference đó đến một object mới.
Thì chúng ta có thể thấy giá trị của student
được khai báo ở line 3 không hề thay đổi, vẫn print 9 ở line 6.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class PassByValueReferenceVariable { public static void main(String[] args) { Student student = new Student(); student.mark = 9; changeMark(student); System.out.println(student.mark); // 9 } public static void changeMark(Student student) { Student newStudent = new Student(); newStudent.mark = 8; student = newStudent; } } class Student { int mark; } |
Chúng ta có thể lý giải như sau.
# | == operator | equals method |
---|---|---|
So sánh biến primitive | Sẽ luôn return true nếu chúng có cùng value (ngoại trừ float/double ở 1 số trường hợp đặc biệt) |
Không dùng để so sánh các biến primitive. |
So sánh biến reference | So sánh memmory address của object mà 2 biến đó trỏ tới.
Kết quả sẽ là true nếu cả 2 biến reference đều trỏ vào 1 object, ngược lại thì return false
|
|
Primitive | References |
---|---|
Java có 8 kiểu dữ liệu primitive: boolean , byte , short
int , long , float , double , char |
Biến có kiểu dữ liệu reference type sẽ refers đến một object |
Lưu trữ giá trị của biến tùy thuộc vào kiểu dữ liệu | Lưu trữ memory address của object mà nó refer đến |
Không lưu trữ được giá trị null |
Lưu trữ được giá trị null |
Không call được method | Có thể call được method
* Nếu reference đang bị null và thực hiện call method thì sẽ bị NullPointerException
|
Tất cả data type primitive đều bắt đầu bằng chữ cái viết thường | Tất cả data type reference đều bắt đầu bằng chữ cái viết hoa (Nếu tuân thủ naming convention) |
Primitive type | Wrapper class | Example of constructing |
---|---|---|
boolean | Boolean | new Boolean(true) |
byte | Byte | new Byte((byte) 1) |
short | Short | new Short((short) 1) |
int | Integer | new Integer(1) |
long | Long | new Long(1) |
float | Float | new Float(1.0) |
double | Double | new Double(1) |
char | Character | new Character('c') |
Việc Java tự chuyển đổi kiểu dữ liệu primitive sang Wrapper class tương ứng với nó gọi là Autoboxing
và ngược lại gọi là Unboxing
List<Integer> numberList = new ArrayList<>(); numberList.add(1); // Autoboxing numberList.add(new Integer(2)); int firstValue = numberList.get(0); // Unboxing
Mặc định sử dụng new
kết hợp constructor là cách khởi tạo object duy nhất của mỗi Class trong Java. Do đó Java luôn cung cấp cho chúng ta 1 default constructor không tham số.
Ngoài ra, Java cũng cho phép mỗi Class có nhiều constructor thông qua cơ chế overloading constructor với mục đích cung cấp linh hoạt cách thức khởi tạo object.
Mỗi constructor là một cách thức ta muốn khởi tạo object,
vì vậy khi ta đã cung cấp một constructor mới thì đó là cách mà developer muốn class được khởi tạo thông qua nó (Có 1 số design pattern còn muốn private
lại constructor).
Lúc này Java không có lý do nào giữ lại default constructor, nếu muốn developer sẽ tự tạo một constructor không tham số.