XML全称为Extensible Markup Language,意思是可扩展的标记语言。
W3C在1998年2月发布1.0版本,2004年2月又发布1.1版本,但因为1.1版本不能向下兼容1.0版本,所以1.1很少有人使用。同时,在2004年2月W3C又发布了1.0版本的第三版。所以我们通常使用1.0版本。
类似于Java代码:
class Person{ String id; String name; } public void test(){ HashSet<Person> persons=new HashSet<Person>(); persons.add(new Person("p001","张三")); persons.add(new Person("p002","李四")); } 配置文件(properties) <?xml version="1.0" encoding="UTF-8"?> <beans> <bean className="com.baidu.User"> <property name="username" value="jack"></property> </bean> </beans>类似于Java代码:
class Bean{ private String username; private String pws; //补全set\get方法 } import com.baidu.User; public static void main(){ Class clazz = Class.forName("com.baidu.User"); Object obj = clazz.newInstance(); Method method = clazz.getMethod("setUsername",String.class); method.invoke(obj,"jack"); }当大量的转义字符出现在XML文档中时,会使xml文档的可读性大幅度降低,这是如果使用CDATA段就会好一些。
在CDATA段中出现的“<”、“>”、“””、“’”、“&”,都无需使用转义字符。这可以提高xml文档的可读性。
在CDATA段中不能包含“]]>”,即CDATA段结束定界符。
在XML技术里,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束
常见的xml约束:DTD、Schema
DTD(Document Type Definition),文档类型定义,用来约束XML文档。规定XML文档中元素的名称,子元素的名称及顺序,元素的属性等。
开发中,我们很少自己编写DTD约束文档,通常情况我们都是通过框架提供的DTD约束文档,编写对应的XML文档,常见的框架使用DTD约束有:struts2、hibernte等。 通过提供的DTD“bean.dtd”编写xml
<?xml version="1.0" encoding="UTF-8"?> <!-- DTD实例文档。 模拟spring规范,如果开发人员需要在xml使用当前DTD约束,必须包括DOCTYPE。 格式如下: <!DOCTYPE beans SYSTEM "bean.dtd"> --> <!ELEMENT beans (bean*,import*) > <!ELEMENT bean (property*)> <!ELEMENT property (#PCDATA)> <!ELEMENT import (#PCDATA)> <!ATTLIST bean id CDATA #REQUIRED className CDATA #REQUIRED > <!ATTLIST property name CDATA #REQUIRED value CDATA #REQUIRED > <!ATTLIST import resource CDATA #REQUIRED>大概了解一下
什么是Schema Schema是新的XML文档约束; Schema要比DTD强大很多,是DTD替代者 Schema本身也是XML文档,但Schema文档的扩展名为xsd,而不是xml Schema功能更加强大,数据类型更完善 Schema支持名称空间
Schema重点要求 与DTD一样,要求可以通过Schema约束文档编写xml文档,常见的框架使用Schema的有:spring等。
通过提供“bean-schema.xsd”编写文档
<?xml version="1.0" encoding="UTF-8"?> <!-- Schema实例文档。 模拟spring规范,如果开发人员需要在xml使用当前Schema约束,必须包括指定命名空间。 格式如下: <beans xmlns="http://www.spring.cn/bean" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.spring.cn/bean bean-schema.xsd" > --> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.spring.cn/bean" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.spring.cn/bean" elementFormDefault="qualified"> <!-- 声明根标签 --> <element name="beans"> <complexType> <choice minOccurs="0" maxOccurs="unbounded"> <element name="bean"> <complexType> <sequence minOccurs="0" maxOccurs="unbounded"> <element name="property"> <complexType> <attribute name="name" use="required"></attribute> <attribute name="value" use="required"></attribute> </complexType> </element> </sequence> <attribute name="id" use="required"></attribute> <attribute name="className" use="required"></attribute> </complexType> </element> <element name="import"> <complexType> <attribute name="resource" use="required"></attribute> </complexType> </element> </choice> </complexType> </element> </schema> 命名空间(语法) 什么是命名空间 如果一个XML文档中使用多个Schema文件,而这些Schema文件中定义了相同名称的元素时就会出现名字冲突。这就像一个Java文件中使用了import java.util.*和import java.sql.*时,在使用Date类时,那么就不明确Date是哪个包下的Date了。 总之名称空间就是用来处理元素和属性的名称冲突问题,与Java中的包是同一用途。如果每个元素和属性都有自己的名称空间,那么就不会出现名字冲突问题,就像是每个类都有自己所在的包一样,那么类名就不会出现冲突。 约束文档和XML关系 当W3C提出Schema约束规范时,就提供“官方约束文档”。我们通过官方文档,必须“自定义schema 约束文档”,开发中“自定义文档”由框架编写者提供。我们提供“自定义文档”限定,编写出自己的xml文档。当将数据存储在xml后,我们就希望通过程序获得xml的内容,如果我们使用Java基础所学习的IO知识是可以完成的,不过你需要非常繁琐的操作才可以完成,且开发中会遇到不同的问题(只读、读写)。人们为不同问题提供不同的解析方式,并提交对应的解析器,方便开发人员操作xml。
开发中比较常见的解析方式有三种,如下: 1. DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象。 优点:元素与元素之间保存结构关系,故可以进行增删改查操作。 缺点:xml文档过大,可以出现内存溢出显现。 2. SAX:是一种速度更快,更有效的方法。它逐行扫描,一遍扫描一遍解析。 并以事件驱动的方式进行具体解析,每执行一行,都将触发对应的事件。 优点:处理速度快,可以处理大文件 缺点:只能读,逐行后将释放资源。 3. PULL:Android内置的xml解析方式,类似SAX。 解析器:就是根据不同的解析方式提供的具体实现,有的解析器操作过于繁琐,为了方便开发人员,有提供易于操作的解析开发包。常见的解析开发包JAXP:sun公司提供支持DOM和SAX开发包
JDom:dom4j兄弟
jsoup:一种处理HTML特定解析开发包
dom4j:比较常用的解析开发包,hibernate底层采用。
XML DOM将整个XML文档加载到内存,生成一个DOM树,并获得一个Document对象,通过Document对象就可以对DOM进行操作
DOM中的核心概念就是节点,在XML文档中的元素、属性、文本等,在DOM中都是节点。
dom4j 必须使用核心类SacReader加载xml文档获得Document,通过Document对象获得文档的根元素,然后就可以操作了。
常用API如下:
SaxReader对象 read(…)加载执行xml文档Document对象 getRootElement()获得根元素Element对象 elements(…)获得指定形成的所有子元素,可以不指定名称 element(…)获得指定名称的第一个子元素, 指定名称 getName() 获得当前元素的元素名 attributeValue(…) 获得指定属性名的属性值 elementText(…) 获得指定名称子元素的文本值 getText()获得当前元素的文本内容 public static void main(String[] args) throws Exception { SAXReader sax = new SAXReader(); // 加载执行XMl文档 Document document = sax.read( "D:\\Java\\Java8\\day0903\\beans.xml"); // 获得根元素 Element rootElement = document.getRootElement(); // 获得指定名称对的所有字元素。可以不指定名称 List<Element> list = rootElement.elements(); for(Element element :list){ List<Element> list1 = element.elements(); System.out.println(element.attributeValue("id")); System.out.println(element.attributeValue("className")); for (Element e : list1) { System.out.println(e.attributeValue("user")); System.out.println(e.attributeValue("value")); } } }benans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="001" className="com.baidu.demo.User"> <property name="user" value="jacl"></property> <property name="user" value="rose"></property> </bean> <bean id="002" className="com.baidu.demo.Admin"> <property name="user" value="admin"></property> <property name="user" value="write"></property> </bean> </beans>目前为止我们已经知道把class文件加载到内存做了哪些事情,那么,如果我们仅仅站在这些class文件的角度,我们如何来使用这些class文件内容呢?
Java反射机制是在运行状态中(和编译无关),对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。(框架的灵魂就是反射)
要想解刨一个类,必须先要获取到该类的字节码文件对象,而解刨这个类,使用的就是Class类中的方法,所以先要获取到每一个字节码文件所对应的Class类型对象。
类的加载器把要运行的类装进内存 类的加载器有三个: (1)引导类加载器:由C语言编写(加载使用的核心类库) (2)扩展类加载器:Java语言编写(加载JDK的扩展类库) (3) 应用类加载器:Java语言编写(加载我们写的类) Java.lang.ClassLoader表示类的加载器的对象 一个类智能被加载一次,不能被加载两次,(java类加载的双亲委派模型) 对象都是由类产生的类的加载器,负责运行的类加载到内存 一件事情:创建一个对象,创建A.Class文件的对象
无参构造,并获得实例
public void test DefaultCons() throws Exception{ //无参构造 , 并实例化 //1获得Class Class beanClass = Bean.class; //2获得构造 -- 没有形参 Constructor constructor = beanClass.getConstructor(); //3 实例对象,没有实参 Object bean = constructor.newInstance(); System.out.println(bean); /* 结果: * 无参构造 * com.baidu.Bean@8c5488 */ }有参构造,并获得实例
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 */ }无参构造,简化版获得实例
publicvoidtestDefaultSimple() throws Exception{ //无参构造 , 简化版 //1获得Class Class beanClass = Bean.class; //2 直接获得实例对象,两个字符串实参 Object bean = beanClass.newInstance(); System.out.println(bean); /* 结果: * 无参构造 * com.baidu.Bean@101acff */ }修改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 */ }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] */ }BeanUtils是Apache commons组件的成员之一,主要用于简化JavaBean封装数据的操作,它可以给JavaBean封装一个字符串数据,也可以将一个表单提交的所有数据封装到JavaBean中。
使用需要导入包:
commons-beanutils-1.8.3.jar commons-logging-1.1.1.jar工具类常用类有两个:BeanUtils、ConvertUtils。BeanUtils用于封装数据,ConvertUtils用于处理类型转换。
提供JavaBean User,并提供对应的构造方法 public class User { private String id; private String username; private String pwd; @Override public String toString() { return "User{" + "id='" + id + '\'' + ", username='" + username + '\'' + ", pwd='" + pwd + '\'' + '}'; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } } 设置属性 User user=new User(); /** * 设置属性 */ BeanUtils.setProperty(user,"id","001"); BeanUtils.setProperty(user,"username","zhangsan"); BeanUtils.setProperty(user,"pwd","1234"); System.out.println(user); 获得属性 /** * 获得属性 */ String id = BeanUtils.getProperty(user, "id"); String username = BeanUtils.getProperty(user, "username"); System.out.println(id); System.out.println(username); 封装表单数据,populate 方法 /** * 封装表单数据 */ Map<String,Object> properties=new HashMap<>(); properties.put("id","1001"); properties.put("username","lisi"); properties.put("pwd","111"); //批量设置属性 BeanUtils.populate(user,properties); System.out.println(user);