如何获取任何Java文件的类名

4

Java是否提供了一种简单的方法来实现这个?

我知道如何使用Foo.class.getName()来获取这个。

但是如果我通过某个方法传递任何对象,我该怎么做呢?比如:

public String getClass(File file){
          // Get file class
}

其中,file是一个以.java为扩展名的Java文件。如果我直接硬编码Java类的名称到Foo.class.getName()中,我知道它可以工作,但我的方法包括在当前目录或包中找不到的Java文件。有人能指导我正确的方向吗?提前感谢您。


2
所以你不是在询问如何找到一个对象的类,而是在询问文件声明的public class - 2rs2ts
这是一个 .java 文件吗?即您想从中提取类名的 Java 源代码;还是一个 .class 文件?即您想要加载的已编译 Java 类? - Boris the Spider
2
清除一下,假设文件名为HelloWorld.java。文件对象是java.io.File的实例,其中包含来自HelloWorld.java的内容。OP想知道的是如何通过此文件对象检索HelloWorld。 - Sikorski
1
请下次发布您的真正问题,而不是其中的一部分。这样,您可以获得更好和更精确的帮助。 - Luiggi Mendoza
@LuiggiMendoza 嗨,对此感到抱歉。我已经完成了方法计数部分,唯一遇到的问题是如何对包外的任何文件进行计数。 - Ceelos
显示剩余3条评论
4个回答

4

Java文件名应该与类名或枚举名称相同,因此我们可以使用文件名:

public String getClass(File file){
  return removeExtension(file.getName());
}

removeExtension 有很多不同的实现方式,这里只提供一种:

public static String removeExtension(String file){
  return file.replaceFirst("[.][^.]+$", "");
}

更多内容请参见:如何在Java中获取不带扩展名的文件名? 引用:

......我想这样做的原因是我想计算类中的方法。

好的,这并不是实现目标的正确方法。你应该研究反射:什么是反射以及为什么它有用?

为了在类上使用反射,必须先加载它。如果您正在评估包外的类,则使用反射可能无法正常工作,并且在尝试加载它们时可能会遇到问题。最好的情况是解析Java文件并获取所需信息。 - Luiggi Mendoza
1
这并不完全等同于 Class.getName(),后者还会返回包名。这可能需要读取包声明。 - Bhesh Gurung
@LuiggiMendoza 说得好,但是由于OP无法从文件中获取类名,他们将在解析文件的其余部分时遇到很大的麻烦,所以我希望他们不要尝试这样做。 - weston
@BheshGurung 说得好,如果需要的话,打开文件并从中使用正则表达式提取包名称应该是一个简单的任务。 - weston
@LuiggiMendoza 我不会说真正的问题是计算类内方法的数量。这个已经解决了,我遇到的问题是获取类本身。 - Ceelos
显示剩余4条评论

3
这是一个示例代码,借助 JavaParser 从源中获取类名。
对于命名错误的源文件也适用。
import com.github.javaparser.*;
import com.github.javaparser.ast.*;
import com.github.javaparser.ast.body.*;
import java.io.*;
import java.util.*;

public class ClassnameLister {

    private static String parseClassname(File filename) throws Exception {
        try (FileInputStream fin = new FileInputStream(filename)) {
            CompilationUnit cu = JavaParser.parse(fin);
            String packagePrefix = cu.getPackage().getName().toString();
            if (!packagePrefix.isEmpty()) packagePrefix += ".";
            for (TypeDeclaration type : cu.getTypes())
                if (type instanceOf ClassOrInterfaceDeclaration 
                        && ModifierSet.isPublic(type.getModifiers()))
                    return packagePrefix + type.getName();
        }
        return null;
    }

    public static void main(final String[] args) throws Exception {
        System.out.println(parseClassname(new File(args[0])));
    }
}

2
你可以直接使用文件名来处理,不需要使用 getClass()。你想要做的是使用 getName() 获取File的文件名,然后你需要去掉扩展名
在那个SO问题中有一个解决方案,用了Apache的FilenameUtils 来实现第二部分。对于你而言应该像这样:
import org.apache.commons.io.FilenameUtils;

public String getClass(File file) {
    return FilenameUtils.removeExtension(file.getName());
}

当然,如果您已经创建了一个文件,那么您应该已经知道它的名称。我只是让它适合您的存根函数。

如果您总是要处理一个.java文件,那么您可以简单地将扩展名split()分离出来:

    return file.getName().split(".java")[0];

我非常接近投票支持这个问题的回答和Weston的答案,但阻止我这样做的是需要第三方库来完成,而这可以通过正则表达式来完成... - JonK
1
@JonK 因此我在备注中提到了OP是否能够知道这个扩展名的问题。他说他知道它将是一个.java文件,但我不应该假设。 - 2rs2ts
好的,你的编辑提供了一种不依赖于库的方法,所以这里给你加上一个赞。 - JonK
@JonK Apache Commons Libraries都是开源的。如果您不想/不需要添加该库,只需将代码复制并添加到项目中的实用类/方法中即可。 - Luiggi Mendoza
@LuiggiMendoza 确实如此,不过我个人不会这样做。不过,这只是我的个人看法! - JonK

1
你需要自己解析该文件。
  1. 包名 查找以 \\s*package 开头的行。 如果找不到匹配的行,则没有声明包。

  2. 类名 外部类定义包含 class,但可以以更多关键字开始和引导。最好的方法是取第一次出现的 class,并检查最终键。

将你的包名和类名用一个点连接起来,就完成了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接