Java存储在类中静态反射的方法:安全?
在Java中类似于下面的“安全”吗?为什么Java存储在类中静态反射的方法:安全?,java,methods,reflection,static,singleton,Java,Methods,Reflection,Static,Singleton,在Java中类似于下面的“安全”吗?为什么 public final class Utility { private Utility() {} private static Method sFooMethod = null; public static void callFoo(SomeThing thing) { try { if(sFooMethod == null) sFooMethod
public final class Utility {
private Utility() {}
private static Method sFooMethod = null;
public static void callFoo(SomeThing thing) {
try {
if(sFooMethod == null)
sFooMethod = SomeThing.class.getMethod("foo");
sFooMethod.invoke(thing);
} catch(Exception e) {} // Just for simplicity here
}
}
我的基本原理是,即使另一个线程在后台写入sFooMethod
,并且当前线程在执行callFoo()
时突然在某处看到它,它仍然会导致对thing.foo()
进行相同的反射调用
额外问题:以下方法与上述方法有哪些不同(正面/负面)?你会更喜欢它吗
public final class Utility {
private Utility() {}
private static final Method sFooMethod;
static {
try {
sFooMethod = SomeThing.class.getMethod("foo");
} catch(Exception e) {}
}
public static void callFoo(SomeThing thing) {
try {
if(sFooMethod != null)
sFooMethod.invoke(thing);
} catch(Exception e) {}
}
}
评论的背景更新:
我正在编写一个Android应用程序,我需要调用一个在API 29之前是私有的方法,当API 29公开时,它没有被更改。在AndroidX核心库的alpha版本(目前还不能使用)中,Google提供了一个HandlerCompat方法,如果私有方法不是公共的,它可以使用反射来调用私有方法。所以现在我将Google的方法复制到我自己的HandlerCompatP类中,但是我注意到如果我调用它1000次,那么反射查找将发生1000次(我看不到任何缓存)。因此,我开始思考是否有一种好方法可以只执行一次反射,并且仅在需要时执行
“不要使用反射”在这里不是一个答案,因为在本例中它是必需的,谷歌自己也打算在他们的兼容性库中实现这一点。我的问题也不是使用反射是否安全和/或良好实践,我很清楚这通常不好,而是考虑到我使用反射,哪种方法更安全/更好
在Java中类似于下面的“安全”吗?为什么
public final class Utility {
private Utility() {}
private static Method sFooMethod = null;
public static void callFoo(SomeThing thing) {
try {
if(sFooMethod == null)
sFooMethod = SomeThing.class.getMethod("foo");
sFooMethod.invoke(thing);
} catch(Exception e) {} // Just for simplicity here
}
}
public final class Utility {
private Utility() {}
private static Method sFooMethod = null;
public static void callFoo(SomeThing thing) {
try {
if(sFooMethod == null)
sFooMethod = SomeThing.class.getMethod("foo");
sFooMethod.invoke(thing);
} catch(Exception e) {} // Just for simplicity here
}
}
因此,如果你不需要思考,就不要使用思考。我不确定你的目标是什么——也许有更好的方法来完成你想做的事情
使用静态初始值设定项的第二种方法更可取,因为您的第一个实现有一个竞争条件。我不确定您的目标是什么——可能有更好的方法来完成您要做的事情
使用静态初始值设定项的第二种方法更可取,因为您的第一个实现具有竞争条件。避免内存一致性错误的关键是理解“先发生后发生”关系。这种关系只是保证一条特定语句的内存写入对另一条特定语句可见。
Java语言规范说明如下:
两个动作可以由“发生在之前”关系排序。如果有 动作发生在另一个动作之前,然后第一个动作对和可见 在第二天之前订购 如果我们有两个动作x和y,我们写hb(x,y)来表示x 发生在你之前 如果x和y是同一个线程的动作,并且x在y之前 程序顺序,然后是hb(x,y) 在您的例子中,向静态字段写入数据和从静态字段读取数据是以相同的方式进行的。因此,建立了“发生在”之前的关系。因此,读取操作将始终看到写入操作的效果。
此外,所有线程都将写入相同的数据。更糟糕的是,所有符合条件的线程将同时写入变量。该变量将引用最后分配的对象,其余被取消引用的对象将被垃圾收集。
你的应用程序中不会有太多线程同时进入同一个方法,这将由于大量对象创建而导致显著的性能下降。但是如果您只想设置一次变量,那么第二种方法更好。正如。避免内存一致性错误的关键是理解“发生在发生之前”的关系。这种关系只是保证一条特定语句的内存写入对另一条特定语句可见。
Java语言规范说明如下:
两个动作可以由“发生在之前”关系排序。如果有 动作发生在另一个动作之前,然后第一个动作对和可见 在第二天之前订购 如果我们有两个动作x和y,我们写hb(x,y)来表示x 发生在你之前 如果x和y是同一个线程的动作,并且x在y之前 程序顺序,然后是hb(x,y) 在您的例子中,向静态字段写入数据和从静态字段读取数据是以相同的方式进行的。因此,建立了“发生在”之前的关系。因此,读取操作将始终看到写入操作的效果。
此外,所有线程都将写入相同的数据。更糟糕的是,所有符合条件的线程都将被删除