Lớp cục bộ (local class) là các lớp được định nghĩa trong một khối lệnh.
Thường thì chúng ta hay định nghĩa lớp cục bộ trong khối lệnh của một phương thức, một câu lệnh for
hoặc một câu lệnh if.
Ví dụ:
public class OuterClass { public void printMessage(String msg) { final String parent = "Outer Class"; class LocalClass { String msg; LocalClass(String msg) { this.msg = msg; } public void print() { System.out.println(this.msg + " from " + parent); } } LocalClass lc = new LocalClass(msg); lc.print(); } public static void main(String[] args) { OuterClass oc = new OuterClass(); oc.printMessage("Hello World"); } }
Trong đoạn code trên thì chúng ta có lớp OuterClass
là lớp cha ngoài cùng, bên trong có phương thức printMessage(),
trong phương thức này chúng ta định nghĩa lớp LocalClass
có phương thức print().
Ở đây lớp LocalClass
chính là một lớp cục bộ, vì được định nghĩa trong một khối lệnh.
Hello World from Outer Class
Các lớp cục bộ có thể truy xuất đến các phương thức và thuộc tính của lớp cha của nó, tuy nhiên với điều kiện là thuộc tính đó phải được khai báo với từ khóa final
. Trong đoạn code trên phương thức print()
của lớp LocalClass
có thể đọc thuộc tính parent
của lớp OuterClass
là vì thuộc tính parent
được khai báo là final
.
Tuy nhiên, kể từ phiên bản Java 8 trở đi thì lớp cục bộ cũng có thể truy xuất đến các thuộc tính “gần như final” nữa, ở đây Java quy định thuộc tính “gần như final” là các thuộc tính không khai báo từ khóa final
nhưng không bao giờ thay đổi giá trị sau khi đã được khai báo và khởi tạo.
Do đó trong đoạn code trên chúng ta có thể bỏ từ khóa final
ở thuộc tính parent
. Nhưng nếu chúng ta gán lại giá trị mới cho thuộc tính parent
thì Java sẽ báo lỗi khi biên dịch.
public class OuterClass { public void printMessage(String msg) { String parent = "Outer Class"; class LocalClass { String msg; LocalClass(String msg) { parent = "Changed"; this.msg = msg; } public void print() { System.out.println(this.msg + " from " + parent); } } LocalClass lc = new LocalClass(msg); lc.print(); } public static void main(String[] args) { OuterClass oc = new OuterClass(); oc.printMessage("Hello World"); } }
Trong đoạn code trên chúng ta bỏ từ khóa final
cho biến parent,
sau đó thay đổi giá trị của biến này trong phương thức khởi tạo của lớp LocalClass
. Khi biên dịch thì Java sẽ thông báo lỗi:
local variables referenced from an inner class must be final or effectively final parent = "Changed"; ^
Lớp cục bộ và lớp nội khá giống nhau vì chúng đều không thể khai báo và định nghĩa các thuộc tính và phương thức static
. Lớp cục bộ được định nghĩa trong một phương thức static
thì chỉ có thể truy xuất các thuộc tính static
của lớp chứa phương thức đó. Nói chung là việc truy xuất các thuộc tính static
của lớp cục bộ khá hạn chế.
Chúng ta cũng không thể định nghĩa interface
trong một khối lệnh bởi vì vốn dĩ interface
cũng là static
rồi.
public class OuterClass { public void printMessage(String msg) { String parent = "Outer Class"; class LocalClass { String msg; LocalClass(String msg) { parent = "Changed"; this.msg = msg; } public void print() { System.out.println(this.msg + " from " + parent); } public void greetInEnglish() { interface HelloThere { public void greet(); } class EnglishHelloThere implements HelloThere { public void greet() { System.out.println("Hello "); } } HelloThere myGreeting = new EnglishHelloThere(); myGreeting.greet(); } } LocalClass lc = new LocalClass(msg); lc.print(); } public static void main(String[] args) { OuterClass oc = new OuterClass(); oc.printMessage("Hello World"); } }
Đoạn code trên sẽ báo lỗi.
interface not allowed here interface HelloThere { ^
Ngoài ra chúng ta cũng không thể khai báo phương thức static
trong một lớp cục bộ:
public class OuterClass { public void outerClassMethod() { class LocalClass { public static void doNothing() { //... } LocalClass() { //... } } } public static void main(String[] args) { OuterClass oc = new OuterClass(); oc.outerClassMethod(); } }
Đoạn code trên sẽ báo lỗi:
Illegal static declaration in inner class LocalClass public static void doNothing() { ^
Tuy nhiên có một điều kì dị là Java cho phép chúng ta khai báo một thuộc tính final
là static
trong một lớp cục bộ:
public class OuterClass { public void outerClassMethod() { class LocalClass { public static final float PI = 3.14159f; LocalClass() { //... } } } public static void main(String[] args) { OuterClass oc = new OuterClass(); oc.outerClassMethod(); } }