今日目标
- xml
- 反射
一.xml
1.xml简介
可扩展标记语言,简称XML。是一种用于标记电子文件使其具有结构性的标记语言言。 在电子计算机中,标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种的信息比如文章等。它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 它非常适合万维网传输,提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。是Internet环境中跨平台的、依赖于内容的技术,也是当今处理分布式结构信息的有效工具。早在1998年,W3C就发布了XML1.0规范,使用它来简化Internet的文档信息传输。
- 存储数据
- 传输数据
案例:
- 写一个xml文件,用来储存家庭的人口信息(姓名,年龄等)。
- 写一个xml文件,用来传输和好友的一段qq聊天信息(发送时间,信息文本内容,发送者,接收者)
<?xml version="1.0" encoding="UTF-8" ?>
<families>//根标签
<family>
<person>
<name>父亲</name>
<age>36</age>
</person>
<person>
<name>母亲</name>
<age>35</age>
</person>
</family>
<family>
<person>
<name>父亲</name>
<age>36</age>
</person>
<person>
<name>母亲</name>
<age>35</age>
</person>
</family>
</families>
- 总结特点
1.必须要有一个根标签
2.任意标签之间只能是包含关系或并列关系,合理的嵌套
3.除了标签体,还可以有属性和文本
4.xml中没有内置任何标签,没有内置任何属性。所以:标签和属性都是自定义的。
xml的创建
2.xml解析
- 解析方式
DOM(Document Object Model)解析:是基于 XML 文档树结构的解析,整颗树加载到内存中,耗内存,可多次获取。
SAX(Simple API for XML)解析:是基于事件流的解析。效率高,数据量小,仅一次获取 。
DOM4J解析:融合了Dom和Sax的优点,即能保证效率,同时也可多次获取。著名的开发框架Spring和Hibernate都使用了Dom4j的功能。
2.1查询
- 先导入jar包: dom4j-1.6.1.jar
@Test//获取xml中的数据
public void test1() throws DocumentException {
//1.获取sax解析器对象
SAXReader reader = new SAXReader();
//2.读取某个xml文件--返回一个文档对象,表示整个xml文档树
Document doc = reader.read("src/xml1/a.xml");
//3.获取跟标签
Element root = doc.getRootElement();
//4.逐级向下寻找标签
Element family1 = (Element) root.elements("family").get(0);
Element person1 = (Element)family1.elements("person").get(0);
Element age = person1.element("age");
System.out.println(age.getText());//获取标签的文本内容
}
<?xml version="1.0" encoding="UTF-8"?>
<msgs>
<msg>
<time>2020-1-1 00:00:00</time>
<content>宝贝,生日快乐!</content>
<sender>1025652</sender>
<receiver>4568422</receiver>
</msg>
<msg>
<time>2020-1-2 10:00:00</time>
<content>我们就这样吧!</content>
<sender>4568422</sender>
<receiver>1025652</receiver>
</msg>
<msg2>
<time>2020-1-2 10:00:00</time>
<content>我们就这样吧!</content>
<sender>4568422</sender>
<receiver>1025652</receiver>
</msg2>
<msg3>
<content>元旦快乐!</content>
</msg3>
</msgs>
@Test//查询
public void test1() throws Exception {
//1.创建一个解析器
SAXReader reader = new SAXReader();
//2.读取某个xml文件,返回xml对应的dom文档树
Document doc = reader.read("src/xml/msg.xml");
//3.获取根标签
Element root = doc.getRootElement();
System.out.println(root.getName());
//4.1 获取所有子标签
List <Element> msgs = root.elements();
for (Element msg : msgs) {
System.out.println(msg.getName());
}
//4.1 获取第一个子标签--2种方式
Element e = msgs.get(0);
System.out.println(e.getName());
Element ee = root.element("msg");
System.out.println(ee.getName());
//4.2 使用迭代器获取子标签
Iterator it = e.elementIterator();
while (it.hasNext()){
Element e1 = (Element) it.next();
System.out.println(e1.getName()+"--"+e1.getText());
}
}
- 案例:输出湖北和山东的城市名称
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.Iterator;
import java.util.List;
public class Testchina {
public static void main(String[] args) throws DocumentException {
SAXReader reader = new SAXReader();
Document doc = reader.read("day22-java22/src/xml/china.xml");
Element root = doc.getRootElement();
System.out.println(root.getName());
System.out.println("---------");
List<Element> c = root.elements();
for (Element c1 : c) {
System.out.println(c1.getName());
}
System.out.println("---------");
Element bj = root.element("北京");
Iterator it = bj.elementIterator();
while (it.hasNext()){
Element next = (Element) it.next();
System.out.println(next.getName());
}
}
}
2.2增删改
-
文档对象的来源
- 文档对象可以是通过SaxReader获取到的
- 也可以是DocumentHelper.createDocument();
-
增删改操作都需要将文档对象重新写入xml文件,用更新后的dom去覆盖之前的dom树
//1.准备输出流--可以尝试用System.out
FileOutputStream out = new FileOutputStream("src/xml/b.xml");
//2.准备格式化对象
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("utf-8");
//3.构建xml输出流对象
XMLWriter writer = new XMLWriter(out,format);
//4.将文档对象,写入输出流
writer.write(doc);
//5.刷新缓冲区,关闭资源
writer.close();
@Test//新增
public void test2()throws Exception{
//一.构建文档树
//1.创建一个解析器
SAXReader reader = new SAXReader();
//2.读取某个xml文件,返回xml对应的dom文档树
Document doc = reader.read("src/xml/msg.xml");
//3.获取根标签
Element root = doc.getRootElement();
//4.给根标签加一个子标签
Element msg3 = root.addElement("msg3");
Element content = msg3.addElement("content");
content.setText("元旦快乐!");
//二.用新的文档树覆盖旧的文档树
//1.借助字节输出流
FileOutputStream out = new FileOutputStream("src/xml/msg.xml");
//2.需要一个格式美化对象
OutputFormat format = OutputFormat.createPrettyPrint();
//3.根据上面的2个对象,构建一个xml输出流对象
XMLWriter writer = new XMLWriter(out,format);
//4.将doc文档树 重新写入 xml文件中
writer.write(doc);
//5.关闭流--刷新缓冲区
writer.close();
}
@Test//新增--场景2
public void test3()throws Exception{
//1.创建一个文档对象--dom树
Document doc = DocumentHelper.createDocument();
//2.添加根元素
Element root = doc.addElement("heroes");
//3.添加子元素
Element hero = root.addElement("hero");
Element name = hero.addElement("name");
Element age = hero.addElement("age");
//4.给子元素设置文本
name.setText("曹操");
age.setText("26");
//5.将上面创建的dom树,写进一个xml文件中
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("src/xml/heroes.xml"), OutputFormat.createPrettyPrint());
xmlWriter.write(doc);
}
- 案例:
- 给family.xml中新增一个成员
- 修改某个成员的年龄
- 删除某个成员
二.Reflect
1.反射概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
理解Reflect
- 反射
- 反转
理解为控制反转,权力的反转:
每一个人都有活着的权力,行动和自由的权力;每一个类都有创建对象,调用属性和方法的权力。现在将类的这些权力转交给Class对象,让它来帮助某个类去完成这些操作。
- 理解Class
每一个实体类都会被编译成字节码文件,java中万事万物都是对象,那么天下所有的字节码文件都可以看成是对象,谁的对象呢? 当然得有一个类,来代表所有的字节码文件,这个类就是Class类。
即:所有实体类文件被编译成字节码文件后,都可以看成是Class类的对象。
例如:
Class c=Dog.class; //Dog.class就表示Dog类文件被编译后的字节码文件
2.反射功能\
- 三种方式获取Class对象
@Test//获取Class --范围:所有的字节码文件
public void test1() throws ClassNotFoundException {
//方式1--通过类名
Class c=Dog.class;//Dog.java编译后的字节码文件
Class c1=Book.class;//Book.java编译后的字节码文件
//方式2--通过对象
Class c3 = new Dog().getClass();
//方式3--通过类路径
Class c4 = Class.forName("reflect1.Book");
}
@Test//任意一个类,获取Class对象
public void test1() throws ClassNotFoundException {
//1.类名.class
Class<reflect.Hero> c1 = reflect.Hero.class;//代指Hero.java被编译后的字节码文件
//2.对象的getClass方法
Class <? extends reflect.Hero> c2=new Hero().getClass();
//3.Class的静态方法forName
Class<?> c3 = Class.forName("reflect.Hero");
}
@Test
public void test1() throws ClassNotFoundException {
Class<Hero> c1=Hero.class;
Class c11=Hero.class;
Class<? extends Hero> c2=new Hero().getClass();
Class c22=new Hero().getClass();
Class<?> c3=Class.forName("reflect.Hero");
Class c33=Class.forName("reflect.Hero");
}
Hero类
public class Hero {
private String name;
private int age;
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Hero() {
System.out.println("无参构造");
}
public Hero(int age) {
this.age = age;
}
public Hero(String name) {
this.name = name;
}
public Hero(String name, int age) {
System.out.println("有参构造");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- 管理无参构造
//1.管理无参构造
@Test
public void test2() throws Exception {
//1.获取到某个类的字节码文件对象,即Class的对象
Class<Dog> c = Dog.class;
//2.帮Dog调用无参构造
Dog dog = c.newInstance();
System.out.println(dog);
}
- 管理有参构造
//2.管理有参构造
@Test
public void test3() throws Exception {
//1.获取到某个类的字节码文件对象,即Class的对象
Class<Dog> c = Dog.class;
//2.获取有参构造的管理对象--2个参数的那个
Constructor<Dog> con = c.getDeclaredConstructor(String.class,int.class);
//3.帮助Dog类调用有参构造
Dog dog = con.newInstance("旺财",2);
System.out.println(dog);
}
@Test
public void test2() throws Exception {
Class<Hero> c1=Hero.class;
Hero hero=c1.newInstance();
System.out.println(hero);
System.out.println("------------");
//Constructor<Hero> con = c1.getDeclaredConstructor(String.class, int.class);
Constructor<Hero> con = c1.getDeclaredConstructor(String.class, int.class);
Hero hero1 = con.newInstance("貂蝉", 16);
System.out.println(hero1);
Constructor<Hero> con1 = c1.getDeclaredConstructor(String.class);
Hero hero2 = con1.newInstance("貂蝉");
System.out.println(hero2);
}
- 管理属性
//3.管理属性
@Test
public void test4() throws Exception {
//1.获取到某个类的字节码文件对象,即Class的对象
Class<Dog> c = Dog.class;
//2.获取某个属性的管理对象
Field f = c.getDeclaredField("name");
//先创建一个狗狗对象
Dog dog = c.newInstance();
f.setAccessible(true);//开启私有属性操作权限
//3.帮助dog给name属性赋值
f.set(dog,"来福");
System.out.println(dog);
}
@Test
public void test3() throws Exception {
Class<Hero> c1=Hero.class;
Field f = c1.getDeclaredField("name");
Hero h = c1.newInstance();
f.setAccessible(true);
f.set(h,"曹操");
System.out.println(h);
Field f1 = c1.getDeclaredField("age");
Hero h2 = c1.newInstance();
f1.setAccessible(true);
f1.set(h2,12);
System.out.println(h2);
/* f1.setAccessible(true);
f1.set(h,12);
System.out.println(h);//Hero{name='曹操', age=12}*/
}
- 管理方法
//4.管理方法
@Test
public void test5() throws Exception {
//1.获取到某个类的字节码文件对象,即Class的对象
Class<Dog> c = Dog.class;
//2.获取某个方法setAge(int age)的管理对象
Method m = c.getDeclaredMethod("setAge", int.class);
//先创建一个狗狗对象
Dog dog = c.newInstance();
//3.帮助dog给调用setAge方法
m.invoke(dog,3);
//System.out.println(dog);
//管理toString方法
Method m2 = c.getDeclaredMethod("toString");
System.out.println(m2.invoke(dog));
}
@Test
public void test4() throws Exception {
Class<?>c1=Class.forName("reflect.Hero");
Method toString = c1.getDeclaredMethod("toString");
System.out.println(toString.invoke(c1.newInstance()));
System.out.println("---------");
Method setName = c1.getDeclaredMethod("setName", String.class);
Method setAge = c1.getDeclaredMethod("setAge", int.class);
Hero hero = (Hero) c1.newInstance();
setName.invoke(hero,"曹操");
Hero hero2 = (Hero) c1.newInstance();
setAge.invoke(hero,21);
System.out.println(hero);
System.out.println(hero2);
}
3.案例
反射结合泛型案例
将一个map中的数据转存到一个实体类对象中。
@Test//案例一:将一个map中的数据转存到一个实体类对象中。
public void test5() throws Exception {
HashMap<String, Object> map = new HashMap<>();
map.put("name","旺财");
map.put("age",3);
Dog dog = getObject(map, Dog.class);
System.out.println(dog);
}
public <T>T getObject(Map<String,Object> map, Class<T> c) throws Exception {
T t = c.newInstance();
//1.拆开map
Set<Map.Entry<String, Object>> entries = map.entrySet();
for (Map.Entry<String, Object> entry : entries) {
String key = entry.getKey();
//2.将map中的值存入T这个类的对象属性中
Field f = c.getDeclaredField(key);
f.setAccessible(true);
f.set(t,entry.getValue());
}
return t;
}
xml和反射综合案例
- 宠物管理系统
1.预先定义好父类:动物类,子类:狗狗类,企鹅类,大象类,
2.在xml文件中配置各个宠物类的全路径名
3.编写一个宠物领养方法,根据用户输入的宠物名称,从xml读取相应的类路径,使用反射构建宠物对象,并返回。
注意:使用父类作为方法返回值,字符串作为参数。
<?xml version="1.0" encoding="UTF-8" ?>
<animal>
<狗狗>
<name>旺财</name>
<class>reflect.pet.Dog</class>
</狗狗>
<企鹅>
<name>皮皮</name>
<class>reflect.pet.Penguin</class>
</企鹅>
<大象>
<name>肉肉</name>
<class>reflect.pet.Elephant</class>
</大象>
</animal>
@Test
public void test1() throws Exception {
Scanner sc=new Scanner(System.in);
System.out.println("请选择您要领养的宠物:狗狗,企鹅,大象");
String name = sc.next();
Animal animal = getAnimal(name);
System.out.println(animal);
}
public Animal getAnimal(String name) throws Exception {
// 1.创建解析器
SAXReader reader = new SAXReader();
// 解析xml文档,得到document对象
Document document = reader.read("src/reflect1/pet/pet.xml");
// 根据document对象获取根节点
Element root = document.getRootElement();
// 查找根节点下的子节点 element() elements()
Element animal = root.element(name);
String className = animal.element("class").getText();
//2.使用反射创建对象
return (Animal) Class.forName(className).newInstance();
}
作业
1.动物园新进了3头大象:
胖胖,2岁,1.2吨;
肥仔,1岁,1.5吨;
憨憨,3岁,1.8吨;
还有3只猴子:
星仔,3岁,0.8米;
狒狒,4岁,0.9米;
猴哥,5岁,1.0米;
它们的信息存在了集合中,现在动物管理员需要将这些宝贝们的信息存入xml中保存.请你写一个程序,结合面向对象,和dom4j技术,帮管理员实现这个功能。
package work1.one;
public class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package work1.one;
public class Elephant extends Animal {
private double weight;
public Elephant() {
}
public Elephant(double weight) {
this.weight = weight;
}
public Elephant(String name, int age, double weight) {
super(name, age);
this.weight = weight;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
package work1.one;
public class Monkey extends Animal{
private double height;
public Monkey() {
}
public Monkey(double height) {
this.height = height;
}
public Monkey(String name, int age, double height) {
super(name, age);
this.height = height;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
}
package work1.one;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import java.io.FileOutputStream;
import java.util.ArrayList;
public class Test1 {
public static void main(String[] args) throws Exception {
ArrayList<Animal> animals = new ArrayList<>();
animals.add(new Elephant("胖胖",2,1.3));
animals.add(new Elephant("肥仔",1,1.5));
animals.add(new Elephant("憨憨",3,1.8));
animals.add(new Monkey("星仔",3,0.8));
animals.add(new Monkey("狒狒",4,0.9));
animals.add(new Monkey("猴哥",5,1.0));
createXml(animals);
}
public static void createXml(ArrayList<Animal> animals) throws Exception {
//创建一个dom树
Document doc = DocumentHelper.createDocument();
//添加根节点
Element ani = doc.addElement("animals");
//遍历集合
for (int i = 0; i < animals.size(); i++) {
//添加子节点
Element a = ani.addElement("animal");
//给子节点添加子节点
Element name = a.addElement("name");
name.setText(animals.get(i).getName());
Element age = a.addElement("age");
//age.setText(Integer.toString(animals.get(i).getAge()));
//age.setText(String.valueOf(animals.get(i).getAge()));
age.setText(animals.get(i).getAge()+"岁");
//判断 是大象还是猴子
if(animals.get(i) instanceof Elephant){
Element weight = a.addElement("weight");
weight.setText(((Elephant) animals.get(i)).getWeight()+"吨");
}else {
Element height = a.addElement("height");
height.setText(((Monkey) animals.get(i)).getHeight()+"米");
}
}
//写入xml中
FileOutputStream out = new FileOutputStream("day23-java23/src/work1/one/animal.xml");
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(out, format);
writer.write(doc);
writer.close();
}
}
2.优化上面的宠物领养系统,将宠物名称的输出动态化,即:从xml文件中读取现有宠物名称,而不是直接写出,改进下面这行代码:
System.out.println("请选择您要领养的宠物:狗狗,企鹅,大象");
3.继续优化宠物领养系统,添加一个宠物捐献功能模块。整个系统称为宠物管理系统(包含领养和捐献两个功能)。开始需要询问客户是领养还是捐献。
在领养宠物后,需要删除xml中对应的标签。
在捐献功能中,接受用户输入的宠物类型(如:大象,狗狗)和宠物名称(如:肉肉,皮皮)。随即利用程序,实现在xml中添加相应的标签。注意:新的宠物类需要自己手动创建。