什么是反射?
(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。 本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了, 而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到, 所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性, 不需要提前在编译期知道运行的对象是谁。
反射:能够分析类能力的程序叫做反射
翻译成人话:能够分析类信息的能力的程序叫做反射。
什么是类的信息?
简单的来说比如 属性、方法、构造器等等。。。
举例:
Class class1 = Class.forName("reflect.Person");
System.out.println(class1);
Field[] fields = class1.getFields();
for (Field field : fields) {
System.out.println(field);
}
那么一个新的问题就来了,我们明明可以通过new 一个对象来获取类信息,那么我们为什么要使用反射呢?
我们在这里说一个实际的列子,比如说我们以前使用过的servlet框架,·那么在servlet框架当中我们写过JBDC类,在这个类当中我们引入了一个mysql.jar包,那么这个jar包是怎么起作用的呢,请大家请注意,我们的servlet类当中课没有main方法,那我们的servlet类是如何启动的呢?如何加载到我们的JVM当中呢?
答案就是使用了反射,大家看一个东西:
从上面可以看到,正式因为有了反射,我们才能将他们加载如JVM当中。
那么反射是如何工作的呢?
要想理解反射是如何工作的我们先来看类的声明周期类的生命周期:
好处:
1.在程序的运行过程中,来操作这些对象
String str = "123";
str.
我们对 . 会出现很多的方法,这其实就是内部就是使用的是反射机制,你定义了一个字符串,那么他会把字符串的字节码文件加载进内存,在内存当中有一个class类对象,class对象已将所有的方法都抽取出来封装在method[]数组当中,所以我们能够 . 出这么多的程序。
*获取class对象的方式
1.Class.forName("全类名"):将字节码文件加载进内存,返回class对象;
多用于配置文件,将类名定义在配置文件当中,读取文件,加载类
2.类名.class:通过类名的class获取
多用于参数的传递
3.对象.getClass():getClass()方法在object类当中定义着
多用于对象获取字节码的方式
首先定义一个person类,内部定义好成员变量,构造方法和成员方法:
package com.haijiao12138.demo.spring.reflection;
/**
* @author: haijiao12138
* @ClassName: Person
* @description: TODO
* @date: 2021/8/15 2:06
*
*/
public class Person {
private String nameString;
private int age;
public Person() {
}
public Person(String nameString, int age) {
this.nameString = nameString;
this.age = age;
}
public String getNameString() {
return nameString;
}
public void setNameString(String nameString) {
this.nameString = nameString;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [nameString=" + nameString + ", age=" + age + "]";
}
}
定义测试类:
package com.haijiao12138.demo.spring.reflection;
/**
* @author: haijiao12138
* @ClassName: RefulectDemo1
* @description: TODO
* @date: 2021/8/15 2:07
*
*/
public class RefulectDemo1 {
/**
*1.Class.forName("全类名"):将字节码文件加载进内存,返回class对象
*2.类名.class:通过类名的class获取
*3.对象.getClass(): getClass()方法在object类当中定义着
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws Exception {
// 1.Class.forName("全类名"):
Class class1 = Class.forName("com.haijiao12138.demo.spring.reflection.Person");
System.out.println(class1);
//2.类名.class:通过类名的class获取
Class class2 = Person.class;
System.out.println(class2);
//3.对象.getClass()
Person person = new Person();
Class class3 = person.getClass();
System.out.println(class3);
System.out.println(class1 == class2);
System.out.println(class2==class3);
}
}
用 == 进行比较:控制台输出结果:
结论:
同一类加载器加载的文件(*.class)在一次程序运行过程中,只会被加载一次,不论你通过哪种方式获取的class对象都是同一个;
反射创造*class对象后,类对象的功能如下:可以在Idea中测试:
· 1.获取成员变量们
1.Field[] getFields() :获取所有public修饰的成员变量
2.Field getField(String name):获取指定名称的
3.Field[] getDeclaredFilds():获取所有的成员变量,不考虑修饰符
4.Field getDeclaredField(String name)
2.获取构造方法们
1.Constructor[] getConstructors()
2.Constructor getConstructor(类...parameterTypes)
3.Constructor[] getDeclaredConstructors()
4.Constructor getDeclaredConstructors(类...parameterTypes)
3.获取方法名
1.Method[] getMethod()
2.Method getMethod(String name,类... parameterTypes)
3.Method[] getDeclaredMethod()
4.Method getDeclaredMethod(String name,类... parameterTypes)
4.获取类名
String getName()
Field成员变量
操作
1.设置值
void set(Object obj,Object value)
2.获取值
get(Object obj)
3.忽略安全访问修饰符的安全检查
setAccessible(true) //暴力反射 ---》private
package com.haijiao12138.demo.spring.reflection;
/**
* @author: 候苑博
* @ClassName: Person
* @description: TODO
* @date: 2021/8/15 2:06
*
*/
public class Person {
private String nameString;
public String name;
private int age;
public String age1;
public Person() {
}
public Person(String nameString, int age) {
this.nameString = nameString;
this.age = age;
}
public String getNameString() {
return nameString;
}
public void setNameString(String nameString) {
this.nameString = nameString;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"nameString='" + nameString + '\'' +
", name='" + name + '\'' +
", age=" + age +
", age1='" + age1 + '\'' +
'}';
}
}
package com.haijiao12138.demo.spring.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @author: haijiao12138
* @ClassName: RefulectDemo1
* @description: TODO
* @date: 2021/8/15 2:07
*
*/
public class RefulectDemo1 {
/**
*1.Class.forName("全类名"):将字节码文件加载进内存,返回class对象
*2.类名.class:通过类名的class获取
*3.对象.getClass(): getClass()方法在object类当中定义着
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
//0.获取Person的Class对象
Class personClass = Person.class;
/*
1. 获取成员变量们
* Field[] getFields()
* Field getField(String name)
* Field[] getDeclaredFields()
* Field getDeclaredField(String name)
*/
//1.Field[] getFields()获取所有public修饰的成员变量
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("------------");
//2.Field getField(String name)
Field a = personClass.getField("age1");
System.out.println(a);
//获取成员变量a 的值
Person p = new Person();
System.out.println(p);
Object value = a.get(p);
System.out.println(value);
//设置a的值
a.set(p,"张三");
System.out.println(p);
System.out.println("===================");
//Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
//Field getDeclaredField(String name)
Field d = personClass.getDeclaredField("age");
//忽略访问权限修饰符的安全检查
d.setAccessible(true);//暴力反射
Object value2 = d.get(p);
System.out.println(value2);
}
}
Constructor访问构造方法
*创建对象
*T newInstance(Object... initarges)
*如果使用空参数构造方法,此操作可以简化:class对象的newInstance方法
package com.haijiao12138.demo.spring.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @author: haijiao12138
* @ClassName: RefulectDemo1
* @description: TODO
* @date: 2021/8/15 2:07
*
*/
public class RefulectDemo1 {
/**
*1.Class.forName("全类名"):将字节码文件加载进内存,返回class对象
*2.类名.class:通过类名的class获取
*3.对象.getClass(): getClass()方法在object类当中定义着
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws Exception {
//0.获取Person的class对象
Class personClass = Person.class;
//因为构造器的方法名称是相同的,不同的是参数列表,所以我们可以根据不同的参数列表来找到构造器
Constructor constructor = personClass.getConstructor(String.class,int.class);
System.out.println(constructor);
//创建对象
Object perObject = constructor.newInstance("张三",20);
System.out.println(perObject);
System.out.println("-------------------------------");
Constructor constructor1 = personClass.getConstructor();
System.out.println(constructor1);
//创建对象,newInstance简化创建
Object perObject1 = constructor1.newInstance();
System.out.println(perObject1);
System.out.println("-------------------------------");
Object o = personClass.newInstance();
System.out.println(o);
}
}
}
Method:方法对象
*执行方法
*object invoke(Object object,Object... ages)
*获取方法名称
*String getName:获取方法名
实体类中多了两个方法:一个代参,一个不带参,其余的与上述的实体类一致:
public void eat1(){
System.out.println("吃的方法@!");
}
public void eat(String name){
System.out.println("我是吃的有参的方法!");
}
package com.haijiao12138.demo.spring.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @author: haijiao12138
* @ClassName: RefulectDemo1
* @description: TODO
* @date: 2021/8/15 2:07
*
*/
public class RefulectDemo1 {
/**
*1.Class.forName("全类名"):将字节码文件加载进内存,返回class对象
*2.类名.class:通过类名的class获取
*3.对象.getClass(): getClass()方法在object类当中定义着
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws Exception {
//0.获取Person的class对象
Class personClass = Person.class;
//获取指定名称的方法,方法无参
Method eat_method = personClass.getMethod("eat1");
//执行方法
Person person =new Person();
eat_method.invoke(person);
//获取指定名称的方法,方法有参
Method eat_method1 = personClass.getMethod("eat",String.class);
//执行方法
eat_method1.invoke(person,"饭");
//获取所有public修饰的方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
//获取方法的名称
String name = method.getName();
System.out.println(name);
}
}
}
Java Bean利用反射示例:
Bean
package com.haijiao12138.demo.spring.reflection1;
/**
* @author: haijiao12138
* @ClassName: Student
* @description: TODO
* @date: 2021/8/15 2:51
*
*/
public class Student {
private String name;
private int age;
private String address;
public Student(String name,int age,String address) {
this.address = address;
this.age = age;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
package com.haijiao12138.demo.spring.reflection1;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author: haijiao12138
* @ClassName: CommonReflect
* @description: TODO
* @date: 2021/8/15 2:52
*
*/
public class CommonReflect {
//获取该类的名称
public static void getClassName(Object object) {
//Class studentClass = Student.class;
//String name = studentClass.getName().;
String className = object.getClass().getSimpleName();
System.out.println("类的名字是:"+className);
}
//获取类的变量名称 不考虑修饰符
public static void getField(Object object) {
Field[] fields = object.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
System.out.println("成员变量的名称为:"+fields[i].getName());
}
}
//获取类的成员方法 所有private的方法
public static void getMethod(Object object) {
Method[] methods = object.getClass().getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println("成员方法的名称:"+methods[i].getName());
}
}
//调用该类的成员方法,以get为例
public static void getAction(Object object) throws Exception {
//获取到有多少get方法
Field[] fields = object.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
String fieldName = fields[i].getName();
String fistfont = fieldName.substring(0,1).toUpperCase();
String methodname = "get"+fistfont+fieldName.substring(1); //get+N+name=getName; getAge getAddress
Method method = object.getClass().getMethod(methodname);
System.out.println("get的输出结果:"+method.invoke(object));
}
}
public static void main(String[] args) throws Exception {
Object studentObject = Student.class.getConstructor(String.class,int.class,String.class).newInstance("张三",20,"保定");
getClassName(studentObject);//类名
getField(studentObject);//成员变量名
getMethod(studentObject);//成员方法名
getAction(studentObject);//成员变量的输出结果
}
}
最后 回顾一下 获取class对象的方式:
/**
* 1.Class.forName("全类名"):将字节码文件加载进内存,返回class对象
2.类名.class:通过类名的class获取
3.对象.getClass():getClass()方法在object类当中定义着
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws Exception {
// 1.Class.forName("全类名"):
Class class1 = Class.forName("com.haijiao12138.demo.spring.reflection.Person");
System.out.println(class1);
//2.类名.class:通过类名的class获取
Class class2 = Person.class;
System.out.println(class2);
//3.对象.getClass()
Person person = new Person();
Class class3 = person.getClass();
System.out.println(class3);
System.out.println("----------------------------");
System.out.println(class1 == class2);
System.out.println(class1 == class3);
}