一、反射机制是概述?
1、Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
2、Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
简言之就是可以动态获取任意一个类对象并对其属性、方法等进行操作;还可以通过配置文件动态创建对象。
二、反射获取类对象的三种方式
三种方式分别是:
(1) Class.forName("包名+类名");
(2) 类名.cass();
(3) 对象.getClass();
代码详解:
1、先创建一个Student实体类
package com.zyx;
import java.io.IOException;
public class Student {
private String name;
private Integer age;
public String sex;
Student(String name, Integer age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public Student() {
}
protected Student(String name) {
this.name = name;
}
private Student(Integer age) {
this.age = age;
}
private Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void sing() {
System.out.println("唱歌啦啦啦啦啦");
}
private String dance(String name) throws IOException, NullPointerException {
System.out.println(name + "在跳舞啊啊啊啊");
return name+"在跳舞";
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
package com.zyx;
import java.lang.reflect.*;
public class TestReflect {
public static void main(String[] args) throws ClassNotFoundException {
/**
* 一、 反射获取类对象的三种方式
*/
// 1. 获取方式 Class.forName("包名+类名")
Class clazz = Class.forName("com.zyx.Student");
//2. 第二种方式 类名.class
Class clazz1 = Student.class;
//3. 第三种方法 类名.getClass
Student student = new Student();
Class clazz2 = student.getClass();
System.out.println(clazz == clazz1); // true
System.out.println(clazz == clazz2); // true
System.out.println(clazz2 == clazz1); // true 三种方式获取的类对象在内存中是同一个
}
}
三、反射获取类的构造方法及参数
(1)获取公有的构造方法 返回构造方法数组 clazz.getConStructors();
(2)获取所有的构造方法,包括私有和公有的所有权限的构造方法 返回构造方法数组clazz.getDeclaredConstructors();
(3)获取具体的某个公有的构造方法,返回单个构造方法clazz.getConStructor(); 则会获取空参的构造方法
(4) 获取所有的构造方法,包括私有和公有的所有权限的构造方法 返回构造方法数组clazz.getDeclaredConstructor(String.class); 则会获取带参类型为String类型的构造方法
clazz.getDeclaredConstructor(String.class, Integer.class); 则会获取参数为String类型和Integer类型的构造方法
(5) 获取构造方法的参数 con.getParameters();返回参数数组
package com.zyx;
import java.lang.reflect.*;
public class TestReflect {
public static void main(String[] args) {
Class clazz = Class.forName("com.zyx.Student");
/**
* 反射获取类对象的构造方法
*/
// 获取所有公共的构造方法 返回Constructor[]数组
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
// 获取所有构造方法 私有+公有的
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
// 获取具体的构造方法 返回Constructor类对象
Constructor con1 = clazz.getConstructor();
System.out.println(con1);
Constructor con2 = clazz.getDeclaredConstructor(String.class);
System.out.println(con2);
Constructor con3 = clazz.getDeclaredConstructor(String.class, Integer.class);
System.out.println(con3);
Constructor con4 = clazz.getDeclaredConstructor(Integer.class);
System.out.println(con4);
Constructor con5 = clazz.getDeclaredConstructor(String.class, Integer.class, String.class);
System.out.println(con5);
/**
* 反射获取构造方法的参数
*/
// 获取类的所有参数 返回参数列表Parameter[]数组
Parameter[] parameters = con4.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
}
}
四、 反射获取构造方法的权限
con.getModifiers(); 可以获取构造方法的权限,当然也可以获取成员变量、
方法等的权限,都有getModifiers()这个函数方法。
如果权限是非公有的,那我们就不能对其进行赋值等操作,所以有setAccessible()来临时取消其权限。
package com.zyx;
import java.lang.reflect.*;
public class TestReflect {
public static void main(String[] args){
Class clazz = Class.forName("com.zyx.Student");
Constructor con = clazz.getConstructor();
/**
* 反射获取构造方法的权限
*/
// 获取有参构造方法的修饰权限 private是2 public是 1 protected 是4 default是0
int modifiers = con1.getModifiers();
System.out.println(modifiers);
/**
* 临时取消权限
*/
con3.setAccessible(true);
Student stu = (Student) con3.newInstance("zyx", 26);
System.out.println(stu);
}
五、 反射获取类的成员变量
(1) clazz.getFields();
获取类的公有权限的成员变量数组
(2) clazz.getDeclaredFields();
获取类的所有成员变量数组
(3) clazz.getField("name");
获取类的成员变量名为“name”的公有属性
(4) clazz.getDeclaredField(“age”);
获取类的成员变量名为"age"的属性,age属性可以是任意权限
(5) 属性名.getType();
获取类的属性的类型
(6) 属性名.get(对象)
获取类对象的属性的值
package com.zyx;
import java.lang.reflect.*;
public class TestReflect {
public static void main(String[] args){
Class clazz = Class.forName("com.zyx.Student");
Constructor con = clazz.getConstructor();
/**
* 反射获取对象的属性
*/
// 获取反射对象的所有公有的字段/属性
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
// 获取反射对象的所有的字段/属性 包括所有修饰权限的属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
Field name = clazz.getDeclaredField("name");
System.out.println(name);
Field sex = clazz.getField("sex");
System.out.println(sex);
int nameModifiers = name.getModifiers();
System.out.println(nameModifiers);
System.out.println(sex.getModifiers());
// 获取name的数据类型
Class<?> type = name.getType();
System.out.println(type);
// 获取属性的值
name.setAccessible(true);
Student s = new Student("zyx", 26, "女");
Object value = name.get(s);
System.out.println(value);
System.out.println(clazz.getField("sex").get(s));
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);
name.set(s, "zhangsan");
age.set(s, 18);
System.out.println(s.getAge());
System.out.println(s.getName());
}
}
六、反射获取类的方法
(1) clazz.getMethods()
获取类的所有公有的方法
(2) clazz.getDeclaredMethods()
获取类的所有方法
(3) clazz.getDeclaredMethod("dance", String.class);
获取类的方法名为"dance",参数类型为String类型的方法
(4) 方法名.getReturnType();
获取方法的返回类型
(5) Object o = 方法名.invoke(类对象, "方法参数值")
获取方法的返回值
package com.zyx;
import java.lang.reflect.*;
public class TestReflect {
public static void main(String[] args){
Class clazz = Class.forName("com.zyx.Student");
Constructor con = clazz.getConstructor();
/**
* 七、 反射获取类对象的方法
*/
// 获取所有共有的方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
// 获取所有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
// 获取具体的公有的某个方法
Method sing = clazz.getMethod("sing");
System.out.println(sing);
// 获取具体的任意修饰权限的方法
Method dance = clazz.getDeclaredMethod("dance", String.class);
System.out.println(dance);
// 获取方法的权限
System.out.println(sing.getModifiers());
// 获取方法的名称
System.out.println(sing.getName());
// 获取方法的形参
Parameter[] parameters2 = dance.getParameters();
for (Parameter parameter : parameters2) {
System.out.println(parameter);
}
// 八、获取方法的返回类型
Class<?> returnType = dance.getReturnType();
System.out.println(returnType);
System.out.println(clazz.getMethod("toString").getReturnType());
// 九、获取方法抛出的异常
Class<?>[] exceptionTypes = dance.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
// 十、 调用方法并获取方法的返回值
Student student2 = new Student();
dance.setAccessible(true);
Object result = dance.invoke(student2, "张张");
System.out.println(result);
}
}