XML&反射

1.xml

1.1)什么是xml

xml全称为:Extensible Markup Language,即可扩展的标记语言。xml语法上和html相识,但html的标签是固定的,而xml的标签是用户自定义的

xml常用于:配置文件(例如:Servlet的配置),存放数据(极少,现在大多数使用json)

1.2)xml语法

文档声明:

a.必须以”<?xml“开头,以“?>”结束,

b.文档声明必须从文档的0行0列开始

c.文档声明只有三个属性:version(必须,xml版本,value=1.0),encoding(可选,编码方式,默认:UTF-8)

<?xml version="1.0" encoding="UTF-8"?>

元素:

a.元素的结构为标签-元素体-结束标签,例如:<hello>你好</hello>

b.元素体可以是元素,也可以是文本,例如:<a><b>hi</b></a>

c.空元素只有开始标签没有结束标签,自己闭合,例如:<a/>

d.命名规则:区分大小写,不能使用空格和冒号,以.xml文件名结尾,只有一个根元素(像html中的<head>)

属性:

a.属性是元素的一部分,出现在标签中,

b.格式:属性名="属性值",使用单引或双引

c.一个标签中可以有多个不同的属性,属性名不能有冒号、空格等特殊字符,必须以字母开头

注释:

<!-- 这是一行注释->d

转义字符:

在需要使用:“<”,“>”,“'”,“"”,“&”等,符号时就要用到转义字符。

<(&lt;),>(&gt;),'(&quot;),"(&apos;),&(&amp;)

如果有大量转义字符时,我们使用CDATA区

<![CDATA[
	任意字符	
]]>

1.3)xml约束

我们一般根据xml的约束文档编xml文件:常见的xml约束有:DTD约束,Schema约束,约束中的符号对照表

约束对照表

 

a.DTD约束

开发中我们很少自己编写DTD约束文档,通常使用框架提供的DTD约束文档:struts2,hibernate等框架

<?xml version="1.0" encoding="UTF-8"?>
<!--
	Servlet的DTD实例文档,提供头部文件如下:SYSTEM(DTD在本地),PUBLIC(DTD在网络上)
	<!DOCTYPE web-app SYSTEM "web-app_2_3.dtd">
-->
<!ELEMENT web-app (servlet*,servlet-mapping* , welcome-file-list?) >
<!ELEMENT servlet (servlet-name,description?,(servlet-class|jsp-file))>
<!ELEMENT servlet-mapping (servlet-name,url-pattern+) >
<!ELEMENT servlet-name (#PCDATA)>
<!ELEMENT servlet-class (#PCDATA)>
<!ELEMENT url-pattern (#PCDATA)>
<!ELEMENT description (#PCDATA)>
<!ELEMENT jsp-file (#PCDATA)>

<!ELEMENT welcome-file-list (welcome-file+)>
<!ELEMENT welcome-file (#PCDATA)>

<!ATTLIST web-app version CDATA #IMPLIED>

Servlet的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app SYSTEM "web-app_2_3.dtd">
<web-app version="1.0">
	<servlet>
		<servlet-name></servlet-name>
		<servlet-class></servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name></servlet-name>
		<url-pattern></url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file></welcome-file>
	</welcome-file-list>
</web-app>

 

b.Schema约束(重点掌握)

Schema是新的xml文档约束,是DTD的替代者,文件后缀名为(.xsd),支持名称空间(像java中的package),采用框架有sprin等

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
	Schema实例文档。模拟servlet2.5规范,头文件如下
	<web-app xmlns="http://www.example.org/web-app_2_5" 
			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
			version="2.5">
-->
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" 
	targetNamespace="http://www.example.org/web-app_2_5"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:tns="http://www.example.org/web-app_2_5" 
	elementFormDefault="qualified">
	
	<xsd:element name="web-app">
		<xsd:complexType>
			<xsd:choice minOccurs="0" maxOccurs="unbounded">
				<xsd:element name="servlet">
					<xsd:complexType>
						<xsd:sequence>
							<xsd:element name="servlet-name"></xsd:element>
							<xsd:element name="servlet-class"></xsd:element>
						</xsd:sequence>
					</xsd:complexType>
				</xsd:element>
				<xsd:element name="servlet-mapping">
					<xsd:complexType>
						<xsd:sequence>
							<xsd:element name="servlet-name"></xsd:element>
							<xsd:element name="url-pattern" maxOccurs="unbounded"></xsd:element>
						</xsd:sequence>
					</xsd:complexType>
				</xsd:element>
				<xsd:element name="welcome-file-list">
					<xsd:complexType>
						<xsd:sequence>
							<xsd:element name="welcome-file" maxOccurs="unbounded"></xsd:element>
						</xsd:sequence>
					</xsd:complexType>
				</xsd:element>
			</xsd:choice>
			<xsd:attribute name="version" type="double" use="optional"></xsd:attribute>
		</xsd:complexType>
	</xsd:element>
</xsd:schema>

Servlet的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://www.example.org/web-app_2_5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
	version="2.5">

	<servlet>
		<servlet-name>helloServlet</servlet-name>
		<servlet-class>xxxxxxxxxx</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>helloServlet</servlet-name>
		<url-pattern>/hello</url-pattern>
	</servlet-mapping>
</web-app>

2.dom4j解析

当数据存储在xml后我们就希望获取xml中的内容,这时就需要对xml文件进行解析。

导入jar包:dom4j-1.6.1.jar,jaxen-1.1-beta-6.jar

2.2)解析方式和解析器

a.常见的解析方式

DOM:把整个xml文档加载到内存 并解析成一个Document对象,优点(元素间保留了结构关系,可以进行增、删、改操作)缺点(xml文档过大会有内存溢出情况)

SAX:速度快,边扫描边解析,优点(处理速度快,可以处理大文件)缺点(只能读,扫描后即会释放资源)(了解)

PULL:android内置的解析方式,类似SAX(了解)

b.常见的解析开发包

JAXP:sun公司提供支持DOM和SAX开发包

JDom:dom4j兄弟

jsoup:一种处理html特定解析开发包

dombi:比较常用的解析开发包,hibernate底层采用

2.3)xml DOM

xml DOM 和 html DOM类似,是将整个xml加载到内存,生成一个DOM树,并获得一个Document对象,通过Document对象就可以对DOM进行操作

文档(Document),元素(Element),属性(Attrbute),文本(text)

DOM中的核心概念就是节点,在xml文档中的元素、属性、文本等,在DOM中都是节点!

2.4)API

a.SAXReader对象

read(...):加载执行xml文档

b.Document对象

getRootElement():获取根元素

c.Element对象

elements(...):获取指定名称所有的子元素,可以不指定名称

element(...):获取指定名称第一个子元素,可以不指定名称

getName():获取当前元素名称

element(...):获取指定属性名称的属性值

elementText(...):获取指定名称的子元素的文本值

getText():获取当前元素的文本内容

@Test
	public void testReadWebXML() {
		try {
			// 1.获取解析器
			SAXReader saxReader = new SAXReader();
			// 2.获得document文档对象
			Document doc = saxReader.read("src/web.xml");
			// 3.获取根元素
			Element rootElement = doc.getRootElement();
			// System.out.println(rootElement.getName());//获取根元素的名称
			// System.out.println(rootElement.attributeValue("version"));//获取根元素中的属性值
			// 4.获取根元素下的子元素
			List<Element> childElements = rootElement.elements();
			// 5.遍历子元素
			for (Element element : childElements) {
				//6.判断元素名称为servlet的元素
				if ("servlet".equals(element.getName())) {
					//7.获取servlet-name元素
					Element servletName = element.element("servlet-name");
					//8.获取servlet-class元素
					Element servletClass = element.element("servlet-class");
					System.out.println(servletName.getText());
					System.out.println(servletClass.getText());
				}
			}

		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}

3.反射

java反射机制动态获取指定类及类中的方法和属性,并运行其内容,极大的提高了程序的扩展性

运行状态中,对于任意一个类都能知道其属性和方法,并且能够调用属性和方法

使用反射,可以在运行时对类Class构造方法Constructor普通方法Method字段Field进行操作

栗子:程序已经运行,无法在其中new对象的建立,就无法使用对象。根据配置文件的类全名去找对应的字节码文件,并加载进内存,并创建该类的实例。

@Test
	public void testMyServlet(){
		try {
			//1.通过servletClass获取字节码文件
			Class clazz = Class.forName("com.imwj.servlet.ImServlet");
			//2.通过字节码文件创建实例对象
			Object obj = clazz.newInstance();
			//3.通过字节码文件获取方法(两个参数:第一个是方法名称;第二个参数是方法的参数)
			Method method = clazz.getMethod("service", null);
			//4.调用invoke方法执行实例对象里面的方法(前面写的方法init)【两个参数:第一个是调用方法的实例对象,第二个是方法的实参】
			method.invoke(obj, null);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

3.2)四大对象操作

a.Class对象:是对Class文件(字节码文件)的描述对象

获得Class对象:

已知类的全名(完整路径名):Class.forName(...)

Class clazz = Class.forName(className);

常用方法:

newInstance():使用默认的构造方法创造对象实例

Object obj = clazz.newInstance();

 

b.Constructor对象:是构造方法的描述对象

常用方法:

newInstance(Object...initargs)

 

c.Method对象:普通方法的描述对象

获得公共方法:

getMethod("方法名", 方法参数)

Method method = clazz.getMethod("方法名", null);

执行指定方法:

invoke(指定对象, 方法的实参(一般为null))

method.invoke(实例化对象, null);

 

d.Field对象:字段的描述对象(属性)

获得方法:

所有字段:getField("String name"),可以指定字段名称

声明字段:getDeclaredField("String name"),可以指定字段名称

Field field = clazz.getDeclaredField("age");

常用方法:

获取内容:get(Object obj),obj即实例化对象

设置内容:set(Object obj),obj即实例化对象

field.set(obj, 789);/对私有访问,必须取消对其的访问控制检查field.setAccessible(true);

一个有点长的例子:有一个ImServletImpl方法(servlet需要在web.xml中配置),通过dom4j解析web.xml文件得到ImServletImpl方法的全民(包含路径),再利用反射调用其中的service方法打印消息。

public class testServlet2 {
	//8.创建一个map集合
		private HashMap<String, String> data = new HashMap<String,String>();
		
		//@Test执行前会执行@Before
		@Before
		public void testReadWEBXml(){
			try {
				//1.创建解析器对象
				SAXReader saxReader = new SAXReader();
				//2.使用解析器加载web.xml文件得到document对象
				Document document = saxReader.read("src/web.xml");
				//3.获取根元素节点
				Element rootElement = document.getRootElement();
				//4.获取子节点(servlet和servlet-mapping)
				List<Element> childElements = rootElement.elements();
				//5.遍历
				for (Element element : childElements) {
					//6.判断元素的名称为servlet的元素节点
					if("servlet".equals(element.getName())){
						//7.分别获取servlet元素节点的servlet-name和servlet-class的值
						String servletName = element.element("servlet-name").getText();
						String servletClass = element.element("servlet-class").getText();
						System.out.println(servletName);
						System.out.println(servletClass);
						data.put(servletName, servletClass);
					}
					//9.判断元素的名称为servlet-mapping的元素节点
					if("servlet-mapping".equals(element.getName())){
						//10.分别获取servlet元素节点的servlet-name和servlet-class的值
						String servletName = element.element("servlet-name").getText();
						String urlPattern = element.element("url-pattern").getText();
						//11.将servletName作为key来获取servletClass的值
						String servletClass = data.get(servletName);
						//12.将url-pattern作为key,servletClass作为value存到map中去
						data.put(urlPattern, servletClass);
						System.out.println(urlPattern);
						System.out.println(servletClass);
						//13.移除servletName
						data.remove(servletName);
					}
				}
				//System.out.println(data);
				
			} catch (DocumentException e) {
				e.printStackTrace();
			}
		}
		
		@Test
		public void testMyServlet(){
			try {
				
				//1.模拟在浏览器输入一个url
				String url1 = "/ImServletImpl";
				//2.将urlPattern作为key来获取servletClass
				String className = data.get(url1);
				//3.通过servletClass获取字节码文件
				Class clazz = Class.forName(className);
				//4.通过字节码文件创建实例对象
				Object obj = clazz.newInstance();
				//5.通过字节码文件获取方法(两个参数:第一个是方法名称;第二个参数是方法的参数)
				Method method = clazz.getMethod("service", null);
				//6.调用invoke方法执行实例对象里面的方法(前面写的方法init)【两个参数:第一个是调用方法的实例对象,第二个是方法的实参】
				method.invoke(obj, null);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
}

猜你喜欢

转载自blog.csdn.net/langao_q/article/details/81075465
今日推荐