Java反射机制
1. Object类的支持
- 在Object类中定义了一下方法,此方法将被所有子类继承
- public final Class getClass()
- 以上的方法的返回值类型是一个“Class”类,实际上此类是Java反射机制的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称
- 正常方式
- 引入需要的“包.类”名称 -----> 通过new实例化 -----> 取得实例对象
- 反射方式
- 实例化对象 -----> getClass()方法 -----> 得到完整的“包.类“名称
2. 实例化Class类对象
- 实例化Class类对象的三种方法:
- 通过forName()方法 (重点掌握)
- 类.class
- 对象.getClass()
- 从实际角度看,如果要使用反射进行对象的实例化操作,最好在类中存在无参构造
//Person类
package com.lgt.Demo2;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
<注意>
该类中写了两个构造方法,后面在调用有参构造函数时,Constructors[]数组的下标;
无参构造 cons[0] 有参cons[1]
package com.lgt.Demo2;
/**
* @Author LGT
* @Date 2021/7/10 15:03
* @Version 1.0
*/
public class InstanceDemo1 {
public static void main(String[] args) {
Class<?> c = null;
try{
c = Class.forName("com.lgt.Demo2.Person");
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
Person person = null;
try {
person = (Person) c.newInstance();
}
catch (Exception e){
e.printStackTrace();
}
person.setName("曲小檀");
person.setAge(23);
System.out.println(person);
}
}
-
getConstructors
public Constructor<?>[] getConstructors() throws SecurityException 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。如果该类没有公共构造方法,或者该类是一个数组类,或者该类反映一个基本类型或 void,则返回一个长度为 0 的数组。 注意,此方法返回 Constructor<T> 对象的数组(即取自此类构造方法的数组)时,此方法的返回类型是 Constructor<?>[],不是 预期的 Constructor<T>[]。此少量信息的返回类型是必需的,因为从此方法返回之后,该数组可能被修改以保存不同类的 Constructor 对象,而这将违反 Constructor<T>[] 的类型保证。 返回: 表示此类公共构造方法的 Constructor 对象数组 抛出: SecurityException - 如果存在安全管理器 s,并满足下列任一条件: 调用 s.checkMemberAccess(this, Member.PUBLIC) 拒绝访问该类中的构造方法 调用者的类加载器不同于也不是当前类的类加载器的一个祖先,并且对 s.checkPackageAccess() 的调用拒绝访问该类的包
package com.lgt.Demo2;
import java.lang.reflect.Constructor;
/**
* @Author LGT
* @Date 2021/7/10 16:01
* @Version 1.0
*/
public class InstanceDemo2 {
public static void main(String[] args) {
Class<?> c = null;
try{
c = Class.forName("com.lgt.Demo2.Person");
}
catch (ClassNotFoundException e){
e.printStackTrace();
}
Person person = null;
Constructor<?>[] cons = c.getConstructors();
try{
person = (Person) cons[1].newInstance("李光泰",23);
}
catch (Exception e){
e.printStackTrace();
}
System.out.println(person);
}
}
总结:
- 在使用Class实例化对象的时候,必须保证类中存在一个无参构造,否则无法使用
- 如果想调用有参构造进行对象的实例化操作,则必须使用Constructor类完成,在操作的时候需要明确的调用类中的公祖奥方法,并将参数传递进去之后才能进行实例化操作,操作步骤如下:
- 通过Class类中的getConstructors()取得本类中的全部构造方法。
- 向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的哥哥参数
- 通过Constructor实例化对象
3. 反射机制深入-取得类结构
通过反射机制可以获得一个类的完整结构
java.lang.reflect 类 AccessibleObject
java.lang.Object java.lang.reflect.AccessibleObject
所有已实现的接口:
直接已知子类:
- Constructor: 表示类中的构造方法
- Filed: 表示类中的属性
- Method: 表示类中的方法
3.1 取得类所实现的全部接口
使用Class类中的 getInterface()方法
- public Class[] getInterface()
- 此方法返回的是Class类的对象数组,之后可以直接利用Class类中的getName()输出
3.2 取得类所继承的父类
一个类可以实现多个接口,但只能继承一个父类;要想取得一个类的父类,可以直接通过Class类中的 getSuperclass() 方法
3.3 取得类中的其他信息
public static void main(String[] args) {
Class<?> c = null;
try{
c = Class.forName("com.lgt.GetInterfaceDemo.FruitImpl");
}catch(ClassNotFoundException e){
e.printStackTrace();
}
FruitImpl fruit = null;
Constructor<?>[] cons = c.getConstructors();//取得所有的构造方法
Class<?>[] ins = c.getInterfaces();//取得实现的所有接口
//获取全部的构造方法
System.out.println("--------- 构造方法 -----------");
for(int i = 0;i< cons.length;i++){
//注意,直接通过getModifiers()获取的修饰符是数字,需要转换
//System.out.println(cons[i].getModifiers());//获取访问权限
int mo = cons[i].getModifiers();//获取访问修饰符
System.out.print(Modifier.toString(mo)+" ");//转换为String
System.out.print(cons[i].getName());
Class<?>[] parameter = cons[i].getParameterTypes();//得到构造方法的全部参数
System.out.print("("+" ");
for(int n = 0;n<parameter.length;n++){
System.out.print(parameter[n].getName()+" args");
if(n!=parameter.length-1)
System.out.print(" , ");
}
System.out.print(")");
System.out.println();
}
System.out.println("--------- 实现的所有接口 -----------");
for(int i = 0;i< ins.length;i++){
System.out.println(ins[i].getName());
}
}
//输出结果
--------- 构造方法 -----------
public com.lgt.GetInterfaceDemo.FruitImpl( java.lang.String args , float args)
public com.lgt.GetInterfaceDemo.FruitImpl( java.lang.String args)
public com.lgt.GetInterfaceDemo.FruitImpl( )
--------- 实现的所有接口 -----------
com.lgt.GetInterfaceDemo.Fruit
Process finished with exit code 0
4. 动态代理
4.1 Proxy类
- 类加载器
-
在Proxy类中的newProxyInstance()方法需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在java中主要有以下三类类加载器
-
可以通过 对象.getClass().getClassLoader().getClass().getName() 获取类加载器的名称
-
4.2 动态代理实现 ———— 定义MyInvocationHandler的类
package com.lgt.Demo3;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Author LGT
* @Date 2021/7/12 13:04
* @Version 1.0
*/
public class MyInvocationHandler implements InvocationHandler {
private Object obj; //真实主题
//绑定真实操作主题
public Object bind(Object obj){
this.obj =obj;
//取得代理对象
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
}
//动态调用方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object temp = method.invoke(this.obj,args);//调用方法传入真实的主题和参数
return temp;
}
}
public class test {
public static void main(String[] args) {
// 静态代理
//Chinese ch = new Chinese();
//StaticProxy staticProxy = new StaticProxy();
//staticProxy.setHuman(ch);
//staticProxy.say();
// 动态代理(1)
// Human human = (Human) new MyInvocationHandler().bind(new Chinese());
// human.say();
// 动态代理(2)
Chinese chinese = new Chinese();
MyInvocationHandler mi = new MyInvocationHandler();
Human human = (Human) mi.bind(chinese);
human.say();
}
总结:
- Proxy----------------提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类
- InvocationHandler-----调用处理程序并返回结果