java中的反射与应用

6 篇文章 0 订阅

摘要:本文主要讲解了反射的基础语法、反射在动态代理中的应用,动态代理主要讲解了JDK动态代理和Cglib的动态代理。两者的区别是JDK是面向接口的编程,Cglib是面向方法的编程,都有各自的应用场景。

1、什么反射?

Java程序在运行时,可以获取类的相关信息,可以动态调用对象的方法机制。

类比:类是所有对象的抽象,类对象class是对所有类的抽象。(个人观点)

2、反射的使用

反射应用的前提是获取类所对应的类对象,一个类能且只能产生一个类对象。假设在包com.smart.reflect下存在一个Student类,获取类对象的三个方法

(1) Class studentClass=  Class.forName("com.smart.reflect.Student"); 推荐使用

(2) Student student = new Student (); Class studentClass = student.getClass();

(3)  Class studentClass = Student.class;

拿到类对象之后,就可以获取类及其父类的相关信息,属性,方法(构造方法和普通方法),来看下主要信息

(1)Class 描述类本身

(1.1)获取类的修饰符:studentClass.getModifies()

(1.2)获取类的名字:studentClass.getSimpleName();studentClass.getName();

   (1.3)   获取父类的信息:Class superClass = studentClass,getSuperClass()

(1.4)获取接口信息:Class[] interface = studentClass.getInterfaces();

创建对象

Object object =  studentClass.newInstance(),调用无参构造函数;studentClass.newInstance()

(2)Package 包信息

         获取包的相关信息:Package p = studentClass.getPackage();

(3)Field 属性信息

  (3.1)获取 属性:Field field = studentClass.getField(属性名); Field field = studentClass.getDeclareField(属性名); 

  (3.2)获取属性的类型:Class fclass = field.getType();

    (3.3)  为属性赋值:field.set(对象,值)

 (3.4)取属性的值:field.get(对象)

 (3.5) 获取所有公有的属性: Field[] field = studentClass.getFields()

 (3.6) 获取所有的属性: Field[] field = studentClass.getDeclaredFields()

注意:访问私有属性 field.setAccessible(true);

   (3.7) 获取所有内部类:Class[] innerClass = studentClass.getClasses()

(4)Method 方法信息

 (4.1)获取 方法:Method method = studentClass.getMethod(方法名,类型); Method method = studentClass.getDeclareMethod(方法名,类型); 

(4.2)获取方法的信息:返回值类型,方法名,参数列的类型,异常类型

 (4.3) 获取所有公有的方法: Method[] method= studentClass.getMethods()

 (4.4) 获取所有的方法: Method[] method = studentClass.getDeclaredMethods()

(4.5)有参数:method.invoke(对象,参数); 无参数:method.invoke(对象);

  注意:访问私有属性 method.setAccessible(true);

(5)Constructor 用来描述类中的构造方法

(6)Annotation 描述类中的注解

3、反射的应用

3.1 动态代理

3.1.1.静态代理之Helloworld

(1)创建目标接口

 

interface Service{
       void sayHello();
   } 

(2)实现目标接口

 

class RealService implements Service{
        @Override
        public void sayHello() {
            System.out.println("hello, world!");
        }

    }

(3)创建代理类,实现了Service接口

 

class StaticProxy implements Service{

        private Service realService;
        public StaticProxy(Service service){
            this.realService = service;
        }
        @Override
        public void sayHello() {
            realService.sayHello();
        }

    }

代理类中注入了Service接口的对象,实例化时只需要注入Service的实现类就好。

(4)创建测试程序

3.1.2.动态代理-JDK

 

(1)创建目标接口

 

interface Service{
       void sayHello();
   } 

(2)实现目标接口

class RealService implements Service{
        @Override
        public void sayHello() {
            System.out.println("hello, world!");
        }

    }

(3)创建代理类

 

public class DynamicProxyHanlder implements InvocationHandler {
    private Object obj;
    public DynamicProxyHanlder(Object realObj){
        this.obj = realObj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        method.invoke(obj, args);
        return null;
    }
}

创建动态代理,主要是实现InvocationHandler接口,重写了invoke方法,其中obj表示要真实代理的类。

(4)创建测试程序

 

public class Client {

    public static void main(String[] args) {
        Service realService = new ServiceImpl();
        InvocationHandler proxyHandler = new DynamicProxyHanlder(realService);
        Service proxyService = 
                (Service) Proxy.newProxyInstance(
                        Service.class.getClassLoader(),
                        new Class<?>[]{Service.class}, 
                        proxyHandler);
        proxyService.sayHello();
        
    }
}

代理类传入的参数是:被代理接口的类加载器,类类型的数组,代理类。

3.1.3.动态代理-Cglib

(1)创建目标方法类

 

class Service{
        public void sayHello(){
            System.out.println("hello,world");
        }
    }

(2)创建代理类

 

class SimpleInterceptor implements MethodInterceptor {

        @Override
        public Object intercept(Object object, Method method,
                Object[] args, MethodProxy proxy) throws Throwable {
            Object result = proxy.invokeSuper(object, args);
            return result;
        }

    }

实现的是MethodInterceptorie接口中的intercept的方法

(3)创建测试程序

 

public class Main {

    private static <T> T getProxy(Class<T> clazz){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(new SimpleInterceptor());

        return (T)enhancer.create();
    }

    public static void main(String[] args) {
        Service proxyService = getProxy(Service.class);
        proxyService.sayHello();
    }
}

总结:静态代理和动态代理-JDK是面向接口编程的,而动态代理-cglib是面向方法的编程。

动态代理涉及到类加载器的加载,具体的文章请参考:https://www.cnblogs.com/hiyujie/p/wo-xueJava1ClassLoader-yu-shuang-qin-wei-tuo-mo-sh.html

4、类加载器和反射的关系

      类加载器将字节码文件加载如JVM。

5、反射实例 (简化版的SpringIOC的实现)

5.1创建Person类:

/**
 *
 * @author smart 2019/3/23
 */
public class Person {

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    private Integer age;
}

5.2 创建简化版的Spring处理类

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;

/**
 *
 * @author smart 2019/3/23
 */
public class MySpring {
    public Object getBean(String packagePath){
        Object result = null;
        Scanner scanner = new Scanner(System.in);
        try{
            //创建类
           Class<?> classObject = Class.forName(packagePath);
           result = classObject.newInstance();

           //获取类的属性
            Field[] fields = classObject.getDeclaredFields();
            for (Field field: fields) {
                //获取属性名
                String name = field.getName();
                String firstLetter = name.substring(0,1).toUpperCase();
                String otherLetter = name.substring(1);
                StringBuilder propertiesMethod = new StringBuilder("set");
                propertiesMethod.append(firstLetter).append(otherLetter);
                Class fieldClass = field.getType();
                Method method = classObject.getMethod(propertiesMethod.toString(),fieldClass);
                //参数可以从文件中读取或者从注解中读取
                System.out.println("请输入参数");
                String param = scanner.nextLine();
                Constructor con = fieldClass.getConstructor(String.class);
                method.invoke(result,con.newInstance(param));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return result ;
    }
}

5.3测试及结果

/**
 *
 * @author smart 2019/3/23
 */
public class MainTest {
    public static void main(String[] args) {
        MySpring mySpring = new MySpring();
        Person person = (Person) mySpring.getBean("Person");
        System.out.println(person);
    }
}
测试结果:

请输入参数
12222
请输入参数
12
Person{name='12222', age=12}

5.4 利用注解的方式注入值

(1)自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *
 * @author smart 2019/3/23
 */
@Target(value = {ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnoation {
    String value();
}

(2)修改Person类

/**
 *
 * @author smart 2019/3/23
 */
public class Person {

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @MyAnnoation("smart")
    private String name;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @MyAnnoation("12")
    private Integer age;
}

(3)修改MySpring类

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;

/**
 *
 * @author smart 2019/3/23
 */
public class MySpring {
    public Object getBean(String packagePath){
        Object result = null;
        Scanner scanner = new Scanner(System.in);
        try{
            //创建类
           Class<?> classObject = Class.forName(packagePath);
           result = classObject.newInstance();
           //获取类的属性
            Field[] fields = classObject.getDeclaredFields();
            for (Field field: fields) {
                //获取属性名
                String name = field.getName();
                String firstLetter = name.substring(0,1).toUpperCase();
                String otherLetter = name.substring(1);
                StringBuilder propertiesMethod = new StringBuilder("set");
                propertiesMethod.append(firstLetter).append(otherLetter);
                Class fieldClass = field.getType();
                Method method = classObject.getMethod(propertiesMethod.toString(),fieldClass);
                //参数可以从文件中读取或者从注解中读取
                Annotation annotation = field.getAnnotation(MyAnnoation.class);
                Constructor con = fieldClass.getConstructor(String.class);
                method.invoke(result,con.newInstance(((MyAnnoation) annotation).value()));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return result ;
    }
}

(4)测试结果

Person{name='smart', age=12}

备注:调用注解的里的value方法,可以通过如下的代码:‘

’Annotation annotation = field.getAnnotation(MyAnnoation.class);

Class annotationClass = annotation.getClass();

Method method = annotationClass.getMethod("value");

String value = method.invoke(annotationClass);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值