反射基本操作


* 本文主要介绍反射相关:
* 反射:(Reflection) 是java被视为动态语言的关键,反射机制允许程序在动态执行期间借助ReflectionAPI动态的获取类的任何
* 内部信息,并能直接操作对象的任何内部属性及方法。
* 通过类加载器,加载完类之后,在堆内存的方法区中就产生了Class类型的对象(对于相同的类只有一个Class对象),这个对象包含了
* 完整的类的结构信息,我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子,我们可以看到类的结构,所以,我们形象地称之为:反射.
* 正常情况下,我们通过new关键字来实例化并获取实例对象
* 反射,通过实例化获取完整的类的内部结构
* 缺点:
*      对性能影响极大,这类操作总是慢于直接执行相同的操作。
* java.lang.Class
* java.lang.reflect.Method       类的方法
* java.lang.reflect.Field        类的成员变量
* java.lang.reflect.Constructor  类的构造器

 

public class OperationsOfReflection {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,
            NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        // 通过反射来获取类的class对象, 此处需要处理异常。
        // 获取反射的Class对象方式1  Class.forName(全类名)
        // forName()里面是全类名  异常 ClassNotFoundException,
        Class c1 = Class.forName("cn.JAVandReflection.Reflection.Person");
        // 获取方式2, 用某个类的对象的 对象.getClass()获取对应的Class对象
        Person person = new Person();
        Class c2 = person.getClass();
        /**
         * 一个类一定只有一个class对象,验证:用反射获取的对象和这个类的对象的getClass()创建的对象比较其hashCode
         */
        System.out.println(c2.hashCode() == c1.hashCode());   // true
        // 获取方式3 : 用类的class属性获取,该获取方式最快最可靠
        Class c3 = Person.class;
        // 简介获取方式: 通过子类class对象获取父类的Class对象
        /**
         * Man extend Person
         */
        Class c4 = Man.class;
        Class c5 = c4.getSuperclass();
        System.out.println(c5.hashCode() == c3.hashCode()); // true
        /**
         * Class对象反操作类的一些方法, 如下:
         */
        // 获取类名  以Person的Class类为例  c3  或者 c5
        // 获取到的是全类名
        String allName = c3.getName();
        System.out.println(allName);
        // 获取到的是仅仅类名
        String simpleName = c3.getSimpleName();
        System.out.println(simpleName);
        /**
         * 输出:
         * cn.JAVandReflection.Reflection.Person
         * Person
         */
        // 根据Class对象获取类属性操作
        // getFields()
        Field[] fields = c3.getFields();
        Field[] fieldsAll = c3.getDeclaredFields();
        // 打印查看区别
        System.out.println(Arrays.toString(fields));
        System.out.println(Arrays.toString(fieldsAll));
        /**
         *[public java.lang.String cn.JAVandReflection.Reflection.Person.name,
         *  public char cn.JAVandReflection.Reflection.Person.sex]
         * 第二个
         * [public java.lang.String cn.JAVandReflection.Reflection.Person.name,
         * public char cn.JAVandReflection.Reflection.Person.sex,
         * private java.lang.String cn.JAVandReflection.Reflection.Person.id,
         * private int cn.JAVandReflection.Reflection.Person.age]
         * 可以看出,每一行第一个是修饰符,最后一个是字段名,
         * 第一个获取到的都是poublic修饰的
         * 第二个获取到的是public 和 private 其实它可以获取所有修饰的属性,包括private 私有属性
         */
        // 以上是获取属性列表,那么如何获取单个属性呢?
        // 同样的 加上Declared就是获取所有属性的而没有这个的方法获取到的都是publc修饰的
        //  NoSuchFieldException
        // 像这样,获取的name属性必须是public修饰的,不然会抛出  NoSuchFieldException异常
        Field name = c3.getField("name");
        // 这样的可以获取任意修饰符修饰的属性
        Field name1 = c3.getDeclaredField("name");

        /**
         * 获取方法
         */
        // 获取所有public的方法和父类的public方法, 注意 c4是Man的class
        Method[] methods = c4.getMethods();
        Method[] declaredMethods = c4.getDeclaredMethods();
        System.out.println(Arrays.toString(methods));
        System.out.println(Arrays.toString(declaredMethods));
        /**
         *注意。因为Man继承了person类,而person类继承了Object类,所以它列出了所有的public方法,很多
         * [public static void cn.JAVandReflection.Reflection.Man.main(java.lang.String[]),
         * public java.lang.String cn.JAVandReflection.Reflection.Person.toString(),
         * public java.lang.String cn.JAVandReflection.Reflection.Person.getName(),
         * public java.lang.String cn.JAVandReflection.Reflection.Person.getId(),
         * public void cn.JAVandReflection.Reflection.Person.setName(java.lang.String),
         * public void cn.JAVandReflection.Reflection.Person.setSex(char),
         * public char cn.JAVandReflection.Reflection.Person.getSex(),
         * public int cn.JAVandReflection.Reflection.Person.getAge(),
         * public final void java.lang.Object.wait() throws java.lang.InterruptedException,
         * public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException,
         * public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException,
         * public boolean java.lang.Object.equals(java.lang.Object),
         * public native int java.lang.Object.hashCode(),
         * public final native java.lang.Class java.lang.Object.getClass(),
         * public final native void java.lang.Object.notify(),
         * public final native void java.lang.Object.notifyAll()]
         * 第二个输出  应为man里面除了构造器,就创建了一个main方法用于测试
         * [public static void cn.JAVandReflection.Reflection.Man.main(java.lang.String[])]
         */
        // 获取单个方法  捕捉异常:NoSuchMethodException
        // 注意: 只能获取public修饰的方法
        // 参数列表: 第一个:获取方法的名字, 后面的参数依次是该方法对应参数的Class对象,例如,setName(String str)
        // 那么第二个参数就是Strin.class
        Method setName = c3.getMethod("setName", String.class);
        // 获取构造器
        Constructor[] constructors = c3.getConstructors();
        Constructor[] constructors2 = c3.getDeclaredConstructors();
        // 或者获取指定构造器
        Constructor constructor = c3.getDeclaredConstructor(String.class, char.class, String.class, int.class);
        System.out.println(Arrays.toString(constructors));
        System.out.println(Arrays.toString(constructors2));
        System.out.println(constructor);
        /**
         * 输出:
         * [public cn.JAVandReflection.Reflection.Person(),
         * public cn.JAVandReflection.Reflection.Person(java.lang.String,char,java.lang.String,int)]
         * -----------------------------------------------------------------------------------------------
         * [public cn.JAVandReflection.Reflection.Person(),
         * public cn.JAVandReflection.Reflection.Person(java.lang.String,char,java.lang.String,int)]
         * -----------------------------------------------------------------------------------------------
         * public cn.JAVandReflection.Reflection.Person(java.lang.String,char,java.lang.String,int)
         * 经比对:完全一致:
         */
        /*
        上面是获取信息,下面利用反射来创建和使用对象
         */
        // 获取对象,注意:直接获取到的是Object的对象,需要向下转型
        // 注意: 需要调用无参构造器,如果没有无参构造器就会抛异常,InstantiationException
        // 如果类构造器的权限是私有的,也不能通过这种方式获取对象
        Object person2 = c3.newInstance();
        // 通过获取到的构造器进行初始化 constructor 上面获取到的构造器
        Person o = (Person)constructor.newInstance("李白", 'M', "002", 15);
        // 通过反射调用方法
        // 调用方法前需要先创建对象,因为对象才能调用方法
        // 通过反射获取方法
        // 比如通过反射获取toString方法
        Method toString = c3.getDeclaredMethod("toString");
        // 使用invoke使用方法:invoke激活的意思
        // 使用方法.invoke()参数的第一个是通过反射创建的对象,后面的参数是方法的参数列表,如果没有传入null
        System.out.println(toString.invoke(o, null));
        /**
         * Person{name='李白', sex=M}  执行结果就和正常调用一样,说明处理正常
         */
        /**
         * !!!!!!!!!!! 注意:无论是获取私有方法还是私有属性,如果直接获取获取不到抛出异常
         * 就用  .setAccessible(true)方法关闭安全检测,这不仅能加括执行速度,还可以获取private修饰的东西
         */
        // 操作属性
        // 通过上面创建的对象 操作属性
        // 属性通过反射获取
        Field name2 = c3.getDeclaredField("name");
        name2.setAccessible(true);
        // 通过set修改
        name2.set(o, "张飞");
        // 通过get查看
        System.out.println(name2.get(o));
        // 为了验证,我们再次使用toString方法查看
        System.out.println(toString.invoke(o, null));
        /**
         * Person{name='李白', sex=M}
         * 张飞
         * Person{name='张飞', sex=M}
         * 可以看到,对象确实被修改了
         */
        /**
         * 反射操作泛型:
         * java采用泛型擦除机制来引入泛型,java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的问题
         * 但是一旦编译完成,所有和泛型相关的类型都会被擦除
         * 为了通过反射操作泛型,java新增了ParameterizedType : 表示参数化类型
         * 1、 getGenericParameterType
         * 2   遍历上面获取到Type 判断每一项  instanceof ParameterizedType
         * --- 此处理解先查看Type类型,然后是参数化类型  等
         *
         */

    }
}

 Person 类

package cn.JAVandReflection.Reflection;

public class Person {
    public String name;
    public char sex;
    private String id;
    private int age;

    public Person() {
    }

    public Person(String name, char sex, String id, int age) {
        this.name = name;
        this.sex = sex;
        this.id = id;
        this.age = age;
    }

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

    public String getName() {
        return name;
    }

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

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getId() {
        return id;
    }

    private void setId(String id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    private void setAge(int age) {
        this.age = age;
    }

    protected void eat() {
        System.out.println("人要吃饭饭!!!");
    }

}

Man

package cn.JAVandReflection.Reflection;

public class Man extends Person{
    public Man() {
        super.sex = 'M';
    }

    public Man(String name, String id, int age) {
        super(name, 'M', id, age);
    }

    public static void main(String[] args) {
        Man man = new Man("li", "001", 45);
        System.out.println(man);

    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值