java年薪几十万的程序员必会的骚操作~

反射

一说到反射,我们通常想到的可能会是,镜面反射啊、条件反射之类的,但是我们今天要说的反射跟那个可没有任何的关系。

我们说 在java中一切皆对象

那么,在我们java程序运行时,会把我们的 .class 文件加载到 方法区 中,会使用一系列的类对我们类中的构造方法、成员方法、成员变量进行描述,而这个 class 文件java也使用了一个类来对它进行描述,这个类就是Class类,;我们之前学过 class 关键字,而Class这个是一个类。

获取 Class 对象的三种方法:

Employee类:

package cn.it.test.bean;

public class Employee {
    private String name;
    private int age;
    public double height;
    public double salary;
    protected double weight;

    // 一般工作中反射方法,对成员变量进行取值/设置
    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;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public double getSalary() {
        return salary;
    }

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

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public Employee() {
    }

    private Employee(String name) {
        this.name = name;
        this.age = age;
    }

    protected Employee(int age) {
        this.name = name;
        this.age = age;
    }

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int sleep(int hour) {
        System.out.println(name + "睡了" + hour);
        return hour + 2;
    }

    private void eat() {
        System.out.println(name + "吃饭了");
    }

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

public class Demo4 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 第一种:通过 类名.class
        //Class cls = Employee.class;
        //System.out.println("cls = " + cls);

        // 第二种:通过 对象.getClass
        //Employee e = new Employee();
        //Class cls = e.getClass();
        //System.out.println("cls = " + cls);

        // 第三种:也是推荐使用的;通过 Class.forName(类全名)
        Class cls = Class.forName("cn.it.test.bean.Employee");
        System.out.println("cls = " + cls);

    }
}

拿到 Employee 类的Class对象之后我们就可以获取这个类的一些信息了:类名啊、对应的构造方法、成员方法、成员变量之类的。

#Class对象相关方法

  • String getSimpleName(); 获得简单类名,只是类名,没有包
  • String getName(); 获取完整类名,包含包名+类名
  • T newInstance() ;创建此 Class 对象所表示的类的一个新实例。要求:类必须有public的无参数构造方法
		Class cls = Class.forName("cn.it.test.bean.Employee");
        // 获取类全名
        String name = cls.getName();
        System.out.println("name = " + name);
        // 获取类名
        String simpleName = cls.getSimpleName();
        System.out.println("simpleName = " + simpleName);

#Constructor类

Constructor是构造方法类,类中的每一个构造方法都是Constructor的对象,通过Constructor对象可以实例化对象。

##Class类中与Constructor相关方法

  1. Constructor getConstructor(Class… parameterTypes) 根据参数类型获取构造方法对象,只能获得public修饰的构造方法。如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
  2. Constructor getDeclaredConstructor(Class… parameterTypes) 根据参数类型获取构造方法对象,包括private修饰的构造方法。如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
  3. Constructor[] getConstructors() 获取所有的public修饰的构造方法
  4. Constructor[] getDeclaredConstructors() 获取所有构造方法,包括privat修饰的

##Constructor类中常用方法

  1. T newInstance(Object… initargs) 根据指定参数创建对象。
  2. void setAccessible(true) 暴力反射,设置为可以直接访问私有类型的构造方法。
public class Demo6 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        // 获取所有 public 修饰的构造方法
        Class cls = Class.forName("cn.it.t.bean.Employee");
        /*Constructor[] constructors = cls.getConstructors();
        for (Constructor c : constructors) {
            System.out.println("c = " + c);
        }*/

        // 获取 一个 public修饰的构造方法
        // Constructor c = cls.getConstructor(String.class,int.class);
        // System.out.println("c = " + c);

        // 获取 所有声明的构造方法
        // Constructor[] declaredConstructors = cls.getDeclaredConstructors();
        // for (Constructor c : declaredConstructors) {
        //     System.out.println("c = " + c);
        // }

        // 获取 一个声明的构造方法
        // Constructor c = cls.getDeclaredConstructor(String.class);
        // System.out.println("c = " + c);


        // 练习 Class 的 newInstance
        // Constructor c = cls.getConstructor();
        // Employee e = (Employee) c.newInstance();
        // System.out.println("e = " + e);

        // 练习 Class 的 newInstance;要求 类必须有 无参构造方法
        Employee ee = (Employee) cls.newInstance();
        System.out.println("e = " + ee);
    }
}

#Method类

Method是方法类,类中的每一个方法都是Method的对象,通过Method对象可以调用方法。

##Class类中与Method相关方法

  1. Method getMethod(“方法名”, 方法的参数类型… 类型)
    根据方法名和参数类型获得一个方法对象,只能是获取public修饰的
  2. Method getDeclaredMethod(“方法名”, 方法的参数类型… 类型)
    根据方法名和参数类型获得一个方法对象,包括private修饰的
  3. Method[] getMethods()
    获取所有的public修饰的成员方法,包括父类中。
  4. Method[] getDeclaredMethods()
    获取当前类中所有的方法,包含私有的,不包括父类中。

##Method类中常用方法

  1. Object invoke(Object obj, Object… args)
    根据参数args调用对象obj的该成员方法
    如果obj=null,则表示该方法是静态方法
  2. void setAccessible(boolean flag)
    暴力反射,设置为可以直接调用私有修饰的成员方法
// 获取 Class 对象所表示类的成员方法
public class Demo7 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        // 获取所有 public 修饰的成员方法;包括父类的
        Class cls = Class.forName("cn.it.test.bean.Employee");
        // Method[] methods = cls.getMethods();
        // for (Method m : methods) {
        //     System.out.println("m = " + m);
        // }

        // 获取 一个 public 修饰的成员方法
        Method method = cls.getMethod("sleep", int.class);
        System.out.println("method = " + method);
        // 调用方法
        Constructor c = cls.getDeclaredConstructor(String.class);
        c.setAccessible(true); // 这里就是暴力反射,c是私有的构造方法,外人不可使用,现在我们暴力反
        //射,使得我们可以通过构造方法c创建一个对象
        Employee e = (Employee) c.newInstance("胡歌");
        method.invoke(e,2);

        // 获取该类所有声明的成员方法;不包括父类
        // Method[] declaredMethods = cls.getDeclaredMethods();
        // for (Method m : declaredMethods) {
        //     System.out.println("m = " + m);
        // }

        // 获取 一个声明的方法
        // Method method = cls.getDeclaredMethod("eat");
        // System.out.println("method = " + method);
    }
}

#Field类、与Filed相关的方法

public class Demo71 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 获取所有 public 修饰的 成员变量
        Class cls = Class.forName("cn.it.test.bean.Employee");
        // Field[] fields = cls.getFields();
        // for (Field f : fields) {
        //     System.out.println("f = " + f);
        // }

        // 获取一个 public 修饰的成员变量
        // Field f = cls.getField("salary");
        // System.out.println("f = " + f);

        // 获取所有声明的成员变量
        // Field[] declaredFields = cls.getDeclaredFields();
        // for (Field f : declaredFields) {
        //     System.out.println("f = " + f);
        // }

        // 获取一个 声明的 成员变量
        // Field f = cls.getDeclaredField("weight");
        // System.out.println("f = " + f);

        // 下面我们来对变量进行一下 操作
        Constructor c = cls.getDeclaredConstructor(String.class);
        c.setAccessible(true);
        Employee e = (Employee) c.newInstance("李易峰");
        // Field f = cls.getDeclaredField("name");
        // f.setAccessible(true);  // 暴力反射
        // f.set(e,"黄渤");
        Field ff = cls.getField("height");
        ff.setDouble(e,180.0);

        // 获取变量的值
        // String name = e.getName();
        // System.out.println("name = " + name);
        double height = ff.getDouble(e);
        System.out.println("height = " + height);
        System.out.println("e = " + e);
    }
}

反射案例

需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
实现:

  1. 配置文件
  2. 反射

步骤:
3. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
4. 在程序中加载读取配置文件
5. 使用反射技术来加载类文件进内存
6. 创建对象
7. 执行方法

pro.properties

className=com.it.domain.Student
methodName=sleep

Student.java

package com.it.domain;
public class Student {
public void sleep(){
System.out.println("sleep...");
}
}

RefectTest.java

public class ReflectTest {
	@Test
	public void test() throws Exception {
		//可以创建任意类的对象,可以执行任意方法
		//前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法
		//1.加载配置文件
		//1.1创建Properties对象
		Properties pro = new Properties();
		//1.2加载配置文件,转换为一个集合
		//1.2.1获取class目录下的配置文件
		ClassLoader classLoader = ReflectTest.class.getClassLoader();
		InputStream is = classLoader.getResourceAsStream("pro.properties");
		pro.load(is);
		//2.获取配置文件中定义的数据
		String className = pro.getProperty("className");
		String methodName = pro.getProperty("methodName");
		//3.加载该类进内存
		Class cls = Class.forName(className);
		//4.创建对象
		Object obj = cls.newInstance();
		//5.获取方法对象
		Method method = cls.getMethod(methodName);
		//6.执行方法
		method.invoke(obj);
	}
}

猜你喜欢

转载自blog.csdn.net/RookiexiaoMu_a/article/details/88836430
今日推荐