工作了有一段时间了,我觉得是时候去复习下Java的一些基础知识,因此写下了这篇文章。平常开发过程中,前端写的比较多,后端也不能忘!
一. 案例出发
先准备一个模板类:
public class User { public int id; private String name; public User(String name, int id) { this.id = id; this.name = name; } private User(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
开始反射
import java.lang.reflect.*; public class Test { public static final String LINE = " "; public static final String SPACE = " "; public static void main(String[] args) throws Exception { Class<?> c = Class.forName("com.User"); // Class<?> c = Test.class.getClassLoader().loadClass("com.User"); StringBuilder sb = new StringBuilder(); // 打印包,类名 String packageName = c.getPackage().getName(); sb.append("package " + packageName + ";" + LINE); sb.append(LINE); sb.append("public class " + c.getSimpleName() + "{" + LINE); // 打印成员变量 Field[] declaredFields = c.getDeclaredFields(); for (Field field : declaredFields) { // Field.getModifiers()返回一个int类型的数值,用于标识public、static等标识符 String fieldModifier = Modifier.toString(field.getModifiers()); // 获取属性类型的简要名称 String typeName = field.getType().getSimpleName(); // 属性的名称 String fieldName = field.getName(); sb.append(SPACE + fieldModifier + " " + typeName + " " + fieldName + ";" + LINE); } sb.append(LINE); // 打印构造 Constructor<?>[] declaredConstructors = c.getDeclaredConstructors(); for (Constructor<?> constructor : declaredConstructors) { // 构造函数的标识符 String constructorModifier = Modifier.toString(constructor.getModifiers()); sb.append(SPACE + constructorModifier + " " + c.getSimpleName() + " " + "("); // 打印构造函数的参数 printParam(sb, constructor.getParameterTypes()); } // 打印方法 Method[] methods = c.getDeclaredMethods(); for (Method method : methods) { // 方法的标识符 String methodModifier = Modifier.toString(method.getModifiers()); // 方法返回类型 String returnTypeName = method.getReturnType().getSimpleName(); // 方法名称 String methodName = method.getName(); sb.append(SPACE + methodModifier + " " + returnTypeName + " " + methodName + "("); printParam(sb, method.getParameterTypes()); } sb.append("}"); System.out.println(sb.toString()); } private static void printParam(StringBuilder sb, Class<?>[] parameterTypes2) { Class<?>[] parameterTypes = parameterTypes2; for (int i = 0; i < parameterTypes.length; i++) { // 参数的类型 String simpleName = parameterTypes[i].getSimpleName(); if (i == 0) { sb.append(simpleName + " args"); } else { sb.append(", " + simpleName + " args"); } } sb.append(") {" + LINE); sb.append(SPACE + "}" + LINE); sb.append(LINE); } }
最终的结果如下:
二. 反射方法的分析
2.1 反射的方式
代码中我们可以发现,这里提供了两种基本的反射:
-
Class.forName()
-
getClassLoader().loadClass()
首先,在模板类中添加静态块代码:
再来运行一下两种反射方式的代码:
forName
:
getClassLoader
:
结论如下:
初始化:通过forName
方式反射的对象,会进行初始化(会执行静态代码),而通过getClassLoader
方式反射的对象,是不会进行初始化的。
2.2 修饰符的打印
如果想打印方法、属性的修饰符,我们应该通过Modifier
类去拿到。请看这一行代码:
String fieldModifier = Modifier.toString(field.getModifiers());
来看下Modifier.toString
的源码:
public static String toString(int mod) { StringBuilder sb = new StringBuilder(); int len; if ((mod & PUBLIC) != 0) sb.append("public "); if ((mod & PROTECTED) != 0) sb.append("protected "); if ((mod & PRIVATE) != 0) sb.append("private "); /* Canonical order */ if ((mod & ABSTRACT) != 0) sb.append("abstract "); if ((mod & STATIC) != 0) sb.append("static "); if ((mod & FINAL) != 0) sb.append("final "); if ((mod & TRANSIENT) != 0) sb.append("transient "); if ((mod & VOLATILE) != 0) sb.append("volatile "); if ((mod & SYNCHRONIZED) != 0) sb.append("synchronized "); if ((mod & NATIVE) != 0) sb.append("native "); if ((mod & STRICT) != 0) sb.append("strictfp "); if ((mod & INTERFACE) != 0) sb.append("interface "); if ((len = sb.length()) > 0) /* trim trailing space */ return sb.toString().substring(0, len-1); return ""; }
很明显,其通过语言修饰符的类型(int类型)来做对应的映射并返回。
案例代码中有三块地方都支持获得修饰符类型:
-
field.getModifiers()
:字段修饰符。 -
constructor.getModifiers()
:构造修饰符。 -
method.getModifiers()
:方法的修饰符。
2.3 getDeclaredxxx和getxxx的区别
以Field为例:
Field[] declaredFields = c.getDeclaredFields(); Field[] fields = c.getFields();
案例如下:
1.新建一个Parent
类:
public class Parent { public String parentAddress; private Integer Number; }
2.让User
类继承Parent
类
3.测试1:getDeclaredFields
打印成员变量:
4.测试2:getFields
打印成员变量:
两者区别如下:
比较内容 | getDeclaredFields | getFields |
---|---|---|
作用的类的范围 | 仅仅限于当前类 | 还可以包括父类 |
作用的修饰符范围 | 可以获取public和非public类型 | 只能获得public类型的相关值 |
2.4 getSimpleName和getName有什么不同
以这行代码为例:
String typeName = field.getType().getSimpleName();
若我将getSimpleName
改为getName
,看看输出结果会有什么不同:
可以发现gatName
输出的是这个类型的全名称,那么对应的getSimpleName
就顾名思义,返回的是类型名称。
对于其他的相关属性和API,代码的注释都写的比较详细了,就不展开介绍了。
到此这篇关于Java通过反射来打印类的方法实现的文章就介绍到这了,更多相关Java反射打印类内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://blog.csdn.net/Zong_0915/article/details/120238079