2013-03-15 47 views
10

我有一個子類和一個超類。在超類中,我有一個記錄某些東西的方法。當我創建子類的實例時,記錄器爲超類創建日誌消息。爲什麼這會發生?如何獲取子類的記錄器?

代碼例如:

SuperClass.java

import java.util.logging.Level; 
import java.util.logging.Logger; 

public abstract class SuperClass { 
    public void logAndPrintClass(){ 
     String name = this.getClass().getName(); 
     System.out.println(name); 
     Logger logger = Logger.getLogger(name); 
     logger.log(Level.INFO, "Logmessage"); 
    } 
} 

SubClass.java

public class SubClass extends SuperClass { 
} 

TestLogBubClass.java

public class TestLogBubClass { 

    public static void main(String[] args){ 
     SuperClass obj = new SubClass(); 
     obj.logAndPrintClass(); 
    } 
} 

輸出:

SubClass 
Mar 15, 2013 6:30:04 PM SuperClass logAndPrintClass 
INFO: Logmessage 

正如可以看到的類的名稱被正確地打印,但在日誌消息錯誤地表示。

回答

5

其理由是,在JavaDoc的LogRecord

注意,如果客戶端應用程序並沒有顯式指定源方法名和源類的名字,那麼的LogRecord類將自動推斷出他們時,他們是第一次通過分析調用堆棧來訪問(由於調用了getSourceMethodName或getSourceClassName)。

在這種情況下,調用堆棧結束於由SuperClass所定義的方法,所以LogRecord假設它正在被調用的類。如果你想看到這個動作,執行此代碼:

public class Example { 

    public static class Superclass { 
     public void foo() { 
      new Exception().printStackTrace(); 
     } 
    } 

    public static class Subclass extends Superclass { 
     // nothing here 
    } 

    public static void main(String[] argv) 
    throws Exception 
    { 
     Superclass s = new Subclass(); 
     s.foo(); 
    } 
} 

編輯:我不使用七月,但希望會有配置輸出(像其他記錄器實現提供了一種簡單的方法)。看起來你必須實現你自己的Formatter類,並使用java.util.logging.ConsoleHandler.formatter屬性來指定它。

我建議如果可能切換到SLF4J。您可以橋接所有現有的j.u.l通過SLF4J編碼到一個實際的記錄器,使您可以更好地控制其輸出(如Log4J或Logback)。

0

我認爲我有一個解決方法,即使我無法提供完整的解釋。

重寫logAndPrintClass只需super呼叫,像這樣,在​​:

class SubClass extends SuperClass { 
    protected void logAndPrintClass(){ super.logAndPrintClass(); } 
} 

我仍然有相同的輸出。

SubClass 
Mar 15, 2013 11:22:10 AM SuperClass logAndPrintClass 
INFO: Logmessage 

然後,我只是複製的方法體到子類:

class SubClass extends SuperClass { 
    protected void logAndPrintClass(){ 
     String name = this.getClass().getName(); 
     System.out.println(name); 
     Logger logger = Logger.getLogger(name); 
     logger.log(Level.INFO, "Logmessage"); 
    } 
} 

然後我得到不同的輸出:

SubClass 
Mar 15, 2013 11:23:31 AM SubClass logAndPrintClass 

我不知道爲什麼這工作,但唯一區別我似乎發現Logger對象現在正在實例化在子類內而不是在超類內部。

+0

實際上,在Logger.log()調用後面隱藏的LogRecord對象正在子類中創建。 – parsifal 2013-03-15 18:34:34

+0

我不想爲了記錄而重寫每個子類中的方法。在生產代碼中,不僅僅是打印和記錄消息。問題中的代碼只是具有相同行爲的最簡單的示例。 – Paling 2013-03-15 18:36:49

1

This java.util.logging code is pretty strange .. 日誌記錄不使用name,但試圖找出源類本身(然後記錄)。 查看類中的方法private void inferCaller()

1

@Parsifal解釋了爲什麼發生這種情況,我會嘗試解釋一種解決方法。

如果您想查看確切的課程,在哪裏調用方法,我會推薦使用log4jslf4j。如果你確實需要使用java.util.Logger,那麼請看看jul-to-slf4j

我試過和我相同的類輸入看起來像我的標準輸出如下:

子類

2013年3月15日下午8時39分44秒父類logAndPrintClass

INFO:的LogMessage

20:39:44478個INFO亞類:12 - 的LogMessage

和日誌文件只有:

20:39:44478 INFO亞綱:12 - 的LogMessage

它看起來並不好,但在某些情況下,這可能是作爲適當的解決方法。