Nó thậm chí có thể?
Câu trả lời:
nếu bạn muốn nói đến một hàm ẩn danh và đang sử dụng phiên bản Java trước Java 8, thì trong một từ, không. ( Đọc về biểu thức lambda nếu bạn sử dụng Java 8+ )
Tuy nhiên, bạn có thể triển khai một giao diện có chức năng như sau:
Comparator<String> c = new Comparator<String>() {
int compare(String s, String s2) { ... }
};
và bạn có thể sử dụng điều này với các lớp bên trong để có được một hàm gần như ẩn danh :)
Đây là một ví dụ về một lớp bên trong ẩn danh.
System.out.println(new Object() {
@Override public String toString() {
return "Hello world!";
}
}); // prints "Hello world!"
Điều này không hữu ích lắm nhưng nó chỉ ra cách tạo một thể hiện của một lớp bên trong ẩn danh extends Object
và phương thức @Override
của nó toString()
.
Các lớp ẩn danh bên trong rất tiện dụng khi bạn cần triển khai một lớp interface
có thể không được tái sử dụng nhiều (và do đó không có giá trị cấu trúc lại thành lớp được đặt tên riêng của nó). Một ví dụ hướng dẫn đang sử dụng một tùy chỉnh java.util.Comparator<T>
để sắp xếp.
Đây là một ví dụ về cách bạn có thể sắp xếp String[]
dựa trên String.length()
.
import java.util.*;
//...
String[] arr = { "xxx", "cd", "ab", "z" };
Arrays.sort(arr, new Comparator<String>() {
@Override public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
});
System.out.println(Arrays.toString(arr));
// prints "[z, cd, ab, xxx]"
Lưu ý thủ thuật so sánh từng phép trừ được sử dụng ở đây. Cần phải nói rằng kỹ thuật này bị hỏng nói chung: nó chỉ áp dụng khi bạn có thể đảm bảo rằng nó sẽ không bị tràn (chẳng hạn như trường hợp với String
độ dài).
EventListener
triển khai (phụ) trong ứng dụng Swing trung bình.
Linked
thanh bên, vì vậy tôi đang cố gắng hết sức để sử dụng nó.
Với sự ra đời của biểu thức lambda trong Java 8, giờ đây bạn có thể có các phương thức ẩn danh.
Giả sử tôi có một lớp Alpha
và tôi muốn lọc Alpha
các s theo một điều kiện cụ thể. Để làm điều này, bạn có thể sử dụng một Predicate<Alpha>
. Đây là một giao diện chức năng có một phương thức test
chấp nhận một Alpha
và trả về a boolean
.
Giả sử rằng phương thức lọc có chữ ký này:
List<Alpha> filter(Predicate<Alpha> filterPredicate)
Với giải pháp lớp ẩn danh cũ, bạn sẽ cần một cái gì đó như:
filter(new Predicate<Alpha>() {
boolean test(Alpha alpha) {
return alpha.centauri > 1;
}
});
Với lambdas Java 8 bạn có thể làm:
filter(alpha -> alpha.centauri > 1);
Để biết thêm thông tin chi tiết, hãy xem hướng dẫn về Biểu thức Lambda
Các lớp bên trong ẩn danh việc triển khai hoặc mở rộng giao diện của một kiểu hiện có đã được thực hiện trong các câu trả lời khác, mặc dù điều đáng chú ý là có thể triển khai nhiều phương thức (ví dụ: thường với các sự kiện kiểu JavaBean).
Một đặc điểm ít được công nhận là mặc dù các lớp ẩn danh bên trong không có tên, nhưng chúng có một kiểu. Các phương pháp mới có thể được thêm vào giao diện. Các phương thức này chỉ có thể được gọi trong một số trường hợp hạn chế. Chủ yếu trực tiếp trên new
chính biểu thức và trong lớp (bao gồm cả các bộ khởi tạo cá thể). Nó có thể gây nhầm lẫn cho người mới bắt đầu, nhưng nó có thể "thú vị" đối với đệ quy.
private static String pretty(Node node) {
return "Node: " + new Object() {
String print(Node cur) {
return cur.isTerminal() ?
cur.name() :
("("+print(cur.left())+":"+print(cur.right())+")");
}
}.print(node);
}
(Ban đầu tôi đã viết điều này bằng cách sử dụng node
chứ không phải cur
trong print
phương pháp. Nói KHÔNG với việc bắt final
người dân địa phương " ngầm "? )
node
nên được khai báo final
ở đây.
cur
.
"Node" +
để thực hiện phương thức thứ hai). / Tôi không có tên. Có lẽ tôi có thể tạo ra một câu hỏi "thăm dò ý kiến" (CW) đặt tên, và đưa nó vào quên lãng.
Có nếu bạn đang sử dụng java mới nhất là phiên bản 8. Java8 giúp bạn có thể xác định các hàm ẩn danh, điều không thể xảy ra trong các phiên bản trước.
Hãy lấy ví dụ từ tài liệu java để biết cách chúng ta có thể khai báo các hàm, lớp ẩn danh
Ví dụ sau, HelloWorldAnonymousClasses, sử dụng các lớp ẩn danh trong các câu lệnh khởi tạo của các biến cục bộ frenchGreeting và spanishGreeting, nhưng sử dụng một lớp cục bộ để khởi tạo biến englishGreeting:
public class HelloWorldAnonymousClasses {
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
public void sayHello() {
class EnglishGreeting implements HelloWorld {
String name = "world";
public void greet() {
greetSomeone("world");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hello " + name);
}
}
HelloWorld englishGreeting = new EnglishGreeting();
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
HelloWorld spanishGreeting = new HelloWorld() {
String name = "mundo";
public void greet() {
greetSomeone("mundo");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hola, " + name);
}
};
englishGreeting.greet();
frenchGreeting.greetSomeone("Fred");
spanishGreeting.greet();
}
public static void main(String... args) {
HelloWorldAnonymousClasses myApp =
new HelloWorldAnonymousClasses();
myApp.sayHello();
}
}
Cú pháp của các lớp ẩn danh
Xem xét việc tạo đối tượng frenchGreeting:
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
Biểu thức lớp ẩn danh bao gồm những điều sau:
new
điều hànhTên của một giao diện để triển khai hoặc một lớp để mở rộng. Trong ví dụ này, lớp ẩn danh đang triển khai giao diện HelloWorld.
Dấu ngoặc đơn chứa các đối số của một hàm tạo, giống như một biểu thức tạo cá thể lớp bình thường. Lưu ý: Khi bạn triển khai một giao diện, không có hàm tạo, vì vậy bạn sử dụng một cặp dấu ngoặc đơn trống, như trong ví dụ này.
Một phần thân, là phần tử khai báo lớp. Cụ thể hơn, trong phần thân, khai báo phương thức được phép nhưng câu lệnh thì không.