java----反射

动态语言

  首先java不是一个动态语言,但是java具有一定的动态性,这个动态性实现方式之一:反射

String str = "xx";
Class<?> aClass = Class.forName(str); //根据字符串的不同,动态编译不同的类对象

  反射的强大之处

   指的是可以运行时加载、探知、使用编译期间完全未知的类。

      程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;

获取Class对象的三种方法

package com.first;
public class Demo {
    public static void main(String[] args) {
        Dog dog = new Dog("花花",10);
        //方式一,通过对象获取class对象
        Class<? extends Dog> aClass = dog.getClass();

        //方式二,通过类来获取
        Class<Dog> dogClass = Dog.class;

        //方式三,通过Class.forName;(好处在于类不存在再编译期不会报错)
        try {
            Class.forName("com.first.Dog");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }


    }
}
class Dog{
    private String name;
    private int age;
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

一个类只有一个class对象

public class Test1 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> aClass1 = Class.forName("com.zy.Dog");
        Class<?> aClass2 = Class.forName("com.zy.Dog");
        Dog dog = new Dog();
        Class<? extends Dog> aClass3 = dog.getClass();
        Class<Dog> aClass4 = Dog.class;
        System.out.println(aClass1.hashCode()==aClass2.hashCode()); //true
        System.out.println(aClass2.hashCode()==aClass3.hashCode()); //true
        System.out.println(aClass3.hashCode()==aClass4.hashCode()); //true
    }
}

Class类的使用(通过反射,任何封装都可以被访问到)

通过反射实例化对象,实例化对象的类必须设置相应的构造方法;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Demo {
    public static void main(String[] args) {
        //test1(); //实例化对象
        //test2(); //获取类对象的属性(字段)
        test3();   //方法的调用;

    }
    public static void test1(){
        Class<Dog> dogClass = Dog.class;
        try {
            //通过Class实例化对象,默认调用对象的无参构造方法;(jdk9不推荐使用)
            Dog dog = dogClass.newInstance();
            //实例化对象,调用有参构造方法;
            Constructor<Dog> constructor = dogClass.getConstructor(String.class, int.class);
            //dogClass.getConstructors()  获取所有的构造方法,生成一个[],列表
            Dog dog1 = constructor.newInstance("花花",10);
        } catch (InstantiationException|IllegalAccessException|NoSuchMethodException|InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    public static void test2(){
        Class<Dog> dogClass = Dog.class;
        System.out.println(dogClass.getFields().length);  //获取所有的公有属性,静态属性,私有属性获取不到
        System.out.println(dogClass.getDeclaredFields().length);//获取所有的属性,(包括静态和私有)
        for (int i = 0; i <dogClass.getDeclaredFields().length ; i++) {
            System.out.println(Modifier.toString(dogClass.getDeclaredFields()[i].getModifiers())+" "+dogClass.getDeclaredFields()[i].getType()+" "+dogClass.getDeclaredFields()[i].getName());
        }
    }
    public static void test3(){
        Class<Dog> dogClass = Dog.class;
        //System.out.println(dogClass.getPackage());  //获取包名
        //访问公有的方法(包括继承的父类的方法)
        for (int i = 0; i < dogClass.getMethods().length; i++) {
            if (dogClass.getMethods()[i].getName().equals("toString")){
                try {
                    //通过invoke调用方法,第一个参数传对象,第二个参数传参数的形参(没有就不用填)
                    String str = (String) dogClass.getMethods()[i].invoke(new Dog("花花",10));
                    System.out.println(str);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }

            }
        }
        //访问包括私有方法的所有的方法(不继承父类的任何一个方法)
        Method[] methods = dogClass.getDeclaredMethods();
        Method method = dogClass.getDeclaredMethod("setName",String.class); //获取指定的方法,但是如果方法有参数,右面需要填写参数的class对象,如果没有,传null
         for (int i = 0; i < methods.length; i++) {
            if (methods[i].getName().equals("test")){
                //设置私有方法可以被访问
                methods[i].setAccessible(true);  //不能这样设置(没有效果,可能这种执行方法是没有保存数据):dogClass.getDeclaredMthods[i].setAccessible(true);
                try {
                    methods[i].invoke(new Dog("花花",10));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class Dog{
    static String t1;
    public String t2;
    private String name;
    private int age;
    public Dog(){}
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
    private void test(){
        System.out.println("我是私有方法");
    }
    @Override
    public String toString() {
        return "Dog{" +
                "t2='" + t2 + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

利用反射来操作对象

首先通过三种方式的一种获取Class对象;

可以找到class对象的方法、属性等,传入我们实例化的对象,就可以进行操作了

public class Test1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        Dog dog = new Dog();
        dog.setName("嘿嘿");
        Class<Dog> dogClass = Dog.class;
        Field name = dogClass.getDeclaredField("name");
        name.setAccessible(true);

        String  o = (String) name.get(dog);
        System.out.println(o);
        name.set(dog,"大大");
        String  o1 = (String) name.get(dog);
        System.out.println(o1);
    }
}

class Dog{
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

 

反射机制性能问题

public class Test1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Dog dog = new Dog();

        //普通方法调用
        long l = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            dog.test();
        }
        long l2 = System.currentTimeMillis();
        System.out.println(l2-l);

        //反射:不跳过安全检查
        //检查就是为了不然我们执行private方法
        Class<? extends Dog> aClass = dog.getClass();
        Method test = aClass.getDeclaredMethod("test");
        for (int i = 0; i < 10000000; i++) {
            test.invoke(dog);
        }
        long l3 = System.currentTimeMillis();
        System.out.println(l3-l2);

        //反射:跳过安全检查
        //即使我们知道这是一个public方法,我们也设置setAccessible(true),可以加快执行效率
        test.setAccessible(true);
        for (int i = 0; i < 10000000; i++) {
            test.invoke(dog);
        }
        long l4 = System.currentTimeMillis();
        System.out.println(l4-l3);
    }
}

class Dog{
    public void test(){

    }
}

  

 

posted @ 2019-04-24 19:37  小名的同学  阅读(216)  评论(0编辑  收藏  举报