java 反射机制-学习笔记(2)

Class 类


实例化对象

先看Class 完整写法如下

public final class Class<T>
extends Object
implements Serializable, GenericDeclaration, Type, AnnotatedElement

如果想使用Class 类进行操作,那么就必须产生Class 类的实例化对象。有以下几种方式:

  • Object类提供了一个返回Class 类对象的方法: public Class<?> getClass()
  • 利用“类.class” 取得, 日后见的最多的就是在Hibernate 上;
  • 利用Class 类的static 方法取得:public static Class<?> forName(String className)
    throws ClassNotFoundException;

反射的泛型几乎无用,直接用“?” 代替。
看下面例子:

package cn.lyx.reflact;
class Student   {
    public Student() {
        System.out.println("Student 类的构造方法");
    }
}
public class ReflactDemo {
    public static void main(String[] args)  throws ClassNotFoundException,
        InstantiationException, IllegalAccessException{ 
        Class<?> cls = Class.forName("cn.lyx.reflact.Student");// 使用泛型Class<Student> 会报异常,改成Class<?>就行
        Object obj = cls.newInstance();   // 相当  Object obj = new Student()  
    }
}

当反射使用泛型时异常

此例说明 实例化一个对象不一定用 new.使用 Class 的 newInstance() 方法同样达到一样效果。
注! 如果使用反射实例化类对象,必须要求该类中存在无参构造方法。因为使用 Class 的 newInstance()方法,只能找到无参。

package cn.lyx.reflact;
class Student   {
    private String name;
    private Integer age;
    public Student(String name, Integer age) {
        super();
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }


}
public class ReflactDemo {
    public static void main(String[] args)  throws ClassNotFoundException,
        InstantiationException, IllegalAccessException{ 
        Class<?> cls = Class.forName("cn.lyx.reflact.Student");// 使用泛型Class<Student> 会报错,改成Class<?>就行
        Object obj = cls.newInstance();   // 相当  Object obj = new Student()
        System.out.println(obj);
    }
}

此时Student类没有无参构造方法,当运行此段代码后会报错:找不到无参构造。

找不到无参构造

正是因为如果是通过构造方法实例化对象规格不统一。所以在进行简单Java类的的操作明确给出,必须有无参构造

获取父类对象

还有一个常用的方法:获取父类对象 public Class<? super T> getSuperclass()

操作构造方法

如果使用反射实例化类对象,必须要求类中存在无参构造方法。这个时候只能取得类之中的构造方法,传递所需的参数后方可执行。
Class 类中有以下两个方法可以实现。

  • 获取指定某个构造方法: public Constructor getConstructor(Class<?>… parameterTypes)
    throws NoSuchMethodException,
    SecurityException

  • 获取全部构造方法: public Constructor<?>[] getConstructors()
    throws SecurityException

调用类中方法

实话化类对象完成之后的主要工作内容就是调用类中可以使用的方法。

  • 获取包括父类继承而来的方法:
    a.获取全部方法: public Method[] getMethods()
    throws SecurityException // 不能获取private 修饰的方法
    b.获取指定方法:public Method getMethod(String name,
    Class<?>… parameterTypes)
    throws NoSuchMethodException,
    SecurityException

  • 获取类自身定义的方法:
    a 获取全部方法: public Method[] getDeclaredMethods()
    throws SecurityException // 可以获取private 修饰方法
    b 获取指定方法:public Method getDeclaredMethod(String name,
    Class<?>… parameterTypes)
    throws NoSuchMethodException,
    SecurityException

通过以上获取方法对象之后,还需要进一步操作获取方法的修饰符。看例子:


class Parent {   
    private static final Integer parentAge = 40;
    public String parentName;
    private static void parentWork(String str){
        System.err.println("工作");
    }
    public Integer parentDriver(Map<String, Object> map){
        System.out.println("开车");
        return 1;
    }
}
class Child extends Parent {
    public   List<String> childToy;
    private  Long score ;

    public Child() {
        super();
    }
    public Child(List<String> childToy, Long score) {
        super();
        this.childToy = childToy;
        score = score;
    }
    public final static List<Map<String, Object>> childMethod(String str, Map<String, Object> map)
    throws IOException, FileNotFoundException{
        System.out.println("子类方法");
        return null;
    }
}
public class ReflactDemo {
    public static void main(String[] args)  throws ClassNotFoundException,
        InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException{   
        Class<?> childClass = Class.forName("cn.lyx.reflact.Child");//
        Constructor<?>[] cttArray = childClass.getConstructors(); // 获取所有构造方法
        System.out.println("获取Child 所有构造方法");
        for (Constructor<?> ctt : cttArray) {
            System.out.println(ctt);
        }
        // 获得指定某个方法. 方法名:childMethod, 类型是String, Map
        Method method = childClass.getMethod("childMethod", String.class, Map.class);
        System.out.println("getMethod()的默认输出   : " + method);
        System.out.println("从getMethod()的默认输出 结果会输出所有的包名,在使用中很不方便,于是我们需要单独提取");
        System.out.println("获取修饰符 (整形)"+ method.getModifiers()); // 这里的修饰符是 整形需要转成普通字符串
        // 用Modifier 自带的toStrng 方法将整形修饰符转换成字符串
        String modify = Modifier.toString(method.getModifiers());
        System.out.println("普通修饰符  " + modify);
        // 获得参数类型,getReturnType() 会返回带着包名的类名
        System.out.println("返回参数类型   " + method.getReturnType().getSimpleName()); // 需要通过getSimpleName仅获得名字
        System.out.println("获取方法方法名 "+method.getName());
        // 获得所有参数类型
        Class<?>[] parames = method.getParameterTypes();
        System.out.print("所有参数类型   ");
        for (Class<?> parame : parames) {
            System.out.print(parame.getSimpleName()+  " "); // 输出所有参数类型
        }
        // 获取抛出的所有异常
        Class<?>[] exps = method.getExceptionTypes();
        System.out.println();
        System.out.println("抛出的所有异常  ");
        for (Class<?> exp : exps) {
            System.out.print(exp.getSimpleName() +" ");
        }

    }
}

输出结果:

获取Child 所有构造方法
public cn.lyx.reflact.Child()
public cn.lyx.reflact.Child(java.util.List,java.lang.Long)
getMethod()的默认输出   : public static final java.util.List cn.lyx.reflact.Child.childMethod(java.lang.String,java.util.Map) throws java.io.IOException,java.io.FileNotFoundException
从getMethod()的默认输出 结果会输出所有的包名,在使用中很不方便,于是我们需要单独提取
获取修饰符 (整形)25
普通修饰符  public static final
返回参数类型   List
获取方法方法名 childMethod
所有参数类型   String Map 
抛出的所有异常  IOException FileNotFoundException 

获取属性

获得属性与获得方法的方式相同,直接贴代码:

package cn.lyx.reflact;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

class Parent {   
    public String name;
    private Integer age;

}
class Child extends Parent {
    public String score;
    private String toy;
}
public class ReflactDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException  {
        Class<?> testCls = Class.forName("cn.lyx.reflact.Child");
        // 获取所有属性
        // 获取包括父类继承过来的所有属性 getFields(),  不能获取private 修饰的属性
        // 获取包括父类继承过来的指定属性 getField(String name)
        // 获取自身所有属性 getDeclaredFields(),  可以获取private 修饰的属性
        // 获取自身指定属性 getDeclaredField(String name)

        System.out.println("getFields() 方式 ");
        Field[] fields = testCls.getFields();   // 
        for (int i =0;i<fields.length;i++) {
            Field field = fields[i];
            System.out.println("第 "+ (i+1) +"个属性; 为  " + 
            Modifier.toString(field.getModifiers()) +" "
            + field.getType().getSimpleName()+" "
            + field.getName());
        }
        System.out.println("getDeclaredFields() 方式");
        Field[] fields2 = testCls.getDeclaredFields();
        for (int i =0;i<fields2.length;i++) {
            Field field = fields2[i];
            System.out.println("第 "+ (i+1) +"个属性; 为  " +
            Modifier.toString(field.getModifiers()) +" "
            + field.getType().getSimpleName()+ " "
            +  field.getName());
        }

    }
}

运行的结果为:
获取属性

从运行结果可以看出: getFields()可以获取从父类继承而来的所有公共属性,不能获取private 修饰的属性。getDeclaredFields()可以获取所有 包括private 修饰的属性,除了继承而来的属性。

操作属性

Field 提供方法操作属性。

package cn.lyx.reflact;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

class Parent {   
    public String name;
    private Integer age;

}
public class ReflactDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, 
    SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException  {
        Class<?> testCls = Class.forName("cn.lyx.reflact.Parent");
        Object obj = testCls.newInstance();  // 注意这里 的实例化,下面set 方法用到
        Field name = testCls.getDeclaredField("name");  
        Field age = testCls.getDeclaredField("age");
        System.out.println("设置前的名字    " + name.get(obj));
        name.set(obj, "思思"); // obj :要修改属性的那个类实例
        System.out.println("设置后的名字  " + name.get(obj));
        System.out.println("-----");
        System.out.println("设置前的年龄    " + age.get(obj));
        age.set(obj, 18);
        System.out.println("设置后的年龄  " + age.get(obj));

    }
}

运行结果图示:
设置名字

从结果中发现:属性name 可以正常set,get .唯有被private 修饰的 age 出现异常an not access (不能访问)。java 简单类的属性一般是private 修饰,不推荐直接操作属性,而是通过get,set方法,所有就出现为什么java 类中有那么多的get,set 方法。 如果一定要直接操作尼,也不是没有办法。

Field 类继承了一个方法 public void setAccessible(boolean flag)
throws SecurityException
官方对此方法大概的解释是:将此对象的可访问标记设置为指示布尔值。true的值表示反射对象在使用时应该抑制Java语言访问检查。值为false表示反射对象应该执行Java语言访问检查。
当我们把private 对象属性设置为 true 时,通过反射访问属性时,java 检查机制不起作用,可以操作属性。
看代码:
只需在 age 操作之前加上

age.setAccessible(true);

结果正常:
正常访问

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值