本篇博文主要包含:
- JSON简单使用,Java对象、json字符串对象和json对象互转
- XML简单使用,Dom4j解析XML
- XML与JSON区别
- Java反射机制
- 反射机制获取类的方法
-Class.class
-Class.forName()
-.getClass() - 利用反射给私有属性赋值
- 利用反射手写springIOC原理:dom4j+反射机制
一、数据交换格式
- JSON简单使用
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相比于xml这种数据交换格式来说,因为解析xml比较的复杂,而且需要编写大段的代码,所以客户端和服务器的数据交换格式往往通过JSON来进行交换。
常用JSON解析框架:
fastjson(阿里)、gson(谷歌)、jackson(SpringMVC自带)
以下案例使用fastjson解析json:
1.1 添加jar fastjson-1.1.43 或引入maven依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.1.43</version>
</dependency>
1.2 将json字符串转化为json对象
public static void jsonStrToJsonObject() {
String jsonStr = "{\"sites\":[{\"name\":\"三多\",\"url\":\"不抛弃\"},{\"name\":\"史今\",\"url\":\"不放弃\"}]}";
JSONObject jsonObject = new JSONObject();
// 将json字符串转为jsonbject
JSONObject jsonStrObject = jsonObject.parseObject(jsonStr);
//将数组转化为json数组
JSONArray jsonArray = jsonStrObject.getJSONArray("sites");
for (Object object : jsonArray) {
JSONObject stObject = (JSONObject) object;
String name = stObject.getString("name");
String url = stObject.getString("url");
System.out.println(name + "---" + url);
}
}
运行结果:
1.3 将json字符串转化为java对象
User和Item类
class Item {
private String itemId;
private String itemName;
public String getItemId() {
return itemId;
}
public void setItemId(String itemId) {
this.itemId = itemId;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
@Override
public String toString() {
return "Item [itemId=" + itemId + ", itemName=" + itemName + "]";
}
}
class User {
private String id;
private String name;
private List<Item> items;
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 List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", items=" + items + "]";
}
}
将json字符串转化为对象的方法:
public static void jsonStrToObject() {
String jsonStr = "{\"name\":\"不抛弃,不放弃\",\"id\":\"0\",\"items\":[{\"itemName\":\"三多\",\"itemId\":\"1\"},{\"itemName\":\"史今\",\"itemId\":\"2\"}]}";
//使用java反射机制 对应生成对象
User user = new JSONObject().parseObject(jsonStr, User.class);
System.out.println("user:" + user.toString());
}
运行结果:
1.4 Json api封装json
public static void toJsonObject() {
JSONObject root = new JSONObject();
root.put("id", "1");
root.put("name", "成才");
//定义一个json数组
JSONArray arrayList = new JSONArray();
JSONObject object1 = new JSONObject();
object1.put("itemId", "2");
object1.put("itemName", "醒悟");
JSONObject object2 = new JSONObject();
object2.put("itemId", "3");
object2.put("itemName", "成长");
arrayList.add(object1);
arrayList.add(object2);
root.put("items", arrayList);
System.out.println(root.toJSONString());
}
运行结果:
1.5 将对象转换成json字符串
public static void ObjectToJsonObjectStr() {
User user = new User();
user.setId("1");
user.setName("六一");
List<Item> items =new ArrayList<Item>();
Item item1 = new Item();
item1.setItemId("2");
item1.setItemName("坚韧");
Item item2 = new Item();
item2.setItemId("3");
item2.setItemName("优秀");
items.add(item1);
items.add(item2);
user.setItems(items);
System.out.println(new JSONObject().toJSONString(user));
}
运行结果:
- XML简单使用
XML 全称为可扩展的标记语言。它是一种重量级的数据交换格式。XML 文档的根元素被称为文档元素,它和在其外部出现的处理指令、注释等作为文档实体的子节点,根元素本身和其内部的子元素也是一棵树。
XML 文档在逻辑上主要由一下 5 个部分组成:
- XML 声明:指明所用 XML 的版本、文档的编码、文档的独立性信息
- 文档类型声明:指出 XML 文档所用的 DTD
- 元素:由开始标签、元素内容和结束标签构成
- 注释:以结束,用于对文档中的内容起一个说明作用
- 处理指令:通过处理指令来通知其他应用程序来处理非 XML 格式的数据。
XML解析方式有:Dom4j、Sax、Pull
2.1 Dom4j与Sax区别
dom4j不适合大文件的解析,因为它是一下子将文件加载到内存中,所以有可能出现内存溢出,sax是基于事件来对xml进行解析的,所以他可以解析大文件的xml,也正是因为如此,所以dom4j可以对xml进行灵活的增删改查和导航,而sax没有这么强的灵活性,所以sax经常是用来解析大型xml文件,而要对xml文件进行一些灵活(crud)操作就用dom4j。
- 以下案例使用dom4j解析xml
3.1 引入maven依赖
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.0.0</version>
</dependency>
3.2 stu.xml配置(本次放在项目根目录下)
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student1 id="001">
<微信公众号>每特学院</微信公众号>
<学号>20140101</学号>
<地址>北京海淀区</地址>
<座右铭>要么强大,要么听话</座右铭>
</student1>
<student2 id="002">
<新浪微博>蚂蚁课堂</新浪微博>
<学号>20140102</学号>
<地址>北京朝阳区</地址>
<座右铭>在哭泣中学会坚强</座右铭>
</student2>
</students>
3.3 解析代码
public class Dom4jDemo {
public static void main(String[] args) throws DocumentException {
SAXReader saxReader = new SAXReader();
//读取xml配置文件
Document read = saxReader.read(new File("C:\\ww\\workSpace\\zbm\\zbm\\stu.xml"));
// 获取根节点
Element rootElement = read.getRootElement();
getNodes(rootElement);
}
static public void getNodes(Element rootElement) {
//获取节点名称
System.out.println("当前节点名称:" + rootElement.getName());
// 获取属性ID
List<Attribute> attributes = rootElement.attributes();
for (Attribute attribute : attributes) {
System.out.println("属性:" + attribute.getName() + "---" + attribute.getText());
}
//获取节点中的值
if (!rootElement.getTextTrim().equals("")) {
System.out.println(rootElement.getName() + "--" + rootElement.getText());
}
// 使用迭代器遍历
Iterator<Element> elementIterator = rootElement.elementIterator();
while (elementIterator.hasNext()) {
Element next = elementIterator.next();
getNodes(next);
}
}
}
运行结果:
this.getClass().getClassLoader().getResourceAsStream(xmlPath) 可以获取当前项目路径。
- XML与JSON区别
xml是重量级数据交换格式,占宽带比较大。
JSON是轻量级交换格式,xml占宽带小。
所有很多互联网公司都会使用json作为数据交换格式
很多银行项目,大多数还是在使用xml。
二、Java反射机制
- 什么是Java反射
就是正在运行,动态获取这个类的所有信息。 - 反射机制的作用
通过反射机制访问java对象的属性,方法,构造方法等。 - 反射机制的应用场景
Jdbc 加载驱动
Spring ioc
框架 - 禁止使用反射机制初始化?
将构造函数为私有化 - 反射机制获取类有三种方法
1)Class.class 的形式会使 JVM 将使用类装载器将类装入内存(前提是类还没有装入内存),不做类的初始化工作,返回 Class 对象。
代码演示:
ReflectUser类
public class ReflectUser {
private String name;
private String addr;
public ReflectUser() {
System.out.println("调用无参函数了,哈哈哈。。。。");
}
public ReflectUser(String name, String addr) {
super();
System.out.println("调用有参函数了,咦咦咦.....");
this.name = name;
this.addr = addr;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public String say(String str) {
return str;
}
@Override
public String toString() {
return "ReflectUser [name=" + name + ", addr=" + addr + "]";
}
2)Class.forName() 的形式会装入类并做类的静态初始化,返回 Class 对象。
forNameDemo()方法:
static void forNameDemo() throws ClassNotFoundException, InstantiationException, IllegalAccessException,
NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
//创建此Class 对象所表示的类的一个新实例
Class<?> forName = Class.forName("wmq.fly.reflection.ReflectUser");
//调用了User的无参数构造方法.
ReflectUser reflectUser = (ReflectUser) forName.newInstance();
reflectUser.setName("铁军");
reflectUser.setAddr("七连");
System.out.println(reflectUser.toString());
//调用了User的有参数构造方法.
Constructor<?> constructor = forName.getConstructor(String.class,String.class);
ReflectUser reflectUser2 = (ReflectUser) constructor.newInstance("小宁","七连");
System.out.println(reflectUser2.toString());
}
运行结果:
3).getClass() 的形式会对类进行静态初始化、非静态初始化,返回引用运行时真正所指的对象(因为子对象的引用可能会赋给父对象的引用变量中)所属的类的 Class 对象。
代码演示:
static void getClassDemo() throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
ReflectUser reflectUser = new ReflectUser();
//调用了User的无参数构造方法.
Class user = reflectUser.getClass();
Method method = user.getMethod("say", String.class);
Object invoke = method.invoke(reflectUser, "老刘");
System.out.println(invoke);
}
运行结果:
静态属性初始化是在加载类的时候初始化,而非静态属性初始化是 new 类实例对象的时候初始化。他们三种情况在生成 Class 对象的时候都会先判断内存中是否已经加载此类。
- 利用反射给私有属性赋值
代码演示:
static void assignmentValueToPrivate() throws ClassNotFoundException, InstantiationException,
IllegalAccessException, NoSuchFieldException, SecurityException {
//创建此Class 对象所表示的类的一个新实例
Class<?> forName = Class.forName("wmq.fly.reflection.ReflectUser");
//获取当前类的所有属性
Field[] fields = forName.getDeclaredFields();
System.out.println("属性:");
for(Field field : fields ) {
System.out.println(field.getName());
}
//获取当前类的所有属性
Method[] methods = forName.getDeclaredMethods();
System.out.println("方法:");
for(Method method : methods ) {
System.out.println(method.getName());
}
//使用java的反射机制给私有属性赋值
Object newInstance = forName.newInstance();
Field fieldName = forName.getDeclaredField("name");
//允许反射操作私有属性
fieldName.setAccessible(true);
fieldName.set(newInstance,"一乐");
Field fieldAdrr = forName.getDeclaredField("addr");
//允许反射操作私有属性
fieldAdrr.setAccessible(true);
fieldAdrr.set(newInstance,"下榕树");
ReflectUser reflectUser = (ReflectUser)newInstance;
System.out.println(reflectUser.toString());
}
运行结果:
三、利用反射手写springIOC
实现原理:
- 利用传入的参数获取xml文件的流,并且利用dom4j解析成Document对象
- 对于Document对象获取根元素对象后对下面的标签进行遍历,判断是否有符合的id.
- 如果找到对应的id,相当于找到了一个Element元素,开始创建对象,先获取class属性,根据属性值利用反射建立对象.
- 遍历标签下的property标签,并对属性赋值.注意,需要单独处理int,float类型的属性.因为在xml配置中这些属性都是以字符串的形式来配置的,因此需要额外处理.
- 如果属性property标签有ref属性,说明某个属性的值是一个对象,那么根据id(ref属性的值)去获取ref对应的对象,再给属性赋值.
- 返回建立的对象,如果没有对应的id,或者下没有子标签都会返回null
代码实现:
1.引入jar包
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
2.applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
">
<bean id="reflectUser" class="wmq.fly.reflection.ReflectUser">
<property name="name" value="二和"></property>
<property name="addr" value="下榕树"></property>
</bean>
</beans>
3.解析applicationContext.xml实现springIOC:
public class ClassPathXmlApplicationContext {
private String pathXml = null;
public ClassPathXmlApplicationContext(String pathXml) {
this.pathXml = pathXml;
}
public Object getBean(String beanId) throws Exception {
if (StringUtils.isEmpty(beanId)) {
throw new Exception("beanId is null");
}
//解析xml
SAXReader saxReader = new SAXReader();
//this.getClass().getClassLoader().getResource(pathXml)表示获取resource下的xml路径
Document read = saxReader.read(this.getClass().getClassLoader().getResource(pathXml));
// 获取到根节点
Element rootElement = read.getRootElement();
// 根节点下所有的子节点
List<Element> elements = rootElement.elements();
for (Element element : elements) {
// 获取到节点上的属性
String id = element.attributeValue("id");
if (StringUtils.isEmpty(id)) {
continue;
}
if (!id.equals(beanId)) {
continue;
}
// 使用java反射机制初始化对象
String beanClass = element.attributeValue("class");
Class<?> forName = Class.forName(beanClass);
Object newInstance = forName.newInstance();
List<Element> propertyElementList = element.elements();
//使用java的反射机制给私有属性赋值
for (Element el : propertyElementList) {
String name = el.attributeValue("name");
String value = el.attributeValue("value");
Field declaredField = forName.getDeclaredField(name);
declaredField.setAccessible(true);
declaredField.set(newInstance, value);
}
return newInstance;
}
return null;
}
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext classPath = new ClassPathXmlApplicationContext("applicationContext.xml");
ReflectUser reflectUser = (ReflectUser) classPath.getBean("reflectUser");
System.out.println(reflectUser.getName()+ "---" + reflectUser.getAddr());
}
}
运行结果: