如何调用getClass()从一个静态方法在Java?

我有一个类,必须有一些静态方法。在这些静态方法中,我需要调用方法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

修复此编译时错误的适当方法是什么?

261468 次浏览

这个问题的答案

只要使用TheClassName.class而不是getClass()

宣布伐木工

由于这对于一个特定的用例(提供一种插入日志声明的简单方法)引起了如此多的关注,所以我想在此补充一下我的想法。日志框架通常希望日志被限制在特定的上下文中,比如一个完全限定的类名。所以它们不经过修改就不能复制粘贴。在其他回答中提供了粘贴安全日志声明的建议,但它们有缺点,例如膨胀字节码或添加运行时自省。我不推荐这些。复制粘贴是编辑器关心的问题,所以编辑器解决方案是最合适的。

在IntelliJ中,我建议添加一个Live模板:

  • 使用“log”作为缩写
  • 使用private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger($CLASS$.class);作为模板文本。
  • 单击“编辑变量”并使用表达式className()添加CLASS
  • 选中复选框以重新格式化和缩短FQ名称。
  • 将上下文更改为Java: declaration。

现在如果你输入log<tab>,它会自动展开为

private static final Logger logger = LoggerFactory.getLogger(ClassName.class);

并自动为您重新格式化和优化导入。

简单地使用类字面量,即NameOfClass.class

getClass()方法在对象类中定义,具有以下签名:

getClass()

由于它没有定义为static,所以不能在静态代码块中调用它。查看这些答案以获取更多信息:第一季度第二季第三季

如果你在一个静态的上下文中,那么你必须使用类文字表达式来获取类,所以你基本上必须这样做:

Foo.class

这种类型的表达式被称为类文字,它们在Java语言规范手册中解释如下:

类字面值是由类、接口、数组或基本类型的名称后跟'组成的表达式。'和令牌类。类文字的类型是class。它为当前实例的类的定义类装入器所定义的命名类型(或void)求值为Class对象。

你也可以在Class的API文档中找到关于这个主题的信息。

对于问题中的代码示例,标准解决方案是通过类的名称显式引用类,甚至可以不调用getClassLoader():

class MyClass {
public static void startMusic() {
URL songPath = MyClass.class.getResource("background.midi");
}
}

这种方法仍然有一个缺点,如果您需要将此代码复制到许多类似的类中,它对于复制/粘贴错误不是很安全。

至于标题中的确切问题,相邻的线程中有一个技巧:

Class currentClass = new Object() { }.getClass().getEnclosingClass();

它使用一个嵌套的匿名Object子类来获取执行上下文。这个技巧的好处是复制/粘贴安全…

在其他类继承的基类中使用this时要注意:

同样值得注意的是,如果此代码段被塑造为某个基类的静态方法,则currentClass值将始终是对该基类的引用,而不是可能使用该方法的任何子类的引用。

我自己也在努力解决这个问题。一个很好的技巧是在静态上下文中使用当前线程来获取ClassLoader。这也可以在Hadoop MapReduce中工作。其他方法在本地运行时有效,但在MapReduce中使用时返回空InputStream。

public static InputStream getResource(String resource) throws Exception {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
InputStream is = cl.getResourceAsStream(resource);
return is;
}

试试这样的方法。这对我很管用。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");

在Java7+中,你可以在静态方法/字段中做到这一点:

MethodHandles.lookup().lookupClass()

试一试

Thread.currentThread().getStackTrace()[1].getClassName()

Thread.currentThread().getStackTrace()[2].getClassName()

假设有一个Utility类,那么示例代码将是-

    URL url = Utility.class.getClassLoader().getResource("customLocation/".concat("abc.txt"));

CustomLocation -如果资源中有任何文件夹结构,则删除此字符串文字。

我也有同样的问题! 但要解决它,只需修改你的代码如下
public static void startMusic() {
URL songPath = YouClassName.class.getClassLoader().getResource("background.midi");
}

这对我来说很好,希望它也会对你很好。