目录
知识点补充
线程通信
生产者与消费者模型
测试类
package com.itheima.thread.communication_thread;
/**
* 生产者和消费者模型
* 需求:有三个厨师做包子和两个客人吃包子
* 客人每次只能吃一个包子,桌上有包子时,客人就可以吃
* 吃完叫厨师做,没包子就等
* 桌上有包子厨师就等,没包子了厨师就做,做完叫客人吃
*/
public class Test {
public static void main(String[] args) {
new Cooker("厨师1").start();
new Cooker("厨师2").start();
new Cooker("厨师3").start();
new Foodie("小明").start();
new Foodie("小红").start();
}
}
Foodie类
package com.itheima.thread.communication_thread;
public class Foodie extends Thread {
public Foodie(String name) {
super(name);
}
@Override
public void run() {
while (true){
synchronized (Desk.class){
if (Desk.count>0){
if (Desk.foodExist){
System.out.println(Thread.currentThread().getName()+"吃掉了一个包子");
Desk.foodExist = false;
Desk.count--;
System.out.println("包子总数剩余:"+Desk.count);
//使用什么当作锁,就要用什么去唤醒线程,让线程等待
Desk.class.notifyAll();
}else {
try {
Desk.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}else {
break;
}
}
}
}
}
Cooker类
package com.itheima.thread.communication_thread;
public class Cooker extends Thread {
public Cooker(String name) {
super(name);
}
@Override
public void run() {
while (true){
synchronized (Desk.class){
if (Desk.count>0){
if (Desk.foodExist){
try {
Desk.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println(Thread.currentThread().getName()+"做了一个包子");
Desk.foodExist = true;
Desk.class.notifyAll();
}
}else{
break;
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Desk 类
package com.itheima.thread.communication_thread;
public class Desk {
//定义食物存在标记
public static boolean foodExist = false;
//定义食物总数量
public static int count = 10;
}
枚举
枚举的特点
1.所有枚举类都是Enum的子类
2.通过枚举类名.枚举项访问枚举项
3.每个枚举项其实就是一个枚举类的对象
4.枚举也是一个类,可以定义成员变量
5.枚举类的第一行必须写枚举项,当枚举项后面没有其他东西时,最后一个枚举项后面的分号可以省略,但不建议省略
6.枚举类可以有构造器,但必须用private修饰,且默认用private修饰,其用法也比较特殊:枚举(“”);
7.枚举类可以有抽象方法,但所有枚举项都必须重写所有抽象方法
枚举的方法
package com.itheima.demo04enum;
/**
* 枚举的方法
*/
public class DemoEnum02 {
public static void main(String[] args) {
//1.String name() 返回枚举项的名称
System.out.println(Name.X.name());
System.out.println("----------------------");
//2.int ordinal() 返回枚举项在枚举类中的索引
System.out.println(Name.X.ordinal());
System.out.println(Name.Y.ordinal());
System.out.println(Name.Z.ordinal());
System.out.println("----------------------");
//3.int compareTo(E e) 比较两个枚举项,返回索引差值
System.out.println(Name.Z.compareTo(Name.X));
System.out.println("----------------------");
//4.String toString() 返回枚举常量的名称
System.out.println(Name.Z.toString());
System.out.println("------------------------");
//5.static <T> valueOf(class <T> type,String name) 获取指定枚举类中指定枚举项的值
System.out.println(Enum.valueOf(Name.class, "Y"));
System.out.println(Name.valueOf("X")==Name.X);
System.out.println("--------------------------");
//6.values() 获取所有枚举项
Name[] values = Name.values();
for (Name value : values) {
System.out.println(value);
}
}
}
Name类
package com.itheima.demo04enum;
/**
* 枚举实际上也是一个类,同样可以定义构造器,成员变量,但一般不这么做
*/
public enum Name {
//枚举项必须重写所有抽象方法
X("李四"){
@Override
public void showName() {
System.out.println(name);
}
},Y("王五"){
@Override
public void showName() {
System.out.println(name);
}
},Z("张三"){
@Override
public void showName() {
System.out.println(name);
}
};//枚举项后面写括号其实就是在调用枚举类的有参构造
public String name;
//空参构造,枚举类的构造器必须是private修饰的,默认也是private修饰
private Name() {
}
//有参构造
Name(String name){
this.name = name;
}
//抽象方法
public abstract void showName();
}
XML文件写入
package com.itheima.d6_write_xml;
import java.io.BufferedWriter;
import java.io.FileWriter;
/**
* 往XML文件中写入数据
* Dom4j提供的写入方法使用比较麻烦,这里使用StringBuilder来做
*/
public class Demo01 {
public static void main(String[] args) {
// 1、使用一个StringBuilder对象来拼接XML格式的数据。
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n");
sb.append("<book>\r\n");
sb.append("\t<name>").append("从入门到跑路").append("</name>\r\n");
sb.append("\t<author>").append("shifan").append("</author>\r\n");
sb.append("\t<price>").append(999.99).append("</price>\r\n");
sb.append("</book>");
try (
BufferedWriter bw = new BufferedWriter(new FileWriter("day14-xml/src/book.xml"));
){
bw.write(sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
DTD约束文件
dtd语法规则
<!-- DTD语法规则
定义元素规则:<!ELEMENT 元素名 元素类型)>
简单元素:
EMPTY:表示标签体为空
ANY:表示标签体可以为空也可以不为空
PCDATA:表示标签体为字符串
复杂元素:
直接写子元素名称.
多个子元素可以使用,或者|隔开
","表示定义子元素的顺序
"|"表示子元素只能出现任意一个
"?"表示零次或一次
"+"表示一次或多次
"*"表示零次或多次
不写默认表示出现一次
定义属性的规则
定义格式:<!ATTLIST 元素名称 属性名称 属性的类型 属性的约束>
属性的类型:CDATA类型 字符串
属性的约束:
#REQUIRED 必需的
#IMPLIED 非必需的
#FIXED value 属性值是固定的
-->
<!ELEMENT persons (person+)>
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ATTLIST person id CDATA #FIXED "1">
dtd的三种引入方式
引入本地约束文件
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 引入dtd约束,persons为根标签名,system表示引入的是本地约束,单引号内是路径 -->
<!DOCTYPE persons SYSTEM 'H:\JavaLearning\JavaSEAdvance\day14-xml\src\com\itheima\d1_xml_constraint\dtd\person.dtd'>
<persons>
<person id="1">
<name>shiafan</name>
<age>30</age>
</person>
<person>
<name>fan</name>
<age>20</age>
</person>
</persons>
xml文件内部引入
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 在XML文件内部引入dtd约束 -->
<!DOCTYPE persons [
<!ELEMENT persons (person+)>
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
]>
<persons>
<person>
<name>shiafan</name>
<age>30</age>
</person>
<person>
<name>fan</name>
<age>20</age>
</person>
</persons>
引入网络dtd
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 引入网络dtd约束 -->
<!DOCTYPE persons PUBLIC "DTD文件名称" "DTD文档URL">
<persons>
<person>
<name>shiafan</name>
<age>30</age>
</person>
<person>
<name>fan</name>
<age>20</age>
</person>
</persons>
schema约束文件
schema与dtd的区别
1.schema约束文件也是一个xml文件,符合xml语法,后缀名为.xsd
2.一个xml文件中可以引入多个schema约束文件,使用名称空间区分(名称空间类似Java包名
3.dtd里元素类型取值比较单一,常见的是#PCDATA类型,schema中可以支持很多数据类型
4.schema语法更复杂
编写schema文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--根标签schema
参数一:表示当前文件是一个约束文件,用于约束别的文件,同时此属性也对schema进行约束
参数二:当前schema文件的名称空间,唯一的url地址,其他文件通过该名称空间引入该约束
参数三:固定格式,表示当前schema文件是一个质量良好的文件-->
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itheima.cn/javase"
elementFormDefault="qualified">
<!-- 定义元素 -->
<element name="persons">
<!-- 表示元素为复杂元素-->
<complexType>
<!-- 表示子元素要按顺序定义-->
<sequence maxOccurs="unbounded">
<element name="person">
<complexType>
<sequence>
<element name="name" type="string"></element>
<element name="age" type="string"></element>
</sequence>
<!--定义属性-->
<attribute name="id" type="string" use="required"></attribute>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
引入schema文件
<?xml version="1.0" encoding="UTF-8" ?>
<!-- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"表示本文件被约束
xmlns="http://www.itcast.cn"约束文件名称空间,表示被该文件约束
xsi:schemaLocation="http://www.itcast.cn data.xsd"> 指定约束文件路径
格式:xsi:schemaLocation="名称空间url 文件路径" 空格隔开
-->
<persons xmlns="http://www.itheima.cn/javase"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.itheima.cn/javase person.xsd">
<person id="1">
<name>shiafan</name>
<age>30</age>
</person>
<person id="2">
<name>fan</name>
<age>20</age>
</person>
</persons>
类加载器
定义
负责将.class文件(物理存储的文件)加载到内存中去
类加载的时机
1.创建类的实例
2.调用类的方法
3.访问类或者接口的类变量,或为类变量赋值
4.使用反射方式强制创建某个类或接口的java.lang.class对象
5.初始化某个类的子类
6.直接使用java.exe命令来运行某个主类
简单来说就是,用到就加载,不用不加载
类加载的过程
加载->链接(验证->准备->解析)->初始化
加载:通过类的全限名获取类的二进制字节流,将字节流所代表的静态存储结构转化为运行时数据结构,在内存中生成一个代表这个类的java.lang.Class对象
验证:链接阶段的第一步,确保Class文件字节流中包含的信息符合当前虚拟机的要求,且不会危害虚拟机自身安全
准备:为类的类变量分配内存,赋值为null
解析:将类的二进制数据流中的符号引用替换成直接引用,如果类中用到了其他类,之前会将其他类替换为符号引用,此时需要找到对应的类,替换为直接引用
初始化:根据程序员的主观计划初始化类变量和其他资源
类加载器分类
启动类加载器,平台类加载器,系统类加载器
双亲委派模型
package com.ithaima.d5_classloader;
/**
* 双亲委派模型
*/
public class Demo01 {
public static void main(String[] args) {
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//获取系统类加载器的父类-->平台类加载器
ClassLoader platformClassLoader = systemClassLoader.getParent();
//获取平台类加载器的父类-->启动类加载器
ClassLoader bootstrapClassLoader = platformClassLoader.getParent();
/*
系统类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
平台类加载器:jdk.internal.loader.ClassLoaders$PlatformClassLoader@79698539
启动类加载器:null
*/
System.out.println("系统类加载器:"+systemClassLoader);
System.out.println("平台类加载器:"+platformClassLoader);
System.out.println("启动类加载器:"+bootstrapClassLoader);
}
}
类加载器的常用方法
package com.ithaima.d5_classloader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 类加载器的常用方法
* public static ClassLoader getSystemClassLoader() 获取系统类加载器
* public InputStream getResourceAsStream(String name) 加载某个资源文件
*/
public class Demo02 {
public static void main(String[] args) throws IOException {
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//获取资源文件字节输入流
InputStream ras = systemClassLoader.getResourceAsStream("prop.properties");
Properties properties = new Properties();
properties.load(ras);
System.out.println(properties);
}
}
UUID类
import java.util.UUID;
public class UUIDDemo {
public static void main(String[] args) {
//生成一个随机且唯一的UUID对象
UUID uuid = UUID.randomUUID();
String replace = uuid.toString().replaceAll("-", "");
//e6268fb7671448d3bab68a44298a02a2
System.out.println(replace);
}
}