第二十天
Map集合
Interface Map<k,v> key 键 value 值
Map接口下面 已经封装好实现类
--|HashMap
--|TreeMap
Map接口下面的方法
增: V put(K key, V value) 将指定的值与该映射中的指定键相关联(可选操作)。 void putAll(Map<? extends K,? extends V> m) 将指定地图的所有映射复制到此映射(可选操作)。 删: V remove(K key); 通过键删除指定的值 返回值是被删除的值 改: V put(K key, V value) 当键没有的话,就是添加,没有的话,就是覆盖 查: int size(); 查看集合中的元素的个数 boolean isEmpty(); 判断集合是否为空 boolean containsKey(Obejct Key); 判断集合中是否包含这个键 boolean containsValue(Obejct value); 判断集合中是否包含这个值 重要的方法: V get(K key); 通过键获取值 Set<K> keySet() 获取所有的键存到set集合中 Collection<V> values() 获取所有集合中的值 Set<Map.Entry<K,V>> entrySet() 将键值对 的map的实体存到set集合中
File类
相对路径:
得有一个参照物
./ 代表的是当前的工作目录
../上一级目录
../../上两级目录
../../../上三级目录
绝对路径:
从磁盘的跟目录一直到文件的所在位置
C:\aaa\3.txt
File构造方法
File(String pathname)
通过将给定的路径名字符串转换为抽象路径名来创建新的 File
实例。
File(String parent, String child)
static String` `separator`与系统相关的默认名称 - 分隔符字符
File类下面的方法
boolean createNewFile(); 新建一个文件
1.如果文件路径不存在, 系统找不到指定的路径
2.如果文件已经存在 返回一个false
3.磁盘坏了
boolean mkdir(); 创建单级的目录
boolean mkdirs();创建多级的目录
删除文件或者文件夹
boolean delete();
File类下面判断的方法
boolean isFile();是否是文件
boolean isDirectory(); 是否是文件夹
boolean isHidden(); 是否是隐藏文件
boolean isAbsolute(); 是否是绝对路径
boolean exists(); 文件或者文件夹是否存在
获取方法 返回值的是字符串的方法
String getName();获取文件或者文件夹的名字的
STring getParent();获取上一级目录
String getPath();获取file对象的绝对路径
方法是long类型数据
long length();获取文件占用磁盘的字节数
long lastModified(); 获取当前文件修改的时间 时间戳
获取当前文件夹下面的所有的文件
File[] listFiles();
String[] list();
递归
一句话来概括:
一个方法自己多次调用自己,但是得有结束的条件
例如:删除某一个目录下面的所有文件
package com.qf.d_digui; import java.io.File; public class Demo3 { public static void main(String[] args) { File file = new File("c:/bbb"); del(file); } public static void del (File file) { //找到bbb文件夹下面所有的文件和文件夹 File[] files = file.listFiles(); for (File file1 : files) { if (file1.isDirectory()) {//如果是文件夹 就继续执行del方法 del(file1); } else {//不是文件夹 file1.delete(); } } } }
第二十一天
IO流
以后会遇到 上传和下载 等这些需求。
I input 输入
O output 输出
缓冲的概念
计算机通过cpu读取硬盘的数据,在Java中可以加上缓冲的概念,每次读取具体的缓冲值。可以提高效率
IO流
从磁盘(c盘)读取数据到内存(Java代码) 1.txt====》java代码(输出出来)
输入流:
input :场景使用 从磁盘的c:/aaa/1.txt文件中 读取数据 到内存中(Java代码)
字节输入流
字符输入流
从内存(Java代码 String="狗蛋")写入数据到 磁盘(c盘 1.txt)
输出流:
output : 从内存(String str = " 还是数据库的借口借口") 写入到磁盘的c:/aaa/1.txt文件中
字节输出流:
字符输出流
参照物体 是内存
字节传文件案例:
package com.qf.a.test; import java.io.*; //5、编写一个程序,将d:\java目录下的a.txt文件复制到d:\jad目录下。 public class Demo1 { public static void main(String[] args) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("D:/java/a.txt"))); BufferedOutputStream bof = new BufferedOutputStream(new FileOutputStream(new File("D:/java/jad/sb.txt"))); byte[] buf = new byte[1024]; int length; while ((length=bis.read(buf))!=-1) { bof.write(buf,0,length); } bof.close(); bis.close(); } } 字符的案例:
package com.qf.f_zonghe; import java.io.*; public class Demo1 { public static void main(String[] args) throws IOException { //字符流将一个文本赋值2到另外一个文件夹下面 //BufferedReader 专门将文本内容读取到内存中 BufferedReader br = new BufferedReader(new FileReader("c:/bbb/《雪中悍刀行》.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("c:/aaa/88.txt")); char[] cbuf= new char[1024]; int length; while ((length = br.read(cbuf)) != -1) { bw.write(cbuf, 0, length); } bw.close(); br.close(); } }
总结
总结: 1.输入流和输出流的功能 输入流: 从磁盘到内存(Java代码) 输出流: 从内存(java 代码)到磁盘 2.输入流 分为两种: 字节输入流 FileInputSrteam 字符输入流 FileR4 核心方法: read 关于效率问题,他们两个有对应的缓冲流 FileInputSrteam 对应的BufferedInputStream FileReader 对应的 BufferedReader 3.输出流 分为两种: 字节输出流: FileOutputStream 字符输出流: FileWriter 核心的方法 write 关于效率问题,他们两个有对应的缓冲流 FileOutputStream对应的缓冲流 BufferedOutputStream FileWriter对应缓冲流 BufferedWriter 4.记住一句话 用字节流
序列化和反序列化
从内存到磁盘 序列化 输出流 ObjectOutputStream write
package com.qf.g_serialize; import java.io.*; import java.util.ArrayList; class Employee implements Serializable { String name; int age; transient int ID;//短暂的 此属性不可序列化 String adress;//地址 public void eat() { System.out.println("今天中午没有吃饱"); } } public class Demo1 { public static void main(String[] args) throws IOException { ArrayList arrayList = new ArrayList(); Employee employee = new Employee(); employee.name = "gousheng"; employee.adress = "航海中路"; employee.age = 18; employee.ID = 8989; //将Java代码中的对象存到磁盘中 FileOutputStream fos = new FileOutputStream("c:/aaa/emp.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(employee); oos.close(); fos.close(); } }
反序列化 从磁盘到 内存中 inputStream
package com.qf.g_serialize; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.ObjectInputStream; public class Demo2 { public static void main(String[] args) throws Exception { //反序列化 FileInputStream fis = new FileInputStream("c:/aaa/emp.ser"); ObjectInputStream ois = new ObjectInputStream(fis); Employee emp = (Employee)ois.readObject(); System.out.println(emp.name); System.out.println(emp.age); System.out.println(emp.adress); System.out.println(emp.ID);//0 } }
第二十二天
StringBuffer
线程安全 , 可变的字符序列
方法:
package com.qf.a_stringbuffer; public class Demo1 { public static void main(String[] args) { StringBuffer sb = new StringBuffer("abcdef"); System.out.println(sb); //System.out.println(sb.toString());//将StringBuffer类型的数据转为String sb.append("a");//追加 abcdtrue sb.insert(2, "狗"); //ab狗cdefa sb.delete(2, 4);//abdefa //字符串反转 System.out.println(sb.reverse());//afedba System.out.println(sb); System.out.println(sb.capacity());//容量 容量是新插入字符可用的存储量 StringBuffer sb1 = new StringBuffer(); System.out.println(sb1.capacity());//16 sb1.append("12345678912345671"); System.out.println(sb1.capacity()); } }
枚举类
Java中有一个特殊的类叫枚举类,一般表示的是常量。
语法格式:
public enum 枚举类名 { 各组常量,常量之间使用逗号隔开 }
枚举方法:
values(); 枚举类中的所有的值 oridnal();每个常量的索引值 valueOf();返回值的指定的字符串的常量
package com.qf.b_enum; enum SexEnum { MALE(0, "男"), FEMALE(1, "女"), ; private int sex;//0代表男 or 1 代表女 private String sexName;//男 or 女 SexEnum(int sex, String sexName) { this.sex = sex; this.sexName = sexName; } public int getSex() { return sex; } public String getSexName() { return sexName; } } class User {//用户类 private String name;//用户名字 private SexEnum sex;//用户的性别 public String getName() { return name; } public void setName(String name) { this.name = name; } public SexEnum getSex() { return sex; } public void setSex(SexEnum sex) { this.sex = sex; } } public class Demo6 { public static void main(String[] args) { User user = new User(); user.setName("狗蛋");//赋值 user.setSex(SexEnum.MALE); System.out.println(user.getSex().getSexName()); } }
包装类
Java八大基本数据类型,都有与之对应的包装类
int==>Integer
byte===>Byte
short====>Short
long====>Long
float====>Float
double====>Double
boolean====>Boolean
char====>Character
【重点】:
1.自从jdk5之后 ,有自动拆箱和自动装箱
自动装箱: 将基本数据类型转为包装类类型
自动拆箱: 将包装类转为基本数据类型
2. static String toString(); 将基本数据类型转为 字符串 3. static parse***(); 将一个字符串转为 所对应基本数据类型
Math
Math
类包含执行基本数字运算的方法,如基本指数,对数,平方根和三角函数。
Math的方法:
Math.abs(); //求一个数的绝对值 Math.max(a,b); // 求两个数最大值的 Math.min(a,b); // 求两个数最小值的 Math.ceil(a);//向上取整 Math.floor(a);//向下取整 Math.round(a);//四舍五入 Math.random();//double 大于等于 0.0 ,小于 1.0 。
Random
package com.qf.e_random; import java.util.Random; public class Demo1 { public static void main(String[] args) { Random random = new Random(); System.out.println(random.nextInt()); System.out.println(random.nextBoolean()); System.out.println(random.nextInt(3)); System.out.println(random.nextDouble()); } }
System
System
类提供的System
包括标准输入,标准输出和错误输出流; 访问外部定义的属性和环境变量; 一种加载文件和库的方法; 以及用于快速复制阵列的一部分的实用方法。
package com.qf.f_system; import java.io.PrintStream; import java.util.Properties; import java.util.Scanner; public class Demo1 { public static void main(String[] args) { PrintStream out = System.out;//标准输出 out.println("hehe"); System.out.println("xiix"); Scanner scanner = new Scanner(System.in); //m err //“标准”错误输出流。 System.err.println("haha"); //返回当前的时间 long l = System.currentTimeMillis(); //ms System.out.println(l);//1680076586166 //在1970年1月1日UTC之间的当前时间和午夜之间的差异,以毫秒为单位。 //通过类 获取当前系统的一个属性 Properties properties = System.getProperties(); System.out.println(properties.get("os.name"));//Windows 10 System.out.println(properties.get("user.name"));//bowang System.out.println(properties.get("java.version"));//1.8.0_241 } }
Date
专门处理时间的一个类
package com.qf.g_date; import java.text.SimpleDateFormat; import java.util.Date; public class Demo1 { public static void main(String[] args) { Date date = new Date(); System.out.println(date); //Wed Mar 29 16:17:57 IRKT 2023 //我难受 看不懂? 吧咋办? 转成你能看懂的 格式化 //SimpleDateFormat是一个具体的类,用于以区域设置敏感的方式格式化和解析日期 //SimpleDateFormat(String pattern) //使用给定模式 SimpleDateFormat并使用默认的 FORMAT语言环境的默认日期格式符号。 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = sdf.format(date); System.out.println(format); } }
package com.qf.g_date; import java.util.Calendar; import java.util.Date; public class Demo2 { public static void main(String[] args) { Date date = new Date(); //返回一个值,该值是从包含本开始时间的年份中减去1900的值 System.out.println(date.getYear() + 1900); //返回一个数字,表示包含或开始于此Date对象所代表的时刻的月份 。 返回的值在0和11之间,其值为0代表一月。 System.out.println(date.getMonth() + 1);//2 //返回由此日期表示的星期几。 返回值( 0 =星期日, 1 =星期一, 2 =星期二, 3 =星期三, 4 =星期四, 5 =星期五, 6 =星期六)表示包含或以此时间表示的时刻开始的星期几Date对 System.out.println(date.getDay());//3 Calendar rightNow = Calendar.getInstance();//获取日历的对象 System.out.println(rightNow); System.out.println(rightNow.get(Calendar.YEAR));//2023 System.out.println(rightNow.get(Calendar.MONTH) + 1);//3 System.out.println(rightNow.get(Calendar.DAY_OF_MONTH));//29 System.out.println(rightNow.get(Calendar.DAY_OF_YEAR));//88 System.out.println(rightNow.get(Calendar.DAY_OF_WEEK) - 1);//4 System.out.println(rightNow.get(Calendar.HOUR));//4 pm System.out.println(rightNow.get(Calendar.HOUR_OF_DAY));//16 } }
第二十三天
进程
是一个独立的运行应用程序
-
独立性
各个进程之间是互相独立的,互相不影响的。
-
互斥性
每个应用程序(软件) 系统分配一个独立的端口号如果一个软件qq端口号 97 idea端口也叫97
线程
进程是由至少一个或者多个线程组成的。
线程是进程最小的基本单位。
1.抢占式运行【重要】
给程序 分配CPU,按照时间片来执行,单位时间片抢占式执行的。随机抢占的
2.资源共享
同一个进程,有多个线程,这个多个线程是可以共享同一个数据的
Java程序:Demo1可以看成一个进程,
一个Java程序中有两个线程:
1.main 主线程
2.垃圾回收的线程
面试题: 进程和线程区别
1、调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
2、并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
3、拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程
的资源。
4、系统开销:在创建或撤销进程的时候,由于系统都要为之分配和回收资源,导致系统的明显
大于创建或撤销线程时的开销。但进程有独立的地址空间,进程崩溃后,在保护模式下不会对其
他的进程产生影响,而线程只是一个进程中的不同的执行路径。线程有自己的堆栈和局部变量,
但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多
线程的程序健壮,但是在进程切换时,耗费的资源较大,效率要差些。
并行和并发
并行: 真正的同时执行
并发: 同时发生,轮流交替执行
创建线程的两种方式
Java虚拟机允许应用程序同时执行多个执行线程。
创建线程的第一种:
创建一个新的执行线程有两种方法。 一个是将一个类声明为Thread
的子类。 这个子类应该重写run
方法Thread
。 然后可以分配并启动子类的实例。
第二种创建方式:
另一种方法来创建一个线程是声明实现类Runnable
接口。 那个类然后实现了run
方法。 然后可以分配类的实例,在创建Thread
时作为参数传递,并启动。
第一方式: 继承Thread 第二种方式: 实现Runnable接口
线程方法
构造方法:
Thread()
分配一个新的 Thread
对象。
Thread(Runnable target)
分配一个新的 Thread
对象。 第二种创建的形式
Thread(Runnable target, String name)
分配一个新的 Thread
对象。并对这个线程起一个名字
方法:
static Thread | currentThread() 返回对当前正在执行的线程对象的引用。 |
---|---|
String | getName() 返回此线程的名称。 |
void | setName(String name) 将此线程的名称更改为等于参数 name 。 |
Thread.currentThread();//获取当前线程对象 getNeme(); 获取当前线程的名字
线程下面的方法:
int | getPriority() 返回此线程的优先级。 |
---|---|
void | setPriority(int newPriority) 更改此线程的优先级。 |
还是抢占,结果不可预期
static void
sleep(long millis)
使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
线程同步和锁
当多个线程同时请求一个数据的时候,会导致数据不准确的情况。相互之间产生问题。容易出现线程安全的问题。比如多个线程操作同一个数据,都打算修改商品库存。
线程的同步真实的意思: 让你"排队",几个线程之间要排队。一个一个对共享资源进行操作,等一个结束以后,另外一个再进来操作。变量 是唯一的和准确的
可以加锁
package com.qf.d_thread; class SaleTicket implements Runnable { private int ticket = 100; @Override public void run() { while (true) { synchronized (this) { if (ticket > 0) { //线程2卖出了第72票 //线程2卖出了第71票 //线程1卖出了第100票 //线程1 线程2 都进入到if语句了 // System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket +"票"); ticket--; } else { System.out.println("卖完了"); break; } } } } } public class Demo1 { public static void main(String[] args) { //强调的是:多个线程操作同一个数据 ticket SaleTicket saleTicket = new SaleTicket(); new Thread(saleTicket, "线程1").start(); new Thread(saleTicket, "线程2").start(); } }
Java中的锁
synchronized 被成为隐式锁,会自动释放,式一个非公平的锁。
Lock锁 被成为显示锁。
他们两个锁都可以解决线程同步的问题。但是synchronized 更加强大,更加粒度化。更加灵活。
所以一般开发时候用synchronized 。以后还会有线程池,也有锁 更高级。
Lock是一个接口,实现ReentrantLock
有两个重要方法:
lock();
unlock();
package com.qf.d_thread; import java.util.concurrent.locks.ReentrantLock; class SaleTicket1 implements Runnable { private int ticket = 100; ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true) { try{ lock.lock(); if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "票"); ticket--; } else { System.out.println("票已经买完了"); break; } } catch (Exception e) { } finally { lock.unlock(); } } } } public class Demo2 { public static void main(String[] args) { //强调的是:多个线程操作同一个数据 ticket SaleTicket1 saleTicket = new SaleTicket1(); new Thread(saleTicket, "线程1").start(); new Thread(saleTicket, "线程2").start(); } }
守护线程【了解】
守护线程是用来守护非守护线程的
package com.qf.d_thread; class MyThread8 implements Runnable { @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("守护线程:" + i); } } } public class Demo3 { public static void main(String[] args) { Thread thread = Thread.currentThread(); System.out.println(thread.isDaemon());//false 非守护线程 // thread.setDaemon(true);//设置为守护线程 Thread thread1 = new Thread(new MyThread8()); //System.out.println(thread1.isDaemon()); thread1.setDaemon(true); thread1.start(); for (int i = 0; i < 200; i++) { System.out.println("主线程:" + i); } } }
第二十四天
死锁
开发中禁止出现死锁
面试会问:
应用场景: 并发场景,多个线程。线程之间在共享数据的时候 是互不相让的
线程加锁为了线程安全,但是物极必反。
死锁是一种状态,当两个线程互相持有对象所需要的资源的时候,这两个线程又都不主动释放资源
就会导致死锁。代码无法正常执行。这两个线程就会僵持住。
Object类下面的和线程相关的方法
public final void wait() throws InterruptedException
导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。
总结: 至少两个线程, 对象.wait() ,那么当前线程就会等待。
package com.qf.b_object; //为啥写Message这个类? wait方法 对象.wait(); 创建Message对象 // class Message { private String message;//信息 public Message(String message) { this.message = message; } public void setMessage(String message) { this.message = message; } public String getMessage() { return message; } } //线程类 等待线程 class WaitThread implements Runnable { private Message message; public WaitThread(Message message) { this.message = message; } //等待线程抢到了 //等待线程睡了5秒 然后唤醒线程执行。 synchronized (message) //message 对象从等待池中国去取的,结果发现没有 阻塞 //回到等待线程睡醒了以后开始 wait等待 @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + "正在等待中...."); synchronized (message) { try { //当调用wait方法的时候,会自动释放锁,并将对象放到等待池中,让唤醒线程锁来操作这个对象 // message.wait();//代码走到这一步 当前线程会等待!!! } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name +"被唤醒!!!Line45行的"); System.out.println(message.getMessage()); } } } //唤醒线程 class NotifyThread implements Runnable { private Message message; public NotifyThread(Message message ) { this.message = message; } @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("唤醒线程已经执行"); synchronized (message) { message.setMessage("我是修改之后的message对象"); //message.notify(); message.notifyAll(); } } } public class Demo1 { public static void main(String[] args) { Message message = new Message("我是message对象"); WaitThread waitThread = new WaitThread(message); WaitThread waitThread1 = new WaitThread(message); NotifyThread notifyThread = new NotifyThread(message); new Thread(waitThread1, "wait2线程").start(); new Thread(waitThread, "wait1线程").start(); new Thread(notifyThread, "notify线程").start(); } }