1. 类加载器
1.1 作用
前期写的Java代码,属于源代码,后期要进行运行,首先需要将这个源代码进行编译,编译完成之后会形成一个.class文件,这个.class文件就是字节码文件,后期进行运行的时候,就需要将这个字节码文件加载到内存中,要把这个字节码文件加载到内存中就需要类加载器来完成 也就是说,类加载器就是负责将.class文件加载到内存中
1.2 类的加载时机问题
一个类什么时候被加载到内存?
创建类的实例(即对象) 调用类的类方法 访问类或者接口的类变量,或者为该类变量赋值 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象 初始化某个类的子类 直接使用java.exe命令来运行某个主类
1.3 类的加载过程
一个类通过类加载器,将其加载到内存是需要经过很多个阶段的。大致可以分为
加载
通过包名+类名,获取这个类,准备用流进行传输 在这个类加载到内存中 加载完毕创建一个class对象,这个Class对象就是对这个类的字节码文件进行描述。Java语言是面向对象的语言,在Java看来万物皆对象,因此一个字节码文件Java也提供了对应的类对其进行描述,这个类就是Class 链接
验证
确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全 准备
负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值 解析
初始化
根据程序员通过程序制定的主观计划去初始化类变量和其他资源 总结
当一个类被使用的时候,才会被加载到内存 类加载的过程:加载、验证、准备、解析、初始化
1.4 分类
分类
Bootstrap class loader:启动类加载器
虚拟机的内置类加载器,通常表示为null,并且没有父null Platfrom class loader:平台类加载器
System class loader:系统类加载器
类加载器存在逻辑上的继承关系
System的父加载器为Platform Platform的父加载器为Bootstrap 逻辑上的继承关系
没有通过extends关键字去指定某一个类加载器对应的父类加载器,但是他们的确是存在继承关系的,这是Java中的一种的机制,在类加载器这里可以看到 代码演示
public class ClassLoaderDemo1 {
public static void main ( String[ ] args) {
ClassLoader systemClassLoader = ClassLoader. getSystemClassLoader ( ) ;
ClassLoader classLoader1 = systemClassLoader. getParent ( ) ;
ClassLoader classLoader2 = classLoader1. getParent ( ) ;
System. out. println ( "系统类加载器" + systemClassLoader) ;
System. out. println ( "平台类加载器" + classLoader1) ;
System. out. println ( "启动类加载器" + classLoader2) ;
}
}
1.5 双亲委派模型
如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
1.6 ClassLoader中的两个方法
Java语言的是面向对象的,万物皆对象。类加载器其实也是一个对象,在Java中就提供了一个类对其进行描述,这个类就是ClassLoader 方法介绍
方法名 说明 public static ClassLoader getSystemClassLoader() 获取系统类加载器 public InputStream getResourceAsStream(String name) 加载某一个资源文件
public class ClassLoaderDemo2 {
public static void main ( String[ ] args) throws IOException {
ClassLoader systemClassLoader = ClassLoader. getSystemClassLoader ( ) ;
InputStream is = systemClassLoader. getResourceAsStream ( "prop.properties" ) ;
Properties prop = new Properties ( ) ;
prop. load ( is) ;
System. out. println ( prop) ;
is. close ( ) ;
}
}
2. 反射
2.1 概述
本质上
反射机制
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意属性和方法; 这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制 如何我们可以获取到一个类的字节码文件对象,那么我们就可以从这个字节码文件中解析出来这个类中的成员,然后在使用成员。Java是面向对象的,万物皆对象,因此在Java看来一个类的构造方法是一对象,成员变量也是对象,成员方法也是对象。那么Java就提供了对应的类对其进行描述:Constructor、Field、Method。当我们获取到的对应的成员对象以后,就可以调用成员对象中的方法使用对应的成员 反射学习思路
首先获取一个类的字节码文件对象 调用字节码文件对象(Class)的方法获取类的指定的成员对象(构造方法,成员变量,成员方法) 调用对应的成员对象的方法使用类中的成员
2.2 获取Class对象
获取Class对象的三种方式
通过Class类中的静态方法forName来进行获取 通过类的class属性来获取,即类名.class 通过对象名.getClass()方法 三种方式获取的是同一个Class对象,因为一个类的字节码文件只有一个,所以一个类的字节码文件对象只有一个 代码演示
public class Student {
private String name;
private int age;
public Student ( ) {
}
public Student ( 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 study ( ) {
System. out. println ( "学生在学习" ) ;
}
@Override
public String toString ( ) {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}' ;
}
}
public class ReflectDemo1 {
public static void main ( String[ ] args) throws ClassNotFoundException {
Class clazz = Class. forName ( "com.itheima.myreflect2.Student" ) ;
System. out. println ( clazz) ;
Class clazz2 = Student. class ;
System. out. println ( clazz2) ;
Student s = new Student ( ) ;
Class clazz3 = s. getClass ( ) ;
System. out. println ( clazz3) ;
System. out. println ( clazz == clazz2) ;
System. out. println ( clazz2 == clazz3) ;
}
}
2.3 获取构造方法对象
方法名 说明 Constructor<?>[] getConstructors() 返回所有公共构造方法对象的数组 Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象的数组 Constructor getConstructor(Class<?>… parameterTypes) 返回单个公共构造方法对象 Constructor getDeclaredConstructor(Class<?>… parameterTypes) 返回单个构造方法对象
常用的是第四种
parameterTypes:表示的是构造方法参数对应的Class类型 代码演示
public class Student {
private String name;
private int age;
private Student ( String name) {
System. out. println ( "name的值为:" + name) ;
System. out. println ( "private...Student...有参构造方法" ) ;
}
public Student ( ) {
System. out. println ( "public...Student...无参构造方法" ) ;
}
public Student ( String name, int age) {
System. out. println ( "name的值为:" + name + "age的值为:" + age) ;
System. out. println ( "public...Student...有参构造方法" ) ;
}
}
public class ReflectDemo1 {
public static void main ( String[ ] args) throws ClassNotFoundException, NoSuchMethodException {
}
private static void method4 ( ) throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class. forName ( "com.itheima.myreflect3.Student" ) ;
Constructor constructor = clazz. getDeclaredConstructor ( String. class ) ;
System. out. println ( constructor) ;
}
private static void method3 ( ) throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class. forName ( "com.itheima.myreflect3.Student" ) ;
Constructor constructor1 = clazz. getConstructor ( ) ;
System. out. println ( constructor1) ;
Constructor constructor2 = clazz. getConstructor ( String. class , int . class ) ;
System. out. println ( constructor2) ;
Constructor constructor3 = clazz. getConstructor ( int . class ) ;
System. out. println ( constructor3) ;
}
private static void method2 ( ) throws ClassNotFoundException {
Class clazz = Class. forName ( "com.itheima.myreflect3.Student" ) ;
Constructor[ ] constructors = clazz. getDeclaredConstructors ( ) ;
for ( Constructor constructor : constructors) {
System. out. println ( constructor) ;
}
}
private static void method1 ( ) throws ClassNotFoundException {
Class clazz = Class. forName ( "com.itheima.myreflect3.Student" ) ;
Constructor[ ] constructors = clazz. getConstructors ( ) ;
for ( Constructor constructor : constructors) {
System. out. println ( constructor) ;
}
}
}
2.4 使用构造方法对象
方法名 说明 T newInstance(Object…initargs) 根据指定的构造方法创建对象 setAccessible(boolean flag) 设置为true,表示取消访问检查
initargs: 表示的就是给构造方法所传递的具体的数据(实际参数) 代码演示
public class ReflectDemo2 {
public static void main ( String[ ] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
}
private static void method4 ( ) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class clazz = Class. forName ( "com.itheima.myreflect3.Student" ) ;
Constructor constructor = clazz. getDeclaredConstructor ( String. class ) ;
constructor. setAccessible ( true ) ;
Student student = ( Student) constructor. newInstance ( "zhangsan" ) ;
System. out. println ( student) ;
}
private static void method3 ( ) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class clazz = Class. forName ( "com.itheima.myreflect3.Student" ) ;
Student student = ( Student) clazz. newInstance ( ) ;
System. out. println ( student) ;
}
private static void method2 ( ) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class clazz = Class. forName ( "com.itheima.myreflect3.Student" ) ;
Constructor constructor = clazz. getConstructor ( ) ;
Student student = ( Student) constructor. newInstance ( ) ;
System. out. println ( student) ;
}
private static void method1 ( ) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class clazz = Class. forName ( "com.itheima.myreflect3.Student" ) ;
Constructor constructor = clazz. getConstructor ( String. class , int . class ) ;
Student student = ( Student) constructor. newInstance ( "zhangsan" , 23 ) ;
System. out. println ( student) ;
}
}
2.5 获取成员变量对象
方法名 说明 Field[] getFields() 返回所有公共成员变量对象的数组 Field[] getDeclaredFields() 返回所有成员变量对象的数组 Field getField(String name) 返回单个公共成员变量对象 Field getDeclaredField(String name) 返回单个成员变量对象
public class Student {
public String name;
public int age;
public String gender;
private int money = 300 ;
@Override
public String toString ( ) {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", money=" + money +
'}' ;
}
}
public class ReflectDemo1 {
public static void main ( String[ ] args) throws ClassNotFoundException, NoSuchFieldException {
}
private static void method4 ( ) throws ClassNotFoundException, NoSuchFieldException {
Class clazz = Class. forName ( "com.itheima.myreflect4.Student" ) ;
Field field = clazz. getDeclaredField ( "money" ) ;
System. out. println ( field) ;
}
private static void method3 ( ) throws ClassNotFoundException, NoSuchFieldException {
Class clazz = Class. forName ( "com.itheima.myreflect4.Student" ) ;
Field field = clazz. getField ( "money" ) ;
System. out. println ( field) ;
}
private static void method2 ( ) throws ClassNotFoundException {
Class clazz = Class. forName ( "com.itheima.myreflect4.Student" ) ;
Field[ ] fields = clazz. getDeclaredFields ( ) ;
for ( Field field : fields) {
System. out. println ( field) ;
}
}
private static void method1 ( ) throws ClassNotFoundException {
Class clazz = Class. forName ( "com.itheima.myreflect4.Student" ) ;
Field[ ] fields = clazz. getFields ( ) ;
for ( Field field : fields) {
System. out. println ( field) ;
}
}
}
2.6 使用成员变量对象
方法名 说明 void set(Object obj, Object value) 赋值 Object get(Object obj) 获取值
obj:表示的就是一个对象 value:表示的就是要设置的值 返回值表示的就是成员变量的值,方法参数obj表示的就是一个对象 代码演示
public class ReflectDemo2 {
public static void main ( String[ ] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
}
private static void method2 ( ) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
Class clazz = Class. forName ( "com.itheima.myreflect4.Student" ) ;
Field field = clazz. getDeclaredField ( "money" ) ;
field. setAccessible ( true ) ;
Student student = ( Student) clazz. newInstance ( ) ;
Object o = field. get ( student) ;
System. out. println ( o) ;
}
private static void method1 ( ) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
Class clazz = Class. forName ( "com.itheima.myreflect4.Student" ) ;
Field field = clazz. getField ( "name" ) ;
Student student = ( Student) clazz. newInstance ( ) ;
field. set ( student, "zhangsan" ) ;
System. out. println ( student) ;
}
}
2.7 获取成员方法对象
方法名 说明 Method[] getMethods() 返回所有公共成员方法对象的数组,包括继承的 Method[] getDeclaredMethods() 返回所有成员方法对象的数组,不包括继承的 Method getMethod(String name, Class<?>… parameterTypes) 返回单个公共成员方法对象 Method getDeclaredMethod(String name, Class<?>… parameterTypes) 返回单个成员方法对象
常用的就是第四种
name:表示的是成员方法的名称 parameterTypes:表示的就是成员方法参数类型所对应的Class类型 代码演示
public class Student {
private void show ( ) {
System. out. println ( "私有的show方法,无参无返回值" ) ;
}
public void function1 ( ) {
System. out. println ( "function1方法,无参无返回值" ) ;
}
public void function2 ( String name) {
System. out. println ( "function2方法,有参无返回值,参数为" + name) ;
}
public String function3 ( ) {
System. out. println ( "function3方法,无参有返回值" ) ;
return "aaa" ;
}
public String function4 ( String name) {
System. out. println ( "function4方法,有参有返回值,参数为" + name) ;
return "aaa" ;
}
}
public class ReflectDemo1 {
public static void main ( String[ ] args) throws ClassNotFoundException, NoSuchMethodException {
}
private static void method5 ( ) throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class. forName ( "com.itheima.myreflect5.Student" ) ;
Method method = clazz. getDeclaredMethod ( "show" ) ;
System. out. println ( method) ;
}
private static void method4 ( ) throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class. forName ( "com.itheima.myreflect5.Student" ) ;
Method method = clazz. getMethod ( "function2" , String. class ) ;
System. out. println ( method) ;
}
private static void method3 ( ) throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class. forName ( "com.itheima.myreflect5.Student" ) ;
Method method1 = clazz. getMethod ( "function1" ) ;
System. out. println ( method1) ;
}
private static void method2 ( ) throws ClassNotFoundException {
Class clazz = Class. forName ( "com.itheima.myreflect5.Student" ) ;
Method[ ] methods = clazz. getDeclaredMethods ( ) ;
for ( Method method : methods) {
System. out. println ( method) ;
}
}
private static void method1 ( ) throws ClassNotFoundException {
Class clazz = Class. forName ( "com.itheima.myreflect5.Student" ) ;
Method[ ] methods = clazz. getMethods ( ) ;
for ( Method method : methods) {
System. out. println ( method) ;
}
}
}
2.8 使用成员方法对象
方法名 说明 Object invoke(Object obj, Object… args) 运行方法
参数详解
参数一: 用obj对象调用该方法 参数二: 调用方法的传递的参数(如果没有就不写) 返回值: 方法的返回值(如果没有就不写) 代码演示
public class ReflectDemo2 {
public static void main ( String[ ] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class clazz = Class. forName ( "com.itheima.myreflect5.Student" ) ;
Method method = clazz. getMethod ( "function4" , String. class ) ;
Student student = ( Student) clazz. newInstance ( ) ;
Object result = method. invoke ( student, "zhangsan" ) ;
System. out. println ( result) ;
}
}
3. xml
3.1 概述
万维网联盟(W3C)
万维网联盟(W3C)创建于1994年,又称W3C理事会。1994年10月在麻省理工学院计算机科学实验室成立。 建立者: Tim Berners-Lee (蒂姆·伯纳斯·李)。 是Web技术领域最具权威和影响力的国际中立性技术标准机构。 到目前为止,W3C已发布了200多项影响深远的Web技术标准及实施指南, 如广为业界采用的超文本标记语言HTML(标准通用标记语言下的一个应用)、 可扩展标记语言XML(标准通用标记语言下的一个子集) 以及帮助残障人士有效获得Web信息的无障碍指南(WCAG)等 xml概述
XML的全称为(EXtensible Markup Language),是一种可扩展的标记语言 标记语言: 通过标签来描述数据的一门语言(标签有时我们也将其称之为元素) 可扩展:标签的名字是可以自定义的,XML文件是由很多标签组成的,而标签名是可以自定义的 配置文件
用于去配置软件在运行的时候所需要的一些参数 配置文件种类较多
xml 作用
作为配置文件的优势
3.2 标签的规则
< student>
< student> < / student>
< ! -- 前边的是开始标签,后边的是结束标签-- >
< address/ >
标签中可以定义属性,属性和标签名空格隔开,属性值必须用引号引起来
< student id= "1" > < / student>
这是正确的: < student id= "1" > < name> 张三< / name> < / student>
这是错误的: < student id= "1" > < name> 张三< / student> < / name>
3.3 xml 语法规则
语法规则
XML文件的后缀名为:xml 文档声明必须是第一行第一列 必须存在一个根标签,有且只能有一个 XML文件中可以定义注释信息 XML文件中可以存在以下特殊字符 XML文件中可以存在CDATA区 文档声明属性说明
version : 该属性是必须的,声明当前xml文件的版本。一般我们使用的都是1.0。 encoding: 该属性不是必须的,告知浏览器在打开该xml文件的时候应该是使用什么字符编码表(一般取值都是UTF-8)。 standalone: 该属性不是必须的,描述XML文档是否是孤独的(是否不需要依赖其他的xml文件),取值为yes/no。
文档声明示例
< ? xml version= "1.0" encoding= "UTF-8" standalone= "yes”? >
特殊符号如下:
& lt; < 小于
& gt; > 大于
& amp; & 和号
& apos; ' 单引号
& quot; " 引号
CDATA区示例
< ! [ CDATA[ …内容… ] ] >
<?xml version="1.0" encoding="UTF-8" ?>
< students>
< student id = " 1" >
< name> 张三</ name>
< age> 23</ age>
< info> 学生< > > > > > > > > > > > 的信息</ info>
< message> <![CDATA[内容 <<<<<< >>>>>> ]]]> </ message>
</ student>
< student id = " 2" >
< name> 李四</ name>
< age> 24</ age>
</ student>
</ students>
如何保证我们编写的xml文件是否正确?
通过idea开发工具进行校验,如果xml编写有误,idea开发工具会有指定的错误提示信息 使用浏览器打开,如果可以正常显示xml文件的内容,那么说明没有问题,如果存在问题,那么在使用浏览器打开的时候就会出错
3.4 xml解析
概述
常见的解析思想
DOM(Document Object Model)文档对象模型
把文档的各个组成部分看做成对应的对象 会把xml文件全部加载到内存,在内存中形成一个树形结构,再获取对应的值 作为一个xml文件有哪些组成部分?
xml文档本身 ----- Document 标签 ----- Element 属性 ----- Attribute 注释 ----- Comment 标签体文本内容 ----- Text
Element、Attribute、Text它们之前是存在共性的内容,因此可以向上进行抽取,最终形成了一个父类,这个父类就是Node 常见的解析工具
JAXP: SUN公司提供的一套XML的解析的API JDOM: 开源组织提供了一套XML的解析的API-jdom DOM4J: 开源组织提供了一套XML的解析的API-dom4j,全称:Dom For Java pull: 主要应用在Android手机端解析XML 解析的准备工作
我们可以通过网站:https://dom4j.github.io/ 去下载dom4j 将提供好的dom4j-1.6.1.zip解压,找到里面的dom4j-1.6.1.jar 在idea中当前模块下新建一个libs文件夹,将jar包复制到文件夹中 选中jar包 -> 右键 -> 选择add as library即可 需求
解析提供好的xml文件 将解析到的数据封装到学生对象中 并将学生对象存储到ArrayList集合中 遍历集合 代码实现< ? xml version= "1.0" encoding= "UTF-8" ? >
< ! -- 注释的内容-- >
< ! -- 本xml文件用来描述多个学生信息-- >
< students>
< ! -- 第一个学生信息-- >
< student id= "1" >
< name> 张三< / name>
< age> 23 < / age>
< / student>
< ! -- 第二个学生信息-- >
< student id= "2" >
< name> 李四< / name>
< age> 24 < / age>
< / student>
< / students>
public class Student {
private String id;
private String name;
private int age;
public Student ( ) {
}
public Student ( String id, String name, int age) {
this . id = id;
this . name = name;
this . age = age;
}
public String getId ( ) {
return id;
}
public void setId ( String id) {
this . id = id;
}
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;
}
@Override
public String toString ( ) {
return "Student{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
'}' ;
}
}
public class XmlParse {
public static void main ( String[ ] args) throws DocumentException {
SAXReader saxReader = new SAXReader ( ) ;
Document document = saxReader. read ( new File ( "myxml\\xml\\student.xml" ) ) ;
Element rootElement = document. getRootElement ( ) ;
List< Element> studentElements = rootElement. elements ( "student" ) ;
ArrayList< Student> list = new ArrayList < > ( ) ;
for ( Element element : studentElements) {
Attribute attribute = element. attribute ( "id" ) ;
String id = attribute. getValue ( ) ;
Element nameElement = element. element ( "name" ) ;
String name = nameElement. getText ( ) ;
Element ageElement = element. element ( "age" ) ;
String age = ageElement. getText ( ) ;
Student s = new Student ( id, name, Integer. parseInt ( age) ) ;
list. add ( s) ;
}
for ( Student student : list) {
System. out. println ( student) ;
}
}
}
3.5 DTD约束
3.5.1 编写
什么是约束
约束的分类
编写DTD约束
创建一个文件,这个文件的后缀名为.dtd 看xml文件中使用了哪些元素, <!ELEMENT> 可以定义元素 判断元素是简单元素还是复杂元素
< ! ELEMENT persons ( person) >
< ! ELEMENT person ( name, age) >
< ! ELEMENT name ( #PCDATA) >
< ! ELEMENT age ( #PCDATA) >
3.5.2 引入
引入DTD约束
引入DTD约束的三种方法
引入本地dtd : <!DOCTYPE 根元素名称 SYSTEM ‘DTD文件的路径'>
在xml文件内部引入:<!DOCTYPE 根元素名称 [ dtd文件内容 ]>
引入网络dtd:<!DOCTYPE 根元素的名称 PUBLIC "DTD文件名称" "DTD文档的URL">
代码实现
// 这是persondtd.dtd文件中的内容,已经提前写好
< !ELEMENT persons (person) >
< !ELEMENT person (name,age) >
< !ELEMENT name (#PCDATA) >
< !ELEMENT age (#PCDATA) >
// 在person1.xml文件中引入persondtd.dtd约束
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE persons SYSTEM 'persondtd.dtd'>
< persons>
< person>
< name> 张三</ name>
< age> 23</ age>
</ person>
</ persons>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE persons [
<!ELEMENT persons (person)>
< !ELEMENT person (name,age) >
< !ELEMENT name (#PCDATA) >
< !ELEMENT age (#PCDATA) >
]>
< persons>
< person>
< name> 张三</ name>
< age> 23</ age>
</ person>
</ persons>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE persons PUBLIC "dtd文件的名称" "dtd文档的URL">
< persons>
< person>
< name> 张三</ name>
< age> 23</ age>
</ person>
</ persons>
3.5.3 DTD语法
定义元素
定义一个元素的格式为:<!ELEMENT 元素名 元素类型>
简单元素 EMPTY: 表示标签体为空 ANY: 表示标签体可以为空也可以不为空 PCDATA: 表示该元素的内容部分为字符串 复杂元素 直接写子元素名称. 多个子元素可以使用",“或者”|"隔开; ","表示定义子元素的顺序 ; “|”: 表示子元素只能出现任意一个 "?"零次或一次, "+"一次或多次, "*"零次或多次;如果不写则表示出现一次 定义属性
定义一个属性的格式为
<!ATTLIST 元素名称 属性名称 属性的类型 属性的约束>
属性的类型
属性的约束
// #REQUIRED: 必须的 // #IMPLIED: 属性不是必需的 // #FIXED value:属性值是固定的 代码实现< ! ELEMENT persons ( person+ ) >
< ! ELEMENT person ( name, age) >
< ! ELEMENT name ( #PCDATA) >
< ! ELEMENT age ( #PCDATA) >
< ! ATTLIST person id CDATA #REQUIRED>
< ? xml version= "1.0" encoding= "UTF-8" ? >
< ! DOCTYPE persons SYSTEM 'persondtd.dtd' >
< persons>
< person id= "001" >
< name> 张三< / name>
< age> 23 < / age>
< / person>
< person id = "002" >
< name> 张三< / name>
< age> 23 < / age>
< / person>
< / persons>
```
3.6 schema约束
3.6.1 schema和dtd的区别
schema约束文件也是一个xml文件,符合xml的语法,这个文件的后缀名.xsd 一个xml中可以引用多个schema约束文件,多个schema使用名称空间区分(名称空间类似于java包名) dtd里面元素类型的取值比较单一常见的是PCDATA类型,但是在schema里面可以支持很多个数据类型 schema 语法更加的复杂
3.6.2 编写schema约束
1. 创建一个文件,这个文件的后缀名为.xsd
2. 定义文档声明
3. schema文件的根标签为: `<schema>`
4. 在`<schema>`中定义属性:`xmlns=http://www.w3.org/2001/XMLSchema`
5. 在`<schema>`中定义属性 :targetNamespace =唯一的url地址,指定当前这个schema文件的名称空间
6. 在`<schema>`中定义属性 :elementFormDefault="qualified“,表示当前schema文件是一个质量良好的文件。
7. 通过element定义元素
8. 判断当前元素是简单元素还是复杂元素
< ? xml version= "1.0" encoding= "UTF-8" ? >
< schema
xmlns= "http://www.w3.org/2001/XMLSchema"
targetNamespace= "http://www.itheima.cn/javase"
elementFormDefault= "qualified"
>
< ! -- 定义persons复杂元素-- >
< element name= "persons" >
< complexType>
< sequence>
< ! -- 定义person复杂元素-- >
< element name = "person" >
< complexType>
< sequence>
< ! -- 定义name和age简单元素-- >
< element name = "name" type = "string" > < / element>
< element name = "age" type = "string" > < / element>
< / sequence>
< / complexType>
< / element>
< / sequence>
< / complexType>
< / element>
< / schema>
3.6.3 引入schema约束
1. 在根标签上定义属性xmlns="http://www.w3.org/2001/XMLSchema-instance"
2. 通过xmlns引入约束文件的名称空间
3. 给某一个xmlns属性添加一个标识,用于区分不同的名称空间,格式为: xmlns:标识=“名称空间地址” ,标识可以是任意的,但是一般取值都是xsi
4. 通过xsi:schemaLocation指定名称空间所对应的约束文件路径,格式为:xsi:schemaLocation = "名称空间url 文件路径“
< ? xml version= "1.0" encoding= "UTF-8" ? >
< persons
xmlns: xsi= "http://www.w3.org/2001/XMLSchema-instance"
xmlns= "http://www.itheima.cn/javase"
xsi: schemaLocation= "http://www.itheima.cn/javase person.xsd"
>
< person>
< name> 张三< / name>
< age> 23 < / age>
< / person>
< / persons>
```
3.6.4 schema约束定义属性
< ? xml version= "1.0" encoding= "UTF-8" ? >
< schema
xmlns= "http://www.w3.org/2001/XMLSchema"
targetNamespace= "http://www.itheima.cn/javase"
elementFormDefault= "qualified"
>
< ! -- 定义persons复杂元素-- >
< element name= "persons" >
< complexType>
< sequence>
< ! -- 定义person复杂元素-- >
< element name = "person" >
< complexType>
< sequence>
< ! -- 定义name和age简单元素-- >
< element name = "name" type = "string" > < / element>
< element name = "age" type = "string" > < / element>
< / sequence>
< ! -- 定义属性,required ( 必须的) / optional ( 可选的) -- >
< attribute name= "id" type= "string" use= "required" > < / attribute>
< / complexType>
< / element>
< / sequence>
< / complexType>
< / element>
< / schema>
< ? xml version= "1.0" encoding= "UTF-8" ? >
< persons
xmlns: xsi= "http://www.w3.org/2001/XMLSchema-instance"
xmlns= "http://www.itheima.cn/javase"
xsi: schemaLocation= "http://www.itheima.cn/javase person.xsd"
>
< person id= "001" >
< name> 张三< / name>
< age> 23 < / age>
< / person>
< / persons>
```
4. 枚举
4.1 概述
为了间接的表示一些固定的值,Java就给我们提供了枚举 是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内
4.2 定义格式
格式public enum s {
枚举项1 , 枚举项2 , 枚举项3 ;
}
注意: 定义枚举类要用关键字enum
示例代码
public enum Season {
SPRING, SUMMER, AUTUMN, WINTER;
}
4.3 枚举的特点
特点
所有枚举类都是Enum的子类 我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项 每一个枚举项其实就是该枚举的一个对象 枚举也是一个类,也可以去定义成员变量 枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略 枚举类可以有构造器,但必须是private的,它默认的也是private的。 枚举项的用法比较特殊:枚举(""); 枚举类也可以有抽象方法,但是枚举项必须重写该方法 示例代码public enum Season {
SPRING ( "春" ) {
@Override
public void show ( ) {
System. out. println ( this . name) ;
}
} ,
SUMMER ( "夏" ) {
@Override
public void show ( ) {
System. out. println ( this . name) ;
}
} ,
AUTUMN ( "秋" ) {
@Override
public void show ( ) {
System. out. println ( this . name) ;
}
} ,
WINTER ( "冬" ) {
@Override
public void show ( ) {
System. out. println ( this . name) ;
}
} ;
public String name;
private Season ( String name) {
this . name = name;
}
public abstract void show ( ) ;
}
public class EnumDemo {
public static void main ( String[ ] args) {
System. out. println ( Season. SPRING) ;
System. out. println ( Season. SUMMER) ;
System. out. println ( Season. AUTUMN) ;
System. out. println ( Season. WINTER) ;
Season spring = Season. SPRING;
}
}
4.4 枚举的方法
方法介绍
方法名 说明 String name() 获取枚举项的名称 int ordinal() 返回枚举项在枚举类中的索引值 int compareTo(E o) 比较两个枚举项,返回的是索引值的差值 String toString() 返回枚举常量的名称 static T valueOf(Class type,String name) 获取指定枚举类中的指定名称的枚举值 values() 获得所有的枚举项
示例代码
public enum Season {
SPRING, SUMMER, AUTUMN, WINTER;
}
public class EnumDemo {
public static void main ( String[ ] args) {
String name = Season. SPRING. name ( ) ;
System. out. println ( name) ;
System. out. println ( "-----------------------------" ) ;
int index1 = Season. SPRING. ordinal ( ) ;
int index2 = Season. SUMMER. ordinal ( ) ;
int index3 = Season. AUTUMN. ordinal ( ) ;
int index4 = Season. WINTER. ordinal ( ) ;
System. out. println ( index1) ;
System. out. println ( index2) ;
System. out. println ( index3) ;
System. out. println ( index4) ;
System. out. println ( "-----------------------------" ) ;
int result = Season. SPRING. compareTo ( Season. WINTER) ;
System. out. println ( result) ;
System. out. println ( "-----------------------------" ) ;
String s = Season. SPRING. toString ( ) ;
System. out. println ( s) ;
System. out. println ( "-----------------------------" ) ;
Season spring = Enum. valueOf ( Season. class , "SPRING" ) ;
System. out. println ( spring) ;
System. out. println ( Season. SPRING == spring) ;
System. out. println ( "-----------------------------" ) ;
Season[ ] values = Season. values ( ) ;
for ( Season value : values) {
System. out. println ( value) ;
}
}
}
5. 注解
5.1 概述
对我们的程序进行标注和解释 注解和注释的区别
使用注解进行配置配置的优势
5.2 JDK中的注解
注解 作用 @Override 描述子类重写父类的方法 @SuppressWarnings 压制警告 @Deprecated 描述方法过时
@SuppressWarnings ( value = "all" )
public class Zi extends Fu {
@Override
public void show ( ) {
System. out. println ( "子类的方法" ) ;
}
@Deprecated
public void method ( ) {
System. out. println ( "method......." ) ;
}
public void function2 ( ) {
int a = 10 ;
}
@SuppressWarnings ( value = "all" )
public void function ( ) {
int a = 10 ;
int b = 20 ;
}
}
5.3 自定义注解
格式public @interface 注解名称 {
public 属性类型 属性名( ) default 默认值 ;
}
在定义属性的时候,可以通过default子句去给该属性指定默认值 属性类型
基本数据类型 String类型 Class类型 注解类型 枚举类型 以上类型的一维数组 代码演示public @interface Anno1 {
int a ( ) default 23 ;
public String name ( ) default "itheima" ;
public Class clazz ( ) default Anno2. class ;
public Anno2 anno ( ) default @Anno2 ;
public Season season ( ) default Season. SPRING;
public int [ ] arr ( ) default { 1 , 2 , 3 , 4 , 5 } ;
public Season[ ] seasons ( ) default { Season. SPRING, Season. SUMMER} ;
public String value ( ) ;
}
@Anno1 ( "abc" )
public class AnnoDemo {
}
注意
如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
5.4 自定义注解案例
方法 说明 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果此元素上 存在指定类型的注释,则返回true,否则返回false
需求
自定义一个注解@Test,用于指定类的方法上,如果某一个类的方法上使用了该注解,就执行该方法 实现步骤
自定义一个注解Test,并在类中的某几个方法上加上注解 在测试类中,获取注解所在的类的Class对象 获取类中所有的方法对象 遍历每一个方法对象,判断是否有对应的注解 代码实现
@Retention ( value = RetentionPolicy. RUNTIME)
public @interface Test {
}
public class UseTest {
public void show ( ) {
System. out. println ( "UseTest....show...." ) ;
}
@Test
public void method ( ) {
System. out. println ( "UseTest....method...." ) ;
}
@Test
public void function ( ) {
System. out. println ( "UseTest....function...." ) ;
}
}
public class AnnoDemo {
public static void main ( String[ ] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class clazz = Class. forName ( "com.itheima.myanno3.UseTest" ) ;
UseTest useTest = ( UseTest) clazz. newInstance ( ) ;
Method[ ] methods = clazz. getDeclaredMethods ( ) ;
for ( Method method : methods) {
if ( method. isAnnotationPresent ( Test. class ) ) {
method. invoke ( useTest) ;
}
}
}
}
5.5 元注解
概述
元注解介绍
元注解名 说明 @Target 指定了注解能在哪里使用 @Retention 可以理解为保留时间(生命周期) @Inherited 表示修饰的自定义注解可以被子类继承 @Documented 表示该自定义注解,会出现在API文档里面。
示例代码
@Target ( { ElementType. FIELD, ElementType. TYPE, ElementType. METHOD} )
@Retention ( RetentionPolicy. RUNTIME)
public @interface Anno {
}
@Anno
public class Person {
}
public class Student extends Person {
public void show ( ) {
System. out. println ( "student.......show.........." ) ;
}
}
public class StudentDemo {
public static void main ( String[ ] args) throws ClassNotFoundException {
Class clazz = Class. forName ( "com.itheima.myanno4.Student" ) ;
boolean result = clazz. isAnnotationPresent ( Anno. class ) ;
System. out. println ( result) ;
}
}
6. 单元测试
6.1 概述
单元测试
常见的单元测试工具:Junit JUnit是一个 Java 编程语言的单元测试工具,是一个非常重要的测试工具
6.2 Junit 特点
JUnit是一个开放源代码的测试工具。 提供注解来识别测试方法。 JUnit测试可以让你编写代码更快,并能提高质量。 JUnit优雅简洁。没那么复杂,花费时间较少。 JUnit在一个条中显示进度。如果运行良好则是绿色;如果运行失败,则变成红色。
6.3 使用步骤
将junit的jar包导入到工程中 junit-4.9.jar 编写测试方法该测试方法必须是公共的无参数无返回值的非静态方法 在测试方法上使用@Test注解标注该方法是一个测试方法 选中测试方法右键通过junit运行该方法
6.4 相关注解
7. 日志
7.1 概述
如果我们想清楚的知道程序在运行时候的一些详细信息,该怎么是实现 程序中的日志可以用来记录程序在运行的时候点点滴滴。并可以进行永久存储。 日志与输出语句的区别
输出语句 日志技术 取消日志 需要修改代码,灵活性比较差 不需要修改代码,灵活性比较好 输出位置 只能是控制台 可以将日志信息写入到文件或者数据库中 多线程 和业务代码处于一个线程中 多线程方式记录日志,不影响业务代码的性能
7.2 日志体系结构和Log4J
体系结构 常见的日志接口有两个:JCL,slf4j
JCL是sun公司提供的一套日志接口,但是这套日志在使用的时候是存在问题的,因此后来就出现了第三方的日志接口:slf4j slf4j是一套日志接口,是由很多的抽象类和接口组成,不能真正的干活,因此后期针对这套接口又提供了很多的实现类。目前市面上使用最多的就是log4j,logback。这里介绍比较简单的log4j Log4J
Log4j是Apache的一个开源项目。 通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件等位置。 我们也可以控制每一条日志的输出格式。 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。 最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
7.3 入门案例
使用步骤
导入log4j的相关jar包 编写log4j配置文件 在代码中获取日志的对象,即创建一个日志记录器对象(这个Logger对象是slf4j里面的) 按照级别设置记录日志信息 代码示例
log4j. rootLogger= debug, my, fileAppender
### direct log messages to my ###
log4j. appender. my= org. apache. log4j. ConsoleAppender
log4j. appender. my. ImmediateFlush = true
log4j. appender. my. Target= System. out
log4j. appender. my. layout= org. apache. log4j. PatternLayout
log4j. appender. my. layout. ConversionPattern= % d % t % 5 p % c{ 1 } : % L - % m% n
# fileAppender演示
log4j. appender. fileAppender= org. apache. log4j. FileAppender
log4j. appender. fileAppender. ImmediateFlush = true
log4j. appender. fileAppender. Append= true
log4j. appender. fileAppender. File= D: / log4j- log. log
log4j. appender. fileAppender. layout= org. apache. log4j. PatternLayout
log4j. appender. fileAppender. layout. ConversionPattern= % d % 5 p % c{ 1 } : % L - % m% n
public class Log4JTest01 {
private static final Logger LOGGER = LoggerFactory. getLogger ( Log4JTest01. class ) ;
public static void main ( String[ ] args) {
LOGGER. debug ( "debug级别的日志" ) ;
LOGGER. info ( "info级别的日志" ) ;
LOGGER. warn ( "warn级别的日志" ) ;
LOGGER. error ( "error级别的日志" ) ;
}
}
7.4 配置文件详解
三个核心
Loggers(记录器) :日志的级别
Loggers组件在此系统中常见的五个级别:DEBUG、INFO、WARN、ERROR 和 FATAL。 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=INFO,ca,fa ConsoleAppender常用的选项
ImmediateFlush=true
表示所有消息都会被立即输出,设为false则不输出,默认值是true。 Target=System.err
FileAppender常用的选项
ImmediateFlush=true
表示所有消息都会被立即输出。设为false则不输出,默认值是true Append=false
true表示将消息添加到指定文件中,原来的消息不覆盖。 false则将消息覆盖指定的文件内容,默认值是true。 File=D:/logs/logging.log4j
PatternLayout常用的选项
7.5 在项目中的应用
导入相关所需要的jar包 将properties配置文件复制到src目录下 在代码中获取日志的对象 按照级别设置记录日志信息