我有一个必须有一些静态方法的类。在这些静态方法中,我需要调用方法 getClass() 来进行以下调用:
public static void startMusic() {
URL songPath = getClass().getClassLoader().getResource("background.midi");
}
但是 Eclipse 告诉我:
Cannot make a static reference to the non-static method getClass()
from the type Object
修复此编译时错误的适当方法是什么?
getResource()
有时会失败。问题是 JRE 将在那个阶段使用引导类加载器,它不会在(引导加载器的)类路径上拥有应用程序资源。
答案
只需使用 TheClassName.class
而不是 getClass()
。
声明记录器
由于这在特定用例中引起了如此多的关注——提供一种插入日志声明的简单方法——我想我会在这方面添加我的想法。日志框架通常希望日志被限制在特定的上下文中,比如一个完全限定的类名。因此,如果不进行修改,它们就不能复制粘贴。其他答案中提供了关于粘贴安全日志声明的建议,但它们有缺点,例如膨胀字节码或添加运行时自省。我不推荐这些。复制粘贴是编辑器关注的问题,因此编辑器解决方案是最合适的。
在 IntelliJ 中,我建议添加一个 Live Template:
使用“日志”作为缩写
使用私有静态最终 org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger($CLASS$.class);作为模板文本。
单击编辑变量并使用表达式 className() 添加 CLASS
选中复选框以重新格式化和缩短 FQ 名称。
将上下文更改为 Java: 声明。
现在,如果您输入 log<tab>
,它将自动展开为
private static final Logger logger = LoggerFactory.getLogger(ClassName.class);
并自动为您重新格式化和优化导入。
至于问题中的代码示例,标准解决方案是通过名称显式引用该类,甚至可以不调用 getClassLoader()
:
class MyClass {
public static void startMusic() {
URL songPath = MyClass.class.getResource("background.midi");
}
}
这种方法仍然有一个缺点,即如果您需要将此代码复制到许多类似的类中,它对于复制/粘贴错误不是很安全。
至于标题中的确切问题,adjacent thread中发布了一个技巧:
Class currentClass = new Object() { }.getClass().getEnclosingClass();
它使用嵌套的匿名 Object
子类来获取执行上下文。这个技巧的好处是复制/粘贴安全......
在其他类继承自的基类中使用它时要小心:
还值得注意的是,如果此代码段被塑造为某个基类的静态方法,则 currentClass
值将始终是对该基类的引用,而不是对可能使用该方法的任何子类的引用。
在 Java7+ 中,您可以在静态方法/字段中执行此操作:
MethodHandles.lookup().lookupClass()
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
我自己为此苦苦挣扎。一个不错的技巧是在静态上下文中使用当前线程来获取 ClassLoader。这也适用于 Hadoop MapReduce。其他方法在本地运行时有效,但在 MapReduce 中使用时返回 null InputStream。
public static InputStream getResource(String resource) throws Exception {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
InputStream is = cl.getResourceAsStream(resource);
return is;
}
只需使用类文字,即 NameOfClass.class
试试看
Thread.currentThread().getStackTrace()[1].getClassName()
或者
Thread.currentThread().getStackTrace()[2].getClassName()
[1]
将导致所有日志消息将 Thread
报告为其在 Android 4.4.4 上的来源。 [2]
似乎在 Android 和 OpenJRE 上都给出了正确的结果。
getClass()
方法在 Object 类中定义,具有以下签名:
公共最终类 getClass()
由于它未定义为 static
,因此您不能在静态代码块中调用它。有关详细信息,请参阅以下答案:Q1、Q2、Q3。
如果你在一个静态上下文中,那么你必须使用类文字表达式来获取类,所以你基本上必须这样做:
Foo.class
这种类型的表达式称为 Class Literals,它们在 Java Language Specification Book 中解释如下:
类文字是一个表达式,由类、接口、数组或原始类型的名称后跟一个“.”组成。和令牌类。类文字的类型是 Class。它评估为由当前实例的类的定义类加载器定义的命名类型(或 void)的 Class 对象。
您还可以在 API documentation 上找到有关此主题的信息,以供课堂使用。
我有同样的问题 !但要解决它只需修改您的代码如下。
public static void startMusic() {
URL songPath = YouClassName.class.getClassLoader().getResource("background.midi");
}
这对我来说很好,希望它对你也很好。
假设有一个 Utility 类,那么示例代码将是 -
URL url = Utility.class.getClassLoader().getResource("customLocation/".concat("abc.txt"));
CustomLocation - 如果资源中的任何文件夹结构,否则删除此字符串文字。
尝试这样的事情。这个对我有用。 Logg(类名)
String level= "";
Properties prop = new Properties();
InputStream in =
Logg.class.getResourceAsStream("resources\\config");
if (in != null) {
prop.load(in);
} else {
throw new FileNotFoundException("property file '" + in + "' not found in the classpath");
}
level = prop.getProperty("Level");
Log
,这需要提供标签,通常是类名。可能还有其他例子。当然,您可以为此声明一个字段(这是常见做法),但这仍然是复制和粘贴。CLASS
的表达式中输入className()
。这将确保 $CLASS$ 实际上被替换为类名,否则它将为空。