反射就是把Java类中的各个成分映射成一个个java对象。
一个类有成员变量、方法、构造函数等信息,利用反射可以对一个类进行解 剖,把各个组成部分映射成一个个对象。
反射也可以理解为动态调用写了一个.java文件,编译后为字节码文件,虚拟机加载了这个字节码文件也就是加载到内存中,就能执行一些指令。在这个类中 当我需要调用另外一个类的时候,而内存中并没有这个类,这时候我就可以使用反射动态加载这个类,使用其中的属性 跟方法。
反射获取class对象的三种方式
1)通过 Class 的 forName 的静态方法获得(参数:包名 + 类名):
Class<?> classType = Class.forName("java.lang.String");
2)通过类名 + 点 class 的方法获得:
Class<?> c = String.class;
3)通过类的对象的 getClass 的方法获得:
String str = "heima";
Class<?> typeClass = str.getClass();
反射构造函数:
//获取字节码文件
Class clazz = Class.forName(对象的路径如:”cn.itcast.domain.Student”)
//获取构造器
Constructor con =clazz.getConstructor(String.class);//如果是空参的就写null
//创建对象
Object obj = con.newInstance(“liwen”);//如果是空参的就写null
反射方法:
//获取字节码文件
Classclazz = Class.forName(对象的路径如:”cn.itcast.domain.Student”)
//创建一个对象
Student stu =(student)clazz.newInstance();
//获取方法
Method method = clazz.getMethod(方法名如“aa’“,参数类型如”String.calss”)
//运行
method.invoke(对象名如stu,参数如“liwen”)
反射字段:
//获取字节码文件
Class clazz = Class.forName(对象的路径如:”cn.itcast.domain.Student”)
//创建对象
Student stu =(Student)clazz.newInstance();
//获取字段
Field field = clazz.getField(字段名称如“name”);
//设置字段的值
field.set(对象名称如stu,参数如“liwen”)
注意:
以上反射的都是非私有的,那么反射私有的怎么办呢?
总体步骤是不变的,只是在获取构造器。方法或字段是的方法变了,在获取后还要将其打开(暴力访问)
===================================================
获取私有构造器:
Constructor con =clazz.getDeclaredConstructor(String.class,int.class,String.class);
将其打开
con.setAccessible(true);//true是打开,false是关闭
===================================================获取私有方法
Method method = clazz.getDeclaredMethod("cc",String.class,int.class,String.class);
将其打开
method.setAccessible(true);
===================================================
获取私有字段
Field field = clazz.getDeclaredField("age");
将其打开
field.setAccessible(true);
===================================================
访问被private 修饰的方法和属性
package com.weaver.java;
public class Person
{
private String name = "小四";
private String getName()
{
return name;
}
}
package com.weaver.java;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class PersonReflect {
public static void main(String[] args)throws Exception
{
Class<?> classType = Class.forName("com.weaver.java.Person");
Constructor con = classType.getDeclaredConstructor(new Class[]{});
Object object =con.newInstance(new Object[]{});//new实例
Field field = classType.getDeclaredField("name");
field.setAccessible(true);//暴力访问
field.set(object, "小小四");
Method getNameMethod = classType.getDeclaredMethod("getName", new Class[]{});
getNameMethod.setAccessible(true);
Object obj = getNameMethod.invoke(object, new Object[]{});
System.out.println("通过反射修改后的值为:"+obj.toString());
}
}
动态代理
在java种怎样实现动态代理呢
第一步,我们要有一个接口,还要有一个接口的实现类,而这个实现类呢就是我们要代理的对象,所谓代理呢也就是在调用实现类的方法时,可以在方法执行前后做额外的工作,这个就是代理。
第二步,我们要自己写一个在要代理类的方法执行时,能够做额外工作的类,而这个类必须继承InvocationHandler接口,为什么要继承它呢?因为代理类的实例在调用实现类的方法的时候,不会调真正的实现类的这个方法, 而是转而调用这个类的invoke方法(继承时必须实现的方法),在这个方法中你可以调用真正的实现类的这个方法。
第三步,在要用代理类的实例去调用实现类的方法的时候,写出下面的代码。
package com.weaver.java;
//去黑马学习的接口
public interface ToSchool {
void study();
}
package com.weaver.java;
//去黑马学习的实现类
public class ToSchoolImp implements ToSchool{
@Override
public void study() {
System.out.println("终于到黑马学习了");
}
}
package com.weaver.java;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//去黑马学习的代理类
//监听方法所在类,该类实现了InvocationHandler 接口,通过invoke方法利用java的反射机制实现对相关方法的监听
public class ToSchoolProxy implements InvocationHandler{
private Object study = null;
public ToSchoolProxy(Object obj) {
this.study = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("去黑马之前要自学");//去学习之前需要做的事情
return method.invoke(study, args);
}
}
package com.weaver.java;
import java.lang.reflect.Proxy;
public class ToSchoolMain {
/**
* @param args
*/
public static void main(String[] args) {
//先将实现类实例化,也就是得到ToSchool接口的一个实例对象
ToSchool school = new ToSchoolImp();
//得到ToSchoolImp这个类的一个代理类,同时为代理类绑定了一个处理类ToSchoolProxy。
ToSchool toSchool = (ToSchool) Proxy.newProxyInstance(
school.getClass().getClassLoader(), //要代理类的类加载器
school.getClass().getInterfaces(), //代理类所实现的所有的接口
new ToSchoolProxy(school));
toSchool.study();//调用方法
}
}