文章目录
十三、泛型
1. 泛型:
泛型 是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,而这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口。
2. 作用:
泛型的出现就是为了避免类型强转而产生的异常,确保代码可以正常编译。
3. 泛型通配符
当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?> 表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
类名 <? extends 类>
说明:表示可以传递类以及它的子类
举例: List<? extends Father> list1 = new ArrayList< Son>;
其中,Son类为Father类的子类
类名<? super 类>
说明:表示可以传递类以及它的父类
十四、IO流
1. 什么是IO流
流是一组有序的数据集合,即数据在两设备间的传输称为流。流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
IO流,简单来说就是为了读写数据,来进行系统调用。绝大部分都是用来读文件写文件,其中字节流一次操作一个字节,字符流一次操作一个字符,至于bufferReader之类的,是带缓存的流,一次操作一大堆,减少系统调用。
2. 分类
a. 输入流与输出流
一次调用,读就是把文件从硬盘读取到内存(输入流),写就是把文件从内存中保存到硬盘(输出流)
b. 字节流和字符流
如果一次操作一个字节,就是字节流(字节输入流InputStream、字节输出流OutputStream),也就是说一次读、写一个字节,这种流可以读取任意类型文件。
对应一次操作一个字符,就是字符流(字符输入流Reader、字符输出流Write),方便读取文本文件,不能读取图片、音频、视频等。
3. IO流继承关系
4. 常用方法:
https://blog.csdn.net/my_name_nb/article/details/53439114
5. 详解
感兴趣的可以看看https://blog.csdn.net/qq_44732146/article/details/120444101
6. 实例,读取csv文件并保存
public void readCSVFile() {
// 获取文件
File file = new File("C://Users/asus/Desktop/test2020-09-06.csv");
String tempStr = "";
// 封装文件内容的List
List<String[]> tempStrArryList = new ArrayList<>();
// 使用了java7的try-catch-with,可以不用手动关闭流
try (BufferedReader read = new BufferedReader(new FileReader(file))) {
// 将文件中每一行的文字赋值给临时变量tempStr
while ((tempStr = read.readLine()) != null) {
// 这里以csv文件为例子,去除csv文件读入时的双引号,并将数据以逗号进行分割,封装成数组
String[] tmpStrArray = tempStr.replace("\"", "").split(",", -1);
// 每一行数据封装的数组保存在List中
tempStrArryList.add(tmpStrArray);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void exportCsvFile() {
// 定义文件生成的路径
File file = new File("C://Users/asus/Desktop/test"
+ DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now()) + ".csv");
StringBuilder sb = new StringBuilder();
try (BufferedWriter write = new BufferedWriter
(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
// 这里正常会是一个实体类型的List,这里为了测试数据量而临时制作
for (int i = 0, j = 500000; i <= 500000; i++, j--) {
sb.delete(0, sb.length());
sb.append("\"").append(i + "" + j).append("\"").append(",").append("\n");
// 将内容写入文件中
write.append(sb.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
}
十五、多线程
1. 什么是进程
进程是指在系统中能独立运行并作为资源分配的基本单位,它是由一组机器指令、数据和堆栈等组成的,是一个能独立运行的活动实体。
一个进程包括由操作系统分配的内存空间,包含一个或多个线程。
2. 什么是线程
线程是进程中的一个实体,作为系统调度和分派的基本单位。 Linux 下的线程看作轻量级进程。
一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。
3. 进程3状态,线程5状态
进程的3种状态:
就绪状态
执行状态
等待状态(或称阻塞状态)
线程的5种状态:
新建状态New:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
就绪状态Runnable: 当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
运行状态Running:
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
阻塞状态Blocked:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep()
状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
死亡状态Dead:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
4. 多线程的创建和启动
简单来说,比如用百度云来下载文件,当打开百度云时就打开了一个进程,下载一个文件就是开启一个线程,当我们用百度云同时下载多个文件,也就是多线程。
多线程有3种创建方式,主要还是前两种:
(1)实现Runnable接口**(推荐使用,单继承多实现)
创建一个类,实现Runnable接口
类中需要执行方法来调用run(),可重写
在实现类中实例化一个线程对象
Thread(Runnable threadOb,String threadName);
Runnable类型是放入Runnable的实现类即可,后一个参数为线程名
创建后,调用start()方法运行
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// 让线程睡眠一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
(2)继承Thread类本身**
创建一个类,继承Thread,并创建实例
继承类必须重写run()方法,这个方法是新线程的入口点,必须**调用start()**方法才能执行
本质上也是实现了Runnable接口的实例,因为Thread就是Runnable类的实现类
说明: 线程开启未必立即执行,等待CPU调度
/**
* 创建一个类继承Thread
*/
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
@Override
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// 让线程睡眠一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
@Override
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo( "Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo( "Thread-2");
T2.start();
}
}
编译结果:
Thread方法:
(3)通过Callable和Future创建
了解即可:
实现Callable接口
重写call方法
创建目标对象
创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
提交执行:Future result1 = ser.submit(t1);
获取结果:boolean r1 = result1.get();
关闭服务:ser.shutdownNow();
public class CallableThreadTest implements Callable<Integer> {
public static void main(String[] args)
{
CallableThreadTest ctt = new CallableThreadTest();
FutureTask<Integer> ft = new FutureTask<>(ctt);
for(int i = 0;i < 100;i++)
{
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
if(i==20)
{
new Thread(ft,"有返回值的线程").start();
}
}
try
{
System.out.println("子线程的返回值:"+ft.get());
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e)
{
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception
{
int i = 0;
for(;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}