เป็นไปได้หรือไม่?
เป็นไปได้หรือไม่?
คำตอบ:
หากคุณหมายถึงฟังก์ชันที่ไม่ระบุชื่อและกำลังใช้ Java เวอร์ชันก่อน Java 8ดังนั้นในคำว่า no ( อ่านเกี่ยวกับนิพจน์แลมบ์ดาหากคุณใช้ Java 8+ )
อย่างไรก็ตามคุณสามารถใช้อินเทอร์เฟซที่มีฟังก์ชันดังนี้:
Comparator<String> c = new Comparator<String>() {
int compare(String s, String s2) { ... }
};
และคุณสามารถใช้สิ่งนี้กับคลาสภายในเพื่อรับฟังก์ชั่นที่แทบไม่ระบุตัวตน :)
นี่คือตัวอย่างของคลาสภายในที่ไม่ระบุชื่อ
System.out.println(new Object() {
@Override public String toString() {
return "Hello world!";
}
}); // prints "Hello world!"
นี้ไม่ได้เป็นประโยชน์อย่างมากในขณะที่มันเป็น แต่มันแสดงให้เห็นถึงวิธีการสร้างตัวอย่างของระดับชั้นที่ไม่ระบุชื่อที่extends Object
และ@Override
ของtoString()
วิธีการ
คลาสภายในที่ไม่ระบุตัวตนมีประโยชน์มากเมื่อคุณต้องการใช้งานinterface
ซึ่งอาจไม่สามารถนำกลับมาใช้ใหม่ได้อย่างมาก (ดังนั้นจึงไม่คุ้มค่าที่จะปรับโครงสร้างเป็นคลาสที่มีชื่อของตัวเอง) ตัวอย่างคำแนะนำใช้แบบกำหนดเองjava.util.Comparator<T>
สำหรับการเรียงลำดับ
นี่คือตัวอย่างของวิธีการที่คุณสามารถจัดเรียงหนึ่งขึ้นอยู่กับString[]
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]"
สังเกตเคล็ดลับการเปรียบเทียบโดยการลบที่ใช้ที่นี่ ควรกล่าวว่าเทคนิคนี้ใช้งานไม่ได้โดยทั่วไป: ใช้ได้เฉพาะเมื่อคุณสามารถรับประกันได้ว่าจะไม่ล้น (เช่นกรณีที่มีString
ความยาว)
EventListener
การใช้งาน (ย่อย) ในแอปพลิเคชัน Swing โดยเฉลี่ย
Linked
แถบด้านข้างดังนั้นฉันจึงพยายามอย่างเต็มที่เพื่อใช้ประโยชน์จากมัน
ด้วยการแนะนำ lambda expression ใน Java 8 ตอนนี้คุณสามารถมีเมธอดที่ไม่ระบุตัวตนได้แล้ว
สมมติว่าฉันมีชั้นเรียนAlpha
และต้องการกรองAlpha
เงื่อนไขเฉพาะ ในการดำเนินการนี้คุณสามารถใช้ไฟล์Predicate<Alpha>
. นี่คืออินเทอร์เฟซที่ใช้งานได้ซึ่งมีวิธีการtest
ที่ยอมรับAlpha
และส่งคืนไฟล์boolean
.
สมมติว่าวิธีการกรองมีลายเซ็นนี้:
List<Alpha> filter(Predicate<Alpha> filterPredicate)
ด้วยโซลูชันคลาสนิรนามแบบเก่าคุณจะต้องทำสิ่งต่อไปนี้:
filter(new Predicate<Alpha>() {
boolean test(Alpha alpha) {
return alpha.centauri > 1;
}
});
ด้วย Java 8 lambdas คุณสามารถทำได้:
filter(alpha -> alpha.centauri > 1);
สำหรับข้อมูลเพิ่มเติมโปรดดูบทแนะนำ Lambda Expressions
คลาสภายในแบบไม่ระบุชื่อที่ใช้หรือขยายส่วนต่อประสานของประเภทที่มีอยู่ได้ทำในคำตอบอื่น ๆ แม้ว่าจะเป็นที่น่าสังเกตว่าสามารถใช้งานได้หลายวิธี (มักใช้กับเหตุการณ์ในรูปแบบ JavaBean เป็นต้น)
คุณลักษณะที่เป็นที่รู้จักเล็กน้อยคือแม้ว่าคลาสภายในที่ไม่ระบุชื่อจะไม่มีชื่อ แต่ก็มีประเภท สามารถเพิ่มวิธีการใหม่ลงในอินเทอร์เฟซได้ วิธีการเหล่านี้สามารถเรียกใช้ได้ในบางกรณีเท่านั้น โดยเฉพาะอย่างยิ่งในnew
นิพจน์ตัวเองและภายในคลาส (รวมถึงตัวเริ่มต้นอินสแตนซ์) อาจทำให้ผู้เริ่มต้นสับสน แต่อาจ "น่าสนใจ" สำหรับการเรียกซ้ำ
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);
}
(ฉันเดิมเขียนนี้ใช้node
มากกว่าcur
ในprint
วิธี. บอกว่าไม่มีการจับ "โดยปริยายfinal
" ชาวบ้าน? )
node
ควรประกาศไว้final
ที่นี่
cur
อันที่จริงความผิดพลาดของฉันไม่ได้กับการใช้งาน
"Node" +
เพื่อสร้างวิธีที่สองที่จำเป็น) / ฉันไม่มีชื่อ. บางทีฉันอาจสร้างคำถาม "การสำรวจความคิดเห็น" (CW) เพื่อตั้งชื่อและให้คะแนนนั้นลดลง
ใช่ถ้าคุณใช้ java ล่าสุดซึ่งเป็นเวอร์ชัน 8 Java8 ทำให้สามารถกำหนดฟังก์ชันที่ไม่ระบุชื่อซึ่งเป็นไปไม่ได้ในเวอร์ชันก่อนหน้า
มายกตัวอย่างจากjava docsเพื่อทำความรู้จักว่าเราสามารถประกาศฟังก์ชัน anonymous class ได้อย่างไร
ตัวอย่างต่อไปนี้ HelloWorldAnonymousClasses ใช้คลาสที่ไม่ระบุชื่อในคำสั่งเริ่มต้นของตัวแปรโลคัล frenchGreeting และ spanishGreeting แต่ใช้คลาสโลคัลสำหรับการเริ่มต้นตัวแปร 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();
}
}
ไวยากรณ์ของคลาสที่ไม่ระบุชื่อ
พิจารณาการสร้างอินสแตนซ์ของวัตถุ 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);
}
};
นิพจน์คลาสที่ไม่ระบุชื่อประกอบด้วยสิ่งต่อไปนี้:
new
ดำเนินการชื่อของอินเทอร์เฟซที่จะใช้หรือคลาสที่จะขยาย ในตัวอย่างนี้คลาสที่ไม่ระบุชื่อกำลังใช้อินเตอร์เฟส HelloWorld
วงเล็บที่มีอาร์กิวเมนต์ของตัวสร้างเช่นเดียวกับนิพจน์การสร้างอินสแตนซ์คลาสปกติ หมายเหตุ: เมื่อคุณใช้อินเทอร์เฟซไม่มีตัวสร้างดังนั้นคุณจึงใช้วงเล็บคู่ว่างดังในตัวอย่างนี้
ร่างกายซึ่งเป็นเนื้อหาการประกาศคลาส โดยเฉพาะอย่างยิ่งในเนื้อความอนุญาตให้มีการประกาศวิธีการ แต่ไม่สามารถใช้คำสั่งได้