博主声明:
转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。
本文首发于此 博主:威威喵 | 博客主页:https://blog.csdn.net/smile_running
Java Reflection,称为 Java 反射,是Java基础部分的一个比较难的点。Reflection(反射)是被视为动态语言的关键,通过反射机制,我们可以在运行时(runtime)获取类的完整结构。例如,可以获取到类的变量名、方法、构造器、内部类、接口、注解等等,并且通过反射机制可以对类内部进行操作。
Java反射机制在实际开发中是非常常用的,强大一词完全可以用来形容它。作为Java基础内容的一部分,并且在很多开源框架(jdbc、spring、hibermate...)都使用到反射,可谓反射的重要性。
首先,定义一个 Person 类及 Student 类,Student 继承自 Person 类,代码非常简单。如下:
package com.test;
public class Person {
public String weight;
public String height;
public Person() {
super();
}
public Person(String weight, String height) {
super();
this.weight = weight;
this.height = height;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
@Override
public String toString() {
return "Person [weight=" + weight + ", height=" + height + "]";
}
}
package com.test;
import java.io.Serializable;
public class Student extends Person implements Serializable, Runnable {
public String stuNo;
private String stuName;
public Student() {
super();
}
public Student(String stuNo, String stuName) {
super();
this.stuNo = stuNo;
this.stuName = stuName;
}
public String getStuNo() {
return stuNo;
}
public void setStuNo(String stuNo) {
this.stuNo = stuNo;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
private int exam(String str, Integer tag) throws NoSuchMethodException {
System.out.println(str);
return tag;
}
@Override
public String toString() {
return "Student [stuNo=" + stuNo + ", stuName=" + stuName + "]";
}
@Override
public void run() {
}
}
有了这两个类,我们就可以开始利用反射来获取类的内部结构了。我们常规的创建对象操作:
@Test
public void test() {
Student student = new Student();
student.setStuNo("01");
student.setStuName("张三");
}
在开始之前,我们来学习如何利用反射的方式来获取类的结构,反射的方式有这样 4 种。
* 反射的4种获取方式,反射的源头就是获取到一个 Class 对象进行操作类的内部方法和获取类的结构。
注意:父类中声明为 public 的变量、方法、接口等也可以被获取到。
@Test
public void test() throws Exception {
/** 第一种反射方式 */
Class clazz1 = new Student().getClass();
/** 第二种反射方式 */
Class clazz2 = Student.class;
/** 第三种反射方式 */
// 先声明 xxx 类所在包的完整名
String className = "com.test.Student";
Class clazz3 = Class.forName(className);
/** 第四种反射方式 */
Class clazz4 = this.getClass().getClassLoader().loadClass(className);
}
以下都是利用反射来获取类结构的例子。
@Test
public void test() throws Exception {
Class clazz = Student.class;
Student student = (Student) clazz.newInstance();
/** 声明为 public 类型的变量可以这样获取 **/
Field field1 = clazz.getField("stuNo");
field1.set(student, "01");
System.out.println(student);
/** 其他类型变量只能通过如下获取 **/
Field field2 = clazz.getDeclaredField("stuName");
field2.setAccessible(true);
field2.set(student, "张三");
System.out.println(student);
}
@Test
public void test() throws Exception {
Class clazz = Student.class;
Student student = (Student) clazz.newInstance();
Field field1 = clazz.getField("stuNo");
Field field2 = clazz.getDeclaredField("stuName");
/** 获取 权限修饰符 **/
String str = Modifier.toString(field1.getModifiers());
System.out.println(str);
String str2 = Modifier.toString(field2.getModifiers());
System.out.println(str2);
}
获取类中的方法,并调用该方法(需注意权限修饰符)
获取类中方法的返回值
获取类中方法形参列表
获取类中方法异常类型
@Test
public void test() throws Exception {
Class clazz = Student.class;
Student student = (Student) clazz.newInstance();
Method method = clazz.getMethod("setStuNo", String.class);
method.invoke(student, "02");
System.out.println(student);
/** 获取方法的返回值类型 */
Class returnType = method.getReturnType();
System.out.println(returnType);
Method method2 = clazz.getDeclaredMethod("exam", String.class, Integer.class);
method2.setAccessible(true);
method2.invoke(student, "invoke exam method", 1);
/** 获取方法的形参列表 */
Class[] params = method2.getParameterTypes();
for (Class param : params) {
System.out.println(param);
}
/** 获取方法的异常类型 */
Class[] exceptions =method2.getExceptionTypes();
for(Class excp : exceptions) {
System.out.println(excp);
}
}
获取类的完整包名、
类中所有的构造器、
类中实现的所有接口
@Test
public void test() throws Exception {
Class clazz = Student.class;
Student student = (Student) clazz.newInstance();
//获取包名
System.out.println(clazz.getPackage());
/**
* 获取 所有构造器
*/
Constructor[] constructor = clazz.getDeclaredConstructors();
for(Constructor cons : constructor) {
System.out.println(cons);
}
/**
* 获取 所有接口
*/
Class[] interfaces =clazz.getInterfaces();
for( Class its:interfaces) {
System.out.println(its);
}
}
@Test
public void test() throws Exception {
Class clazz = Student.class;
Student student = (Student) clazz.newInstance();
//获取父类
System.out.println(clazz.getSuperclass());
//获取带泛型的父类
Type type = clazz.getGenericSuperclass();
System.out.println(type);
/**
* 获取父类的泛型
*/
Type type2 = clazz.getGenericSuperclass();
ParameterizedType args = (ParameterizedType)type2;
Type[] types = args.getActualTypeArguments();
String t_Type = (String)types[0].getTypeName();
System.out.println(t_Type);
}
以上的几个例子可以让我们知道反射的作用,反射能够在运行时状态下获取类的完整结构,在框架里显得尤为重要。