java反射详解

动态代理

  • 什么是动态代理?

    特点:无侵入式的给代码增加额外的功能

    对象有什么方法想要被代理,代理就一定要有对应的方法

    对象和代理需要实现同一个接口,接口中就是被代理的方法

    调用者通过代理,调用代理中的方法,代理再去调用对象的方法

    //为对象生产代理对象的方法
    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interface,InvocationHandler h){
        参数一:用于指定用哪个类加载器,去加载生成的代理类
        参数二:指定接口,这些接口用于指定生成的代理长什么样,也就是有哪些方法
        参数三:用来指定生成的代理对象要干什么事情
    }
    

    对象:

    package bean;
    
    public class BigStar implements Star {
        String name;//明星的名字
    
        @Override
        public String toString() {
            return "BigStar{" +
                    "name='" + name + '\'' +
                    '}';
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public BigStar() {
        }
    
        public BigStar(String name) {
            this.name = name;
        }
    
        @Override
        public void sing(String name) {
            System.out.println(this.name + "在唱歌");
        }
    
        @Override
        public void dance() {
            System.out.println(this.name + "在跳舞");
        }
    }
    
    

    接口:

    package bean;
    
    public interface Star {
        public abstract void sing(String name);//参数为歌名
    
        public void dance();
    }
    
    

    代理:

    package bean;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class ProxyUtil {
        public static Star createProxy(BigStar bigStar){
            Star star = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(), new Class[]{Star.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    /*
                    * 参数一:被代理的对象
                    * 参数二:要运行的方法
                    * 参数三:调用方法时,传递的实参
                    *
                    * */
                    if("sing".equals(method.getName())){
                        System.out.println("准备场地,开始唱歌");
                    }else if("dance".equals(method.getName())){
                        System.out.println("准备场地,开始跳舞");
                    }
    
                    return method.invoke(bigStar,args);//调用对象的方法
                }
            });
            return star;
        }
    }
    
    

    测试:

    package bean;
    
    public class Test {
        public static void main(String[] args) {
            //获取代理对象
            BigStar bigStar = new BigStar("鸡哥");
            Star proxy = ProxyUtil.createProxy(bigStar);
            //调用方法
            proxy.sing("只因你太美");
    
            proxy.dance();
        }
    }
    
    

    结果

    java反射详解_第1张图片

反射

反射允许对封装类的字段,方法,和构造函数的信息进行编程的访问

获取class对象的三种方法

  • Class.forName(“全类名”);全类名:包名+类名

    最为常用

  • 类名.class

    一般更多的是当作参数传递

  • 对象.getClass()

    有一定的局限性,当我们已经有了该类的对象才可以使用

反射获取构造方法

获取Class对象 Class
构造方法 constructor
字段(成员变量) Field
成员方法 Method
package bean;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;

public class MyReflect {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取字节码文件对象
        Class clazz = Class.forName("bean.Student");

        //获取构造方法
        System.out.println("获取所有的public修饰的构造方法");
        Constructor[] constructors = clazz.getConstructors();
        for(Constructor c : constructors){
            System.out.println(c);
        }
        System.out.println("获取所有的构造方法");
        Constructor[] declaredConstructor = clazz.getDeclaredConstructors();
        for(Constructor c : declaredConstructor){
            System.out.println(c);
        }
        System.out.println("获取单个的构造方法(空参构造)");
        Constructor declaredConstructor1 = clazz.getDeclaredConstructor();
        System.out.println(declaredConstructor1);
        System.out.println("获取单个构造方法(一个参数的,该参数为形参的字节码)");
        Constructor declaredConstructor2 = clazz.getDeclaredConstructor(String.class);
        System.out.println(declaredConstructor2);
        Constructor declaredConstructor3 = clazz.getDeclaredConstructor(String.class, int.class);
        System.out.println(declaredConstructor3);
        System.out.println("获取权限修饰符");
        int modifiers = declaredConstructor3.getModifiers();
        System.out.println("权限修饰符:"+modifiers);
        System.out.println("获取参数类型");
        Parameter[] parameters = declaredConstructor3.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        System.out.println("创建对象");
        Object stu = declaredConstructor3.newInstance("张三", 18);
        System.out.println(stu);
        //临时取消权限校验:class.setAccessible(true)
    }
}

输出结果

获取所有的public修饰的构造方法
public bean.Student(java.lang.String,int)
public bean.Student(int)
public bean.Student()
获取所有的构造方法
public bean.Student(java.lang.String,int)
public bean.Student(int)
protected bean.Student(java.lang.String)
public bean.Student()
获取单个的构造方法(空参构造)
public bean.Student()
获取单个构造方法(一个参数的,该参数为形参的字节码)
protected bean.Student(java.lang.String)
public bean.Student(java.lang.String,int)
获取权限修饰符
权限修饰符:1
获取参数类型
java.lang.String arg0
int arg1
创建对象
Student{name='张三', age=18}

在java中权限修饰符是用整数来表示的,如图所示:public == 1,private= == 2

java反射详解_第2张图片
)

反射获取成员变量

package bean;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
import java.sql.SQLOutput;

public class MyReflect {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //获取字节码文件对象
        Class clazz = Class.forName("bean.Student");
        System.out.println("获取所有成员变量");
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        System.out.println("获取所有的公共的成员变量");
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("获取单个成员变量");
        Field name = clazz.getField("name");
        System.out.println(name);
        System.out.println("获取成员变量的权限修饰符");
        int modifiers = name.getModifiers();
        System.out.println(modifiers);
        System.out.println("获取成员变量名:");
        System.out.println(name.getName());
        System.out.println("获取数据类型");
        Class<?> type = name.getType();
        System.out.println(type);

        Student s = new Student("张三",18);
        System.out.println("获取成员变量的值");
        Object val = name.get(s);
        System.out.println(val);
        System.out.println("修改变量的值");
        name.set(s,"李四");
        Object val2 = name.get(s);
        System.out.println(val2);
    }
}

输出结果:

获取所有成员变量
public java.lang.String bean.Student.name
private int bean.Student.age
获取所有的公共的成员变量
public java.lang.String bean.Student.name
获取单个成员变量
public java.lang.String bean.Student.name
获取成员变量的权限修饰符
1
获取成员变量名:
name
获取数据类型
class java.lang.String
获取成员变量的值
张三
修改变量的值
李四

获取成员方法

实例代码:

package bean;

import java.lang.reflect.*;
import java.sql.SQLOutput;

public class MyReflect {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //获取字节码文件对象
        Class clazz = Class.forName("bean.Student");
        System.out.println("获取所有的public方法对象,包括父类中的公共方法");
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("获取本类所有的方法包含私有的方法(不能获取父类的)");
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        System.out.println("获取指定方法");
        Method eat = clazz.getMethod("eat", String.class);
        System.out.println(eat);
        System.out.println("获取方法的修饰符");
        int modifiers = eat.getModifiers();
        System.out.println(modifiers);
        System.out.println("获取方法的名字");
        String name = eat.getName();
        System.out.println(name);
        System.out.println("获取方法的形参");
        Parameter[] parameters = eat.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        System.out.println("获取方法的返回值");
        Class<?> returnType = eat.getReturnType();
        System.out.println(returnType);
        System.out.println("获取方法的抛出的异常");
        Class[] exceptionTypes = eat.getExceptionTypes();
        for (Class exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }
        System.out.println("方法的运行。。。。");
        Student stu = new Student("张三",18);
        /*
        invoke方法中:
        第一个参数:用obj对象调用该方法,方法的调用者
        第二个参数:调用该方法传递的参数(没有就不写)
        返回值:没有就不写
         */
        Object res = eat.invoke(stu, "酸菜");//返回值为该方法的返回值
        System.out.println(res);

    }
}

运行结果:

获取所有的public方法对象,包括父类中的公共方法
public java.lang.String bean.Student.getName()
public java.lang.String bean.Student.toString()
public void bean.Student.setName(java.lang.String)
public int bean.Student.getAge()
public java.lang.String bean.Student.eat(java.lang.String) throws java.io.IOException,java.lang.NullPointerException,java.io.FileNotFoundException
public void bean.Student.setAge(int)
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
public final void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
获取本类所有的方法包含私有的方法(不能获取父类的)
public java.lang.String bean.Student.getName()
public java.lang.String bean.Student.toString()
private void bean.Student.sleep()
public void bean.Student.setName(java.lang.String)
public int bean.Student.getAge()
public java.lang.String bean.Student.eat(java.lang.String) throws java.io.IOException,java.lang.NullPointerException,java.io.FileNotFoundException
public void bean.Student.setAge(int)
获取指定方法
public java.lang.String bean.Student.eat(java.lang.String) throws java.io.IOException,java.lang.NullPointerException,java.io.FileNotFoundException
获取方法的修饰符
1
获取方法的名字
eat
获取方法的形参
java.lang.String arg0
获取方法的返回值
class java.lang.String
获取方法的抛出的异常
class java.io.IOException
class java.lang.NullPointerException
class java.io.FileNotFoundException
方法的运行。。。。
吃酸菜
吃饱了
  • 反射的作用

    获取一个类的所有信息,得到信息之后,再去执行其他的业务逻辑

lic java.lang.String bean.Student.eat(java.lang.String) throws java.io.IOException,java.lang.NullPointerException,java.io.FileNotFoundException
获取方法的修饰符
1
获取方法的名字
eat
获取方法的形参
java.lang.String arg0
获取方法的返回值
class java.lang.String
获取方法的抛出的异常
class java.io.IOException
class java.lang.NullPointerException
class java.io.FileNotFoundException
方法的运行。。。。
吃酸菜
吃饱了


* 反射的作用

  获取一个类的所有信息,得到信息之后,再去执行其他的业务逻辑

  结合配置文件,动态的创建对象并调用方法

你可能感兴趣的:(java,java)