博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java语法之反射
阅读量:6696 次
发布时间:2019-06-25

本文共 10063 字,大约阅读时间需要 33 分钟。

一、反射机制

在前面Java语法之注解自定义注解时我们也有提到反射,要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation对象。那什么是反射呢?JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。它有点类似照妖镜的作用,不管是什么妖魔鬼怪(类或对象)都能看到它的真面目(获取类的属性方法、调用对象的属性方法)。

二、Class理解

 反射机制可以动态获取类信息以及调用对象方法,那它是通过什么实现的呢?这就要介绍下Class类了。首先明确Class也是一个类,只是它是一个描述类的类,它也可以生成对象。对于每个类而言,在JRE中有且仅有一个不变的 Class 类型的对象,而这个Class 类型的对象只能由系统建立,封装了当前对象所对应的类的信息,有哪些属性,方法,构造器,实现了哪些接口等等。而且每个类的实例都会记得自己是由哪个Class实例所生成。

 那要获取类信息或调用对象方法,肯定首先要获取到该类或对象对应的Class类的实例。一般获取Class对象有三种方式。

 1. 通过类名获取   类名.class

 2. 通过对象获取   对象.getClass()

 3. 通过全类名获取 Class.forName(全类名)

 这里我们可以使用用字符串来做验证。输出结果都是class java.lang.String。

package Reflection;public class ReflectionTest {        public static void main(String[] args) throws ClassNotFoundException {       //字符串的例子       Class clazz = null;       //类名.class       clazz = String.class;       System.out.println(clazz);       //对象.getClass()       clazz = "ReflectionTest".getClass();       System.out.println(clazz);       //Class.forName(全类名)       clazz = Class.forName("java.lang.String");       System.out.println(clazz);    }}
class java.lang.Stringclass java.lang.Stringclass java.lang.String

上面通过三种方式能获取到Class实例,然后再了解一下Class类常用的方法

方法名

功能说明

forName(String name)

返回指定类名 name Class 对象

newInstance()

调用缺省构造函数,返回该Class对象的一个实例

newInstance(Object []args)

调用当前格式构造函数,返回该Class对象的一个实例

getName()

返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称

getSuperClass()

返回当前Class对象的父类的Class对象

getInterfaces()

获取当前Class对象的接口

getClassLoader()

返回该类的类加载器

getSuperclass()

返回表示此Class所表示的实体的超类的Class

getFields()

获取类中public类型的属性

getField(String name)

获取类特定的方法,name参数指定了属性的名称

getDeclaredFields()

获取类中所有的属性(publicprotecteddefaultprivate),但不包括继承的属性

getDeclaredField(String name)

获取类特定的方法,name参数指定了属性的名称

getConstructors()

获取类中的公共方法

getConstructor(Class[] params)

获取类的特定构造方法,params参数指定构造方法的参数类型

getDeclaredConstructors()

获取类中所有的构造方法(publicprotecteddefaultprivate)

getDeclaredConstructor(Class[] params)

获取类的特定构造方法,params参数指定构造方法的参数类型

getMethods()

获得类的public类型的方法

getMethod(String name, Class[] params)

获得类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型

getDeclaredMethods()

获取类中所有的方法(publicprotecteddefaultprivate)

getDeclaredMethod(String name, Class[] params)

获得类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型

 三、反射的使用

 这里要着重介绍下上面API的使用,因为在后面要学习的Spring中IOC的原理就是反射加工厂模式。学好反射API有助于理解Spring框架内部实现。为了演示Class方法的使用,在注解demo的基础上对Person、Student类进行了修改。

Person类:

package Reflection;@CustomDescription(description="基类")@CustomDescription(description="人")public class Person {        private String Name;        public String getName() {        return Name;    }        public void setName(String name) {        Name = name;    }        public String PersonPublicMethod(String str)    {        return str;    }        public Person(String name) {        Name = name;    }    public String PersonPrivateMethod(String str)    {        return str;    }    public Person() {        super();    }    }
View Code

 Student类:

package Reflection;@CustomDescription(description="学生")@CustomDescription(description="人")public class Student extends Person {    public String StudentId;    public String getStudentId() {        return StudentId;    }    public void setStudentId(String studentId) {        StudentId = studentId;    }        public String StudentPublicMethod(String str)    {        return str;    }        private String StudentPrivateMethod(String str)    {        return str;    }        public Student(String name, String studentId) {        super(name);        StudentId = studentId;    }        private Student(String name) {        super(name);        StudentId="123456";    }        public Student() {            }}
View Code

一、描述方法Method

描述方法的主要是4个获取方法getMethods、getMethod、getDeclaredMethods、getDeclaredMethod和1个调用方法invoke。

getMethods:获取clazz对应类中的所有方法,不能获取private方法,且获取从父类继承来的所有方法包括私有父类的私有方法
getMethod:获取clazz对应类中指定方法名和参数类型的方法,不能获取private方法,且获取从父类继承来的所有方法包括私有父类的私有方法,因为存在同方法名不同参数这种情况,所以只有同时指定方法名和参数类型才能唯一确定一个方法。
getDeclaredMethods:获取所有方法,包括私有方法,所有声明的方法,都可以获取到,且只获取当前类的方法。
getDeclaredMethod:获取clazz对应类中指定方法名和参数类型的方法,包括私有方法,所有声明的方法,都可以获取到,且只获取当前类的方法。
Invoke:执行方法,第一个参数表示执行哪个对象的方法,剩下的参数是执行方法时需要传入的参数,私有方法的执行,必须在调用invoke之前加上一句method.setAccessible(true);

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {        Class clazz = Class.forName("Reflection.Student");        Method method=null;        Method[] methods=null;                methods = clazz.getMethods();        for(Method mth:methods){            System.out.print(mth.getName()+" ");        }        System.out.println();                method = clazz.getMethod("StudentPublicMethod",String.class);        System.out.print(method.getName()+" ");        System.out.println();        methods = clazz.getDeclaredMethods();        for(Method mth:methods){            System.out.print(mth.getName()+" ");        }        System.out.println();                method = clazz.getDeclaredMethod("StudentPrivateMethod",String.class);        System.out.print(method.getName()+" ");        System.out.println();                Object obje = clazz.newInstance();        method.setAccessible(true);        String result=(String) method.invoke(obje,"inputParams");        System.out.println(result);    }

输出结果:

StudentPublicMethod setStudentId getStudentId getName setName PersonPrivateMethod PersonPublicMethod wait wait wait equals toString hashCode getClass notify notifyAll StudentPublicMethod StudentPrivateMethod StudentPublicMethod setStudentId getStudentId StudentPrivateMethod inputParams

 二、描述字段Filed

描述字段Filed方法的使用和描述方法Method中方法的使用有点类似,也是4个获取字段的方法:getFields、getField、getDeclaredFields、getDeclaredField。
getFields:获得某个类的所有的公共(public)的字段,包括父类中的字段。
getField:获取某个类public成员变量中指定变量名的字段,包括基类。
getDeclaredFields:获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
getDeclaredField:获取某个类的所有成员变量指定变量名的字段,不包括基类。

1.字段获取

Class clazz = Class.forName("Reflection.Student");        System.out.println("---------getDeclaredFields---------");        Field[] fields = clazz.getDeclaredFields();        for(Field field: fields){            System.out.print(field.getName()+" ");        }        System.out.println();        System.out.println("---------getFields---------");        fields = clazz.getFields();        for(Field field: fields){            System.out.print(field.getName()+" ");        }        System.out.println();               System.out.println("---------getDeclaredField---------");        Field field = clazz.getDeclaredField("StudentId");        field.setAccessible(true);        System.out.println(field.getName());                System.out.println("---------getField--------");                field = clazz.getField("StudentId");        System.out.println(field.getName());
---------getDeclaredFields---------StudentId ---------getFields---------StudentId ---------getDeclaredField---------StudentId---------getField--------StudentId

2.字段的使用

Class clazz = Class.forName("Reflection.Person");    Person person = new Person("CYW");        //获取私有字段的值        Field field = clazz.getDeclaredField("Name");        //由于是私有字段,需要使用setAccessible(true)        field.setAccessible(true);        Object val = field.get(person);        System.out.println(val);        //改变私有字段的值        field.set(person, "ivan");        System.out.println(person.getName());

三、描述构造器Constructor

先介绍下描述构造函数Constructor用到的方法,主要用到的还是4个:getConstructors、getDeclaredConstructors、getConstructor、getDeclaredConstructor。和前面Method、Field用的方法进行比较,类比思想,举一反三,我们也能大概了解这几个方法的使用。其实在编程中有好多体现哲学思想的地方,有正有反,有阴有阳,学会思考这样可以以点带面,触类旁通。
getConstructors:获取对应类中public类型的构造函数,且只获取当前类的构造函数
getConstructor:获取对应类中public指定参数类型的构造函数,且只获取当前类的构造函数
getDeclaredConstructors:获取对应类中所有构造函数,包括私有构造函数,且只获取当前类的构造函数。

getDeclaredConstructor:获取对应类中指定参数类型的方法,包括私有构造函数,且只获取当前类的方法。

String className = "Reflection.Student";        Class
clazz = (Class
) Class.forName(className); //指定成父类之后实际还是获取子类的构造函数 Constructor
[] constructors = (Constructor
[]) Class.forName(className).getConstructors(); for(Constructor
constructor: constructors){ System.out.println("getConstructors:"+constructor); } Constructor
[] constructorsa = (Constructor
[]) Class.forName(className).getDeclaredConstructors(); for(Constructor
constructor: constructorsa){ System.out.println("getDeclaredConstructors:"+constructor); } //通过getConstructor获取公有构造函数 Constructor
constructor = clazz.getConstructor(String.class, String.class); System.out.println("getConstructor:"+constructor); Student obj = constructor.newInstance("cyw", "123456"); System.out.println(obj.getName()); //通过getDeclaredConstructor获取私有构造函数 constructor = clazz.getDeclaredConstructor(String.class); System.out.println("getDeclaredConstructor:"+constructor); //对于私有构造函数在初始化之前要设置setAccessible(true) constructor.setAccessible(true); obj = constructor.newInstance("cyw"); System.out.println(obj.getName());
getConstructors:public Reflection.Student(java.lang.String,java.lang.String)getConstructors:public Reflection.Student()getDeclaredConstructors:public Reflection.Student(java.lang.String,java.lang.String)getDeclaredConstructors:private Reflection.Student(java.lang.String)getDeclaredConstructors:public Reflection.Student()getConstructor:public Reflection.Student(java.lang.String,java.lang.String)cywgetDeclaredConstructor:private Reflection.Student(java.lang.String)cyw

四、描述注解Annotation

描述注解主要用到getAnnotation(Class<A> annotationClass) 方法,它返回该元素的指定类型的注解,否则返回null。

String className = "Reflection.Student";        Class
clazz = (Class
) Class.forName(className); CustomDescriptions customDescriptions =clazz.getAnnotation(CustomDescriptions.class); for(CustomDescription h: customDescriptions.value()){ System.out.println("description:" + h.description()); }
description:学生description:人

 

转载地址:http://gbvoo.baihongyu.com/

你可能感兴趣的文章
多年珍藏的55w御剑字典
查看>>
Python实践之路7——计算器
查看>>
java中堆和栈的区别
查看>>
后渗透之meterpreter攻略
查看>>
vue页面初始化
查看>>
按钮切换显示不同的内容(js控制)
查看>>
【056】我的电子产品
查看>>
宝塔面板快速开启https服务
查看>>
c++线程池小例子
查看>>
angular
查看>>
转载文章:Windows Azure 七月份更新:SQL 数据库、流量管理器、自动伸缩、虚拟机...
查看>>
RDLC报表部署到服务器的相关问题
查看>>
HTML5移动Web开发(九)——优化浏览器视口宽度设置
查看>>
Spark- 根据ip地址计算归属地
查看>>
python中的面向对象学习以及类的继承和继承顺序
查看>>
注册表的作用、bat文件中REG ADD命令添加注册表项以及bat
查看>>
sort
查看>>
C# is 强制转换
查看>>
rigi参考书籍
查看>>
慎用线程局部变量
查看>>