您的位置:首页 > 教育 > 锐评 > 获取 包 的类名信息以及 使用类名信息反向实例化类

获取 包 的类名信息以及 使用类名信息反向实例化类

2025/2/25 14:08:46 来源:https://blog.csdn.net/ling_zhi_xin/article/details/141830209  浏览:    关键词:获取 包 的类名信息以及 使用类名信息反向实例化类

文章目录

        • 反实例化
        • 获取对应的包路径
        • 获取 file 的 class 文件类名
        • 获取 jar 包class 文件类名
        • 完整Utils方法

反实例化

所有类实现 DeviceInterface 接口本处不做简绍

  • Class.forName(classPath)
    Class.forName(classPath) 是 Java 反射 API 中的一个方法,用于根据给定的类名(通常是完全限定的类名,即包含包名的类名)加载类。这个方法会在类路径(classpath)中查找指定的类,并返回一个 Class 对象,该对象代表了指定类的运行时类信息。
  • DeviceInterface.class.isAssignableFrom
    判断是否对应类信息
  • clazz.getDeclaredConstructor()
    clazz.getDeclaredConstructor() 是 Java 反射 API 中的一个方法,用于获取一个类中声明的构造函数(即没有继承的构造函数)。此方法仅返回类中声明的构造函数,而不包括从父类继承的构造函数。如果类中没有任何构造函数,那么这个方法将返回 null
  • constructor.newInstance();
    返回实例
String classPath = devicePackAge + "." + className;
Class<?> aclazz = Class.forName(classPath);
if(DeviceInterface.class.isAssignableFrom(aclazz)){return createInstance((Class<DeviceInterface>) aclazz);
}private static <T> T createInstance(Class<T> clazz) throws Exception {Constructor<T> constructor = clazz.getDeclaredConstructor();return constructor.newInstance();
}
获取对应的包路径

在处理 Java 类加载器和资源定位时,URL 对象的 getProtocol() 方法返回的协议(protocol)指定了资源的来源类型。常见的协议有两种:file 和 jar。

  • file 协议
    当 URL 的协议是 file 时,它表示资源位于本地文件系统中。这种情况下,URL 的路径部分通常指向一个文件或目录的本地路径。
  • jar 协议
    当 URL 的协议是 jar 时,它表示资源位于一个 JAR 文件中。这种情况下,URL 的路径部分通常指向一个 JAR 文件的位置,后面跟着一个 ! 符号,再跟上一个内部路径,指示 JAR 文件内的某个资源位置。
public static List<String> getClassName(String packageName, boolean recursive) {List<String> classes = new ArrayList<>();String packageDirName = packageName.replace('.', '/');Enumeration<URL> dirs;try {dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);while (dirs.hasMoreElements()) {URL url = dirs.nextElement();String protocol = url.getProtocol();if ("file".equals(protocol)) {String filePath = URLDecoder.decode(url.getFile(), "UTF-8");findAndAddClassNamesByFile(packageName, filePath, recursive, classes);} else if ("jar".equals(protocol)) {handleJarFile(url, packageName, recursive, classes);}}} catch (IOException e) {e.printStackTrace();}return classes;}
获取 file 的 class 文件类名

获取项目运行时 的class 文件信息获取类名

private static void findAndAddClassNamesByFile(String packageName, String packagePath, final boolean recursive, List<String> classes) {File dir = new File(packagePath);if (!dir.exists() || !dir.isDirectory()) {return;}File[] dirfiles = dir.listFiles(file -> (recursive && file.isDirectory()) || (file.getName().endsWith(".class")));if (dirfiles != null) {for (File file : dirfiles) {if (file.isDirectory()) {findAndAddClassNamesByFile(packageName + "." + file.getName(),file.getAbsolutePath(),recursive,classes);} else {String className = file.getName().substring(0, file.getName().length() - 6); // Remove .class extensionif (className.length() > 0) {classes.add(className);}}}}}
获取 jar 包class 文件类名
  • 处理文件系统路径 (file 协议):
    使用 URLDecoder.decode 来解码文件路径。
    调用 findAndAddClassesInPackageByFile 方法来递归地查找文件系统中的类文件。
  • 处理 JAR 文件 (jar 协议):
    使用 URL.openStream() 打开 JAR 文件流。
    创建 JarInputStream 来读取 JAR 文件中的条目。
    遍历 JAR 文件中的所有条目,并检查每个条目是否是一个类文件。
    如果是类文件,则将其名字添加到类列表中。
    如果是目录并且递归标志为 true,则递归处理子目录。
  • 递归处理子目录:
    当遇到 JAR 文件中的子目录时,可以递归调用 handleJarFile 方法来处理子目录中的类文件。
  • getNextJarEntry:
    getNextJarEntry 是 java.util.jar.JarInputStream 类中的一个方法,用于从 JAR 文件流中读取下一个条目(即 JarEntry)。这个方法在处理 JAR 文件时非常有用,因为它允许你逐个读取 JAR 文件中的每个条目,并对其进行处理。
private static void handleJarFile(URL jarUrl, String packageName, boolean recursive, List<String> classes) throws IOException {InputStream is = jarUrl.openStream();JarInputStream jis = new JarInputStream(is);try {JarEntry entry;while ((entry = jis.getNextJarEntry()) != null) {String name = entry.getName();if (name.startsWith(packageName) && name.endsWith(".class")) {String className = name.substring(0, name.length() - 6).replace('/', '.');classes.add(className);} else if (recursive && entry.isDirectory()) {String subPackageName = name.replace('/', '.').substring(0, name.length() - 1);if (!subPackageName.equals(packageName)) {handleJarFile(jarUrl, subPackageName, recursive, classes);}}}} finally {jis.close();}
}
完整Utils方法

这个是完整的 整个 utils 方法,通过filie获取跟jar 包获取, 用于获取对应的类名去反项实例化实体类去调用方法

package org.gateway.utils.scanner;import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;public class PackageScanner {public static List<String> getClassName(String packageName, boolean recursive) {List<String> classes = new ArrayList<>();String packageDirName = packageName.replace('.', '/');Enumeration<URL> dirs;try {dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);while (dirs.hasMoreElements()) {URL url = dirs.nextElement();String protocol = url.getProtocol();if ("file".equals(protocol)) {String filePath = URLDecoder.decode(url.getFile(), "UTF-8");findAndAddClassNamesByFile(packageName, filePath, recursive, classes);} else if ("jar".equals(protocol)) {handleJarFile(url, packageName, recursive, classes);}}} catch (IOException e) {e.printStackTrace();}return classes;}private static void findAndAddClassNamesByFile(String packageName, String packagePath, final boolean recursive, List<String> classes) {File dir = new File(packagePath);if (!dir.exists() || !dir.isDirectory()) {return;}File[] dirfiles = dir.listFiles(file -> (recursive && file.isDirectory()) || (file.getName().endsWith(".class")));if (dirfiles != null) {for (File file : dirfiles) {if (file.isDirectory()) {findAndAddClassNamesByFile(packageName + "." + file.getName(),file.getAbsolutePath(),recursive,classes);} else {String className = file.getName().substring(0, file.getName().length() - 6); // Remove .class extensionif (className.length() > 0) {classes.add(className);}}}}}private static void handleJarFile(URL jarUrl, String packageName, boolean recursive, List<String> classes) throws IOException {InputStream is = jarUrl.openStream();JarInputStream jis = new JarInputStream(is);try {JarEntry entry;while ((entry = jis.getNextJarEntry()) != null) {String name = entry.getName();if (name.startsWith(packageName) && name.endsWith(".class")) {String className = name.substring(0, name.length() - 6).replace('/', '.');classes.add(className);} else if (recursive && entry.isDirectory()) {String subPackageName = name.replace('/', '.').substring(0, name.length() - 1);if (!subPackageName.equals(packageName)) {handleJarFile(jarUrl, subPackageName, recursive, classes);}}}} finally {jis.close();}}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com