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+构造方法的方式创建类的对象;然后才能通过对象去调用类的属性或方法.
但是这样的方式不太灵活;

还有通过IO流的反序列化获取对象;

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

实际上,在之前学习时也是接触过反射的;
比如说,在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

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

在这里插入图片描述

可以用Class类的 newInstance()方法 创建这个Class对象的对应的类的对象.


获取类的构造方法信息

😃(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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小智RE0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值