一、反射机制

在前面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.String
class java.lang.String
class 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()

获取类中所有的属性(public、protected、default、private),但不包括继承的属性

getDeclaredField(String name)

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

getConstructors()

获取类中的公共方法

getConstructor(Class[] params)

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

getDeclaredConstructors()

获取类中所有的构造方法(public、protected、default、private)

getDeclaredConstructor(Class[] params)

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

getMethods()

获得类的public类型的方法

getMethod(String name, Class[] params)

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

getDeclaredMethods()

获取类中所有的方法(public、protected、default、private)

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();
} }

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

一、描述方法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<Student> clazz = (Class<Student>) Class.forName(className); //指定成父类之后实际还是获取子类的构造函数
Constructor<Person> [] constructors =
(Constructor<Person>[]) Class.forName(className).getConstructors(); for(Constructor<Person> constructor: constructors){
System.out.println("getConstructors:"+constructor);
} Constructor<Student> [] constructorsa =
(Constructor<Student>[]) Class.forName(className).getDeclaredConstructors(); for(Constructor<Student> constructor: constructorsa){
System.out.println("getDeclaredConstructors:"+constructor);
} //通过getConstructor获取公有构造函数
Constructor<Student> 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)
cyw
getDeclaredConstructor:private Reflection.Student(java.lang.String)
cyw

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

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

Java语法之反射的更多相关文章

  1. Java高级语法之反射

    Java高级语法之反射 什么是反射 java.lang包提供java语言程序设计的基础类,在lang包下存在一个子包:reflect,与反射相关的APIs均在此处: 官方对reflect包的介绍如下: ...

  2. Java基础学习笔记二十三 Java核心语法之反射

    类加载器 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化. 加载就是指将class文件读入内存,并为之创建一个Class对象.任 ...

  3. java中动态反射

    java中动态反射能达到的效果和python的语法糖很像,能够截获方法的实现,在真实方法调用之前和之后进行修改,甚至能够用自己的实现进行特别的替代,也可以用其实现面向切片的部分功能.动态代理可以方便实 ...

  4. java基础之反射机制

    一.概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...

  5. java基础(十一 )-----反射——Java高级开发必须懂的

    本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...

  6. java 基础之--反射详解

    java 反射绝大部分都位于 java.lang.reflect package 中:常用的类就是: 1.class类:代表一个类 2.field类:代表类的成员变量 3.method:代表类的方法 ...

  7. Java中的反射机制(一)

    基本概念 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法? 答案是肯定的. 这种动态获取类的信息以及动态调用对象的方法的功能来自于J ...

  8. java学习--Reflection反射机制

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. ...

  9. Java语法知识总结

    一:java概述: 1991 年Sun公司的James Gosling等人开始开发名称为 Oak 的语言,希望用于控制嵌入在有线电视交换盒.PDA等的微处理器: 1994年将Oak语言更名为Java: ...

随机推荐

  1. Python3基础知识之数据结构List和Tuple

    问题:今天学习python数据结构中的List和Tuple. 目标:了解二者的区别,学会一般的应用 相关知识:列表(List) : 类似于 .NET ArrayList / List.元组(Tuple ...

  2. Java多线程系列4 线程交互(wait和notify方法)

    wait()/ notify()/ notifyAll() 任何Object对象都可以作为这三个方法的主调,但是不推荐线程对象调用这些方法. 1使用wait().notify()和notifyAll( ...

  3. Oracle中为表设置自动增长的标识列

    -- Create sequence create sequence INNERID minvalue 1 maxvalue 99999999999999 start with 1 increment ...

  4. lua的table转为excel表格的方法

    项目中需要用到转表工具,由于没有直接的转表工具,而且嵌套的table(table里面嵌套了多层表格与数组).无奈之下,只好采用折衷的方法,先将table表格转为json数据,再用在线转表工具将json ...

  5. Codeforces Round #485 (Div. 2) A. Infinity Gauntlet

    Codeforces Round #485 (Div. 2) A. Infinity Gauntlet 题目连接: http://codeforces.com/contest/987/problem/ ...

  6. springMVC一个Controller处理所有用户请求的并发问题(转)

    springMVC一个Controller处理所有用户请求的并发问题 有状态和无状态的对象基本概念: 有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的.一 ...

  7. Vmware Vtop基本使用

      俗话说:"最了解孩子的莫过于亲妈",算了编不下去了,简而言之就是我们想知道虚机的详情可以通过Vmware Vtop登录宿主机进行查看,直接上干货.   有这些信息我们可以从Vt ...

  8. [转]kaldi中的在线识别----Online Recognizers

    转自: http://blog.csdn.net/wbgxx333/article/details/24932533 本文是kaldi学习联盟中@冒顿翻译的,下面是@冒顿的翻译结果,在这里感谢@冒顿的 ...

  9. 【BZOJ4025】 二分图(线段树分治)

    传送门 BZOJ Solution 只是为了学习一下线段树分治的啦! 当你学会线段树分治之后,可以跳过下面的一部分: 按照时间搞一颗线段树出来,把包含这段区间的操作用vector压进去. 每一个线段树 ...

  10. ajax跨域问题小结

    跨域:跨域名的访问,是浏览器对ajax的一种限制,这样可以有效的房子跨站攻击 跨域的范畴: 域名不同  或 端口不同 或 二级域名不同 解决方案: 第一种:由于前端基础薄弱,且该方式老掉牙,不讲解: ...