在学习反射之前,我先回忆了一下可变参数。
public static void main(string[] args) { test();//调用方法1test(java);//调用方法2test(java,工程师);//调用方法3test(new string[]{水果,电器});//调用方法4 } static void test(string ... array){ //直接打印:system.out.println(array);for(string str:array){ //利用增强for遍历 system.out.println(str); } }
之所以回忆可变参数呢,是因为它与反射的应用有点像。如果将一个方法定义为可变参数,在调用的时候传参的限制就少了一大截。在反射当中呢,我们利用一些方法,得到类的实例对象,那么类里面的方法、属性等,就尽收眼底。在前面的学习中知道了,方法、属性等都有静态的和非静态的,私有的和非私有的之分,那么我们在调用的时候,想取哪一块,或者说只想取得哪一块,是不是也可以想个办法实现呢?这时候,反射就出现了,现今我对它的理解就只有这些了。继续努力吧。
一、反射的概念
java反射机制是在运行状态中(注意不是编译的时候),对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
java反射机制主要提供了以下功能:
-- 在运行时判断任意一个对象所属的类;
-- 在运行时构造任意一个类的对象;
-- 在运行时判断任意一个类所具有的成员变量和方法;
-- 在运行时调用任意一个对象的方法;
-- 生成动态代理。
jdk中,与反射相关的类,主要有以下几个
//java.lang包下
class 类
class 类的实例表示正在运行的 java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 class 对象。基本的 java 类型(boolean、byte、char、short、int、long、float 和 double) 和关键字 void 也表示为 class 对象。
关于class类jdk里面的解释:
public finalclass class<t> implements java.io.serializable, java.lang.reflect.genericdeclaration, java.lang.reflect.type, java.lang.reflect.annotatedelement {private static final int annotation= 0x00002000;private static final int enum = 0x00004000;private static final int synthetic = 0x00001000;private static native void registernatives();static { registernatives(); }/* * constructor. only the java virtual machine creates class * objects. */private class() {}
class类jdk里的一些方法(个人觉得读起来很舒服,自己想记录一下)
public string tostring() {return (isinterface() ? interface : (isprimitive() ? : class ))+ getname(); }//应该是三元表达式
public static class<?> forname(string classname)throws classnotfoundexception { class<?> caller = reflection.getcallerclass();return forname0(classname, true, classloader.getclassloader(caller), caller); }
public static class<?> forname(string name, boolean initialize, classloader loader)throws classnotfoundexception { class<?> caller = null; securitymanager sm = system.getsecuritymanager();if (sm != null) {// reflective call to get caller class is only needed if a security manager// is present. avoid the overhead of making this call otherwise.caller = reflection.getcallerclass();if (loader == null) { classloader ccl = classloader.getclassloader(caller);if (ccl != null) { sm.checkpermission( securityconstants.get_classloader_permission); } } }return forname0(name, initialize, loader, caller); }
private static native class<?> forname0(string name, boolean initialize, classloader loader, class<?> caller)throws classnotfoundexception;
public t newinstance()throws instantiationexception, illegalaccessexception {if (system.getsecuritymanager() != null) { checkmemberaccess(member.public, reflection.getcallerclass(), false); }// note: the following code may not be strictly correct under// the current java memory model.// constructor lookupif (cachedconstructor == null) {if (this == class.class) {throw new illegalaccessexception(can not call newinstance() on the class for java.lang.class); }try { class<?>[] empty = {};final constructor<t> c = getconstructor0(empty, member.declared);// disable accessibility checks on the constructor// since we have to do the security check here anyway// (the stack depth is wrong for the constructor's// security check to work) java.security.accesscontroller.doprivileged(new java.security.privilegedaction<void>() {public void run() { c.setaccessible(true);return null; } }); cachedconstructor = c; } catch (nosuchmethodexception e) {throw new instantiationexception(getname()); } } constructor<t> tmpconstructor = cachedconstructor;// security check (same as in java.lang.reflect.constructor)int modifiers = tmpconstructor.getmodifiers();if (!reflection.quickcheckmemberaccess(this, modifiers)) { class<?> caller = reflection.getcallerclass();if (newinstancecallercache != caller) { reflection.ensurememberaccess(caller, this, null, modifiers); newinstancecallercache = caller; } }// run constructortry {return tmpconstructor.newinstance((object[])null); } catch (invocationtargetexception e) { unsafe.getunsafe().throwexception(e.gettargetexception());// not reachedreturn null; } }
public string getname() { string name = this.name;if (name == null)this.name = name = getname0();return name; }
// cache the name to reduce the number of calls into the vmprivate transient string name;private native string getname0();
还有很多,暂不记录了。。。。。
//java.lang.reflect 包下 constructor 代表构造函数 method 代表方法 field 代表字段 array 与数组相关
二、class类的说明
常用的得到class类的方法 // class c=new class(); 不可以,因为它被私有化了1) class c=student.class; //用类名.class 就可以得到class类的实例2) student stu=new student(); class c=stu.getclass(); //用对象名.getclass();3) class c=class.forname(com.mysql.jdbc.driver);
//例一 通过调用无参的构造函数,创建类对象public class test {public static void main(string[] args) throws instantiationexception, illegalaccessexception { class clazz=dog.class; dog dog=(dog)clazz.newinstance(); dog.shout(); } } class dog{void shout(){ system.out.println(汪汪); } }
通过例一,我并没有看出来利用反射的好处,呃~~
//例二 上例的改写class clazz=class.forname(com.weiboo.dog); //注意,必须是类的全部dog dog=(dog)clazz.newinstance(); dog.shout();
//例三 (运行本类,dog 和 cat 类,必须有一个无参的构造函数)public class test {public static void main(string[] args) throws instantiationexception, illegalaccessexception, classnotfoundexception { dog dog=(dog)createobj(dog.class); dog.shout(); cat cat=(cat)createobj(cat.class); cat.speak(); } static object createobj(class clazz) throws instantiationexception, illegalaccessexception{return clazz.newinstance(); //调用的是newinstance() 方法创建的类对象,它调用的是类中无参的构造方法} } class dog{void shout(){ system.out.println(汪汪); } } class cat{void speak(){ system.out.println(喵~~~); } }
三、反射中的其他的类的说明
1) constructor
代表类中的构造函数 class 类提供了以下四个方法
public constructor<?>[] getconstructors() //返回类中所有的public构造器集合,默认构造器的下标为0
public constructor<t> getconstructor(class<?>... parametertypes) //返回指定public构造器,参数为构造器参数类型集合
public constructor<?>[] getdeclaredconstructors() //返回类中所有的构造器,包括私有的
public constructor<t> getdeclaredconstructor(class<?>... parametertypes) //返回任意指定的构造器,包括私有的
import java.lang.reflect.constructor;import java.lang.reflect.invocationtargetexception;//例子 得到某个类中指定的某个构造函数所对应的 constructor对象class test2 {public static void main(string[] args) throws instantiationexception, illegalaccessexception, classnotfoundexception, nosuchmethodexception, securityexception, illegalargumentexception, invocationtargetexception { class<cat> clazz = cat.class; constructor<cat> c = clazz.getconstructor(int.class, string.class); cat cat = (cat) c.newinstance(20, 加飞猫); cat.speak(); }class cat {private string name;private int age;public cat(int age, string name) {this.age = age;this.name = name; }public cat(string content) { system.out.println(这是构造函数得到的参数 + content); }void speak() { system.out.println(喵~~~); system.out.println(我的名字是 + this.name + 我的年龄是 + this.age); } } }
/例子 访问类中的私有构造函数 class clazz=cat.class; constructor c=clazz.getdeclaredconstructor(); c.setaccessible(true); //让私有成员可以对外访问cat cat=(cat) c.newinstance(); //对于私有的来说,能不能行?cat.speak();
2) method 代表类中的方法
class 类提供了以下四个方法
public method[] getmethods() //获取所有的共有方法的集合,包扩继承的
public method getmethod(string name,class<?>... parametertypes) // 获取指定公有方法 参数1:方法名 参数2:参数类型集合
public method[] getdeclaredmethods() //获取所有的方法(包扩私有的),除了继承来的
public method getdeclaredmethod(string name,class<?>... parametertypes) //获取任意指定方法,除来了继承来的
//调用类中的私有方法main 函数 class clazz=cat.class;//调用一个不带参数的方法method m=clazz.getdeclaredmethod(speak); m.setaccessible(true); cat c=new cat(); m.invoke(c); //让方法执行 //调用一个带参数的方法method m=clazz.getdeclaredmethod(eat, int.class,string.class); m.setaccessible(true); cat c=new cat(); m.invoke(c, 20,鱼); class cat{private string name;private int age; cat(){ }public cat(int age,string name){this.age=age;this. name=name; } public cat(string content){ system.out.println(这是构造函数得到的参数+content); } private void speak(){ system.out.println(喵~~~); system.out.println(我的名字是+this.name+我的年龄是+this.age); } private void eat(int time,string something){ system.out.println(我在+time +分钟内吃了一个+something); } }
例子 查看一个类中的所有的方法名public static void main(string[] args) throws instantiationexception, illegalaccessexception, classnotfoundexception, nosuchmethodexception, securityexception, illegalargumentexception, invocationtargetexception { class clazz=cat.class; /*method [] methodlist=clazz.getmethods() ; //查看所有的公有方法,包扩继承的 for(method m:methodlist){ system.out.println(m.getname()); }*/method [] methodlist=clazz.getdeclaredmethods(); //查看所有的方法,包扩私有的,但不包扩继承的for(method m:methodlist){ system.out.println(m.getname()); } }
3) field 代表字段
public field getdeclaredfield(string name) // 获取任意指定名字的成员
public field[] getdeclaredfields() // 获取所有的成员变量,除了继承来的
public field getfield(string name) // 获取任意public成员变量,包含继承来的
public field[] getfields() // 获取所有的public成员变量
//例子 访问字段public class test {public static void main(string[] args) throws exception { class clazz=cat.class; /* field field= clazz.getfield(home); cat c=new cat(); object obj=field.get(c); system.out.println(obj); // 家*/ cat cat=new cat(); field [] fieldlist= clazz.getdeclaredfields();for(field f:fieldlist){ //访问所有字段f.setaccessible(true); system.out.println(f.get(cat)); } } } class cat{private string name=黑猫;private int age=2;public string home=家; }
四、反射的应用
用一个例子来说明一下,比较两个同类对象中的所有字段,不同的并把它输出来。
import java.lang.reflect.field;import java.util.hashmap;import java.util.map;public class test {public static void main(string[] args) throws exception { student stu1 = new student(24, 李磊, 工程大学, 女); student stu2 = new student(20, 王一, 师大, 男); map<string, string> map = compare(stu1, stu2);for (map.entry<string, string> item : map.entryset()) { system.out.println(item.getkey() + : + item.getvalue()); } }static map<string, string> compare(student stu1, student stu2) { map<string, string> resultmap = new hashmap<string, string>(); field[] fieldlis = stu1.getclass().getdeclaredfields(); // 得到stu1所有的字段对象try {for (field f : fieldlis) { f.setaccessible(true); // 别忘了,让私有成员可以对外访问object v1 = f.get(stu1); object v2 = f.get(stu2);if (!(v1.equals(v2))) { resultmap.put(f.getname(), stu1的值是 + v1 + stu2的值是 + v2); } } } catch (exception ex) { ex.printstacktrace(); }return resultmap; } }class student {private string name;private string school;private string sex;public student(int age, string name, string school, string sex) {this.age = age;this.name = name;this.school = school;this.sex = sex; }private int age;public int getage() {return age; }public void setage(int age) {this.age = age; }public string getname() {return name; }public void setname(string name) {this.name = name; }public string getschool() {return school; }public void setschool(string school) {this.school = school; }public string getsex() {return sex; }public void setsex(string sex) {this.sex = sex; } }
以上就是java基础入门之反射的详细内容。
