我们使用的一些像框架,tomcat,或者一些其他的组件(jackson 对象–>json)。他们可以做到给他什么类名,就可以创建给定类的对象,并调用该对象的方法和属性。这是如何做到的?
当他们加载我们本地的类时,需要先创建对象,然后将查询到的结果封装到创建的对象中(调用setxxx()方法,调用xxx属性),但问题是框架只知道Student类的地址,它是如何使用类的?
框架只能根据配置文件中配置的类的地址决定要创建并操作哪个类:
<select id="findStudents" parameterType="Student" resultType="xx.xx.xx.Student">
而且框架要做到可以处理任何类,只需要一套程序来处理,这是怎么办到的?
这时候我们就需要反射机制,只用一套程序来解决框架处理任何类的问题。
JAVA反射机制是再运行状态中,对于任意一个类,都能知道这个类的所有属性和方法,对于任意一个对西昂,都能调用它的任意一个方法和属性,这种动态获取信息以及动态调用对西昂的方法的功能称为java语言的反射机制。它的作用就是动态获取类的信息。
反射机制当中有一个类叫Class,Class类的类表示正在运行的Java应用程序中的类和接口。
一旦class文件被加载到内存,就会为其创建一个Class对象,任何类被使用时都会创建一个Class对象。
Class类是Java反射机制的基础,可以通过获取类的Class类,可以得到一个类的基本信息。
方式1:
String s="Model.User";
Class c1=Class.forName(s); //把给定地址的类进行了加载,为其创建Class对象
Class c2=Class.forName(s); //把给定地址的类进行了加载,为其创建Class对象
System.out.println(c1);
System.out.println(c2);
System.out.println(c1==c2); //true:c1和c2表示的是同一个
//通过user的Class对象,就看可以获得User类的基本信息
方式2:
Class c3= User.class;
方式3:
User user=new User();
Class c4=user.getClass(); //通过已知的对象中的getClass() 获得该对象类的Class对象
//通过Class类的对象,来创建User对象
//newInstance调用默认无参构造方法,所以如果类中有有参构造方法还需要单独把无参构造方法也写出来否则IllegalAccessException
Object objectUser=c.newInstance();
//类中要确保有无参构造方法否则异常NoSuchMethodException
Constructor constructor1=c.getConstructor(); //获得类中指定的公共public构造方法
Object objectUser = constructor1.newInstance(); //通过构造方法中newInstance创建对象
Constructor constructor2=c.getDeclaredConstructor(); //获得类中的指定沟构造方法(包括私有)
Constructor constructor3=c.getConstructor(String.class,String.class); //获得公共的有参构造方法
Object objectUser1=constructor3.newInstance("用户1","密码1"); //创建对象,并为对象属性复制
Constructor[] constructors=c.getConstructors(); //获得所有的公共的构造方法
c.getDeclaredConstructors(); //获得包括私有的所有的构造方法
小知识点:java创建对象三种方式:
(1)new (2)反射机制的newInsteance (3)序列化与反序列化读取文件中的类
String s="Model.User";
Class c=Class.forName(s); //获得类的Class对象
Object objectUser=c.newInstance(); //创建User对象
//获得类中的成员变量
//获得类中指定的公共的属性,把属性封装到一个Field对象
// Field userNameField = c.getField("userName");
Field userNameField = c.getDeclaredField("userName"); //私有成员变量
//获得所有的属性
Field [] fields=c.getFields();
//包括私有
Field [] fields1=c.getDeclaredFields();
//用HashMap模拟查询到的数据
HashMap<String,String> map=new HashMap<>();
map.put("userName","admin");
map.put("password","123456");
//循环所有的属性,为属性赋值
for (Field f: fields) {
//打破了封装性,!慎用,建议使用getset方法因为可能setget方法中还有逻辑语句
f.setAccessible(true); //设置可以访问私有属性
f.set(objectUser,map.get(f.getName()));
}
String s="Model.User";
Class c=Class.forName(s); //获得类的Class对象
Object objectUser=c.newInstance(); //创建User对象
Method eat1=c.getMethod("eat");
//执行objectUser对象中的无参eat方法——invoke:调用
eat1.invoke(objectUser);
Method eat2=c.getMethod("eat",String.class);
eat2.invoke(objectUser,"参数");
//包括继承的方法
Method[] methods1=c.getMethods();
//获得本类中所有的成员方法包括私有
Method[] methods2=c.getDeclaredMethods();
System.out.println(methods1.length); //15
System.out.println(methods2.length); //7
Field[] fields=c.getDeclaredFields(); //获得所有属性
for (Field f:fields) { //循环拿到每一个属性
//通过属性名 匹配到getset方法
String set="set"+String.valueOf(f.getName().charAt(0)).toUpperCase()+f.getName().substring(1);
Method setMethod=c.getMethod(set,String.class); //通过set方法名获得set方法
setMethod.invoke(objectUser,"用户和密码"); //调用set方法
}