如何从 Java 中的静态方法调用 getClass()?
Posted
技术标签:
【中文标题】如何从 Java 中的静态方法调用 getClass()?【英文标题】:How to call getClass() from a static method in Java? 【发布时间】:2012-01-06 17:04:13 【问题描述】:我有一个必须有一些静态方法的类。在这些静态方法中,我需要调用方法 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
修复此编译时错误的适当方法是什么?
【问题讨论】:
在用户定义(例如非 J2SE)类的实例之前使用getResource()
有时会失败。问题是 JRE 将在那个阶段使用引导类加载器,它不会在(引导加载器的)类路径上拥有应用程序资源。
【参考方案1】:
答案
只需使用TheClassName.class
而不是getClass()
。
声明记录器
由于这在特定用例中引起了如此多的关注——提供一种插入日志声明的简单方法——我想我会在这方面添加我的想法。日志框架通常期望日志被限制在特定的上下文中,比如一个完全限定的类名。因此,如果不进行修改,它们就不能复制粘贴。其他答案中提供了有关粘贴安全日志声明的建议,但它们有缺点,例如膨胀字节码或添加运行时自省。我不推荐这些。复制粘贴是编辑器的问题,因此编辑器解决方案是最合适的。
在 IntelliJ 中,我建议添加一个实时模板:
使用“log”作为缩写 使用private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger($CLASS$.class);
作为模板文本。
单击编辑变量并使用表达式className()
添加类
选中复选框以重新格式化和缩短 FQ 名称。
将上下文更改为 Java:声明。
现在如果你输入log<tab>
,它会自动展开为
private static final Logger logger = LoggerFactory.getLogger(ClassName.class);
并自动为您重新格式化和优化导入。
【讨论】:
当不正确的代码在不同的类中运行时,这将导致复制/粘贴和悲伤的结果。 @WilliamEntriken:使用匿名内部类并不是一个很好的解决方案,它只是用额外的类文件使你的字节码膨胀,以节省几秒钟的开发人员工作量。我不确定人们在必须在整个地方复制/粘贴的地方都在做什么,但应该使用编辑器解决方案而不是语言破解来处理它。例如如果使用 IntelliJ,请使用可以插入类名的实时模板。 “我不确定人们在到处复制/粘贴的地方做什么”——例如在 android 中使用Log
,通常需要提供标签类名。可能还有其他例子。当然,您可以为此声明一个字段(这是常见做法),但这仍然是复制和粘贴。
@user149408:是的,这已经被讨论了很多。尽管此用例与原始问题实际上无关,但这是人们访问此问题的常见原因,因此我在答案中添加了一些想法。
您在实时模板解决方案中忘记了一件事:单击“编辑变量”并在CLASS
的表达式中输入className()
。这将确保 $CLASS$ 实际上被替换为类名,否则它将为空。【参考方案2】:
对于问题中的代码示例,标准的解决方案是通过名称显式引用该类,甚至可以不使用getClassLoader()
调用:
class MyClass
public static void startMusic()
URL songPath = MyClass.class.getResource("background.midi");
这种方法仍有一个缺点,即如果您需要将此代码复制到许多类似的类中,它对复制/粘贴错误不是很安全。
而至于标题中的确切问题,adjacent thread 贴出了一个技巧:
Class currentClass = new Object() .getClass().getEnclosingClass();
它使用嵌套的匿名Object
子类来获取执行上下文。这个技巧的好处是复制/粘贴安全......
在其他类继承自的基类中使用 this 时的注意事项:
同样值得注意的是,如果这个 sn-p 是某个基类的静态方法,那么currentClass
值将始终是对该基类的引用,而不是对可能使用该方法的任何子类的引用。
【讨论】:
到目前为止我最喜欢的答案。 NameOfClass.class 很明显,但这需要您知道您的班级名称。 getEnclosureClass 技巧不仅对复制粘贴有用,对使用自省的静态基类方法也很有用 顺便提一下,Class.getResource()
的行为可能与 ClassLoader.getResource()
略有不同;见***.com/a/676273【参考方案3】:
在 Java7+ 中,您可以在静态方法/字段中执行此操作:
MethodHandles.lookup().lookupClass()
【讨论】:
如果您只需要 getSimpleName() 调用即可从 main 方法打印帮助,这是一个不错的解决方案。 我正在寻找一种“复制粘贴”解决方案,用于在每个位置添加记录器,而无需每次都更改类名。你给了我:private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
支持它的最佳解决方案,缺点是Android直到API 26,即Android 8才支持它。【参考方案4】:
我自己也在为此苦苦挣扎。一个不错的技巧是在静态上下文中使用当前线程来获取 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;
【讨论】:
【参考方案5】:只需使用类文字,即NameOfClass.class
【讨论】:
【参考方案6】:试试看
Thread.currentThread().getStackTrace()[1].getClassName()
或者
Thread.currentThread().getStackTrace()[2].getClassName()
【讨论】:
这种方法的美妙之处在于它也适用于 Android 8 (API 26) 之前的版本。请注意索引[1]
将导致所有日志消息将Thread
报告为其在Android 4.4.4 上的来源。 [2]
似乎在 Android 和 OpenJRE 上都给出了正确的结果。【参考方案7】:
getClass()
方法在 Object 类中定义,签名如下:
公共最终类 getClass()
因为它没有被定义为static
,所以你不能在静态代码块中调用它。有关更多信息,请参阅这些答案:Q1、Q2、Q3。
如果你在静态上下文中,那么你必须使用类文字表达式来获取 Class,所以你基本上必须这样做:
Foo.class
这种类型的表达式称为Class Literals,它们在Java Language Specification Book中解释如下:
类字面量是由类、接口、数组或原始类型的名称后跟一个“.”组成的表达式。和令牌类。类文字的类型是 Class。它评估为由当前实例的类的定义类加载器定义的命名类型(或 void)的 Class 对象。
您还可以在 API documentation 上找到有关此主题的信息,以获取 Class。
【讨论】:
【参考方案8】:我遇到了同样的问题! 但要解决它只需修改您的代码如下。
public static void startMusic()
URL songPath = YouClassName.class.getClassLoader().getResource("background.midi");
这对我来说很好,希望它对你也很好。
【讨论】:
什么是“YourClassName”?应该是'startMusic'?无论如何,为了避免指定类名,我们不能只使用'this.class.getClassLoader()'吗?【参考方案9】:假设有一个 Utility 类,那么示例代码将是 -
URL url = Utility.class.getClassLoader().getResource("customLocation/".concat("abc.txt"));
CustomLocation - 如果资源中的任何文件夹结构,否则删除此字符串文字。
【讨论】:
【参考方案10】:试试这样的。这个对我有用。 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");
【讨论】:
不知道为什么您要提供与此线程中已有的相同答案三次:2011 年两次,2013 年一次。 如果类 Logg 由具有“resources\\config”文件夹访问权限的类加载器加载,则此解决方案有效。在某些具有多个类加载器的服务器上(例如,一个类加载器用于加载 lib 文件夹,另一个用于加载应用程序库和资源),这是不正确的。出于这个原因,这个答案的解决方案有时只是巧合!以上是关于如何从 Java 中的静态方法调用 getClass()?的主要内容,如果未能解决你的问题,请参考以下文章