一知识总结
String字符串(重点)
String 是一个类,属于数据类型中的引用类型。
Java 中一切使用 "" 引起来的内容,都是这个类的实例,称为字符串对象。
字符串 在定义后,值不可改变,是 一个常量 ,实际是一个 字符数组
//这句话执行时,创建一个"Tom"字符串对象,将其地址保存在变量name中
String name = "Tom";
//这句话执行看似在改变字符串的值,实际是创建了一个新的"Jerry"字符串对象,将其地址保存到变量
name中
name = "Jerry";
//以上两句,在内存中,会有两个字符串对象"Tom"和"Jerry",没有任何字符串发生了改变,只是name引用
了不同的字符串地址
//字符串可以当做数组使用
String str1 = "hello";
//字符串对象实际是一个字符数组对象"包装"而来
char[] list = {'h', 'e', 'l', 'l', 'o'};
String str2=new String(list);
System.out.println(str1);
System.out.println(str2);
String类使用时注意
右上方案例可见,如果频繁地将一个 String 类型变量的值进行更改时,会创建很多字符串对象。效率
低,浪费内存空间。
所以在频繁更改字符串时,不要使用 String 类变量。
如果要频繁更改字符串,使用 StringBuilder 类或 StringBuffer 类
如何创建字符串对象
1.使用""赋值创建
String str="abc";
2.通过构造方法创建
常用构造方法说明
string(0
创建一个空白字符串对象。
String(String str)
创建一个指定字符串的字符串对象。
String(char[] list)
创建一个指定字符数组的字符串对象。
String(byte[] list,String
charsetName)
按指定的编码格式创建一个指定字节数组的字符串对
象。
不同方式创建字符串的过程
使用""赋值的形式创建
//这句话执行时,先判断字符串常量池(缓冲区)中是否存在"ab",不存在则创建,将其地址保存到str1变量
中
String str1 = "ab";
//这句话执行时,先判断字符串常量池(缓冲区)中是否存在"ab",已存在,不用创建,将其地址保存到str2
变量中
String str2 = "ab";
//这句话执行时,+两端如果都是""定义的字符串,拼接后再判断字符串常量池(缓冲区)中是否存在
//拼接后的"ab"依然存在,将其地址保存到str3变量中
String str3 = "a" + "b";
//以上三句话,只会在内存中的字符串常量池(缓冲区)创建一个字符串对象"ab",分别引用给3个变量
System.out.println(str1==str2);//true
System.out.println(str1==str3);//
使用构造方法String(String str)创建
//这句话执行时的流程
//1.在字符串常量池中寻找"ab",不存在,创建
//2.在堆中new String(),将字符串常量池中的"ab"保存到new出来的区域
//3.将堆中new出来的地址保存到栈中变量str1中
String str1 = new String("ab");
//这句话执行时的流程
//1.在字符串常量池中寻找"ab",存在,直接引用
//2.在堆中new String(),将字符串常量池中的"ab"保存到new出来的区域
//3.将堆中new出来的地址保存到栈中变量str2中
String str2 = new String("ab");
//由于str1和str2是堆中的两个区域,所以结果为false
System.out.println(str1 == str2);//false
下面的是易错点 对于我来说
在使用字符串时,如果要比较其值是否相同,不要使用==判断,因为==判断的是内存地址。
使用+拼接""和new出来的字符串对象创建
//在字符串常量池中创建"ab"
String str1 = "ab";
//1.创建StringBuilder对象
//2.在字符串常量池中创建"a"
//3.在字符串常量池中创建"b"
//4.创建String对象
//5.调用StringBuilder的append方法,将"a"和new String("b")拼接
String str2 = "a" + new String("b");//一共创建了"a","b",String,StringBuilder这四个对
象
//两个不同的地址
System.out.println(str1==str2);//false
所以在比较字符串是否相同时,要使用 String 类重写的 equals 方法进行判断。
该方法判断的原理大致为:将两个字符串用字符数组保存,逐个判断字符数组中的每个字符,全部一致
时返回 true ,
所以比较的是字面值。在使用 equals 方法时,通常将已知的非空字符串作为调用者。
字符串相关面试题
//题目一
String str1 = "ab";//常量池中创建"ab"
String str2 = new String("ab");//堆中new String()保存常量池中已有的"ab"
String str3 = "a" + "b";//用常量池已有的"ab"
String str4 = "a" + new String("b");//常量池中创建"a"和"b",堆中new String()和new
StringBuilder()
String str5 = "ab";//用常量池已有的"ab"
System.out.println(str1 == str2);//false
System.out.println(str1 == str3);//true
System.out.println(str1 == str4);//false
System.out.println(str1 == str5);//true
//题目二
//这两句话执行后,会创建几个对象
String s1 = "abc";
String s2 = "a" + "b" + "c";
//在字符串常量池中创建一个对象"abc"
//题目三
//这两句话执行后,会创建几个对象
String s3 = new String("你好");//常量池:"你好",堆中:new String()
String s4 = new String("你好");//堆中:new String()
//3个对象:堆中两个new String(),常量池中"你好"
//题目四
//这两句话执行后,会创建几个对象
String s5 = "hello";//常量池:"hello"
String s6 = "hel" + new String("lo");//常量池:"hel"和"lo" 堆:new String()和new
StringBuilder
//5个对象:常量池:"hello"、"hel"和"lo",堆:new String()和new StringBuilder
//题目五
String s7 = new String("wor");//常量池:"wor",堆:new String()
String s8 = s7 + "ld";//常量池:"ld" 堆:new StringBuilder()
//4个对象:常量池:”wor"和"ld",堆:new String()和new StringBuilder
字符串String类中的常用方法
方法名
返回值
作用
length()
int
得到字符串的长度
toLowerCase()
String
转换为小写
toUpperCase()
String
转换为大写
trim()
String
去除字符串首尾的所有空格
isEmpty()
boolean
判断字符串是否为空白字符串 ""
getBytes()
byte[]
将字符串转换为字节数组
toCharArray()
char[]
将字符串转换为字符数组
equalsIgnoreCase(String
str)
boolean
忽略大小写判断两个字符串是否相同
equals(String str)
boolean
判断两个字符串是否相同
charAt(int index)
char
得到字符串指定索引上的字符
indexOf(String str)
int
得到字符串中某个子字符串第一次出现的索引,如果不
存在,返回 -1
lastIndexOf(String str)
int
得到字符串中某个子字符串最后一次出现的索引,如果
不存在,返回 -1
contains( 字符序列 )
boolean
判断某个子字符串是否在原字符串中出现
concat(String str)
String
将参数字符串拼接到原字符串末尾
startsWith(String str)
boolean
判断是否以指定字符串开头
endsWith(String str)
boolean
判断是否以指定字符串结尾
substring(int begin)
String
从指定索引开始截取字符串至末尾
substring(int being,int
end)
String
截取 [begin,end) 区间内的字符串
split(String regex)
String[]
按执行字符串或正则表达式切分原字符串。如果指定内
容不再末尾, n 个指定字符能得到 n+1 个子串 ; 如果指定
内容在末尾, n 个指定字符能得到 n 个子串 ( 不包含末尾
的无效字符 )
replace(char
oldChar,char newChar)
String
将原字符串中的所有指定字符替换为新字符
String.valueOf( 参数 )
String
将任意参数转换为字符串。通常用于原始类型转换为字
符串。
String.formart(String 格
式 ,Object... obj)
String
根据指定格式转换参数。常用于将浮点数保留小数。如
String.format("%4.2f",10.0/3) 表示将计算的结果四舍
五入保留 2 位小数转换为字符串;如果最终数据所占位
置小于 4 ,原样输出,大于 4 在最前补充空格
作业
接收一个身份证号码,输出这个人的年龄和性别 ( 倒数第二位奇数为男 )
接收一个手机号码,使用 * 替换中间 4 位。如 13915812345 ,输出 139****2345
接收一个字符串,输出其倒序形式。如 how are you ,输出 uoy era woh
接收一个网站的全域名,输出其顶级域名属于什么类型
顶级域名: www.baidu.com 中 .com 就是顶级域名
.com 商业网站 .edu 教育网站 .gov 政务网站 .org 论坛
public class Homework {
public static void main(String[] args) {
String idCard = "500123199903262154";
//使用substring截取所需信息
String birthYear = idCard.substring(6, 10);
String sexNum = idCard.substring(16, 17);
//字符串转换为数字Integer.parseInt(String str)
int age = 2022 - Integer.parseInt(birthYear);
if (Integer.parseInt(sexNum) % 2 == 0) {
System.out.println(age + "岁,性别女");
} else {
System.out.println(age + "岁,性别男");
}
System.out.println("=====================");
String phone = "13915811581";
//如果使用replace,会全部替换
String newPhone = phone.replaceFirst(phone.substring(3, 7), "****");
System.out.println(newPhone);
System.out.println("=====================");
String str = "how are you";
//将原字符串转换为字符数组
char[] chars = str.toCharArray();
//定义翻转后的字符数组
char[] reverseChars = new char[str.length()];
//倒序遍历
for (int i = chars.length - 1; i >= 0; i--) {
//正向存储
reverseChars[chars.length - i - 1] = chars[i];
}
//使用字符串的构造方法,将数组定义为字符串
String reverseStr = new String(reverseChars);
System.out.println(reverseStr);
System.out.println("=====================");
String url = "www.baidu.edu";
//从.最后一次出现的位置开始截取至末尾
String test = url.substring(url.lastIndexOf("."));
switch (test) {
case ".com":
System.out.println(url+"是一个商业网站");
break;
case ".edu":
System.out.println(url+"是一个教育网站");
break;
case ".gov":
System.out.println(url+"是一个政务网站");
break;
case ".org":
System.out.println(url+"是一个非盈利网站");
break;
default:
System.out.println("无法识别");
break;
}
}
}
StringBuilder类
用于表示可变字符串的一个类,是 非线程安全 的,建议在单线程环境下使用。
StringBuffer类
用于表示可变字符串的一个类,是 线程安全 的,建议在多线程环境下使用。
StringBuilder 和 StringBuffer 中的方法都一致,只不过 StringBuffer 中的方法使用了 synchoronized 关键
字修饰,表示是一个同步方法,在多线程环境下不会出现问题。
构造方法
常用构造方法
作用
StringBuilder()
创建一个大小为 16 的字符串数组,表示一个空白字符。类似于 String
str="";
StringBuilder(String
str)
创建一个 str 长度 +16 的字符数组后,将 str 添加到其中。类似于 String
str=" 初始值 ";
注意
以上的方法都是在直接操作同一个字符串对象,每次调用方法后,原字符串都会发生变化
StringBuffer 和 StringBuilder 并没有重写 equals 方法,所以可变字符串的值是否相同时,调用的是
equals 中原始的 == 判断。如果要判断两个可变字符串的值是否相同时,需要将其转换为 String 后调
用 equals 判断
System类
这个类中包含了一些系统相关的信息和一些方法。其中的属性和方法都是静态的。
该类不能创建对象,不是因为它是一个抽象类,而是因为它的构造方法是私有的。
常用属性和方法
System.out
获取打印输出流 PrintStream 对象,用于控制台打印
信息。
System.in
获取输入流 InputStream 对象,用于获取输入的信息
System.err
获取打印输出流 PrintStream 对象,用于控制台打印
异常信息。
System.exit(int statues)
终止虚拟机运行,参数 0 表示正常终止。
System.currentTimeMillis()
获取从 1970.1.1 0:0:0 至今进过了多少毫秒。中国是
UTC(+8) ,所以是从 1970.1.1 8:0:0 至今经过了多少毫
秒。返回 long 类型。
System.arraycopy( 原数组 , 原数组起始位
置 , 目标数组 , 目标数组起始位置 , 原数组要
复制的元素数量 )
将原数组中指定长度的元素复制到新数组中
会用方法和知道这些方法
RunTime 类
Runtime 类的对象,表示 程序运行时对象 ( 程序运行环境对象 ) 。
包含了程序运行环境相关的信息。常用于获取运行环境信息 ( 如虚拟机内存 ) 或执行某个命令。
特点
这个类不是一个抽象类,但不能创建对象,因为它的构造方法是私有的。
这个类提供了一个静态方法 getRuntime() ,通过这个方法,可以获取一个 Runtime 类的对象。
这是 Java 中的一种设计模式 -- 单例模式 ( 一个类只能有一个创建对象 )
Date类
在实际应用中时不时是会用到这个类
构造方法
常用构造方法
说明
Date()
创建当前瞬间对应的日期对象 ,这是比较常用的.
Date(long l)
创建指定瞬间对应的日期对象
Date(int year,int
month,int day)
该构造方法已过时。创建指定年月日的日期对象 ( 年是 1900 年起经过的
年数,月用 0-11 表示 1 到 12 月 )
常用方法
作用
getTime()
得到对应 Date 对象表示的毫秒数
setTime(long l)
设置 Date 对象的毫秒数
after(Date when)
判断调用日期对象是否在 when 之后
before(Date when)
判断调用日期对象是否在 when 之前
SimpleDateFormat类
这个类会经常和Ddate类一起使用
构造方法
SimpleDateFormat(String pattern);
创建一个指定日期模板的格式化日期对象
这个方法 经常会与Date中的方法一起使用
Calendar类
日历类
表示日历的类,包含了很多日历相关的信息。
是一个抽象类,无法创建对象。可以通过静态方法 getInstance() 获取该类的一个实例。
//获取Calendar类的对象
Calendar cal = Calendar.getInstance();
会用这个类就行
包装类
这个就会与实际发生作用
在实际工作中对数据的转换
Java 是纯面向对象语言,宗旨是将一切事物视为对象处理。
但原始类型不属于对象,不满足面向对象的思想。但原始类型在使用时无需创建对象,保存在栈中,效
率高。
为了让原始类型也有对应的类类型,达到 " 万物皆对象 " 的理念,所以就有了包装类的概念。
包装类就是原始类型对应的类类型。 包装类通常用于字符串与原始类型之间的转换。
在 web 应用中,从浏览器页面中获取到后台的数据,全部都是 String 类型,所以一定要使用转换为原始
类型的方法
特点
八个原始类型中,除了 int 和 char ,其余类型的包装类,都是将首字母改为大写。 int 对应
Integer,char 对应 Character
包装类都是被 final 修饰的,不能被继承
除了 Character 类,其余包装类都有两个构造方法:参数为原始类型或 String 的构造方法。
Character 的构造方法只有一个,参数为 char 类型。这些构造方法用于将原始类型或字符串转换为
包装类对象
除了 Character 类,其余类都有 静态方法 parse 原始类型 (String str) ,用于将字符串转换为相应的
原始类型
数值型的包装类的 parseXXX() 方法,如果参数不是对应的数字,转换时就会抛出
NumberFormat 异常。如 "123abc" ,或 "123.4" ,在使用 Integer.parseInt() 时都会抛出异常
Boolean 类型中的 parseBoolean() 方法,参数如果是 "true" 这四个字母,不区分大小写,都能
转换为真正 boolean 类型的 true ,只要不是 "true" 这个单词,转换结果都为 false
除了 Boolean 类,其余包装类都有 MAX_VALUE 和 MIN_VALUE 这两个静态属性,用于获取对应类
型支持的最大最小值
所有包装类都重写了 toString() 方法,用于将包装类对象转换为 String 对象
我们只要知道是哪些就好
字符串与原始类型之间的转换
所有包装类都有一个静态方法 valueOf( 原始类型 ) ,将某个原始类型的数据转换为相应的包装类对
象。这个过程称为装箱 boxing 。
所有包装类都有一个 原始类型 Value() 方法,用于将包装类对象转换为原始类型。这个过程称为拆
箱 unboxing 。
自动装箱和拆箱。在jdk1.5之后,为了方便原始类型和包装类之间做转换,加入了自动装箱拆箱的
概念,可以直接将原始类型和包装类对象之间互相赋值 这是重点
//自动装箱
Integer anInt = 345;
//自动拆箱
int i = anInt;
异常(不重要)
会抛异常就行
处理异常
方式一: try-catch-finally 语句
这种方式处理异常,无论会不会抛出异常,都能让程序正常执行。
try{
//可能出现异常的代码
}catch(异常类 异常对象){
//如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}catch(异常类 异常对象){
//如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}finally{
//无论程序是否会抛出异常,都要执行的代码
}
方式二: throws 关键字
public class Test{
public void fun() throws InterruptException{//这时该方法就会有一个声明:该方法可能
会抛出异常
//这句话直接写完后,会报错,因为sleep()方法可能会抛出InterruptException异常,属于
编译时异常,必须要处理
Thread.sleep(500);
}
}
throw和throws
throws 表示用于声明方法有可能出现的异常。使用时写在方法的小括号之后
public void fun() throws InterruptException{
Thread.sleep(500);
}
throw 用于手动抛出异常对象。使用时,写在方法体中,常用于满足某种情况时,强制中断程序
用法: throw 异常对象;
public void fun2(){
for(int i=0;i<10;i++){
if(i==5){
//手动抛出异常
throw new NullPointerException();
}
}
}
集合框架(集合家族)重点
Collection 还有父接口 Iterable ,但 Iterable 接口不算严格意义上的集合的根接口。它称为迭代器,是用
于遍历集合元素的一个工具接口。
所以 集合的根接口为 Collection 接口和 Map 接口 ,位于 java.util 包中。
Collection接口
该接口有两个核心子接口: List 和 Set 。
这两个接口都可以保存一组元素, List 接口 保存元素时,是 有序可重复 的; Set 接口 保存元素时,是 无序
不重复 的。
常用方法
返回值
作用
add(Object obj)
boolean
将元素添加到集合中
size()
int
获取集合中的元素数量
isEmpty()
boolean
判断集合是否为空
clear()
void
清空集
contains(Object obj)
boolean
判断集合中是否存在指定元素
remove(Object obj)
boolean
移除集合中的指定元素
toArray()
Object[]
将集合转换为数组
iterator()
Iterator
获取集合的迭代器对象,用于遍历集合
List 接口 ( 有序可重复 )
有序集合,元素可以重复,允许保存 null ,可以通过索引获取对应位置上的元素。
在该接口继承 Collection 接口的同时,又拓展了一些操作元素的方法,如添加到指定索引、根据索引删
除、获取指定索引的元素、截取子集合的方法等。
ArrayList实现类(掌握)
采用数组实现的集合
可以通过索引访问元素,可以改变集合大小。如果要在其中插入或删除元素时,会影响后续元素
该集合中保存的都是引用类型,即便保存了数组 123 ,也保存的是 Integer 类型的 123 ,而不是 int 类
型的 123
该集合查询效率高,中途增加和删除元素效率低
常用构造方法
说明
ArrayList()
创建一个 Object 类型的空数组。在调用添加方法后,才会更改该数组 大小为10
ArrayList(int initialCapacity)
创建一个指定容量的 Object 数组,如果参数为负,会抛出
IllegalArgumentException 异常
常用方法
ArrayList 中的常用方法,就是 Collection 接口和 List 接口中定义的方法。
LinkedList 实现类
采用双向链表实现的集合
集合中保存的每个元素也称为节点,除首尾节点外,其余节点都保存了自己的信息外,还保存了其
前一个和后一个节点的地址
如果在双向链表的数据结构中插入和删除操作节点时,不会影响其他节点的位置。如添加时新节点
时,只需要重写定义新节点的前后节点位置即可
如果要查询某个节点时,需要从头结点或尾结点开始一步步得到目标节点的位置
双向链表在中间插入和删除的效率高,随机读取的效率低
构造方法
LinkedList()
创建一个空链表
常用方法
由于 LinkedList 既实现了 List 接口,又实现了 Deque 接口,所以还有 Deque 接口中的一些方法
ArrayList和LinkedList的区别(要记得)
这两个类都是 List 接口的实现类,保存的元素有序可重复,允许保存 null
ArrayList 采用数组实现,随机读取效率高,插入删除效率低,适合用于查询
LinkedList 采用双向链表实现,插入删除时不影响其他元素,效率高,随机读取效率低,适合用于
频繁更新集合
Set 接口 ( 无序不重复 )
无序集合,元素不可以重复,允许保存 null ,没有索引。
Set 接口中没有自己定义的方法,都是继承于 Collection 接口中的方法
哈希表 hash table
哈希表,也称为散列表,是一种数据结构,能更快地访问数据。
要保存的数据称为原始值,这个原始值通过一个函数得到一个新的数据,这个函数称为 哈希函数 ,这个
新数据称为 哈希码 ,哈希码和原始值之间有一个映射关系,这个关系称为哈希映射,可以构造一张映射
表,这个表称为哈希表。在哈希表中,可以通过哈希码快速地访问对应的原始值
哈希码的特点
如果两个对象的 hashCode 不同,这两个对象一定不同
如果两个对象的 hashCode 相同,这两个对象不一定相同
hashCode 相同,对象不同,这种现象称为哈希冲突
" 通话 " 和 " 重地 " 这两个字符串的 hashCode 相同,但是两个不同的对象
HashSet 实现类
采用哈希表实现
元素不能重复,无序保存,允许保存一个 null
本质是一个 HashMap 对象
使用 HashSet 集合时,通常要重写实体类中的 equals 和 hashcode 方法
HashSet()
创建一个空集合,实际是创建一个 HashMap 对象。
构造方法
HashSet()
创建一个空集合,实际是创建一个 HashMap 对象
HashSet 添加数据的原理
如果两个元素的 hashCode 相同且 equals 结果为 true ,视为同一个对象,不能添加。
每次向集合中添加元素时,先判断该元素的 hashCode 是否存在
如果不存在,视为不同对象,直接添加
如果存在,再判断 equals 方法的结果
如果 false ,视为不同对象,可以添加
如果 true ,视为同一对象,不能添加
由此可见,不能添加的条件是两个对象的 hashCode 相同且 equals 的结果为 true 。
如果每次只判断 equals 的话,由于 equals 方法通常重写时会判断很多属性,效率不高。
如果每次只判断 hashCode 的话,效率高,但有可能会有哈希冲突,
所以先判断 hashCode ,再判断 equals ,技能保证效率,又能保证不添加重复元素。
equals 方法和 hashCode 的关系
如果两个对象的 equals 方法结果为 true ,在没有重写 equals 方法的前提下, hashCode 相同吗
如果没有重写 equals ,默认是 Object 中使用 == 判断,如果结果为 true ,说明是同一个对象,
hashCode 一定相同
如果两个对象的 hashCode 不同,在没有重写 equals 方法的前提下, equals 方法的结果为?
hashCode 不同,说明不是同一个对象,没有重写 equals ,说明使用 Object 中 equals 的 == 判
断,结果为 false
如果两个对象的 hashCode 相同, equals 方法的比较结果为?
可能为 true 也可能为 false
TreeSet 实现类
特殊的 Set 实现类,数据可以有序保存,可以重复,不能添加 null
采用红黑树 ( 自平衡二叉树 ) 实现的集合
二叉树表示某个节点最多有两个子节点
某个节点右侧节点值都大于左侧节点值
红黑树会经过不停的 " 变色 " 、 " 旋转 " 达到二叉树的平衡
只能添加 同一种类型 的对象且该类 实现了 Comparable 接口
实现 Comparable 接口后必须要重写 compareTo() 方法
每次调用添加 add(Object obj) 方法时,就会自动调用参数的 compareTo() 方法
compareTo() 方法的返回值决定了能否添加新元素和新元素的位置
如果返回 0 ,视为每次添加的是同一个元素,不能重复添加
如果返回正数,将新元素添加到现有元素之后
如果返回负数,将新元素添加到现有元素之前
添加的元素可以自动排序
构造方法
TreeSet()
创建一个空集合,实际是创建了一个 TreeMap 对象
Map 接口
Map 称为映射,数据以 键值对 的形式保存。保存的是键与值的对应关系。
键称为 Key ,值称为 Value ,键不能重复,键允许出现一个 null 作为键,值无限制。
键和值都是引用类型。
如, yyds 就是一个键 key ,代表了一个含义: “ 永远单身 ” 即为值 value 。
HashMap 实现类
构造方法
HashMap()
创建一个空的映射集合,默认大小为 16 ,加载因子为 0.75
遍历方式
方式一:普通 for 循环
System.out.println("使用普通for循环遍历");
//方式一:普通for循环
for (int i = 0; i < nameList.size(); i++) {//从0遍历到size()
String name = nameList.get(i);//通过get(int index)获取指定索引的元素
System.out.println(name);
}
方式二:增强 for 循环
System.out.println("使用增强for循环遍历");
//方式二:增强for循环
for (String name : nameList) {
System.out.println(name);
}
方式三:迭代器
System.out.println("使用迭代器遍历");
//方式三:迭代器
//Collection类型的集合对象.iterator(),获取迭代器
Iterator<String> iterator = nameList.iterator();
// iterator.hasNext()判断集合中是否还有下一个元素
// iterator.next();获取下一个元素
while (iterator.hasNext()) {
String name = iterator.next();
System.out.println(name);
}
Collections 集合工具类
Collection 是集合的根 接口 ,定义了集合操作元素的方法
Collections 是集合的工具 类 ,定义了集合操作元素的静态方法
方法
集合和数组之间的转换
集合转换为数组 :使用 Collection 接口中的 toArray() 方法
文件类File
Java 中的 File 类,表示本地硬盘中的文件 ( 文件和目录 ) 的一个类。
通过这个类创建的对象,可以操作对应的文件。
构造方法
常用方法
递归遍历文件夹
import java.io.File;
import java.util.Date;
public class Test3 {
//查看某个目录下的所有文件
public static void main(String[] args) {
File source = new File("E:\\adobe");
Test3 t = new Test3();
t.fun(source);
}
/*
* 递归遍历文件夹
* */
public void fun(File source) {
//输出某个目录中超过3个月未使用且大于500MB的文件
/*
long start = source.lastModified();
long end = System.currentTimeMillis();
if ((end - start) / 1000 / 3600 / 24 > 90 && source.length() / 1024 /
1024 > 500) {
System.out.println(source.getName() + "\t" + new
Date(source.lastModified()) + "\t" + source.length() / 1024 / 1024);
}*/
//判断是否为目录
if (source.isDirectory()) {
//将其展开
for (File child : source.listFiles()) {
//因为子文件有可能是目录,继续调用本方法
fun(child);
}
}
}
}
IO
I : Input 输入
O : Output 输出
流 Stream
在 Java 中, 流用于表示计算机硬盘与内存之间传输数据的通道。
将 内存 中的数据存入 到硬盘 中,称为 写 write ,也称为 输出 Output 。
将 硬盘 中的数据存入 到内存 中,称为 读 read ,也称为 输入 Input 。
流的分类
Java 中将流定义为类,以对象的形式表现流。流有 " 四大家族 " ,是所有流的父类。
字节输入流 InputStream
FileInpuStream 、 ObjectInputStream
字节输出流 OutputStream
FileOutputStream 、 ObjectOutputStream
字符输入流 Reader
FileReader 、 BufferedReader 、 OutputStreamWriter
字符输出流 Writer
FileWriter 、 BufferedWriter 、 InputStreamReader
按方向分类
输入流: InputStream 、 Reader
将硬盘中的数据读取到内存中
输出流: OutputStream 、 Writer
将内存中的数据写入到硬盘中 常用构造方法
说明
FileInputStream(String pathName)
根据文件名创建流对象
FileInputStream(File file)
根据文件对象创建流对象
按类型分
字节流: InputStream 、 OutputStream
读写非文本类型文件。如图片、音视频、其他文件等。
字符流: Reader 、 Writer
读写纯文本类型文件。如 txt 、 md 等
如要将硬盘中某个 txt 文件中的内容读取到程序中,使用 Reader
如要将硬盘中的某个图片读取到程序中,使用 InputStream
如要将程序中的文本写入到硬盘中为 txt 类型文件时,使用 Writer
如要将程序中的数据写入到硬盘中为非文本文件时,使用 OutputStream
流的四个父类的特点
这四个父类都是在 java.io 包下,都是抽象类,不能直接创建其对象,使用其子类创建对象
这四个父类中都定义了 close() 方法,用于关闭流对象,释放资源
输入流 (InputStream 和 Reader) 都有 read() 方法读取数据到内存中,输出流都有 write() 方法写入数
据到硬盘中
输出流 (OutputStream 和 Writer) 都有 flush() 方法,用于将流中的数据冲刷到硬盘中
在使用输出流对象时,一定要调用 flush() 或 close() 方法后,才能真正将数据写入到硬盘中
所有的流中,以 Stream 结尾,都是字节流,数据以字节传输;以 Reader 或 Writer 结尾的,都是字
符流,数据以字符传输
读取硬盘中的数据,使用输入流,读取的文件必须存在;将数据写入到硬盘中,使用输出流,文件
可以不存在,但父目录必须存在。
读入或写入文本时,使用字符流;读取或写入非文本时,使用字节流
FileInputStream文件字节输入流(掌握)
按字节读取硬盘中的文件。
常用方法
FileOutputStream文件字节输出流(掌握)
构造方法
常用方法
使用 FileInputStream 和 FileOutputStream
读写时的注意事项
在通过 FileInputStream 对象使用 read(byte[] bytes) 方法时,每次读取指定数组的字节,将读取到
的字节保存在字节数组中,该方法返回读取到的字节数量。如果最后一次读取的字节数不足字节数
组的大小时,只会将读取到内容覆盖数组中最前的几个元素。所以会导致读取到的内容多于实际内
容。 在通过 FileOutputStream 对象使用 write(byte[] bytes) 方法时,会将字节数组中的所有内容写入到
输出流中,在最后一次写入时,可能会写入多余的内容。所以在写入时,最好使用 write(byte[]
bytes,int off,int lef) 方法,表示将字节数组中的内容,从 off 开始写入 len 个。
如有 word.txt 文件,其中保存 aaabbbccc
BufferedReader缓冲字符输入流(掌握)
自带缓冲区 ( 字符数组 ) 的字符输入流。默认字符数组大小为 8192 ,每次最多读取 8192 个字符。
在读取纯文本文件 (txt 或 md) 时,首选该类。
构造方法
常用方法
BufferedWriter缓冲字符输出流(掌握)
自带缓冲区 ( 字符数组 ) 的字符输出流
构造方法
常用方法
ObjectOutputStream对象字节输出流(序列
化)(掌握)
序列化:将对象转换为文件的过程
被序列化的对象,必须要实现 Serializable 接口。
这个接口是一个特殊的接口,没有定义任何方法,只是给该类加上标记,表示该类可以被序列化
构造方法
ObjectInputStream对象字节输入流(反序列
化)(掌握)
反序列化:将文件转换为对象的过程
转换流
实际属于字符流,作用为将一个字节流对象转换为字符流对象
OutputStreamWriter
将字节输出流转换为字符输出流
InputStreamReader
将字节输入流转换为字符输入流
网络编程
InetAddress 类
Socket 类和 ServerSocket 类
都属于 Socket( 套接字 ) 对象,表示网络中的某个端点
Socket 指普通端
ServerSocket 指服务器端
使用套接字对象实现两个端点 (Socket 和
ServerSocket) 之间发送文件
服务器端
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
/*
* 使用套接字对象,实现客户端向服务端发送文件
*
* 定义服务端套接字对象
客户端
* */
public class Server {
public static void main(String[] args) throws IOException {
//以本机创建服务端套接字对象
ServerSocket server = new ServerSocket(8899, 100,
InetAddress.getLocalHost());
//等待客户端连接,返回连接的客户端套接字对象
Socket client = server.accept();
//定义要将读取到的数据写入到本地的文件字节输出流对象
FileOutputStream fos = new FileOutputStream("上传文件.md");
//获取客户端与服务端的输入流对象,读取发送的数据
InputStream is = client.getInputStream();
//定义读取的字节数组
byte[] bytes = new byte[1024 * 1024 * 8];
int count = is.read(bytes);
while (count != -1) {
//将读取到的数据写入到本地
fos.write(bytes, 0, count);
count = is.read(bytes);
}
fos.close();
is.close();
}
}
客户端
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/*
* 定义客户端套接字对象
* */
public class Client {
public static void main(String[] args) throws IOException {
//创建客户端套接字对象,连接指定的服务端套接字对象
Socket client = new Socket("192.168.31.39", 8899);
//获取客户端与服务端的输出流对象
OutputStream os = client.getOutputStream();
//成功连接后,将某个文件发送给服务端
//定义要发送的文件对象
File file = new File("F:\\221001\\笔记\\面向对象部分回顾.md");
//读取要发送的文件
FileInputStream fis = new FileInputStream(file);
作业
//定义字节数组
byte[] bytes = new byte[1024 * 1024 * 8];
//循环读取要发送的文件
int count = fis.read(bytes);
while (count != -1) {
//将读取到的数据写入到客户端套接字与服务端套接字的通道中
os.write(bytes,0,count);
count = fis.read(bytes);
}
fis.close();
os.close();
}
}
二我认为的重要知识点及我的错题
在这个阶段的学习中,知识多.所以我要分出重要知识点,String类和集合类,还有就是File类,绝对是必须掌握的.其他知识我们必须会用,知道哪些方法怎样用
- 指出下列程序运行的结果 ( )
public class Example{
String str=new String("good");
char[] ch = {'a','b','c'};
public static void main(String args[]){
Example ex=new Example();
ex.change(ex.str,ex.ch);
System.out.print(ex.str+" and ");
Sytem.out.print(ex.ch);
}
public void change(String str,char ch[]){
str="test ok";
ch[0]='g';
}
}
[A] good and abc [B] good and gbc
[C] test ok and abc [D] test ok and gbc
2.在读文件Employee.dat时,最好使用的类是()。
A.BufferedReader
B.DataInputStream
C.DataOutputStream
D.FileInputStream
3.以下Java语句中,
String str = “123456789”;
str =str.subString(1,3);
执行后str中的值为( )
(A) “23” (B) “123”
(C) “12” (D) “234”
4. 在Java语言中,下面代码编译运行结果是( )。(选择一项)
publicclass A {
public void changeName(StringBuffer name, StringBuffer nickname) {
name = new StringBuffer("YangFan");// 第三行代码
nickname.append("1");
System.out.print(name);
System.out.print(" " + nickname);
}
Public static void main(String[] args) {
StringBuffer name = new StringBuffer("YangYang");
StringBuffer nickname = new StringBuffer("Yaya");
A a = newA();
a.changeName(name, nickname);
System.out.print(" " + name);
System.out.print(" " + nickname);
}
}
A.输出:YangFan Yaya1 YangYang Yaya
B.输出:YangFan Yaya1 YangYang Yaya1
C.因为第三行代码有错误,程序无法编译通过
D.输出:YangFan Yaya1 YangFan Yaya1
三分享homework
//1. 读取信息
读取 " 信息 " 文件夹中的所有文件,获取其文件名 , 该文件名由 " 学号 + 姓名 " 组成。
//2. 保存信息
将获取到的文件名拆解为学号和姓名后,作为学生的属性,创建学生对象进行保存。
将学生对象保存到集合中,将该集合序列化,保存为一个文件。
//3. 加载信息
反序列化之前保存的集合文件。读取该文件,输出所有的学生信息
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
StudentManager sm = new StudentManager();
ArrayList<Student> studentList = null;
while (true) {
System.out.println("1.初始化数据");
System.out.println("2.加载查看信息");
Scanner sc = new Scanner(System.in);
switch (sc.nextInt()) {
case 1:
File source = new File("f:/作业素材");
sm.init(source);
//对该集合进行序列化
studentList = sm.getStudentList();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f:/stuList.stu"));
oos.writeObject(studentList);
oos.close();
System.out.println("数据加载成功");
break;
case 2:
File file = new File("f:/stuList.stu");
if (!file.exists()) {
System.out.println("数据未初始化");
return;
}
//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
studentList = (ArrayList<Student>) ois.readObject();
ois.close();
for (Student student : studentList) {
System.out.println(student);
}
break;
}
}
}
}
mport java.io.Serializable;
/*
* 要对该类进行序列化,必须先实现Serializable接口
* */
public class Student implements Serializable {
private String stuNo;
private String stuName;
@Override
public String toString() {
return "Student{" +
"stuNo='" + stuNo + '\'' +
", stuName='" + stuName + '\'' +
'}';
}
public Student(String stuNo, String stuName) {
this.stuNo = stuNo;
this.stuName = stuName;
}
public String getStuNo() {
return stuNo;
}
public void setStuNo(String stuNo) {
this.stuNo = stuNo;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
}
import java.io.File;
import java.util.ArrayList;
public class StudentManager {
//定义保存每个文件名的集合
private ArrayList<String> fileNameList = new ArrayList<>();
//定义保存学生对象的集合
private ArrayList<Student> studentList = new ArrayList();
/*
* 只能获取学生集合
* */
public ArrayList<Student> getStudentList() {
return studentList;
}
/*
* 初始化数据
* 读取提供的文件夹,获取其中的文件名,截取相关信息
* */
public void init(File file) {
//调用递归读取文件的方法
getFileName(file);
//遍历文件名的集合
for (String fileName : fileNameList) {
//使用.分割
String s = fileName.split("\\.")[0];
//使用空格分割
String stuNo = s.split(" ")[0];
String stuName = s.split(" ")[1];
//创建学生对象,添加到集合中
Student student = new Student(stuNo, stuName);
studentList.add(student);
}
}
/*
* 递归遍历文件
* */
public void getFileName(File file) {
if (file.isFile()) {
//将文件名保存到集合中
fileNameList.add(file.getName());
} else {
for (File listFile : file.listFiles()) {
getFileName(listFile);
}
}
}
}