我试图将JVM中的初始化和实例化过程拼凑在一起,但JLS对一些细节有点迟钝,所以如果有人想清除一些细节,我们将不胜感激.这是我迄今为止能够弄清楚的.
初始化
递归初始化类的静态最终变量及其作为编译时常量的接口.
退出以文本顺序处理静态块和静态字段的递归.
实例化
递归初始化作为编译时常量的类的最终实例变量.
退出递归处理文本顺序中的非静态块和实例字段,在返回时将它们预先添加到构造函数中.
好的,现在提问.
是按声明顺序处理的接口?
是在单独的递归堆栈中处理的接口?
a)如果是,是否在超类之前或之后处理接口?
b)如果是,我在推断其中一个或其他(接口或超类)在其他编译时常量之前初始化其非编译时常量字段时是正确的.
调用非默认的super()构造函数在此过程中起什么作用?
我的任何结论都错了吗?
我错过了其他任何关键细节吗?
VarHandle显示以下错误 -
Exception in thread "main" java.lang.NoSuchMethodError: VarHandle.compareAndSet(VarHandleExample,int,int)void
at java.base/java.lang.invoke.MethodHandleNatives.newNoSuchMethodErrorOnVarHandle(MethodHandleNatives.java:492)
at java.base/java.lang.invoke.MethodHandleNatives.varHandleOperationLinkerMethod(MethodHandleNatives.java:445)
at java.base/java.lang.invoke.MethodHandleNatives.linkMethodImpl(MethodHandleNatives.java:378)
at java.base/java.lang.invoke.MethodHandleNatives.linkMethod(MethodHandleNatives.java:366)
at j9.VarHandleExample.update(VarHandleExample.java:23)
at j9.VarHandleExample.main(VarHandleExample.java:14)
Run Code Online (Sandbox Code Playgroud)
我的计划是:
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
public class VarHandleExample {
public int publicTestVariable = 10;
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
VarHandleExample e= new VarHandleExample();
e.update();
}
public void update() throws NoSuchFieldException, IllegalAccessException {
VarHandle publicIntHandle = MethodHandles.lookup()
.in(VariableHandlesTest.class)
.findVarHandle(VarHandleExample.class, "publicTestVariable", int.class);
publicIntHandle.compareAndSet(this, 10, 100); // CAS
}
}
Run Code Online (Sandbox Code Playgroud) 警告:我意识到这可能是对 spring bean 和/或 Java 8 的默认接口方法背后意图的滥用。我正在寻找的是对为什么这可能是一种我未能认识到的不安全方法的具体且合理的批评。
我定义了一个类,它使我可以静态访问正在运行的应用程序上下文:
@Component
public class BeanAccessor implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static <T> T getSingleton(Class<T> clazz){
return applicationContext.getBean(clazz);
}
public static <T> T getSingleton(String beanName, Class<T> clazz){
return applicationContext.getBean(beanName, clazz);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanAccessor.applicationContext = applicationContext;
}
}
Run Code Online (Sandbox Code Playgroud)
然后我可以在默认接口方法中使用这些 BeanAccessor 方法,以便从方法内部访问 spring 管理的 bean。
我意识到可以通过实现其他类和服务来实现此功能,而不是觉得需要将它混合到当前的类和服务中(至少对于下面的示例,我实际上并没有对“this”做任何事情)。这在一定程度上是一种“艺术”偏好,我相信我会继续寻找其他用例。
请注意,我并没有像这里描述的那样尝试保留每个实例的状态https://kerflyn.wordpress.com/2012/07/09/java-8-now-you-have-mixins/我确实认识到存在危险在这样做。
这是一个示例用法:
public interface ClientAware {
String TENANT_NAME = "TENANT_NAME";
default ClientDetails clientDetails() {
ClientDetailsService service …Run Code Online (Sandbox Code Playgroud) 我正在经历一种对我来说没有意义的奇怪行为.以下程序(我试图将其减少到最小的例子)崩溃NullPointerException因为Bar.Y是null:
$ javac *.java
$ java Main
FooEnum.baz()
Exception in thread "main" java.lang.NullPointerException
at Main.main(Main.java:6)
Run Code Online (Sandbox Code Playgroud)
我希望它打印:
FooEnum.baz()
Bar.qux
Run Code Online (Sandbox Code Playgroud)
但是,如果Bar.qux首先访问(可以通过取消注释main方法的第一行或通过重新排序以下两行来完成),程序将正确终止.
我怀疑这个问题与Java类初始化顺序有关,但我无法在相关的JLS部分找到任何解释.
所以,我的问题是:这里发生了什么?这是某种错误还是我错过了什么?
我的JDK版本是1.8.0_111
interface Bar {
// UPD
int barF = InitUtil.initInt("[Bar]");
Bar X = BarEnum.EX;
Bar Y = BarEnum.EY;
default void qux() {
System.out.println("Bar.qux");
}
}
enum BarEnum implements Bar {
EX,
EY;
// UPD
int barEnumF = InitUtil.initInt("[BarEnum]");
}
interface Foo {
Foo A = FooEnum.EA;
Foo B = FooEnum.EB;
// …Run Code Online (Sandbox Code Playgroud)