DW-CHEN的Java点滴记录之类加载器/反射机制/xml/DTD/Schema/枚举/注解/单元测试/日志技术

类加载器

负责将 .class文件(存储的物理文件)加载到内存中

  • 类加载的时机:用到就加载,不用不加载
  • 类加载的过程:加载,验证,准备,解析,初始化

类加载器的分类

1.启动类加载器(Bootstrap ClassLoader):虚拟机内置的类加载器
2.平台类加载器(Platform Classloader):负责加载JDK中一些特殊的模块
3.系统加载器(System Classloader):负责加载用户类路径上所指定的类库

双亲委派模型

package cn.cdw.demo;

/**
 * @author DW-CHEN
 * 双亲委派模型
 */
public class Demo134 {
    public static void main(String[] args) {
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        ClassLoader parent1 = systemClassLoader.getParent();
        ClassLoader parent2 = parent1.getParent();

        System.out.println("获得系统类加载器: "+systemClassLoader);
        System.out.println("获取系统加载器的父类,就是获取到了平台类加载器: "+parent1);
        System.out.println("获取平台控制器的父类,就是获取到了启动类加载器: "+parent2);
    }
}

类加载器

方法名说明
public static ClassLoader getSystemClassLoader()获取系统类加载器
public InputStream getResourceAsStream(String name)加载某一个资源文件

类加载器加载资源文件

package cn.cdw.demo;

import java.io.*;
import java.util.Properties;

/**
 * @author DW-CHEN
 * 类加载器加载资源文件
 */
public class Demo135 {
    public static void main(String[] args) throws IOException {
        Properties properties = new Properties();

        //写一些测试数据到资源文件
        properties.setProperty("小明", "12");
        properties.setProperty("小小", "21");
        properties.setProperty("小李", "15");

        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("src\\test.properties"));
        properties.store(bufferedWriter, null);

        //通过类加载器加载资源文件
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();//系统类加载器
        InputStream resourceAsStream = systemClassLoader.getResourceAsStream("test.properties");//读取资源文件

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resourceAsStream));
        properties.load(bufferedReader);
        System.out.println(properties);

        resourceAsStream.close();
        bufferedWriter.close();
    }
}

反射

在运行的状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意属性和方法,这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

  • 利用反射可以无视修饰符获取类里面的所有属性和方法

使用反射机制动态获取配置文件中的类名和方法名,进行创建对象和运行对应的方法

package cn.cdw.demo;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @author DW-CHEN
 * 反射机制
 * 使用反射机制动态获取配置文件中的类名和方法名,进行创建对象和运行对应的方法
 */
public class Demo136 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //properties,为了直观一些,这里我直接创建了配置文件和写入一些测试数据
        Properties properties = new Properties();

        properties.setProperty("className", "cn.cdw.demo.Student9");
        properties.setProperty("methodName", "play");

        FileOutputStream fileOutputStream = new FileOutputStream("src\\pro.properties");
        properties.store(fileOutputStream, null);
        fileOutputStream.close();

        //使用反射机制读取配置文件动态创建对象和调用方法
        InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream("pro.properties");//读取配置文件
        properties.load(resourceAsStream);//加载配置文件
        resourceAsStream.close();

        Class clazz = Class.forName(properties.getProperty("className"));//获取字节码文件的class对象对象
        Constructor constructor = clazz.getConstructor();//获取构造器对象
        Object newInstance = constructor.newInstance();//通过构造器对象创建一个对象
        Method methodName = clazz.getMethod(properties.getProperty("methodName"));//获取方法对象
        methodName.invoke(newInstance);//运行方法


    }
}

//学生
class Student9 {
    private String name;
    private int age;

    public Student9() {
    }

    public Student9(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;
    }

    public void play() {
        System.out.println("学生在玩.....");
    }
}


//老师
class Teacher {
    private String name;
    private int age;

    public Teacher() {
    }

    public Teacher(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;
    }

    public void work() {
        System.out.println("老师在工作.....");
    }
}

反射获取Class类的对象

  • Class.forName(“全类名”);
  • 类名.class
  • 对象.getClass

获取Class对象的三种方式

package cn.cdw.demo;

/**
 * @author DW-CHEN
 * 获取Class对象的三种方式
 */
public class Demo137 {
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("方式一:" + Class.forName("cn.cdw.demo.Student10"));
        System.out.println("方式二:" + Student10.class);
        System.out.println("方式三:" + new Student10().getClass());
    }
}

//学生
class Student10 {
    private String name;
    private int age;

    public Student10() {
    }

    public Student10(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;
    }

}

反射获取构造方法并使用

方法名说明
Constructor< ? >[] getConstructors()返回所有公共构造方法对象的数组
Constructor< ?>[] geDeclaredConstructors()返回所有构造方法对象的数组
Constructor< T > getConstructor(Class< ? >… parameterTypes)返回单个公共构造方法对象
Constructor< T > getDeclaredConstructor(Class< ? >… parameterTypes)返回单个构造方法对象
T newInstance(Object… initargs)Constructor类中用于创建对象的方法,根据指定的构造方法创建对象

注意:如果是私有的构造函数创建对象,那么需要临时取消检查,然后再创建对象
取消临时检查:setAccessible(boolean);暴力反射

反射机制获取构造方法
package cn.cdw.demo;

import java.lang.reflect.Constructor;

/**
 * @author DW-CHEN
 * 反射机制获取构造方法
 */
public class Demo138 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {

        System.out.println("===============================方式一:getConstructors()========================================");
        Class clazz = Class.forName("cn.cdw.demo.Student11");
        Constructor[] constructors = clazz.getConstructors();
        System.out.println("获得所有的公共构造方法:");
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        System.out.println();
        System.out.println("===============================方式二:getDeclaredConstructors()========================================");
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        System.out.println("获得所有的构造方法: ");
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }

        System.out.println();
        System.out.println("===============================方式三:getConstructor(Class<?>... parameterTypes)========================================");
        Constructor constructor = clazz.getConstructor(String.class, Integer.class);
        System.out.println("获取单个指定的公共构造方法:");
        System.out.println(constructor);

        System.out.println();
        System.out.println("===============================方式四:getDeclaredConstructor(Class<?>... parameterTypes)========================================");
        Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class);
        System.out.println("获取单个指定的私有构造方法: ");
        System.out.println(declaredConstructor);
    }
}

class Student11{
    private String name;
    private int age;

    public Student11() {//公共的无参构造方法

    }

    private Student11(String name) {//私有的带参数构造方法
        this.name = name;
    }

    public Student11(String name, Integer age) {//公共的带参数构造方法
        this.name = name;
        this.age = age;
    }
}
反射机制获取构造函数之后,然后通过构造函数进行创建对象
package cn.cdw.demo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @author DW-CHEN
 * 反射机制获取构造函数之后,然后通过构造函数进行创建对象
 */
public class Demo139 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        System.out.println("=================================通过获取到的公共带参构造函数创建对象===================================");
        Class clazz = Class.forName("cn.cdw.demo.Student12");
        Constructor constructor = clazz.getConstructor(String.class, Integer.class);

        Student12 s1 = (Student12)constructor.newInstance("小明", 12);//通过获取到的公共带参构造函数创建对象
        s1.show();

        System.out.println();
        System.out.println("=================================通过获取到的私有带参构造函数创建对象===================================");
        Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class);

        declaredConstructor.setAccessible(true);//临时取消访问检查,因为它是私有的

        Student12 s2 = (Student12)declaredConstructor.newInstance("小李");//通过获取到的私有带参构造函数创建对象
        s2.show();
    }

}

class Student12{
    private String name;
    private int age;

    public Student12() {//公共的无参构造方法

    }

    private Student12(String name) {//私有的带参数构造方法
        this.name = name;
    }

    public Student12(String name, Integer 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;
    }

    public void show() {
        System.out.println("姓名:" + this.getName() + "  年龄: " + this.getAge());
    }
}

反射获取成员变量并使用

方法名说明
Field[] getFields()返回所有公共成员变量对象的数组
Field[] getDeclaredFields()获取所有成员变量对象的数组
Field getField(String name)返回单个公共成员变量对象
Field getDeclaredField(String name)返回单个成员变量对象
void set(Object obj,Object value)给指定对象的成员变量赋值
Object get(Object obj)返回指定对象的Field的值
反射机制获取成员变量
package cn.cdw.demo;

import java.lang.reflect.Field;

/**
 * @author DW-CHEN
 * 反射机制获取成员变量
 */
public class Demo140 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        System.out.println("==================================获取所有公共的成员变量=============================================");
        Class clazz = Class.forName("cn.cdw.demo.Student13");
        Field[] fields = clazz.getFields();

        System.out.println("获取所有公共的成员变量: ");
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println();
        System.out.println("==================================获取所有的成员变量=============================================");
        Field[] declaredFields = clazz.getDeclaredFields();

        System.out.println("获取所有的成员变量: ");
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

        System.out.println();
        System.out.println("==================================获取公共的单个成员变量=============================================");
        System.out.println("获取公共的单个成员变量: ");
        System.out.println(clazz.getField("name"));

        System.out.println();
        System.out.println("==================================获取单个成员变量=============================================");
        System.out.println("获取单个成员变量: ");
        System.out.println(clazz.getDeclaredField("password"));

    }
}

class Student13{
    public String name;
    public Integer age;

    private String password;
    private String email;
}
反射机制对成员变量的赋值和获取值
package cn.cdw.demo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * @author DW-CHEN
 * 反射机制对成员变量的赋值和获取值
 */
public class Demo141 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, NoSuchFieldException {
        System.out.println("============================设置对象的指定属性值=================================");
        Class clazz = Class.forName("cn.cdw.demo.Student14");

        Constructor constructor = clazz.getConstructor();//获取无参的构造方法
        Student14 s1 = (Student14)constructor.newInstance();//创建对象

        Field name = clazz.getField("name");//获取对象的指定属性名
        name.set(s1, "小小");//设置属性值

        System.out.println(s1.toString());

        System.out.println();
        System.out.println("============================获取对象的指定属性值=================================");

        Field password = clazz.getDeclaredField("password");//注意它是私有的,需要临时取消检查
        password.setAccessible(true);

        String s = (String)password.get(s1);//获取上面刚才创建的学生对象的密码属性值
        System.out.println(s);
    }
}

class Student14{
    public String name;
    public Integer age;

    private String password = "123";
    private String email;

    public Student14() {

    }

    @Override
    public String toString() {
        return "Student14{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

反射获取成员方法并运行

方法名说明
Method[] getMethods()返回所有公共成员方法对象的数组,包括继承的
method[] getDeclaredMethods()返回所有成员方法对象的数组,不包含继承的
Method getMethod(Stirng name,Class< ? >… parameterTypes)返回单个公共成员方法对象
Method getDeclaredMethod(String name,Class< ? >… parameterTypes)返回单个成员方法对象
Object invoke(Object obj,Object… args)运行方法
反射机制获取成员方法
package cn.cdw.demo;

import java.lang.reflect.Method;

/**
 * @author DW-CHEN
 * 反射机制获取成员方法
 */
public class Demo142 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        System.out.println("============================获取所有公共成员方法,包括继承的============================================");
        Class clazz = Class.forName("cn.cdw.demo.Student15");
        Method[] methods = clazz.getMethods();
        System.out.println("获取所有公共成员方法,包括继承的: ");
        for (Method method : methods) {
            System.out.println(method);
        }

        System.out.println();
        System.out.println("============================获取所有成员方法,不包括继承的============================================");
        Method[] declaredMethods = clazz.getDeclaredMethods();
        System.out.println("获取所有成员方法,不包括继承的: ");
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }

        System.out.println();
        System.out.println("============================获取单个公共成员方法============================================");
        Method function5 = clazz.getMethod("function5", String.class);
        System.out.println(function5);

        System.out.println();
        System.out.println("============================获取单个成员方法============================================");
        Method function1 = clazz.getDeclaredMethod("function1",String.class);
        System.out.println(function1);
    }
}

class Student15{
    private void function1(String name) {//私有无返回值带参的构造方法

    }

    public void function2() { //公共无返回值无参的构造方法

    }

    public void function3(Integer age) { //公共无返回值带参的构造方法

    }

    public String function4(){//公共有返回值无参的构造方法
        return "function4测试数据";
    }

    public String function5(String name) {//公共有返回值有参的构造方法
        return "function5测试数据";
    }
}
反射机制获取成员方法并运行
package cn.cdw.demo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author DW-CHEN
 * 反射机制获取成员方法并运行
 */
public class Demo143 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class clazz = Class.forName("cn.cdw.demo.Student16");
        Constructor constructor = clazz.getConstructor();
        Student16 s1 = (Student16) constructor.newInstance();//创建对象

        Method show = clazz.getMethod("show", String.class);//获取方法
        String result = (String)show.invoke(s1, "我是参数");//运行方法,参数中指定这个方法的对象和这个调用方法的参数
        System.out.println(result);
    }
}

class Student16{
    public Student16() {

    }
    public String show(String str) {
        System.out.println("你输入的参数:"+str);
        return "测试通过....";
    }
}

XML

xml(Externaible Markup Language):是一种可扩展的标记预约

  • 标记语言:通过标签来描述数据的一门语言(标签有时我们也将其称为元素)
  • 可扩展性:标签的名字可以自定义

简单理解:XML文件是由多个标签组成的,而标签名是可以自定义的

作用

1.用于进行存储数据和传输数据
2.用于软件的配置文件

XML语法规则

1.文档声明必须是第一行第一列

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
  • version:该属性是必须的
  • encoding 该属性不是必须的,表示指定打开xml文件的时候是使用什么字符编码表
  • standalone 该属性不是必须的,描述XML文件是否依赖其他的XML文件,取值为yes/no

2.必须存在一个根标签,而且只能有一个
3.XML文件中可以定义注释信息

4.XML文件中可以存在特殊字符
在这里插入图片描述
5.XML文件中可以存在CDATA区:<![CDATA[....内容......]]>

解析xml

就是从xml中获取数据

常见的解析思想

DOM(Document Object Model) 文档对象模型:就是把文档的各个组成部分看做成对应的对象,

把xml文件全部加载到内存,在内存中形成树形结构,然后再获取对应的值

1.Document对象:整个XML文档
2.Element对象:所有标签(Node对象)
3.Attribute对象:所有属性(Node对象)
4.Text对象:所有文本内容(Node对象)

常见的解析工具

1.JAXP----------------------------SUN公司提供的一套XML的解析API
2.JDOM----------------------------开源组织提供了一套XML的解析API-JDOM
3.DOM4J----------------------------开源组织提供了一套XML解析的API-DOM4J

通过第三方的Dom4j解析xml文件中的数据,然后封装到学生类对象中

dom4j-1.6.1.jar下载地址:https://download.csdn.net/download/qq_42795277/12754013

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<students>
    <student id="1">
        <name>小明</name>
        <age>12</age>
    </student>

    <student id="2">
        <name>小李</name>
        <age>21</age>
    </student>

    <student id="3">
        <name>小小</name>
        <age>15</age>
    </student>

</students>
package cn.cdw.demo;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.util.ArrayList;
import java.util.List;

/**
 * @author DW-CHEN
 * 通过第三方的Dom4j解析xml文件中的数据,然后封装到学生类对象中
 * 需要手动导入第三方jar包: dom4j-1.6.1.jar
 */
public class Demo144 {
    public static void main(String[] args) throws DocumentException {
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read("xml\\demo1.xml");//将xml加载到内存
        ArrayList<Student17> arrayList = new ArrayList<>();

        Element rootElement = document.getRootElement();//获取根节点
        List<Element> studentElements = rootElement.elements("student");//获取根节点下的student标签的所有子节点

        for (Element studentElement : studentElements) {
            Attribute attribute = studentElement.attribute("id");//获得属性名
            String id = attribute.getValue();//根据属性名获取到属性值

            Element nameElement = studentElement.element("name");//获取name标签
            String name = nameElement.getText();//根据name标签获取到里面的值

            Element ageElement = studentElement.element("age");//获取age标签
            String age = ageElement.getText();//根据age标签获取到里面的值

            //封装到学生对象中
            Student17 student = new Student17(Integer.parseInt(id), name, Integer.parseInt(age));
            arrayList.add(student);
        }

        for (Student17 student : arrayList) {
            System.out.println(student);
        }

    }
}

class Student17{
    private Integer id;
    private String name;
    private Integer age;

    public Student17() {

    }

    public Student17(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student17{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

XML约束

用来限定XML文件中可以使用的标签以及属性

DTD约束

1.<!ELEMENT> 可以定义元素
2.简单元素:没有子元素<!ELEMENT 元素名称(#PCDATA)>
3.复杂元素:有子元素 <!ELEMENT 元素名称(子元素,子元素,...)>

引入DTD约束的三种方法
方式说明
引入本地DTD<!DOCTYPE 根元素名称 SYSTEM ‘DTD文件的路径’>
在xml文件内部引入DTD<!DOCTYPE 根元素名称[DTD文件内容]>
引入网络DTD<!DOCTYPE 根元素名称 PUBLIC “DTD文件名称” “DTD文件的URL”>

引入本地DTD

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE persions SYSTEM 'demo.dtd'>

<persions>
    <persion>
        <name>小明</name>
        <age>12</age>
    </persion>
</persions>

在xml文件内部引入DTD

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE persions [
        <!ELEMENT persions (persion)>
        <!ELEMENT persion (name,age)>
        <!ELEMENT name (#PCDATA)>
        <!ELEMENT age (#PCDATA)>
        ]>
<persions>
    <persion>
        <name>小李</name>
        <age>13</age>
    </persion>
</persions>
DTD语法规则
  • 简单元素
    1.EMPTY:表示标签为空
    2.ANY:表示标签可以为空也可以不为空
    3.PCDATA:表示元素的内容部分为字符串
<!ELEMENT persions (persion)>
<!ELEMENT persion (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
  • 复杂元素
    1.多个子元素可以用",“或者”|“隔开
    2.”,“逗号表示定义元素的顺序
    3.”|“竖线表示子元素只能出现任意一个
    4.”?“问号表示出现0次或一次
    5.”+“加号表示出现一次或多次
    6.”*"表示出现0次或多次

如果不写规则只能出现任意一个

定义一个属性的格式
<!ATTLIST 元素名称 属性名称 属性类型 属性约束>
  • 属性类型:
    CDATA:普通的字符串

  • 属性约束:
    #REQUIRED:必须的
    #IMPLIED:属性不是必须的
    #FIXED value:属性值是固定的

<!ELEMENT persions (persion+)>
<!ELEMENT persion (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ATTLIST persion id CDATA #REQUIRED>
Schema和dtd的区别

1.schema约束文件也是一个xml文件,符合xml的语法,后缀为.xsd
2.一个xml文件中可以引用多个schema约束文件,多个schema使用名称命名空间(名称命名空间类似于Java包名)
3.dtd里面的元素类型的取值比较单一,常见的就是PCDATA类型,但是在schema里面可以支持多个数据类型
4.schema语法更加复杂
5.schema文件用来约束一个xml文件,同时也被别的文件约束着

Schema约束

编写schema约束步骤

1.创建一个文件夹,后缀为.xsd
2.定义文档声明
3.schema文件的根标签为:<schema>
4.在<schema>中定义属性:xmlns=“http://www.w3.rog/2001/XMLSchema”
5.在<schema>中定义属性:targetNamespace=唯一的url地址,指定当前的这个schema文件的名称空间
6.在<schema>中定义属性elementFormDefault=“qualified”,表示当前文件是一个质量良好的文件
7.通过element定义元素
8.判断当前元素是简单元素还是复杂元素

<?xml version="1.0" encoding="utf-8" ?>
<schema
    xmlns="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.cdw.cn/666"
    elementFormDefault="qualified"
>
    <element name="persons"> <!--persons是一个复杂元素-->
        <complexType>
            <sequence>
                <element name="person"><!--定义person是一个复杂元素-->
                    <complexType>
                        <sequence>
                            <element name="name" type="string"></element><!--定义name简单元素-->
                            <element name="age" type="int"></element><!--定义age简单元素-->
                        </sequence>
                           <attribute name="id" type="string" use="required"></attribute> <!--定义复杂元素person的属性-->
                    </complexType>

                </element>
            </sequence>
        </complexType>
    </element>

</schema>
引入schema约束

1.在根标签上定义属性:xmlns=“http://www.w3.org/2001/XMLSchema-instance”
2.通过xmlns引入约束文件的名称空间
3.给某一个xmlns属性添加一个标识,用于区分不同的名称空间,格式:xmlns:标识=“名称空间地址”,标识可以是任意的,但一般取值都是xsi
4.通过xsi:schemaLocation指定名称空间锁对应的约束文件路径,格式:xsi:schemaLocation = “名称空间url 文件路径”

schema属性定义

required 表示必须的
optional 表示可选的

<?xml version="1.0" encoding="utf-8" ?>
<persons
    xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xmlns = "http://www.cdw.cn/666"
    xsi:schemaLocation = "http://www.cdw.cn/666 demo.xsd"
>
    <person id="01">
        <name>小明</name>
        <age>12</age>
    </person>

</persons>

枚举(enum)

为了间接的表示一些固定的值,Java给我们提供了枚举;

就是将变量的值一一列出来,变量的值只限于列出来的只的范围

枚举特点

1.所有的枚举的类都是Enum的子类
2.我们可以通过“枚举类名.枚举项名称”去访问指定的枚举项
3.每一个枚举项其实就是该枚举的一个对象
4.枚举也是一个类,也可以去定义成员变量
5.枚举类的第一行上必须是枚举项,最后一个枚举项后的分号可以省略,但是如果枚举类有其他的东西,这个分号就不能省略,建议不要省略
6.枚举类可以有构造器,当必须是private的,它默认的也是private的
7.枚举类也可以有抽象方法,但是枚举项必须重写该方法

枚举的方法

方法名说明
String name()获取枚举项的名称
int ordinal()返回枚举项在枚举类中的索引值
int compareTo(E o)比较两个枚举项,返回的是索引的差值
String toString()返回枚举常量的名称
static <T> T valueOf(Class<T>type,String name)获取指定枚举类中的指定名称的枚举值
values()获取所有的枚举项
package cn.cdw.demo;

/**
 * @author DW-CHEN
 * 枚举:为了表示一些固定的值
 * 春夏秋冬
 */
public class Demo145{
    public static void main(String[] args) {
        System.out.println("获取SPRING枚举项的名称: "+Season.SPRING.name());
        System.out.println("获取SUMMER枚举项在类中的索引位置:"+Season.SUMMER.ordinal());
        System.out.println("比较两个枚举项,返回的是索引的差值: "+Season.SPRING.compareTo(Season.WINTER));
        System.out.println("获取枚举常量的名称: "+Season.SPRING.toString());
        System.out.println("获取指定枚举类中的指定枚举值: "+Enum.valueOf(Season.class, "SPRING"));

        System.out.println();
        System.out.println("获取所有的枚举: ");
        Season[] values = Season.values();//获取所有的枚举
        for (Season value : values) {
            System.out.println(value);

        }
    }
}

//枚举
enum Season {
    SPRING,SUMMER,AUTUMN,WINTER;
}

注解

作用:就是对我们的程序进行标注和解释

注解名说明
@Override描述子类重写父类的方法
@Deprected描述方法过时
SuppressWarnings压制警告

注解和注释的区别

  • 注释:给程序员看的
  • 注解:给编译器看的(让虚拟机看到程序中的注解,注解代表程序的一些特殊功能)

自定义注解

package cn.cdw.demo;

/**
 * @author DW-CHEN
 * 自定义注解
 */
 public @interface Demo146 {
    public int age() default 12;//定义基本类型属性

    public String name();//定义String类型属性

    public Class clazz() default Student18.class;//定义class类型属性

    public Anno anno() default @Anno;//定义注解类型属性

    public  Season1 season() default Season1.SPRING;//定义枚举类型属性

    public int[] arr() default {1, 2, 3};//定义基本类型的一维数组属性

    public Season1[] season1() default {Season1.SPRING, Season1.SUMMER};//定义枚举类型的一维数组属性

    public String value();//特殊属性value,后期我们在使用注解的时候,如果我们只需要给注解的value属性赋值,那么value可以省略

}


class Student18{

}

@interface Anno{

}

enum Season1 {
    SPRING,SUMMER,AUTUMN,WINTER;
}

自定义一个注解@Run,当这个注解标注在某个方法上的时候,这个方法就运行

package cn.cdw.demo;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author DW-CHEN
 * 自定义一个注解@Run,当这个注解标注在某个方法上的时候,这个方法就运行
 */
public class Demo147 {
    @Run
    public void show() {
        System.out.println("运行了");
    }

    @Run
    public void play() {
        System.out.println("玩游戏中....");
    }
}


//自定义的注解
@Retention(RetentionPolicy.RUNTIME) //表示@Run这个注解的存活时间
@interface Run {

}

//注解逻辑处理,通过反射机制来判断方法上是否有指定的注解,如果有则运行该方法
class Main{
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //通过反射机制进行处理
        Class clazz = Class.forName("cn.cdw.demo.Demo147");//获取类字节码文件
        Object o = clazz.getConstructor().newInstance();//通过无参构造方法进行创建对象

        Method[] declaredMethods = clazz.getDeclaredMethods();//获取所有的方法

        for (Method declaredMethod : declaredMethods) {
            if (declaredMethod.isAnnotationPresent(Run.class)) {//判断该方法上是否有@Run这个注解,如果有返回true,否则返回false
                declaredMethod.invoke(o);//运行该方法
            }
        }
    }
}

元注解

元注解名说明
@Target指定注解能在哪里使用
@Retention可以理解为保留的时间(生命周期)
@Inherited表示修饰的自定义注解可以白子类继承
@Documented表示该自定义注解,会出现在API文档里面
package cn.cdw.demo;

import java.lang.annotation.*;

/**
 * @author DW-CHEN
 * 元注解
 */

@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})//指定注解使用的位置(在成员变量,类上,方法上)
@Retention(RetentionPolicy.RUNTIME)//指定注解的存活时间
@Inherited//指定注解可以被继承
public @interface Demo148 {
}

单元测试

Junit:是java编程语言的单元测试工具

需要导入的jar包:junit-4.10.jar

junit-4.10.jar下载地址:https://download.csdn.net/download/qq_42795277/12754593

Junit特点

1.Junit是一个开源代码的测试工具
2.提供注解来识别测试方法
3.Junit测试可以让你编写代码更快,并提高质量
4.Junit优雅简洁,没有那么复杂,花费时间少
5.Junit在一个条中显示进度,如果运行良好就是绿色,如果运行失败则变为红色

Junit常用的注解

注解说明
@Test表示测试该方法
@Before在测试的方法前运行
@After在测试的方法后运行
package cn.cdw.demo;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author DWCHEN
 * junit,注意:需导入junit-4.10.jar包
 */

public class Demo149 {

    @Before
    public void before() {
        System.out.println("BEFORE......");
    }

    @Test
    public void test () {
        System.out.println("TEST......");
    }


    @After
    public void after() {
        System.out.println("AFTER......");
    }
}

日志技术

记录程序在运行的时候的点点滴滴,并可以进行永久保存

需要log4j的所需jar包,下载地址:https://download.csdn.net/download/qq_42795277/12754704
需要将配置文件放置在src目录下,log4j.properties下载地址:https://download.csdn.net/download/qq_42795277/12755030

package cn.cdw.demo;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author DW-CHEN
 * log4j
 */
public class Demo150 {
    //private static final Logger LOGGER = Logger.getLogger(Demo150.class);//使用log4j的api获取对象,不推荐使用,因为如果以后我们更换了日志实现类,那下面的代码就需要跟着改

    private static final Logger LOGGER = LoggerFactory.getLogger(Demo150.class);//推荐使用slf4j里面的api获取对象,因为如果以后我们更换了日志实现类,那下面的代码不需要跟着改

    public static void main(String[] args) {
        LOGGER.debug("DEBUG....");
        LOGGER.info("INFO...");
        LOGGER.warn("WARN...");
        LOGGER.error("ERROR...");
    }
}

日志和输出语句的区别

输出语句日志技术
取消日志需要修改代码,灵活性比较差不需要修改代码,灵活性比较好
输出位置只能在控制台可以将日志信息写入到文件或者数据库中
多线程和业务代码处于一个线程中多线程方式记录日志,不影响业务代码的性能

Log4j组成

1.Loggers(记录器)-----------------日志的级别
2.Appenders(输出源)-----------------日志要输出的地方
3.Layouts(布局)-----------------日志输出的格式

Loggerrs(记录器)

Loggers组件在此系统中常见的五个级别:DEBUG,INFO,WARN,ERROR和FATAL

DEBUG < INFO < WARN < ERROR < FATAL

Log4j有一个规则,只输出级别不低于设定级别的日志信息

Appenders(输出源)

把日志输出到不同的地方,例如控制台(Console),文件(Files)等

org.apache.log4j.ConsoleAppender (控制台)
org.apache.log4j.FileAppender (文件)

Layouts(布局)

可以根据自己的喜好规定日志输出的格式

常用的布局管理器

org.apache.log4j.PatternLayout --------------- 可以灵活的指定布局模式(常用这个布局管理器)
org.apache.log4j.SimpleLayout---------------包含日志信息的级别和信息字符串
org.apache.log4j.TTCCLayout---------------包含日志产生的时间,线程,类别等信息

配置根Logger

格式:log4j.rootLogger=日志级别,appenderName1,AppenderName2,…

  • 日志级别:OFF,FATAL,ERROR,WARN,INFO,DEBUG,ALL或者自定义的级别
  • appenderName1:就是指定日志信息要输出到哪里,可以同时指定多个输出目的地,用逗号隔开
log4j.rootLogger=debug, stdout,file
配置appender
ConsoleAppender常用选项
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.ImmediateFlush=true
log4j.appender.stdout.Target=System.err
ImmediateFlush=true表示所有的消息都会被立即输出,设为false则不输出,默认值为true
Target=System.err默认值是System.out
FileAppender常用选项
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.ImmediateFlush=true
log4j.appender.file.Append=true
log4j.appender.file.File=d:\\mylog.log
ImmediateFlush=true表示所有的消息都会被立即输出,设为false则不输出,默认值为true
Append=truetrue表示将消息添加到指定的文件中,原来的消息不覆盖,false则将消息覆盖指定的文件内容,默认为true
File=d:\mylog.log指定消息输出到mylog.log文件中
配置Layout
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

org.apache.log4j.PatternLayout --------------- 可以灵活的指定布局模式(常用这个布局管理器)
org.apache.log4j.SimpleLayout---------------包含日志信息的级别和信息字符串
org.apache.log4j.TTCCLayout---------------包含日志产生的时间,线程,类别等信息

log4j.properties配置文件
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.ImmediateFlush=true
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.ImmediateFlush=true
log4j.appender.file.Append=true
log4j.appender.file.File=d:\\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=debug, stdout,file
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值