![](/img/trans.png)
[英]Java - How can I convert an object from my own class to a string in the main class?
[英]How can I detect if a Java class is called by its own main() or from another class?
我有一个看起来像这样的Java类:
public class My_ABC
{
int a=0;
boolean B=true;
static // Initialize and load existing data only once at start-up
{
// need to know if it's called from its own main()
// or by another class to conditionally set veriables
}
public My_ABC(int AA,boolean BB)
{
}
public static void main(String[] args)
{
My_ABC my_abc = new My_ABC(3,true);
}
}
因为静态块是在加载类时运行的,所以如何检测它是从自己的main()
调用还是由另一个类调用以有条件地设置变量?
我知道你们中的一些人说:“各种钟声响起!” 好吧,这是因为我遇到了一种情况:我正在设计一个类,需要将大量数据加载到PC的极限(4G Ram)中,并且我正在运行只能使用1.5G的Java 32位版本的Ram max; 因此,当我单独测试该类时,我需要加载尽可能多的数据以测试所有可能的情况,但是当从多个其他类中调用它时,它将无法执行此操作(将导致堆空间不足错误),因此只能加载最小 需要的数据。 但是,由于所有数据在启动时仅应加载一次,因此应将其保存在静态块中。 否则,我需要实现额外的逻辑来检测它是第一次加载(需要加载数据)还是第二次,第三次加载(不应该一次又一次地加载数据)。 而且,如果我实施额外的逻辑来做到这一点并将数据加载代码移出静态块,则会导致不必要的复杂性,因为如果我移至64位版本的Java(希望很快),那么额外的复杂性将是额外的负担(我将有足够的空间来加载所有数据,即使从其他类调用时也是如此。 因此,临时的快速修复方法是在静态块中检测出该异常并相应地处理差异,当我有足够的空间时,只需将它们注释掉,而无需更改编程逻辑结构。
感谢您提供所有答案和建议,我尝试了“ StackTraceElement”方法,效果很好! 它解决了我的问题。
只看实际的堆栈。 使用静态块的以下实现进行测试。 无论您是“执行” My_ABC类还是稍后加载该类,打印输出都会有所不同:
static // Initialize and load existing data only once at start-up
{
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement el : stackTrace) {
System.out.println(el);
}
// in real life you wouldn't print but use the stackTrace array
// to identify why the class has been loaded and do your initialisation
}
我认为您绝对应该改变方法。
但是由于您在这里问的是具体的东西 (总结)。
public class X {
static {
System.out.println("Static free block");
StackTraceElement [] st = new RuntimeException("").getStackTrace();
if( st.length == 1 ) {
System.out.println("Invoked from main");
} else {
System.out.println("Invoked from somewhere else");
}
}
public static void main( String [] args ) {
System.out.println("Main");
}
}
使用它来测试它:
public class Y {
public static void main( String [] args ) {
X x = new X();
}
}
ps我不知道为什么约瑟夫删除他的答案是正确的。
从技术上讲,您不能从其自己的main方法调用静态初始化程序,因为它总是在 main
方法之前运行:
// output: 'foobar'
public class Foobar {
static { System.out.print("foo"); }
public static void main(String[] args) { System.out.print("bar"); }
}
因此,您正在尝试测试不可能的事情;-)
一个非常脏的解决方案将在静态初始化块中引发并捕获异常。 捕获异常时,使它将堆栈跟踪打印到ByteArrayOutputStream上,将字节数组转换为String并分析跟踪以查看是否从所需的主方法调用了静态初始化程序。
但是,这样做听起来像是不可思议的事情,必须避免采用更好的设计。 。 。
最好使用静态初始化程序加载数据。 也许另一种方法是使它成为单实例类(通过使用Singleton Pattern或仅通过在代码中确保只实例化一次)即可。 然后,您可以调用构造函数或带有标志的load方法来指示如何设置变量。
FWIW,我认为即使使用静态方法(再次可以向其传递标志)加载数据,虽然不是一个很好的解决方案,但也比使用静态初始化器更好。
我不知道是否有可能绝对地知道某个类是否正在被加载,是因为其自身的main()
被调用,还是因为另一个类对其进行了引用-或只是决定加载它。 您可以调查堆栈跟踪,但这会导致代码很脆弱。 可能在一个JVM上运行但不在另一个JVM上运行的代码。 或在桌面应用程序中有效但在Applet或Web Start应用程序中无效的代码。 这不是一个好主意。
最好是重新考虑您的设计。 如果一个类需要知道是谁加载的,则该类正在做太多事情。 将部分因素分解到配置类中(或其他合适的方法),以便任何人加载类都可以提供正确的信息。
这是创建单例的一个可爱技巧:使用单值枚举。 JVM保证创建的实例不能超过一个。 在枚举的构造函数(不是静态初始化程序块)中,进行所需的任何数据库或文件系统访问,如果失败,则抛出适当的RuntimeException
。 枚举将在加载类时实例化,因此您不需要使用静态init块。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.