什么是 XML?
XML 指可扩展标记语言(EXtensible Markup Language)。 XML 是一种很像HTML的标记语言。
XML的设计宗旨是传输数据,而不是显示数据。
XML 标签没有被预定义。您需要自行定义标签。
XML 被设计为具有自我描述性。 XML 是 W3C的推荐标准。
XML 和 HTML 之间的差异
XML 不是 HTML 的替代。。
XML 和 HTML 为不同的目的而设计:
XML 被设计用来传输和存储数据,其焦点是数据的内容。
HTML 被设计用来显示数据,其焦点是数据的外观。
HTML 旨在显示信息,而 XML 旨在传输信息。
一、什么是反射:
1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
二、反射的原理
下图是类的正常加载过程、反射原理与class对象:
Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
三、反射的优缺点:
1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
2、缺点:(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
四、反射的用途:
1、反编译:.class–>.java
2、通过反射机制访问java对象的属性,方法,构造方法等
3、当我们在使用IDE,比如Ecplise时,当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。
4、反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。
五、反射机制常用的类:
Java.lang.Class;
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;
1、获得Class:主要有三种方法:
(1)Object–>getClass
(2)任何数据类型(包括基本的数据类型)都有一个“静态”的class属性
(3)通过class类的静态方法:forName(String className)(最常用)
@Test
//获取Class --范围:所有的字节码文件
public void test1() throws ClassNotFoundException {
//方式一,通过类名
Class c = Dog.class; //Dog.java 编译后的字节码
Class c1 = Book.class; //Book.java编译后的字节码文件
// 方式二--通过对象
Class c3 = new Dog().getClass();
// 方式三--通过类路径
Class c4 = Class.forName("demo.Book");
System.out.println(c4);
System.out.println(c3);
}
2.创建实例:通过反射来生成对象主要有两种方法:
(1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。
//1.管理无参构造
@Test
public void test2() throws Exception {
//1.获取到某个类的字节码文件对象,即class的对象
Class<Dog> c = Dog.class;
// 2.帮你调用无参构造
Dog dog = c.newInstance();
System.out.println(dog);
}
(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建对象,这种方法可以用指定的构造器构造类的实例。
//2.管理有参构造
@Test
public void test3() throws Exception {
// 1.获取到某个类的字节码文件对象,即class的对象
Class<Dog> c = Dog.class;
// 2.获取有参构造的管理对象--2个参数的那个
Constructor<Dog> con = c.getDeclaredConstructor(String.class);
// 3.帮助Dog类调用有参构造
Dog dog = con.newInstance("旺财");
System.out.println(dog);
}
3、通过反射获取构造方法并使用:
(1)批量获取的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
(2)单个获取的方法,并调用:
public Constructor getConstructor(Class… parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class… parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
(3) 调用构造方法:
Constructor–>newInstance(Object… initargs)
newInstance是 Constructor类的方法(管理构造函数的类)
//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);
}
//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));
}
六、反射结合泛型案例
将一个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();
}