为什么需要java反射?
在编写代码的时候,当你仅仅知道一个类名,并且想要动态得到类的定义消息,包含的方法和属性等的时候,我们就需要通过java反射来获得这些.由于像框架,tomcat,或者一些其他的组件(jackson 对象-->json),事先不知道是哪个类,只能根据配置文件中配置的类的地址决定要创建并且操作哪一个类.
Java反射的概念
java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,并且对于任意一个对象,都可以调用他的任意一个方法和属性.这种动态的获得类中的方法和属性的操作就叫做java反射.那么我们如何在只有一个类名的情况下获得这个类?
Java反射的实例
首先我们应该知道java反射获得对象的原理,首先通过forName("java类的名称")来获得该类的class类的对象,之后该类的class类会到达内存的方法区,注意的是任意类的class类只有一个,无论创建几次,都是同一个class类.之后可以通过newInstance()方法来获得该类的对象.代码如下:
Class userClass=Class.forName("com.ffyc.javaerflect.Admin");
Constructor constructor =userClass.getConstructor();
Object userObj = constructor.newInstance();
接下来我会为大家解释反射中常用的几种方法:
- getConstructor()和getDeclaredConstructor()方法:
Class userClass=Class.forName("com.ffyc.javaerflect.User");
// Constructor constructor=userClass.getConstructor();//获取指定参数个数的公共构造方法
// Constructor constructor=userClass.getConstructor(int.class);//获取指定参数个数的公共构造方法
/*Constructor constructor=userClass.getConstructor(int.class,String.class);//获取指定参数个数的公共构造方法
Constructor[] constructors=userClass.getConstructors();
Object obj = constructor.newInstance(10,"134"); //创建一个对象,通过Constructor.newInstance()方法来创建对象*/
/*Constructor declareConstructor = userClass.getDeclaredConstructor(int.class,String.class);
//默认情况下,私有成员不能访问,可以设置允许访问私有成员
declareConstructor.setAccessible(true);
Object obj = declareConstructor.newInstance(10,"134");*/
Constructor[] declareConstructors = userClass.getDeclaredConstructors();//获取类中所有的构造方法,包括私有的
两个方法如果不传参数的话,就会自动调用无参构造方法,而在框架中,框架在通过反射获得类的对象的时候,就是默认调用无参构造方法,所以当我们定义了有参构造方法后,必须定义一个无参构造方法来满足后面框架的需求.如果想要获得有参的构造方法,我们需要在调用方法的时候在参数里写入所需的参数类型的class类.
两个方法在功能上是一致的,都是为了获得类的构造方法,但是区别是getConstructor只能获得该类中的公共方法,而getDeclaredConstructor看可以获得该类中的所有方法,包含私有方法.
- getFields()和getDeclaredFields()方法
HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("account","11111");
hashMap.put("password","1877124");
Class userClass=Class.forName("com.ffyc.javaerflect.Admin");
Constructor constructor =userClass.getConstructor();
Object userObj = constructor.newInstance();
// Field filed = userClass.getDeclaredField("id");
Field[] fields = userClass.getDeclaredFields();
for (Field f:fields) {
// System.out.println(f.getName());
f.setAccessible(true);
f.set(userObj,hashMap.get(f.getName()));
}
System.out.println(userObj);
两个方法都是用于获取类的属性,但是getFields()只能获得该类的所有公共属性,但是getDeclaredFields()可以获得该类中的所有属性(包括私有属性).
- getMethod()和getDeclaredMethods()方法
Class userClass = Class.forName("com.ffyc.javaerflect.User");
Constructor constructor = userClass.getConstructor();
Object objUser = constructor.newInstance();
Method method1 = userClass.getDeclaredMethod("eat",String.class);
method1.invoke(objUser,"123");
二者共同点是在获取方法的时候,可以通过在getMthods()参数中写入方法名称和参数类型的class类,从而在后面的invoke中运行.
二者的不同点是getMethod可以获得父类中可访问到的方法和本类中的所有公共方法,而getDeclaredMethods可以访问到本类中的所有方法(包括私有方法).
最后我们可以通过一个实例来验证框架中前后端交互中的数据模板:
public class JsonUtil {
public static String objectTJson(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
String json= "{";
Class classobj = object.getClass();
Field[] fields = classobj.getFields();//获取所有的属性
for (Field f:fields) {
//循环属性 拼接属性的get方法名称
String get = "get"+String.valueOf(f.getName().charAt(0)).toUpperCase()+f.getName().substring(1);
Method method = classobj.getMethod(get);
json+=f.getName()+":"+method.invoke(classobj)+",";//调用get方法获得返回值
}
json=json.substring(0,json.length()-1);
json+="}";
return json;
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
User user = new User();
user.setId("100");
user.setName("tom");
Admin admin = new Admin();
admin.setAccount("1111");
admin.setPassword("222200");
System.out.println(objectTJson(user));
System.out.println(objectTJson(admin));
}
}