概述
反射机制,就是通过一个抽象的类名能够在自己记忆(加载类的内存)中找到相匹配的类的具体信息
前提:jvm已经加载这个类,相当于人脑有了这个类的记忆
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
Java反射机制提供的功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的成员变量和方法
生成动态代理
实例化Class类对象(四种方法)
package day14;
public class Test {
public static void main(String[] args) {
Person p =new Person();
Class c0 =Person.class; //通过类名.class创建指定类的class实例
Class c1 =p.getClass(); //通过一个类的实例对象.getclass方法获取对应实例对象的类的class实例
try {
//通过class的静态方法forname(string name)来获取一个类的class实例
//参数是获取class类的全路径(包名.类名),常用
Class c2=Class.forName("day14.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
通过反射调用类的完整结构
实现的全部接口
所继承的父类
全部的构造器
package day14;
public class Person {
String name;
int age;
}
package day14;
public class Test {
public static void main(String[] args) {
Person p =new Person();
Class c0 =Person.class; //通过类名.class创建指定类的class实例
Class c1 =p.getClass(); //通过一个类的实例对象.getclass方法获取对应实例对象的类的class实例
try {
//通过class的静态方法forname(string name)来获取一个类的class实例
//参数是获取class类的全路径(包名.类名),常用
Class c2=Class.forName("day14.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
package day14;
public interface Move {
void moveType();
}
package day14;
public interface Study {
void studyInfo();
}
package day14
public class Student extends Person implements Move,Study{
public Student() {
System.out.println("调用的是无参构造");
}
public Student(String school) {
this.school=school;
System.out.println("调用的String school构造");
}
private Student (String name,int age) {
this.name=name;
this.age=age;
System.out.println("调用的是String name,int age构造");
}
String school;
public void showInfo() {
System.out.println("学校是"+this.school);
}
@Override
public void studyInfo() {
System.out.println("学习的知识");
}
@Override
public void moveType() {
System.out.println("骑自行车");
}
}
package day14;
import java.lang.reflect.Constructor;
public class Test1 {
public static void main(String[] args) {
try {
Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例
Class superClazz=clazz.getSuperclass();//获取父类
System.out.println(superClazz.getName());
Class[] inclazz=clazz.getInterfaces();//获取当前类的接口
for(Class c:inclazz) {
System.out.println(c);
}
// Constructor[]cons=clazz.getConstructors();//获取公有的构造方法,private修饰的获取不到
// //getModifiers()返回数字1代表public,2代表private
//
// for(Constructor c:cons) {
// System.out.println("构造方法名称是"+c.getName()+"构造修饰符是 "+c.getModifiers());
// Class[]cc=c.getParameterTypes();//参数类型
// for(Class s:cc) {
// System.out.println("构造方法名称是"+c.getName()+"的参数类型是 "+s.getName());
// }
// //System.out.println(c.getParameterTypes());
// }
Constructor[] conss =clazz.getDeclaredConstructors();//获取所有的构造方法
for(Constructor c:conss) {
System.out.println("构造方法名称是"+c.getName()+"构造修饰符是 "+c.getModifiers());
Class[]cc=c.getParameterTypes();//参数类型
for(Class s:cc) {
System.out.println("构造方法名称是"+c.getName()+"的参数类型是 "+s.getName());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
通过反射的方法创建对象
package day14;
import java.lang.reflect.Constructor;
public class Test1 {
public static void main(String[] args) {
try {
Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例
try {
Object obj =clazz.newInstance(); //相当于调用Student类的无参共有的构造方法
Student stu =(Student)obj ; //把obj强转,这样就可以输出了,输出的是 调用的是无参构造
Constructor c= clazz.getConstructor(String.class);//指定一获取一个参数并且为string类型的构造方法
Object obj1=c.newInstance("第一中学");//newInstance实例化对象
Student stu1 =(Student)obj1;
System.out.println(stu1.school);
//通过反射机制,可以强制的调用私有的构造方法
Constructor c1=clazz.getDeclaredConstructor(String.class,int.class);//指定两个参数的构造方法
c1.setAccessible(true);//解除私有封装,下面就可以对私有方法强制调用
Student stu2=(Student)c1.newInstance("张三",12);
}
catch (Exception e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
全部的方法
package day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Test1 {
public static void main(String[] args) {
try {
Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例
try {
//Method[] ms=clazz.getMethods(); //获取所有共有的的方法
Method[] ms=clazz.getDeclaredMethods();
for(Method m:ms) {
System.out.println("方法名"+m.getName());
System.out.println("返回值类型"+m.getReturnType());
System.out.println("修饰符"+m.getModifiers());
Class[]c=m.getParameterTypes();
if(c!=null&&c.length>0) {
for(Class cs:c) {
System.out.println("参数类型"+ cs.getName());
}
}
System.out.println("===========================");
}
}
catch (Exception e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
全部的Field(属性)
package day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test1 {
public static void main(String[] args) {
try {
Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例
try {
//Field[] f=clazz.getFields();//获取所有公有属性,包括父类的
Field[] f=clazz.getDeclaredFields();//获取所有属性包括私有属性,不包含父类的
for(Field fs:f) {
System.out.println("修饰符是"+fs.getModifiers());
System.out.println("属性的类型"+fs.getType());
System.out.println("属性的名称是"+fs.getName());
}
Package p=clazz.getPackage(); //获取类所在的包
System.out.println(p.getName());
}
catch (Exception e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
通过反射调用类中的指定方法、指定属性
指定方法
package day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test1 {
public static void main(String[] args) {
try {
Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例
/**
* 注意,下面不论是反射调用哪个方法都是调用obj对象的方法,实际上就是调用student对象
*/
try {
//Constructor con = clazz.getConstructor();//获取无参构造
//Object obj=con.newInstance();//使用无参构造创建对象(这两行等于下边一行)
Object obj=clazz.newInstance(); //使用无参构造创建对象
//名称setSchool 参数是string,string的方法
Method m =clazz.getMethod("setSchool",String.class,String.class);
m.invoke(obj, "张三","第一中学"); //,调用方法,参数一是实例化的对象,后面参数是当前方法的参数
//如果想要调用私有方法
Method m1 =clazz.getDeclaredMethod("test", String.class);//获取方法名为test参数为String的方法
m1.setAccessible(true);//解除私有方法封装
m1.invoke(obj, "李四");
//重载一个setSchool方法
Method m2 =clazz.getDeclaredMethod("setSchool", int.class);//重载方法
m2.invoke(obj, 1);
//有返回值的方法
Method m3 =clazz.getDeclaredMethod("getSchool");//获取方法
String school =(String) m3.invoke(obj); //调用有返回值没有参数的的方法,强转
System.out.println(school);//输出是第一中学,因为上边setSchool赋值了,这里返回来了
}
catch (Exception e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
指定属性
package day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test1 {
public static void main(String[] args) {
try {
Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例
try {
//反射创建对象
Constructor con =clazz.getConstructor();
Student stu =(Student) con.newInstance();
Field f =clazz.getField("school"); //获取名为school的属性
f.set(stu, "第三中学");//对stu对象的school属性设置值 第三中学
String s=(String) f.get(stu); //获取stu对象的school属性的值
System.out.println(s);
//私有的属性
Field f1 =clazz.getDeclaredField("fied");//获取私有属性
f1.setAccessible(true);
f1.set(stu, "测试私有属性");
String ss=(String) f1.get(stu);
//f1.setAccessible(true); 写在这个位置就不行,写上面就行
System.out.println(ss);
}
catch (Exception e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Java动态代理
一个java项目,其中有100java类,每个java有1000个方法,总共100个方法。需要在每个方法上加上两句话,在方法执行前输出这个方法开始执行,在方法之后输出方法结束。
动态代理步骤
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作。
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个Subject接口代理
4.通过 Subject代理调用RealSubject实现类的方法
package day14;
public interface ITestDemo {
void test1();
void test2();
}
package day14;
public class TestDemoImpl implements ITestDemo {
@Override
public void test1() {
System.out.println("执行test1方法");
}
@Override
public void test2() {
System.out.println("执行test2方法");
}
}
package day14;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 动态代理类
* @author xrh
*
*/
public class ProxyDemo implements InvocationHandler{
Object obj ; //被代理的对象
public ProxyDemo(Object obj) {
this.obj=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName()+"方法开始执行");
Object result=method.invoke(this.obj, args);//执行指定代理对象的指定方法,可能会有返回值所以要接收
System.out.println(method.getName()+"方法执行完毕");
return result;
}
}
package day14;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test2 {
public static void main(String[] args) {
ITestDemo test =new TestDemoImpl(); //对象多态
/**
* 一个对象想要通过Proxy.newProxyInstance方法被代理
* 那么这个对象的类一定要有相应的接口,
* 就像这里TestDemoImpl类有一个ITestDemo接口
*/
test.test1();
test.test2();
System.out.println("=============================");
/**
* 每个执行方法时加入东西
*/
//ProxyDemo实现的接口是InvocationHandler,所以可以这样new,接口的多态,参数就是代理对象
InvocationHandler handler =new ProxyDemo(test);
//第一个参数类加载器,第二个参数被代理的对象的接口,参数三是代理对象,返回的值是成功被代理后的对象
ITestDemo t=(ITestDemo) Proxy.newProxyInstance(handler.getClass().getClassLoader(), test.getClass().getInterfaces(), handler);
//返回的是object类型,需要根据情况转化类型
t.test1();
t.test2();
}
}