11Java 反射篇


Java反射

Java反射机制,可以在程序中访问 已经写好类和方法 的Java对象的描述,实现访问、检测、修改Java本身的信息 等功能 。提供功能的包:java.lang.reflect

Modifier类 常用解析方法: (解析返回整型数值)

修饰符 静态方法 说明
boolean Modifier.isPublic(int mod) 被public修饰,则true
boolean Modifier.isProtected(int mod) 被protected修饰,则true
boolean Modifier.isPrivate(int mod) 被private修饰,则true
boolean Modifier.isStatic(int mod) 被static修饰,则true
boolean Modifier.isFinal(int mod) 被final修饰,则true
boolean Modifier.toString(int mod) 以字符串形式返回所有修饰符

其他信息

类型 修饰符 方法 说明
包路径 Package getPackage() 获取该类的存放路径
类名称 String getName() 获取类名称
继承类 Class getSuperclass() 获取该类的继承类
实现接口 Class[] getInterfaces() 获取该类实现的所有接口
内部类 Class[] getClasses() 获取所有权限为public的内部类
内部类 Class[] getDeclaredClasses() 获取所有内部类
内部类声明类 Class getDeclaringClass() 如果该类为内部类,则返回它的成员类,否则为null(空)

访问构造方法

*Class Constructor <T> *

java.lang.Object
java.lang.reflect.AccessibleObject
java.lang.reflect.Executable
java.lang.reflect.Constructor<T>

通过方法访问构造方法,将返回Constructor类型对象,每个Constructor对象代表一个构造方法

获取构造方法:

修饰符 方法 说明
Constructor[] class.getConstructors() 获取所有权限为public(公开)的构造方法
Constructor class.getConstructor(Class<?>···parameterTypes) 获取权限为public的指定构造方法
Constructor[] class.getDeclaredConstructors() 获取所有的构造方法,按声明顺序排列
Constructor class.getDeclaredConstructor(Class<?>···parameterTypes) 获取指定的构造方法

Constructor类 常用方法:

修饰符 方法 说明
int Constructor.getModifiers() 获取构造方法的修饰符
String Constructor.getName() 获取构造方法的名字
Class[] Constructor.getParameterTypes() 获取构造方法的参数类型
boolean Constructor.isVarArgs() 带有可变数量的参数,则true
Class[] Constructor.getExceptionTypes() 获取构造方法可能抛出的异常类型
Object T Constructor.newInstance(Obj··· initargs) 利用指定参数创建该类对象,如果未设置参数,则以无参构造方法创建

通过 java.lang.reflect.Modifier类 来解析部分无法识别的信息,比如getModifiers() 返回的值是需要解析的

例子:

Student类(学生类)

public class Student {
    public int id ;
    public String name ;
    public double Achievement;

    //无参构造方法
    public Student(){
        super();
    }

    //有参构造方法(参数1)
    public Student(int id){
        super();
        this.id = id;
    }

    //可变参数
    public Student(String...strs){
        System.out.println("可变参数获取的值有:");
        for (String tmp : strs){
            System.out.println(tmp);
        }
    }

    //私有构造方法(参数3)
    private Student(int id , String name , double Achievement)throws NumberFormatException{
        super();
        this.id = id ;
        this.name = name;
        this.Achievement = Achievement;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", Achievement=" + Achievement +
                '}';
    }
}

Demo类 (执行类)

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

public class Demo {
    public static void main(String[] args) {
        try {
            //获取类
            Class c = Class.forName("Student");
            //获取所有构造方法
            Constructor[] cons = c.getDeclaredConstructors();
            //遍历该类中的构造方法
            for(Constructor con : cons){
                //修饰符类型
                System.out.print(Modifier.toString(con.getModifiers())+" ");
                //构造方法名
                System.out.print(con.getName()+" (");

                //获取参数
                Class[] paras = con.getParameterTypes();
                //遍历参数元素
                for (int i = 0; i < paras.length; i++) {
                    System.out.print(paras[i].getSimpleName()+" args");
                    if( i < paras.length-1){
                        System.out.print(" , ");
                    }
                }
                System.out.println(") { } ");
                System.out.println("查看是否允许带有可变数量的参数:"+con.isVarArgs());

                //获取构造方法可能抛出的异常类型 且遍历 异常类型
                System.out.println("该构造方法可能抛出的异常类型为:");
                Class[] geterror = con.getExceptionTypes();
                for (Class tmp : geterror){
                    System.out.println(tmp+"\t");
                }

                System.out.println("---");
            }

            System.out.println("==================================");

            Constructor cs = c.getDeclaredConstructor();
            Object obj = cs.newInstance();
            System.out.println(obj.toString());

            Constructor cs2 = c.getDeclaredConstructor(int.class);
            Object obj2 = cs2.newInstance(1322334);
            System.out.println(obj2.toString());

            Constructor cs3 = c.getDeclaredConstructor(int.class , String.class , double.class );
            //获取操作权限
            cs3.setAccessible(true);
            Object obj3 = cs3.newInstance(1332445 , "小明" , 84.2);
            System.out.println(obj3.toString());


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

运行结果

private Student (int args , String args , double args) { } 
查看是否允许带有可变数量的参数:false
该构造方法可能抛出的异常类型为:
class java.lang.NumberFormatException    
---
public transient Student (String[] args) { } 
查看是否允许带有可变数量的参数:true
该构造方法可能抛出的异常类型为:
---
public Student (int args) { } 
查看是否允许带有可变数量的参数:false
该构造方法可能抛出的异常类型为:
---
public Student () { } 
查看是否允许带有可变数量的参数:false
该构造方法可能抛出的异常类型为:
---
==================================
Student{id=0, name='null', Achievement=0.0}
Student{id=1322334, name='null', Achievement=0.0}
Student{id=1332445, name='小明', Achievement=84.2}

访问成员变量

Class Field

java.lang.Object
java.lang.reflect.AccessibleObject
java.lang.reflect.Field

通过方法访问成员变量,将返回Field类型对象,每个Field对象代表一个成员变量

获取成员变量

修饰符 方法 说明
Field[] class.getFields() 获取 所有 权限为public的成员变量
Field class.getField(String name) 获取权限为public的 指定 成员变量
Field[] class.getDeclaredFields() 获取说有成员变量,按声明顺序排列
Field class.getDeclaredField(String name) 获取指定的成员变量

Field类 常用方法

修饰符 方法 说明
String Field.getName() 返回变量名
class Field.getType() 返回该成员类型的class对象
Object Field.get(Object obj) 指定对象obj中成员变量的值进行返回
void Field.set(Object obj , Object value) 指定对象obj中成员变量的值置为value
int Field.getInt(Object obj) 获取指定对象obj中类型为int的值
void Field.setInt(Object obj , int i) 指定对象obj中类型为int的值置为 i
float Field.getFloat(Object obj) 获取指定对象obj中类型为float的值
void Field.setFloat(Object obj , float f) 指定对象obj中类型为float的值置为 f
boolean Field.getBoolean(Object obj) 获取指定对象obj中类型为boolean的值
void Field.setBoolean(Object obj , boolean z) 指定对象obj中类型为boolean的值置为 z
void Field.setAccessible(boolean flag) 设置是否忽略权限限制直接访问私有成员
int Field.getModifiers() 获取该成员变量修饰符的整型

Student类 (学生信息类)

public class Student {
    /*
    *
    *   学号
    *   名字
    *   性别
    *   总分数
    *
    * */
    //分别设置初始值
    public int id = 99999;
    public String name = "XXX";
    public String esx = "男";
    private double Ovresult = 720.0;


    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", esx='" + esx + '\'' +
                ", Ovresult=" + Ovresult +
                '}';
    }
}

Demo类 (执行类)

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

public class Demo {

    public static void main(String[] args) {

        try{
            /*  遍历Student类的成员变量
            *
            * */
            //获取类
            Class c = Class.forName("Student");
            //获取该类所有成员变量
            Field[]  fid= c.getDeclaredFields();
            //获取所有的构造方法
            Constructor cs = c.getDeclaredConstructor();
            //创建该类对象 Student
            Student setSude = (Student) cs.newInstance();

            //遍历成员变量
            System.out.println("遍历Student类的成员变量:");
            for (Field tmp : fid){
                //修饰符
                System.out.print(Modifier.toString(tmp.getModifiers())+" ");
                //类型
                //class.getSimpleName()方法 返回类型名称(简略名)
                System.out.print(tmp.getType().getSimpleName()+" ");
                //变量名
                System.out.print(tmp.getName()+" = ");
                    //获取指定的成员变量
                    //tmp.getName()返回成员变量名
                    Field f = c.getDeclaredField(tmp.getName());
                    //忽略权限限制直接访问私有成员
                    f.setAccessible(true);
                    System.out.print(f.get(setSude)+";");
                System.out.println();
            }


            /*  更改Student类的成员变量的值
            *
            * 由于枚举型,为学习则这样表示
            *   数组索引位置的说明:(顺序严格)
            *       更改开关
            *       更改结果(无更改用null代替)
            *
            * */
            //限于更改一位同学的数据
            Object[] mations = new Object[]{

                    //更改 学号(0 ,1)
                    true,
                    12345,

                    //更改 名字(2 ,3)
                    true,
                    "小明",

                    //更改性别(4 ,5)(此处为无更改)
                    false,
                    null,

                    //更改 总分数(6 ,7)
                    true,
                    523.5
            };

            System.out.println("============================");
            //获取所有成员变量(按声明顺序获取)
            Field[] setmations = c.getDeclaredFields();
            System.out.println("====信息更新====");
            for (Field tmp : setmations){

                //更改学号
                if (tmp.getName().equals("id") && (Boolean) mations[0]){
                    tmp.set(setSude , (int)mations[1]);
                    System.out.print("学号更改为:");
                    System.out.println(tmp.get(setSude));
                }

                //更改姓名
                if (tmp.getName().equals("name") && (Boolean) mations[2]){
                    tmp.set(setSude , (String)mations[3]);
                    System.out.print("姓名更改为:");
                    System.out.println(tmp.get(setSude));
                }

                //更改性别
                if (tmp.getName().equals("esx") && (Boolean) mations[4]){
                    tmp.set(setSude , (String)mations[5]);
                    System.out.print("性别更改为:");
                    System.out.println(tmp.get(setSude));
                }

                //更改总成绩
                if (tmp.getName().equals("Ovresult") && (Boolean) mations[6]){
                    //忽略权限限制直接访问私有成员
                    tmp.setAccessible(true);
                    tmp.set(setSude, (double)mations[7]);
                    System.out.print("总成绩更改为:");
                    System.out.println(tmp.get(setSude));
                }
            }

            //重新遍历学生数据
            System.out.println("====重新遍历学生数据====");
            /*
            *
            * (1)自选
            *
            *  */
//            for (Field tmp : setmations){
//                System.out.print(tmp.getName()+" = ");
//                System.out.print(tmp.get(setSude));
//                System.out.println();
//            }
            /*
             *
             * (2)自选
             *
             *  */
            System.out.println(setSude.toString());

        }catch (ClassNotFoundException | NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

    }
}

运行结果

遍历Student类的成员变量:
public int id = 99999;
public String name = XXX;
public String esx = 男;
private double Ovresult = 720.0;
============================
====信息更新====
学号更改为:12345
姓名更改为:小明
总成绩更改为:523.5
====重新遍历学生数据====
Student{id=12345, name='小明', esx='男', Ovresult=523.5}

访问方法

Class Method

java.lang.Object
java.lang.reflect.AccessibleObject
java.lang.reflect.Executable
java.lang.reflect.Method

通过方法访问方法,将返回Method类型对象,每个Method对象代表一个方法

获取方法

修饰符 方法 说明
Method[] class.getMethods() 获取所有权限为public的方法
Method class.getMethod(String name , Class<?>····parameterTypes) 获取权限为public的指定方法
Method[] class.getDeclaredMethods() 获取所有的方法,按声明顺序排列
Method class.getDeclaredMethod(String name , Class<?>····parameterTypes) 获取指定方法

Method类 常用方法

修饰符 方法 说明
String Method.getName() 获取方法名称
Class[] Method.getParameterTypes() 获取参数的类型
Class Method.getReturnType() 获取方法返回的类型
Class[] Method.getExceptionTypes() 返回方法抛出的异常类型
Object Method.invoke(Object obj , Object … args) 指定参数args指定obj方法
Boolean Method.isVarArgs() 带有可变数量的参数,则true
int Method.getModifiers() 获取方法的修饰符(呈现形式整数)

Dog类

public class Dog {

    //算术 (数值相加)
    // 抛出算术异常ArithmeticException
    public int Countadd(int a , int b ) throws ArithmeticException{
        return (a+b);
    }

    //行为
    public void Behavior(String naem ,String...agrs){
        System.out.print("我的小狗叫:"+naem);
        System.out.print(",他会");
        for (String tmp : agrs){
            System.out.print(tmp+"\t");
        }
        System.out.println();
    }

    //主人(认领 / 更换)
    private String hostnaem = null;
    private void Thehost(String name){
        this.hostnaem = name;
    }

}

Demo类

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) {

        //遍历Dog类的所有方法
        try {

            Class c = Class.forName("Dog");
            //获取所有方法
            Method[] mod = c.getDeclaredMethods();
            //遍历方法
            for (Method tmp : mod){
                //修饰符权限
                System.out.print(Modifier.toString(tmp.getModifiers())+" ");
                //方法返回类型
                System.out.print(tmp.getReturnType()+" ");
                //方法名字
                System.out.print(tmp.getName()+" (");

                //参数
                Class[] paras = tmp.getParameterTypes();
                for (int i = 0; i < paras.length; i++) {
                    System.out.print(paras[i].getSimpleName());//.getSimpleName()   java.lang.String
                    if (i < paras.length-1){
                        System.out.print(" ,");
                    }
                }
                System.out.print(") ");

                //抛出异常(无则跳过)
                Class[] exces = tmp.getExceptionTypes();
                if (exces.length != 0){
                    System.out.print(" throws ");
                    for (int i = 0; i < exces.length; i++) {
                        System.out.print(exces[i].getSimpleName());
                        if (i < exces.length-1){
                            System.out.print(",");
                        }
                    }
                }

                System.out.print("{ } ");
                System.out.println(" 可变数量的参数?"+tmp.isVarArgs());
            }

            //调用方法Dog类中的Countadd()方法(算术行为)
            System.out.println("======Countadd()方法");
            //获取构造方法(无参构造方法)
            Constructor cs = c.getConstructor();
            //实例化对象
            Dog tmpmethod =(Dog) cs.newInstance();

            Method m= c.getDeclaredMethod("Countadd", int.class , int.class);
            System.out.println(m.invoke(tmpmethod , 4 , 3));


            //调用方法Dog类中的Behavior()方法(行为)
            System.out.println("======Behavior()方法");
            Method m2= c.getDeclaredMethod("Behavior", String.class , String[].class);
            //获取权限
            m2.setAccessible(true);
            m2.invoke(tmpmethod , "Jak" , new String[]{"奔跑" , "吃"});

            //Dog属者(主人)
            //调用方法Dog类中的Thehost()方法
            System.out.println("\n======Thehost()方法");
            Method m3= c.getDeclaredMethod("Thehost", String.class);
            m3.setAccessible(true);
            m3.invoke(tmpmethod , "Tom");

        }catch (ClassNotFoundException | NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }
}

运行结果

public transient void Behavior (String ,String[]) { }  可变数量的参数?true
public int Countadd (int ,int)  throws ArithmeticException{ }  可变数量的参数?false
private void Thehost (String) { }  可变数量的参数?false
======Countadd()方法
7
======Behavior()方法
我的小狗叫:Jak,他会奔跑    吃    
======Thehost()方法

访问Annotation

Class Annotation

java.lang.Object
java.text.Annotation

对Annotation类型未了解,可前去网址了解:点击了解

访问的前提注解要有该注解@Retention(RetentionPolicy.RUNTIME)

获取注解

修饰符 调用的类型 方法 说明
Annotation Constructor(构造方法)
Field(成员变量)
Method(方法)
getAnnotation(Class annotationClass) 获取指定的Annotation,不存在则返回null
Annotation[] Constructor(构造方法)
Field(成员变量)
Method(方法)
getAnnotations() 获取所有的Annotation

方法

修饰符 调用的类型 方法 说明
String Class AnnotationClass toString() 返回此注释的String表示形式
boolean Constructor(构造方法)
Field(成员变量)
Method(方法)
isAnnotationPresent(Class annotationClass) 查看是否添加注解

例子:

BookAnnotation注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)//可被反射利用
public @interface BookAnnotation {
     //备注
     String remark() default "";
     //属性是否打开
     boolean enable() default true;

}

Book类

public class Book {
    //书名
    @BookAnnotation(remark = "书名")
    public String name;
    //类型
    @BookAnnotation(remark = "类型" , enable = false)//不启动属性
    public String species;
    //价钱
    @BookAnnotation(remark = "价钱")
    public int price;
    //厂商
    @BookAnnotation(remark = "厂商")
    public String firm;
}

Demo类

import java.lang.reflect.Field;

public class Demo {
    public static void main(String[] args) {

        try{
            Class c = Book.class;
            //获取Book类的所有成员变量
            Field[] fields = c.getDeclaredFields();
            //遍历成员变量
            for (Field tmp : fields){
                //查看是否添加注解(成员变量)
                if (tmp.isAnnotationPresent(BookAnnotation.class)){
                    System.out.println(tmp.getName()+"注解过了");
                    //获取所有注解
                    BookAnnotation b = tmp.getAnnotation(BookAnnotation.class);
                    //返回remark值
                    System.out.println("内容为:"+b.remark());
                    //返回enable值
                    System.out.println("属性是否有效:"+b.enable());
                    System.out.println("注解形式:"+b.toString());
                }
                System.out.println("\n==============");
            }
        }catch (Exception e){
            e.printStackTrace();
        }


    }
}

运行结果

name注解过了
内容为:书名
属性是否有效:true
注解形式:@BookAnnotation(enable=true, remark="书名")

==============
species注解过了
内容为:类型
属性是否有效:false
注解形式:@BookAnnotation(enable=false, remark="类型")

==============
price注解过了
内容为:价钱
属性是否有效:true
注解形式:@BookAnnotation(enable=true, remark="价钱")

==============
firm注解过了
内容为:厂商
属性是否有效:true
注解形式:@BookAnnotation(enable=true, remark="厂商")

==============

文章作者: 柏竹
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 柏竹 !
评论
  目录