【韩顺平】零基础30天学会Java

第一天2023/11/21零钱通项目

视频 0334-0341

  • 概念:面向过程编程&面向对象编程、变量&属性、过程&封装方法。
  • 常见语句1 Scanner:接收输入
Scanner scanner = new Scanner(System.in);
String key = scanner.next();
  • 常见语句2 Data:日期
Date date  = new Date(); //获取当前日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); //日期时间格式化
System.out.println(sdf.format(date));
  • 常见语句3 do{} while(loop): 默认显式一次时,loop = false跳出循环。
    常见语句4 switch:多分支条件
switch(key){
    case "key_value":
        break;
    default:
        ......;
}
  • 编程思想-逆向思维:1)特殊用例更容易想到、2)可扩展性,增添条件语句更简单。

项目二 坦克大战

2023/11/27 视频568-571
Java绘图技术
JFrame 画框、 JPannel画板、 paint(Graphics g) g画笔
调用paint()方法的情况:
(1)组件第一次在屏幕中显示的时候;
(2)窗口最小化,然后再显示;
(3)窗口大小发生变化时。
在这里插入图片描述
2023/12/1 视频577/578
分析:敌 人坦克数量多,可以放到集合Vector,因为考虑多线程问题
2023/12/2 视频579-598
线程的使用-创建线程的两种方法
1 通过继承Thread类创建线程
main 主线程,调用(对象化)继承了线程的类创建子线程Thread0x

public static void main(String[] args) throws InteruptedException{
    Cat cat = new Cat();
}

注意:实现多线程的不是run,而是Thread中的start0方法,原理见方法2

class cat extends Thread {

	@Override
    public viod run(){
        System.out.println(“miaomiao”);
        Thread.sleep(1000);//线程休眠。Command+Alt+T, Surround with: try / catch
    }
}

2 通过实现接口Runnable来开发线程

public static void main(String[] args){
    Dog dog = new Dog();//Dog没有继承Thread,不能直接调用start();实现了Runnable
    Thread thread = new Thread(dog); //1.线程接收了实现Runnable接口的dog对象
    thread.start();//2.线程执行start方法...执行dog的run方法
}

class Dog implements Runnable{}
    @Override
    public void run(){}

因为线程实现了Runnable

public static void main(String[] args){
    Tiger tiger = new tiger();
    ThreadProxy threadProxy = new ThreadProxy(tiger);//1 线程代理接收了实现了Runnable的对象tiger作为target
    threadProxy.start();//2 线程代理执行start方法
}

class ThreadProxy implements Runnable{
   private Runnable target = null;
   @Override
   public void run() {
       if(target != null) {
           target.run();//5.target动态绑定了tiger对象,是想tiger的run方法
       }
   public ThreadProxy(Runnable target) {
       this.target = target;
   }
   public void start(){//3.start方法执行start0方法
       start0();
   }
   public void start0(){//4.start0方法执行run方法
       run();
   }
}

vs
实现Runnable接口方式更加适合多个线程共享一个资源的情况,避免了单继承的限制

T3 t3 = new T3("hello ");
Thread thread01 = new Thread(t3);
Thread thread02 = new Thread(t3);
thread01.start();
thread02.start();   

线程常用方法

线程终止
1 自动退出:线程完成任务后
2 通知方式:使用变量控制run方法退出方式停止线程
在这里插入图片描述
在这里插入图片描述

//设置守护线程
MyDaemonThread myDaemonThread = new MyDaemonThread();
myDaemonThread.setDaemon(true);
myDaemonThread.start
线程的状态 在这里插入图片描述
线程同步机制

在这里插入图片描述

Synchronized方法
1 同步代码块

synchronized (对象) { //得到对象的锁,才能操作同步代码
//需要被同步代码;
}

2 方法声明 同步整个方法

public synchronized void m (String name){
}

根据线程同步机制,Java引入对象“互斥锁”,保证任一时刻只有一个一个线程能够访问该对象。同步会导致程序的执行效率降低。
(1)同步方法(非静态的,没有使用static修饰)的锁默认是this,也可以是其他对象(要求是同一个对象);
(2)同步方法(静态的,使用static修饰)的锁为当前类本身,当前类.class
步骤:1 分析上锁的代码;2选择同步代码块或同步方法;3 多个线程的所对象为同一个。
备注:
实现接口的对象中的this,多个线程是同一this,new Object是不同对象
继承Thread的对象中的this,多个线程是不同的this

释放锁

1 当前线程的同步方法、同步代码块执行结束
2 当前线程同步代码块、同步方法中遇到break、return
3 当前线程同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束
4 当前线程同步代码块、同步方法中,遇到wait()方法,线程暂停,释放锁

不会释放锁的操作:

1 线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield,暂停线程执行
2 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁。注:不推荐使用suspend()和resume()来控制线程

子弹发射

本方坦克

用户按下J键,本方坦克发射一颗子弹
1 当发射一颗子弹后,就相当于启动一个线程
2 Hero有子弹的对象,当按下J时,就启动一个发射行为(线程),让子弹不停地移动,行程一个射击效果
3 MyPanel不停地重绘子弹
4 当子弹移动到面板地边界时,就应改销毁(线程)

敌人坦克

敌人坦克可以发射子弹(有多颗)
1 在敌人坦克类,使用Vector保存多个Shot
2 当创建敌人坦克时,给敌人坦克初始化一个Shot对象,同时启动Shot
3 在绘制敌人坦克时,需要遍历敌人坦克对象Vector,绘制所有的子弹,当子弹isLive==false时,就从Vector移除
让敌人坦克可以自由移动
思路:
1 因为要求敌人坦克可以自由移动,需要将敌人坦克当作线程使用,启动线程,调用的run方法可以触发循环
2 创建时启动线程,绘制我放子弹时遍历Vector,面板上最懂5颗

功能:我方坦克在发射的子弹消亡后,才能发射新的子弹=>扩展:发射多颗子弹怎么处理
1 按下J键,判断hero的子弹是否销毁,没有销毁就不去触发shotEnemyTank,销毁触发
2 发射多颗子弹,用Vector

功能:敌人坦克可以发射多颗子弹

抽象类不能直接实例化,实例其子对象
sout简写,System.out.println();

避坑

1 视频604
问题:坦克爆炸效果,加入图片后报空指针,找不到url
java版本升级,定位资源方式发生变化,不能用Panel.class.getResource(“url”),而要用MyPanel.class.getResource(“url”),url命名至文件格式 /bomb_1.gif
2 视频605
问题:坦克被击中爆炸后,移除隐形坦克后,rerun,子弹击中坦克即卡住
遍历敌人坦克是否被击中时,循环次数不能使用固定值enemyTankSize,而要使用Vector的size,即enemyTanks.size()

可改善:
1 第一次击中敌人坦克,不会出现爆炸效果

IO流

文件

文件流

流:数据在源文件和程序内存之间的传输
输入流:数据从源文件到程序内存的路径
输出流:数据从程序内存到源文件的路径

常见文件操作

//创建文件对象
new File(String pathname) //根据路径
new File(File parent, String child)//根据父目录文件+子路径构建
new (String parent, String child)//根据父目录+子路径

//获取文件相关信息
getName
getAbsolutePath
getParent
length
exists
isFile
isDirectory

//目录的操作和文件删除
mkdir//创建一级目录
mkdirs//创建多级目录
delete//删除空目录或文件

IO流原理及流的分类

流的分类

按数据单位:字节流(8bit)二进制文件 & 字符流(按字符)文本文件
按流的角色:节点流 & 处理流/包装流
按流的方向:输入流 & 输出流

角色抽象基类字节流字符流
节点流输入流InpuStreamReader
节点流输出流OutputStreamWriter
包装流Buffered~Buffered~

在这里插入图片描述

1 字节流
1.1 InputStream

  • FileInputStram
    1.2 OutputStream
  • FileOutputStream
  • FilterOutputStream
    • BufferedOutputStram
      2 字符流
      2.1 Reader
  • InputStreamReader
    • FileReader
  • BufferedReader
    2.2 Writer
  • OutputStreamWriter
    • FileWriter
  • BufferedWriter

流总结

流常见操作流
  1. 创建流对象
  2. 用流对象的方法进行输入或输出
  3. 关闭流
相关API
(char)readData//将(int)字节转为char
new String(char[])//将char[]转换成String
new String(char[], off, len)//转换指定部分
str.toCharArray()//将String转换成char[]
常见异常处理

Alt+Enter: 抛出到方法外
try-catch-finally
try-catch: finally关闭流

FileInputStream & FileOutputStream

FileInputStream

使用FileInputStream读取hello.txt文件,并将文件内容显示到控制台

String filePath = "e:\\hello.txt";
//【1】字节读取返回int
int readData = 0;
//【2】字节数组
byte[] buf = new byte[8];
int readLen = 0;
//step1. 创建FileInputStream对象,用于读取文件
new FileInputStream(filePath).var;
//step2. 从该输入流读取字节数据
//【1】一次读取一个字节:1)若没有输入,方法将被阻止;2)若返回-1,表示读取完毕
while((readData=fileInputStream.read()) != -1){
	sout((char)readData);//int字节转成char显示
}
//【2】一次读取多字节到字节数组(最多bu f.length):1)读取正常,返回实际读取的字节数;2)返回-1表示读取完毕
while ((readLen = fileInputStream.read(buf))= -1) {
	souf(new String(buf, 0, readLen));//字节数组按实际长度展示为string
}
//step3. 关闭流,释放资源
fileInputStream.close();
FileOutputStream

在a.txt文件中写入“hello, world",如果文件不存在,会创建文件(前提目录存在)

//step1. 创建FileOutputStream对象
//【1】默认覆盖方式
new FileOutputStream(filePath)
//【2】设置追加方式
new FileOutputStream(filePath, true)
//step2. 写入
fileOutputStream.write('H');//写入一个字节
fileOutputStream.write(str.getBytes());//写入字符串/多个字节,需将字符串转为字节数组
write(str.getBytes(), int off, int len);
//step3. 关闭流
fileOutputStream.close();
用字节流拷贝二进制文件(图片/音乐):FileInputStream 和 FileOutputStream

step1. 创建文件的输入流和输出流,将文件读入到程序,再将读取到的文件,写入到指定的输出流
step2. 边读边写

while((readLen = fileInputStram.read(buf)) != -1) {
	fileOutputStream.write(buf, 0, readLen);
}

step3. 关闭流

FileReader & FileWriter

//FileReader相关方法
new FileReader(File/String)
read//每次读取单个字符,返回该字符,读取完毕返回-1
read(char[])//批量读取多个字符到数组,返回读取到的字符数,读取完毕返回-1
//FileWriter相关方法
new FileWriter(File/String)//覆盖模式
new FileWriter(File/String, true)//追加模式
write(int)//写入单个字符
write(char[])
write(char[], off, len)
write(string)
write(string, off, len)
FileReader

从story.txt读取内容并显示

int data = 0;
byte[] buf = new byte[8];
//step1. 创建FileReader对象
new FileReader(filePath).var
//step2. 循环读取
//【1】使用read单个字符读取
while((data = fileReader.read()) != -1){
	souf((char)data);
}
//【2】字符数组读取文件
while((readLen = fileReader.read(buf)) != -1){
	sout(new String(buf, 0, readLen));
}
//step3. 关闭流
fileReader.close();
FileWriter

TankGame05

1 防止坦克重叠
EnemyTank类中增加是否碰撞方法
EnemyTank设置setVector,MyPanel调用传入

2 记录玩家成绩(累计击打敌人坦克数量)
记录器Recorder
记录我方击毁地方坦克数

游戏结束,将数据写入文件(IO) myRecord.txt
3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值