类加载器
负责将 .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=true | true表示将消息添加到指定的文件中,原来的消息不覆盖,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