本帖最后由 小石姐姐 于 2018-11-30 15:06 编辑
day07 线程间通信 线程池 Lambda表达式
等待唤醒中的方法
java.lang.Object类:
// 成员方法 (只能通过"锁对象"调用)
void notify(): 随机唤醒在同一个锁对象上的某一个处于等待状态的线程
void notifyAll(): 唤醒所有在同一个锁对象上处于等待状态的线程
void wait(): 让当前线程处于无限等待状态, 同时释放锁
可以通过等待唤醒,实现线程的交替运行,
例如:
[AppleScript] 纯文本查看 复制代码 boolean lock=false;
A线程中
synchronized(lock)
{
if(lock){
lock.wait();//此处为方便阅读省略try catch,下同
}
...
Thread.sleep(2000);
lock=true;
lock.nofity();
}
b线程中
synchronized(lock)
{
if(!lock){
lock.wait();
}
...
lock=false;
lock.nofity();
}
线程池:
节省内存资源
java.util.concurrent.Executors类: 线程池工厂类, 用于创建和管理线程池
// 静态方法:
static ExecutorService newFixedThreadPool(int nThreads): 创建固定数量线程的线程池(常用)
java.util.concurrent.ExecutorService接口: 真正执行任务的线程池服务
// 成员方法:
Future submit(Runnable task): 提交一个Runnable任务
void shutdown(): 通知线程执行完任务后关闭. 如不调此方法, 则线程执行完任务后仍在运行以便重复使用
线程池的创建和使用步骤:
1. 使用Executors的静态方法 newFixedThreadPool(int nThreads) 创建线程池ExecutorService
2. 创建一个任务类, 实现Runnable接口, 重写run()方法
3. 调用ExecutorService对象的 submit(Runnable task) 方法, 传递任务给线程池, 执行任务
4. 调用ExecutorService对象的 shutdown() 方法, 销毁线程池 (不建议执行)
lambda表达式
格式:(参数列表) -> {一些重写方法的代码}
应用条件:函数式接口:
函数式接口: "有且仅有一个抽象方法的接口"
但函数式接口对于 哪些方法算作抽象方法 有特殊规定:
1. 有方法体的方法"不算作"抽象方法, 如默认方法, 静态方法, 私有方法
2. 如果一个抽象方法 与 java.lang.Object类中的方法 定义相同的, 也"不算作"抽象方法
因为任何实现本接口的实现类, 都会直接或间接继承java.lang.Object类的public的方法, 所以在创建实现类时其实不用重写该抽象方法, 也就不算作抽象方法
可以省略的部分:
1. (参数列表): 参数"类型"可以省略 (a, b) -> {}
2. (参数列表): 如果参数只有1个, 则"类型"和"小括号"都可以省略 a -> sout(a)
3. {一些代码}: 如果只有一条代码, 则"大括号", "return", "分号"都可以"一起省略"
day08 File类 递归
file类:
java.io.File类: 文件和目录的路径名的抽象表现形式, 主要用于文件和目录的创建, 查找和删除等操作
// 静态成员变量
static String pathSeparator: 路径分隔符的字符串形式
static char pathSeparatorChar: 路径分隔符的char形式
Windows系统是 分号;
Linux系统是 冒号:
static String separator: 文件名称分隔符的字符串形式
static char separatorChar: 文件名称分隔符的char形式
Window系统是 反斜杠\
Linux系统是 正斜杠/
绝对路径:
以盘符开始的路径
如: "D:\\a\\hi.txt"
相对路径:
不以盘符开始的简化路径. IDEA项目, 相对于项目的根目录
如: "a\\1.mp3", "123.txt"
"d:\\t"
File File(String pathname): 根据 路径字符串 封装一个File对象
File File(String parent, String child): 根据 父路径字符串 和 子路径字符串 封装File对象
File File(File parent, String child): 根据 父路径的File对象 和 子路径 封装File对象
java.io.File类
// 常用获取方法
String getAbsolutePath(): 返回此File的绝对路径名字符串
String getPath(): 获取File对象的封装路径 (创建对象时传入的路径)
String getName(): 获取File对象的文件名或目录名 d:\a\b\c\aaa.txt
long length(): 获取File表示的"文件"大小的字节byte数 (不能获取目录的大小)
// 常用判断方法
boolean exists(): 判断File对象代表的文件或目录是否实际存在
boolean isDirectory(): 判断File表示的是否为目录
boolean isFile(): 判断File表示的是否为文件
// 常用创建删除方法
boolean createNewFile(): 当文件不存在时, 创建一个新的空文件
false: 路径已经存在(无论文件还是目录)
抛IO异常: 写的路径不符合逻辑 (Y:\\a.txt\dsfsd)
boolean delete(): 删除由此File表示的文件或目录.
删除目录时: 必须是空目录
boolean mkdir(): 创建File表示的目录 "d:\\a\\b\\c\\我的目录"
false: 1. 路径已经存在(无论文件还是目录) 2. 写的路径不符合逻辑 (Y:\\a.txt\dsfsd)
boolean mkdirs(): 创建File表示的多级目录 "d:\\a\\b\\c\\我的目录"
false: 1. 路径已经存在(无论文件还是目录) 2. 写的路径不符合逻辑 (Y:\\a.txt\ds)
// 常用获取目录中内容的方法
String[] list(): 获取当前File目录下的所有子文件或目录的名字数组
File[] listFiles(): 获取当前File目录中的所有子文件或目录的File对象数组
递归:
Java中实现递归的方式:
方法内部调用方法自己 (所以必须定义方法)
递归的分类:
直接递归: 方法自己调用方法
间接递归: A方法调用B方法, B方法调用C方法, C方法调用A方法
递归时的注意事项:
1. 递归要有限定条件(出口), 保证递归能够停止(就是在某种情况下方法不再调用自己), 否则会栈内存溢出
2. 递归次数不能太多, 否则会栈内存溢出
3. 构造方法不能递归
递归的使用前提:
调用方法时, 方法的主体不变, 但每次传递的参数值不同, 可以使用递归
递归求1-5的和:
[AppleScript] 纯文本查看 复制代码 public static void main(String[] args) {
int sum = sum(5);
System.out.println(sum);
}
public static int sum(int n) {
if (n == 1) {
return 1;
}
return n + sum(n-1);
}
递归打印多级目录:
[AppleScript] 纯文本查看 复制代码 File[] listFiles()
for(File file : arr) {
if (是文件) {
直接操作
} else {
是目录, 就递归调用方法
}
}
FileFilter文件过滤器的原理和使用:
java.io.File类: Filter过滤器
File[] listFiles(FileFilter filter): 返回文件过滤器过滤后的File对象数组
File[] listFiles(FilenameFilter filter): 返回文件过滤器过滤后的File对象数组
java.io.FileFilter接口: 用于File对象的过滤器
boolean accept(File pathName): true则会将参数的File对象加入返回的File[], false则不加入
java.io.FilenameFilter接口: 将File对象拆分为父路径和子路径来判断的过滤器
boolean accept(File dir, String name): true则会将参数的File对象加入返回的File[], false则不加入
dir: 被找到的文件所在的目录 (父路径)
name: 文件的名称 (子路径)
文件过滤器的Lambda优化例子:
//筛选出目录下.java文件和及目录,并存储为一个File数组
File[] childFiles = dir.listFiles((d, name) -> new File(d, name).isDirectory() || name.toLowerCase().endsWith(".java"));
day09 字节流 字符流 Properties
字节输出流: OutputStream和FileOutputStream
java.io.OutputStream抽象类: 字节输出流 (顶层类)
// 成员方法
void close() :释放资源
void flush() :刷新缓冲区(对于字节流来说没有作用)
// 写字节的成员方法
abstract void write(int b): 一次写一个字节 (参数int便于传递byte的整数不用强转)
void write(byte[] b): 一次写一个字节数组
void write(byte[] b, int offset, int len): 一次写一个字节数组的一部分
java.io.FileOutputStream类: 文件字节输出流 (向文件写数据)
// 构造方法
FileOutputStream(String name): 通过文件路径创建文件字节输出流
FileOutputStream(File file): 通过File对象创建文件字节输出流
构造方法的作用:
1. 创建一个FileOutputStream对象
2. 根据构造方法传递的路径, 在磁盘上创建一个空文件 ("如果文件存在则会清空数据")
3. 将创建的FileOutputStream对象指向这个磁盘上的文件
文件存储原理和记事本打开文件的原理:
向文件中写入字节数据时, 十进制的数字会被转换为"二进制"的数字写入文件
文本编辑器打开文本文件时, 会先查询编码表, 将二进制数字转换为对应的字符进行显示
0-127: 查询ASCII码表 -128~127
其他: 查询系统默认码表
Windows简体中文系统的程序打开是按 GBK 码表
IDEA中使用的是 UTF-8 码表
ASCII编码表: 1个byte就是一个字符
GBK编码表: 2个byte数字组成一个汉字
UTF-8编码表: 3个byte数字组成一个汉字 (utf-8其实是不定长的)
字节输出流: 续写, 换行:
java.io.FileOutputStream类: 文件字节输出流
// 带有 续写 功能的构造方法, 不会清空文件
FileOutputStream(String name, boolean append): 通过文件路径创建流, true可以续写
FileOutputStream(File file, boolean append): 通过File对象创建流, true可以续写
换行符:
Windows系统: "\r\n"
Linux系统: "\n"
MacOS系统: "\r"
字节输入流: InputStream和FileInputStream
java.io.InputStream抽象类: 字节输入流 (顶层类)
// 常用成员方法
void close(): 释放资源
// 读数据的方法
int read(): 一次读一个字节
读到文件末尾返回-1 (返回int也是为了代码编写方便)
int read(byte[] b): 一次读一个字节数组
读到的字节存放在参数中的字节数组中, 返回int值是本次读到的字节的个数. 读到文件末尾返回-1
java.io.FileInputStream类: 文件字节输入流
// 构造方法
FileInputStream(String name): 使用文件路径创建文件字节输入流
FileInputStream(File file): 使用File对象创建文件字节输入流
构造方法的作用:
1. 创建FileInputStream对象
2. 将FileInputStream对象指向磁盘上的文件
字节流复制图片文件:
文件复制的步骤:
1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
3.使用字节输入流对象中的方法read读取文件
4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
5.释放资源
字节流读取中文问题:
编码不同不要使用字节流读取,会引起乱码,应使用day10中的转换流读取。
字符输入流: Reader和FileReader:
java.io.Reader抽象类: 字符输入流 (顶层)
// 常用成员方法
void close() :关闭此流并释放与此流相关联的任何系统资源
// 读
int read(): 一次读一个字符char, 返回读到的字符.
读到文件末尾返回-1 (返回int为了代码编写方便)
int read(char[] cbuf): 一次读取一个字符数组char[]
返回读取的字符个数. 读到文件末尾返回-1
java.io.FileReader类: 文件字符输入流
// 构造方法
FileReader(File file): 根据File对象创建文件字符输入流
FileReader(String fileName): 根据File对象创建文件字符输入流
构造方法的作用:
1. 创建FileReader对象
2. 将FileReader对象指向磁盘上的文件
字符输出流: 续写, 换行:
FileWriter中带有续写功能的构造:
FileWriter(File file, boolean append): 通过File对象创建流. 第二个参数为true可以续写
FileWriter(String fileName, boolean append): 通过文件路径创建流. 第二个参数为true可以续写
换行:
windows: "\r\n" fw.write("\r\n");
字节流 和 字符流 如何选择:
1. 如果不确定读写的是什么类型的数据, 用字节流最通用
2. 如果确定读写的就是文本, 用字符流最方便
IO异常处理:
IO流操作中的异常处理:
IO流的标准格式:
[AppleScript] 纯文本查看 复制代码 FileWriter fw = null;
try {
//IO流对象的创建, 操作等代码
fw = new FileWriter("d:\\09_IOAndProperties\\g.txt", true);
for (int i = 0; i <10 ; i++) {
fw.write("HelloWorld"+i+"\r\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源
if(fw != null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
JDK7和JDK9中IO异常处理的不同方式:
JDK 7 增加的 "try-with-resource"
省略了 finally, 可自动释放资源
// 格式
try (创建流对象语句,如果多个,使用';'隔开) {
// 读写数据
} catch (IOException e) {
e.printStackTrace();
}
JDK 9 对于"try-with-resource"的改进:
流对象的声明和创建可以放在括号外面
流对象要求是有效final的.(即不要修改流对象的值)
Properties集合:
Properties存储数据和遍历:
Properties双列集合:
键和值都是 String 类型
java.util.Properties类: 属性集, 属于Map的双列集合, 继承自Hashtable
// 构造方法
Properties(): 创建一个Properties集合
// 可以使用Map接口中的方法
// 特有成员方法
Object setProperty(String key, String value): 保存/替换键值对
String getProperty(String key): 通过键获取值. 键不存在返回null
Set<String> stringPropertyNames(): 返回键的集合
void store(OutputStream out, String comments): 将集合用字节流写入文件(不能中文),并写入注释
void store(Writer writer, String comments): 将集合用字符流写入文件(可以中文),并写入注释
void load(InputStream inStream): 从配置文件中通过字节流加载数据到Properties集合(不能中文)
void load(Reader reader): 从配置文件中通过字符流加载数据到Properties集合(可以中文)
Properties: store()存储数据到文件:
Properties将数据写入到文件的方法:
void store(OutputStream out, String comments): 将集合用字节流写入文件(不能中文),并写入注释
void store(Writer writer, String comments): 将集合用字符流写入文件(可以中文), 并写入注释
使用步骤:
1.创建Properties集合对象,添加数据
2.创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
4.释放资源
Properties: load()从文件加载数据到集合
Properties将数据从文件加载到集合中的方法:
void load(InputStream inStream): 从配置文件中通过字节流加载数据到Properties集合(不能读中文)
void load(Reader reader): 从配置文件中通过字符流加载数据到Properties集合(可以读中文)
使用步骤:
1.创建Properties集合对象
2.使用Properties集合对象中的方法load读取保存键值对的文件
3.遍历Properties集合
day10 缓冲流 转换流 序列化流 打印流
缓冲字节输出流: BufferedOutputStream:
字节缓冲流
|_ BufferedInputStream # 缓冲字节输入流
|_ BufferedOutputStream # 缓冲字节输出流
字符缓冲流
|_ BufferedReader # 缓冲字符输入流
|_ BufferedWriter # 缓冲字符输出流
java.io.BufferedOutputStream类: 缓冲字节输出流
// 构造方法
BufferedOutputStream(OutputStream out): 使用基本流创建一个缓冲字节输出流
BufferedOutputStream(OutputStream out, int size): 使用基本流创建一个缓冲字节输出流, 设置缓冲区大小
BufferedOutputStream使用步骤:
1.创建FileOutputStream对象, 构造方法中绑定要输出的目的地
2.创建BufferedOutputStream对象, 构造方法中传递FileOutputStream对象
3.使用BufferedOutputStream对象中的方法 write(), 把数据写入到内部缓冲区中
4.使用BufferedOutputStream对象中的方法 flush(), 把内部缓冲区中的数据,刷新到文件中
5.释放资源(会先调用flush方法刷新数据, 第4步可以省略)
FileOutputStream fos = new FileOutputStream("文件路径");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("你好".getBytes());
// bos.flush(); // 可以省略
bos.close();
缓冲字节输入流: BufferedInputStream
java.io.BufferedInputStream类: 缓冲字节输入流
// 构造方法
BufferedInputStream(InputStream in): 使用基本流创建一个缓冲字节输入流
BufferedInputStream(InputStream in, int size): 使用基本流创建一个缓冲字节输入流, 设置缓冲区大小
使用步骤:
1.创建FileInputStream对象, 构造方法中绑定要读取的数据源
2.创建BufferedInputStream对象, 构造方法中传递FileInputStream对象
3.使用BufferedInputStream对象中的方法 read(), 读取文件
4.释放资源 close()
FileInputStream fis = new FileInputStream("文件路径");
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
bis.close();
缓冲流 + 一次读写一个字节数组 效率最高
缓冲字符输出流: BufferedWriter:
java.io.BufferedWriter类:
// 构造方法
BufferedWriter(Writer out): 使用基本流创建一个缓冲字符输出流
BufferedWriter(Writer out, int size): 使用基本流创建一个缓冲字符输出流, 设置缓冲区大小
// 特有方法
void newLine(): 写入一个换行符, 换行符自动根据当前系统确定
缓冲字符输入流: BufferedReader:
java.io.BufferedReader类: 缓冲字符输入流
// 构造方法
BufferedReader(Reader in): 使用基本流创建一个缓冲字符输入流
BufferedReader(Reader in, int size): 使用基本流创建一个缓冲字符输入流, 设置缓冲区大小
// 特有方法
String readLine(): 一次读一行字符串, "不包含换行符". 读到文件末尾返回null
转换流:
OutputStreamWriter类介绍及使用:
java.io.OutputStreamWriter类: 输出转换流. 字符流通往字节流的桥梁
// 构造方法
OutputStreamWriter(OutputStream out): 使用默认编码表创建转换流
OutputStreamWriter(OutputStream out, String charsetName): 使用指定编码表创建转换流
// 使用默认UTF-8
OutputStreamWriter o = new OutputStreamWriter(new FileOutputStream("a.txt"));
o.write("dsfdsfdsaf")
// 使用指定的GBK
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"), "GBK");
osw.write("你") -> 查"GBK"码表 -> -1,-2 -> FileOutputStream -> a.txt文件
写数据: 字符流 --------------------------> 字节流
InputStreamReader类介绍及使用:
java.io.InputStreamReader类: 输入转换流. 字节流通往字符流的桥梁
// 构造方法
InputStreamReader(InputStream in): 使用默认编码表创建转换流
InputStreamReader(InputStream in, String charsetName): 使用指定编码表创建转换流
// 使用默认UTF-8
InputStreamReader r = new InputStreamReader(new FileInputStream("a.txt"));
// 使用指定的GBK
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "GBK");
'你' <- 查"GBK"码表 <- isr.read() <- -1,-2 <- FileInputStream <- a.txt文件
读数据: 字符流 <---------- 字节流
序列化流(对象流):
序列化: 内存中的对象转换为字节序列, 以流的方式写入到磁盘的文件中
对象 -> 字节
反序列化: 磁盘文件中的字节序列, 以流的方式读取到内存中变成对象
字节 -> 对象
通过序列化流, 我们可以将内存中的数据方便的存储到磁盘上, 下次程序启动后也能从磁盘读取恢复之前的对象状态
OutputStream
|_ ObjectOutputStream类: 对象字节输出流
InputStream
|_ ObjectInputStream类: 对象字节输入流
对象序列化流: ObjectOutputStream:
java.io.ObjectOutputStream类: 对象字节输出流
// 构造方法
ObjectOutputStream(OutputStream out)
// 特有成员方法
void writeObject(Object obj): 将对象写出
// 创建对象输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.txt"));
// 写对象
Student s = new Student("小美女", 18);
oos.writeObject(s);
// 释放资源
oos.close();
注意:
被读写的对象的类必须实现"java.io.Serializable"接口, 否则会抛出"NotSerializableException"
对象反序列化流: ObjectInputStream:
java.io.ObjectInputStream类: 对象字节输入流
// 构造方法
ObjectInputStream(InputStream in)
// 特有成员方法
Object readObject(): 读取对象
// 创建对象输入流
ObjectInputStream oos = new ObjectInputStream(new FileInputStream("student.txt"));
// 读对象
Object o = oos.readObject();
Student s = (Student)o;
System.out.println(s);
// 释放资源
oos.close();
transient瞬态关键字: 避免属性序列化:
static 修饰的成员变量属于类不属于对象, 所以不能序列化
transient 修饰的成员变量, 不能被序列化
transient 应用场景:
如果对象的某个属性不希望被序列化, 可以使用 transient 修饰, 这样就不会被对象流写到文件中
InvalidClassException异常: 原因和解决方案:
serialVersionUID序列号的作用:
序列化操作时, 会根据类生成一个默认的 serialVersionUID 属性, 写入到文件中.
该版本号是根据类中成员计算出来的一个数值. 当类的成员发生改变时, 序列版本号也会发生变化
当代码中的类和读取的对象序列版本号不一致时, 就会抛出InvalidClassException
为了避免这种问题, 我们可以手动写死这个序列号, 这样无论成员如何变化, 序列版本号都是一样的
打印流:
打印流PrintStream: 概述和使用:
PrintStream特点:
1. 只有输出流, 没有输入流
2. PrintStream不会抛出IOException
3. 有特殊方法 print(), println(), 可以输出任意类型的值, 原样输出
java.io.PrintStream类: 字节打印流
// 构造方法
PrintStream(File file): 创建字节打印流, 输出到一个文件
PrintStream(OutputStream out): 创建字节打印流, 输出到一个字节输出流
PrintStream(String fileName): 创建字节打印流, 输出到一个文件路径
注意事项:
如果用 write(97) 方法, 会查编码表 97 -> a
如果用 print(97), println(97), 则原样输出 97 int -> '9''7' -> byte -> 文件 97
System.out.println();
PrintStream out;
java.lang.System类:
// 静态方法
static void setOut(PrintStream out): 设置System.out的输出目的地为参数的打印流
IO框架体系结构:
// 体系结构:
字节流
|_ InputStream # 字节输入流
| |_ FileInputStream # 专门操作文件的字节输入流
| |_ BufferedInputStream # 带有缓冲区的字节输入流, 效率高
| |_ ObjectInputStream # 对象输入流
|
|_ OutputStream # 字节输出流
|_ FileOutputStream # 专门操作文件的字节输出流
|_ BufferedOutputStream # 带有缓冲区的字节输出流, 效率高
|_ ObjectOutputStream # 对象输出流
|_ PrintStream # 字节打印流
字符流
|_ Reader # 字符输入流
| |_ BufferedReader # 带有缓冲区的字符输入流, 效率高
| |_ InputStreamReader # 将字节流转换为字符流输入的转换输入流
| |_ FileReader # 专门操作文件的字符输入流
|
|_ Writer # 字符输出流
|_ BufferedWriter # 带有缓冲区的字符输出流, 效率高
|_ OutputStreamWriter # 将字符流转换为字节流输出的转换输出流
| |_ FileWriter # 专门操作文件的字符输出流
附打砖块java小程序(有些功能正在开发中。。):[Java] 纯文本查看 复制代码 package olddriver;[/size][/color][/size][/color]
import javax.swing.*;
import java.awt.*;
import java.awt.Font;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.ReentrantLock;
import static java.util.concurrent.Executors.newFixedThreadPool;
public class OnScreen extends JFrame implements KeyListener{
public static final ReentrantLock lock=new ReentrantLock();
private static final int FRONTLINE =34, LEFTLINE =32;
private static int playerpoint= LEFTLINE /2-3;
private static final int HIGH = FRONTLINE -2;
private static ArrayList<Boolean> monster_row1 = new ArrayList<>();
private static ArrayList<Boolean> monster_row2 = new ArrayList<>();
private static ArrayList<Boolean> monster_row3 = new ArrayList<>();
private static ArrayList<Boolean> monster_row4 = new ArrayList<>();
private static ArrayList<Boolean> monster_row5 = new ArrayList<>();
private static ArrayList<Boolean> monster_row6 = new ArrayList<>();
private static ArrayList<Boolean> monster_list = new ArrayList<>();
private static ArrayList<ArrayList<Boolean>> monster_row =new ArrayList<>();
private static int ball_row = LEFTLINE /2;
private static int ball_list = HIGH -1;
private static boolean gamestart=false;
private static int gamespeed=100;
private static boolean gameover=true;
private static boolean hardselect=false;
private static final String info="哲学版打方块5.0版本 \n 请选择游戏难度 \n 数字键:0-6 \n 其它键为默认难度 \n 0最快 6最慢 \n 左右键或者AD键控制方向";
private static ExecutorService gameline=newFixedThreadPool(2);
private Center center=new Center();
private FlushWindow flushWindow=new FlushWindow();
private static JMenuBar jMenuBar=new JMenuBar();
private static JMenu jMenu1=new JMenu("文件");
private static JMenuItem jMenuItem1=new JMenuItem("打开历史记录");
private static File savefile=new File("abc.save");
private static FileInputStream load;
JPanel jp1;
static JTextPane jt1;
public OnScreen(){
jp1=new JPanel();
jt1=new JTextPane();
jp1.add(jt1);
jt1.setPreferredSize(new Dimension(450,590));
jt1.setEditable(false);
jt1.setFont(new Font("黑体", Font.BOLD,30));
jt1.addKeyListener(this);
this.add(jp1, BorderLayout.CENTER);
this.setSize(500,690);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(800,360);
this.setResizable(false);
this.setVisible(true);
this.setTitle("哲学版打方块5.0!!!");
this.setJMenuBar(jMenuBar);
jMenuBar.add(jMenu1);
jMenu1.add(jMenuItem1);
if (!savefile.exists()) {
try {
savefile.createNewFile();
} catch (IOException e) {
}
} else{
try {
load=new FileInputStream(savefile);
} catch (FileNotFoundException e) {
}
}
}
public static void main(String[] args) {
gameInit();
OnScreen onScreen=new OnScreen();
jt1.setText(info);
// playerpoint=LEFTLINE-6;
/*//左右移动小测试
boolean left=false;
boolean right=false;
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (playerpoint<LEFTLINE-6 && !right){
playerpoint++;
} else if (playerpoint==LEFTLINE-6){
playerpoint--;
right=true;
} else if(playerpoint==1){
playerpoint++;
right=false;
} else if (right && playerpoint>1){
playerpoint--;
}
onScreen.jt1.setText(onScreen.flushScreen(playerpoint));
}*/
//
//刷新画面
// onScreen.center();
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (!gamestart && !hardselect) {
gameHard((char)e.getKeyCode());
hardselect=true;
}
if (!gamestart && hardselect){
jt1.setFont(new Font("黑体", Font.BOLD,12));
gamestart=true;
gameover=true;
gameline.submit(center);
gameline.submit(flushWindow);
playerpoint++;
}
if ((e.getKeyCode()==KeyEvent.VK_LEFT || e.getKeyCode()==KeyEvent.VK_A) && playerpoint>1 && gameover){
playerpoint--;
}
if((e.getKeyCode()==KeyEvent.VK_RIGHT || e.getKeyCode()==KeyEvent.VK_D) && playerpoint< LEFTLINE -6 && gameover){
playerpoint++;
}
}
@Override
public void keyReleased(KeyEvent e) {
if ((e.getKeyCode()==KeyEvent.VK_LEFT || e.getKeyCode()==KeyEvent.VK_A) && playerpoint>1 && gameover){
playerpoint--;
} else if((e.getKeyCode()==KeyEvent.VK_RIGHT || e.getKeyCode()==KeyEvent.VK_D) && playerpoint< LEFTLINE -6 && gameover){
playerpoint++;
}
}
public static String flushScreen(int playerpoint){
String temp="";
for (int i = 0; i <= FRONTLINE; i++) {
for (int i1 = 0; i1 <= LEFTLINE; i1++) {
if(i == 0 || i == FRONTLINE) {
temp=(temp+"□");
} else if(i1 == 0 || i1 == LEFTLINE) {
temp=(temp+"□");
} else if(i == HIGH && i1 == playerpoint) {
temp=(temp+"======");
i1 += 5;
} else if(monster_list.get(i) && monster_row.get(i>0&&i<6?i-1:5).get(i1)) {
temp=(temp+"♂");
} else if(ball_list==i && ball_row==i1){
temp=(temp+"Ο");
} else {
temp=(temp+" ");
}
}
temp=(temp+"\n");
}
return temp;
}
public static class Center implements Runnable{
@Override
public void run() {
boolean left_wall=true;
boolean right_wall=false;
boolean front_wall=false;
boolean kick=true;
boolean dead=false;
boolean kill_monster=false;
synchronized (lock){
ArrayList<Integer> temp=new ArrayList<>();
while (gameover) {
temp.clear();
for (int i = 0; i < 6; i++) {
temp.add(playerpoint+i);
}
int point=temp.indexOf(ball_row);
try {
Thread.sleep(gamespeed);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(ball_list==FRONTLINE-1){
dead=true;
}
if(ball_row==LEFTLINE-1){
right_wall=true;
left_wall=false;
}
if(ball_list==1){
front_wall=true;
kick=false;
}
if(ball_row==1){
right_wall=false;
left_wall=true;
}
if(ball_list<7){
if(monster_row.get(ball_list-1).get(ball_row-1)){
monster_row.get(ball_list-1).set(ball_row-1,false);
if(monster_row.get(ball_list).get(ball_row-1)){
monster_row.get(ball_list).set(ball_row-1,false);
}
kill_monster=true;
kick=false;
}
}
if(ball_list==HIGH-1 && (point != -1)){
kick=true;
front_wall=false;
kill_monster=false;
if(point==0) {
if(left_wall) {
right_wall = true;
left_wall = false;
}
}
if(point==5) {
if(right_wall) {
right_wall = false;
left_wall = true;
}
}
}
if(dead){
gameover=false;
jt1.setText("你死啦!! \n 莫慌!5秒后游戏重新开始。。");
jt1.setFont(new Font("黑体",Font.BOLD,25));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
gameOver();
break;
}
if(left_wall){
ball_row++;
}
if(right_wall){
ball_row--;
}
if(front_wall){
ball_list++;
}
if(kick){
ball_list--;
}
if(kill_monster){
ball_list++;
}
jt1.setText(flushScreen(playerpoint));
}
}
}
}
private static void init(boolean b){
monster_row1.add(b);
monster_row2.add(b);
monster_row3.add(b);
monster_row4.add(b);
monster_row5.add(b);
}
public static void gameHard(char hard){
switch (hard){
case '0':
gamespeed=33;
break;
case '1':
gamespeed=66;
break;
case '2':
gamespeed=100;
break;
case '3':
gamespeed=200;
break;
case '4':
gamespeed=300;
break;
case '5':
gamespeed=400;
break;
case '6':
gamespeed=500;
break;
case 96:
gamespeed=33;
break;
case 97:
gamespeed=66;
break;
case 98:
gamespeed=100;
break;
case 99:
gamespeed=200;
break;
case 100:
gamespeed=300;
break;
case 101:
gamespeed=400;
break;
case 102:
gamespeed=500;
break;
default:
gamespeed=200;
break;
}
}
public static class FlushWindow implements Runnable{
@Override
public void run() {
synchronized (lock) {
while (gameover) {
jt1.setText(flushScreen(playerpoint));
try {
Thread.sleep(33);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void gameOver() {
gameInit();
jt1.setText(info);
}
public static void gameInit(){
playerpoint= LEFTLINE /2-3;
monster_row1 = new ArrayList<>();
monster_row2 = new ArrayList<>();
monster_row3 = new ArrayList<>();
monster_row4 = new ArrayList<>();
monster_row5 = new ArrayList<>();
monster_row6 = new ArrayList<>();
monster_list = new ArrayList<>();
monster_row =new ArrayList<>();
ball_row = LEFTLINE /2;
ball_list = HIGH -1;
gamespeed=100;
init(false);
for (int i=1;i<LEFTLINE;i++){
init(true);
}
init(false);
for (int i=0;i<=LEFTLINE;i++) {
monster_row6.add(false);
}
monster_list.add(false);
for (int i = 1; i < 6; i++) {
monster_list.add(true);
}
for (int i = 6; i < FRONTLINE; i++) {
monster_list.add(false);
}
monster_row.add(monster_row1);
monster_row.add(monster_row2);
monster_row.add(monster_row3);
monster_row.add(monster_row4);
monster_row.add(monster_row5);
monster_row.add(monster_row6);
gamestart=false;
gameover=false;
hardselect=false;
}
}
|
|