Java学习总结:39(反射机制)
反射机制
JAVA中反射是动态获取信息以及动态调用对象方法的一种反射机制。
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为动态语言的一个关键性质。Java反射的功能是在运行时判断任意一个对象所属的类,在运行时构造任意一个类的对象,在运行时判断任意一个类所具有的成员变量和方法,在运行时调用任意一个对象的方法,生成动态代理。反射是Java中最为重要的特性,几乎所有的开发框架以及应用技术都是基于反射技术的应用。
认识反射
在一个程序中如果要通过对象取得这个对象所在类的信息,可以通过Object类中的getClass()方法(public final Class<?>getClass())实现。
例:反射初步操作
package Project.Study.Reflect;import java.util.Date;public class Test1 {public static void main(String[]args){Date date=new Date(); //产生实例化对象System.out.println(date.getClass());//直接反射输出对应类的信息}
}
//结果:
//class java.util.Date
Class类对象实例化
当我们使用getClass()方法时,返回的类型为java.lang.Class,这是反射操作的源头类,即所有的反射操作都需要从此类开始,而最关键的是这个类有以下3种实例化方式。
一.调用Object类中的getClass()方法,但是如果要使用此类操作必须要有实例化对象。
该方法往往出现在简单Java类与提交参数的自动赋值操作中,像Struts、Spring MVC都会提供表单参数与简单Java类的自动转换。
例:
package Project.Study.Reflect;import java.util.Date;public class Test2 {public static void main(String[]args){Date date=new Date(); //产生实例化对象Class<?>cls=date.getClass(); //通过实例化对象取得Class对象//Class类中定义有“public String getName()”方法可以取得类的完整名称System.out.println(cls.getName()); //直接对象所在类的名称}
}
//结果:
//java.util.Date
二.使用“类.class”取得,此时可以不需要通过指定类的实例化对象取得
该方式往往是将反射操作的类型设置交由用户使用,像Hibernate中进行数据保存以及根据ID查询中会使用到此类操作。
例:
package Project.Study.Reflect;public class Test3 {public static void main(String[]args){Class<?>cls=java.util.Date.class; //通过类名称取得Class类对象System.out.println(cls.getName()); //直接对象所在类的名称}
}
//结果:
//java.util.Date
三.调用Class类提供的方法:public static Class<?>forName(String className)throws ClassNotFoundException。
该方法可以实现配置文件以及Annotation配置的反射操作,几乎所有的开发框架都是依靠此方式实现的。
例:
package Project.Study.Reflect;public class Test4 {public static void main(String[]args) throws Exception {//此处直接传递了一个要进行反射操作类的完整名称,是用字符串定义的Class<?>cls=Class.forName("java.util.Date");System.out.println(cls.getName()); //直接对象所在类的名称}
}
//结果:
//java.util.Date
反射实例化对象
掌握了Class类对象实例化的三种操作方式,我们现在就可以利用Class类来进行类的反射控制了。
Class类的常用方法
No. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public static Class<?>forName(String className) throws ClassNotFoundException | 普通 | 通过字符串设置的类名称实例化Class类对象 |
2 | public Class<?>[] getInterfaces() | 普通 | 取得类实现的所有接口 |
3 | public String getName() | 普通 | 取得反射操作类的全名 |
4 | public String getSimpleName() | 普通 | 取得反射操作类名,不包括包名称 |
5 | public Package getPackage() | 普通 | 取得反射操作操作类所在的包 |
6 | public Class<? super T>getSuperclass() | 普通 | 取得反射操作类的父类 |
7 | public boolean isEnum() | 普通 | 反射操作的类是否是枚举 |
8 | public boolean isInterface() | 普通 | 反射操作的类是否是接口 |
9 | public boolean isArray() | 普通 | 反射操作的类是否是数组 |
10 | public T newInstance() throws InstantiationException,IllegalAccessException | 普通 | 反射实例化对象 |
在Class类中最重要的一个方法就是newInstance()方法,通过此方法可以利用反射实现Class类包装类型的对象实例化操作,也就是说即使不使用关键字new也可以进行对象的实例化操作。
注意:如果利用newInstance()方法反射实例化对象,则类中一定要提供无参构造方法,否则会出现语法错误。
例:利用反射实例化对象
package Project.Study.Reflect;class Book{public Book(){System.out.println("该类的无参方法");}@Overridepublic String toString(){return "Hello World";}
}
public class Test5 {public static void main(String[]args) throws Exception {Class<?>cls=Class.forName("Project.Study.Reflect.Book");//设置要操作对象的类名称//反射实例化后的对象返回的结果都是Object类型Object object=cls.newInstance(); //相当于使用new调用无参结构Book book=(Book)object; //向下转型System.out.println(book);}
}
//结果:
//该类的无参方法
//Hello World
上程序中的newInstance()方法返回的类型为Object,如果有需要则可以利用对象的向下转型操作将其强制变为子类实例进行操作。
可能会有人问使用newInstance()方法进行对象的实例化有什么好处,直接用new它不香吗?
其实因为关键字new实例化对象需要明确地指定类的构造方法,故new是造成耦合的最大元凶,所以使用newInstance()方法实例化对象可以实现更好的解耦合操作。
使用反射调用构造
使用Class类中的newInstance()方法虽然可以实现反射实例化对象操作,但是这样的操作本身有一个限制,就是操作对象的类中必须提供无参的构造方法。
例:错误示例
package Project.Study.Reflect;class Book2{private String title;private double price;public Book2(String title,double price){this.price=price;this.title=title;}@Overridepublic String toString(){return "图书名称:"+this.title+",价格:"+this.price;}
}
public class Test6 {public static void main(String[]args) throws Exception {Class<?>cls=Class.forName("Project.Study.Reflect.Book2");Object object=cls.newInstance();System.out.println(object);}
}
//结果:
//Exception in thread "main" java.lang.InstantiationException: Project.Study.Reflect.Book2
// at java.base/java.lang.Class.newInstance(Class.java:585)
// at Project.Study.Reflect.Test6.main(Test6.java:18)
//Caused by: java.lang.NoSuchMethodException: Project.Study.Reflect.Book2.<init>()
// at java.base/java.lang.Class.getConstructor0(Class.java:3350)
// at java.base/java.lang.Class.newInstance(Class.java:572)
// ... 1 more
所以,当类中没有提供无参构造方法的时候,就必须通过java.lang.reflect.Constructor类来实现对象的反射实例化操作。(java.lang.reflect是所有反射操作类的程序包)
取得类中的构造方法
No. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public Constructor<?>[] getConstructors() throws SecurityException | 普通 | 取得全部的构造方法 |
2 | public Constructor< T >[] getConstructors(Class<?>…parameterTypes) throws NoSuchMethodException, SecurityException | 普通 | 取得指定参数类型的构造方法 |
Constructor类的常用操作方法
No. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public Class<?>[] getExceptionTypes() | 普通 | 返回构造方法上所有抛出异常的类型 |
2 | public int getModifiers() | 普通 | 取得构造方法的修饰符 |
3 | public String getName() | 普通 | 取得构造方法的名字 |
4 | public int getParameterCount() | 普通 | 取得构造方法中的参数个数 |
5 | public Class <?>[] getParameterTypes() | 普通 | 取得构造方法中的参数类型 |
6 | public T newInstance(Object…initargs) throws InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException | 普通 | 调用指定参数的构造实例化对象 |
注意:因为修饰符是用数字描述的,所有的修饰符都是一个数字,所以取得修饰符的方法返回的是int类型。
例:明确调用类中的有参构造
package Project.Study.Reflect;import java.lang.reflect.Constructor;class Book3{private String title;private double price;public Book3(String title,double price){this.title=title;this.price=price;}@Overridepublic String toString(){return "图书名称:"+this.title+",价格:"+this.price;}
}
public class Test6 {public static void main(String[]args)throws Exception{Class<?>cls=Class.forName("Project.Study.Reflect.Book3");//明确地找到Book3类中两个参数的构造,第一个参数类型是String,第二个是doubleConstructor<?>constructor=cls.getConstructor(String.class,double.class);Object object=constructor.newInstance("Java",79.9); //实例化对象System.out.println(object);}
}//结果:
//图书名称:Java,价格:79.9
上程序的思路:
1.首先利用Class类对象取得此构造方法(返回Constructor类对象);
2.然后利用Constructor类中的newInstance()方法传递指定的数据,就可以调用有参构造进行对象的反射实例化。
反射调用方法
Class类取得普通方法的操作
No. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public Method[] getMethods() throws SecurityException | 普通 | 取得类中的全部方法 |
2 | public Method[] getMethod(String name,Class<?>…parameterTypes) throws NoSuchMethodException,SecurityException | 普通 | 取得类中指定方法名称与参数类型的方法 |
注:反射操作中,每一个方法都通过java.lang.reflect.Method类表示。
Method类的常用方法
No. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public int getModifiers() | 普通 | 取得方法的修饰符 |
2 | public Class<?> getReturnType() | 普通 | 取得方法的返回值类型 |
3 | public int getParameterCount() | 普通 | 取得方法中定义的参数数量 |
4 | public Class<?> getParameterTypes() | 普通 | 取得方法中定义的所有参数类型 |
5 | public Object invoke(Object obj,Object…args) throws IllegalAccessException,IllegalArgumentException,InvocationTargetException | 普通 | 反射调用方法并且传递执行方法所需要的参数数据 |
6 | public Class<?> getExceptionTypes() | 普通 | 取得方法抛出的异常类型 |
例:使用反射操作简单Java类的属性
package Project.Study.Reflect;import java.lang.reflect.Method;class Book4{private String title;public void setTitle(String title){this.title=title;}public String getTitle() {return title;}
}
public class Test7 {public static void main(String[]args)throws Exception{String fieldName="Title";Class<?>cls=Class.forName("Project.Study.Reflect.Book4");Object object=cls.newInstance();//取得类中的setTitle()方法Method setMet=cls.getMethod("set"+fieldName,String.class);//取得类中的getTitle()方法,本方法不接收参数并且没有返回值类型说明Method getMet=cls.getMethod("get"+fieldName);setMet.invoke(object,"Java书"); //等价于Book4类对象.setTitle("Java书");System.out.println(getMet.invoke(object)); //等价于Book4类对象.getTitle();}
}
//结果:
//Java书
反射调用成员
Class类中取得成员的操作
No. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public Field[] getDeclaredFields() throws SecurityException | 普通 | 取得本类定义的全部成员 |
2 | public Field[] getDeclaredFields(String name) throws NoSuchFieldException,SecurityException | 普通 | 取得本类指定名称的成员 |
3 | public Field[] getFields() throws SecurityException | 普通 | 取得本类继承父类的全部成员 |
4 | public Field[] getField(String name) throws NoSuchFieldException,SecurityException | 普通 | 取得本类继承父类中指定名称的成员 |
Field类的常用方法
No. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public Class<?> getType() | 普通 | 取得改成员的类型 |
2 | public Object get(Object obj) throws IllegalAccessException,IllegalArgumentException | 普通 | 取得指定对象中的成员的内容,相当于直接调用成员 |
3 | public void set(Object obj,Object value) throws IllegalAccessException,IllegalArgumentException | 普通 | 设置指定对象中的成员内容,相当于直接利用对象调用成员设置内容 |
注意:不管使用反射调用的是普通方法还是调用类中的成员,都必须存在实例化对象(可以依靠反射取得实例化对象),因为类中的属性必须在类产生实例化对象后才可以使用。
例:利用反射直接操作私有成员
package Project.Study.Reflect;import java.lang.reflect.Field;class Book5{private String title;
}
public class Test8 {public static void main(String[]args)throws Exception{Class<?>cls=Class.forName("Project.Study.Reflect.Book5"); //取得反射对象Object object=cls.newInstance(); //必须给出实例化对象Field titleField=cls.getDeclaredField("title"); //取得类中的title属性titleField.setAccessible(true); //取消封装,使title属性可以被外界访问titleField.set(object,"Java书"); //相当于:Book5类对象.title="数据"System.out.println(titleField.get(object)); //相当于:Book5类对象.title}
}
//结果:
//Java书
Java学习总结:39(反射机制)相关推荐
- Java学习-类的隐藏机制(封装性)
Java学习-类的隐藏机制(封装性) 1.封装的含义 2.类的setXXX 和 getXXX 3.this关键字 4.总结 1.封装的含义 封装(encapsulation)是面向对象的三要素之一(其 ...
- java学习笔记13--反射机制与动态代理
本文地址:http://www.cnblogs.com/archimedes/p/java-study-note13.html,转载请注明源地址. Java的反射机制 在Java运行时环境中,对于任意 ...
- Flex前端与Java服务端交互,反射机制挑大旗
Flex作为RIA的一支,提供了非常丰富多彩的客户端实现,并且编写起来非常灵活.Java提供了强大的功能实现,与Flex结合也让Java开发穿上了华丽外衣 . BlazeDS 是LCDS的一个衍生版 ...
- java 求正割_Java 反射机制详解
动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化.比如众所周知的ECMAScript(JavaScript)便是一个动态语言.除此之外如Ru ...
- Java基础篇:反射机制详解
反射机制 反射机制.反射含义 1.利用反射获取类对象的三种方法 2.利用反射获取类对象的类名.方法.属性 3.利用反射获取类对象中的构造器.构造器参数类型.实例化构造器 实例化重点 类的加载方式不同 ...
- JAVA学习日记(18)——反射和枚举
1.反射 1.1 定义 Java的反射(reflection)机制是在运行状态下,对于任何一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意属性和方法,既然能够拿到那么我们 ...
- JAVA基础,注解反射机制
文章目录 注解 (非常重要) 什么是注解 基本注解 @Override @Deprecated @SuppressWarnings @SafeVarargs @FunctionalInterface ...
- JAVA语言中的反射机制
在Java 运行时 环境中,对于任意一个类,能否知道这个类有哪些属性和方法? 对于任意一个对象,能否调用他的方法?这些答案是肯定的,这种动态获取类的信息,以及动态调用类的方法的功能来源于JAV ...
- Java高级语法笔记-反射机制(Reflection) (1)
反射机制:在C/C++里面是没有的. 反射机制是Java的一个非常重要的机制.一些著名的应用框架都使用了此机制. java.lang.Class它是Java语法的一个基础类,用于描述一个class对象 ...
最新文章
- 005_Java操作ZooKeeper
- ecshop后台增加栏目查询会员是否重复注册
- 微信小程序页面间的对象传递
- 原生js、jQuery实现选项卡功能
- Java9个异常处理的最佳实践
- django,cbv,模板层
- 华为P50系列相机全球首发新技术:告别偏色做到真实原色捕捉
- RK3399pro Linux Rock-X AI组件库支持
- mysql语句错误怎么查找_SQL语法错误但是怎么也找不出来,求指导
- 腾讯之困,QQ与微信各有各的烦恼
- 防止ADSL被***的一些技巧
- 旅游管理系统——你凭什么不被吐槽?
- 2017VS2018年非工作日日期大集合
- 如何下载海淀区卫星地图高清版大图
- JAVA数据库增删改查
- python执行bat文件_让Python文件也可以当bat文件运行
- 微信公众号运营辅助工具汇总
- GitHub iOS开源项目
- gcc简介和命令行参数说明
- 纯CSS实现超美选项卡