目录
在运行状态中,对于任意一个类,都能够知道其所有属性和方法,对于任意一个对象,都能够调用其任意方法和属性,这种动态获取信息、动态调用方法的能力称为java语言的反射机制,大部分框架都有用到反射机制,了解反射的使用方法非常重要。
一个类通常包含了属性、方法、构造函数等,而java一般情况下是现有类再有对象,通过对象调用各种属性和方法,而java反射则是通过已有的对象,反过来得到其所属类的相关信息,调用所属类的相关方法。
我们知道在java的世界中,万事万物皆对象。其实类本身也是对象,任何一个类都是class类的实例对象。
//定义了一个superhero的类 public class superhero {}
如上面定义的superhero类,是类也是对象,
对象:superhero类是class类的实例,class类是superhero的类类型,故而为对象;
类:以类的方式创建,superhero本身可以调用superhero ironman = new superhero ()
被实例化,ironman 就是创建的实体,故而也是类。
class类很特殊,它表示了某个类的类类型,被不可被继承,每个类的class对象仅有一个,class类没有公共构造函数。 相反, class对象由java虚拟机自动构建,因为加载了类,并且通过调用类加载器中的defineclass
方法,原始java类型( boolean
, byte
, char
, short
, int
, long
, float
和double
),和关键字void
也表示为class对象
//class源码,final修饰不可被继承,构造函数是private的,不可手动实例化 public final class class<t> { private class(classloader loader) { // initialize final field for classloader. the initialization value of non-null // prevents future jit optimizations from assuming this final field is null. classloader = loader; } }
public static void main(string[] args) { try { class clazz1 = class.forname("java.lang.integer"); class clazz2 = class.forname("java.lang.integer"); system.out.println(clazz1 == clazz2); system.out.println(int.class); system.out.println(void.class); } catch (classnotfoundexception e) { e.printstacktrace(); } }
运行结果为:
true int void
先定义一个类
package reflectdemo; import java.io.serializable; /** * 超级英雄类 */ public class superhero implements serializable { public static final string address = "earth"; private string id; private string name; private integer age; private string skill; public superhero() { } public superhero(string id, string name, integer age, string skill) { this.id = id; this.name = name; this.age = age; this.skill = skill; } public string getid() { return id; } public void setid(string id) { this.id = id; } public string getname() { return name; } public void setname(string name) { this.name = name; } public integer getage() { return age; } public void setage(integer age) { this.age = age; } public string getskill() { return skill; } public void setskill(string skill) { this.skill = skill; } public void print(){ system.out.println("超级英雄:" + this.name); } }
public static void main(string[] args) { superhero ironman = new superhero("1","钢铁侠",35, "战甲"); class clazz = ironman.getclass(); system.out.println(clazz.getname()); }
输出结果:
reflectdemo.superhero
public static void main(string[] args) { class clazz = superhero.getclass(); system.out.println(clazz.getname()); }
输出结果:
reflectdemo.superhero
public static void main(string[] args) { try { class clazz = class.forname("reflectdemo.superhero"); system.out.println(clazz.getname()); } catch (classnotfoundexception e) { e.printstacktrace(); } }
输出结果:
reflectdemo.superhero
三种创建方式:
第一种方式对象已经有了,所有的操作直接通过该对象进行即可,
第二种方式需要import将类引入,也不是常用的方式,
第三种仅需传入类的路径,即可得到类的相关信息,是最常用的方式。
public static void main(string[] args) { try { class clazz = class.forname("reflectdemo.superhero"); //获取类名称(含路径) system.out.println(clazz.getname()); //获取类名称(不含路径) system.out.println(clazz.getsimplename()); //获取所在包 system.out.println(clazz.getpackage()); //通过class创建对象 superhero hero = (superhero)clazz.newinstance(); } catch (classnotfoundexception e) { e.printstacktrace(); } }
输出结果:
reflectdemo.superhero superhero package reflectdemo
这里提前说明一下:class中两个功能相同的方法,若其中一个带有declared字样,表示针对类中所有声明的变量、方法、构造函数等,而对应不带declared字样的方法,则表示仅对公有(public)成员变量、方法起作用,下面不再重复描述,下面仅对带有declared字样的方法进行讲解。
public class classutils { /** * 获取构造函数 * @param clazz 类 * @param params 构造函数参数类型 * @throws nosuchmethodexception */ public static void getdeclaredconstructor(class clazz, class[] params) throws nosuchmethodexception { system.out.println(clazz.getdeclaredconstructor(params)); } } public class classtest { public static void main(string[] args) { try { class clazz = class.forname("reflectdemo.superhero"); //打印无参构造函数 classutils.getdeclaredconstructor(clazz, null); //打印有参构造函数 classutils.getdeclaredconstructor(clazz, new class[]{string.class, string.class, integer.class, string.class}); } catch (exception e) { e.printstacktrace(); } } }
输出结果为:
public reflectdemo.superhero() public reflectdemo.superhero(java.lang.string,java.lang.string,java.lang.integer,java.lang.string)
public class classutils { /** * 遍历构造函数 * @param clazz 类 */ public static void getdeclaredconstructors(class clazz){ //获取所有的构造函数 constructor[] constructors = clazz.getdeclaredconstructors(); for (constructor constructor : constructors) { //直接打印构造函数 system.out.println(constructor); //打印构造函数名称 system.out.println(constructor.getname()); //打印构造函数参数 parameter[] parameters = constructor.getparameters(); for(parameter parameter : parameters){ system.out.print(parameter); system.out.print(", "); } system.out.println("---------------------"); } } } public class classtest { public static void main(string[] args) { try { class clazz = class.forname("reflectdemo.superhero"); //遍历构造函数 classutils.getdeclaredconstructors(clazz); } catch (exception e) { e.printstacktrace(); } } }
输出结果为:
public reflectdemo.superhero() reflectdemo.superhero --------------------- public reflectdemo.superhero(java.lang.string,java.lang.string,java.lang.integer,java.lang.string) reflectdemo.superhero java.lang.string arg0, java.lang.string arg1, java.lang.integer arg2, java.lang.string arg3, ---------------------
public class classutils { /** * 获取属性字段 * @param clazz 类 * @param fieldname 属性名称 * @throws exception */ public static void getdeclaredfield(class clazz, string fieldname) throws exception{ system.out.println(clazz.getdeclaredfield(fieldname)); } } public class classtest { public static void main(string[] args) { try { class clazz = class.forname("reflectdemo.superhero"); //测试公有属性 classutils.getdeclaredfield(clazz, "address"); //测试私有属性 classutils.getdeclaredfield(clazz, "name"); } catch (exception e) { e.printstacktrace(); } } }
输出结果为:
public static final java.lang.string reflectdemo.superhero.address private java.lang.string reflectdemo.superhero.name
public class classutils { /** * 遍历clazz对象已有的成员变量 * @param clazz */ public static void getdeclaredfields(class clazz){ field[] fields = clazz.getdeclaredfields(); for (field field: fields) { //如果要设置值,需要加入下面这句,反射对象在使用时不使用java语言访问检查 //field.setaccessible(true); //直接打印field system.out.println(field); //手动获取变量类型和变量名称 system.out.println(field.gettype().getname() + " " +field.getname()); system.out.println("--------------------"); } } } public class classtest { public static void main(string[] args) { try { class clazz = class.forname("reflectdemo.superhero"); //遍历成员变量 classutils.getdeclaredfields(clazz); } catch (exception e) { e.printstacktrace(); } } }
输出结果为:
public static final java.lang.string reflectdemo.superhero.address java.lang.string address -------------------- private java.lang.string reflectdemo.superhero.id java.lang.string id -------------------- private java.lang.string reflectdemo.superhero.name java.lang.string name -------------------- private java.lang.integer reflectdemo.superhero.age java.lang.integer age -------------------- private java.lang.string reflectdemo.superhero.skill java.lang.string skill --------------------
public class classutils { /** * 获取成员方法 * @param clazz 类 * @param methodname 方法名称 * @param params 参数列表 * @throws exception */ public static void getdeclaredmethod(class clazz, string methodname, class[] params) throws exception{ method method = clazz.getdeclaredmethod(methodname, params); system.out.println("直接打印"); system.out.println(method); system.out.println("手动构建"); //获取返回类型 system.out.print(method.getreturntype().getsimplename() + " "); //获取方法名称 system.out.print(method.getname() + "("); //获取参数类型 class[] paramtypes = method.getparametertypes(); for(int i = 0; i < paramtypes.length; i++){ class param = paramtypes[i]; if(i < paramtypes.length - 1){ system.out.print(param.getsimplename() + ", "); }else { system.out.print(param.getsimplename()); } } system.out.print(")"); system.out.println(); } } public class classtest { public static void main(string[] args) { try { class clazz = class.forname("reflectdemo.superhero"); //打印无参数方法 classutils.getdeclaredmethod(clazz, "getname", null); //打印有参数方法 classutils.getdeclaredmethod(clazz, "setname", new class[]{string.class}); } catch (exception e) { e.printstacktrace(); } } }
输出结果为:
直接打印 public java.lang.string reflectdemo.superhero.getname() 手动构建 string getname() 直接打印 public void reflectdemo.superhero.setname(java.lang.string) 手动构建 void setname(string)
public class classutils { /** * 遍历方法 * @param clazz */ public static void getdeclaredmethods(class clazz){ //获取类中所有声明的方法 method[] methods = clazz.getdeclaredmethods(); for (method method : methods){ system.out.println(method); } } } public class classtest { public static void main(string[] args) { try { class clazz = class.forname("reflectdemo.superhero"); //遍历方法 classutils.getdeclaredmethods(clazz); } catch (exception e) { e.printstacktrace(); } } }
输出结果为:
public java.lang.string reflectdemo.superhero.getname() public java.lang.string reflectdemo.superhero.getid() public void reflectdemo.superhero.setname(java.lang.string) public void reflectdemo.superhero.print() public java.lang.string reflectdemo.superhero.getskill() public void reflectdemo.superhero.setage(java.lang.integer) public void reflectdemo.superhero.setskill(java.lang.string) public void reflectdemo.superhero.setid(java.lang.string) public java.lang.integer reflectdemo.superhero.getage()
public class classutils { /** * 执行set方法(通过method的invoke方法) * @param o 待执行的实体 * @param methodname 方法名称 * @param params 方法参数类型 * @throws exception */ public static void invokesetmethod(object o, string methodname, class[] params) throws exception { method method = o.getclass().getdeclaredmethod(methodname, params); method.invoke(o, "钢铁侠"); } /** * 执行get方法(通过method的invoke方法) * @param o 待执行的实体 * @param methodname 方法名称 * @throws exception */ public static void invokegetmethod(object o, string methodname) throws exception{ method method = o.getclass().getdeclaredmethod(methodname); object obj = method.invoke(o); system.out.println(obj); } } public class classtest { public static void main(string[] args) { try { class clazz = class.forname("reflectdemo.superhero"); //创建实体 object o = clazz.newinstance(); //调用set方法 classutils.invokesetmethod(o, "setname", new class[]{string.class}); //调用get方法 classutils.invokegetmethod(o, "getname"); } catch (exception e) { e.printstacktrace(); } } }
输出结果为:
钢铁侠
下面是对invoke方法的api说明
public object invoke(object obj, object... args) throws illegalaccessexception, illegalargumentexception, invocationtargetexception在具有指定参数的
方法
对象上调用此方法
对象表示的基础方法。如果底层方法是静态的,则指定的
obj
参数将被忽略。 它可能为null。如果底层方法所需的形式参数的数量为0,则提供的
args
数组的长度为0或为空。如果底层方法是一个实例方法,它将使用动态方法查找来调用,如“java语言规范”第二版,第15.12.4.4节所述; 特别是将会发生基于目标对象的运行时类型的覆盖。
如果底层方法是静态的,则如果尚未初始化该方法,那么声明该方法的类将被初始化。
如果方法正常完成,则返回的值将返回给调用者; 如果值具有原始类型,则首先将其适当地包装在对象中。 但是,如果该值具有基本类型的数组的类型,则该数组的元素不会包含在对象中; 换句话说,返回一个原始类型的数组。 如果底层方法返回类型为void,则调用返回null。
参数
obj
- 从底层方法被调用的对象
args
- 用于方法调用的参数结果
由该对象表示的方法在
obj
上调用args
异常
illegalaccessexception
- 如果这个方法
对象正在强制执行java语言访问控制,并且底层方法是无法访问的。
illegalargumentexception
- 如果方法是一个实例方法,并且指定的对象参数不是声明底层方法(或其子类或实现者)的类或接口的实例; 如果实际和正式参数的数量不同; 如果原始参数的解包转换失败; 或者如果在可能的展开之后,通过方法调用转换,参数值不能转换为相应的形式参数类型。
invocationtargetexception
- 如果底层方法抛出异常。
nullpointerexception
- 如果指定的对象为空,该方法为实例方法。
exceptionininitializererror
- 如果由此方法引发的初始化失败。
本文对反射的定义,反射使用过程中重要的、常用的类和方法进行了讲解,包括class类,constructor类,field类,method类的说明及使用。反射机制允许在运行时判断任意一个对象所属的类、构造任意一个类的对象、判断任意一个类所具有的成员变量和方法、调用任意一个对象的方法。大大提高了系统的灵活性和扩展性,不过凡事都有两面性,反射破坏了java封装的特性,相对来说不安全,需要根据场景酌情考虑,若有不对之处,请批评指正,望共同进步,谢谢!
如对本文有疑问, 点击进行留言回复!!
Mybatis PersistenceException异常:Error building SqlSession The error may exist in SQL Mapper Configur
MyBatis——动态SQL语句——if标签和where标签复合使用
网友评论