java基础--14(反射)

1.反射机制的作用

   在运行时分析类的能力

   在运行时查看对象,例如编写一个toString方法供所有的类使用,

   实现通用的数组操作代码

   利用Method对象

2.检查类的结构

    现在有两个类

package com.wx1.test4;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * User: Mr.Wang
 * Date: 2019/10/27
 */
public class Employee {
    private String name;
    private Double salary;
    private LocalDateTime hireDay;

    public Employee(){

    }
    public Employee(String name, Double salary, LocalDateTime hireDay) {
        this.name = name;
        this.salary = salary;
        this.hireDay = hireDay;
    }

    public String getName() {
        return name;
    }

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

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    public LocalDateTime getHireDay() {
        return hireDay;
    }

    public void setHireDay(LocalDateTime hireDay) {
        this.hireDay = hireDay;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null) return false;//优化
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(name, employee.name) &&
                Objects.equals(salary, employee.salary) &&
                Objects.equals(hireDay, employee.hireDay);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, salary, hireDay);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", salary=" + salary +
                ", hireDay=" + hireDay +
                '}';
    }
}

  

package com.wx1.test4;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * User: Mr.Wang
 * Date: 2019/10/27
 */
public class Manager extends Employee {
    private Double bonus;

    public static final String NO_STR = "str";


    public Manager(String name, Double salary, LocalDateTime hireDay) {
        super(name, salary, hireDay);
        bonus = 0d;
    }

    public Double getBonus() {
        return super.getSalary() + this.getBonus();
    }

    public void setBonus(Double bonus) {

        this.bonus = bonus;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;
        Manager manager = (Manager) o;
        return Objects.equals(bonus, manager.bonus);
    }

    @Override
    public int hashCode() {

        return Objects.hash(super.hashCode(), bonus);
    }
}

 ok,我要查看这两个类的结构可以获得这个类的构造器,方法,域,以及他们的修饰符,参数类型,返回值类型等等。

package com.wx1.test4;


import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * User: Mr.Wang
 * Date: 2019/10/27
 */
public class Test1 {
    public static void main(String[] args) {
      
        //检查类的结构
        try {
            Class<Employee> employeeClass = Employee.class;
            Class<?> aClass = Class.forName("com.wx1.test4.Manager");

            //不包括超类
            Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
            Method[] declaredMethods = aClass.getDeclaredMethods();
            Field[] declaredFields = aClass.getDeclaredFields();

            //拿到public域包括超类,拿到方法包括超类,拿到本类的构造器
            Constructor<?>[] constructors = aClass.getConstructors();
            Field[] fields = aClass.getFields();
            Method[] methods = aClass.getMethods();

            //拿到构造器的修饰符
            List<String> collect = Arrays.stream(declaredConstructors)
                    .map((e) -> Modifier.toString(e.getModifiers()))
                    .collect(Collectors.toList());
            //拿到构造器的名字,构造器的参数类型
            Map<String, List<String>> collect1 = Stream.of(declaredConstructors)
                    .collect(Collectors.toMap(e -> e.getName(), e -> Stream.of(e.getParameterTypes()).map(v -> v.getName()).collect(Collectors.toList())));


            //拿到方法的修饰符
            List<String> collect2 = Arrays.stream(methods)
                    .map(e -> Modifier.toString(e.getModifiers()))
                    .collect(Collectors.toList());
            //拿到方法的返回值类型
            List<? extends Class<?>> collect3 = Arrays.stream(methods)
                    .map(e -> e.getReturnType())
                    .collect(Collectors.toList());
            //拿到方法的参数类型,按照子类和超类来分组
            Map<? extends Class<?>, List<Method>> listMap = Arrays.stream(methods)
                    .collect(Collectors.groupingBy(e -> e.getDeclaringClass()));
            for (Method method : methods) {
                Class<?> declaringClass = method.getDeclaringClass();
                Class<?> returnType = method.getReturnType();
                String name = method.getName();
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (Class<?> parameterType : parameterTypes) {
                    String name1 = parameterType.getName();
                }
            }

            //拿到域的修饰符
            List<String> collect4 = Stream.of(fields)
                    .map(e -> Modifier.toString(e.getModifiers()))
                    .collect(Collectors.toList());
            //拿到域的类型
            List<? extends Class<?>> collect5 = Stream.of(fields)
                    .map(e -> e.getType())
                    .collect(Collectors.toList());


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

    }
}

3.在运行时使用反射分析对象

   比如在运行时拿的到对象属性的值,设置对象属性的值,判断访问修饰符,这里需要注意一个问题就是java反射机制默认行为受限于java的访问控制。

  例如在运行时拿到employee对象的属性值:

            Employee employee=new Employee("MrWang",50000d,LocalDateTime.now());
            Class<? extends Employee> aClass1 = employee.getClass();
            Field name = aClass1.getDeclaredField("name");
            name.setAccessible(true);
            Object o = name.get(employee);

 可以将所有的域设置为可访问,那么也就可以编写一个通用的toString()方法。

4.使用反射可以编写泛型的数组

   在反射包下有一个Array对象,有一个newInstance方法可以创建新的数组,下面我们来编写一个扩展数组的方法,int[]可以转换为Object,所以参数的签名为Object.

    public static Object copyOf(Object o, int newLength) {
        Class<?> aClass = o.getClass();
        if (!aClass.isArray()) {
            return null;
        }
        Class<?> componentType = aClass.getComponentType();
        int length = Array.getLength(o);
        Object newInstance = Array.newInstance(componentType, newLength);
        System.arraycopy(o, 0, newInstance, 0,
                Math.min(length, newLength));
        return newInstance;
    }

 测试:

            String[] a = {"w", "x", "c"};
            String[] strings = (String[]) Test1.copyOf(a, 10);
            int length = strings.length;

5.调用任意方法

Method类中有一个invoke方法,它允许调用包装在当前Method对象中的方法。静态方法第一个参数可以设置为null

更多Class API方法:https://www.jianshu.com/p/9be58ee20dee

发布了217 篇原创文章 · 获赞 70 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/weixin_37650458/article/details/102771596