第2章 反射
能够说出反射的概念
能够说出获取一个类的class文件对象的三个方式
能够实现反射构造方法
能够实现反射方法
能够使用BeanUtils工具类方法setProperty
能够使用BeanUtils工具类方法getProperty
能够完成BeanUtils工具类的综合案例
1.1 类的初始化
-
创建类的实例
-
类的静态变量,或者为静态变量赋值
-
类的静态方法
-
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
-
初始化某个类的子类
-
直接使用java.exe命令来运行某个主类
到目前为止我们已经知道把class文件加载到内存做了哪些事情了,那么,如果我们仅仅站在这些class文件的角度,我们如何来使用这些class文件中的内容呢?那就是我们反射将要学习的内容了。
1.2反射概述
Java反射机制是在运行状态中(和编译无关),对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。(框架的灵魂就是反射)
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖这个类,使用的就是Class类中的方法,所以先要获取到每一个字节码文件所对应的Class类型对象。
类的加载器把要运行的类装进内存。
类的加载器有三个:
(1)引导类加载器:由C语言编写(加载使用的核心类库)
(2)扩展类加载器:Java语言编写(加载JDK的扩展类库)
(3)应用类加载器:Java语言编写(加载我们写的类)
Java.lang.ClassLoader表示类的加载器的对象
一个类只能被加载一次,不能被加载两次
对象都是由类产生的
[外链图片转存失败(img-Sn9rDcZB-1562192873796)(pics/搜狗截图20190520112521.png)]
1.3 准备数据
自定义一个类
1.4知识储备
需要掌握6个单词
Class类
Constructor 构造
Method 方法
Field 字段
instance 实例
invoke 执行
1.5 Class获得方式
//1 通过类型获得
// 语法:类名.class
// 应用场景:确定类型等
Classclazz1 = Bean.class;
//2 通过实例对象获得
// 语法:变量.getClass()
// 应用场景:在方法内部通过参数获得类型等
Bean bean = newBean();
Classclazz2 = bean.getClass();
//3 通过字符串获得
// 语法:Class.forName("全限定类名")
// 应用场景:通过配置获得字符串等
Classclazz3 = Class.forName("com.baidu.Bean");
1.6 构造方法与实例
添加有参无参构造方法
1.6.1 无参构造
无参构造,并获得实例
public void test DefaultCons() throws Exception{
//无参构造 , 并实例化
//1获得Class
Class beanClass = Bean.class;
//2获得构造 -- 没有形参
Constructorconstructor = beanClass.getConstructor();
//3 实例对象,没有实参
Object bean = constructor.newInstance();
System.out.println(bean);
/* 结果:
* 无参构造
* com.baidu.Bean@8c5488
*/
}
1.6.3 有参构造
有参构造,并获得实例
publicvoidtestParamCons() throws Exception{
//有参构造 , 并实例化
//1获得Class
ClassbeanClass = Bean.class;
//2获得构造 -- 两个字符串形参 -- Bean(String id, String className)
Constructorconstructor = beanClass.getConstructor(String.class,String.class);
//3 实例对象,两个字符串实参
Object bean = constructor.newInstance("ArrayListId","java.util.ArrayList");
System.out.println(bean);
/* 结果:
* 有参构造:ArrayListId,java.util.ArrayList
* com.baidu.Bean@101acff
*/
}
1.6.4 无参构造,简化版获得实例
无参构造,简化版获得实例
publicvoidtestDefaultSimple() throws Exception{
//无参构造 , 简化版
//1获得Class
ClassbeanClass = Bean.class;
//2 直接获得实例对象,两个字符串实参
Object bean = beanClass.newInstance();
System.out.println(bean);
/* 结果:
* 无参构造
* com.baidu.Bean@101acff
*/
}
1.6.5 扩展:私有构造(暴力反射)
修改Bean添加私有构造
getConstructor() 使用该方法将无法获得私有方法,程序运行抛异常
没有使用setAccessible(true),将抛异常
publicvoidtestPrivateCons() throws Exception{
//私有构造
//1获得Class
Class beanClass = Bean.class;
//2获得构造 -- 两个字符串形参 -- Bean(String id, String className)
// * getConstructor() 将抛异常java.lang.NoSuchMethodException
// * getDeclaredConstructor可以获得私有构造
Constructor constructor = beanClass.getDeclaredConstructor(String.class);
//暴力访问
constructor.setAccessible(true);
//3 实例对象,两个字符串实参
Object bean = constructor.newInstance("userId");
System.out.println(bean);
/* 结果:
* 有参构造:userId
* com.baidu.Bean@8c5488
*/
}
1.7方法与执行
1.7.1 添加set、get方法
//Bean类提供getter和setter方法
public String getId() {
System.out.println("getId方法执行");
return id;
}
public void setId(String id) {
System.out.println("setId方法执行:" + id);
this.id = id;
}
1.7.2 public方法
publicvoidtestMethod() throws Exception{
//1 获得Class
Class clazz = Class.forName("com.baidu.Bean");
//2 获得实例 ,相当于 Object obj = new Bean();
Object obj = clazz.newInstance();
//3 操作setId方法
//3.1 获得的方法,一个形参
// * 格式:getMethod(方法名,参数列表)
Method setMethod = clazz.getMethod("setId", String.class);
//3.2 执行方法,一个实参
Object setReturnObj = setMethod.invoke(obj, "我是参数");
System.out.println("set方法返回值:" + setReturnObj);
/* 运行结果:
* 无参构造
* setId方法执行:我是参数
* set方法返回值:null
*/
System.out.println("---------------");
//4 操作getId方法 (巩固)
// 3.1 获得方法,没有形参
Method getMethod = clazz.getMethod("getId");
// 3.2 执行方法,没有实参
Object getReturnObj = getMethod.invoke(obj);
System.out.println("get方法返回值:" + getReturnObj);
/* 运行结果:
* getId方法执行
* get方法返回值:我是参数
*/
}
1.7.3 扩展:私有方法(暴力反射)
//私有方法
private String show(){
System.out.println("私有方法执行");
return"Bean["+id+", "+ className +"]";
}
getMethod() 使用该方法将无法获得私有方法,程序运行抛异常
没有使用setAccessible(true),将抛异常
publicvoidtestPrivateMethod() throws Exception{
//1 获得Class
Class clazz = Class.forName("com.baidu.Bean");
//2获得构造 -- 两个字符串形参 -- Bean(String id, String className)
Constructor constructor = clazz.getConstructor(String.class,String.class);
//3 实例对象,两个字符串实参
Object bean = constructor.newInstance("ArrayListId","java.util.ArrayList");
//3获得方法 -- 私有方法 -- private String show()
// * getMethod(方法名,形成列表) 将抛异常java.lang.NoSuchMethodException
// * getDeclaredMethod(方法名,形成列表) 可以获得私有构造
Method showMethod = clazz.getDeclaredMethod("show");
//暴力访问
showMethod.setAccessible(true);
// 4 执行方法,没有实参
Object getReturnObj = showMethod.invoke(bean);
System.out.println("show方法返回值:" + getReturnObj);
/* 运行结果:
* 有参构造:ArrayListId,java.util.ArrayList
* 私有方法执行
* show方法返回值:Bean[ArrayListId, java.util.ArrayList]
*/
}
1.8 字段(成员变量)与数据操作(了解)
1.8.1 添加public字段
publicclass Bean {
private String id;
private String className;
public String description;
1.8.2 public字段的操作
publicvoidtestField() throws Exception{
/* 获得实例,为public字段赋值、获取值
* public String description;
*/
//1 获得Class
Class clazz = Class.forName("com.baidu.Bean");
//2 获得实例 ,相当于 Object obj = new Bean(); 但是必须是无参构造
Object bean= clazz.newInstance();
//3 操作字段,进行赋值,public String description;
//3.1 获得的字段,一个形参
// * 格式:getField(字段名)
Field descriptionField = clazz.getField("description");
//3.2 为对象的字段赋值
descriptionField.set(bean, "Bean的描述");
//3.3 获取对象的字段值
Object fieldReturnObj = descriptionField.get(bean);
System.out.println("description字段返回值:"+fieldReturnObj);
}
1.9 综合案例
- 提供一个User对象,并提供getter和setter方法,并复写toString()
public class TbUser {
private String id;
private String username;
private String pwd;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
//....省略
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", pwd=" + pwd + "]";
}
-
读取properties文件,将文件内容设置到User中
/* * 读取配置文件(IO+集合),键值对存储到集合中 * 键获取集合中的所有值 * 反射,创建出User类的对象,调用方法setXX,数据存储 */ public void test()throws Exception{ Properties pro = new Properties(); FileInputStream fis = new FileInputStream("data.properties"); pro.load(fis); fis.close(); Class clazz = Class.forName("com.baidu.domain.User"); Object obj = clazz.newInstance(); Set<String> keys = pro.stringPropertyNames(); for(String key : keys){ String methodName = "set"+key.substring(0,1).toUpperCase()+key.substring(1); Method method = clazz.getMethod(methodName, String.class); method.invoke(obj, pro.getProperty(key)); } System.out.println(obj); }配置文件data.properties
uid=001
username=jack
password=123
#第3章 BeanUtils工具类
BeanUtils 是 Apache commons组件的成员之一,主要用于简化JavaBean封装数据的操作。它可以给JavaBean封装一个字符串数据,也可以将一个表单提交的所有数据封装到JavaBean中。
使用第三方工具,需要导入jar包:
[外链图片转存失败(img-CDOTWKM1-1562192873797)(pics/搜狗截图20190520113602.png)]
BeanUtils工具常用工具类有两个:BeanUtils、ConvertUtils。BeanUtils用于封装数据,ConvertUtils用于处理类型转换,常用API如下
[外链图片转存失败(img-0oJ7d8d9-1562192873797)(pics/搜狗截图20190520113632.png)]
- 提供JavaBean User ,并提供对应的构造方法
public class User {
private String id;
private String username;
private String pwd;
//省略setter和getter
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", pwd=" + pwd + "]";
}
}
- 功能1:设置属性
public void demo01() throws Exception{
User user = new User();
//设置属性
BeanUtils.setProperty(user, "id", "u001");
BeanUtils.setProperty(user, "username", "jack");
BeanUtils.setProperty(user, "pwd", "1234");
System.out.println(user);
/* 结果:
* User [id=u001, username=jack, pwd=1234]
*/
}
- 功能2:获得属性
@Test
public void demo02() throws Exception{
User user = new User("u001","jack","1234");
//设置属性
String id = BeanUtils.getProperty(user, "id");
String username = BeanUtils.getProperty(user, "username");
System.out.println(id);
System.out.println(username);
/* 结果:
* u001
* jack
*/
}
- 功能3:封装表单数据,populate方法
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("com.baidu.demo4.User");
User instance = (User)clazz.newInstance();
//设置值
// BeanUtils.setProperty(instance, "id", 1001);
// BeanUtils.setProperty(instance, "username", "haha");
// BeanUtils.setProperty(instance, "pwd", "123");
//获取值
// System.out.println(BeanUtils.getProperty(instance, "id"));
// System.out.println(BeanUtils.getProperty(instance, "username"));
// System.out.println(BeanUtils.getProperty(instance, "pwd"));
Map<String, Object> properties=new HashMap<>();
properties.put("id", 1001);
properties.put("username", "qinghua");
properties.put("pwd", 1111);
//批量设置属性
BeanUtils.populate(instance, properties);
System.out.println(BeanUtils.getProperty(instance, "id"));
System.out.println(BeanUtils.getProperty(instance, "username"));
System.out.println(BeanUtils.getProperty(instance, "pwd"));
// System.out.println(instance);
}
2.1 综合案例
读取XML中的配置文件信息,使用BeanUtils工具类创建JavaBean对象,将XML中的数据保存到JavaBean类的属性中
/**
* 读取xml中的内容
* 通过反射 设置到对象中
* 测试
*
*/
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("com.baidu.demo5.User");
User user1 = (User)clazz.newInstance();
User user2 = (User)clazz.newInstance();
User user3 = (User)clazz.newInstance();
ArrayList<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
//读取beans.xml中的内容
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("beans.xml");
Element rootElement = document.getRootElement();
List<Element> elements = rootElement.elements();
for(int i=0;i<elements.size();i++) {
User user = userList.get(i);
BeanUtils.setProperty(user, "id", elements.get(i).attributeValue("id"));
BeanUtils.setProperty(user, "username", elements.get(i).attributeValue("name"));
BeanUtils.setProperty(user, "pwd", elements.get(i).attributeValue("pwd"));
}
for(User u:userList) {
System.out.println(u);
}
}
本文介绍了Java反射机制,包括类的初始化、反射概述、Class获得方式、构造方法与实例、方法与执行、字段与数据操作等内容,还涉及暴力反射。此外,讲解了BeanUtils工具类,包括其功能和常用API,并给出了综合案例,如读取配置文件设置对象属性等。
380

被折叠的 条评论
为什么被折叠?



