Vous pouvez créer une nouvelle classe pour que:
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
Techniquement, il n'y a plus une fonction de haut niveau, mais l'effet souhaité.
Maintenant, si vous saviez que et que vous voulez toujours faire référence à des méthodes de haut niveau ...
Pour autant que je peux dire, la « classe de niveau supérieur » qui tient « Etat » pour la coquille est jdk.jshell.JShell
, mais jdk.jshell.JShell::printIsEven
dans Error: invalid method reference
. Et vous avez déjà mentionné qu'il n'est pas possible de rendre les méthodes de niveau supérieur statiques (Modifier 'static' not permitted in top-level declarations, ignored
). Après un coup d'oeil rapide à la JEP, il semble intentionnel. Et il mentionne en fait l'approche "définir-static-method-in-new-class" par le dessus.
Je suis deviner la « classe » de haut niveau a besoin de magie pour pouvoir redéfinir méthodes & autres déclarations de haut niveau, et les limitations pourraient découler de ses propres limites de la machine virtuelle Java dans sa capacité à redéfinir les classes/méthodes au moment de l'exécution. The source est intéressant mais je ne suis pas en mesure d'en tirer une réponse significative.
Edit: Donc, je me suis un peu emporté. C'est de ta faute.
Je pense toujours qu'il n'est pas possible d'obtenir une référence de méthode à une méthode de niveau supérieur dans jshell, mais ... ma précédente estimation des raisons pour lesquelles est probablement erronée. Le tableau suivant montre que dans jshell, lorsque vous "redéfinissez" une classe, l'ancienne classe est toujours présente: le contexte d'évaluation décale simplement certains mappages pour résoudre d'autres références à la nouvelle définition de classe.
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
donc cette petite démo suggère qu'il n'a rien à voir avec internals JVM pour la redéfinition des classes, car pas une telle chose se passe ici.
Alors je voulais voir la liste de toutes les classes chargées:
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, oui, Java 9 modules ... :) Bon sang
Oh, eh bien, ce sera tout pour aujourd'hui.
Je n'ai pas utilisé JShell, mais ne pouvez-vous pas rendre la méthode statique? –
@ChandlerBing Non, cela rend 'Modifier 'static' non autorisé dans les déclarations de niveau supérieur, ignoré' –