思考:在讲反射之前,先思考一个问题,java中如何创建一个对象,有哪几种方式?
java中创建对象大概有这几种方式:
1、使用new关键字:这是我们最常见的也是最简单的创建对象的方式2、使用clone的方法:无论何时我们调用一个对象的clone方法,jvm就会创建一个新的对象,将前面的对象的内容全部拷贝进去3、使用反序列化:当我们序列化和反序列化一个对象,jvm会给我们创建一个单独的对象上边是java中常见的创建对象的三种方式,其实除了上边的三种还有另外一种方式,就是接下来我们要讨论的“反射”
反射就是把java类中的各个部分,映射成一个个的java对象,拿到这些对象后可以做一些事情。
既然说反射是反射java类中的各个组成部分,所以说咱们得知道一个类中有哪儿些部分?
例如,一个类有:成员变量,方法,构造方法,等信息,利用反射技术咱们可以把这些组成部分映射成一个个对象。
说完反射的概念后,咱们说一下反射能干什么?
一般来说反射是用来做框架的,或者说可以做一些抽象度比较高的底层代码,反射在日常的开发中用到的不多,但是咱们还必须搞懂它,因为搞懂了反射以后,可以帮助咱们理解框架的一些原理。所以说有一句很经典的话:反射是框架设计的灵魂。现在说完这个可能还不太能理解,不急,等下说完一个快速入门的例子后,应该会稍微有点感觉
1.3、怎么得到想反射的类
刚才已经说过,反射是对一个类进行解剖,想解剖一个东西,前提是首先你得拿到这个东西,那么怎么得到咱们想解剖的类呢?
首先大家要明白一点,咱们写的代码是存储在后缀名是 .java的文件里的,但是它会被编译,最终真正去执行的是编译后的 .class文件。java是面向对象的语言,一切皆对象,所以java认为 这些编译后的 class文件,这种事物也是一种对象,它也给抽象成了一种类,这个类就是class,大家可以去aip里看一下这个类
所以拿到这个类后,就相当于拿到了咱们想解剖的类,那怎么拿到这个类?
看api文档后,有一个方法forname(string classname); 而且是一个静态的方法,这样咱们就可以得到想反射的类了
到这里,看class clazz = class.forname("com.cj.test.person");
这个应该有点感觉了吧
class.forname("com.cj.test.person");
因为这个方法里接收的是个字符串,字符串的话,我们就可以写在配置文件里,然后利用反射生成我们需要的对象,这才是我们想要的。很多框架里都有类似的配置
我们知道一个类里一般有构造函数、方法、成员变量(字段/属性)这三部分组成
翻阅api文档,可以看到
class对象提供了如下常用方法:
public constructor getconstructor(class<?>…parametertypes)public method getmethod(string name,class<?>… parametertypes)public field getfield(string name)public constructor getdeclaredconstructor(class<?>…parametertypes)public method getdeclaredmethod(string name,class<?>… parametertypes)public field getdeclaredfield(string name)这些方法分别用于帮咱们从类中解剖出构造函数、方法和成员变量(属性)。
然后把解剖出来的部分,分别用constructor、method、field对象表示。
可以看到 默认的无参构造方法执行了
从上边的例子看出,要想反射,首先第一步就是得到类的字节码
所以简单说一下得到类的字节码的几种方式
(1)、class.forname(“com.cj.test.person”); 这就是上边我们用的方式(2)、对象.getclass();(3)、类名.class;注意:在反射私有的构造函数时,用普通的clazz.getconstructor()会报错,因为它是私有的,所以提供了专门反射私有构造函数的方法clazz.getdeclaredconstructor(int.class);//读取私有的构造函数
,用这个方法读取完还需要设置一下暴力反射才可以
c.taccessible(true);//暴力反射
package com.cj.test; import java.util.date; public class person {public person(){system.out.println("默认的无参构造方法执行了");} public person(string name){system.out.println("姓名:"+name);}public person(string name,int age){system.out.println(name+"="+age);}private person(int age){system.out.println("年龄:"+age);}public void m1() {system.out.println("m1");}public void m2(string name) {system.out.println(name);}public string m3(string name,int age) {system.out.println(name+":"+age);return "aaa";}private void m4(date d) {system.out.println(d);}public static void m5() {system.out.println("m5");}public static void m6(string[] strs) {system.out.println(strs.length);} public static void main(string[] args) {system.out.println("i形容词性物主代词main");} }
package com.cj.test; import java.lang.reflect.method;import java.util.date;import org.junit.test; public class demo2 { @test//public void m1()public void test1() throws exception{class clazz = class.forname("com.cj.test.person");person p = (person)clazz.newinstance();method m = clazz.getmethod("m1", null);m.invoke(p, null);}@test//public void m2(string name)public void test2() throws exception{class clazz = person.class;person p = (person) clazz.newinstance();method m = clazz.getmethod("m2", string.class);m.invoke(p, "张三");}@test//public string m3(string name,int age)public void test3() throws exception{class clazz = person.class;person p = (person) clazz.newinstance();method m = clazz.getmethod("m3", string.class,int.class);string returnvalue = (string)m.invoke(p, "张三",23);system.out.println(returnvalue);}@test//private void m4(date d)public void test4() throws exception{class clazz = person.class;person p = (person) clazz.newinstance();method m = clazz.getdeclaredmethod("m4", date.class);m.taccessible(true);m.invoke(p,new date());}@test//public static void m5()public void test5() throws exception{class clazz = person.class;method m = clazz.getmethod("m5", null);m.invoke(null,null);}@test//private static void m6(string[] strs)public void test6() throws exception{class clazz = person.class;method m = clazz.getdeclaredmethod("m6",string[].class);m.taccessible(true);m.invoke(null,(object)new string[]{"a","b"});}@testpublic void test7() throws exception{class clazz = person.class;method m = clazz.getmethod("main",string[].class);m.invoke(null,new object[]{new string[]{"a","b"}});}}
*****注意:看下上边代码里test6和test7的invoke方法里传的参数和其他的有点不一样
这是因为 jdk1.4和jdk1.5处理invoke方法有区别
1.5:public object invoke(object obj,object…args)
1.4:public object invoke(object obj,object[] args)
由于jdk1.4和1.5对invoke方法的处理有区别, 所以在反射类似于main(string[] args) 这种参数是数组的方法时需要特殊处理
启动java程序的main方法的参数是一个字符串数组,即public static void main(string[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理
,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mainmethod.invoke(null,new string[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不一致连续性把它当作jdk1.5的语法解释,因此会出现参数个数不对的问题。
上述问题的解决方法:
(1)mainmethod.invoke(null,new object[]{new string[]{“xxx”}});这种方式,由于你传的是一个数组的参数,所以为了向下兼容1.4的语法,javac遇到数组会给你拆开成多个参数,但是由于咱们这个object[ ] 数组里只有一个元素值,所以就算它拆也没关系
(2)mainmethod.invoke(null,(object)new string[]{“xxx”});这种方式相当于你传的参数是一个对象,而不是数组,所以就算是按照1.4的语法它也公路行业不会拆,所以问题搞定
编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了
对上边的描述进行一下总结:在反射方法时,如果方法的参数是一个数组,考虑到向下兼容问题,会按照jdk1.4的语法来对待(jvm会把传递的数组参数拆开,拆开就会报参数的个数不匹配的错误)
解决办法:防止jvm拆开你的数组
方式一:把数组看做是一个object对象方式二:重新构建一个object数组,那个参数数组作为唯一的元素存在。package com.cj.test; import java.util.date; public class person {public string name="李四";private int age = 18;public static date time;public int getage() {return age;}public person(){system.out.println("默认的无参构造方法执行了");} public person(string name){system.out.println("姓名:"+name);}public person(string name,int age){system.out.println(name+"="+age);}private person(int age){system.out.println("年龄:"+age);}public void m1() {system.out.println("m1");}public void m2(s纠错本怎么写tring name) {system.out.println(name);}public string m3(string name,int age) {system.out.println(name+":"+age);return "aaa";}private void m4(date d) {system.out.println(d);}public static void m5() {system.out.println("m5");}public static void m6(string[] strs) {system.out.println(strs.l什么专业吃香ength);}public static void main(string[] args) {system.out.println("main");}}
package com.cj.test; import java.lang.reflect.field;import java.util.date;import org.junit.test; public class demo3 {//public string name="李四";@testpublic void test1() throws exception{class clazz = person.class;person p = (person)clazz.newinstance();field f = clazz.getfield("name");string s = (string)f.get(p);system.out.println(s);//更改name的值f.t(p, "王六");system.out.println(p.name);}@test//private int age = 18;public void test2() throws exception{class clazz = person.class;person p = (person)clazz.newinstance();field f = clazz.getdeclaredfield("age");f.taccessible(true);int age = (integer)f.get(p);system.out.println(age);f.t(p, 28);age = (integer)f.get(p);system.out.println(age);}@test//public static date time;public void test3() throws exception{class clazz = person.class;field f = clazz.getfield("time");f.t(null, new date());system.out.println(person.time);}}
以上就是自己对java中反射的一些学习总结,欢迎大家留言一起学习、讨论
看完上边有关反射的东西, 对常用框架里的配置文件是不是有点思路了
上边是spring配置文件里的常见的bean配置,这看起来是不是可以用反射很轻易的就可以实现:解析xml然后把xml里的内容作为参数,利用反射创建对象。
以上所述是www.887551.com给大家介绍的java基础篇之反射机制详解,希望对大家有所帮助。在此也非常感谢大家对www.887551.com网站的支持!
本文发布于:2023-04-04 09:56:51,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/7bb945716bf8c0ac4407cd6a85d9ece6.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:Java基础篇之反射机制详解.doc
本文 PDF 下载地址:Java基础篇之反射机制详解.pdf
留言与评论(共有 0 条评论) |