如何在Java中从静态方法调用getClass()?
我有一个类,它必须有一些静态方法。在这些静态方法中,我需要调用getClass()方法进行以下调用:如何在Java中从静态方法调用getClass()?,java,static-methods,Java,Static Methods,我有一个类,它必须有一些静态方法。在这些静态方法中,我需要调用getClass()方法进行以下调用: public static void startMusic() { URL songPath = getClass().getClassLoader().getResource("background.midi"); } 但是Eclipse告诉我: Cannot make a static reference to the non-static method getClass() fro
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
修复此编译时错误的适当方法是什么?答案
只需使用classname.class
而不是getClass()
申报伐木工人
由于这对于一个特定的用例(提供一种插入日志声明的简单方法)非常重要,我想我应该补充一下我的想法。日志框架通常期望日志被约束到特定的上下文中,比如说一个完全限定的类名。因此,如果不进行修改,它们是不可复制的。其他答案中提供了粘贴安全日志声明的建议,但它们也有缺点,如增加字节码或添加运行时内省。我不推荐这些。复制粘贴是一个编辑器问题,因此编辑器解决方案是最合适的
在IntelliJ中,我建议添加一个活动模板:
- 使用“log”作为缩写
- 使用
private static final org.slf4j.Logger Logger=org.slf4j.LoggerFactory.getLogger($CLASS$.CLASS)代码>作为模板文本李>
- 单击编辑变量并使用表达式
className()
- 选中复选框以重新格式化和缩短FQ名称
- 将上下文更改为Java:declaration
- 单击编辑变量并使用表达式
log
,它将自动展开为
private static final Logger logger = LoggerFactory.getLogger(ClassName.class);
并自动为您重新格式化和优化导入。只需使用类文字,即
NameOfClass。class
getClass()
方法在对象类中定义,并具有以下签名:
公共最终类getClass()
因为它没有定义为静态的,所以不能在静态代码块中调用它。有关更多信息,请参见以下答案:
如果处于静态上下文中,则必须使用类文字表达式来获取类,因此基本上必须执行以下操作:
Foo.class
这种类型的表达式称为类字面值,其解释如下:
类文字是由类、接口、数组或基元类型的名称后跟“.”和标记类组成的表达式。类文本的类型是class。它计算为当前实例类的定义类加载器定义的命名类型(或void)的类对象
您还可以在for Class上找到有关此主题的信息。至于问题中的代码示例,标准解决方案是通过其名称显式引用该类,甚至可以不使用
getClassLoader()
调用:
class MyClass {
public static void startMusic() {
URL songPath = MyClass.class.getResource("background.midi");
}
}
这种方法仍然有一个缺点,即当您需要将此代码复制到许多类似的类时,它不能非常安全地防止复制/粘贴错误
至于标题中的确切问题,有一个技巧贴在报纸上:
它使用嵌套的匿名对象
子类来获取执行上下文。此技巧的优点是复制/粘贴安全
在其他类继承自的基类中使用此选项时要小心:
还值得注意的是,如果这个代码段被塑造成某个基类的静态方法,那么
currentClass
值将始终是对该基类的引用,而不是对可能使用该方法的任何子类的引用。我自己也在努力解决这个问题。一个很好的技巧是在静态上下文中使用当前线程获取类加载器。这也适用于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;
}
试试这样的。它对我有用。日志(类名)
在Java7+中,您可以在静态方法/字段中执行此操作:
MethodHandles.lookup().lookupClass()
试试看
或
假设有一个实用程序类,那么示例代码将是——
URL url = Utility.class.getClassLoader().getResource("customLocation/".concat("abc.txt"));
CustomLocation—如果资源中有任何文件夹结构,请删除此字符串文字 我也有同样的问题!
但要解决这个问题,只需修改代码如下
public static void startMusic() {
URL songPath = YouClassName.class.getClassLoader().getResource("background.midi");
}
这对我来说很好,希望它也能对您很好。在出现用户定义(例如非J2SE)类的实例之前使用
getResource()
有时会失败。问题是JRE在那个阶段将使用引导类装入器,而引导类装入器的类路径上没有应用程序资源。class.class的名称是显而易见的,但这要求您知道类的名称。GetEnclosuringClass技巧不仅适用于复制粘贴,也适用于静态基类方法,这些方法间接地利用了内省类。getResource()
的行为可能与类加载器.getResource()
稍有不同;请参阅“不确定为什么要提供此线程中已有的相同答案”三次:从2011年起两次,从2013年起一次。如果类加载器通过访问“resources\\config”文件夹加载类日志,则此解决方案有效。在一些具有多个类加载器的服务器上(例如,一个类加载器用于加载lib文件夹,另一个用于加载app lib和资源),情况并非如此。出于这个原因,这个答案的解决方案有时只是巧合!如果您只需要getSimpleName()调用来打印main方法的帮助,那么这是一个不错的解决方案。我正在寻找一个“复制粘贴”解决方案,用于在不每次更改类名的情况下,随时随地添加记录器。你给了我:private static final Logger LOG=LoggerFactory.getLogger(MethodHandles.lookup().lookupClass())代码>受支持的最佳解决方案,缺点是Android在API 26(即Android 8)之前不支持此功能。当运行错误代码时,这将导致复制/粘贴和sad结果
Thread.currentThread().getStackTrace()[1].getClassName()
Thread.currentThread().getStackTrace()[2].getClassName()
URL url = Utility.class.getClassLoader().getResource("customLocation/".concat("abc.txt"));
public static void startMusic() {
URL songPath = YouClassName.class.getClassLoader().getResource("background.midi");
}