反射:将类的各个组成部分封装为其他对象,这就是反射机制
好处:
- 可以在程序运行过程中,操作这些对象
- 可以解耦,提高程序的可扩展性
获取Class对象的方式
- Class.forName(”全类名”):将字节码文件加载进内存,返回Class对象
多用于配置文件,将类名定义在配置文件中。读取文件,加载类
- 类名.Class:通过类名的属性Class获取
多用于参数的传递
- 对象.getclass():getclass()方法在Object类中定义着
多用于对象的获取字节码的方式
Class对象功能
获取功能
1.获取成员变量们
Field[ ] getFields( ) :获取所有public修饰的成员变量
Field getField(String name) :获取指定名称的public修饰的成员变量
Field[ ] getDeclaredFields( ) :获取所有的成员变量,不考虑修饰符
Field getDeclaredField(String name)
2.获取构造方法们
Constructor<?>[ ] getConstructors( )
Constructor
Constructor
Constructor<?>[ ] getDeclaredConstructors( )
3.获取成员方法们
Method[ ] getMethods( )
Method getMethod(String name,类<?>… parameterTypers)
Method[ ] getDeclaredMethods( )
Method getDeclaredMethod(String name,类<?>… parameterTypers)
4**.**获取类名
String getName( )
**
Field:成员变量
操作
1.设置值
void set(Object obj,Object value)
2.获取值
get(Object obj)
3.忽略访问权限修饰符的安全检查
setAccessible(true):暴力反射
Person类:
package HeiMa.Reflect;/*
@create 2020--12--24--20:53
*/
public class Person {
private String name;
private int age;
public String a;
protected String b;
String c;
private String d;
public Person() {
}
public Person(String name, int age, String a, String b, String c, String d) {
this.name = name;
this.age = age;
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
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 getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
public String getD() {
return d;
}
public void setD(String d) {
this.d = d;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
public void eat() {
System.out.println("eat...");
}
public void eat(String food) {
System.out.println("eat..."+ food);
}
}
获取成员变量:
package HeiMa.Reflect;/*
@create 2020--12--24--20:55
*/
import java.lang.reflect.Field;
public class ReflectDemo {
public static void main(String[] args) throws Exception {
//获取person的class对象
Class personClass = Person.class;
// Field[] getFields()获取所有public修饰的成员变量
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("------------------");
Field a = personClass.getField("a");
//获取成员变量a的值
Person person = new Person();
Object o = a.get(person);
System.out.println(o);
a.set(person, "张三");
System.out.println(person);
System.out.println("===================");
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
//field getDeclaredField(String name)
Field d = personClass.getDeclaredField("d");
//忽略访问权限修饰符的安全检查
d.setAccessible(true);//暴力反射
Object o1 = d.get(person);
System.out.println(o1);
}
}
Constructor:构造方法
创建对象:
T newInstance(Object……initargs)
如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance
获取构造方法:
package HeiMa.Reflect;/*
@create 2020--12--24--20:55
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
//获取person的class对象
Class personClass = Person.class;
Constructor constructor = personClass.getConstructor(String.class, int.class,String.class,String.class,String.class,String.class);
System.out.println(constructor);
//创建对象
Object person = constructor.newInstance("张三", 28,"a","b","c","d");
System.out.println(person);
System.out.println("---------------------");
Constructor constructor1 = personClass.getConstructor();
System.out.println(constructor1);
//创建对象
Object o = constructor1.newInstance();
System.out.println(o);
Object o1 = personClass.newInstance();
System.out.println(o1);
}
}
Method:方法对象
执行方法
Object invoke(Object obj,Object…… args)
获取方法名称:
String getName:获取方法名
获取方法对象及方法名:
package HeiMa.Reflect;/*
@create 2020--12--24--20:55
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
//获取person的class对象
Class personClass = Person.class;
//获取指定名称的方法
Method eat = personClass.getMethod("eat");
Person p = new Person();
//执行方法
eat.invoke(p);
Method eat1 = personClass.getMethod("eat", String.class);
//执行方法
eat1.invoke(p, "饭");
System.out.println("-----------");
//获取所有public修饰的方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
System.out.println(method.getName());
}
//获取类名
String name = personClass.getName();
System.out.println(name);
}
}
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
Java反射机制是Java中底层的一个功能,就是通过这个机制可以进行对象的灵活的调用和处理
在后期学习中会用到反射的相关的内容,但是都是底层的理解,比如:文件的加载,spring框架底层……
目前我们讲反射是讲解反射的使用
Java中提供了一个api - Class用于反射机制的一个类
是在Java.lang包下的,不需要导包
当前案例演示利用反射的机制获取对象的属性
package Test25_Demo.TestDemo2;/*
@create 2020--12--18--10:14
*/
import org.junit.Test;
public class ReflectDemo {
//新建对象的获取直接使用反射获取 - 不适用new
//单元测试
@Test
public void test1() {
//已知明确的类型,获取Class对象
Class clazz = Student.class;
System.out.println(clazz);//class Test25_Demo.TestDemo2.Student
}
@Test
public void test2() {
//已知对象获取class对象
Student s = new Student();
Class clazz = s.getClass();//getClass()是顶级父类Object中的方法
System.out.println(clazz);//class Test25_Demo.TestDemo2.Student
}
@Test
public void test3() throws ClassNotFoundException {
//完全限定名(包名.类名),获取Class对象 - 比较常用 - 安全
String className = "Test25_Demo.TestDemo2.Student";
//forName()返回这个地址值所对应的类
Class<?> aClass = Class.forName(className);
System.out.println(aClass);//class Test25_Demo.TestDemo2.Student
}
//测试结果:通过不同的反射获取的对象是同一个
@Test
public void test4() throws ClassNotFoundException {
Class clazz1 = Student.class;
Student s1 = new Student();
Class clazz2 = s1.getClass();
String className = "Test25_Demo.TestDemo2.Student";
Class<?> aClass = Class.forName(className);
//比较
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz2 == aClass);//true
System.out.println(clazz1 == aClass);//true
}
}
package Test25_Demo.TestDemo2;/*
@create 2020--12--18--10:14
*/
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 通过Java反射机制构建对象的测试 - 这些操作平时只要我们创建对象,内存中就偷偷的帮我们做了
* 步骤:
* 1.创建该类的Class对象
* 2.利用Class对象去创建类对象
* 3.利用Class对象中的newInstance方法创建对象,类中有公共的无参构造方法
* 4.最后获取Class类中的构造函数对象,通过构造函数创建实例对象
*/
public class ReflectDemo2 {
@Test
public void test01() throws IllegalAccessException, InstantiationException {
//类中有无参构造方法
Class clazz = Student.class;
Object obj = clazz.newInstance();//默认调用的是无参的 - 创建实例
System.out.println(clazz);//class Test25_Demo.TestDemo2.Student
System.out.println(obj);//Student{id=0, name='null'} - 当前的Object进行了向下转型给了反射获取到的类Student
}
@Test
public void test02() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class类中的构造函数对象
Class clazz = Student.class;
//获取到构造函数 - 有参
Constructor constructor = clazz.getConstructor(int.class, String.class);
//通过构造函数为属性赋值
Object tom = constructor.newInstance(20, "Tom");//Student{id=20, name='Tom'}
System.out.println(tom);
}
//演示普通的方式实例化对象做不到的事情
@Test
public void test03() {
Student s = new Student();
s.setId(1);
//s.setName();//不能进行name的赋值,因为方法是私有的
System.out.println(s);//Student{id=1, name='null'}
}
}