JavaSE(十四) --- <补充知识点> [XML文件,反射]

Posted 小智RE0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaSE(十四) --- <补充知识点> [XML文件,反射]相关的知识,希望对你有一定的参考价值。


XML文件

xml文件是可扩展性标记语言,是用来存储,传输数据的;

html作为超文本标记语言 (HyperText Markup Language);是用来显示数据的.

缺点就是xml的语法比较繁琐,早期还是要用Java语言解析xml文件,读写数据.

XML能对各种编程语言编写的数据进行管理,使得在任何平台下都能通过解析器来读取XML数据。


XML的命名规则

(1)名称没有字符限制,数字字母字符都可以用(没有保留字这个说法),但是不能以数字或者标点符号,或者以字符 “xml”(或者 XML、Xml)开始
(2)写名称不能包含空格;


就从Tomcat的web.xml配置文件来看吧

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"
         metadata-complete="true">
</web-app>

XML 主要分为4个部分,

  • 文档声明

声明文件的可选部分,若存在需要放在文档的第一行

<?xml version="1.0" encoding="UTF-8"?>
  • 元素(标签)

注意只能有一个根元素;元素中可嵌套其他元素,也可以出现空元素(即只写标签,内部不写内容)

需要注意的是,写的标签必须要闭合;

标签对大小写敏感

比如说,我在自定义xml文件时,上面开始写了一个根元素users ,但是下面又写出一个根元素,出现错误提示Multiple root tags(多个根标签)

  • 属性

属性是修饰元素的.

如果要在一个元素写比较多的属性时,注意属性名不要相同.
在写属性值的时候,记着别写 & 或者 ' 或者< ;而且属性值一定要用双引号或者单引号包括起来;

比如说,我在同一个标签name内写了两个属性名相同的属性word,诶,就出现错误了.
提示Duplicate attribute word(重复属性词)

  • 注释

注释使用<!---->;对需要说明的地方,写上自己的解释.


XML的语法规则

首先需要注意的是,不要随意留空格,空格会被保留;

在 XML 中,有 5 个预定义的实体引用:

引用表示含义
&lt;<小于 (less than)
&gt;>大于 (greater than)
&amp;&和 (ampersand)
&apos;单引号 (apostrophe)
&quot;"双引号 (quotation mark)

XML约束
可以写一个文档约束对xml的书写规范进行约束,

  • DTD约束:语法相对简单,功能简单。学习成本低。
  • Schema约束:语法相对复杂,功能强大。学习成本高.

而Tomcat的xml约束就是Schema约束;


反射

在之前需要获取一个类的对象时,首先需要设计定义一个类,然后才用new+构造方法的方式创建类的对象;然后才能通过对象去调用类的属性或方法.
但是这样的方式不太灵活

反射
而反射机制只需要类名就能动态获取得到类的信息,类的对象

实际上,在之前学习时也是接触过反射的;
比如说,在web.xml配置文件中配置servlet时,当时是通过类名获取到定义的servlet类信息

实际可理解为;先解析xml文件;然后读取到类的地址,根据类的地址,通过反射机制获取类的对象.

第二个情况就是在学习Jdbc时,加载类的机制就是用了反射.

Class.forName(“com.mysql.cj.jdbc.Driver”);


反射的理解
每当使用一个类时,类加载器就把类的字节码信息读取到内存中,并且为每个类创建一个class类的对象,通过Class对象即可获取类的信息.


练习时使用的实体类Person

public class Person {
    public String name;
    private int age;
    private int id;

    public Person(){
        System.out.println("无参构造方法");
    }

    public Person(String name,int id,int age){
        this.name=name;
        this.age=age;
        this.id=id;
        System.out.println("有参构造方法-->name-->id-->age");
    }

    private Person(int age){
        System.out.println("私有构造方法-->id");
    }

    public void run(){
        System.out.println("run方法");
    }

    public void run(String name){
        System.out.println("run方法-->name");
    }
    private void run(String name,int age){
        System.out.println("私有修饰run方法-->name-->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;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }     
}

获取Class类对象的三种方式
(1) 类名.class的方式

//方式1:直接用类名.class的方式;
Class person1 = Person.class;
System.out.println(person1);

返回

class com.xiaozhi.pojo.Person

(2)使用Object类的getClass()方法

//方式2;先获取到Person类的对象,然后使用getClass方式获取;
Person p=new Person();
Class person2 = p.getClass();
System.out.println(person2);

返回

无参构造方法
class com.xiaozhi.pojo.Person

(3)通过Class类的forName(String name)方法

//方式3:通过Class类的forName方法;前提是需要知道类的路径地址;
//根据Person类的地址,将类的信息加载到内存中,然后获得Class的对象;可动态操作类的信息;
Class person3 = Class.forName("com.xiaozhi.pojo.Person");
System.out.println(person3);

返回

class com.xiaozhi.pojo.Person

其实,这几种方式获取到的是一样的


获取类的构造方法信息

😃(1)Class类的 getConstructor() 方法可获取公共的无参构造方法

public Constructor getConstructor(Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException

Constructor类的 newInstance()方法也可以为类创建对象;

public Object newInstance(Object… initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, reflect.InvocationTargetException

练习

//通过Class类的forName方法;前提是需要知道类的路径地址;
Class person = Class.forName("com.xiaozhi.pojo.Person");

//Class类的 getConstructor() 方法;获取公共的无参构造方法;
Constructor constructor = person.getConstructor();
System.out.println(constructor);
//Constructor类的 newInstance 可为类创建对象;
Person p=(Person)constructor.newInstance();
System.out.println(p);

输出:

public com.xiaozhi.pojo.Person()
无参构造方法
com.xiaozhi.pojo.Person@74a14482

😃(2)Class类的getConstructor(Class<?>... parameterTypes)方法;获取公共的指定参数列表的有参构造方法;

public Constructor getConstructor(Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException

练习

//通过Class类的forName方法;前提是需要知道类的路径地址;
Class person = Class.forName("com.xiaozhi.pojo.Person");

//Class类的getConstructor(Class<?>... parameterTypes)方法;获取公共的指定参数列表的有参构造方法;
Constructor constructor = person.getConstructor(String.class,int.class,int.class);
System.out.println(constructor);
//根据得到的构造方法创建对象;
Person p=(Person)constructor.newInstance("小智",21,178);
System.out.println(p);

输出:

public com.xiaozhi.pojo.Person(java.lang.String,int,int)
有参构造方法-->name-->id-->age
com.xiaozhi.pojo.Person@74a14482

😃(3)Class类的getConstructors()方法;获取所有公共的构造方法;

public Constructor<?>[] getConstructors() throws SecurityException

练习:

//Class类的getConstructors() 方法;获取所有公共的构造方法;
Constructor[] constructors = person.getConstructors();
for (Constructor constructor : constructors) {
    System.out.println(constructor);
}

输出:

public com.xiaozhi.pojo.Person(java.lang.String,int,int)
public com.xiaozhi.pojo.Person()

😃(4)Class类的getDeclaredConstructor(Class<?>... parameterTypes) 方法,获取指定参数列表的构造方法;包括私有修饰的构造方法

public Constructor getDeclaredConstructor(Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException

练习

//通过Class类的forName方法;前提是需要知道类的路径地址;
Class person = Class.forName("com.xiaozhi.pojo.Person");

//Class类的getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数列表的构造方法;
Constructor declaredConstructor = person.getDeclaredConstructor(String.class,int.class,int.class);
System.out.println(declaredConstructor);
Constructor declaredConstructor1 = person.getDeclaredConstructor(int.class);
System.out.println(declaredConstructor1);

输出

public com.xiaozhi.pojo.Person(java.lang.String,int,int)
private com.xiaozhi.pojo.Person(int)

但是呢,拿到私有修饰的构造方法时,就需要解决权限问题;

 //通过Class类的forName方法;前提是需要知道类的路径地址;
Class person = Class.forName("com.xiaozhi.pojo.Person");

//涉及到私有修饰的方法时;
Constructor declaredConstructor1 = person.getDeclaredConstructor(int.class);
Person p= (Person) declaredConstructor1.newInstance(21);
System.out.println(p);

出现异常;提示IllegalAccessException 没有访问权限.

Exception in thread “main” java.lang.IllegalAccessException: Class com.xiaozhi.pojo.Test2 can not access a member of class com.xiaozhi.pojo.Person with modifiers “private”

那么就去设置手动打开权限;

Constructor类有这样一个父类AccessibleObject

有这样的一个方法setAccessible(boolean flag) 可以设置是否检查访问权限;默认为false

true的值表示反射对象应该在使用时抑制Java语言访问检查。 false的值表示反映的对象应该强制执行Java语言访问检查。

那就试试吧

//涉及到私有修饰的方法时;
Constructor declaredConstructor1 = person.getDeclaredConstructor(int.class);
//拒绝权限检查;
declaredConstructor1.setAccessible(true);
Person p= (Person) declaredConstructor1.newInstance(21);
System.out.println(p);

输出

私有构造方法-->id
com.xiaozhi.pojo.Person@74a14482

😃(5) Class类的getDeclaredConstructors() 获取所有的构造方法

public Constructor<?>[] getDeclaredConstructors() throws SecurityException

练习

//通过Class类的forName方法;前提是需要知道类的路径地址;
Class person = Class.forName("com.xiaozhi.pojo.Person");

//Class类的getDeclaredConstructors() 获取所有的构造方法
Constructor[] declaredConstructors = person.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
    System.out.println(declaredConstructor);
}

输出

private com.xiaozhi.pojo.Person(int)
public com.xiaozhi.pojo.Person(java.lang.String,int,int)
public com.xiaozhi.pojo.Person()

获取类的 属性; 和 方法

(1)Class类的getFields()方法; 获取所有公共属性;

public Field[] getFields() throws SecurityException

Filed类的 getName()方法;获取属性名;

public String getName()

Filed类的get(对象)方法;获取属性值;

public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException

练习

//通过Class类的forName方法;前提是需要知道类的路径地址;
Class person = Class.forName("com.xiaozhi.pojo.Person");
//先用构造方法创建一个对象;
Constructor declaredConstructor = person.getConstructor();
Person p= (Person) declaredConstructor.newInstance();
//Class类的 getFields() 方法获取所有公共属性;
Field[] fields = person.getFields();
for (Field field : fields) {
    //Filed类的 getName()方法;获取属性名;
    System.out.println("Person类的属性=>"+field.getName());
    //Filed类的 get(对象)方法;获取属性值;
    System.out.println("Person类的属性值=>"+field.get(p));
}

输出;

无参构造方法
Person类的属性=>name
Person类的属性值=>null

(2)Class类的getDeclaredFields()方法; 获取所有属性; 包括私有修饰的属性

public Field[] getDeclaredFields() throws SecurityException

练习

//通过Class类的forName方法;前提是需要知道类的路径地址;
Class person = Class.forName("com.xiaozhi.pojo.Person");
//先用构造方法创建一个对象;
Constructor declaredConstructor = person.getDeclaredConstructor(String.class,int.class,int.class);
Person p= (Person) declaredConstructor.newInstance("小智",21,178);
//Class类的 getDeclaredFields() 方法获取所有属性;
Field[] fields = person.getDeclaredFields();
for (Field field : fields) {
    //需要开启权限;
    field.setAccessible(true);
    //Filed类的 getName()方法;获取属性名;
    System.out.println("Person类的属性=>"+field.getName());
    //Filed类的 get(对象)方法;获取属性值;
    System.out.println("Person类的属性值=>"+field.get(p));
}

输出

有参构造方法-->name-->id-->age
Person类的属性=>name
Person类的属性值=>小智
Person类的属性=>age
Person类的属性值=>21
Person类的属性=>id
Person类的属性值=>178

(3)Class类的 getDeclaredMethod() 方法 获取指定名称,指定参数列表的方法

public Method getDeclaredMethod(String name, Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException

练习

//通过Class类的forName方法;前提是需要知道类的路径地址;
Class person = Class.forName("com.xiaozhi.pojo.Person");
// Class类的 getDeclaredMethod 方法 获取指定名称,指定参数列表的方法
Method run = person.getDeclaredMethod("run",String.class,int.class);
System.out.println(run);

输出

private void com.xiaozhi.pojo.Person.run(java.lang.String,int)

(4)Class类的 getDeclaredMethods() 方法,获取所有方法;

public Method[] getDeclaredMethods() throws SecurityException

练习

//通过Class类的forName方法;前提是需要知道类的路径地址;
Class person = Class.forName("com.xiaozhi.pojo.Person");

//Class类的 getDeclaredMethods() 方法,获取所有方法;
Method[] methods = person.getDeclaredMethods();
for (Method method : methods) {
    System.out.println(method);

输出

private void com.xiaozhi.pojo.Person.run(java.lang.String,int)
public void com.xiaozhi.pojo.Person.run(java.lang.String)
public void com.xiaozhi.pojo.Person.run()
public java.lang.String com.xiaozhi.pojo.Person.getName()
public int com.xiaozhi.pojo.Person.getId()
public void com.xiaozhi.pojo.Person.setName(java.lang.String)
public void com.xiaozhi.pojo.Person.setId(int)
public int com.xiaozhi.pojo.Person.getAge()
public void com.xiaozhi.pojo.Person.setAge(int)

以上是关于JavaSE(十四) --- <补充知识点> [XML文件,反射]的主要内容,如果未能解决你的问题,请参考以下文章

javaSE第二十四天

javaSE第十四天

零基础自学javase黑马课程第十四天

JavaSE第十四天20160822

Java知识补充

JAVASE(十四) 集合: 数组和集合CollectionIteratorListSetMap