Java三大版本
- JavaSE 标准版 (桌面程序,控制台开发… )
- JavaME 嵌入式开发 (手机,小家电… )
- JavaEE E企业级开发 (web端,服务器开发… )
JDK , JRE , JVM
- JDK: java Development Kit (Java 开发者工具 , JDK 中包含 JRE)
- JRE: java Runtime Environment (Java运行环境)
- JVM: java Virtual Machine (Java虚拟机)
HelloWorld详解
- 随便新建一个文件夹,存放代码
- 新建一个java文件
- 文件后缀名为 .java
- HelloWorld.java
- [注意点] 系统可能没有显示文件后缀名,我们需要手动打开
- 编写代码
public class HelloWorld{ public static void main(String[] args){ System.out.print("Hello,World!"); } }
- 编译 javac java文件,会生成一个class文件
- 运行class 文件, java class文件 (运行class文件不用加class后缀)
Java八大基础数据类型
数据类型
- 强类型语言
- 要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用
- Java的数据类型分为两大类
- 基本类型 (primitive type)
- 引用类型 (reference type)
-
整型(byte、short、int、long)
虽然byte、short、int、long 数据类型都是表示整数的,但是它们的取值范围可不一样。
byte 的取值范围:-128~127(-2的7次方到2的7次方-1)
short 的取值范围:-32768~32767(-2的15次方到2的15次方-1)
int 的取值范围:-2147483648~2147483647(-2的31次方到2的31次方-1)
long 的取值范围:-9223372036854774808~9223372036854774807(-2的63次方到2的63次方-1)
由上可以看出 byte、short 的取值范围比较小,而long的取值范围时最大的,所以占用的空间也是最多的。int 取值范围基本上可以满足我们的日常计算需求了,所以 int 也是我们使用的最多的一个整型类型。
-
浮点型(float、double)
float 和 double 都是表示浮点型的数据类型,它们之间的区别在于精确度的不同。
float(单精度浮点型)取值范围:3.402823e+38~1.401298e-45(e+38 表示乘以10的38次方,而e-45 表示乘以10的负45次方)
double(双精度浮点型)取值范围:1.797693e+308~4.9000000e-324(同上)
double 类型比float 类型存储范围更大,精度更高。
通常的浮点型数据在不声明的情况下都是double型的,如果要表示一个数据时float 型的,可以在数据后面加上 “F” 。
浮点型的数据是不能完全精确的,有时候在计算时可能出现小数点最后几位出现浮动,这时正常的。
-
字符型(char)
char 有以下的初始化方式:
char ch = ‘a’; // 可以是汉字,因为是Unicode编码
char ch = 1010; // 可以是十进制数、八进制数、十六进制数等等。
char ch = ‘\0’; // 可以用字符编码来初始化,如:’\0’ 表示结束符,它的ascll码是0,这句话的意思和 ch = 0 是一个意思。
Java是用unicode 来表示字符,“中” 这个中文字符的unicode 就是两个字节。
String.getBytes(encoding) 方法获取的是指定编码的byte数组表示。
通常gbk / gb2312 是两个字节,utf-8 是3个字节。
如果不指定encoding 则获取系统默认encoding 。
- boolean 没有什么好说的,它的取值就两个:true 、false 。
类型转换
-
由于Java是强类型语言,所以要进行有些运算的时候,需要用到类型转换
低 -------------------------------------------------------> 高
byte,short,char --> int --> long --> float --> double
- 运算中,不同类型的数据先转换为同一类型,然后进行运算
- 强制类型转换
- 自动类型转换
package com.byxx.yunan;
import java.util.HashMap;
import java.util.concurrent.*;
/**
* @Author yww
* @CreateTime 2020-10-25
*/
public class Test {
public static void main(String[] args){
int i = 128;
byte b = (byte) i; //强制转换内存溢出, Byte最大值为127 ,最小值为-128
//输出值 为 -128
System.out.println(b);
//自动转换
double d = i;
System.out.println(d);
/*
注意点:
1. 不能对布尔值进行转换
2. 不能把对象类型转换为不相干的类型
3. 在把高容量转换到低容量时,需要强制转换,反正,自动转换
4. 转换的时候可能存在内存溢出,或者精度问题!
*/
System.out.println((int)23.7);//23
System.out.println((int)-45.89f);//-45
}
}
注意 操作比较大的数的时候,内存溢出问题
package com.byxx.yunan.test;
/**
* @Author yww
* @CreateTime 2021-02-03
*/
public class Test2 {
public static void main(String[] args) {
//操作比较大的数的时候,注意溢出问题
//JDK7新特性,数字直接可以用下划线分割
int money = 10_0000_0000;
int years = 20;
int total = money * years;//-1474836480 , 内存溢出
long total2 = money * years;//-1474836480 , 先是两个int类型运算 得出结果还是int类型 (结果已经出问题了,再转long也是不行)
long total3 = money * ((long)years);//20000000000 , 先把一个数转为long
System.out.println(total3);
}
}
变量 ,常量 , 作用域
- 默认初始化值:
- 数字: 0 0.0
- char: \u0000
- boolean: false
- 引用:null
package com.byxx.yunan.test;
/**
* @Author yww
* @CreateTime 2021-02-03
*/
public class Test3 {
//静态常量
static final String str = "1";
//类变量,静态变量
static String msg = "123";
//实例变量: 从属于对象,如果不自行初始化值, 则拿 类型的默认值
//int 0,以此类推,除了基本类型,其余的默认都是 null ,布尔值为false
String name;
int age;
public static void main(String[] args) {
//局部变量
int i = 1;
//new 对象
Test3 test = new Test3();
System.out.println(test.name+"\n"+test.age);
}
}
运算符
- 算术运算符:+,-,*,/,%,++,–
- 赋值运算符:=
- 关系运算符:>,<,>=,<=,==,!=,instanceof
- 逻辑运算符:&&,||,!
- 位运算符:&,|,^,~,>>,>>>
- 条件运算符:?,:
- 扩展赋值运算符:+=,-=,*=,/=
算术运算符
package com.byxx.yunan.test;
/**
* @Author yww
* @CreateTime 2021-02-03
*/
public class Test4 {
public static void main(String[] args) {
//++ -- 自增,自减 一元运算符
int a = 3;
int b = a++; //先给b赋值,再自增
int c = ++a; //先自增,再赋值
System.out.println(a);// 5
System.out.println(b);// 3
System.out.println(c);// 5
//幂运算 2^3 2*2*2 = 8
double pow = Math.pow(2,3);//java中的幂运算
System.out.println(pow);
}
}
逻辑运算符
package com.byxx.yunan.test;
/**
* @Author yww
* @CreateTime 2021-02-03
*/
public class Test5 {
public static void main(String[] args) {
//& 与(and) , | 或(or) , ! 非(取反)
boolean a = true;
boolean b = false;
System.out.println(a&&b);//false 逻辑与运算,两个变量都为true,结果才为true
System.out.println(a||b);//true 逻辑或运算,两个变量有一个为true,结果才为true
System.out.println(!(a&&b));//true 如果是真,则为假 如果是假,则为真
//短路运算
System.out.println(b&&a);//第一位数为false则不执行后面操作,输出结果为false
//验证: (短路运算)
int i = 5;
// i>6 = false && i++>7
System.out.println((i>6) && (i++)>7);
//根据 算术运算符定律 i++ 如果执行了,则i=6
System.out.println(i);//输出结果为5,验证了短路运算,前者为false,后者不执行
}
}
位运算符
package com.byxx.yunan.test;
import javax.sound.midi.Soundbank;
/**
* @Author yww
* @CreateTime 2021-02-03
*/
public class Test6 {
public static void main(String[] args) {
/*
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100 位运算(与运算),同级位,两个值相等则为相等值,否则为0
A|B = 0011 1101 位运算(或运算),同级位,
A^B = 0011 0001 位运算(异或运算),同级位,两个值相等则为0,不相等则为1
~B = 1111 0010 (取反运算),0为1,1为0
*/
//左移运算 (第一个数值 乘 2的第二个数值次方)
System.out.println(3*2);
System.out.println(3<<1);//3 * 2的一次方(3乘2的一次方) 3 * 2 = 6
System.out.println(3<<2);//3 * 2的二次方(3乘2的二次方) 3 * (2*2) = 12
System.out.println(3<<3);//3 * 2的三次方(3乘2的三次方) 3 * (2*2*2) = 24
//右移运算 (第一个数值 除 2的第二个数值次方)
System.out.println("-------------------------");
System.out.println(4>>1);//4 / 2的一次方(4除2的一次方) 4 / 2 = 2
System.out.println(4>>2);//4 / 2的二次方(4除2的二次方) 4 / (2*2) = 1
System.out.println(4>>3);//4 / 2的三次方(4除3的三次方) 4 / (2*2*2) = -4
}
}
条件运算符 (三元运算符)
package com.byxx.yunan.test;
/**
* @Author yww
* @CreateTime 2021-02-03
*/
public class Test8 {
public static void main(String[] args) {
int age = 22;
//普通 三元运算符
String type1 = age>18 ? "成年" : "未成年"; //输出结果为 成年
//嵌套 三元运算符
String type2 = age>30 ? "成年" : (age==22) ? "我22岁啦" : "未成年";//输出结果为 我22岁啦
}
}
扩展赋值运算符
package com.byxx.yunan.test;
/**
* @Author yww
* @CreateTime 2021-02-03
*/
public class Test7 {
public static void main(String[] args) {
int a = 10;
int b = 2;
a+=b;//a = a + b;
a-=b;//a = a - b;
a*=b;//a = a * b;
a/=b;//a = a / b;
//字符串连接符 + , String
System.out.println(""+a+b);//字符串在前,则输出字符串连接 结果为 102,要想结果正确加括号即可 ""+(a+b)
System.out.println(a+b+"");//从左开始运算,a+b= 12 加字符串 = 12
}
}
JavaDoc生成文档
- cmd指令 javadoc -encoding UTF-8 -charset UTF-8 Test9.java
需要文档注释
- 生成JavaAPI文档
Switch 多选择结构
- switch case 语句判断一个变量与系列值中某个值是否相等,每个值称为一个分支
- switch 语句中的变量类型可以是:
- byte, short, int 或者char
- 从Java SE7 开始 switch支持字符串String 类型了
- 同时 case 标签必须为字符串常量或字面量
package com.byxx.yunan.test;
/**
* @Author yww
* @CreateTime 2021-02-03
*/
public class Test9 {
public static void main(String[] args) {
byte a = 0;
short b = 1;
int c = 2;
char d = 'A';
String str = "高达";
//JDK 7 ,表达式结果可以是字符串!
//字符的本质还是数字
switch (str){
case "张三":
System.out.println("张三");
break;//没有写break会出现switch穿透
case "李四":
System.out.println("李四");
break;
case "高达":
System.out.println("这里是高达!");
break;
default:
System.out.println("what are you? 弄啥嘞?");
}
}
}
验证字符本质还是数字 (查看编译后源码)
编译后class文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.byxx.yunan.test;
public class Test9 {
public Test9() {
}
public static void main(String[] args) {
byte a = false;
short b = true;
int c = true;
char d = true;
String str = "高达";
byte var7 = -1;
switch(str.hashCode()) {
case 774889:
if (str.equals("张三")) {
var7 = 0;
}
break;
case 842061:
if (str.equals("李四")) {
var7 = 1;
}
break;
case 1265638:
if (str.equals("高达")) {
var7 = 2;
}
}
switch(var7) {
case 0:
System.out.println("张三");
break;
case 1:
System.out.println("李四");
break;
case 2:
System.out.println("这里是高达!");
break;
default:
System.out.println("what are you? 弄啥嘞?");
}
}
}
循环结构
- while 循环
- do … while 循环
- for 循环
- 增强 for 循环
- while 循环
- 只要布尔表达式为true,循环就会一直执行下去,false则退出
int a = 0; while (a<10){ a++; System.out.println(a); }
- do … while 循环
- do … while 和 while 循环相似,不同的是,do … while 循环至少会执行一次。
- while 和 do … while 的区别:
- while 先判断,后执行。do … while 先执行,后判断!
- do … while 总是保证循环体至少会被执行一次!这是他们的主要差别。
int a = 0; do{ a++; System.out.println(a); }while(a<10);
- for 循环
- for 循环执行的次数是在执行前就确定的。语法格式如下:
for(初始化; 布尔表达式; 更新){ //代码语句 }
- for 循环 的 死循环写法
for(;;){ }
- 打印99乘法表
package com.byxx.yunan.test; /** * @Author yww * @CreateTime 2021-02-03 */ public class Test10 { public static void main(String[] args) { /* 打印99乘法表 1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 4*1=4 4*2=8 4*3=12 4*4=16 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 步骤解析: 1. 我们先打印第一列 2. 去掉重复项 b <= a 3. 调整样式 */ for(int a=1;a<=9;a++){ for(int b=1;b<=a;b++){ System.out.print(a+"*"+b+"="+(a*b)+"\t"); } System.out.println(); } } }
- for 循环执行的次数是在执行前就确定的。语法格式如下:
- 增强 for 循环
- 主要用于遍历数组和集合的增强型 for 循环
int[] numbers = {10,20,30,40,50}; for(int x: numbers){ System.out.println(x); }
- while 循环
Break ,Continue
- break 在任何循环语句的主体部分, 均可用break控制循环的流程。break用于强制退出循环,不执行循环中剩余的语句。(break语句也可以在switch中使用)
- continue 语句用在循环语句体中,用于终止某次循环过程,即跳出循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。
方法重载
- 方法名必须相同
- 参数列表必须不同
- 返回值一致或者相同 (返回值不能决定方法是不是重载)
//重载
public String appendMsg(String str1,int a){
return str1+a;
}
//重载
public Integer appendMsg(int a,int b){
return a+b;
}
//原型
public String appendMsg(String str1,String str2){
return str1+str2;
}
可变参数
- 在方法声明中,在指定参数类型后加一个省略号(…)
- 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
package com.byxx.yunan.test;
/**
* @Author yww
* @CreateTime 2021-02-03
*/
public class Test12 {
public static void main(String[] args) {
Test12 t1 = new Test12();
t1.getName("1","2","3");//123
t1.getName("1","4");//14
}
//可变参数
public String getName(String... names){
StringBuffer sb = new StringBuffer();
for(String str : names){
sb.append(str);
}
return sb.toString();
}
}
Math 数学工具类
- 平常基本方法:
- Math.abs(); 获取绝对值
- Math.ceil(); 向上取整
- Math.floor(); 向下取整
- Math.round(); 四舍五入
package com.byxx.yunan.test.arrays;
/**
*
* @Author yww
* @CreateTime 2021-02-07
*/
public class Test7 {
public static void main(String[] args) {
/*
Math 数学工具类, 平常基本方法使用
public static double abs(double num):获取绝对值。有多种重载
public static double ceil(double num):向上取整
public static double floor(double num):向下取整
public static long round(double num):四舍五入
*/
//获取绝对值
System.out.println(Math.abs(3.14));//3.14
System.out.println(Math.abs(0));//0
System.out.println(Math.abs(-3.14));//3.14
//向上取整
System.out.println(Math.ceil(3.9));//4.0
System.out.println(Math.ceil(3.0));//3.0
System.out.println(Math.ceil(3.1));//4.0
//向下取整
System.out.println(Math.floor(3.9));//3.0
System.out.println(Math.floor(3.1));//3.0
System.out.println(Math.floor(3.0));//3.0
//四舍五入
System.out.println(Math.round(3.5));//4
System.out.println(Math.round(3.4));//3
System.out.println(Math.round(3.6));//4
}
}
Random 随机数工具类
package com.byxx.yunan.test.arrays;
import java.util.Random;
/**
* @Author yww
* @CreateTime 2021-02-07
*/
public class Test8 {
public static void main(String[] args) {
//创建随机数
Random random = new Random();
for (int i = 0; i < 100; i++) {
int num = random.nextInt(5);// 范围是 0-5, 实际取值范围是 0-4
// System.out.println(num);
}
//需求: 随机数实际取值 从1开始
for (int i = 0; i < 100; i++) {
int num = random.nextInt(9)+1;// 范围是 (0-9)+1, 原范围是0-8, +1后实际取值范围是 1-9
System.out.println(num);
}
}
}
数组
数组详解
- 必须声明数组变量,才能在程序中使用数组,使用new操作符来创建数组
int[] arrays1 = new int[3];//首选定义方式 int arrays3[] = new int[3];//效果相同,但不是首选 int[] arrays2 = {1,2,3};
- 数组的元素是通过索引访问的,数组索引从0开始
- 获取数组长度:
arrays.length
- 数组的四个基本特点
- 其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
- 其元素必须是相同类型,不允许出现混合类型。
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型。
- 数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
获取数组中的最大值package com.byxx.yunan.test; /** * @Author yww * @CreateTime 2021-02-04 */ public class Test { public static void main(String[] args) { //查询数组中最大值 int[] arrays = {1,5,2,8,3}; int max = 0; for(int a: arrays){ if(a>max){ max = a; } } System.out.println(max);//8 } }
反转数组
- 第一种方法
package com.byxx.yunan.test.arrays; import javax.sound.midi.Soundbank; import java.util.Arrays; /** * @Author yww * @CreateTime 2021-02-04 */ public class Test1 { public static void main(String[] args) { //反转数组 int[] arrays = {1,2,3,4,5}; int[] newArrays = new int[arrays.length]; int initLength = arrays.length-1; //第一种方法 int index = 0; for(int a=initLength; a>=0; a--){ newArrays[index] = arrays[a]; index++; } System.out.println(Arrays.toString(newArrays)); } }
- 第二种方法
package com.byxx.yunan.test.arrays; import javax.sound.midi.Soundbank; import java.util.Arrays; /** * @Author yww * @CreateTime 2021-02-04 */ public class Test1 { public static void main(String[] args) { //反转数组 int[] arrays = {1,2,3,4,5}; int[] newArrays = new int[arrays.length]; int initLength = arrays.length-1; //第二种方法 for(int a = 0,b = initLength; a <=initLength; a++,b--){ newArrays[a] = arrays[b]; } System.out.println(Arrays.toString(newArrays)); } }
多维数组
- 多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组。
- 二维数组
package com.byxx.yunan.test.arrays; /** * @Author yww * @CreateTime 2021-02-04 */ public class Test2 { public static void main(String[] args) { //创建二维数组 //int[][] a = new int[2][5]; int[][] a = {{1,2},{3,4},{5,6}}; for(int i=0;i<a.length;i++){ for (int j=0;j<a[i].length;j++){ System.out.print(a[i][j]+"\t"); } System.out.println(); } /* 输出结果: 1 2 3 4 5 6 */ } }
- 二维数组结构解析
Arrays 工具类
- sort 用法 (升序,降序)
Integer[] arrays = {5,2,4,3,8}; String[] strs = {"aaa","bbb","ccC","eee","ddd"}; //字母也可以,默认按26个英文字母升序排列 //升序 排序 Arrays.sort(arrays); System.out.println(Arrays.toString(arrays));//[2, 3, 4, 5, 8] //降序排序 Arrays.sort(arrays,Collections.reverseOrder()); System.out.println(Arrays.toString(arrays));//[8, 5, 4, 3, 2]
- 冒泡排序
package com.byxx.yunan.test.arrays; import java.util.Arrays; /** * @Author yww * @CreateTime 2021-02-04 */ public class Test4 { public static void main(String[] args) { /* 冒泡排序 1.比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置 2.每一次比较,都会产生一个最大,或者最小的数字 3.下一轮则可以少一次排序 4.一次循环,直到结束 */ int[] arrays = {1,3,2,1,7,4,8}; //临时变量 int temp = 0; boolean flag = false;//是否交换的标志 for (int i = 0; i < arrays.length-1; i++) { // 每次遍历标志位都要先置为false,才能判断后面的元素是否发生了交换 flag = false; for (int j = 0; j < arrays.length-1-i; j++) { if(arrays[j+1] > arrays[j]){ // > 大于为 降序 , < 小于 为升序 temp = arrays[j]; arrays[j] = arrays[j+1]; arrays[j+1] = temp; flag = true; } } // 判断标志位是否为false,如果为false,说明后面的元素已经有序,就直接return if(!flag){ break; } } System.out.println(Arrays.toString(arrays));//[8, 7, 4, 3, 2, 1, 1] } }
Object ,Objects
- Object.equals() Object为null,会报空指针异常
- Objects.equals(a,b) a为null,不会出现空指针异常
package com.byxx.yunan.test.oop; import java.util.Objects; /** * @Author yww * @CreateTime 2021-02-07 */ public class Test1 { public static void main(String[] args) { String str = null; //普通equals() 不允许第一个值null,否则报错 boolean flagA = str.equals("123"); System.out.println(flagA);//报错,空指针异常 //Objects.equals(a,b); 不会报错, 允许第一个值为null,防止空指针 boolean flagB = Objects.equals(str, "123"); System.out.println(flagB); } }
日期
Date
- Date date = new Date(); 无参构造,获取当前系统日期时间
- Date date = new Date(long date); 有参构造,传递毫秒数,把毫秒转换为Date日期
-
date.getTime(); 把日期转换为毫秒(相当于System.currentTimeMillis()) ,
返回 1970年 1月 1日 00:00:00 GMT 以来此表示 Date 对象表示的毫秒数
package com.byxx.yunan.test.oop;
import com.sun.org.apache.bcel.internal.generic.NEW;
import java.util.Date;
/**
* @Author yww
* @CreateTime 2021-02-07
*/
public class Test2 {
public static void main(String[] args) {
demo1();
demo2();
demo3();
}
/*
Date 的无参构造方法
new Date(); 获取当前系统日期时间
*/
private static void demo1(){
Date date = new Date();
System.out.println(date);//Sun Feb 07 15:30:24 CST 2021
}
/*
Date 的有参构造方法
new Date(long date); 传递毫秒值,把毫秒转换为Date日期
*/
private static void demo2(){
Date date = new Date(0L);//初始日期时间
System.out.println(date);//Thu Jan 01 08:00:00 CST 1970
}
/*
Date 类的成员方法
long getTime() 把日期转换为毫秒(相当于System.currentTimeMillis())
返回 1970年 1月 1日 00:00:00 GMT 以来此表示 Date 对象表示的毫秒数
*/
private static void demo3(){
Date date = new Date();
long time = date.getTime();
System.out.println(time);
}
}
SimpleDateFormat
- SimpleDateFormat 常用方法
- format(); 将日期转为字符串格式
- parse(); 将字符串转为日期格式
package com.byxx.yunan.test.oop; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * java.text.SimpleDateFormat:是日期/时间格式化子类的抽象类 * 作用: * 格式化(日期--转--文本) (文本--转--日期) * 成员方法: * String format(Date date) 按照指定的模式,把Date日期,格式化为符合模式的字符串 * Date parse(String source) 把符合模式的字符串,解析为Date日期 * @Author yww * @CreateTime 2021-02-08 */ public class Test3 { public static void main(String[] args) throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:ss:mm"); //日期转字符串 format() Date date = new Date(); String timeStr = sdf.format(date); System.out.println(timeStr);//2021-02-08 09:55:06 //字符串转Date parse() String nowDate = "2021-02-08 09:28:06"; Date timeDate = sdf.parse(nowDate); System.out.println(timeDate);//Mon Feb 08 09:06:28 CST 2021 } }
Calendar 日历类
- Calendar类的成员方法
- public int get (int field); 返回该日历字段的值
- public void set (int field,int value); 将给定的日历字段设置为定值
- public abstract void add (int field,int amount); 根据日历的规则,为给定的日历字段添加或减去指定的时间量
- public Date getTime (); 返回一个表示此Calendar的值 (从历元到现在的毫秒偏移量) 的Date对象
- 成员方法的参数
- int field; 日历类的字段,可以使用Calendar类的静态成员变量获取
- public static final int YEAR = 1; 年
- public static final int MONTH = 2; 月 西方的0-11,东方的1-12,所以结果+1
- public static final int DATE = 5; 月中的某一天
- public static final int DAY_OF_MONTH = 5;月中的某一天
- public static final int HOUR = 10; 时
- public static final int MINUTE = 12; 分
- public static final int SECOND = 13; 秒
package com.byxx.yunan.test.oop;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import java.util.Calendar;
import java.util.Date;
/**
* Calendar类的成员方法:
* public int get(int field); 返回给日历字段的值。
* public void set(int field,int value); 将给定的日历字段设置为定值
* public abstract void add(int field,int amount); 根据日历的规则,为给定的日历字段添加或减去指定的时间量
* public Date getTime(); 返回一个表示此Calendar的值 (从历元到现在的毫秒偏移量)的Date对象
*
* 成员方法的参数:
* int field:日历类的字段,可以使用Calendar类的静态成员变量获取
* public static final int YEAR = 1; 年
* public static final int MONTH = 2; 月 //西方的0-11, 东方的1-12, 所以结果+1
* public static final int DATE = 5; 月中的某一天
* public static final int DAY_OF_MONTH = 5; 月中的某一天
* public static final int HOUR = 10; 时
* public static final int MINUTE = 12; 分
* public static final int SECOND = 13; 秒
*/
public class Test4 {
public static void main(String[] args) {
//日历类
Calendar c = Calendar.getInstance();
//没有打印内存地址,代表重写了toString()方法
//java.util.GregorianCalendar[time=1612747829597,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2021,MONTH=1,WEEK_OF_YEAR=7,WEEK_OF_MONTH=2,DAY_OF_MONTH=8,DAY_OF_YEAR=39,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=2,AM_PM=0,HOUR=9,HOUR_OF_DAY=9,MINUTE=30,SECOND=29,MILLISECOND=597,ZONE_OFFSET=28800000,DST_OFFSET=0]
System.out.println(c);
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH)+1;//西方的0-11, 东方的1-12, 所以结果+1
int date = c.get(Calendar.DATE);
System.out.println(year+"年 "+month+"月 "+date+"号");
//给指定日历字段赋值 calendar.get(int field);
c.set(Calendar.YEAR,2088);
System.out.println(c.get(Calendar.YEAR));// 输出: 2088
//根据日历的规则,为给定的日历字段添加或减去指定的时间量 calendar.add(int field);
c.add(Calendar.YEAR,-2);//减两年
System.out.println(c.get(Calendar.YEAR));// 输出:在2088年上减两年 2086
c.add(Calendar.MONTH,3);//加三月
System.out.println(c.get(Calendar.MONTH)+1);// 输出:5
}
}
面向对象
面向对象特征
- 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据
- 抽象
- 三大特征:
- 封装
- 提高了程序的安全性,保护数据
- 隐藏了代码的实现细节
- 统一接口
- 系统可维护性增加
- 继承
- extends 的意思是 “扩展” 。子类是父类的扩展
- Java中的 类 只有单继承,没有多继承!,接口可以多继承。(一个儿子只有一个亲爸爸(单继承))
- 类被 final 修饰后不能被继承,因为 final 不可更改,子类无法重写父类方法
- 多态
- 父类的引用指向子类 (父 new 子)
- 多态存在的条件:
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
package com.byxx.yunan.test.arrays; /** * @Author yww * @CreateTime 2021-02-04 */ public class Test6 { public static void main(String[] args) { //Student 能调用自身和父类的方法 Student student = new Student(); //Person 只能调用自身的方法, 不可调用子类的方法 Person person = new Student(); //验证父 new 子,类全部都隐式继承了Object Object object = new Student(); } } //学生 继承 人 class Student extends Person{ }
- 封装
值传递,引用传递package com.byxx.yunan.test.arrays; /** * @Author yww * @CreateTime 2021-02-04 */ public class Test5 { public static void main(String[] args) { String name = "李四"; change(name);//值传递,原值不变 System.out.println(name);//输出结果为:李四 Person person = new Person(); person.name = "李四"; changePerson(person); System.out.println(person.name);//输出结果为:王五 } //值传递 public static void change(String name){ name = "张三"; } //引用传递: 对象,本质还是值传递 public static void changePerson(Person person){ //person是一个对象, 指向的 ---> Person person = new Person(); 这是一个具体的对象,可以改变属性! person.name = "王五"; } } //person类 class Person{ String name; }
super,this
super注意点:
1. super 调用父类的构造方法,必须在构造方法的第一个
2. super 必须只能出现在子类的方法或者构造方法中
3. super 和 this 不能同时调用构造方法
VS this:
代表的对象不同:
this:本身调用者这个对象
super:代表父类对象的应用
- 前提:
this:没有继承也可以使用
super:只能在继承条件中才可以使用构造方法
- 构造方法:
this() ; 本身的构造
super() ; 父类的构造
重写
重写:需要有继承关系,子类重写父类的方法!重写:子类的方法和父类必须一致:方法体不同!
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大但不能缩小 public > protected > default > private
- 抛出的异常:范围,可以被缩小,但不能扩大 ClassNotFoundException --> Exception (大)
为什么需要重写 ?
父类的功能,子类不一定需要,或者不一定满足!
static 关键字详解
package com.byxx.yunan.test.arrays;
/**
* @Author yww
* @CreateTime 2021-02-04
*/
public class User {
//2
{
System.out.println("匿名代码块");
}
//1 只执行一次
static {
System.out.println("静态代码块");
}
//3
public User(){
System.out.println("构造方法");
}
public static void main(String[] args) {
/*
创建 User 对象时, 先执行 静态代码块, 再执行 匿名代码块, 最后执行 构造方法
*/
User user = new User();
/*
第二次创建 User 对象,先执行 匿名代码块, 再执行 构造方法,
注意: 第二次创建 该对象 不再 执行静态代码块, 因为 static 修饰 只执行一次
*/
User user2 = new User();
}
}
抽象
- 抽象类不能实例化(new),只能靠子类去实现它
- 抽象类中可以写普通的方法
- 抽象方法必须在抽象类中
- 抽象方法存在构造器
1. 抽象类存在的意义?
更利于代码的维护性和重用,提高开发效率。
2. 验证理论
package com.byxx.yunan.test.oop; //abstract 抽象类: 类 extends 单继承~ (接口可以多继承) public abstract class Action { //abstract, 抽象方法, 只有方法名字, 没有方法的实现! public abstract void sayHi(); //普通方法 public String getName(){ return "张三"; } //1. 抽象类不能实例化(new), 只能靠子类去实现它 //2. 抽象类中可以写普通的方法 //3. 抽象方法必须在抽象类中 //4. 抽象方法存在构造器 /* 抽象类存在的意义? 更利于代码维护和重用,提高开发效率 */ } //抽象类的所有方法, 继承了它的子类, 都必须要实现它的抽象方法, 除非子类也是抽象 class ChildActionB extends Action{ @Override public void sayHi() { } } //子类抽象, 不需要重写 父抽象类 的方法 abstract class ChildActionC extends Action{ }
接口
- interface 关键字定义接口,接口中可以多继承
- 接口中定义变量 实际为 常量 默认加上 public static final
- 接口中的所有定义其实都是抽象的 默认加上 public abstract
- 实现接口必须实现接口中的所有方法,因为接口中的方法 都是抽象的
- 接口不能被实例化,因为接口中没有构造方法
- implement 可以实现多个接口
package com.byxx.yunan.test.oop;
//interface 关键字定义接口, 接口中可以多继承
public interface UserService {
//接口中定义变量 实际为常量 默认加上 public static final
int AGE = 99;
//接口中的所有定义其实都是抽象的 默认加上 public abstract
public abstract String getName();
//等价 public abstract Integer getAge();
public Integer getAge();
//等价 public abstract void sayHello();
void sayHello();
}
N种内部类
- 成员内部类
import javax.sound.midi.Soundbank; /** * 外部类 * @Author yww * @CreateTime 2021-02-05 */ public class Outer { //成员内部类 class Inner{ public void say(){ System.out.println("这是成员内部类的方法"); } } }
- 静态内部类
import javax.sound.midi.Soundbank; /** * 外部类 * @Author yww * @CreateTime 2021-02-05 */ public class Outer { //静态内部类 static class Inner2{ public void say(){ System.out.println("这是静态内部类的方法"); } } }
- 局部内部类
import javax.sound.midi.Soundbank; /** * 外部类 * @Author yww * @CreateTime 2021-02-05 */ public class Outer { //局部内部类 class Inner{ public void say(){ System.out.println("这是局部内部类的方法"); } } }
- 匿名内部类
package com.byxx.yunan.test.oop; import com.sun.org.apache.bcel.internal.generic.NEW; /** * 外部类 * @Author yww * @CreateTime 2021-02-05 */ public class Outer { public static void main(String[] args) { //匿名内部类 new PersonService(){ @Override public void hello() { } }; } } interface PersonService{ void hello(); }
异常
Error 和 Exception
- Error
- Error类对象由 Java 虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
- Exception
- Exception异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
Error 和 Exception 的区别 :
Error 通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机 (JVM) 一般会选择终止线程;
Exception 通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
捕获和抛出异常
- 异常处理机制
- 抛出异常
- 捕获异常
- 异常处理五个关键字
- try (监控区域)
- catch (想要捕获的异常类型!) 捕获异常
- finally (一般用于关闭资源)
- throw (主动抛出异常,一般在 方法中 使用)
- throws (主要抛出异常,一般在 方法上 使用)
package com.byxx.yunan.test.exception; /** * @Author yww * @CreateTime 2021-02-05 */ public class Test1 { public static void main(String[] args) { int a = 1; int b = 0; //假设要捕获多个异常:从小到大 try{//监控区域 new Test1().test(1,0); }catch (Exception e){ //catch(想要捕获的异常类型!) 捕获异常 System.out.println("Exception"); }catch (Throwable t){ System.out.println("Throwable"); }finally { System.out.println("finally"); } //finally 可以不要, 假设IO,资源操作时,则需要finally 用于关闭资源 } //假设这方法中,处理不了这个异常。 方法上 抛出异常 ,使用 throws public void test(int a,int b) throws ArithmeticException{ if(b == 0){//throw throw new ArithmeticException();//主动抛出的异常,一般在 方法中 使用 } } }
自定义异常
自定义异常package com.byxx.yunan.test.exception; /** * 自定义的异常类 * @Author yww * @CreateTime 2021-02-05 */ public class MyException extends Exception{ //传递数字 > 10 private int detail; public MyException(int a){ this.detail = a; } //toString: 异常的打印信息 @Override public String toString() { return "MyException{ detail=" + detail +"} "; } }
自定义异常使用package com.byxx.yunan.test.exception; /** * @Author yww * @CreateTime 2021-02-05 */ public class ExceptionMain { public static void main(String[] args) throws MyException { //调用getNumber方法 new ExceptionMain().getNumber(11); } public int getNumber(int num) throws MyException { if(num>10){//传递值 > 10 抛出自定义异常 throw new MyException(num); } return num; } }
System类
- public static long currentTimeMillis(); 返回以毫秒为单位的当前时间
- public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); 将数组中指定的数据拷贝到另一个数组中
package com.byxx.yunan.test.string;
import java.util.Arrays;
/**
* @Author yww
* @CreateTime 2021-02-10
*/
public class Test1 {
public static void main(String[] args) {
/*
System.currentTimeMillis(); 计算循环1000次后所需要的执行时间 (毫秒为单位)
*/
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
long endTime = System.currentTimeMillis();
System.out.println("程序共用时: "+(endTime - startTime)+"毫秒");
/*
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
将数组中指定的数据拷贝到另一个数组中
参数:
src - 源数组
srcPos - 源数组中的起始位置
dest - 目标数组
destPos - 目标数据中的起始位置
length - 要复制的数组元素的数量
*/
int[] arrays1 = {1,2,3,4,5,6};
int[] arrays2 = {7,8,9,1,2,3};
System.arraycopy(arrays1,0,arrays2,0,3);
System.out.println(Arrays.toString(arrays1));//输出: [1,2,3,4,5,6]
System.out.println(Arrays.toString(arrays2));//输出: [1,2,3,1,2,3]
}
}
StringBuilder
String 类
字符串是常量:它们的值在创建之后不能更改
字符串的底层是一个被final修饰的数组,不能改变,是一个常量
private final byte[] value;
由于String类的对象内容不可改变,所以每当进行字符串拼接时,总是会在内存中创建一个新的对象。列如:
package com.byxx.yunan.test.string;
/**
* @Author yww
* @CreateTime 2021-02-10
*/
public class Test2 {
public static void main(String[] args) {
String str = "a"+"b"+"c";
// "a", "b", "c" 3个字符串
// "a" + "b" "ab" 一个字符串
// "ab" + "c" 一个字符串
}
}
StringBuilder类
字符串缓冲区,可以提高字符串的操作效率 (看成一个长度可以变化的字符串) 底层也是一个数组,但没有被final修饰,可以改变长度。
byte[] value = new byte[16];
“a” + “b” + “c” = “abc”;
StringBuilder 在内存中始终是一个数组,占用空间少,效率高,如果超出了StringBuilder的容量,会自动的扩容。
package com.byxx.yunan.test.string;
/**
* @Author yww
* @CreateTime 2021-02-10
*/
public class Test3 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
StringBuilder sb2 = sb.append("a");
System.out.println(sb == sb2);// == 比较的内存地址(两个对象是同一个对象) 所以 sb == sb2 输出结果为true
//StringBuilder 链式写法
sb.append(1).append("2").append('3').append(4.0);
System.out.println(sb); // a1234.0
//reverse(); 反转
sb.reverse();
System.out.println(sb);// 0.4321a
}
}
循环
for 循环
//for i
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
增强 for 循环
//增强for
for (String s : list) {
System.out.println(s);
}
Iterator 迭代器
- boolean hasNext(); 如果仍有元素可以迭代,则返回true,判断集合中还有没有下一个元素,有就返回true,没有就返回false
- E next(); 返回迭代的下一个元素
迭代器的使用步骤
- 使用集合的方法iterator() 获取迭代器的实现类对象,使用Iterator接口接收(多态)
- 使用Iterator接口中的方法hasNext判断还有没有下一个元素
- 使用Iterator接口中的方法next取出集合中的下一个元素
package com.byxx.yunan.test.string; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; /** * @Author yww * @CreateTime 2021-02-12 */ public class Test4 { public static void main(String[] args) { Collection<String> lists = new ArrayList<>(); lists.add("张三"); lists.add("李四"); lists.add("王五"); lists.add("刘六"); lists.add("陈七"); //使用iterator迭代器 迭代 Iterator<String> iterator = lists.iterator(); //hasNext()判断还有没有下一个元素 while(iterator.hasNext()){ //iterator.next() 取出集合中的下一个元素 System.out.println(iterator.next()); } } }
集合
Collection顶级集合接口
- boolean add (E e); 向集合中添加元素
- boolean remove (E e); 删除集合中的某个元素
- void clear (); 清空集合中所有的元素
- boolean contains (E e); 判断集合中是否包含某个元素
- boolean isEmpty (); 判断集合是否为空
- int size (); 获取集合的长度
- Object[] toArray (); 将集合转成一个数组
List
- List接口特点:
- 有序的集合,存储元素和取出元素的顺序是一致的(存储123,取出123)
- 有索引,包含了一些带索引的方法
- 允许存储重复的元素
- List接口中带索引的方法(特有)
- public void add(int index,E element); 将指定的元素,添加到该集合的指定位置上
- public E get(int index); 返回集合中指定位置的元素
- public E remove(int index); 移出列表中指定位置的元素,返回的是被移出的元素
- public E set(int index,E element); 用指定元素替换集合中指定位置的元素,返回值返回更新前的元素
package com.byxx.yunan.test.arrays;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* List接口特点:
* 1. 有序的集合,存储元素和取出元素的顺序是一致的(存储123,取出123)
* 2. 有索引,包含了一些带索引的方法
* 3. 允许存储重复的元素
* List接口中带索引的方法(特有)
* - public void add(int index,E element); 将指定的元素,添加到该集合的指定位置上
* - public E get(int index); 返回集合中指定位置的元素
* - public E remove(int index); 移出列表中指定位置的元素,返回的是被移出的元素
* - public E set(int index,E element); 用指定元素替换集合中指定位置的元素,返回值返回更新前的元素
*/
public class Test9 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
//使用add方法往集合中添加元素
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
//打印list,没有输出内存地址,代表了内部重写了toString()方法
System.out.println(list);//[a,b,c,d,a]
//public void add(int index,E element); 将指定的元素,添加到该集合的指定位置上
list.add(2,"DDDDD");
System.out.println(list);//[a, b, DDDDD, c, d, a]
//public E remove(int index); 移出列表中指定位置的元素,返回的是被移出的元素
String removeStr = list.remove(2);
System.out.println(removeStr);//DDDDD
//public E set(int index,E element); 用指定元素替换集合中指定位置的元素,返回值返回更新前的元素
list.set(0,"A");
System.out.println(list);//[A,b,c,d,a]
//public E get(int index); 返回集合中指定位置的元素
//for i
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//增强for
for (String s : list) {
System.out.println(s);
}
//iterator迭代器
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
}
}
}
ArrayList
ArrayList集合数据存储的结构是数组结构,元素增删慢,查找快,线程不安全,由于日常开发中使用最多的功能为查询数据,遍历数据,所以ArrayList是最常用的集合。
LinkedList
LinkedList集合数据存储的结构是双向链表,元素增删快,查找快,线程不安全。
package com.byxx.yunan.test.arrays;
import java.util.LinkedList;
/**
* java.util.LinkedList集合 implements List接口
* LinkedList集合的特点:
* 1.底层是一个链表结构:查询慢,增删快
* 2.里面包含了大量操作首尾元素的方法
* 注意:使用LinkedList集合特有的方法,不能使用多态
*
* - public void addFirst(E e); 将指定元素插入此列表的开头
* - public void addLast(E e); 将指定元素添加到此列表的结尾
* - public void push(E e); 将元素推入此列表所表示的堆栈 push()方法等同于addFirst()方法
*
* - public E getFirst(); 返回此列表的第一个元素
* - public E getLast(); 返回此列表的最后一个元素
*
* - public E removeFirst(); 移出并返回此列表的第一个元素
* - public E removeLast(); 移出并返回此列表的最后一个元素
* - public E pop(); 从此列表所表示的堆栈处弹出一个元素 pop()方法等同于removeFirst()方法
*
* - public boolean isEmpty(); 如果列表不包含元素,则返回true
*/
public class Test10 {
public static void main(String[] args) {
LinkedList<String> linked = new LinkedList<>();
linked.add("aaa");
linked.add("bbb");
/*
- public void addFirst(E e); 将指定元素插入此列表的开头
- public void addLast(E e); 将指定元素添加到此列表的结尾
- public void push(E e); 将元素推入此列表所表示的堆栈 push()方法等同于addFirst()方法
*/
linked.addFirst("www");
linked.addLast("com");
linked.push("YYYYYY");
System.out.println(linked);//[YYYYYY, www, aaa, bbb, com]
/*
- public E getFirst(); 返回此列表的第一个元素
- public E getLast(); 返回此列表的最后一个元素
*/
String first = linked.getFirst();
String last = linked.getLast();
System.out.println("第一个元素:"+first+" 最后一个元素:"+last);
System.out.println(linked);
/*
- public E removeFirst(); 移出并返回此列表的第一个元素
- public E removeLast(); 移出并返回此列表的最后一个元素
- public E pop(); 从此列表所表示的堆栈处弹出一个元素 等同于removeFirst()方法
*/
String pop = linked.pop();
linked.clear();//清空集合中的元素 在获取集合中的元素会抛出NoSuchElementException
}
}
Set
Set接口和List接口一样,同样继承Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格了。与List接口不同的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
Set集合中有多个子类,比如:HashSet,TreeSet这两个集合。
Set集合取出元素的方式可以采用:迭代器,增强for
HashSet
HashSet是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。HashSet底层实现其实是一个HashMap支持。
HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCode和equals方法。
package com.byxx.yunan.test.arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Set接口 extends Collection接口
* Set接口的特点:
* 1.不允许存储重复的元素
* 2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历
* HashSet特点:
* 1.不允许存储重复的元素
* 2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历
* 3.是一个无序的集合,存储元素和取出元素的顺序有可能不一致
* 4.底层是一个哈希表结构(查询速度非常的快)
*/
public class Test11 {
public static void main(String[] args) {
Set<Integer> hashSet = new HashSet<>();
hashSet.add(1);
hashSet.add(3);
hashSet.add(2);
hashSet.add(1);
//迭代器 循环
Iterator<Integer> iterator = hashSet.iterator();
while(iterator.hasNext()){
Integer next = iterator.next();
System.out.println(next);//输出123
}
//增强for 循环
for (Integer iter : hashSet) {
System.out.println(iter);//输出123
}
}
}
哈希值
哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址,是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)。
package com.byxx.yunan.test.collection;
import lombok.ToString;
/**
* 哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址,是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)
* 在Object类由一个方法,可以获取对象的哈希值
* int hashCode(); 返回该对象的哈希码值
* hashCode 源码:
* public native int hashCode():
* native:代表该方法调用的是本地操作系统的方法
*/
public class Test1 {
public static void main(String[] args) {
//User类继承了Object类,所以可以使用Object类的hashCode方法
User u1 = new User();
int code1 = u1.hashCode();
System.out.println(code1);//521645586
User u2 = new User();
int code2 = u2.hashCode();
System.out.println(code2);//1296064247
u2.toString();
/*
toString()方法源码:
return getClass().getName() + "@" + Integer.toHexString(hashCode());
*/
System.out.println(u1);//[email protected]
System.out.println(u2);//[email protected]
System.out.println(u1 == u2);//false
}
}
HashSet集合存储数据的结构 (哈希表)
在jdk1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一个hash值的链表都存储在一个链表里。但是当一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而在jdk1.8中,哈希表存储采用数组+链表+红黑树实现,数组初始长度为16,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找实际。
Set集合存储元素不重复的原理
HashSet存储自定义类型元素
- 存储元素(String,Integer,…Person),必须重写hashCode和equals方法
package com.byxx.yunan.test.collection;
import java.util.HashSet;
import java.util.Objects;
/**
* HashSet存储自定义类型元素
*
* set集合保存元素唯一
* 存储的元素(String,Integer,...Person),必须重写hashCode方法和equals方法
*
* 要求:
* 同名同年龄的人,视为同一个人,只能存储一次
*/
public class Test3 {
public static void main(String[] args) {
Person p1 = new Person("张三",18);
Person p2 = new Person("张三", 18);
Person P3 = new Person("张三", 19);
HashSet<Person> set = new HashSet<>();
set.add(p1);
set.add(p2);
set.add(P3);
//存储类型没有重写hashCode和equals方法时
System.out.println(p1==p2);//对比内存地址: false
System.out.println(p1.equals(p2));//对比值: false
System.out.println(set);//[Person{name='张三', age=18}, Person{name='张三', age=19}, Person{name='张三', age=18}]
//对象重写hashCode和equals方法后(完成需求,同名同年龄人,只能存储一次)
System.out.println(p1==p2);//对比内存地址: false
System.out.println(p1.equals(p2));//对比值: true
System.out.println(set);//[Person{name='张三', age=18}, Person{name='张三', age=19}]
}
}
//person类
class Person{
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name) &&
Objects.equals(age, person.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
LinkedHashSet
- LinkedHashSet集合 extends HashSet集合
- 底层是一个哈希表 + 链表 (记录元素的存储顺序),保证元素有序
package com.byxx.yunan.test.collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
/**
* @Author yww
* @CreateTime 2021-02-21
*/
public class Test4 {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<>();
hashSet.add("www");
hashSet.add("ccc");
hashSet.add("bbb");
System.out.println(hashSet);//[ccc, bbb, www]
/*
LinkedHashSet集合 extend HashSet集合
特点:
底层是一个哈希表 + 双向链表 (多了一条链表是为了 记录元素的存储顺序),保证存储元素有序
*/
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("www");
linkedHashSet.add("ccc");
linkedHashSet.add("bbb");
System.out.println(linkedHashSet);//[www, ccc, bbb]
}
}
Collections工具类
- Collections 是集合工具类,用来对集合进行操作,部分方法如下:
- public static boolean addAll(Collection c,T… elements); 往集合中添加一些元素
- public static void shuffle(List<?> list); 打乱集合顺序
- public static void sort(List list); 将集合中元素按照默认规则排序
- public static void sort(List list,Comparator<? super T> ); 将集合中元素按照指定规则排序,被排序的集合里存储的元素,重写Comparator接口中的方法compare定义排序的规则
package com.byxx.yunan.test.collection;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/**
* @Author yww
* @CreateTime 2021-02-22
*/
public class Test5 {
public static void main(String[] args) {
/*
Collections工具类:
public static <T> boolean addAll(Collection<T> c,T... elements); 往集合中添加一些元素
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"1","2","3","4","5");
System.out.println(list);//[1, 2, 3, 4, 5]
//public static void shuffle(List<?> list);打乱集合顺序,每次顺序都不一致
Collections.shuffle(list);
System.out.println(list);//[2, 3, 4, 5, 1]
//public static <T> void sort(List<T> list); 将集合中元素按照默认规则排序
Collections.sort(list);
System.out.println(list);//[1, 2, 3, 4, 5]
/*
按年龄大小排序
sort(List<T> list)使用前提
被排序的集合里存储的元素,必须实现Comparable,重写接口中的compareTo定义排序的规则
*/
ArrayList<Role> roleList = new ArrayList<>();
roleList.add(new Role("张三",17));
roleList.add(new Role("李四",19));
roleList.add(new Role("王五",20));
/*
public static <T> void sort(List<T> list,Comparator<? super T> );
将集合中元素按照指定规则排序,被排序的集合里存储的元素,重写Comparator接口中的方法compare定义排序的规则
*/
//升序 o1.getAge().compareTo(o2.getAge())
Collections.sort(roleList, new Comparator<Role>() {
@Override
public int compare(Role o1, Role o2) {
return o1.getAge().compareTo(o2.getAge());
}
});
System.out.println(roleList);//[Role{name='张三', age=17}, Role{name='李四', age=19}, Role{name='王五', age=20}]
//降序 o2.getAge().compareTo(o1.getAge())
Collections.sort(roleList, new Comparator<Role>() {
@Override
public int compare(Role o1, Role o2) {
return o2.getAge().compareTo(o1.getAge());
}
});
System.out.println(roleList);//[Role{name='王五', age=20}, Role{name='李四', age=19}, Role{name='张三', age=17}]
}
}
//角色类
class Role{
private String name;
private Integer age;
public Role() {
}
public Role(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Role{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
Map
- Map集合的特点:
- Map集合是一个双列集合,一个元素包含两个值 (一个key,一个value)
- Map集合中的元素,key和value的数据类型可以相同,也可以不同
- Map集合中的元素,key是不允许重复的,value是可以重复的 (如果出现key重复,后put重复的value值会替换之前put的value)
- Map集合中的元素,key和value是一 一对应的
- Map接口常用方法
- public V put(K key,V value); 把指定的键与指定的值添加到Map集合中
- public V remove(Object key); 把指定的键所对应的键值对元素在Map集合中删除,返回被删除元素的值
- public V get(Object key); 根据指定的键,在Map集合中获取对应的值
- boolean containsKey(Object key); 判断集合中是否包含指定的键
- public Set keySet(); 获取Map集合中所有的键,存储到Set集合中
- public Set<Map.Entry<K,V>> entrySet(); 获取到Map集合中所有的键值对对象的集合(Set集合)
package com.byxx.yunan.test.collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @Author yww
* @CreateTime 2021-02-24
*/
public class Test6 {
public static void main(String[] args) {
HashMap<String, Object> map = new HashMap<>();
//public V put(K key,V value) 添加元素到集合
map.put("name", "张三");
map.put("sex", "男");
map.put("age", 20);
System.out.println(map);//{sex=男, name=张三, age=20}
//public V remove(Object key) 删除集合中指定的key
map.remove("age");
System.out.println(map);//{sex=男, name=张三}
//public V get(Object key) 根据指定的值,获取对应的值
Object name = map.get("name");
System.out.println(name);//张三
//public Set<K> keySet() 获取Map集合中所有的键,存储到Set集合中
Set<String> keySet = map.keySet();
//for增强
for (String key : keySet) {
Object value = map.get(key);
System.out.print(value);//男 张三
}
//迭代器
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
Object value = map.get(key);
System.out.print(value);//男 张三
}
//public Set<Map.Entry<K,V>> entrySet(); 获取map集合中的 键值对 对象
Set<Map.Entry<String, Object>> entrySet = map.entrySet();
//for增强
for (Map.Entry<String, Object> entry : entrySet) {
String key = entry.getKey();
Object value = entry.getValue();
/*
key:sex value:男
key:name value:张三
*/
System.out.println("key:" + key + " value:" + value);
}
//迭代器
Iterator<Map.Entry<String, Object>> entryIterator = map.entrySet().iterator();
while (entryIterator.hasNext()) {
Map.Entry<String, Object> entryMap = entryIterator.next();
String key = entryMap.getKey();
Object value = entryMap.getValue();
/*
key:sex value:男
key:name value:张三
*/
System.out.println("key:" + key + " value:" + value);
}
}
}
HashMap
- HashMap集合 implements Map接口
- HashMap集合特点:
-
HashMap集合底层是哈希表,查询效率快
JDK1.8之前:数组 + 链表
JDK1.8之后:数组 + 链表 + 红黑树
- HashMap集合是一个无序的集合,存储元素和取出元素的顺序有可能不一致
-
- HashMap存储自定义类型键值
- Map集合保证key是唯一的
- 作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一
package com.byxx.yunan.test.collection;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.aspectj.weaver.ast.Or;
import java.util.HashMap;
import java.util.Objects;
/**
* HashMap集合 implements Map接口
*/
public class Test7 {
public static void main(String[] args) {
/*
hashMap存储自定义类型
Map集合保证key是唯一的:
作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一
*/
HashMap<Organ, Object> hashMap = new HashMap<>();
//Organ对象没有重写hashCode和equals时,同值对象作为key是不会去重的
hashMap.put(new Organ("张三","19"),20);
hashMap.put(new Organ("李四","20"),31);
hashMap.put(new Organ("张三","19"),23);
System.out.println(hashMap);//{Organ{name='张三', age='19'}=20, Organ{name='张三', age='19'}=23, Organ{name='李四', age='20'}=31}
//Organ对象重写hashCode和equals后,同值对象作为key会去重
HashMap<Organ, Object> organMap = new HashMap<>();
organMap.put(new Organ("张三","19"),20);
organMap.put(new Organ("李四","20"),31);
organMap.put(new Organ("张三","19"),23);
System.out.println(organMap);//{Organ{name='李四', age='20'}=31, Organ{name='张三', age='19'}=23}
}
}
//Organ类
class Organ{
private String name;
private String age;
public Organ() {
}
public Organ(String name, String age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Organ organ = (Organ) o;
return Objects.equals(name, organ.name) &&
Objects.equals(age, organ.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Organ{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
LinkedHashMap
- LinkedHashMap集合 extends HashMap集合
- LikedHashMap集合的特点:
- LinkedHashMap集合底层是哈希表 + 链表 (保证迭代的顺序)
- LinkedHashMap集合是一个有序的集合,存储元素和取出元素的顺序是一致的
package com.byxx.yunan.test.collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
/**
* LinkedHashMap<K,V> extends HashMap<K,V>
* 底层结构:
* 哈希表 + 链表 (记录元素的顺序)
*/
public class Test8 {
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("a","D");
hashMap.put("c","C");
hashMap.put("b","B");
hashMap.put("a","A");
System.out.println(hashMap);// key不允许重写,无序 {a=A, b=B, c=C}
LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("a","D");
linkedHashMap.put("c","C");
linkedHashMap.put("b","B");
linkedHashMap.put("a","A");
System.out.println(linkedHashMap);// key不允许重写,有序 {a=A, c=C, b=B}
}
}
TreeMap
- TreeMap<K,V> extends AbstractMap<K,V>
- TreeMap特点:
- key唯一,按照自然顺序排序
package com.byxx.yunan.test.collection;
import org.apache.commons.collections4.map.LinkedMap;
import java.util.*;
/**
* @Author yww
* @CreateTime 2021-02-24
*/
public class Test9 {
public static void main(String[] args) {
TreeMap<Object, Object> treeMap1 = new TreeMap<>();
//TreeMap按照自然顺序迭代
treeMap1.put(1,"aaa");
treeMap1.put(3,"ccc");
treeMap1.put(2,"bbb");
System.out.println(treeMap1);//{1=aaa, 2=bbb, 3=ccc}
TreeMap<String, Object> treeMap2 = new TreeMap<>();
treeMap2.put("a","AAA");
treeMap2.put("c","CCC");
treeMap2.put("b","BBB");
System.out.println(treeMap2);//{a=AAA, b=BBB, c=CCC}
}
}
HashTable
- HashTable<K,V> 集合 implements Map<K,V> 集合
- HashTable 与 HashMap区别
-
HashTable 底层是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢
HashMap 底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快
-
HashTable 不能存储 null 键 null 值
HashMap(包括其他集合) 可以存储 null 键 null 值
- HashTable 和 vector 集合一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了
package com.byxx.yunan.test.collection; import java.util.HashMap; import java.util.Hashtable; /** * @Author yww * @CreateTime 2021-02-24 */ public class Test10 { public static void main(String[] args) { /* HashT ,able<K,V>集合 implements Map<K,V>集合 HashTable: 底层是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢 HashMap: 底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快 HashTable: 不能存储null键null值 HashMap(包过其他集合): 可以存储null键null值 HashTable和vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了 */ HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put(null,"A"); hashMap.put("B",null); hashMap.put(null,null); System.out.println(hashMap);//{null=null, B=null} Hashtable<String, Object> hashTable = new Hashtable<>(); hashTable.put(null,"A");//报异常: NullPointerException hashTable.put("B",null);//报异常: NullPointerException hashTable.put(null,null);//报异常: NullPointerException } }
-
数据结构
常见的数据结构
数据存储的常用结构有:栈,队列,数组,链表,红黑树。
栈
- 栈 :stack,又称堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加,查找,删除等操作。
简单的来说:采用该结构的集合,对元素的存取有如下的特点
- 先进后出(即,存进去的元素,要在它后面的元素依次取出后,才能取出该元素)。例如,子弹压进弹夹,先压进去的子弹在下面,后压进去的子弹在上面,当开枪时,先弹出上面的子弹,然后才能弹出下面的子弹。
- 栈的入口,出口都是栈的顶端位置。
队列
- 队列:queue,简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。
简单的说,采用该结构的集合,对元素的存取有如下的特点:
- 先进先出(即,存进去的元素,要在它前面的元素依次取出来后,才能取出该元素)。例如,小火车过山洞,车头先进去,车尾后进去;车头先出来,车尾后出来。
数组
- 数组:Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间放元素,就像是一排出租屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到租房子的人。
简单的说,采用该结构的集合,对元素的存取有如下的特点:
- 查找元素快:通过索引,可以快速访问指定位置的元素。
- 增删元素慢
- 指定索引位置增加元素,需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。
链表
- 链表:linked list,由一系列节点node(链表中每一个元素称为节点)组成,节点可以在运行时动态生成。每个节点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域,链表结构有单向链表与双向链表
File
概述
File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建,查找和删除等操作。
File类中静态成员变量
- static String pathSeparator 与系统有关的路径分隔符 //windows: 分号; linux: 冒号:
- static char pathSeparatorChar 与系统有关的路径分隔符
- static String separator 与系统有关的默认名称分割符 //windows: 反斜杆\ linux: 正斜杆/
- static String separatorChar 与系统有关的默认名称分隔符
package com.byxx.yunan.test.io;
import java.io.File;
/**
* @Author yww
* @CreateTime 2021-02-24
*/
public class Test1 {
public static void main(String[] args) {
/*
路径分隔符pathSeparator 与 pathSeparatorChar 一致,内部就是将Char变成了字符串
public static final String pathSeparator = "" + pathSeparatorChar;
*/
String pathSeparator = File.pathSeparator;
System.out.println(pathSeparator);//windows: 分号; linux:冒号:
/*
文件名称分隔符separator 与 separatorChar 一致,内部就是将Char变成了字符串
public static final String separator = "" + separatorChar;
*/
String separator = File.separator;
System.out.println(separator);//windows: 反斜杆\ linux: 正斜杆/
}
}
File类构造方法
- File (String pathname) 通过将给定路径名称字符串转换为抽象路径名来创建一个新 File 实例
- File (String parent,String child) 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例
- File (File parent,String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例
package com.byxx.yunan.test.io;
import java.io.File;
/**
* @Author yww
* @CreateTime 2021-02-25
*/
public class Test2 {
public static void main(String[] args) {
/*
File(String pathname)
通过将给定路径名称字符串转换为抽象路径名来创建一个新 File 实例
*/
File file1 = new File("D://a.txt");
System.out.println(file1);//D:\a.txt
/*
File(String parent,String child)
根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例
*/
File file2 = new File("D://","a.txt");
System.out.println(file2);//D:\a.txt
/*
File(File parent,String child)
根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例
*/
File parentFile = new File("E://");
File file3 = new File(parentFile,"a.txt");
System.out.println(file3);//E:\a.txt
}
}
File类常用方法
获取功能的方法
- public String getAbsolutePath() 返回此File的绝对路径名 字符串
- public String getPath() 将此File转换为路径名 字符串
- public String getName() 返回由此File表示的文件或目录的名称
- public long length() 返回由此File表示的文件的长度
package com.byxx.yunan.test.io;
import java.io.File;
/**
* @Author yww
* @CreateTime 2021-02-25
*/
public class Test3 {
public static void main(String[] args) {
getAbsolutePath();
getPath();
getName();
length();
}
/**
* public String getAbsolutePath() 返回此File的绝对路径名 字符串
* 获取的构造方法中的路径无论路径是绝对的还是相对的,getAbsolutePath()方法返回的都是绝对路径
*/
public static void getAbsolutePath(){
File file1 = new File("D:\\log\\a.txt");
String absolutePath1 = file1.getAbsolutePath();
System.out.println(absolutePath1);// D:\log\a.txt
//如果直接填写文件,则按当前项目路径作为参照物 获取绝对路径
File file2 = new File("c.txt");
String absolutePath2 = file2.getAbsolutePath();
System.out.println(absolutePath2);// F:\WorkSpaces\IdeaWork\yunan\c.txt
}
/**
* public String getPath() 将此File转换为路径名 字符串
* 获取的构造方法中传递的路径
*/
public static void getPath(){
File file1 = new File("D:\\log\\a.txt");
String path1 = file1.getPath();
System.out.println(path1);// D:\log\a.txt
File file2 = new File("a.txt");
String path2 = file2.getPath();
System.out.println(path2);// a.txt
}
/**
* public String getName() 获取File结尾的文件名称
*/
public static void getName(){
File file1 = new File("D:\\log");
String name1 = file1.getName();
System.out.println(name1);//log
File file2 = new File("a.txt");
String name2 = file2.getName();
System.out.println(name2);//a.txt
}
/**
* public long length() 返回由此File表示的文件的长度
* 获取的是构造方法指定文件的大小,以字节为单位
* 注意:
* 文件夹或者 给File构造方法中的路径不存在,length 返回0
*/
public static void length(){
File file1 = new File("D:\\log\\a.txt");
long length = file1.length();
System.out.println(length);//858
}
}
判断功能的方法
- public boolean exists() 判断文件是否存在,存在返回 true, 不存在返回 false
- public boolean isDirectory() 判断是否为目录(文件夹),目录(文件夹) 返回 true, 其他返回 false
- public boolean isFile() 判断是否为文件,是文件 返回 true,非文件 返回 false
package com.byxx.yunan.test.io;
import java.io.File;
/**
* @Author yww
* @CreateTime 2021-02-25
*/
public class Test4 {
public static void main(String[] args) {
exists();
isDirectory();
isFile();
}
/**
* public boolean exists() 判断文件是否存在
* 存在返回 true, 不存在返回 false
*/
public static void exists(){
File file1 = new File("D:\\log\\a.txt");
boolean exists1 = file1.exists();
System.out.println(exists1);//true
File file2 = new File("D:\\log");
boolean exists2 = file2.exists();
System.out.println(exists2);//true
}
/**
* public boolean isDirectory() 判断是否为目录(文件夹)
* 目录(文件夹) 返回 true, 其他返回 false
*/
public static void isDirectory(){
File file1 = new File("D:\\log\\a.txt");
boolean directory1 = file1.isDirectory();
System.out.println(directory1);//false
File file2 = new File("D:\\log");
boolean directory2 = file2.isDirectory();
System.out.println(directory2);//true
}
/**
* public boolean isFile() 判断是否为文件
* 是文件 返回 true,非文件 返回 false
*/
public static void isFile(){
File file1 = new File("D:\\log\\a.txt");
boolean directory1 = file1.isFile();
System.out.println(directory1);//true
File file2 = new File("D:\\log");
boolean directory2 = file2.isFile();
System.out.println(directory2);//false
}
}
创建删除功能的方法
- public boolean createNewFile() 创建一个空的新文件,文件不存在,创建文件成功返回 true,文件存在返回 false
- public boolean delete() 删除文件(文件,文件夹都可以),删除成功 返回 true,删除失败 返回 false
- public boolean mkdir() 创建单层文件夹,不可创建多层,创建成功返回 true,文件已存在,创建失败返回 false
- public boolean mkdirs() 创建文件夹,可以创建单层,也可以创建多层文件夹,创建成功返回 true,文件已存在,创建失败返回 false
package com.byxx.yunan.test.io;
import java.io.File;
import java.io.IOException;
/**
* @Author yww
* @CreateTime 2021-02-25
*/
public class Test5 {
public static void main(String[] args) throws IOException {
createNewFile();
delete();
mkdir();
mkdirs();
}
/**
* public boolean createNewFile() 创建一个空的新文件
* 文件不存在,创建文件成功返回 true
* 文件存在返回 false
* @throws IOException
*/
public static void createNewFile() throws IOException {
File file1 = new File("D:\\log\\a.txt");//本地有此文件
boolean newFile1 = file1.createNewFile();
System.out.println(newFile1);//false
File file2 = new File("D:\\log\\ccc.txt");//本地无此文件
boolean newFile2 = file2.createNewFile();
System.out.println(newFile2);//true
}
/**
* public boolean delete() 删除文件(文件,文件夹都可以)
* 删除成功 返回 true
* 删除失败 返回 false
*/
public static void delete(){
File file1 = new File("D:\\log\\ccc.txt");//本地存在
boolean delete1 = file1.delete();
System.out.println(delete1);//true
File file2 = new File("D:\\log\\ccc.txt");//delete()删除后,不存在,返回false
boolean delete2 = file1.delete();
System.out.println(delete2);//false
File file3 = new File("D:\\aaaaa");//文件夹
boolean delete3 = file3.delete();
System.out.println(delete3);//true
}
/**
* public boolean mkdir() 创建单层文件夹,不可创建多层
* 创建成功返回 true
* 文件夹存在,创建失败返回 false
*/
public static void mkdir(){
File file1 = new File("D:\\log\\第一个文件夹");//创建单层
boolean mkdir1 = file1.mkdir();
System.out.println(mkdir1);//true
File file2 = new File("D:\\log\\第一个文件夹");//创建单层
boolean mkdir2 = file2.mkdir();
System.out.println(mkdir2);//false
File file3 = new File("D:\\log\\第一层文件夹\\第二层文件夹");//创建多层
boolean mkdir3 = file3.mkdir();
System.out.println(mkdir3);//false
}
/**
* public boolean mkdirs() 创建文件夹,可以创建单层,也可以创建多层文件夹
* 创建成功返回 true
* 文件夹存在,创建失败返回 false
*/
public static void mkdirs(){
File file1 = new File("D:\\log\\第一层文件夹");//单层文件夹
boolean mkdirs1 = file1.mkdirs();
System.out.println(mkdirs1);//true
File file2 = new File("D:\\log\\第一次文件夹\\第二层文件夹\\第三层文件夹\\第四层文件夹");//多层文件夹
boolean mkdirs2 = file2.mkdirs();
System.out.println(mkdirs2);//true
}
}
目录的遍历
- public String[] list() 返回一个String 数组,获取 File 目录下所有文件及文件夹(不包括子子文件或文件夹),获取为文件或文件夹名称
- public File[] listFiles() 返回一个File数组,获取 File 目录下所有文件及文件夹(不包括子子文件或文件夹),获取为文件对象,可以获取更多信息
package com.byxx.yunan.test.io;
import java.io.File;
/**
* @Author yww
* @CreateTime 2021-02-25
*/
public class Test6 {
public static void main(String[] args) {
list();
listFiles();
}
/**
* public String[] list() 获取目录下所有文件及文件夹(不包括子子文件或文件夹)
* 获取为文件或文件夹名称
*/
public static void list(){
File file = new File("D:\\这是一个目录文件夹");
String[] list = file.list();
for (String name : list) {
/*
输出结果:
子文件1.txt
子文件夹1
子文件夹2
*/
System.out.println(name);
}
}
/**
* public File[] listFiles() 获取目录下所有文件及文件夹(不包括子子文件或文件夹)
* 获取为文件对象,可以获取更多信息
*/
public static void listFiles(){
File file = new File("D:\\这是一个目录文件夹");
File[] files = file.listFiles();
for (File str : files) {
/*
输出结果:
D:\这是一个目录文件夹\子文件1.txt
D:\这是一个目录文件夹\子文件夹1
D:\这是一个目录文件夹\子文件夹2
*/
System.out.println(str);
}
}
}
递归
实例:
package com.byxx.yunan.test.io;
import java.io.File;
/**
* @Author yww
* @CreateTime 2021-02-25
*/
public class Test7 {
public static void main(String[] args) {
File file = new File("D:\\这是一个目录文件夹");
getAllFile(file);
/*
输出结果:
D:\这是一个目录文件夹\子文件1.txt
D:\这是一个目录文件夹\子文件夹1\子子文件夹1-1\子子子文件1-1-1.txt
D:\这是一个目录文件夹\子文件夹1\子子文件夹1-1\子子子文件夹1-1-1
D:\这是一个目录文件夹\子文件夹1\子子文件夹1-1
D:\这是一个目录文件夹\子文件夹1
D:\这是一个目录文件夹\子文件夹2\子子类文件夹2-1
D:\这是一个目录文件夹\子文件夹2
*/
}
/**
* 获取目录下所有文件,递归调用
* @param file
*/
public static void getAllFile(File file){
File[] files = file.listFiles();
for (File fileStr : files) {
if(fileStr.isDirectory()){//如果是文件夹,就递归调用自身
getAllFile(fileStr);
}
System.out.println(fileStr);
}
}
}
IO
字节流
字节输出流 OutputStream
OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写道目的地,它定义了字节输出流的基本共性功能方法
- public void close() 关闭此输出流并释放与此流相关联的任何系统资源
- public void flush() 刷新此输出流并强制任何缓冲的输出字节被写出
- public void write(byte[] b) 将b.length字节从指定的字节数组写入此输出流
- public void write(byte[] b, int off, int len) 从指定的字节数组写入len字节,从偏移量off开始输出到此输出流
- public abstract void write(int b) 将指定的字节输出流
FileOutputStream类
- FileOutputStream extends OutputStream
- FileOutputStream 文件字节输出流 (把内存中的数据写入到硬盘的文件中)
- 构造方法
- FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流
- FileOutputStream(String name, boolean append) 创建一个向具有指定 name 的文件中写入数据的文件输出流,是否开启数据写入追加
- FileOutputStream(File file) 创建一个向指定File对象表示的文件中写入数据的文件输出流
- FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流,是否开启数据写入追加
参数:写入数据的目的
String name :目的地是一个文件的路径
File file :目的地是一个文件
构造方法的作用:
- 创建一个FileOutputStream对象
- 会根据构造方法中传递的文件 / 文件路径,创建一个空的文件
- 会把FileOutputStream对象指向创建好的路径
package com.byxx.yunan.test.io;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @Author yww
* @CreateTime 2021-02-25
*/
public class Test8 {
public static void main(String[] args) throws IOException {
/*
FileOutputStream(String name)
String name: 构造方法中传递写入数据的目的地
*/
//1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
FileOutputStream fos1 = new FileOutputStream("D:\\log\\c.txt");
//2.调用FileOutputStream对象中的方法write,把数据写入到文件中
fos1.write("你好哇,HelloWorld".getBytes());
//3.释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)
fos1.close();
/*
FileOutputStream(String name, boolean append)
String name: 构造方法中传递写入数据的目的地
boolean append: 追加写入开关
true: 创建对象不会覆盖原文件,继续在文件的末尾追加写入数据
false: 创建一个新文件,覆盖原文件
*/
FileOutputStream fos2 = new FileOutputStream("D:\\log\\d.txt",true);//数据写入目的地,开启末尾追加写入数据
for (int i = 0; i < 5; i++) {
String str = "序号"+(i+1);
fos2.write(str.getBytes());//字符转字节数组写入文件中
fos2.write("\r\n".getBytes());// \r\n 换行写入数据
}
fos2.close();
/*
d.txt中写入结果为:
序号1
序号2
序号3
序号4
序号5
*/
}
}
字节输入流 InputStream
InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中,它定义了字节输入流的基本共性功能方法
- public void close() 关闭此输入流并释放与此流相关的任何系统资源
- public abstract int read() 从输入流读取数据的下一个字节
- public int read(byte[] b) 从输入流中读取一些字节数,并将他们存储到字节数组 b 中
FileInputStream类
- FileInputStream extends InputStream
- FileInputStream 文件字节输出流 (从文件中读取字节)
- 构造方法
- FileInputStream(File file) 通过打开与实际文件的连接创建一个FileInputStream,该文件由文件系统中的File对象 file命名
- FileInputStream(String name) 通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名 name 命名
package com.byxx.yunan.test.io; import com.sun.corba.se.spi.presentation.rmi.IDLNameTranslator; import javax.print.DocFlavor; import java.io.FileInputStream; import java.io.IOException; /** * FileInputStream extends InputStream * FileInputStream 文件字节输入流 * 作用: 把硬盘文件中的数据,读取到内存中使用 * * 构造方法: * FileInputStream(String name) * FileInputStream(File file) * 参数:读取文件的数据源 * String name: 文件的路径 * File file: 文件 * 构造方法的作用: * 1.会创建一个FileInputStream对象 * 2.会把FileInputStream对象指定构造方法中要读取的文件 * * 读取数据的原理(硬盘-->内存) * java程序 --> JVM --> OS操作系统 --> OS读取数据的方法 --> 读取文件 * * 字节输入流的使用步骤(重点): * 1.创建FileInputStream对象,构造方法中绑定要读取的数据源 * 2.使用FileInputStream对象中的方法read,读取文件 * 3.释放资源 */ public class Test { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("D:\\log\\d.txt"); /* public abstract int read() 读取文件中的一个字节并返回,读取到文件的末尾返回-1 布尔表达式(len = fis.read()!=-1 1.fis.read() 读取一个字节 2.len = fis.read() 把读取到的字节赋值给变量len 3.(len = fis.read())!=-1 判断变量len是否不等于-1 */ int len = 0; while((len = fis.read())!=-1){ System.out.print((char)len);//abc } fis.close();//关闭流,释放资源 //============================read(byte[] byte)================================= /* public int read(byte b[]) 从输出流中读取一些字节数,并将它们存储到字节数组 b 中 使用byte[]数组作为缓冲区读取 */ FileInputStream fis2 = new FileInputStream("D:\\log\\d.txt"); byte[] bytes = new byte[1024]; int len2 = 0; while((len2 = fis2.read(bytes))!=-1){ //因为byte[]初始化长度为1024,所以会输出很多多余空格 System.out.println(new String(bytes));//abcdefg .... /* public String(byte bytes[], int offset, int length) 将字节数组转String,从哪开始到哪结束 */ System.out.println(new String(bytes,0,len2));//不会输出多余空格 abcdefg } //关闭资源 fis2.close(); } }
复制文件案例
package com.byxx.yunan.test.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @Author yww
* @CreateTime 2021-02-25
*/
public class Test9 {
public static void main(String[] args) throws IOException {
/*
实现文件复制需求:
1.使用输入流FileInputStream读取原文件,转成字节数组
2.使用输出流FileOutputStream读取获取到的字节数组
3.使用输出流FileOutputStream将数据写入磁盘
*/
File file = new File("D:\\log\\abc.jpg");
if(file.exists()){//存在
//输入流,读取文件
FileInputStream fis = new FileInputStream(file.getAbsolutePath());
//输出流,写入文件
FileOutputStream fos = new FileOutputStream("F:\\abc.jpg");
//1.第一种方式,单字节读取
int len = 0;
while((len = fis.read())!=-1){
fos.write(len);//将字节输入流读取出来的数据写入输出流指定的文件中
}
//2.第二种方式,使用byte[]数组作为缓冲区读取 (效率高)
byte[] bytes = new byte[1024];
int len2 = 0;
while ((len2 = fis.read(bytes))!=-1){
//public void write(byte b[], int off, int len) offset 开始索引 count 转换的个数
fos.write(bytes,0,len2);
}
fis.close();//关闭输入流
fos.close();//关闭输出流
}
}
}
字符流
当使用字节流读取文本文件时,可能会有一个小问题,就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储,所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件
字符输入流 Reader
Reader 抽象类是用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法
- public void close() 关闭此流并释放与此流相关联的任何系统资源
- public int read() 从输入流读取一个字符
- public int read(char[] cbuf) 从输入流中读取一些字符,并将它们存储到字符数组cbuf中
FileReader类
- FileReader extends InputStreamReader , InputStreamReader extends Reader
- FileReader 文件字符输入流 (把硬盘文件中的数据以字符的方式读取到内存中)
- 构造方法
- FileReader(String fileName) 创建一个新的FileReader,给定要读取的文件的名称
- FileReader(File file) 创建一个新的FileReader,给定File读取
package com.byxx.yunan.test.io;
import java.io.FileReader;
import java.io.IOException;
/**
* @Author yww
* @CreateTime 2021-02-26
*/
public class Test10 {
public static void main(String[] args) throws IOException {
//字符输入流,将磁盘中的数据读取到内存中
FileReader fr = new FileReader("D:\\log\\d.txt");
/*
第一种读取方式
public int read()
*/
int len1 = 0;
while((len1 = fr.read())!=-1){
System.out.print((char)len1);
}
/*
第二种读取方式,效率高
public int read(char cbuf[])
*/
char[] cbuf = new char[1024];
int len2 = 0;
while((len2 = fr.read(cbuf))!=-1){
//public String(char value[], int offset, int count) offset 开始索引 count 转换的个数
System.out.print(new String(cbuf,0,len2));
}
//关闭资源
fr.close();
}
}
字符输出流 Writer
Writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法
- void write(int c) 写入单个字符
- void write(char[] cbuf) 写入字符数组
- abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,off数组的开始索引,len写的字符个数
- void write(String str) 写入字符串
- void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数
- void flush() 刷新该流的缓冲
- void close() 关闭此流,但要先刷新它。
FileWriter
- FileWriter extends OutputStreamWriter , OutputStreamWriter extends Writer
- FileWriter 文件字符输出流 (将内存中的数据写入磁盘中)
- 构造方法
- FileWriter(File file) 给一个File对象构造一个FileWriter对象
- FileWriter(File file, boolean append) 给一个File对象构造一个FileWriter对象
- FileWriter(String fileName) 构造一个给定文件名的FileWriter对象
- FileWriter(String fileName, boolean append) 构造一个FileWriter对象,给出一个带有布尔值的文件名,表示释放附加写入的数据
package com.byxx.yunan.test.io;
import java.io.FileWriter;
import java.io.IOException;
/**
* @Author yww
* @CreateTime 2021-02-26
*/
public class Test11 {
public static void main(String[] args) throws IOException {
/*
字符输出流
public FileWriter(String fileName, boolean append)
String fileName 文件目的地
boolean append 是否追加写入数据
*/
FileWriter fw = new FileWriter("D:\\log\\e.txt",true);
/*
write()将数据填充到内存缓冲区
*/
//void write(char[] cbuf) 写入字符数组
char[] cs = {'A','B','C','D','E'};
fw.write(cs);//ABCDE
//void write(char[] cbuf, int off, int len) 写入字符数组的一部分,off数组的开始索引,len写的个数
fw.write(cs,2,3);//CDE
fw.write("\r\n");//换行
//void write(String str) 写入字符串
String str = "showme我的time ";
fw.write(str);//showme我的time
//void write(String str, int off, int len) 写入字符串的一部分,off数组的开始索引,len写的个数
fw.write(str,8,4);//time
//刷新缓冲区数据写入到文件中
fw.flush();
//关闭资源
fw.close();
}
}
flush()方法和close()方法的区别
- flush() 刷新缓冲区,流对象可以继续使用
- close() 先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
Properties类
Properties 继承于 HashTable,来表示一个持久的属性集,它使用键值结构存储数据,每个键及其对应值都是一个字符串,该类也被许多java类使用,比如获取系统属性时,getProperties() 方法就是返回一个Properties对象。
- 构造方法
- public Properties() 创建一个空的属性列表
- 基本的存储方法
- public Object setProperty(String key, String value) 保存一对属性
- public String getProperty(String key) 使用此属性列表中指定的键搜索属性值
- public Set stringPropertyNames() 获取所有key存入set集合
- 流相关操作的方法
- public void store(Write write, String comments) 将Properties集合中的数据以字符串输出流的方式写入到文件中
- public synchronized void load(Reader reader) 将文件中的数据以字符串输入流的方法读取到集合中
package com.byxx.yunan.test.io; import javafx.scene.chart.ValueAxis; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Properties; import java.util.Set; /** * Properties集合 extends HashTable集合 * HashTable特性: * 不允许空key,不允许空value * Properties特性: * 1.key和value都是字符串 * 2.不允许空key,不允许空value */ public class Test12 { public static void main(String[] args) { store(); load(); } /** * 使用Properties类中的store(Write write,String comments)方法 * 将集合中的数据存储到文件中 */ public static void store(){ Properties pro = new Properties(); pro.setProperty("张三","18岁"); pro.setProperty("李四","19岁"); pro.setProperty("王五","20岁"); FileWriter fileWriter = null; try { //字符串输出流 fileWriter = new FileWriter("D:\\log\\AAA.txt"); /* properties的store(Write write,String comments) 把集合中的数据,持久化写入硬盘中存储 */ pro.store(fileWriter,"wo shi zhu shi");//Write:字符串输出流 comments:注释 }catch (IOException e){ e.printStackTrace(); }catch (Exception e){ e.printStackTrace(); }finally { try{ fileWriter.close(); }catch (Exception e){ e.printStackTrace(); } } } /** * 使用Properties类中的load(Reader reader)方法 * 将文件中的数据以key,value的形式读取到集合中 * 特点: * 使用#注释的不会读取到集合中 * 使用 = 或者 空格 作为key,value标识 * 示例: * 王五=20岁 或者 王五 20岁 */ public static void load(){ Properties pro = new Properties(); FileReader fileReader = null; try{ /* properties的load(Reader reader)方法 把硬盘中保存的文件(键值对),读到集合中使用 */ fileReader = new FileReader("D:\\log\\AAA.txt"); pro.load(fileReader); //获取properties集合中的数据 Set<String> keys = pro.stringPropertyNames(); for (String key : keys) { String value = pro.getProperty(key); System.out.println("key:"+key+" value:"+value); } }catch (Exception e){ e.printStackTrace(); }finally { try { fileReader.close(); }catch (Exception e){ e.printStackTrace(); } } } }
- store方法将集合中的数据写入文件中效果示例:
缓冲流
缓冲流,也叫高校流,是对4个基本的FIleXxx流的增强,所以也是4个流,按照数据类型分类:
- 字节缓冲流:BufferedInputStream,BufferedOutputStream
- 字符缓冲流:BufferedReader,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率
字节缓冲流
- 构造方法
- public BufferedInputStream(InputStream in) 创建一个新的缓冲字节输入流
- public BufferedOutputStream(OutputStream out) 创建一个新的缓冲字节输出流
package com.byxx.yunan.test.io;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.Buffer;
/**
* @Author yww
* @CreateTime 2021-02-28
*/
public class Test13 {
public static void main(String[] args) throws IOException {
bufferedInputStream();
bufferedOutputStream();
}
/**
* 字节缓冲流输入流BufferedInputStream(InputStream in)
* @throws IOException
*/
public static void bufferedInputStream() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\log\\a.txt"));
//第一种方式,效率低,依次读取文件数据
/*long startTime1 = System.currentTimeMillis();
int len1 = 0;
while((len1 = bis.read())!=-1){
System.out.println(len1);
}
long endTime1 = System.currentTimeMillis();
System.out.print(endTime1-startTime1+"毫秒");*/
System.out.println("==========================缓冲=============================");
//第二种方式,效率高,按数组大小一次性读取文件数据,做缓冲
long startTime2 = System.currentTimeMillis();
byte[] bytes = new byte[1024];
int len2 = 0;
while((len2 = bis.read(bytes))!=-1){
System.out.print(new String(bytes,0,len2));
}
long endTime2 = System.currentTimeMillis();
System.out.print(endTime2-startTime2+"毫秒");
bis.close();
}
/**
* 缓冲字节输出流BufferedOutputStream(OutputStream out)
* @throws IOException
*/
public static void bufferedOutputStream() throws IOException{
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\log\\ABC.txt"));
bos.write("这是缓冲字节输出流".getBytes());
bos.close();
}
}
字符缓冲流
- 构造方法
- public BufferedReader(Reader in) 创建一个新的缓冲字符输入流
- public BufferedWriter(Writer out) 创建一个新的缓冲字符输出流
package com.byxx.yunan.test.io;
import java.io.*;
/**
* @Author yww
* @CreateTime 2021-03-02
*/
public class Test14 {
public static void main(String[] args) throws IOException {
BufferedReader();
BufferedWriter();
}
/**
* 缓冲字符输入流:
* BufferedReader extends Reader
*
* 构造方法:
* BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流
* BufferedReader(Reader in, int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流
*
* 特有方法:
* readLine() 读取一个文本行,如果已到达流末尾,则返回null
*
* @throws IOException
*/
public static void BufferedReader() throws IOException {
//1.创建一个缓冲字符输入流
BufferedReader br = new BufferedReader(new FileReader("D:\\log\\d.txt"));
//2.读取数据
//第一种方式,单个字符读取,效率低
/*int len1 = 0;
while((len1 = br.read())!=-1){
System.out.print((char)len1);
}*/
//第二种方式,创建缓冲数组,效率高
/*char[] chars = new char[1024];
int len2 = 0;
while((len2 = br.read(chars))!=-1){
System.out.println(new String(chars,0,len2));
}*/
//第三种方式,BufferedReader特有方法:readLine(),读取到结尾为null
String len3;
while((len3 = br.readLine())!=null){
System.out.println(len3);
}
//3.关闭资源
br.close();
}
/**
* 缓冲字符输出流:
* BufferedWriter extends Writer
*
* 构造方法:
* BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流
* BufferedWriter(Writer out,int sz) 创建一个使用给定大小输出缓冲区的缓冲字符输出流
*
* 特有方法:
* newLine() 换行符
* @throws IOException
*/
public static void BufferedWriter() throws IOException {
//1.创建缓冲字符输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\log\\f.txt"));
//2.写入数据
for (int i = 0; i < 10; i++) {
bw.write("我是"+i);
bw.newLine();//换行符
}
//3.将缓冲区的数据刷新到文件中
bw.flush();
//4.关闭资源
bw.close();
}
}
对文本内容进行排序
package com.byxx.yunan.test.io;
import com.sun.org.apache.bcel.internal.generic.NEW;
import java.io.*;
import java.util.Set;
import java.util.TreeMap;
/**
* @Author yww
* @CreateTime 2021-03-02
*/
public class Test15 {
public static void main(String[] args) throws IOException {
/**
* 需求:
* 将文件改为正常序号填充到文件中
* 原文件
* 2.我是第二行
* 4.我是第四行
* 1.我是第一行
* 3.我是第三行
*/
//创建缓冲输入流,读取数据
BufferedReader br = new BufferedReader(new FileReader("D:\\log\\f.txt"));
TreeMap<String, String> treeMap = new TreeMap<>();
String len;
while((len = br.readLine())!=null){
String number = len.substring(0, 2);//序号
String content = len.substring(2, len.length());
System.out.println(number+"------"+content);
treeMap.put(number,content);
}
System.out.println(treeMap);
br.close();
/**
* 调整后文件
* 1.我是第一行
* 2.我是第二行
* 3.我是第三行
* 4.我是第四行
*/
//创建缓冲输出流,写入数据
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\log\\g.txt"));
Set<String> keySet = treeMap.keySet();
for (String key : keySet) {
String value = treeMap.get(key);
bw.write(key+value);
bw.newLine();
}
bw.close();
}
}
转换流
输出转换流OutputStreamWriter
- OutputStreamWriter extends Writer
- OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
- 继承自父类的共性成员方法
- void write(int c) 写入单个字符
- void write(char[] cbuf) 写入字符数组
- abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,off数组的开始索引,len写的字符个数
- void write(String str) 写入字符串
- void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数
- void flush() 刷新该流的缓冲
- void close() 关闭此流
- 构造方法
- OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter
- OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的 OutputStreamWriter
- 参数
- OutputStream out : 字节输出流,可以用来写转换之后的字节到文件中
- String charsetName : 指定的编码表名称,不区分大小写,可以是utf-8/gbk…编码,不指定默认使用UTF-8
package com.byxx.yunan.test.io;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
/**
* @Author yww
* @CreateTime 2021-03-03
*/
public class Test16 {
public static void main(String[] args) throws IOException{
OutputStreamWrite();
}
/**
* 转换输出流
* OutputStreamWrite extends Write
* OutputStreamWrite 可以指定输出编码集
*
* 构造方法:
* OutputStreamWrite(OutputStream out) 创建使用默认字符编码的OutputStreamWrite
* OutputStreamWrite(OutputStream out,String charsetName) 创建使用指定字符集OutputStreamWrite
* 参数:
* OutputStream out: 字节输出流,可以用来写转换之后的字节到文件中
* String charsetName: 指定的编码表名称,不区分大小写,可以使用utf-8,gbk...编码,不指定默认使用UTF-8
*/
public static void OutputStreamWrite() throws IOException {
/**
* 不指定,默认使用UTF-8
*/
long startTime1 = System.currentTimeMillis();
//1.创建转换流对象
OutputStreamWriter osw1 = new OutputStreamWriter(new FileOutputStream("D:\\log\\yyyy.txt"));
//2.写入数据
for (int i = 0; i < 100000; i++) {
osw1.write("你好,转换流OutputStreamWriter"+i);
}
//3.将缓冲数据刷新到文件中
osw1.flush();
//4.关闭资源
osw1.close();
long endTime1 = System.currentTimeMillis();
System.out.println("使用缓冲字节输出流作为构造,运行 "+(endTime1-startTime1)+" 毫秒");
/**
* 指定编码集
*/
long startTime2 = System.currentTimeMillis();
//1.创建转换流对象,这次指定编码集
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("D:\\log\\aaaa.txt"),"utf-8");
//2,写入数据
for (int i = 0; i < 100000; i++) {
osw2.write("你好,转换流OutputStreamWriter"+i);
}
//3.将缓冲区数据刷新到文件中
osw2.flush();
//4.关闭资源
osw2.close();
long endTime2 = System.currentTimeMillis();
System.out.println("使用字节输出流作为构造,运行 "+(endTime2-startTime2)+" 毫秒");
}
}
输入转换流InputStreamReader
- InputStreamReader extends Reader
- InputStreamReader 是字符流通向字符流的桥梁,它使用指定的 charset 读取字节并将其解码为字符。
- 继承自父类的共性成员方法
- int read() 读取单个字符并返回
- int read(char[] cbuf) 一次读取多个字符,将字符读入数组
- void close() 关闭该流并释放与之关联的所有资源
- 构造方法
- InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader
- InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader
- 参数
- InputStream in : 字节输入流,用来读取文件中保存的字节
- String charsetName : 指定的编码表名称,不区分大小写,可以是utf-8/gbk…编码,不指定默认使用UTF-8
- 注意事项
- 构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码
package com.byxx.yunan.test.io;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @Author yww
* @CreateTime 2021-03-03
*/
public class Test17 {
public static void main(String[] args) throws IOException{
InputStreamReader();
}
/**
* InputStreamReader extends Reader
* InputStreamReader 是字节流通向字符流的桥梁,它使用指定的 charset 读取字节并将其解码为字符。
*
* 构造方法:
* InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader
* InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader
* 参数:
* InputStream in: 字节输入流,用来读取文件中保存的字节
* String charsetName: 指定的编码表名称,不区分大小写,可以是utf-8/gbk...编码,不指定默认使用UTF-8
* 注意事项:
* 构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码
*
* @throws IOException
*/
public static void InputStreamReader() throws IOException {
//不指定默认使用UTF-8
//1.创建输入转换流
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("D:\\log\\aaaa.txt"));
//2.读取数据
int len1 = 0;
while((len1 = isr1.read())!=-1){
System.out.print((char)len1);
}
//3.关闭资源
isr1.close();
//指定字符编码集,UTF-8
//1.创建输入转换流
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("D:\\log\\aaaa.txt"),"utf-8");
//2.读取数据
int len2 = 0;
while((len2 = isr2.read())!=-1){
System.out.print((char)len2);
}
//3.关闭资源
isr2.close();
}
}
序列化流
ObjectOutputStream类
ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
- 构造方法
- public ObjectOutputStream(OutputStream out) : 创建一个指定OutputStream的ObjectOutputStream。
ObjectInputStream类
ObjectInputStream 类,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
- 构造方法
- public ObjectInputStream(InputStream in) : 创建一个指定InputStream的ObjectInputStream
package com.byxx.yunan.test.io;
import java.io.*;
/**
* @Author yww
* @CreateTime 2021-03-04
*/
public class Test18 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
/**
* 序列化输出流
* 将对象写入文件中
* ObjectOutputStream extends OutputStream
*/
//1.创建ObjectOutputStream
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\log\\tttt.txt"));
//2.将对象写入到文件中 (如果对象没有序列化,则会报java.io.NotSerializableException异常)
oos.writeObject(new Survey("测试问卷",18));
//3.释放资源
oos.close();
/**
* 序列化输入流
* 将序列化输出流写入文件的数据读取出来
* ObjectInputStream extends InputStream
*/
//1.创建ObjectInputStream
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\log\\tttt.txt"));
//2.读取文件中数据
Object o = ois.readObject();//读取一个对象
Survey survey = (Survey) o;
System.out.println(survey.getName());
//3.关闭资源
ois.close();
}
}
//问卷类
class Survey implements Serializable {
private String name;
private Integer age;
public Survey() {
}
public Survey(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
- transient 瞬态关键字
//使用transient关键字修饰不会被序列号 private transient Integer ages;
打印流
PrintStream类
- 构造方法
- public PrintStream(String fileName) : 使用指定的文件名创建一个新的打印流。
package com.byxx.yunan.test.io;
import java.io.FileNotFoundException;
import java.io.PrintStream;
/**
* 打印流
* java.io.PrintStream extends OutputStream
* PrintStream 为其他输出流添加了功能,使它们能够方便的打印各种数据值表示形式
* PrintStream特点:
* 1.只负责数据的输出,不负责数据的读取
* 2.与其他输出流不同,PrintStream永远不会抛出IOException
* 3.有特有的方法,print,println
* void print(任意类型的值)
* void println(任意类型的值并换行)
* 构造方法:
* PrintStream(File file) 输出的目的地是一个文件
* PrintStream(OutputStream out) 输出的目的地是一个字节输出流
* PrintStream(String fileName) 输出目的地是一个文件路径
* 注意:
* 如果使用继承自父类的write方法写数据,那么查看数据的时候会查询编码表 97->a
* 如果使用自己特有的方法print/println方法写数据,写的数据原样输出 97->97
*/
public class Test19 {
public static void main(String[] args) throws FileNotFoundException {
//1.创建打印流
PrintStream ps = new PrintStream("D:\\log\\BBBB.txt");
//2.使用父类的write()方法写入数据,那么查看数据的时候会查询编码表 97->a
ps.write(97);//打印a
//3.使用自身print/println方法,写的数据原样输出 97->97
ps.println(97);//打印97
ps.println("abc");//打印abc
ps.println("这是打印流");//打印 打印流
//4.关闭资源
ps.close();
/*
打印结果:
a97
abc
这是打印流
*/
}
}