Java中的反射机制基本运用详解
目录
- Java中的反射机制基本运用
- 1、什么是反射(reflect)
- 2、反射机制提供的功能
- 3、反射->获取类对象
- 4、反射->利用无参构造实例化对象
- 5、反射->利用有参构造实例化对象
- 6、反射->调用无参方法
- 7、反射->调用有参方法
- 8、反射->访问私有方法
- 9、反射->类加载路径
- 总结
Java中的反射机制基本运用 看完反射可以了解一下注解
注解annotation://www.jb51.net/article/221276.htm
1、什么是反射(reflect) 反射是java的动态机制,它允许将对象的实例化,方案的调用,属性的操作等从编码期确定转移到程序运行期确定。
反射能大大提高代码的灵活度。但同时也带来了更多的系统开销和较慢的运行效率,因此程序不能过度依赖反射。
2、反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象(实例化)
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法——动态代理
3、反射->获取类对象 在开始之前创建一个实体类,用于测试反射机制
package reflect_text; /** * 用于测试反射机制 * * @author Akio * @Create 2021/8/14 10:37 */public class Person {private String name = "刘瑜澄"; //设置初始值private int age = 22; public Person() {//无参构造}public Person(String name, int age) {//有参构造this.name = name; this.age = age; }public void sayHello() {//无参方法System.out.println(name + ":使用sayHello方法"); }public void sayGoodBye() {//无参方法System.out.println(name + ":使用sayGoodBye方法"); }public void say(String info) {//有参方法System.out.println(name + ":" + info); }public void say(String info, int sum) {//有参方法(重载say方法)for (int i = 0; i < sum; i++) {System.out.println(name + ":" + info); }}private void privateMethod() {//私有方法System.out.println(name + ":这是一个私有方法"); }@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}'; }}
以上这个用于测试反射的实体类创建成功后,先学习反射中是如何获取类对象的。
反射的第一步就是要获取操作类的类对象,即一个Class的实例,JVM中每个被加载的类有且只有一个类对象与之对应,获取到这个类对象后我们就可以通过这个类对象来了解该类的一切信息(类名、有哪些方法、属性等等) 以便在程序运行期间通过反射机制进行相关操作
这里介绍三种获取类对象的方式:
(包名.)类名.class
Class personClass = reflect_text.Person.class; Class intClass = int.class;
这种方式最直接,但是由于是靠硬编码形式写死(编译期间已经确定),因此不够灵活。但是需要注意,基本类型(int\double等)只能通过这种方式获取类对象
Class.forName(String className)
Class personClass = Class.forName("reflect_text.Person"); Class stringClass = Class.forName("java.lang.String");
这种方式较为常用,遵循运行期绑定。
类加载器ClassLoader
Class stringClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.String"); Class personClass = ClassLoader.getSystemClassLoader().loadClass("reflect_text.Person");
在这一节中介绍几个简单的方法:
getName()获取类的完全限定名:包名.类名getSimpleName()仅仅获取类名getMethods()返回一个Method数组,获取class所表示的类的所有公开方法(包含从超类中继承的方法)
例子:
Scanner scanner = new Scanner(System.in); Class cls = Class.forName(scanner.nextLine()); //运行期绑定String name = cls.getName(); //获取类的完全限定名:包名.类名System.out.println("完全限定名 = " + name); name = cls.getSimpleName(); //仅获取类名System.out.println("仅类名 = " + name); Method[] methods = cls.getMethods(); for (Method m : methods) {System.out.print(m.getName()+"\t"); }
4、反射->利用无参构造实例化对象 Class类中提供了一个方法newInstance()来实例化,该方法要求此类必须具有无参构造器,它是通过无参构造器实例化对象的。
Person person = new Person(); //1获取要实例化的类的类对象Scanner scanner = new Scanner(System.in); System.out.println("请输入类名:"); Class cls = Class.forName(scanner.nextLine()); /*通过Class提供的方法newInstance()来实例化该方法要求此类必须具有无参构造器,它是通过无参构造器实例化对象的*/Object obj = cls.newInstance(); System.out.println("obj = " + obj);
文章图片
5、反射->利用有参构造实例化对象
getConstructor()//获取无参构造器,可以利用无参构造器实例化对象,但这个方法对于使用无参构造器实例化对象可有可无getConstructor(类对象)//通过类对象获取特定的构造器,该参数列表是根据特定构造器的参数列表类型来决定的,如getConstructor(String.class, int.class)即为调用Person类中两个参数的有参构造器public Person(String name, int age) {//有参构造this.name = name; this.age = age; }
举例
//加载类对象Class cls = Class.forName("reflect.Person"); //通过类对象获取特定的构造器Constructor c = cls.getConstructor(String.class, int.class); Object o = c.newInstance("流年", 21); //实例化System.out.println(o);
结果可知初始值已经被修改
文章图片
6、反射->调用无参方法
getMethod(String MethodName)获取类对象的MethodName方法,返回值类型为Methodinvoke(Object object)执行object对象的某方法
举例
//一般调用方法的做法-------------------Person p = new Person(); //实例化对象p.sayHello(); //调用该对象方法//反射机制调用方法-----------------------//1、实例化对象Class cls = Class.forName("reflect_text.Person"); Object o = cls.newInstance(); //2、调用o的sayHello方案//2.1通过Class获取Person的sayHello方法Method method = cls.getMethod("sayHello"); //2.2调用o的该方法method.invoke(o); //等效于一般方法中的o.sayHello()
可见两种操作均能达到一样的效果
文章图片
7、反射->调用有参方法
getMethod(String MethodName, 类对象)获取类对象的MethodName有参方法,并传入对应参数类型的类对象,返回值类型为Method
举例
//一般调用有参方法------------------------Person p = new Person(); p.say("七夕快乐~"); p.say("七夕快乐~",3); //反射机制调用有参方法---------------------Class cls = Class.forName("reflect_text.Person"); Object o = cls.newInstance(); //调用say(String info)方法Method m1 = cls.getMethod("say", String.class); m1.invoke(o, "春节快乐~"); //调用say(String info, int sum)Method m2 = cls.getMethod("say", String.class, int.class); m2.invoke(o,"春节快乐~",3);
通过结果可以看到,效果都是一样的
文章图片
8、反射->访问私有方法 注意:反射访问私有的方法,但是会破坏类的封装性
getDeclaredMethod(String MethodName)可以仅获取此类定义的所有方法,包含私有方法setAccessible(boolean flag)开启私有方法的访问权限
举例
//正常情况下,在本类中不可以访问外部的私有方法//但在反射机制中可行Class cls = Class.forName("reflect_text.Person"); Object o = cls.newInstance(); Method method = cls.getDeclaredMethod("privateMethod"); method.setAccessible(true); //打开访问权限method.invoke(o);
文章图片
9、反射->类加载路径 加载资源时常用相对路径,之前学习的相对路径./由于运行环境不同,位置并非固定,因此实际开发中使用较少。
接下来介绍,在开发中常用的类加载路径
常用的路径通常为类的加载路径,有两个:
1:
类对象.getResource()
与当前类所处同一目录2:
类加载器.getResource()
类加载路径,类的package定义中根包位置。例如:有一个类:package reflect_text; public class WebServer{……}在WebServer类中,当我们使用上述两种方式获取路径时他们的对应位置为:WebServer.class.getResource()当前WebServer所在的目录(编译后的class文件所在目录)WebServer.class.getClassLoader().getResource()则是在WebServer的包的最上级,即com包的上一级
package reflect_text; public class ReflectDemo {File dir = new File(ReflectDemo.class.getResource(".").toURI()); System.out.println("dir = " + dir); //dir = D:\ClassCode\JavaSE_API\out\production\JavaSE_API\reflectFile dir2 = new File(ReflectDemo.class.getClassLoader().getResource(".").toURI()); System.out.println("dir2 = " + dir2); //dir2 = D:\ClassCode\JavaSE_API\out\production\JavaSE_API}
文章图片
总结 【Java中的反射机制基本运用详解】本片文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- JS中的各种宽高度定义及其应用
- 我眼中的佛系经纪人
- 《魔法科高中的劣等生》第26卷(Invasion篇)发售
- Android中的AES加密-下
- 事件代理
- 放下心中的偶像包袱吧
- C语言字符函数中的isalnum()和iscntrl()你都知道吗
- Java|Java OpenCV图像处理之SIFT角点检测详解