如何在jar文件中获取类的名称?


112

我有一个JAR文件,我需要获取此JAR文件中所有类的名称。我怎样才能做到这一点?

我在Google上搜索了一下,看到了有关JarFile或Java的内容,ClassLoader但我不知道该怎么做。


您使用的是IDE吗?如果使用的是IDE,它将自动显示。
joey rohan

我正在使用Eclipse,但是我需要使用代码来完成此操作。
sticksu 2013年

@LuiggiMendoza-可能的副本包含示例答案以及文档资源。搜索这些类名+示例之一将产生一些有用的结果。
Aiias

@Alias可能重复说明如何从jar中查找和获取文件,而问题是要在jar中获取类名(可能是其中的所有包中的类)。ErikKaju的答案中的链接指向使用JarInputStreamJarEntry类的可能解决方案,而您所引用的链接的任何答案中都找不到该类。
Luiggi Mendoza

Answers:


68

不幸的是,Java没有提供一种简便的方法来在“本地” JRE中列出类。这给您提供了两个选择:(a)对于任何给定的JAR文件,您可以列出该JAR文件中的条目,找到.class文件,然后确定每个.class文件代表哪个Java类;或(b)您可以使用为您执行此操作的库。

选项(a):手动扫描JAR文件

在此选项中,我们将填充classNamesjar文件中包含的所有Java类的列表/path/to/jar/file.jar

List<String> classNames = new ArrayList<String>();
ZipInputStream zip = new ZipInputStream(new FileInputStream("/path/to/jar/file.jar"));
for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
    if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
        // This ZipEntry represents a class. Now, what class does it represent?
        String className = entry.getName().replace('/', '.'); // including ".class"
        classNames.add(className.substring(0, className.length() - ".class".length()));
    }
}

选项(b):使用专门的反射库

番石榴

番石榴ClassPath自至少14.0,这是我使用和喜欢。一件好事ClassPath是,它不会加载找到的类,这在扫描大量类时很重要。

ClassPath cp=ClassPath.from(Thread.currentThread().getContextClassLoader());
for(ClassPath.ClassInfo info : cp.getTopLevelClassesRecurusive("my.package.name")) {
    // Do stuff with classes here...
}

感言

我没有亲自使用Reflections库,但是它似乎很受欢迎。网站上提供了一些很棒的示例,例如这种快速方法,可以将任何类加载到任何 JAR文件提供的包中,这对于您的应用程序也可能有用。

Reflections reflections = new Reflections("my.project.prefix");

Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);

Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(SomeAnnotation.class);

如果从可执行jar运行,则反射也不起作用。
路加福音

在可执行jar上运行的Spring解决方案:stackoverflow.com/a/21430849/4265610
路加福音

1
随便使用。jar tvf jarfile.jar。你为什么要做所有这些。
菲利普·雷戈19'Jul

183

您可以使用Java jar工具。在txt文件中列出jar文件的内容,您可以看到jar中的所有类。

jar tvf jarfile.jar

-t列出要归档的目录

-v在标准输出上生成详细输出

-f指定归档文件名


1
谢谢。这回答了未要求的OP的“仅获取课程清单”部分。
octopusgrabbus

9
您也可以unzip -l jarfile.jar在紧要关头使用。JAR文件只是带有清单的zip文件!
2015年

3
问题是,在给定一个类加载器实例的情况下,他可能想在运行时将类文件放在jar中(可能会看到在该特定jar中加载了哪些类)。
理查德·杜尔

19

也许您正在寻找jar命令以获取终端中的类列表,

$ jar tf ~/.m2/repository/org/apache/spark/spark-assembly/1.2.0-SNAPSHOT/spark-assembly-1.2.0-SNAPSHOT-hadoop1.0.4.jar 
META-INF/
META-INF/MANIFEST.MF
org/
org/apache/
org/apache/spark/
org/apache/spark/unused/
org/apache/spark/unused/UnusedStubClass.class
META-INF/maven/
META-INF/maven/org.spark-project.spark/
META-INF/maven/org.spark-project.spark/unused/
META-INF/maven/org.spark-project.spark/unused/pom.xml
META-INF/maven/org.spark-project.spark/unused/pom.properties
META-INF/NOTICE

哪里,

-t  list table of contents for archive
-f  specify archive file name

或者,仅在结果上方显示grep即可看到.classes

$ jar tf ~/.m2/repository/org/apache/spark/spark-assembly/1.2.0-SNAPSHOT/spark-assembly-1.2.0-SNAPSHOT-hadoop1.0.4.jar | grep .class
org/apache/spark/unused/UnusedStubClass.class

要查看classes的数量,

jar tvf launcher/target/usergrid-launcher-1.0-SNAPSHOT.jar | grep .class | wc -l
61079

2
即使问题所有者需要基于代码的解决方案,这也正是我所需要的。谢谢!
providencemac

10

这是我正在使用的hack:

您可以这样使用java的自动完成功能:

java -cp path_to.jar <Tab>

这将为您提供可作为开始课程通过的课程列表。当然,尝试使用没有主文件的文件不会做任何事情,但是您可以看到java认为内部.jar调用类的想法。



5

你可以试试:

jar tvf jarfile.jar 

仅当您的jar可执行时,这才是有用的,即在清单中您已将某个类定义为主类


在示例jar上向您的答案添加一些特定示例。
朱鲁

4

下面的命令将列出jar文件的内容。

命令:- unzip -l jarfilename.jar

o / p样本:

Archive: hello-world.jar Length Date Time Name --------- ---------- ----- ---- 43161 10-18-2017 15:44 hello-world/com/ami/so/search/So.class 20531 10-18-2017 15:44 hello-world/com/ami/so/util/SoUtil.class --------- ------- 63692 2 files

根据手册 unzip

-l列出归档文件(短格式)。打印指定文件的名称,未压缩的文件大小以及修改日期和时间,以及所有指定文件的总数。如果使用定义的OS2_EAS编译了UnZip,则-l选项还将列出存储的OS / 2扩展属性(EA)和OS / 2访问控制列表(ACL)大小的列。此外,还会显示zipfile注释和单个文件注释(如果有)。如果文件是从单个大小写的文件系统(例如,旧的MS-DOS FAT文件系统)中归档的,并且提供了-L选项,则文件名将转换为小写并以脱字号(^)为前缀。


尽管此代码段是受欢迎的,并且可以提供一些帮助,但是如果它包含有关如何以及为什么可以解决该问题的说明,则可以大大改善。请记住,您将来会为读者回答问题,而不仅仅是现在问的人!请编辑您的答案以添加说明,并指出适用的限制和假设。
Toby Speight


1

使用以下bash脚本:

#!/bin/bash

for VARIABLE in *.jar
do
   jar -tf $VARIABLE |grep "\.class"|awk -v arch=$VARIABLE '{print arch ":" $4}'|sed 's/\//./g'|sed 's/\.\.//g'|sed 's/\.class//g'
done

这将以以下形式列出目录中jar中的类:

file1.jar:fullyqualifiedclassName
file1.jar:fullyqualifiedclassName
file1.jar:fullyqualifiedclassName
file1.jar:fullyqualifiedclassName
file2.jar:fullyqualifiedclassName
file2.jar:fullyqualifiedclassName
file2.jar:fullyqualifiedclassName

样本输出:

commons-io.jar:org.apache.commons.io.ByteOrderMark
commons-io.jar:org.apache.commons.io.Charsets
commons-io.jar:org.apache.commons.io.comparator.AbstractFileComparator
commons-io.jar:org.apache.commons.io.comparator.CompositeFileComparator
commons-io.jar:org.apache.commons.io.comparator.DefaultFileComparator
commons-io.jar:org.apache.commons.io.comparator.DirectoryFileComparator
commons-io.jar:org.apache.commons.io.comparator.ExtensionFileComparator
commons-io.jar:org.apache.commons.io.comparator.LastModifiedFileComparator

在Windows中,您可以使用Powershell:

Get-ChildItem -File -Filter *.jar |
ForEach-Object{
    $filename = $_.Name
    Write-Host $filename
    $classes = jar -tf $_.Name |Select-String -Pattern '.class' -CaseSensitive -SimpleMatch
    ForEach($line in $classes) {
       write-host $filename":"(($line -replace "\.class", "") -replace "/", ".")
    }
}

0

解决方案描述:Eclipse IDE可以通过创建示例Java项目并在Project Build路径中添加所有jar来实现此目的

步骤如下

  1. 创建一个示例Eclipse Java项目。

  2. 您在其构建路径中拥有的所有jar

  3. CTRL + SHIFT + T并输入完整的类名。

  4. 结果将显示在窗口中,所有罐子都具有该类。见附图。 在此处输入图片说明


0

Windows cmd:如果您在同一目录中具有所有te jar并执行以下命令,则此命令将起作用

for /r %i in (*) do ( jar tvf %i | find /I "search_string")

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.