导图社区 04API
这是一篇关于04API的思维导图,04API是关于某些计算机程序的内容,有需要的话可以下载参考一下。
编辑于2022-02-18 08:39:08API
String
String:字符串类型
java.lang.String使用的final修饰,不能被继承
字符串底层封装了字符数组以及针对字符数组的操作算法
Java字符串在内存中采用Unicode编码方式,任何一个字符对应两个字节的编码
字符串一旦创建,对象内容永远无法改变,但字符串引用可以重新赋值
常量池
/* 使用字面量创建字符串时: 1.JVM会检查常量池中是否有该对象: 1)若没有,则创建该字符串对象并存入常量池 2)若有,则直接将该对象返回而不再创建一个新的字符串对象 */ /* String s1 = "123abc"; //常量池还没有,因此创建该字符串对象,并存入常量池 String s2 = "123abc"; //常量池已有了,直接重用对象 String s3 = "123abc"; //常量池已有了,直接重用对象 //引用类型==,比较地址是否相同 System.out.println(s1==s2); //true System.out.println(s1==s3); //true System.out.println(s2==s3); //true */ /* 常见面试题: String s = new String("hello"); 问:创建了几个对象? 答:2个 第一个:字面量"hello" ---java会创建一个String对象表示字面量"hello",并将其存入常量池 第二个:new String() ---new String()时会再创建一个字符串,并引用hello字符串的内容 */ /* String s1 = new String("hello"); //s1装的是new String()对象的地址 String s2 = "hello"; //s2装的是字面量"hello"的地址 System.out.println("s1:"+s1); //hello System.out.println("s2:"+s2); //hello System.out.println(s1==s2); //false,因为s1与s2的地址不同 //字符串实际开发中比较相等的需求都是比较字符串的内容 //因此我们应该使用字符串提供的equals()方法来比较两个字符串的内容 System.out.println(s1.equals(s2)); //true,因为s1与s2的内容相同 */ /* String s1 = "123abc"; String s2 = "123abc"; System.out.println(s1==s2); //true,s1与s2地址相同 s1 = s1+"!"; //创建新对象并把地址赋值给s1 System.out.println(s1==s2); //false,s1为新的对象的地址,与s2不同了 */ //如下代码:常量池中会有3个存储,一个是123abc的地址,一个是123的地址,一个是abc的地址 //一个新的对象,它的值也是123abc String s1 = "123abc"; //编译器在编译时,若发现一个计算表达式可以在编译期间确定结果, //则直接运算好并将结果保存到表达式中 相当于String s2 = "123abc"; String s2 = "123"+"abc"; System.out.println(s1==s2); //true,s1与s2共用常量池中的 String s3 = "123"; //当字符串拼接产生的内容与常量池是某内容相同时,也不会重用常量池的对象 String s4 = s3+"abc"; //创建一个新的对象存储123abc System.out.println(s4==s1); //false
java对字符串有一个优化措施:字符串常量池(堆中)
java推荐我们使用字面量/直接量的方式来创建字符串,并且会缓存所有以字面量形式创建的字符串对象到常量池中,当使用相同字面量再次创建字符串时会重用对象以减少内存开销,避免内存中堆积大量内容相同的字符串对象
String常用方法
length()-查看字符串的长度
String str = "我爱Java!"; int len = str.length(); //获取str的长度 System.out.println(len); //7
charAt() 定位某个位置,返回这个位置的字符
// 0123456789012345 String str = "thinking in java"; char c = str.charAt(9); //获取位置9所对应的字符 System.out.println(c); //i
indexOf(String str):检索给定字符串在当前字符串的开始位置
- ```java // 0123456789012345 String str = "thinking in java"; int index = str.indexOf("in"); //检索in在字符串str中出现的开始位置 System.out.println(index); //2 index = str.indexOf("IN"); //当前字符串不包含给定内容IN,所以返回-1 System.out.println(index); //-1 index = str.indexOf("in",3); //从第4个字符开始找in第一次出现的位置 System.out.println(index); //5 index = str.lastIndexOf("in"); //找in最后一次出现的位置 System.out.println(index); //9 ``` -
lastIndexOf()-某个字符最后一次出现的位置
可以 , 指定位置开始,闭区间 正数第二个要第一个的序号+1开始找 倒数第二个要倒数第一个序号-1开始找
substring()-截取子串,如果参数有两个左闭右开[1,5)
public class SubstringDemo { public static void main(String[] args) { /* // 01234567890 String str = "www.tedu.cn"; String name = str.substring(4,8); //截取第4个到第7个----下标 System.out.println(name); //tedu name = str.substring(4); //从第4个一直截取到字符串末尾----下标 System.out.println(name); //tedu.cn */ String name = getName("www.tedu.com.cn"); System.out.println(name); //tedu String str = getName("http://www.google.com"); System.out.println(str); //google } /** * 获取给定网址中的域名 * @param line 网址 * @return 返回域名 */ public static String getName(String line){ //012345678901234 //www.tedu.com.cn 第一个点到第二个点之间的字符串 int start = line.indexOf(".")+1; //4,加1目的是为了找到点后的第一个字符的位置 int end = line.indexOf(".",start); //8,从start往后找第一个.的位置 return line.substring(start,end); } }
equals()-判断两个串是否相等,注意String重写了Object的此方法,所以内容相同就返回true
startsWith()-判断是不是以参数开头
String str = "thinking in java"; boolean starts = str.startsWith("think"); //判断str是否是以think开头的 System.out.println("starts:"+starts); //true boolean ends = str.endsWith(".png"); //判断str是否是以.png结尾的 System.out.println("ends:"+ends); //false
endsWith()--判断是不是以参数结尾
判断开头可以选从哪里开始,判断结尾只能判断最后一位
split() 以指定字符分割,括号内输入正则,消除输入的正则,将原字符串分割,也可以什么都不输入,即把所有的字符分别存储在字符串数组中
public class Split { public static void main(String[] args) { // 012345678901234 String string = "emotion damage"; String[] sp = string.split(" ");//输入正则,转换为数组 String[] sp1 = string.split("m");//输入正则,转换为数组 String[] sp2 = string.split("");//什么都不输入则切片 for (String a:sp){ System.out.println(a); } for (String a:sp1){ System.out.println(a); } for (String a:sp2){ System.out.println(a); } }
trim()-去掉首尾两端的空格
String str = " hello world "; System.out.println(str); // hello world str = str.trim(); //去除当前字符串两边的空白字符 System.out.println(str); //hello world
getBytes()-把串转换成数组,数据类型为byte
toUpperCase()-变成全大写
String str = "我爱Java!"; String upper = str.toUpperCase(); //将str中英文部分转为全大写 System.out.println(upper); //我爱JAVA! String lower = str.toLowerCase(); //将str中英文部分转为全小写 System.out.println(lower); //我爱java!
toLowerCase()-变成全小写
String.valueOf()-把int类型转换成String类型
int a = 123; String s1 = String.valueOf(a); //将int型变量a转换为String类型并赋值给s1 System.out.println("s1:"+s1); //123 double dou = 123.456; String s2 = String.valueOf(dou); //将double型变量dou转换为String类型并赋值给s2 System.out.println("s2:"+s2); //123.456 String s3 = a + ""; //任何内容与字符串连接结果都是字符串,效率低(下周一才能体会) System.out.println(s3); //123
Java 核心API
StringBuilder
String 类型的连接性能不好,Java提供了StringBuilder解决字符串连接性能问题。
简单理解 StringBuilder性能好!(重点!)
StringBuilder 用于提升String字符串的连接性
StringBuilder称为可变字符串
StringBuilder内部也是字符数组, 其API可以直接修改其内部数组的内容
当数组容量不足时候, 会自动扩容
运算期间会尽力减少创建数组的数量。
StringBuilder API
append() 追加, 在StringBuilder的后面添加字符,当容量满了,会自动扩容, 扩容规则 1倍+2;
insert(位置,字符) 插入字符;
delete(开始位置, 结束位置): 删除一定范围的字符,包括开始,不包括结束
StringBuilder的API返回的大多是当前对象,可以连续使用.调用方法。
toString() 方法可以讲StringBuilder转换为String
正则表达式
用于检测、测试字符串规则的表达式.
经常用于检测字符串是否符合特定的规则,在网站上经常用于检测用户输入数据是否符合规范:
检测 用户名 是否为 8~10 数字 英文(大小写)
检测 电话号码是否符合规则
检测 邮箱地址是否符合规则
等
正则HelloWorld
正则规则 rule = "HelloWorld" 字符串: s1 = "HelloKitty"; 字符串: s2 = "HelloWorld"; // s1 s2 中那个字符串符合 rule 约定的规则? boolean b1 = s1.matches(rule); //false boolean b2 = s2.matches(rule); //true package string; public class RegDemo05 { public static void main(String[] args) { /* * 测试正则表达式 */ //定义正则表达式 String rule = "HelloWorld"; //定义被检测的字符串 String s1 = "HelloKitty"; String s2 = "HelloWorld"; //检测 s1 是否符合规则 boolean b1 = s1.matches(rule); //检测 s2 是否符合规则 boolean b2 = s2.matches(rule); System.out.println(b1); System.out.println(b2); } }
最简单的正则表达式:"HelloWorld" 表示
一共有10个字符
出现的顺序必须是 HelloWorld
Java 提供了正则API, 用于检测一个字符串是否符合,正则规则
boolean matchs(正则) 检测当前字符串是否符合正则规则
字符集
Hello[123456] - 匹配6个字符 - 前5个必须是Hello - 第6个字符,必须 1 2 3 4 5 6 中的一个 如, 可以匹配的字符串: - "Hello1" - "Hello2" - "Hello3" - ... - "Hello6" - "Hello7" 不可以匹配! - “HelloA” 不可以
匹配一个有效字符范围。
语法:[123456] 意义:匹配一个字符 其有效范围: 1 2 3 4 5 6 中的某一个
正则例子: 我[草去艹]
数量词
约定左侧元素出现的次数。
栗子:\w\w\w\w\w\w 等价 \w{6}
语法: X{n} 规定左侧X出现n次 X{n,m} 规定左侧X出现最少n次, 最多m次 X{0,n} 规定左侧X出现0到n次 X{n,} 规定左侧X出现最少n次 X? 和 X{0,1} 等价,X可以没有或者有一个 X+ 和 X{1,} 等价,X至少有一个,多了随意,简称:一个以上 X* 和 X{0,} 等价,X至少有0个,多了随意 简称:0个以上
栗子: - 网站的用户名是 8~16个单词字符: \w{8,16} - 网站的密码是单词字符, 最少8个, 多了不限: \w{8,} - 匹配Hello World,中间至少有一个空白: Hello\s+World - 不能匹配 : "HelloWorld" - 不能匹配: "Hello World!" - 能匹配: "Hello World" - 能匹配: "Hello World" - 能匹配: "Hello World"
java 正则API
matches 检查字符串是否整体符合正则表达式规则
split 劈开
Split 劈开字符串(重要)
将一个字符串劈开为几个子字符串:
"192.168.5.140" 劈开为 "192" "168" "5" "140"
"1, Tom, 110, tom@tedu.cn"" 劈开为 "1" "Tom" "110" "tom@tedu.cn"
replaceAll 全部替换
将正则表达式匹配到的字符,都替换为新字符串
我草疫情又严重了,我去,又要做核算了。 需要替换为 ***疫情又严重了,***,又要做核算了。
Scanner scanner = new Scanner(System.in); System.out.print("请输入:"); String str = scanner.nextLine(); //String str = "我草疫情又严重了,我去,又要做核算了。"; // str.replaceAll("正则", 替换字符串); String s = str.replaceAll("我[去草靠艹]", "***"); System.out.println(s);
二进制
逢2进1的计数规则(重要)
2进制 规则:逢2进1 数字:0 1 权:128 64 32 16 8 4 2 1 基数:2
16进制
16进制用途:16进制用于缩写2进制。
- 2进制书写非常繁琐
- 16进制的基数是2进制的基数4次方, 2进制每4位数可以缩写为1个16进制数。
补码
计算中一种表示有符号数编码,其核心思想就是将固定位数2进制分一般作为负数。
如何将固定位数2进制分一半作为负数?
以4位2进制数讲解如何设计补码
计算时候保持4位不变, 多余位自动溢出
最高位称为符号位,0是正数,1是负数
2进制运算
~ 取反
& 与
逻辑乘法 有0则0
1 7 9 d 5 d 9 e n = 00010111 10011101 01011101 10011110 m = 00000000 00000000 00000000 11111111 8位掩码 k=n&m 00000000 00000000 00000000 10011110 如上运算的意义:k中存储的是n的最后8位数,如上运算叫掩码(mask)运算。m称为mask(掩码), 一般从低位开始1的个数称为掩码的位数。 代码: int n = 0x179d5d9e; int m = 0xff; int k = n & m;
0 & 0 -> 0
0 & 1 -> 0
1 & 0 -> 0
1 & 1 -> 1
| 或运算
逻辑加法, 有1则1
n = 00000000 00000000 00000000 11011101 m = 00000000 00000000 10011101 00000000 k=n|m 00000000 00000000 10011101 11011101 上述计算的意义: 两数错位合并 代码: int n = 0xdd; int m = 0x9d00; int k = n | m; //检查 n m k 的2进制
0 | 0 -> 0
0 | 1 -> 1
1 | 0 -> 1
1 | 1 -> 1
>>> 右移位运算
将2进制数整体向右移动,低位自动溢出舍弃,高位补0
n = 01100111 11010111 10001111 01101101 m=n>>>1 001100111 11010111 10001111 0110110 k=n>>>2 0001100111 11010111 10001111 011011 g=n>>>8 00000000 01100111 11010111 10001111 b3 = (n>>>8) & 0xff; 代码: int n = 0x67d78f6d; int m = n>>>1; int k = n>>>2; int g = n>>>8; int b3 = (n>>>8) & 0xff; //按照2进制输出 n m k g b3
>> 数学右移位运算
向右移若干位,高位补符号位,低位丢弃。 对于正数作右移操作时,具体体现为高位补0;负数则补1。
>>> 和 >> 的区别
栗子, 使用负数比较运算结果: n = 11111111 11111111 11111111 11001100=-1-1-2-16-32=-52 m=n>>1 111111111 11111111 11111111 1100110=-1-1-8-16=-26 k=n>>2 1111111111 11111111 11111111 110011=-1-4-8=-13 g=n>>3 11111111111 11111111 11111111 11001=-1-2-4=-7 n>>>1 011111111 11111111 11111111 1100110=max-25没有数学意义 程序: int n = -52; //0xffffffcc; int m = n>>1; int k = n>>2; int g = n>>3; int x = n>>>1; //输出n m k g x
>>>
逻辑右移位:数字向右移动,低位自动溢出,高位补0, 结果没有数学意义。如果仅仅将数位向右移动,不考虑数学意义,则使用
>>
数学右移位:数学向右移动,低位自动溢出,正数高位补0,负数高位补1, 移动一次数学除以2,小方向取整数。如果是替代数学 /2, 使用数学右移位。
<< 左移位运算
2进制数字整体向左移动,高位自动溢出,低位补0
栗子: n = 00100000 11101111 00110101 10010000 m=n<<1 0100000 11101111 00110101 100100000 k=n<<2 100000 11101111 00110101 1001000000 g=n<<8 11101111 00110101 10010000 00000000 代码: int n = 0x20ef3590; int m = n<<1; int k = n<<2; int g = n<<8; //按照2进制输出 n m k g
移位运算的数学意义
栗子: 16 8 4 2 1 1 0 1 = 5 1 0 1 = 10 向左移动1位 *2 1 0 1 = 20 向左移动2位 *2*2 代码: int n = 5; System.out.println(n<<1); //10 System.out.println(n<<2); //20 System.out.println(n<<3); //40 //...
Object类
Object是所有类的顶级超类,其中有两个经常被子类重写的方法toString()与equals().
toString()
Object已经实现了toString方法. 直接继承下来时返回的字符串内容为当前对象的地址信息. 格式为:类名@地址. toString方法实际开发中很少直接写代码去调用它,都是在不经意间被自动执行的. 例如在使用System.out.println输出时.与字符串连接操作时.
equals()
对于引用类型而言,变量保存的值是对象的地址. ==比较是比较两个变量的值是否相等,因此对于引用类型而言就是比较地址是否相等,那么意思就是比较是否为同一个对象. equals是Object定义的另一个方法,意图是比较两个对象的内容是否相同.但是如果子类不重写这个方法,则没有实际意义,因为Object实现时内部仍然是用==比较的!
包装类
java定义了8个包装类, 目的是为了解决基本类型不能直接参与面向对象开发的问题, 使得基本类型可以通过包装类的实例以对象的形式存在. * 其中数字类型的包装类都继承自java.lang.Number,而char和boolean的包装类直接继承自Object * Number是一个抽象类,定义了一些方法,目的是让包装类可以将其表示的基本类型转换为其他数字类型.
示例
package integer; public class IntegerDemo1 { public static void main(String[] args) { //基本类型转换为包装类 int i = 123; //java推荐我们使用包装类的静态方法valueOf将基本类型转换为包装类,而不是直接new Integer i1 = Integer.valueOf(i);//Integer会重用-128-127之间的整数对象 Integer i2 = Integer.valueOf(i); System.out.println(i1==i2);//true System.out.println(i1.equals(i2));//true double dou = 123.123; Double dou1 = Double.valueOf(dou);//Double则是直接new Double dou2 = Double.valueOf(dou); System.out.println(dou1==dou2);//false System.out.println(dou1.equals(dou2));//true //包装类转换为基本类型 int in = i1.intValue();//获取包装类对象中表示的基本类型值 double doub = i1.doubleValue(); System.out.println(in);//123 System.out.println(doub);//123.0 in = dou1.intValue();//大类型转小类型可能存在丢精度! doub = dou1.doubleValue(); System.out.println(in);//123 System.out.println(doub);//123.123 } }
包装类常用功能
package integer; public class IntegerDemo2 { public static void main(String[] args) { //1可以通过包装类获取其表示的基本类型的取值范围 //获取int的最大值和最小值? int imax = Integer.MAX_VALUE; System.out.println(imax); int imin = Integer.MIN_VALUE; System.out.println(imin); long lmax = Long.MAX_VALUE; System.out.println(lmax); long lmin = Long.MIN_VALUE; System.out.println(lmin); /* 2字符串转换为基本类型的前提是该字符串正确描述了基本类型可以保存的值,否则 会抛出异常:NumberFormatException */ String str = "123"; // String str = "123.123";//这个字符串不能解析为int值! int d = Integer.parseInt(str); System.out.println(d);//123 double dou = Double.parseDouble(str); System.out.println(dou);//123.123 } }
自动拆装箱特性
package integer; public class IntegerDemo3 { public static void main(String[] args) { /* 触发自动拆箱特性,编译器会补充代码将包装类转换为基本类型,下面的代码会变为: int i = new Integer(123).intValue(); */ int i = new Integer(123); /* 触发编译器自动装箱特性,代码会被编译器改为: Integer in = Integer.valueOf(123); */ Integer in = 123; } }
JDK5之后推出了一个新的特性:自动拆装箱
该特性是编译器认可的.当编译器编译源代码时发现有基本类型和引用类型相互赋值使用时会自动补充代码来完成他们的转换工作,这个过程称为自动拆装箱.
File类
File类的每一个实例可以表示硬盘(文件系统)中的一个文件或目录(实际上表示的是一个抽象路径)
使用File可以做到:
public class FileDemo { public static void main(String[] args) { //使用File访问当前项目目录下的demo.txt文件 /* 创建File时要指定路径,而路径通常使用相对路径。 相对路径的好处在于有良好的跨平台性。 "./"是相对路径中使用最多的,表示"当前目录",而当前目录是哪里 取决于程序运行环境而定,在idea中运行java程序时,这里指定的 当前目录就是当前程序所在的项目目录。 */ // File file = new File("c:/xxx/xxx/xx/xxx.txt"); File file = new File("./demo.txt"); //获取名字 String name = file.getName(); System.out.println(name); //获取文件大小(单位是字节) long len = file.length(); System.out.println(len+"字节"); //是否可读可写 boolean cr = file.canRead(); boolean cw = file.canWrite(); System.out.println("是否可读:"+cr); System.out.println("是否可写:"+cw); //是否隐藏 boolean ih = file.isHidden(); System.out.println("是否隐藏:"+ih); } }
1:访问其表示的文件或目录的属性信息,例如:名字,大小,修改时间等等
2:创建和删除文件或目录
3:访问一个目录中的子项
但是File不能访问文件数据.
createNewFile()方法,可以创建一个新文件
package file; import java.io.File; import java.io.IOException; /** * 使用File创建一个新文件 */ public class CreateNewFileDemo { public static void main(String[] args) throws IOException { //在当前目录下新建一个文件:test.txt File file = new File("./test.txt"); //boolean exists()判断当前File表示的位置是否已经实际存在该文件或目录 if(file.exists()){ System.out.println("该文件已存在!"); }else{ file.createNewFile();//将File表示的文件创建出来 System.out.println("文件已创建!"); } } }
delete()方法可以将File表示的文件删除
package file; import java.io.File; /** * 使用File删除一个文件 */ public class DeleteFileDemo { public static void main(String[] args) { //将当前目录下的test.txt文件删除 /* 相对路径中"./"可以忽略不写,默认就是从当前目录开始的。 */ File file = new File("test.txt"); if(file.exists()){ file.delete(); System.out.println("文件已删除!"); }else{ System.out.println("文件不存在!"); } } }
mkDir():创建当前File表示的目录
package file; import java.io.File; /** * 使用File创建目录 */ public class MkDirDemo { public static void main(String[] args) { //在当前目录下新建一个目录:demo // File dir = new File("demo"); File dir = new File("./a/b/c/d/e/f"); if(dir.exists()){ System.out.println("该目录已存在!"); }else{ // dir.mkdir();//创建目录时要求所在的目录必须存在 dir.mkdirs();//创建目录时会将路径上所有不存在的目录一同创建 System.out.println("目录已创建!"); } } }
mkDirs():创建当前File表示的目录,同时将所有不存在的父目录一同创建
delete()方法可以删除一个目录,但是只能删除空目录。
package file; import java.io.File; /** * 删除一个目录 */ public class DeleteDirDemo { public static void main(String[] args) { //将当前目录下的demo目录删除 File dir = new File("demo"); // File dir = new File("a"); if(dir.exists()){ dir.delete();//delete方法删除目录时只能删除空目录 System.out.println("目录已删除!"); }else{ System.out.println("目录不存在!"); } } }
子主题
listFiles方法可以访问一个目录中的所有子项
package file; import java.io.File; /** * 访问一个目录中的所有子项 */ public class ListFilesDemo1 { public static void main(String[] args) { //获取当前目录中的所有子项 File dir = new File("."); /* boolean isFile() 判断当前File表示的是否为一个文件 boolean isDirectory() 判断当前File表示的是否为一个目录 */ if(dir.isDirectory()){ /* File[] listFiles() 将当前目录中的所有子项返回。返回的数组中每个File实例表示其中的一个子项 */ File[] subs = dir.listFiles(); System.out.println("当前目录包含"+subs.length+"个子项"); for(int i=0;i<subs.length;i++){ File sub = subs[i]; System.out.println(sub.getName()); } } } }
获取目录中符合特定条件的子项
package file; import java.io.File; import java.io.FileFilter; /** * 重载的listFiles方法,允许我们传入一个文件过滤器从而可以有条件的获取一个目录 * 中的子项。 */ public class ListFilesDemo2 { public static void main(String[] args) { /* 需求:获取当前目录中所有名字以"."开始的子项 */ File dir = new File("."); if(dir.isDirectory()){ // FileFilter filter = new FileFilter(){//匿名内部类创建过滤器 // public boolean accept(File file) { // String name = file.getName(); // boolean starts = name.startsWith(".");//名字是否以"."开始 // System.out.println("过滤器过滤:"+name+",是否符合要求:"+starts); // return starts; // } // }; // File[] subs = dir.listFiles(filter);//方法内部会调用accept方法 File[] subs = dir.listFiles(new FileFilter(){ public boolean accept(File file) { return file.getName().startsWith("."); } }); System.out.println(subs.length); } } }
重载的listFiles方法:File[] listFiles(FileFilter)
该方法要求传入一个文件过滤器,并仅将满足该过滤器要求的子项返回。
File算法
删除文件
package file; import java.io.File; /** * 编写一个程序,要求实现1+2+3+4+....100并输出结果。 * 代码中不能出现for,while关键字 * * 编写程序计算: * 一个人买汽水,1块钱1瓶汽水。3个瓶盖可以换一瓶汽水,2个空瓶可以换一瓶汽水。不考虑赊账问题 * 问20块钱可以最终得到多少瓶汽水。 * * 删除一个目录 */ public class Test { public static void main(String[] args) { File dir = new File("./a"); delete(dir); } /** * 将给定的File对象表示的文件或目录删除 * @param file */ public static void delete(File file){ if(file.isDirectory()) { //清空目录 File[] subs = file.listFiles(); for (int i = 0; i < subs.length; i++) { File sub = subs[i];//从目录中获取一个子项 //将该子项删除 delete(sub);//递归调用 } } file.delete(); } }
递归
栈内存溢出
判断结束条件
file.delete();
Lamda表达式
package lambda; import java.io.File; import java.io.FileFilter; /** * JDK8之后java支持了lambda表达式这个特性 * lambda表达式可以用更精简的语法创建匿名内部类,但是实现的接口只能有一个抽象 * 方法,否则无法使用。 * lambda表达式是编译器认可的,最终会被改为内部类形式编译到class文件中。 * * 语法: * (参数列表)->{ * 方法体 * } */ public class LambdaDemo { public static void main(String[] args) { //匿名内部类形式创建FileFilter FileFilter filter = new FileFilter() { public boolean accept(File file) { return file.getName().startsWith("."); } }; FileFilter filter2 = (File file)->{ return file.getName().startsWith("."); }; //lambda表达式中参数的类型可以忽略不写 FileFilter filter3 = (file)->{ return file.getName().startsWith("."); }; /* lambda表达式方法体中若只有一句代码,则{}可以省略 如果这句话有return关键字,那么return也要一并省略! */ FileFilter filter4 = (file)->file.getName().startsWith("."); } }
超类接口只有一个方法
简写创建内部类
作用:简化代码
(参数列表)->{ 方法体 }
文件过滤器
FileFilter
FileDemo02.java
file.listFiles();
列出指定目录所有子项
单文件访问(File)
代表磁盘中实际存在的文件和目录
java.io.File类
作用
(文件/文档)的创建/查找/删除
File file = new File("./dog.text");
新建文档
file.createNewFile();
file.isFile();
判断是否是文档
新建目录
file.mkdir();
文件创建.jpg
file.mkdirs();
File file = new File("./a/b");
同时创建多级目录
file.isDirectory()
判断是否是目录
file.delete();
删除文档/目录
简写("test.text");表示路径
FileDemo01.java
方法
String name = file.getName()
文档名字
long length =file.length();
文档长度(字节 )
file.canRead();
是否只读 boolean
file.canWrite();
是否只写 boolean
file.isHidden();
是否隐藏 boolean
file.exists()
是否存在 boolean
IO流
字节流
概念
基本单元
kb
处理数据
二进制
不使用缓冲区
抽象基类
OutputStream
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class OutPutDemo { public static void main(String[] args) throws IOException { /*向文档写入/添加数据*/ FileOutputStream fos = new FileOutputStream("./text.date"); int d = 65; fos.write(d); fos.close(); } }
写入流顶层抽象超类
写入(添加)数据
InputStream
import java.io.FileInputStream; import java.io.IOException; public class InputDemo { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("./text.date"); int d = fis.read(); fis.close(); } }
读取流顶层抽象超类
读取(查看)数据
访问文件
写入流
FileOutputStream
public class FOSDemo { public static void main(String[] args) throws IOException { //向文件test.dat中写入数据 /* 文件字节输出流常用的构造方法: FileOutputStream(String path) FileOutputStream(File file) */ FileOutputStream fos = new FileOutputStream("./test.dat"); // File file = new File("./test.dat"); // FileOutputStream fos = new FileOutputStream(file); /* void write(int d) 写出1个字节,写出的是给定的int值对应的2进制的"低八位" vvvvvvvv 00000000 00000000 00000000 00000001 test.dat中的数据: 00000001 */ fos.write(1); /* vvvvvvvv 00000000 00000000 00000000 00000010 test.dat中的数据: 00000001 00000010 */ fos.write(2); fos.close();//流在使用完毕后要调用close关闭。 } }
字符串
String str = new String(data, StandardCharsets.UTF_8)
byte[] data = line.getBytes(StandardCharsets.UTF_8)
fos.write("八嘎雅鹿".getBytes(StandardCharsets.UTF_8))
fos.write(5);
int类型"低八位"
unicode码只有int类型
FileOutputStream(String path/File file,booolean append)
/** * 文件输出流的追加写模式 */ public class FosDemo2 { public static void main(String[] args) throws IOException { /* 文件流有两种创建模式:覆盖模式和追加模式。 构造器: FileOutputStream(String path) FileOutputStream(File file) 以上两种为覆盖模式的构造器,这种情况下创建文件输出流时如果连接的文件已经存在 则会吧文件之前的数据全部清除。 构造器: FileOutputStream(String path,boolean append) FileOutputStream(File file,boolean append) 如果第二个参数传入true,则文件流为追加模式,此时连接的文件已经存在会保留文件 之前的所有数据。通过当前流每次写入的内容都会陆陆续续追加到文件后面。 */ FileOutputStream fos = new FileOutputStream("fos.txt",true); String line = "你叉叉,穷哈哈~哈利波特骑着扫帚飞,sorry,sorry~"; fos.write(line.getBytes(StandardCharsets.UTF_8)); System.out.println("写出完毕!"); fos.close(); } }
boolean为true,则文件流为追加模式
false
覆盖
连接的文件已经在
删除旧数据
FileOut.png
只删除一次
读取流
FileInputStream
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /** * 使用文件输入流从文件中读取字节 */ public class FISDemo { public static void main(String[] args) throws IOException { //从文件test.dat中读取数据 FileInputStream fis = new FileInputStream("./test.dat"); /* int read() 读取1个字节,并将该字节的2进制保存在返回的int值的"低八位"上。 如果返回的int值为整数"-1"时,则说明读取到了流的末尾。对于读取文件而言相当于是 读取到了文件的末尾:EOF end of file 文件的结尾 结尾 test.dat中的文件数据: 00000001 00000010 ^^^^^^^^ int d = fis.read(); d:00000000 00000000 00000000 00000001 前24位2进制补0 读取的字节 */ int d = fis.read(); System.out.println(d);//1 /* 00000001 00000010 ^^^^^^^^ d = fis.read(); d:00000000 00000000 00000000 00000010 前24位2进制补0 读取的字节 */ d = fis.read();//2 System.out.println(d); /* 00000001 00000010 文件末尾 ^^^^^^^^ d = fis.read(); d:11111111 11111111 11111111 11111111 */ d = fis.read();//-1 System.out.println(d); fis.close(); } }
int d = fis.read();
new FileOutputStream("./test.date")
直接传对象,自动创建文件
java将IO比喻为"流",即:stream. 就像生活中的"电流","水流"一样,它是以同一个方向顺序移动的过程.只不过这里流动的是字节(2进制数据).所以在IO中有输入流和输出流之分,我们理解他们是连接程序与另一端的"管道",用于获取或发送数据到另一端.
File低级流
拷贝
单字节
package io; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * 实现文件复制 */ public class CopyDemo { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("ppt.pptx"); FileOutputStream fos = new FileOutputStream("ppt_cp.pptx"); int d;//记录每次读取到的字节 /* 1.mp4文件数据: 11001100 00110011 11110000 00001111 10101010 01010101 ^^^^^^^^ 1_cp.mp4文件 11001100 00110011 vvvvvvvv d:00000000 00000000 00000000 00110011 */ long start = System.currentTimeMillis(); while( (d = fis.read()) != -1 ){ fos.write(d); } long end = System.currentTimeMillis(); //下面的代码不对,这样会出现奇数位置上的字节读取用于判断,却只将偶数位置的字节写入复制文件 // while( (fis.read()) != -1 ){ // fos.write(fis.read()); // } System.out.println("复制完毕!,耗时:"+(end-start)+"ms"); fis.close(); fos.close(); } }
byte[] data = new byte[fis.available()];
块读写的文件读写操作
package io; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * 提高每次读写的数据量减少实际读写的次数可以提高读写效率 * 一组字节一组字节的读写称为:块读写形式 * 单字节读写是:随机读写形式 * * 使用块读写复制可以显著提高复制效率 */ public class CopyDemo2 { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("ppt.pptx"); FileOutputStream fos = new FileOutputStream("ppt_cp2.pptx"); /* 超类:java.io.InputStream中定义了块读取字节的方法: int read(byte[] data) 一次性读取给定的字节数组总长度的字节量,并存入到该数组中。返回值为实际读取到的 字节量。如果返回值为整数"-1"表示流读取到了末尾 ppt.pptx文件数据: 11001100 00110011 11110000 00001111 10101010 01010101 11000011 byte[] data = new byte[4]; int len; 第一次调用: len = fis.read(data); 从文件中一次性读取4个字节 读取ppt.pptx文件数据: 11001100 00110011 11110000 00001111 10101010 01010101 11000011 ^^^^^^^^ ^^^^^^^^ ^^^^^^^^ ^^^^^^^^ data:[11001100 00110011 11110000 00001111] len:4 表示实际读取到了4个字节 第二次调用: len = fis.read(data); 读取ppt.pptx文件数据: 11001100 00110011 11110000 00001111 10101010 01010101 11000011 ^^^^^^^^ ^^^^^^^^ ^^^^^^^^ 仅能再读取3个字节了 data:[10101010 01010101 11000011 00001111] |-----本次读取到的新数据-----| |旧数据 | len:3 表示实际读取到了3个字节 第三次调用: len = fis.read(data); 读取ppt.pptx文件数据: 11001100 00110011 11110000 00001111 10101010 01010101 11000011 文件末尾 ^^^^^^^^ 已经是文件末尾了,本次一个字节都没有读取到 data:[10101010 01010101 11000011 00001111] |--------------旧数据----------------| len:-1 表示文件末尾了! 字节输出流的超类:java.io.OutputStream定义了块写操作 void write(byte[] data) 一次性将给定字节数组中所有字节写出 void write(byte[] data,int offset,int len) 将给定的字节数组从下标offset处开始的连续len个字节一次性写出 */ /* 0 1 1位2进制称为1bit 00000000 8位2进制称为1byte(1字节) 1024byte 1kb 1024kb 1mb 1024mb 1gb 1024gb 1tb */ byte[] data = new byte[1024*10];//10kb int len; long start = System.currentTimeMillis(); while((len = fis.read(data))!=-1){ // fos.write(data); fos.write(data,0,len); } long end = System.currentTimeMillis(); System.out.println("复制完毕!,耗时:"+(end-start)+"ms"); fis.close(); fos.close(); } }
byte[] data = new byte[4];
len = fis.read(data)
每次读4b
fos.write(data,0,len,UTF-8);
缓存流
BufferedOutputStream
new BufferedOutputStream(fos,true);
开启自动flush
未全部加载完成不会自动写出
已经缓存的数据立即写出
bos.flush();
fush次数越多,效率越差
bos.close();
close包含flush
flush.jpg
传递flush()动作
加快读写效率默认8k
Buff.txt
BufferedInputStream
long start = System.currentTimeMillis()
(d=bis.read())!= -1
Io程序书写流程
1 导包java.io.File
2 操作对象时,处理异常
3 操作对象之后,关闭资源
Io包.png
java流分为两类
节点流:也称为低级流.节点流的另一端是明确的,是实际读写数据的流,读写一定是建立在节点流基础上进行的.
处理流:也称为高级流.处理流不能独立存在,必须连接在其他流上,目的是当数据流经当前流时对数据进行加工处理来简化我们对数据的该操作.
实际应用中,我们可以通过串联一组高级流到某个低级流上以流水线式的加工处理对某设备的数据进行读写,这个过程也成为流的连接,这也是IO的精髓所在.
字符流char
概念
基本单元
Unicode编码
处理数据
文本数据
Unicode码元
存入缓冲区
转换完成后统一存入磁盘
转换成字节序列
装换流(中介)
InputStreamReader
int d = isr.read();
返回int的值本质是Unicode的编码
(char)d
将编码转为字符
OutPutStreamWrite
osw.write("娃哈哈");
缓冲区
字符流-->字节流(按指定字符集)自动转换
new OutputStreamWriter(fos,StandardCharsets.UTF_8);
指定第二个参数,明确字符集
缓存字符流
BufferedReader
line=br.readLine()
PrintWriter
传入String类型参数指定字符集UTF-8
字符错误抛出异常
UnsupportedEncodingException
编码错误
new OutputStreamWriter(fos, StandardCharsets.UTF_8)
包含BufferedWriter
特点
按行写字符串
println
自动行刷新
new PrintWriter(bw,autofushi:true);
缓存字符流内维护一个数组
可以块读写文本数据来进行读写性能的提升
异常处理机制
try{}
try中某句话报错
此句之后的代码都不执行
try语句块不能独立存在
catch(XXXException e){}
catch可以连续多个
catch(XXXException1 | XXXException2 e)
不同的问题,相同的解决方式
输出追踪信息
e.printStackTrace();
获取错误信息
String message = e.getMessage();
catch(Exception e){}
检测异常
finally
最后必须要执行的代码块
释放资源等操
close()调用
虚拟机会实例化空指针异常,并在这里抛出
异常处理
fos.write(5);
catch(IOException e)
finally
fos.close();
catch (IOException e)
e.printStackTrace();
输出追踪的异常
自动关闭特性
简化了io异常处理机制
通过虚拟机自动还原
try(定义并初始化类)
实现AutoCloseable接口
throw/throws异常抛出
自定义异常类
表达业务错误
格式
命名:见名知意
继承Exception
重写异常超类构造器
声明异常
throw new RuntimeException("年龄不合法");
运行异常
通过throws抛出
发现上报异常
使用throws声明该异常的抛出
不属于自身问题
不满足业务要求
age=200;
处理异常
使用try-catch捕获异常
不要在main方法throw抛出异常
异常类继承关系
超类
抛出其中一个异常
public void doSome()throws IOException, AWTException {}
子类
重写throws异常方法
全部抛出
public void doSome()throws IOException, AWTException {}
部分抛出
public void dosome()throws IOException{}
不抛出
public void dosome(){}
(超类异常)抛出等级
允许抛出(超类异常)子类型异常
不允许抛出比(超类异常)更大的异常
不允许抛出异常
超类方法没有声明的异常
与抛出(超类异常)无继承关系
Throwable
所有异常超类
对象流
ObjectOutputStream
序列化
错误
java.io.NotSerializableException
(实现)可序列化接口SeriaLizable
根据类结构自动生成版本号
版本号不同不能反序列化
InvalidClassException
解决:自定义版本号
static final long serialVersionUID = 42L;
作用
签名接口
标识需要序列化的类
oos.writeObject(对象名)
关键字
transient短暂的
对象序列化时,属性值会被忽略
忽略不必要的值,减少内存开销
对象反序列化时,该属性只会采用默认值
定义
将对象-按结构->字节(二进制)
二进制-->硬盘
持久化
ObjectInputStream
反序列化
Object obj = ois.readObject;
返回Object类型
向下转型接收
Persion p = (Persion)ois.readObject();
线程
进程
操作系统中运行的一个任务
线程
单线程
顺序执行
多线程
互不干扰
运行效率问题
继承Thread
方式
重写run方法
实例化线程对象
MyThread1 s0 = new MyThread1();
s0.tart执行
启动线程
优缺点
结构简单,便于创建匿名内部类
继承了该类无法继承其它类
实现接口Runnable
重写run方法
实例化线程对象
Runnable r1 = new MyRunnable(socket服务端);
向下转型
MyRunnable构造器传递socket给分支线程
创建线程
Thread t1 = new Thread(r1);
s0.tart执行
线程优先级
范围1-10
最低1
min.setPriority(Thread.MIN_PRIORITY);
默认5
最高10
max.setPriority(Thread.MAX_PRIORITY);
start方法统一集中管理
被动被分配时间片来并发运行
优先级越高,时间片相对越多
获取线程的方法
Thread main = Thread.currentThread()
获取运行dosome方法的线程
dosome线程.txt
方法
获取线程名称
String name = main.getName();
线程唯一标识
Long id = main.getId();
线程是否活着
boolean isAlive = main.isAlive();
线程是否为守护线程
boolean isDaemon = main.isDaemon();
线程是否被中断
boolean isInterruped = main.isInterrupted();
sleep
Thread.sleep(5000);
睡眠时间
超时后自动回到RUNNING状态
再次运行
程序调用sleep后进入sleep后进入阻塞状态
调用interrupt()
抛出中断异常
InterruptedException
执行时间过长
sleep连接超时
子主题 3
守护线程
用户线程
普通/前台线程
main方法
set.setDemon(true)设置转换守护线程
守护线程
后台线程
GC回收
start执行前被调用
IllegalThreadStateException
普通线程全部结束
守护线程也结束
协调线程同步运行
线程提供了一个join方法,可以协调线程的同步运行。它允许调用该方法的线程等待(阻塞), 直到该方法所属线程执行完毕后结束等待(阻塞)继续运行。 同步运行:多个线程执行存在先后顺序。 异步运行:多个线程各干各的,线程间运行本来就是异步的。
void join()
同步执行
先后顺序
大扫除
download.join(1000)
最多等t时间结束
异步
各干各的
并发安全
多个线程并发操作同一临界资源
package thread; /** * 多线程并发安全问题 * 当多个线程并发操作同一临界资源,由于线程切换的时机不确定,导致操作顺序出现 * 混乱,严重时可能导致系统瘫痪。 * 临界资源:同时只能被单一线程访问操作过程的资源。 */ public class SyncDemo { public static void main(String[] args) { Table table = new Table(); Thread t1 = new Thread(){ public void run(){ while(true){ int bean = table.getBean(); Thread.yield(); System.out.println(getName()+":"+bean); } } }; Thread t2 = new Thread(){ public void run(){ while(true){ int bean = table.getBean(); /* static void yield() 线程提供的这个静态方法作用是让执行该方法的线程 主动放弃本次时间片。 这里使用它的目的是模拟执行到这里CPU没有时间了,发生 线程切换,来看并发安全问题的产生。 */ Thread.yield(); System.out.println(getName()+":"+bean); } } }; t1.start(); t2.start(); } } class Table{ private int beans = 20;//桌子上有20个豆子 /** * 当一个方法使用synchronized修饰后,这个方法称为同步方法,多个线程不能 * 同时执行该方法。 * 将多个线程并发操作临界资源的过程改为同步操作就可以有效的解决多线程并发 * 安全问题。 * 相当于让多个线程从原来的抢着操作改为排队操作。 */ public synchronized int getBean(){ if(beans==0){ throw new RuntimeException("没有豆子了!"); } Thread.yield(); return beans--; } }
由于切换不确定导致操作顺序出现混乱引起逻辑错误
Thread.yield() 方法
当前线程状态 执行->就绪
让出本次cpu分配时间段
等待下一个时间段
顺序排队执行
Synchronized锁
普通方法直接使用synchronized
public synchronized void buy(){}
同步监视不可选,就是当前this
同步块
synchronized(同步监视器对象){ 需要多线程同步执行的代码片段 }
同步(分开)监视对象,该对象可以是任何对象的实例
this调用该方法的对象
shop.buy();
shop1.buy();
同单一方法只能被单一进程执行
同步锁
互斥锁
t1:foo.methodA();
同类
MethodA
t2:foo.methodB();
MethodB
t1调用类任何一个方法,t2不能调用,反之亦然
死锁
线程1
筷子
勺
线程2
勺
筷子
解决
交叉加锁
用完及时释放
静态方法使用synchronized
该方法一定具有同步(分开)效果
b1.dosome
b2.dosome
Boo.dosome
锁:类对象
Class
同步块
synchronized (Boo.class){}
同步块类名.class
网络编程
客户端
封装了TCP通讯协议
与远程计算机建立TCP连接
Socket
new Socket("远端地址信息(IP)",端口(应用程序));
本机IP:localhost 127.0.0.1
ipconfig
端口范围 0-65535
端口范围 0-65535
一般使用2000-6000
6000此前不要使用
8088 8080容器
Connection refused连接拒绝
表示端口未被占用
InputStream in = socket.getInputStream();
服务端
SrverSocket
new ServerSocket(8088);
端口占有抛出异常
Java.net.BindEcception:address already in use
开启8088端口
相当于服务总机指挥
Socket soc = server.accept();
监听服务端口(端口连接是否成功)
阻塞方法,调用后开始等待
成功返回Soc实例
交互
OutputStream out = soc.getOutputStream();
socket.close();
与远程服务器断开连接,tcp挥手
异常断开异常
SocketException: Connection reset
获取远端获取主机地址
socket.getInetAddress().getHostAddress();
集合框架
什么是集合
集合与数组一样,可以保存一组元素,并且提供了操作元素的相关方法,使用更方便.
java.util.Collection接口:
java.util.Collection是所有集合的顶级接口.Collection下面有多种实现类,因此我们有更多的数据结构可供选择.
Collection下面有两个常见的子接口:
package collection; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; /** * 集合的很多操作有与元素的equals方法相关。 */ public class CollectionDemo2 { public static void main(String[] args) { // Collection c = new ArrayList(); Collection c = new HashSet(); c.add(new Point(1,2)); c.add(new Point(3,4)); c.add(new Point(5,6)); c.add(new Point(7,8)); c.add(new Point(1,2)); /* 集合重写了Object的toString方法,输出的格式为: [元素1.toString(), 元素2.toString(), ....] */ System.out.println(c); Point p = new Point(1,2); /* boolean contains(Object o) 判断当前集合是否包含给定元素,这里判断的依据是给定元素是否与集合 现有元素存在equals比较为true的情况。 */ boolean contains = c.contains(p); System.out.println("包含:"+contains); /* remove用来从集合中删除给定元素,删除的也是与集合中equals比较 为true的元素。注意,对于可以存放重复元素的集合而言,只删除一次。 */ c.remove(p); System.out.println(c); } }
java.util.List:线性表.是可重复集合,并且有序.
java.util.Set:不可重复的集合,大部分实现类是无序的.
这里可重复指的是集合中的元素是否可以重复,而判定重复元素的标准是依靠元素自身equals比较的结果.为true就认为是重复元素.
boolean add(E e)
向当前集合中添加一个元素.当元素成功添加后返回true
int size()
返回当前集合的元素个数
boolean isEmpty()
判断当前集合是否为空集(不含有任何元素)
clear()
清空集合
集合与元素equals方法相关的方法
package collection; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; /** * 集合的很多操作有与元素的equals方法相关。 */ public class CollectionDemo2 { public static void main(String[] args) { // Collection c = new ArrayList(); Collection c = new HashSet(); c.add(new Point(1,2)); c.add(new Point(3,4)); c.add(new Point(5,6)); c.add(new Point(7,8)); c.add(new Point(1,2)); /* 集合重写了Object的toString方法,输出的格式为: [元素1.toString(), 元素2.toString(), ....] */ System.out.println(c); Point p = new Point(1,2); /* boolean contains(Object o) 判断当前集合是否包含给定元素,这里判断的依据是给定元素是否与集合 现有元素存在equals比较为true的情况。 */ boolean contains = c.contains(p); System.out.println("包含:"+contains); /* remove用来从集合中删除给定元素,删除的也是与集合中equals比较 为true的元素。注意,对于可以存放重复元素的集合而言,只删除一次。 */ c.remove(p); System.out.println(c); } }
Collection c = new HashSet();
add()
集合重写了Object的toString方法,输出的格式为: [元素1.toString(), 元素2.toString(), ....]
boolean contains(Object o)
判断当前集合是否包含给定元素,这里判断的依据是给定元素是否与集合现有元素存在equals比较为true的情况。
remove()
remove用来从集合中删除给定元素,删除的也是与集合中equals比较为true的元素。 注意,对于可以存放重复元素的集合而言,只删除一次。
集合只能存放引用类型元素,并且存放的是元素的引用(地址)
集合间的操作
package collection; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; /** * 集合间的操作 */ public class CollectionDemo4 { public static void main(String[] args) { // Collection c1 = new ArrayList(); Collection c1 = new HashSet();//不可重复元素 c1.add("java"); c1.add("c"); c1.add("c++"); System.out.println("c1:"+c1); Collection c2 = new ArrayList(); c2.add("android"); c2.add("ios"); c2.add("java"); System.out.println("c2:"+c2); /* boolean addAll(Collection c) 将给定集合中的所有元素添加到当前集合中。当前集合若发生了改变则返回true */ boolean tf = c1.addAll(c2); System.out.println(tf); System.out.println("c1:"+c1); System.out.println("c2:"+c2); Collection c3 = new ArrayList(); c3.add("ios"); c3.add("c++"); c3.add("php"); System.out.println("c3:"+c3); /* boolean containsAll(Collection c) 判断当前集合是否包含给定集合中的所有元素 */ boolean contains = c1.containsAll(c3); System.out.println("包含所有元素:"+contains); /* boolean removeAll(Collection c) 删除当前集合中与给定集合中的共有元素 */ c1.removeAll(c3); System.out.println("c1:"+c1); System.out.println("c3:"+c3); } }
boolean addAll(Collection c)
将给定集合中的所有元素添加到当前集合中。当前集合若发生了改变则返回true
boolean containsAll(Collection c)
判断当前集合是否包含给定集合中的所有元素
boolean removeAll(Collection c)
删除当前集合中与给定集合中的共有元素
集合的遍历
package collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * Collection接口没有定义单独获取某一个元素的操作,因为不通用。 * 但是Collection提供了遍历集合元素的操作。该操作是一个通用操作,无论什么类型的 * 集合都支持此种遍历方式:迭代器模式。 * * Iterator iterator() die(二声) * 该方法会获取一个用于遍历当前集合元素的迭代器 * * java.util.Iterator接口,是迭代器接口,规定了迭代器遍历集合的相关操作,不同的 * 集合都提供了一个用于遍历自身元素的迭代器实现类,不过我们不需要直到它们的名字,以 * 多态的方式当成Iterator使用即可。 * 迭代器遍历集合遵循的步骤为:问->取->删 * 其中删除不是必须操作。 * */ public class IteratorDemo { public static void main(String[] args) { Collection c = new ArrayList(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); System.out.println(c); //获取迭代器 Iterator it = c.iterator(); /* 迭代器提供的相关方法: boolean hasNext() 判断集合是否还有元素可以遍历 E next() 获取集合下一个元素(第一次调用时就是获取第一个元素,以此类推) */ while(it.hasNext()){ String str = (String)it.next(); System.out.println(str); } System.out.println(c); } }
Collection提供了统一的遍历集合方式:迭代器模式
Iterator iterator()
该方法会获取一个用于遍历当前集合元素的迭代器.
java.util.Iterator接口
迭代器接口,定义了迭代器遍历集合的相关操作.
不同的集合都实现了一个用于遍历自身元素的迭代器实现类, 我们无需记住它们的名字,用多态的角度把他们看做为Iterator即可.
迭代器遍历集合遵循的步骤为:问,取,删.其中删除元素不是必要操作
迭代器遍历过程中不得通过集合的方法增删元素
package collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * Collection接口没有定义单独获取某一个元素的操作,因为不通用。 * 但是Collection提供了遍历集合元素的操作。该操作是一个通用操作,无论什么类型的 * 集合都支持此种遍历方式:迭代器模式。 * * Iterator iterator() die(二声) * 该方法会获取一个用于遍历当前集合元素的迭代器 * * java.util.Iterator接口,是迭代器接口,规定了迭代器遍历集合的相关操作,不同的 * 集合都提供了一个用于遍历自身元素的迭代器实现类,不过我们不需要直到它们的名字,以 * 多态的方式当成Iterator使用即可。 * 迭代器遍历集合遵循的步骤为:问->取->删 * 其中删除不是必须操作。 * */ public class IteratorDemo { public static void main(String[] args) { Collection c = new ArrayList(); c.add("one"); c.add("#"); c.add("two"); c.add("#"); c.add("three"); c.add("#"); c.add("four"); c.add("#"); c.add("five"); System.out.println(c); //获取迭代器 Iterator it = c.iterator(); /* 迭代器提供的相关方法: boolean hasNext() 判断集合是否还有元素可以遍历 E next() 获取集合下一个元素(第一次调用时就是获取第一个元素,以此类推) */ while(it.hasNext()){ String str = (String)it.next(); System.out.println(str); if("#".equals(str)){ /* 迭代器要求遍历的过程中不得通过集合的方法增删元素 否则会抛出异常:ConcurrentModificationException */ // c.remove(str); /* 迭代器的remove方法可以将通过next方法获取的元素从集合 中删除。 */ it.remove(); } } System.out.println(c); } }
增强型for循环
JDK5之后推出了一个特性:增强型for循环
for(元素类型 变量名 : 集合或数组){ 循环体 }
也称为新循环,使得我们可以使用相同的语法遍历集合或数组.
package collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * JDK5推出时,推出了一个新的特性:增强型for循环 * 也称为新循环,它可以用相同的语法遍历集合或数组。 * * 新循环是java编译器认可的,并非虚拟机。 */ public class NewForDemo { public static void main(String[] args) { String[] array = {"one","two","three","four","five"}; for(int i=0;i<array.length;i++){ String str = array[i]; System.out.println(str); } for(String str : array){ System.out.println(str); } Collection c = new ArrayList(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); //迭代器遍历 Iterator it = c.iterator(); while(it.hasNext()){ String str = (String)it.next(); System.out.println(str); } //新循环遍历 for(Object o : c){ String str = (String)o; System.out.println(str); } } }
泛型
package collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * JDK5推出时,推出了一个新的特性:增强型for循环 * 也称为新循环,它可以用相同的语法遍历集合或数组。 * * 新循环是java编译器认可的,并非虚拟机。 */ public class NewForDemo { public static void main(String[] args) { String[] array = {"one","two","three","four","five"}; for(int i=0;i<array.length;i++){ String str = array[i]; System.out.println(str); } for(String str : array){ System.out.println(str); } /* * 泛型 JDK5之后推出的另一个特性。 * 泛型也称为参数化类型,允许我们在使用一个类时指定它里面属性的类型, * 方法参数或返回值的类型,使得我们使用一个类时可以更灵活。 * 泛型被广泛应用于集合中,用来指定集合中的元素类型。 * 支持泛型的类在使用时如果未指定泛型,那么默认就是原型Object * * Collection接口的定义 * public interface Collection<E> ... { * * Collection<E> 这里的<E>就是泛型 * * Collection中add方法的定义,参数为E * boolean add(E e) */ Collection<String> c = new ArrayList<>(); c.add("one");//编译器会检查add方法的实参是否为String类型 c.add("two"); c.add("three"); c.add("four"); c.add("five"); // c.add(123);//编译不通过 //迭代器遍历 //迭代器也支持泛型,指定的与其遍历的集合指定的泛型一致即可 Iterator<String> it = c.iterator(); while(it.hasNext()){ //编译器编译代码时会根据迭代器指定的泛型补充造型代码 String str = it.next();//获取元素时无需在造型 System.out.println(str); } //新循环遍历 for(String str : c){ System.out.println(str); } } }
泛型也称为参数化类型,允许我们在使用一个类时指定它当中属性,方法参数或返回值的类型.
泛型在集合中被广泛使用,用来指定集合中的元素类型.
有泛型支持的类在使用时若不指定泛型的具体类型则默认为原型Object
Collection<E> 这里的<E>就是泛型
List集
java.util.List接口,继承自Collection.
List集合是可重复集,并且有序,提供了一套可以通过下标操作元素的方法
常用实现类:
java.util.ArrayList:内部使用数组实现,查询性能更好.
java.util.LinkedList:内部使用链表实现,首尾增删元素性能更好.
List集合常见方法
package collection; import java.util.ArrayList; import java.util.List; /** * List集合 * List是Collection下面常见的一类集合。 * java.util.List接口是所有List的接口,它继承自Collection。 * 常见的实现类: * java.util.ArrayList:内部由数组实现,查询性能更好。 * java.util.LinkedList:内部由链表实现,增删性能更好。 * * List集合的特点是:可以存放重复元素,并且有序。其提供了一套可以通过下标 * 操作元素的方法。 */ public class ListDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); // List<String> list = new LinkedList<>(); list.add("one"); list.add("two"); list.add("three"); list.add("four"); list.add("five"); /* E get(int index) 获取指定下标对应的元素 */ //获取第三个元素 String e = list.get(2); System.out.println(e); for(int i=0;i<list.size();i++){ e = list.get(i); System.out.println(e); } /* E set(int index,E e) 将给定元素设置到指定位置,返回值为该位置原有的元素。 替换元素操作 */ //[one,six,three,four,five] String old = list.set(1,"six"); System.out.println(list); System.out.println("被替换的元素是:"+old); } }
get()
E get(int index) 获取指定下标对应的元素
set(,)
E set(int index,E e) 将给定元素设置到指定位置,返回值为该位置原有的元素。替换元素操作
重载的add()和remove()
package collection; import java.util.ArrayList; import java.util.List; /** * List集合提供了一对重载的add,remove方法 */ public class ListDemo2 { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("one"); list.add("two"); list.add("three"); list.add("four"); list.add("five"); System.out.println(list); /* void add(int index,E e) 将给定元素插入到指定位置 */ //[one,two,six,three,four,five] list.add(2,"six"); System.out.println(list); /* E remove(int index) 删除并返回指定位置上的元素 */ //[one,six,three,four,five] String e = list.remove(1); System.out.println(list); System.out.println("被删除的元素:"+e); } }
void add(int index,E e)
将给定元素插入到指定位置
E remove(int index)
删除并返回指定位置上的元素
subList()
package collection; import java.util.ArrayList; import java.util.List; /** * List subList(int start,int end) * 获取当前集合中指定范围内的子集。两个参数为开始与结束的下标(含头不含尾) */ public class ListDemo3 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); for(int i=0;i<10;i++){ list.add(i); } System.out.println(list); //获取3-7这部分 List<Integer> subList = list.subList(3,8); System.out.println(subList); //将子集每个元素扩大10倍 for(int i=0;i<subList.size();i++){ subList.set(i,subList.get(i) * 10); } //[30,40,50,60,70] System.out.println(subList); /* 对子集元素的操作就是对原集合对应元素的操作 */ System.out.println(list); //删除list集合中的2-8 list.subList(2,9).clear(); System.out.println(list); } }
List subList(int start,int end)
获取当前集合中指定范围内的子集。两个参数为开始与结束的下标(含头不含尾)
对子集元素的操作就是对原集合对应元素的操作
集合与数组的转换
package collection; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * 集合转换为数组 * Collection提供了方法toArray可以将当前集合转换为一个数组 */ public class CollectionToArrayDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("one"); list.add("two"); list.add("three"); list.add("four"); list.add("five"); System.out.println(list); // Object[] array = list.toArray(); /* 重载的toArray方法要求传入一个数组,内部会将集合所有元素存入该数组 后将其返回(前提是该数组长度>=集合的size)。如果给定的数组长度不足, 则方法内部会自行根据给定数组类型创建一个与集合size一致长度的数组并 将集合元素存入后返回。 */ String[] array = list.toArray(new String[list.size()]); System.out.println(array.length); System.out.println(Arrays.toString(array)); } }
Collection提供了一个方法:toArray,可以将当前集合转换为一个数组
重载的toArray方法要求传入一个数组,内部会将集合所有元素存入该数组后将其返回(前提是该数组长度>=集合的size)。如果给定的数组长度不足,则方法内部会自行根据给定数组类型创建一个与集合size一致长度的数组并将集合元素存入后返回。
变长参数
package collection; import java.util.Arrays; public class ArgDemo { public static void main(String[] args) { dosome(1,"a"); dosome(1,"a","b"); dosome(1,"a","b","a","b","a","b","a","b","a","b"); dosome(1,new String[]{"1","2","3"}); } public static void dosome(int i,String... s){ /* 变长参数在方法中实际上就是一个数组.给变长参数传入了几个 实参,该数组长度与实参个数一致. */ System.out.println(s.length); System.out.println("s:"+ Arrays.toString(s)); } }
一个方法中只能声明一个变长参数,并且必须是最后一个参数
变长参数在方法中实际上就是一个数组.给变长参数传入了几个变长参数在方法中实际上就是一个数组.给变长参数传入了几个实参,该数组长度与实参个数一致.
数组转换为List集合
package collection; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * 数组转换为List集合 * 数组的工具类Arrays提供了一个静态方法asList,可以将数组转换为一个List集合。 */ public class ArrayToListDemo { public static void main(String[] args) { String[] array = {"one","two","three","four","five"}; System.out.println(Arrays.toString(array)); List<String> list = Arrays.asList(array); System.out.println(list); list.set(1,"six"); System.out.println(list); //数组跟着改变了。注意:对数组转换的集合进行元素操作就是对原数组对应的操作 System.out.println(Arrays.toString(array)); /* 由于数组是定长的,因此对该集合进行增删元素的操作是不支持的,会抛出 异常:java.lang.UnsupportedOperationException */ // list.add("seven"); /* 若希望对集合进行增删操作,则需要自行创建一个集合,然后将该集合元素 导入。 */ // List<String> list2 = new ArrayList<>(); // list2.addAll(list); /* 所有的集合都支持一个参数为Collection的构造方法,作用是在创建当前 集合的同时包含给定集合中的所有元素 */ List<String> list2 = new ArrayList<>(list); System.out.println("list2:"+list2); list2.add("seven"); System.out.println("list2:"+list2); } }
数组的工具类Arrays提供了一个静态方法asList(),可以将一个数组转换为一个List集合
Arrays.asList(array)
对数组转换的集合进行元素操作就是对原数组对应的操作
由于数组是定长的,因此对该集合进行增删元素的操作是不支持的,对数组增删会抛出异常:java.lang.UnsupportedOperationException
若希望对集合进行增删操作,则需要自行创建一个集合,然后将该集合元素导入。
所有的集合都支持一个参数为Collection的构造方法,作用是在创建当前集合的同时包含给定集合中的所有元素
collections工具类
collections.reverse(list)翻转集合
//[one, six, three, four, five] Collections.reverse(list);//翻转集合 //[five,four,three,six,one] System.out.println(list);
toArray可以将一个集合转换为一个数组
package collection; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; /* 集合转换为数组 Collection定义了方法toArray可以将一个集合转换为一个数组 */ public class CollectionToArrayDemo { public static void main(String[] args) { Collection c = new ArrayList(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); System.out.println(c); //Object[] array = c.toArray(); String[] array =c.toArray(new String[0]); System.out.println(array.length); System.out.println(Arrays.toString(array)); } }
asList,可以将一个数组转换为一个List集合。 //转换后集合的set方法可行,add、remove不行 java.lang.UnsupportedOperationException 不支持的操作异常
package collection; import java.util.Arrays; import java.util.List; /* 数组转换为list集合。 数组的工具类Arrays提供了一个静态方法asList,可以将一个数组转换为一个List集合。 */ public class ArrayToListDemo { public static void main(String[] args) { String[] array = {"one","two","three","four","five"}; System.out.println("Array:"+ Arrays.toString(array)); List list = Arrays.asList(array); System.out.println("List:"+list); //对该集合的操作就是对原数组对应的操作 list.set(1,"six"); System.out.println("list:"+list); System.out.println("Array" +Arrays.toString(array)); } }
需要增删,新建一个集合list2.addAll(list);
/* 如果有增删需求,则需要另外创建一个集合,并现将数组转换的集合内容 导入后方可进行。 */ // List list2 = new ArrayList(); // list2.addAll(list); List list2 = new ArrayList(list); System.out.println("list2:"+list2); list2.add("seven"); System.out.println("list2:"+list2);
Collection.sort(list);集合从小到大排列
package collection; import java.util.*; /* 集合的排序 集合的工具类java.util.Collections提供了一个静态方法sort,可以对List集合进行 自然排序 */ public class SortListDemo { public static void main(String[] args) { List list = new ArrayList(); Random r = new Random(); for (int i = 0; i list.add(r.nextInt()); } System.out.println(list); Collections.sort(list); System.out.println(list); } } /* Collections.sort(List list)在排序List集合时要求集合元素必须实现了 Comparable接口。实现了该接口的类必须重写一个方法compareTo用于定义比较 大小的规则,从而进行元素间的比较后排序。否则编译不通过。 compare:比较 */
排序自定义类型元素
package collection; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * 排序自定义类型元素 */ public class SortListDemo2 { public static void main(String[] args) { List<Point> list = new ArrayList<>(); list.add(new Point(3,5)); list.add(new Point(7,9)); list.add(new Point(1,1)); list.add(new Point(8,3)); list.add(new Point(2,6)); System.out.println(list); /* 编译不通过的原因: Collections.sort(List list)该方法要求集合中的元素类型必须实现接口: Comparable,该接口中有一个抽象方法compareTo,这个方法用来定义元素之间比较 大小的规则.所以只有实现了该接口的元素才能利用这个方法比较出大小进而实现排序 操作. 当我们调用某个API时,它反过来要求我们为其修改其他额外的代码时就是侵入性. 侵入性不利于程序后期的维护,应当在实际开发中尽量避免. */ // Collections.sort(list);//编译不通过 compare比较 comparable可以比较的 /* Collections.sort(List list,Comparator c) 重载的sort方法要求我们再传入一个Comparator"比较器",该比较器用来为集合元素 临时定义一种比较规则,从而将List集合中的元素通过该比较器比较大小后进行排序. Comparator是一个接口,实际应用中我们需要实现该接口为集合元素提供比较规则. */ Comparator<Point> c = new Comparator<Point>() { /** * compare方法用来定义两个参数o1,o2的大小关系 * 返回值用来表示o1与o2的大小关系 * 当返回值>0时,应当表示的含义是o1>o2 * 当返回值<0时,表示o1<o2 * 当返回值=0时,表示o1与o2相等 */ public int compare(Point o1, Point o2) { int olen1 = o1.getX()*o1.getX()+o1.getY()*o1.getY(); int olen2 = o2.getX()*o2.getX()+o2.getY()*o2.getY(); return olen1-olen2; } }; Collections.sort(list,c); System.out.println(list); } }
排序字符串
package collection; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class SortListDemo3 { public static void main(String[] args) { List<String> list = new ArrayList<>(); // list.add("Tom"); // list.add("jackson"); // list.add("rose"); // list.add("jill"); // list.add("ada"); // list.add("hanmeimei"); // list.add("lilei"); // list.add("hongtaoliu"); // list.add("Jerry"); list.add("传奇"); list.add("小泽老师"); list.add("苍老师"); System.out.println(list); //按照字符多少排序 // Collections.sort(list); // Collections.sort(list, new Comparator<String>() { // public int compare(String o1, String o2) { //// return o1.length()-o2.length(); // return o2.length()-o1.length();//反过来减就是降序 // } // }); Collections.sort(list,(o1,o2)->o2.length()-o1.length()); System.out.println(list); } }
java中提供的类,如:String,包装类都实现了Comparable接口,但有时候这些比较规则不能满足我们的排序需求时,同样可以临时提供一种比较规则来进行排序.
Map
方法
包含
boolean c =containsKey(Object key)
map.containsKey("英语");
boolean c =containsValue(Object value)
map.containsValue(97);
大小
int size = map.size();
添加
map.put(“化学”,99)
自动拆箱
指定Key-获取->value
key不存在,返回null
get(Object key)
value=map.get("语文");
删除
value = map.remove("数学");
输入key返回Value
定义
Map<K,V>
Key
键的类型
Value
映的值
Key--->Value(一个Key最多对应一个Value)
嵌套类
Map.Entry<K,V>
映射项(键-值对)
遍历
package map; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Map的遍历 * Map提供了三种遍历方式 * 1:遍历所有的key * 2:遍历每一组键值对 * 3:遍历所有的value(不常用) */ public class MapDemo2 { public static void main(String[] args) { Map<String,Integer> map = new HashMap<>(); map.put("语文",99); map.put("数学",98); map.put("英语",97); map.put("物理",96); map.put("化学",98); System.out.println(map); /* 遍历所有的key Set keySet() 将当前Map中所有的key以一个Set集合形式返回。遍历该集合就等同于 遍历了所有的key */ Set<String> keySet = map.keySet(); for(String key : keySet){ System.out.println("key:"+key); } /* 遍历每一组键值对 Set<Entry> entrySet() 将当前Map中每一组键值对以一个Entry实例形式存入Set集合后返回。 java.util.Map.Entry Entry的每一个实例用于表示Map中的一组键值对,其中有两个常用方法: getKey()和getValue() */ Set<Map.Entry<String,Integer>> entrySet = map.entrySet(); for(Map.Entry<String,Integer> e : entrySet){ String key = e.getKey(); Integer value = e.getValue(); System.out.println(key+":"+value); } /* JDK8之后集合框架支持了使用lambda表达式遍历。因此Map和Collection都 提供了foreach方法,通过lambda表达式遍历元素。 */ map.forEach( (k,v)-> System.out.println(k+":"+v) ); /* 遍历所有的value Collection values() 将当前Map中所有的value以一个集合形式返回 */ Collection<Integer> values = map.values(); // for(Integer i : values){ // System.out.println("value:"+i); // } /* 集合在使用foreach遍历时并不要求过程中不能通过集合的方法增删元素。 而之前的迭代器则有此要求,否则可能在遍历过程中抛出异常。 */ values.forEach( i -> System.out.println("value:"+i) ); } }
单独遍历key
KeySet
Map中所有key以set集合形式返回
Set<String> KeySet = map.keySet();
遍历value
不常用
Collection<Integer> values=map.values();
遍历每一组key---value
entrySet()
Set<Map.Entry<String,Integer>> entrySet=map.entrySet();
equals(Object o)
m1.entrySet().equals(m2.entrySet())
lambda表达式遍历
map.forEach( (k,v)-> System.out.println(k+":"+v) );
子类
HashMap<K,V>
无序列表
实现
散列表实现
Map<String, Integer> map = new HashMap<>();