异常

体系

exception1

Error:代表系统级别的错误(属于严重问题),系统一旦出现问题,sun公司会把这些错误封装成Error对象。Error是给sun公司自己用的,不是给我们程序员用的。因此我们开发人员不用管它。

exception2

exception3

分类

exception4

exception5

作用

  1. 异常是用来查询bug的关键参考信息
  2. 异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况

处理方式

  1. JVM默认的处理方式
  2. 自己处理(捕获异常)
  3. 抛出异常

exception9

JVM默认处理方式

  • 把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
  • 程序停止执行,下面的代码不会再执行了
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {
public static void main(String[] args) {
/*
JVM默认处理方式
- 把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
- 程序停止执行,下面的代码不会再执行了
*/
System.out.println("Hello World");
System.out.println(2/0);
System.out.println("Hello World");
System.out.println("Hello World");
}
}

捕获异常

exception6

快捷键:ctrl+alt+T

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Main {
public static void main(String[] args) {
/*
自己处理
格式:
try {
可能出现异常的代码;
} catch (异常类名 变量名) {
异常的处理代码;
}
*/

int[] arr = {1, 2, 3, 4, 5};

try {
//可能出现异常的代码;
System.out.println(arr[10]); //此处出现了异常,程序就会在这里创建一个ArrayIndexOutOfBoundException对象
//new ArrayIndexOutOfBoundsException();
//拿着这个对象到catch的小括号中对比,看括号中的变量是否可以接受这个对象
//如果能被接受,就表示该异常就被捕获(抓住),执行catch里面对应的代码
//当catch里面所有的代码执行完毕,继续执行try...catch体系下面的其他代码
} catch (ArrayIndexOutOfBoundsException e) {
//如果出现了ArrayIndexOutOfBoundsException异常,我该如何处理
System.out.println("数组越界了");
}

System.out.println("看看我执行了吗?");
}
}

exception7

exception8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Main {
public static void main(String[] args) {

int[] arr = {1, 2, 3, 4, 5};

try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
// String message = e.getMessage();
// System.out.println(message);

// String str = e.toString();
// System.out.println(str);

e.printStackTrace(); //在底层是利用System.err.println进行输出把异常的错误信息以红色字体输出在控制台
// 细节:仅仅只是打印信息,不会停止程序运行
}

System.out.println("看看我执行了吗?");

//正常的输出语句
System.out.println(123);
//错误的输出语句
System.err.println(123);
}
}

抛出异常

excpetion10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Main {
public static void main(String[] args) {

int[] arr = {1, 2, 3, 4, 5};
int max = 0;
try {
max = getMax(arr);
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组索引异常");
}
System.out.println(max);
}

public static int getMax(int[] arr) /*throws NullPointerException, ArrayIndexOutOfBoundsException*/ {
if (arr == null) {
//手动创建一个异常对象,并把这个异常交给方法的调用者处理
//此时方法就会结束,下面的代码不会再执行了
throw new NullPointerException();
}
if (arr.length == 0) {
//手动创建一个异常对象,并把这个异常交给方法的调用者处理
//此时方法就会结束,下面的代码不会再执行了
throw new ArithmeticException();
}
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
}

自定义异常

excpetion11

1
2
3
4
5
6
7
8
9
10
package com.itheima;

public class AgeOutOfBoundsException extends RuntimeException {
public AgeOutOfBoundsException() {
}

public AgeOutOfBoundsException(String message) {
super(message);
}
}

File

  • File 对象就表示一个路径,可以是文件的路径、也可以是文件夹的路径
  • 这个路径可以是存在的,也允许是不存在的

file2

构造方法

file1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.io.File;

public class Main {
public static void main(String[] args) {
/*
E:\code\Java

\:转义字符
Windows:\
Linux:/
*/

//1.根据字符串表示的路径
String str = "E:\\code\\Java\\a.txt";
File f1 = new File(str);
System.out.println(f1); //E:\code\Java\a.txt

//2.父级路径:E:\code\Java
// 子级路径:a.txt
String parent = "E:\\code\\Java";
String child = "a.txt";
File f2 = new File(parent, child);
System.out.println(f2); //E:\code\Java\a.txt

File f3 = new File(parent + "\\" + child);
System.out.println(f3); //E:\code\Java\a.txt

//3.把一个File路径和String路径拼接
File parent2 = new File("E:\\code\\Java");
String child2 = "a.txt";
File f4 = new File(parent2, child2);
System.out.println(f4);
}
}

成员方法

判断、获取

file3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import java.io.File;

public class Main {
public static void main(String[] args) {
/*
public boolean isDirectory()
public boolean isFile()
public boolean exists()
*/

//1.对一个文件的路径进行判断
File f1 = new File("E:\\code\\Java\\a.txt");
System.out.println(f1.isDirectory());
System.out.println(f1.isFile());
System.out.println(f1.exists());

//2.对一个文件夹的路径进行判断
File f2 = new File("E:\\code\\Java\\basic-code");
System.out.println(f1.isDirectory());
System.out.println(f1.isFile());
System.out.println(f1.exists());

//3.对一个不存在的路径进行判断
File f3 = new File("E:\\code\\Java\\b.txt");
System.out.println(f1.isDirectory());
System.out.println(f1.isFile());
System.out.println(f1.exists());

/*
public long length()
public String getAbsolutePath()
public String getPath()
public String getName()
public long lastModified()
*/

//1.length 返回文件的大小(字节数量)
//细节1:这个方法只能获取文件的大小,单位是字节
//如果单位是M,G 可以不断除以1024
//细节2:这个方法无法获取文件夹的大小
//如果我们要获取一个文件夹的大小,需要把这个文件夹里面所有的文件大小都累加在一起

File f4 = new File("E:\\code\\Java\\a.txt");
long len = f4.length();
System.out.println(len);

File f5 = new File("E:\\code\\Java\\basic-code");
long len2 = f5.length();
System.out.println(len2);

//2.getAbsolutePath 返回文件的绝对路径
File f6 = new File("E:\\code\\Java\\a.txt");
String path1 = f6.getAbsolutePath();
System.out.println(path1);

//3.getPath() 返回定义文件时使用的路径
File f7 = new File("E:\\code\\Java\\d.txt");
String path2 = f7.getPath();
System.out.println(path2);

//4.getName 获取名字
//细节1:
// 文件:带后缀名
// 文件夹:文件夹名
File f8 = new File("E:\\code\\Java\\a.txt");
String name1 = f8.getName();
System.out.println(name1);

//5.lastModified 返回文件的最后修改时间(时间毫秒值)
File f9 = new File("E:\\code\\Java\\a.txt");
long time = f9.lastModified();
System.out.println(time);
}
}

创建、删除

file4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import java.io.File;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {
/*
public boolean createNewFile()
public boolean mkdir()
public boolean mkdirs()
public boolean delete()
*/

//1.createNewFile() 创建一个新的文件
//细节1:如果当前路径表示的文件是不存在的,则创建成功,方法返回true
// 如果当前路径表示的文件是存在的,则创建失败,方法返回false
//细节2:如果父级路径不存在,那么方法会有异常IOException
//细节3:createNewFile方法创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀的东西
File f1 = new File("E:\\code\\Java\\a.txt");
boolean b1 = f1.createNewFile();
System.out.println(b1);

//2.mkdir() 创建文件夹
//细节1:Windows中路径是唯一的,如果当前路径已经存在,则创建失败,返回false
//细节2:mkdir方法只能创建单级文件夹,无法创建多级文件夹
File f2 = new File("E:\\code\\Java\\aaa");
boolean b2 = f2.mkdir();
System.out.println(b2);

//3.mkdirs() 创建多级文件夹
File f3 = new File("E:\\code\\Java\\bbb");
boolean b3 = f2.mkdirs();
System.out.println(b3);

//4.delete
//细节1:
// 如果删除的是文件,则直接删除,不走回收站
// 如果删除的是空文件夹,则直接删除,不走回收站
// 如果删除的是有内容的文件夹,则删除失败
//1创建File对象
File f4 = new File("E:\\code\\Java\\a.txt");
//2删除
boolean b4 = f4.delete();
System.out.println(b4);
}
}

获取并遍历

file5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.File;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {
/*
public File[] listFiles()
*/

//1.创建File对象
File f = new File("E:\\code\\Java");
//2.listFiles方法
//作用:获取aaa文件夹里面的所有内容,把所有的内容放到数组中返回
File[] files = f.listFiles();
for (File file : files) {
System.out.println(file);
}
}
}

file6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;

public class Main {
public static void main(String[] args) throws IOException {
/*
public static File[] listRoots()
public String[] list()
public String[] list(FilenameFilter filter)
public File[] listFiles() 掌握
public File[] listFiles(FileFilter filter)
public File[] listFiles(FilenameFilter filter)
*/

//1.listRoots() 获取系统中所有的盘符
File[] arr = File.listRoots();
System.out.println(Arrays.toString(arr));

//2.list() 获取当前该路径下所有内容(仅仅能获取名字)
File f1 = new File("E:\\code\\Java");
String[] arr2 = f1.list();
for (String s : arr2) {
System.out.println(s);
}

//3.list(FilenameFilter filter) 利用文件名过滤器获取当前该路径下所有内容
//需求:我现在要获取E:\code\Python文件夹里面所有的.py文件
File f2 = new File("E:\\code\\Python");
//accept方法的形参,依次表示Python文件夹里面的每一个文件
//参数一:父级路径
//参数二:子级路径
//返回值:如果返回值为true,就表示当前路径保留
// 如果返回值为false,就表示当前路径舍弃不要
String[] arr3 = f2.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
File src = new File(dir, name);
return src.isFile() && name.endsWith(".py");
}
});
System.out.println(arr3);

//4.listFiles()
File f3 = new File("E:\\code\\Python");
File[] arr4 = f3.listFiles();
for (File f : arr4) {
if (f.isFile() && f.getName().endsWith(".py")) {
System.out.println(f);
}
}

//5.listFiles(FileFilter filter)
File f4 = new File("E:\\code\\Python");
File[] arr5 = f4.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isFile() && pathname.getName().endsWith(".py");
}
});

//6.listFiles(FilenameFilter filter)
File[] arr6 = f4.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
File src = new File(dir, name);
return src.isFile() && name.endsWith(".py");
}
});
System.out.println(Arrays.toString(arr5));
}
}

IO流

用于读写文件中的数据(可以读写文件,或网络中的数据…)

io1

io2

体系

io3

字节流

io4

FileOutputStream

操作本地文件的字节输出流,可以把程序中的数据写到本地文件中。

  1. 创建字节输出流对象
  2. 写数据
  3. 释放资源

构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {

//1,创建对象
FileOutputStream fos = new FileOutputStream("a.txt");
//2.写出数据
fos.write(97);
//3.释放资源
fos.close();
}
}

io5

API

io6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {
/*
void write(int b)
void write(byte[] b)
void write(byte[] b, int off, int len)
参数1:
数组
参数2:
起始索引
参数3:
个数
*/

//1,创建对象
FileOutputStream fos = new FileOutputStream("a.txt");
//2.写出数据
// fos.write(97); //a
// fos.write(98); //b
byte[] bytes = {97, 98, 99, 100, 101};
// fos.write(bytes);
fos.write(bytes, 1, 2);
//3.释放资源
fos.close();
}
}

换行和续写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {
/*
换行写:
再次写出一个换行符就可以了
windows: \r\n
Linux: \n
Mac: \r
细节:
在Windows系统中,java对回车换行进行了优化
虽然完整的是\r\n,但是我们写其中一个\r或者\n,
java也可以实现换行,因为java在底层会补全
续写:
如果想要续写,打开续写开关即可
开关位置:创建对象的第二个参数
默认false:表示关闭续写,此时创建对象会清空文件
手动传递true,表示打开续写,此时创建对象不会清空文件
*/

//1,创建对象
FileOutputStream fos = new FileOutputStream("a.txt", true);
//2.写出数据
String str = "I love CS";
byte[] bytes1 = str.getBytes();
fos.write(bytes1);

//再次写出一个换行符就可以了
String wrap = "\r\n";
byte[] bytes2 = wrap.getBytes();
fos.write(bytes2);

String str2 = "520";
byte[] bytes3 = str2.getBytes();
fos.write(bytes3);
//3.释放资源
fos.close();
}
}

io7

FileInputStream

操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来

  1. 创建字节输入流对象
  2. 读数据
  3. 释放资源

构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.FileInputStream;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {

//1.创建对象
FileInputStream fis = new FileInputStream("a.txt");

//2.读取数据
int b1 = fis.read();
System.out.println((char)b1);

int b2 = fis.read();
System.out.println((char)b2);

int b3 = fis.read();
System.out.println(b3); //-1

//3.释放资源
fis.close();
}
}

io8

API

io9

io10

循环读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.FileInputStream;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {

//1.创建对象
FileInputStream fis = new FileInputStream("a.txt");

//2.读取数据
int b;
while ((b = fis.read()) != -1) {
System.out.print((char) b);
}

//3.释放资源
fis.close();
}
}

文件拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {

long start = System.currentTimeMillis();

//1.创建对象
FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("b.txt");

//2.拷贝
int len;
byte[] bytes = new byte[1024 * 1024 * 5];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
//3.释放资源
fos.close();
fis.close();

long end = System.currentTimeMillis();
System.out.println(end - start);
}
}

异常处理

注:后续框架Spring统一用抛出异常处理

io11

io12

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws FileNotFoundException {
//JDK9

FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("b.txt");

try (fis; fos) {
int len;
byte[] bytes = new byte[1024 * 1024 * 5];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

字符集

io14

ASCII

io15

GBK

io16

Unicode

io17

io13

io18

乱码原因:

  1. 读取数据时未读完整个汉字
  2. 编码和解码方式不统一

避免乱码:

  1. 不要用字节流读取文本文件
  2. 编码解码时使用同一个码表,同一个编码方式

编码和解码

io19

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class Main {
public static void main(String[] args) throws UnsupportedEncodingException {
/*
Java中编码的方法
public byte[] getBytes() 使用默认方式编码
public byte[] getBytes(String charsetName) 使用指定方式编码
Java中解码的方法
String(byte[] bytes) 使用默认方式解码
String(byte[] bytes, String charsetName) 使用指定方式解码
*/

//1.编码
String str = "ai你哦";
byte[] bytes1 = str.getBytes();
System.out.println(Arrays.toString(bytes1));

byte[] bytes2 = str.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));

//2.解码
String str2 = new String(bytes1);
System.out.println(str2);

String str3 = new String(bytes1, "GBK");
System.out.println(str3);
}
}

字符流

io20

io21

FileReader

构造方法

io22

API

io23

释放资源

io24

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.io.FileReader;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {

//1.创建对象并关联本地文件
FileReader fr = new FileReader("a.txt");

//2.读取数据 read()
//字符流的底层也是字节流,默认也是一个字节一个字节的读取
//如果遇到中文就会一次读取多个,GBK一次就读2个字节,UTF-8一次读3个字节

//read() 细节
//1.read() 默认也是一个字节一个字节的读取,如果遇到中文就会一次读取多个
//2.在读取之后,方法的底层还会进行解码并转成十进制
// 最终把这个十进制作为返回值
// 这个十进制的数据也表示在字符集上的数字
// 英文:文件里面二进制数据 0110 0001
// read方法进行读取,解码并转成十进制97
// 中文:文件里面的二进制数据 11100110 10110001 10001001
// read方法进行读取,解码并转成十进制27721

//想看到中文汉字,就是把这些十进制数据,再进行强转就可以了
int ch;
while ((ch = fr.read()) != -1) {
System.out.println((char) ch);
}
//3.释放资源
fr.close();
}
}

FileWriter

构造方法

io25

API

io26

io27

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.io.FileWriter;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {

FileWriter fw = new FileWriter("a.txt", true);
// fw.write(25105);
// fw.write("我爱计算机");
char[] chars = {'a', 'b', 'c', '我'};
fw.write(chars);
fw.close();
}
}

文件拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.io.*;

//只能拷贝文件
//相对路径以项目路径 basic-code为当前根路径
public class Main {
public static void main(String[] args) throws IOException {

//1.创建对象表示数据源
File src = new File("oop-polymorphism\\src");
//2.创建对象表示目的地
File dst = new File("dst");

copydir(src, dst);
}

private static void copydir(File src, File dst) throws IOException {
dst.mkdirs();
File[] files = src.listFiles();
for (File file : files) {
if (file.isFile()) {
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(new File(dst, file.getName()));
byte[] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
fos.close();
fis.close();
} else {
copydir(file, new File(dst, file.getName()));
}
}
}
}

字节流和字符流的使用场景

字节流:拷贝任意类型的文件

字符流:

  1. 读取纯文本文件中的数据
  2. 往纯文本文件中写出数据

缓冲流

io28

字节缓冲流

构造方法

io29

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.io.*;

public class Main {
public static void main(String[] args) throws IOException {

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));

int len;
byte[] bytes = new byte[1024];
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}

bos.close();
bis.close();
}
}

io30

字符缓冲流

构造方法

io31

API

io32

io33

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.io.*;

public class Main {
public static void main(String[] args) throws IOException {

//1.创建字符缓冲输入流的对象
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//2.读取数据
//细节:
//readLine方法在读取的时候,一次读一整行,遇到回车换行结束
// 但是他不会把回车换行读取到内存中
// String line1 = br.readLine();
// System.out.println(line1);
//
// String line2 = br.readLine();
// System.out.println(line2);

String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
//3.释放资源
br.close();

//1.创建字符缓冲输出流的对象
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
//2.写出数据
bw.write("ha");
bw.newLine();
bw.write("la");
bw.newLine();
//3.释放资源
bw.close();
}
}

转换流

io34

io35

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.io.*;
import java.nio.charset.Charset;

public class Main {
public static void main(String[] args) throws IOException {

//1.按照指定字符编码读取
// InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "GBK");
//
// int ch;
// while ((ch = isr.read()) != -1) {
// System.out.print((char) ch);
// }
// isr.close();

FileReader fr = new FileReader("a.txt", Charset.forName("GBK"));
int ch;
while ((ch = fr.read()) != -1) {
System.out.print((char) ch);
}
fr.close();

//2.按照指定字符编码写出
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"), "GBK");
// osw.write("hello");
// osw.close();

FileWriter fw = new FileWriter("b.txt", Charset.forName("GBK"));
fw.write("Hello World");
fw.close();

//3.讲本地文件中的GBK文件,转成UTF-8
// InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"),"GBK");
//
// int b;
// while ((b = isr.read()) != -1) {
// osw.write(b);
// }
// osw.close();
// isr.close();

FileReader fr2 = new FileReader("b.txt", Charset.forName("GBK"));
FileWriter fw2 = new FileWriter("c.txt", Charset.forName("UTF-8"));
int b;
while ((b = fr2.read()) != -1) {
fw2.write(b);
}
fr2.close();
fw2.close();
}
}

io36

序列化流

io37

方法

io38

序列化流的细节

使用对象输出流将对象保存到文件时会出现NotSerializableException异常

解决方案:

需要让Javabean类实现Serializable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Main {
public static void main(String[] args) throws IOException {

//1.创建对象
Student stu = new Student("ZhangSan", 18);
//2.创建序列化流的对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
//3.写出数据
oos.writeObject(stu);
//4.释放资源
oos.close();
}
}
class Student implements Serializable {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}

反序列化流

API

io39

细节

io40

io41

打印流

io42

特点

io43

字节打印流

构造方法

io44

API

io45

字符打印流

构造方法

io46

API

io47

io48

解压缩流

io49

解压缩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {

//1.创建一个File表示要解压的压缩包
File src = new File("a.zip");
//2.创建一个File表示解压的目的地
File dest = new File("");

unzip(src, dest);
}

//定义一个方法用来解压
public static void unzip(File src, File dest) throws IOException {
//把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中

//创建一个解压缩流用来读取压缩包中的数据
ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
//要先获取到压缩包里面的每一个zipentry对象
ZipEntry entry;
while ((entry = zip.getNextEntry()) != null) {
System.out.println(entry.getName());
if (entry.isDirectory()) {
File file = new File(dest, entry.getName());
file.mkdirs();
} else {
FileOutputStream fos = new FileOutputStream(new File(dest, entry.getName()));
int b;
while ((b = zip.read()) != -1) {
fos.write(b);
}
fos.close();
zip.closeEntry();
}
}
zip.close();
}
}

压缩流

压缩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class ZipStreamDemo3 {
public static void main(String[] args) throws IOException {
/*
* 压缩流
* 需求:
* 把D:\\aaa文件夹压缩成一个压缩包
* */
//1.创建File对象表示要压缩的文件夹
File src = new File("D:\\aaa");
//2.创建File对象表示压缩包放在哪里(压缩包的父级路径)
File destParent = src.getParentFile();//D:\\
//3.创建File对象表示压缩包的路径
File dest = new File(destParent,src.getName() + ".zip");
//4.创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
//5.获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
toZip(src,zos,src.getName());//aaa
//6.释放资源
zos.close();
}

/*
* 作用:获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
* 参数一:数据源
* 参数二:压缩流
* 参数三:压缩包内部的路径
* */
public static void toZip(File src,ZipOutputStream zos,String name) throws IOException {
//1.进入src文件夹
File[] files = src.listFiles();
//2.遍历数组
for (File file : files) {
if(file.isFile()){
//3.判断-文件,变成ZipEntry对象,放入到压缩包当中
ZipEntry entry = new ZipEntry(name + "\\" + file.getName());//aaa\\no1\\a.txt
zos.putNextEntry(entry);
//读取文件中的数据,写到压缩包
FileInputStream fis = new FileInputStream(file);
int b;
while((b = fis.read()) != -1){
zos.write(b);
}
fis.close();
zos.closeEntry();
}else{
//4.判断-文件夹,递归
toZip(file,zos,name + "\\" + file.getName());
// no1 aaa \\ no1
}
}
}
}

Commons

Commons是apache开源基金组织提供的工具包,里面有很多帮助我们提高开发效率的API

使用方式:

  1. 新建lib文件夹
  2. 把第三方jar包粘贴到文件夹中
  3. 右键点击add as a library

API

io50

io51

Hutool

io52

多线程

io53

并发和并行:

  1. 并发:在同一时刻,有多个指令在单个CPU上交替执行
  2. 并行:在同一时刻,有多个指令在多个CPU上同时执行

实现方式

继承Thread类的方式进行实现

  1. 自己定义一个类继承Thread
  2. 重写run方法
  3. 创建子类的对象,并启动线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MyThread extends Thread {
@Override
public void run() {
for(int i=0; i<100; i++) {
System.out.println(i);
}
}
}
public class Main {
public static void main(String[] args) {
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();

// my1.run();
// my2.run();不可以这样写

//void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法
my1.start();
my2.start();
}
}

实现Runnable接口的方式进行实现

  1. 自己定义一个类实现Runnable接口
  2. 重写里面的run方法
  3. 创建自己的类的对象
  4. 创建一个Thread类的对象,并开启线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class MyRunnable implements Runnable {
@Override
public void run() {
for(int i=0; i<100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class MyRunnableDemo {
public static void main(String[] args) {
//创建MyRunnable类的对象
MyRunnable my = new MyRunnable();

//创建Thread类的对象,把MyRunnable对象作为构造方法的参数
//Thread(Runnable target)
// Thread t1 = new Thread(my);
// Thread t2 = new Thread(my);
//Thread(Runnable target, String name)
Thread t1 = new Thread(my,"坦克");
Thread t2 = new Thread(my,"飞机");

//启动线程
t1.start();
t2.start();
}
}

利用Callable接口和Future接口方式实现

  1. 创建一个MyCallable实现Callable接口
  2. 重写call(含有返回值,表示多线程运行的结果)
  3. 创建MyCallable对象(表示多线程要执行的任务)
  4. 创建FutureTask对象(作用管理多线程运行的结果)
  5. 创建Thread类的对象,并启动(表示线程)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class MyCallable implements Callable<String> {
//泛型表示返回结果的类型
@Override
public String call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println("跟女孩表白" + i);
}
//返回值就表示线程运行完毕之后的结果
return "答应";
}
}
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//线程开启之后需要执行里面的call方法
MyCallable mc = new MyCallable();

//Thread t1 = new Thread(mc);

//可以获取线程执行完毕之后的结果.也可以作为参数传递给Thread对象
FutureTask<String> ft = new FutureTask<>(mc);
//泛型表示返回结果的类型
//创建线程对象
Thread t1 = new Thread(ft);

String s = ft.get();
//开启线程
t1.start();
//获取多线程的结果
String s = ft.get();
System.out.println(s);
}
}

io54

生命周期

io56

常用方法

io55

线程同步

同步代码块

特点:

  1. 锁默认打开,有一个线程进去了,锁自动关闭
  2. 里面的代码全部执行完毕,线程出来,锁自动打开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class SellTicket implements Runnable {
int tickets = 100;
//锁对象,一定要是唯一的
private Object obj = new Object();

@Override
public void run() {
while (true) {
synchronized (obj) { // 对可能有安全问题的代码加锁,多个线程必须使用同一把锁
//t1进来后,就会把这段代码给锁起来
if (tickets > 0) {
try {
Thread.sleep(100);
//t1休息100毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
//窗口1正在出售第100张票
System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
tickets--; //tickets = 99;
}
}
//t1出来了,这段代码的锁就被释放了
}
}
}

public class SellTicketDemo {
public static void main(String[] args) {
SellTicket st = new SellTicket();

Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");

t1.start();
t2.start();
t3.start();
}
}

同步方法

io57

在原来的基础上 ctrl + alt + M

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class MyRunnable implements Runnable {
int ticket = 0;

@Override
public void run() {
while (true) {
if (method()) break;
}
}

private synchronized boolean method() {
if (ticket == 100) {
return true;
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
ticket++;
System.out.println(Thread.currentThread().getName() + ": " + ticket);
}
return false;
}
}
public class Main {
public static void main(String[] args) {

MyRunnable mr = new MyRunnable();

Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
Thread t3 = new Thread(mr);

t1.setName("Window 1");
t2.setName("Window 2");
t3.setName("Window 3");

t1.start();
t2.start();
t3.start();
}
}

io58

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import java.util.concurrent.locks.ReentrantLock;

public class Ticket implements Runnable {

//票的数量
private int ticket = 100;
private Object obj = new Object();
private ReentrantLock lock = new ReentrantLock();

@Override
public void run() {
while (true) {
//synchronized (obj){//多个线程必须使用同一把锁.
try {
lock.lock();
if (ticket <= 0) {
//卖完了
break;
} else {
Thread.sleep(100);
ticket--;
System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + ticket + "张票");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
// }
}
}
}

public class Demo {
public static void main(String[] args) {
Ticket ticket = new Ticket();

Thread t1 = new Thread(ticket);
Thread t2 = new Thread(ticket);
Thread t3 = new Thread(ticket);

t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");

t1.start();
t2.start();
t3.start();
}
}

死锁

写代码不要让多个锁嵌套起来

生产者 消费者

等待唤醒机制

io59

API

io60

等待唤醒机制(基本形式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class Desk {

//0:没有面条 1:有面条
public static int foodFlag = 0;

public static int count = 10;

public static Object lock = new Object();
}
public class Cook extends Thread {
@Override
public void run() {
while (true) {
synchronized (Desk.lock) {
if (Desk.count == 0) {
break;
} else {
if (Desk.foodFlag == 1) {
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println("厨师做了一碗面条");
Desk.foodFlag = 1;
Desk.lock.notifyAll();
}
}
}
}
}
}
public class Foodie extends Thread {
@Override
public void run() {
while (true) {
synchronized (Desk.lock) {
if (Desk.count == 0) {
break;
} else {
if (Desk.foodFlag == 0) {
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
Desk.count--;
System.out.println("吃货在吃面条,还能再吃" + Desk.count + "碗!!!");
Desk.lock.notifyAll();
Desk.foodFlag = 0;
}
}
}
}
}
}
public class Main {
public static void main(String[] args) {

Cook c = new Cook();
Foodie f = new Foodie();

c.setName("厨师");
f.setName("吃货");

c.start();
f.start();
}
}

阻塞队列(形式)

io61

io62

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class Cooker extends Thread {

private ArrayBlockingQueue<String> bd;

public Cooker(ArrayBlockingQueue<String> bd) {
this.bd = bd;
}
// 生产者步骤:
// 1,判断桌子上是否有汉堡包
// 如果有就等待,如果没有才生产。
// 2,把汉堡包放在桌子上。
// 3,叫醒等待的消费者开吃。

@Override
public void run() {
while (true) {
try {
bd.put("汉堡包");
System.out.println("厨师放入一个汉堡包");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

public class Foodie extends Thread {
private ArrayBlockingQueue<String> bd;

public Foodie(ArrayBlockingQueue<String> bd) {
this.bd = bd;
}

@Override
public void run() {
// 1,判断桌子上是否有汉堡包。
// 2,如果没有就等待。
// 3,如果有就开吃
// 4,吃完之后,桌子上的汉堡包就没有了
// 叫醒等待的生产者继续生产
// 汉堡包的总数量减一

//套路:
//1. while(true)死循环
//2. synchronized 锁,锁对象要唯一
//3. 判断,共享数据是否结束. 结束
//4. 判断,共享数据是否结束. 没有结束
while (true) {
try {
String take = bd.take();
System.out.println("吃货将" + take + "拿出来吃了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}
}

public class Demo {
public static void main(String[] args) {
ArrayBlockingQueue<String> bd = new ArrayBlockingQueue<>(1);

Foodie f = new Foodie(bd);
Cooker c = new Cooker(bd);

f.start();
c.start();
}
}

线程的6个状态

io63

io64

线程池

Thread3

API

Thread4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}

public class Main {
public static void main(String[] args) {
ExecutorService pool1 = Executors.newFixedThreadPool(5);

pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());

pool1.shutdown();
}
}

自定义线程池

Thread5

Thread6

拒接策略

Thread7

自定义线程池 ThreadPoolExecutor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.itheima.mythreadpool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadPoolDemo3 {
// 参数一:核心线程数量
// 参数二:最大线程数
// 参数三:空闲线程最大存活时间
// 参数四:时间单位
// 参数五:任务队列
// 参数六:创建线程工厂
// 参数七:任务的拒绝策略
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(
2,
5,
2,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);

pool.submit(new MyRunnable());
pool.submit(new MyRunnable());

pool.shutdown();
}
}

线程大小

Thread8

网络编程

三要素

  1. IP:设备在网络中的地址,是唯一的标识
  2. 端口:应用程序在设备中唯一的标识
  3. 协议:数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp

IP

net1

net2

InetAddress

API

方法名 说明
static InetAddress getByName(String host) 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
String getHostName() 获取此IP地址的主机名
String getHostAddress() 返回文本显示中的IP地址字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.net.InetAddress;
import java.net.UnknownHostException;

public class Main {
public static void main(String[] args) throws UnknownHostException {

InetAddress address = InetAddress.getByName("LAPTOP-P1UKKCPI");
System.out.println(address);

String name = address.getHostName();
System.out.println(name);

String ip = address.getHostAddress();
System.out.println(ip);
}
}

端口

net3

协议

net4

net5

net6

UDP

三种通信方式

net9

发送数据(单播)

net7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class SendDemo {
public static void main(String[] args) throws IOException {
//1.创建DatagramSocket对象
DatagramSocket ds = new DatagramSocket();

//2.打包数据
//DatagramPacket(byte[] buf, int length, InetAddress address, int port)
String str = "hello,udp,我来了"
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10086;

DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);

//3.发送数据
ds.send(dp);

//释放资源
ds.close();
}
}

接受数据(单播)

net8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//1.创建DatagramSocket对象
//细节:
//接受时一定要绑定端口,且与发送端口一致
DatagramSocket ds = new DatagramSocket(10086);

//2.接收据据包
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

//该方法是阻塞的
//程序执行到这里会等发送端发送消息
//System.out.println(1111);
ds.receive(dp);
//System.out.println(2222);

//3.解析数据包
byte[] data = dp.getData();
int len = dp.getLength();
InetAddress address = dp.getAddress();
int port = dp.getPort();

System.out.println("接收到数据" + new Strin(data, 0, len));
System.out.println("该数据是从" + address + "这台电脑中的" + port + "这个端口中发出的");

//4.释放资源
ds.close()
}
}

组播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 发送端
public class ClinetDemo {
public static void main(String[] args) throws IOException {
//1.创建MulticastSocket对象()
MulticastSocket ms = new MulticastSocket();

//2.创建DatagramPacket对象
String s = "hello 组播";
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.getByName("224.0.1.0");
int port = 10000;

DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);

//3. 调用MulticastSocket的方法发送数据
ms.send(dp);
// 4. 释放资源
ms.close();
}
}
// 接收端
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1.创建MulticastSocket对象
MulticastSocket ms = new MulticastSocket(10000);

//2.将当前本机添加到224.1.0这一组中
InetAddress address = InerAddress.getByName("224.0.1.0");
ms.joinGroup(address);

//3 创建DatagramPacket数据包对象
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

//4.接收数据
ms.receive(dp);

//5.解析数据
byte[] data = dp.getData();
int len = dp.getLength();
String ip = dp.getAddress().getHostAddress();
String name = dp.getAddress().getHostName();

System.out.println("ip为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + new String(data, 0, len)));

//6.释放资源
ms.close();
}
}

广播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 发送端
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 1. 创建发送端Socket对象(DatagramSocket)
DatagramSocket ds = new DatagramSocket();
// 2. 创建存储数据的箱子,将广播地址封装进去
String s = "广播 hello";
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.getByName("255.255.255.255");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
// 3. 发送数据
ds.send(dp);
// 4. 释放资源
ds.close();
}
}

// 接收端
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 1. 创建接收端的Socket对象(DatagramSocket)
DatagramSocket ds = new DatagramSocket(10000);
// 2. 创建一个数据包,用于接收数据
DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
// 3. 调用DatagramSocket对象的方法接收数据
ds.receive(dp);
// 4. 解析数据包,并把数据在控制台显示
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println(new String(data,0,length));
// 5. 关闭接收端
ds.close();
}
}

TCP

net10

net11

发送数据(英文)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Client {
public static void main(String[] args) throws IOException {
//TCP协议,发送数据

//1.创建Socket对象
//细节:在创建对象的同时会连接服务端
// 如果连接不上,代码会报错
Socket socket = new Socket("127.0.0.1",10000);

//2.可以从连接通道中获取输出流
OutputStream os = socket.getOutputStream();
//写出数据
os.write("aaa".getBytes());

//3.释放资源
os.close();
socket.close();
}
}

接收数据(英文)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Server {
public static void main(String[] args) throws IOException {
//TCP协议,接收数据

//1.创建对象ServerSocker
ServerSocket ss = new ServerSocket(10000);

//2.监听客户端的链接
Socket socket = ss.accept();

//3.从连接通道中获取输入流读取数据
InputStream is = socket.getInputStream();
int b;
while ((b = is.read()) != -1){
System.out.println((char) b);
}

//4.释放资源
socket.close();
ss.close();
}
}

发送数据(中文)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Client {
public static void main(String[] args) throws IOException {
//TCP协议,发送数据

//1.创建Socket对象
//细节:在创建对象的同时会连接服务端
// 如果连接不上,代码会报错
Socket socket = new Socket("127.0.0.1",10000);


//2.可以从连接通道中获取输出流
OutputStream os = socket.getOutputStream();
//写出数据
os.write("你好你好".getBytes());//12字节

//3.释放资源
os.close();
socket.close();

}
}

接收数据(中文)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Server {
public static void main(String[] args) throws IOException {
//TCP协议,接收数据

//1.创建对象ServerSocker
ServerSocket ss = new ServerSocket(10000);

//2.监听客户端的链接
Socket socket = ss.accept();

//3.从连接通道中获取输入流读取数据
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);

// BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

int b;
while ((b = br.read()) != -1){
System.out.print((char) b);
}

//4.释放资源
socket.close();
ss.close();

}
}

细节

net12

三次握手

net13

四次挥手

net14

反射

reflect1

获取 class 对象

reflect2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//1.第一种方式
//全类名 = 包名 + 类名
//最常用
Class clazz1 = Class.forName("com.itheima.reflectdemo.Student");
//源代码阶段获取 --- 先把Student加载到内存中,再获取字节码文件的对象
//clazz 就表示Student这个类的字节码文件对象。
//就是当Student.class这个文件加载到内存之后,产生的字节码文件对象


//2.第二种方式
//一般更多的是当作参数传递
Class clazz2 = Student.class;

//因为class文件在硬盘中是唯一的,所以,当这个文件加载到内存之后产生的对象也是唯一的
System.out.println(clazz1 == clazz2);//true


//3.第三种方式
//当我们已经有了这个类的对象时,才可以使用
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz2 == clazz3);//true

获取构造方法

reflect3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;

public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

Class clazz = Class.forName("Student");

Constructor[] cons = clazz.getConstructors();
for (Constructor con : cons) {
System.out.println(con);
}

Constructor[] con1 = clazz.getDeclaredConstructors();
for (Constructor con : con1) {
System.out.println(con);
}
Constructor con2 = clazz.getDeclaredConstructor();
System.out.println(con2);

Constructor con3 = clazz.getDeclaredConstructor(String.class);
System.out.println(con3);

Constructor con5 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(con5);

int modifiers = clazz.getModifiers();
System.out.println(modifiers);

Parameter[] parameters = con5.getParameters();
for (Parameter param : parameters) {
System.out.println(param);
}

//暴力反射:临时取消权限
con5.setAccessible(true);
Student stu = (Student) con5.newInstance("ZhangSan", 23);
System.out.println(stu);

}
}

获取成员变量

reflect4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
public class ReflectDemo4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
//获取成员变量对象

//1.获取class对象
Class clazz = Class.forName("com.itheima.reflectdemo.Student");

//2.获取成员变量的对象(Field对象)只能获取public修饰的
Field[] fields1 = clazz.getFields();
for (Field field : fields1) {
System.out.println(field);
}

System.out.println("===============================");

//获取成员变量的对象(public + private)
Field[] fields2 = clazz.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field);
}

System.out.println("===============================");
//获得单个成员变量对象
//如果获取的属性是不存在的,那么会报异常
//Field field3 = clazz.getField("aaa");
//System.out.println(field3);//NoSuchFieldException

Field field4 = clazz.getField("gender");
System.out.println(field4);

System.out.println("===============================");
//获取单个成员变量(私有)
Field name = clazz.getDeclaredField("name");
System.out.println(name);

//获取权限修饰符
int modifiers = name.getModifiers();
System.out.println(modifiers);

//获取成员变量名字
String n = name.getName();
System.out.println(n);

//获取成员变量的数据类型
Class<?> type = name.getType();
System.out.println(type);

//获取成员变量记录的值
Student s = new Student("ZhangSan", 23, "男");
name.setAccessible(true);
String value = (String) name.get(s);
System.out.println(value);

//修改对象里面记录的值
name.set(s, "LiSi");
System.out.println(s);
}
}



public class Student {
private String name;

private int age;

public String gender;

public String address;


public Student() {
}

public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}


public Student(String name, int age, String gender, String address) {
this.name = name;
this.age = age;
this.gender = gender;
this.address = address;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

/**
* 获取
* @return gender
*/
public String getGender() {
return gender;
}

/**
* 设置
* @param gender
*/
public void setGender(String gender) {
this.gender = gender;
}

/**
* 获取
* @return address
*/
public String getAddress() {
return address;
}

/**
* 设置
* @param address
*/
public void setAddress(String address) {
this.address = address;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", address = " + address + "}";
}
}

调用成员方法

reflect5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class ReflectDemo6 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
//1.获取class对象
Class<?> clazz = Class.forName("com.itheima.reflectdemo.Student");


//2.获取方法
//getMethods可以获取父类中public修饰的方法
Method[] methods1 = clazz.getMethods();
for (Method method : methods1) {
System.out.println(method);
}

System.out.println("===========================");
//获取所有的方法(包含私有)
//但是只能获取自己类中的方法
Method[] methods2 = clazz.getDeclaredMethods();
for (Method method : methods2) {
System.out.println(method);
}

System.out.println("===========================");
//获取指定的方法(空参)
Method method3 = clazz.getMethod("sleep");
System.out.println(method3);

Method method4 = clazz.getMethod("eat",String.class);
System.out.println(method4);

//获取指定的私有方法
Method method5 = clazz.getDeclaredMethod("playGame");
System.out.println(method5);
}
}


作用

  1. 获取一个类里面所有的信息,获取后,再执行其他的业务逻辑
  2. 结合配置文件,动态的创建对象并调用方法

reflect6

动态代理

reflect7

reflect8

代码实现

reflect9

1
2
3
4
5
6
7
public interface Star {
//我们可以把所有想要被代理的方法定义在接口当中
//唱歌
public abstract String sing(String name);
//跳舞
public abstract void dance();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class BigStar implements Star {
private String name;


public BigStar() {
}

public BigStar(String name) {
this.name = name;
}

//唱歌
@Override
public String sing(String name){
System.out.println(this.name + "正在唱" + name);
return "谢谢";
}

//跳舞
@Override
public void dance(){
System.out.println(this.name + "正在跳舞");
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

public String toString() {
return "BigStar{name = " + name + "}";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
*
* 类的作用:
* 创建一个代理
*
* */
public class ProxyUtil {
/*
*
* 方法的作用:
* 给一个明星的对象,创建一个代理
*
* 形参:
* 被代理的明星对象
*
* 返回值:
* 给明星创建的代理
*
*
*
* 需求:
* 外面的人想要大明星唱一首歌
* 1. 获取代理的对象
* 代理对象 = ProxyUtil.createProxy(大明星的对象);
* 2. 再调用代理的唱歌方法
* 代理对象.唱歌的方法("只因你太美");
* */
public static Star createProxy(BigStar bigStar){
/* java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
参数一:用于指定用哪个类加载器,去加载生成的代理类
参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
参数三:用来指定生成的代理对象要干什么事情*/
Star star = (Star) Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(),//参数一:用于指定用哪个类加载器,去加载生成的代理类
new Class[]{Star.class},//参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
//参数三:用来指定生成的代理对象要干什么事情
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
* 参数一:代理的对象
* 参数二:要运行的方法 sing
* 参数三:调用sing方法时,传递的实参
* */
if("sing".equals(method.getName())){
System.out.println("准备话筒,收钱");
}else if("dance".equals(method.getName())){
System.out.println("准备场地,收钱");
}
//去找大明星开始唱歌或者跳舞
//代码的表现形式:调用大明星里面唱歌或者跳舞的方法
return method.invoke(bigStar,args);
}
}
);
return star;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Test {
public static void main(String[] args) {
/*
需求:
外面的人想要大明星唱一首歌
1. 获取代理的对象
代理对象 = ProxyUtil.createProxy(大明星的对象);
2. 再调用代理的唱歌方法
代理对象.唱歌的方法("只因你太美");
*/
//1. 获取代理的对象
BigStar bigStar = new BigStar("鸡哥");
Star proxy = ProxyUtil.createProxy(bigStar);

//2. 调用唱歌的方法
String result = proxy.sing("只因你太美");
System.out.println(result);
}
}