🚩 Home / java / reflect.md

反射定义

所有技术实现的目标只有一点:重用性。

正:由class得到object相关信息

反:由object得到class相关信息

public class MainTest {
    public static void main(String[] args) throws Exception{
        Date date = new Date();
        System.out.println(date.getClass());
    }
}

class三种实例化模式:

  1. Object类支持,根据实例化对象获取Class对象

  2. JVM直接支持,

    public class MainTest {

     public static void main(String[] args) throws Exception{
         Class<Date> cls = Date.class;
         System.out.println(cls.getClass());
     }

    }

  3. Class类支持

    public class MainTest {

    public static void main(String[] args) throws Exception{
        Class<?> cls = Class.forName("java.util.Date");
        System.out.println(cls.getName());
    }

    }

反射应用:

反射实例化对象:代替new关键字

public class MainTest {
    public static void main(String[] args) throws Exception{
        Class<?> cls = Class.forName("com.silvester.Person");
        Object object = cls.newInstance();
        System.out.println(object.toString());
    }
}

jdk1.9之后 newInstance方法被取消。

使用cls.getDeclaredConstructor().newInstance()代替

反射与工厂设计模式

普通工厂设计模式:(需要if判断)

interface IMessage {
    public void send();
}
class NetMessage implements IMessage {
    public void send() {
        System.out.println("hello world");
    }
}
class Factory {
    private Factory() {}
    public static IMessage getInstance(String className) {
        if ("netmessage".equalsIgnoreCase(className)) {
            return new NetMessage();
        } else {
            return null;
        }
    }
}
public class MainTest {
    public static void main(String[] args) throws Exception{
        IMessage message = Factory.getInstance("netmessage");
        message.send();
    }
}

使用反射:子类扩充不再影响工厂类

interface IMessage {
    public void send();
}
class NetMessage implements IMessage {
    public void send() {
        System.out.println("hello world");
    }
}
class Factory {
    private Factory() {}
    public static IMessage getInstance(String className) {
        IMessage instance = null;
        try {
            instance = (IMessage) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            // TODO: handle exception
        }
        return instance;
    }
}
public class MainTest {
    public static void main(String[] args) throws Exception{
        IMessage message = Factory.getInstance("com.silvester.NetMessage");
        message.send();
    }
}

当有多个接口,工厂类需要能够提供多个接口服务,依赖泛型

interface IMessage {
    public void send();
}
class NetMessage implements IMessage {
    public void send() {
        System.out.println("hello world");
    }
}
interface IService {
    public void serve();
}
class HotelService implements IService {
    public void serve() {
        System.out.println("hotel service");
    }
}
class Factory {
    private Factory() {}

    /**
     * 获取接口实例化对象
     * @param className 接口子类
     * @param clazz 描述一个接口类型
     * @return 如果子类存在,返回指定接口实例化对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T getInstance(String className, Class<T> clazz) {
        T instance = null;
        try {
            instance = (T) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            // TODO: handle exception
        }
        return instance;
    }
}
public class MainTest {
    public static void main(String[] args) throws Exception{
        IMessage message = Factory.getInstance("com.silvester.NetMessage", IMessage.class);
        message.send();
        IService service = Factory.getInstance("com.silvester.HotelService", IService.class);
        service.serve();
    }
}

反射获取类结构信息

  • public Package getPackage() 获取包信息
  • public Class<? super T> getSuperclass() 获取继承父类
  • public Class<?>[] getInterfaces() 获取父接口

反射调用构造

  • Constructor<?>[] getDeclaredConstructors()
  • Constructor getDeclaredConstructor(Class<?>... parameterTypes)
  • Constructor<?>[] getConstructors()
  • Constructor getConstructor(Class<?>... parameterTypes)

Constructor.newInstance() 调用

反射调用普通方法

  • getMethods() // 包括父类方法
  • getMethod(String name, Class<?>...parameter)
  • getDeclaredMethods()
  • getDeclareMethod(String name, Class<?>...parameter)

Method.invoke()方法调用

反射获取成员

  • getDeclaredFileds()
  • getDeclaredFiled(String name)
  • getFileds()
  • getFiled(String name)

Filed.set() 设置属性内容

FIled.get() 获取属性内容

Filed.setAccessible() 解除封装

Filed.getType() 获取成员类型

应用

传统属性赋值弊端:属性过多,设置属性过程太繁琐

单级属性设置:主要对字符串的属性进行设置,即传入的属性是通过字符串传入的。

设置多种数据类型:可以实现各种类型的内容设置。

级联对象实例化:使用“.”进行级联设置

package com.silvester;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Copyright © 2019 Silvester. All rights reserved.
 * 
 * @Package: com.silvester 
 * @author: Silvester
 * @date: 2019年5月19日 下午2:36:51 
 */

public class MainTest {
    public static void main(String[] args) throws Exception{
        String value = "empno:7369|ename:Smith|job:Clerk|salary:7590.00|hiredata:1998-10-10|" + 
                        "dept.dname:财务部|dept.company.name:京西";
        Emp emp = ClassInstanceFactory.create(Emp.class, value);
        System.out.println("eno:" + emp.getEmpno() + ", name:" + emp.getEname() + ", job:" + emp.getJob() + ", salary:" + emp.getSalary() + ", date:" + emp.getHiredata());
        System.out.println(emp.getDept().getDname());
        System.out.println(emp.getDept().getCompany().getName());
    }
}

class ClassInstanceFactory {
    private ClassInstanceFactory() {}

    @SuppressWarnings("unchecked")
    public static <T> T create(Class<?> clazz, String value) {
        try {
            Object object = clazz.newInstance();
            BeanUtil.setValue(object, value);
            return (T) object;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

class StringUtil {
    public static String initcap(String str) {
        if (str == null || "".equals(str)) {
            return str;
        } 
        if (str.length() == 1) {
            return str.toUpperCase();
        } else {
            return str.substring(0, 1).toUpperCase() + str.substring(1);
        }
    }
}

class BeanUtil {
    private BeanUtil() {}

    /**
     * 属性设置
     * @param obj
     * @param value
     */
    public static void setValue(Object obj, String value) {
        String[] results = value.split("\\|");
        for (int x = 0; x < results.length; x++) {
            String[] attval = results[x].split(":");
            try {
                if (attval[0].contains(".")) {
                    String[] temp = attval[0].split("\\.");
                    Object currentObj = obj;
                    for (int y = 0; y < temp.length - 1; y++) {
                        Method getMethod = currentObj.getClass().getDeclaredMethod("get" + StringUtil.initcap(temp[y]));
                        Object tempObj = getMethod.invoke(currentObj);
                        if (tempObj == null) {
                            Field field = currentObj.getClass().getDeclaredField(temp[y]);
                            Method method = currentObj.getClass().getDeclaredMethod("set" + StringUtil.initcap(temp[y]), field.getType());
                            Object newObj = field.getType().newInstance();
                            method.invoke(currentObj, newObj);
                            currentObj = newObj;
                        } else {
                            currentObj = tempObj;
                        }
                    }
                    Field field = currentObj.getClass().getDeclaredField(temp[temp.length-1]);
                    Method setMethod = currentObj.getClass().getDeclaredMethod("set" + StringUtil.initcap(temp[temp.length-1]), field.getType());
                    Object convertVal = BeanUtil.convertAttributeValue(field.getType().getName(), attval[1]);
                    setMethod.invoke(currentObj, convertVal);
                } else {
                    Field field = obj.getClass().getDeclaredField(attval[0]);
                    Method setMethod = obj.getClass().getDeclaredMethod("set" + StringUtil.initcap(attval[0]), field.getType());
                    Object convertVal = BeanUtil.convertAttributeValue(field.getType().getName(), attval[1]);
                    setMethod.invoke(obj, convertVal);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 实现属性类型转换处理
     * @param type 属性类型,通过Field获取
     * @param value 属性内容,传入的都是字符串,需转换为指定类型
     * @return 转换后的数据
     */
    private static Object convertAttributeValue(String type, String value) {
        if ("long".equals(type) || "java.lang.Long".equals(type)) {
            return Long.parseLong(value);
        } else if ("int".equals(type) || "java.lang.Integer".equals(type)) {
            return Integer.parseInt(value);
        } else if ("double".equals(type) || "java.lang.Double".equals(type)) {
            return Double.parseDouble(value);
        } else if ("java.util.Date".equals(type)) {
            SimpleDateFormat sdf = null;
            if (value.matches("\\d{4}-\\d{2}-\\d{2}")) {
                sdf = new SimpleDateFormat("yyyy-MM-dd");
            } else {
                return new Date();
            }
            try {
                return sdf.parse(value);
            } catch (ParseException e) {
                return new Date();
            }
        } else {
            return value;
        }
    }
}

class Company {
    private String name;
    private Date createdata;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getCreatedata() {
        return createdata;
    }
    public void setCreatedata(Date createdata) {
        this.createdata = createdata;
    }
}

class Dept {
    private String dname;
    private String loc;
    private Company company;

    public String getDname() {
        return dname;
    }
    public String getLoc() {
        return loc;
    }
    public Company getCompany() {
        return company;
    }
    public void setDname(String dname) {
        this.dname = dname;
    }public void setLoc(String loc) {
        this.loc = loc;
    }
    public void setCompany(Company company) {
        this.company = company;
    }
}

class Emp {
    private long empno;
    private String ename;
    private String job;
    private double salary;
    private Date hiredata;
    private Dept dept;

    public long getEmpno() {
        return empno;
    }
    public void setEmpno(long empno) {
        this.empno = empno;
    }
    public String getEname() {
        return ename;
    }
    public void setEname(String ename) {
        this.ename = ename;
    }
    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    public Date getHiredata() {
        return hiredata;
    }
    public void setHiredata(Date hiredata) {
        this.hiredata = hiredata;
    }
    public Dept getDept() {
        return dept;
    }
    public void setDept(Dept dept) {
        this.dept = dept;
    }
}

反射与代理设计模式

动态代理模式

package com.silvester;

import java.io.Closeable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.ConnectException;

/**
 * Copyright © 2019 Silvester. All rights reserved.
 * 
 * @Package: com.silvester 
 * @author: Silvester
 * @date: 2019年5月19日 下午2:36:51 
 */
interface IMessage {
    public void send();
}
class MessageReal implements IMessage {
    @Override
    public void send() {
        // TODO Auto-generated method stub
        System.out.println("send message");
    }
}
class MyProxy implements InvocationHandler {
    private Object target;
    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    public boolean connect() {
        System.out.println("connect");
        return true;
    }
    public void close() {
        System.out.println("close");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行方法" + method);
        Object returndata = null;
        if (this.connect()) {
            returndata = method.invoke(this.target, args);
            this.close();
        }
        return returndata;
    }
}
public class MainTest {
    public static void main(String[] args) throws Exception{
        IMessage msg = (IMessage) new MyProxy().bind(new MessageReal());
        msg.send();
    }
}

CGLIB实现代理设计模式

反射与Annotation

反射获取Annotation

package com.silvester;

import java.io.Closeable;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.ConnectException;

import org.junit.runners.model.Annotatable;

/**
 * Copyright © 2019 Silvester. All rights reserved.
 * 
 * @Package: com.silvester 
 * @author: Silvester
 * @date: 2019年5月19日 下午2:36:51 
 */
@FunctionalInterface
@Deprecated
interface IMessage {
    public void send();
}

@SuppressWarnings("serial")
class MessageImpl implements IMessage, Serializable {
    @Override
    public void send() {
        // TODO Auto-generated method stub
        System.out.println("send");
    }
}
public class MainTest {
    public static void main(String[] args) throws Exception{
        {
            Annotation[] annotations = IMessage.class.getAnnotations();
            for (Annotation a : annotations) {
                System.out.println(a);
            }
        }
        System.out.println("-----------------------------------");
        {
            Annotation[] annotations = MessageImpl.class.getAnnotations();
            for (Annotation a : annotations) {
                System.out.println(a);
            }
        }
        System.out.println("-----------------------------------");
        {
            Method method = MessageImpl.class.getMethod("send");
            Annotation[] annotations = method.getAnnotations();
            for (Annotation a : annotations) {
                System.out.println(a);
            }
        }

    }
}

输出

@java.lang.FunctionalInterface()
@java.lang.Deprecated()
-----------------------------------
-----------------------------------

即有些Annotation可以输出有些不能输出

FunctionalInterface

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

SuppressWarnings

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

RUntime是运行时有效,SOURCE是源码时有效

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

三种类型如上,CLASS是定义为类时有效。

自定义Annotation

    package com.silvester;

    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.reflect.Method;

    /**
     * Copyright © 2019 Silvester. All rights reserved.
     * 
     * @Package: com.silvester 
     * @author: Silvester
     * @date: 2019年5月19日 下午2:36:51 
     */
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation {
        public String title();
        public String url() default "www.baidu.com";
    }
    class Message {
        @MyAnnotation(title="hello")
        public void send(String msg) {
            System.out.println("send: " + msg);
        }
    }
    public class MainTest {
        public static void main(String[] args) throws Exception{
            Method method = Message.class.getMethod("send", String.class);
            MyAnnotation annos = method.getAnnotation(MyAnnotation.class);
            System.out.println(annos.title());
            System.out.println(annos.url());
            method.invoke(Message.class.newInstance(), annos.title() + annos.url());
        }
    }