[英]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.