Bạn có thể tạo một lớp mới cho rằng:
jshell> class Foo { static void printIsEven(int i) {
...> System.out.println(i % 2 == 0);
...> }}
| created class Foo
jshell> Arrays.asList(1,2,3).forEach(Foo::printIsEven)
false
true
false
Về mặt kỹ thuật nó không còn là một chức năng cấp cao nhất, nhưng nó đạt được hiệu quả mong muốn.
Bây giờ, nếu bạn biết điều đó và vẫn muốn tham khảo các phương pháp top-level ...
Theo như tôi có thể nói, các "lớp học cấp cao nhất" chứa "nhà nước" cho vỏ là jdk.jshell.JShell
, nhưng jdk.jshell.JShell::printIsEven
kết quả trong số Error: invalid method reference
. Và bạn đã đề cập đến việc không thể tạo các phương thức cấp cao tĩnh (Modifier 'static' not permitted in top-level declarations, ignored
).
Sau khi xem nhanh JEP, có vẻ như cố ý. Và nó thực sự đề cập đến phương pháp "xác định-tĩnh-phương pháp-trong-lớp mới" từ trên.
Tôi đoán đầu cấp "lớp" cần đặc biệt kỳ diệu để có thể xác định lại phương pháp & tờ khai cấp cao khác, và những hạn chế có thể xuất phát từ những hạn chế riêng của JVM trong khả năng của mình để xác định lại các lớp/phương thức tại thời gian chạy. The source thú vị nhưng tôi không thể tìm ra câu trả lời có ý nghĩa từ đó.
Chỉnh sửa: Vì vậy, tôi đã bị mang đi. Đây là lỗi của bạn.
Tôi vẫn nghĩ rằng không thể có được phương pháp tham chiếu đến phương thức cấp cao nhất trong jshell, nhưng ... dự đoán trước đây của tôi về lý do có thể là sai.
Sau đây cho thấy rằng trong jshell, khi bạn "xác định lại" một lớp, lớp cũ vẫn còn đó: ngữ cảnh đánh giá chỉ thay đổi một số ánh xạ để giải quyết các tham chiếu thêm về định nghĩa lớp mới.
jshell> class A { static int v=1; void m() { System.out.println(getClass() + " v=" + v); } }
| created class A
jshell> new A().m()
class REPL.$JShell$11$A v=1
// Changing static value of "v"
jshell> class A { static int v=2; void m() { System.out.println(getClass() + " v=" + v); } }
| modified class A
// Actually not modified, this is still the same class (and as a result the static init of v has not been reexecuted, so, still 1)
jshell> new A().m()
class REPL.$JShell$11$A v=1
// Let's add a boolean field to change the structure
jshell> class A { static int v=3; boolean x=false; void m() { System.out.println(getClass() + " v=" + v); } }
| replaced class A
// Notice new class name:
jshell> new A().m()
class REPL.$JShell$11B$A v=3
// But old version is still there, only hidden a bit by evaluation context:
jshell> Class.forName("REPL.$JShell$11$A").getDeclaredField("v").getInt(null)
$7 ==> 1
jshell> Class.forName("REPL.$JShell$11B$A").getDeclaredField("v").getInt(null)
$8 ==> 3
Vì vậy, bản trình diễn nhỏ này cho thấy nó không liên quan gì đến nội bộ JVM để xác định lại lớp, vì không có điều gì xảy ra ở đây.
Sau đó, tôi muốn nhìn thấy danh sách của tất cả các lớp nạp:
jshell> Class c = Thread.currentThread().getContextClassLoader().getClass()
c ==> class jdk.jshell.execution.DefaultLoaderDelegate$RemoteClassLoader
jshell> while (c != java.lang.ClassLoader.class) { c = c.getSuperclass(); System.out.println(c); }
class java.net.URLClassLoader
class java.security.SecureClassLoader
class java.lang.ClassLoader
jshell> c.getDeclaredField("classes").setAccessible(true)
| java.lang.reflect.InaccessibleObjectException thrown: Unable to make field private final java.util.Vector java.lang.ClassLoader.classes accessible: module java.base does not "opens java.lang" to unnamed module @7494e528
| at AccessibleObject.checkCanSetAccessible (AccessibleObject.java:337)
| at AccessibleObject.checkCanSetAccessible (AccessibleObject.java:281)
| at Field.checkCanSetAccessible (Field.java:175)
| at Field.setAccessible (Field.java:169)
| at (#26:1)
Ah, vâng, Java 9 module ... chết tiệt :)
Ồ, đó sẽ là tất cả cho hôm nay.
Tôi chưa sử dụng JShell, nhưng bạn không thể làm cho phương thức tĩnh? –
@ChandlerBing Không, điều đó cho phép 'Modifier' static 'không được phép trong khai báo cấp cao nhất, bị bỏ qua' –