String类
- String是一个类,属于数据类型中的引用类型。
- 在创建字符串对象时,先在字符串常量池中搜索要创建的字符串对象是否存在,如果存在则直接使用,这时,如果String a和String b创建了相同的字符串对象,那么a==b,因为它们用的是同一个地址;不存在就创建一个新的字符串对象。
- 在比较字符串的值是否相同时,不建议使用==判断,==判断的是内存地址。建议使用String类重写的equals方法进行判断,这里比较的是字面值。
- 使用+拼接的两个字符串对象,是先拼接了再去字符串常量池中搜索是否存在拼接后的字符串对象。
常用方法名 | 返回值 | 作用 |
length() | int | 得到字符串长度 |
trim() | String | 去除字符串首尾的所有空格 |
toCharArray() | char[ ] | 将字符串转换为字符数组 |
equals(String str) | boolean | 判断两个字符串是否相同 |
charAt(int index) | char | 得到字符串指定索引上的字符 |
indexOf(String str) | int | 得到字符串中某个字符串第一次出现的索引,如果不存在,返回-1 |
lastIndexOf(String str) | int | 得到字符串中某个字符串最后一次出现的索引,如果不存在,返回-1 |
contains(字符序列) | boolean | 判断某个字符串是否在原字符串中出现 |
substring(int begin) | String | 从指定索引开始截取字符串至末尾 |
substring(int begin,int end) | String | 截取[begin,end)区间内的字符串 |
split(String regex) | String[ ] | 根据指定的字符串regex去分割原字符串。 如果指定内容在末尾,n个指定字符串能得到n个分割后的字符串(不包含末尾上的指定字符串后的无效字符);如果不在末尾则得到n+1个分割后的字符串(在头部会包括头部前的无效的字符) |
String.valueOf(参数) | String | 将任意参数转换为字符串。通常用于原始类型转换为字符串。 |
StringBuilder类
可变字符串的一个类,是非线程安全的,建议在单线程环境下使用。
构造方法名 | 作用 |
StringBuilder() | 创建一个大小为16的字符串数组,表示一个空白字符。 |
StringBuilder(String str) | 创建一个str长度+16的字符数组后,将str添加到其中。 |
普通方法名 | 作用 |
append(Object obj) | 将任意类型的参数添加到原可变字符串的末尾 |
delete(int start,int end) | 删除[start,end)区间内的字符 |
deleteCharAt(int index) | 删除index索引上的字符 |
insert(int index,Object obj) | 在索引index上插入obj |
replace(int start,int end,String str) | 将[start,end)区间内的字符替换为str |
reverse() | 反转字符串(相当于倒序) |
StringBuffer类
可变字符串的一个类,是线程安全的,建议在多线程环境下使用。
转换
//String转换为可变字符串
StringBuilder sb=new StringBuilder(String str);
//可变字符串转换为String
StringBuilder sb1=new StringBuilder("方法1");
String str1=String.valueOf(sb1);
StringBuilder sb2=new StringBuilder("方法2");
String str2=sb.toString();
StringBuilder sb3=new StringBuilder("方法3");
String str3=sb+"";
注意
这三个类都是被final修饰的类,不能被继承。
频繁更改字符串时,不要使用String类,会创建很多字符串对象浪费内存;如果要频繁更改字符串,使用StringBuilder类或StringBuffer类。
System类
它的属性和方法都是静态的。它的构造方法是私有的,不能创建对象。
属性和方法 | 作用 |
System.out | 获取打印输出流PrintStream对象,用于控制台打印信息 |
System.in | 获取输入流InputStream对象,用于获取输入的信息 |
System.err | 获取打印输出流PrintStream对象,用于控制台打印异常信息 |
System.exit(int statues) | 终止虚拟机运行,statues为0表示正常终止 |
System.currentTimeMillis() | 获取从1970.1.1 0:0:0至今过了多少毫秒。返回值为long类型 |
System.arraycopy(原数组,原数组起始位,目标数组,目标数组起始位,原数组要复制的元素数量) | 将原数组中指定位置长度的元素复制到新数组指定位置上 |
Date类
构造方法名 | 作用 |
Date() | 创建当前瞬间对应的日期对象 |
Date(long l) | 创建指定瞬间对应的日期对象 |
普通方法名 | 作用 |
getTime() | 得到对应Date对象表示的毫秒数 |
setTime(long l) | 设置Date对象的毫秒数 |
after(Date when) | 判断调用日期对象是否在when之后 |
before(Date when) | 判断调用日期对象是否在when之前 |
SimpleDateFormat类
构造方法
SimpleDateFormat(String pattern); 创建一个指定日期模板的格式化对象
日期模板
特殊字符 | 作用 |
yyyy | 年 |
MM | 月 |
dd | 日 |
HH | 小时 |
mm | 分钟 |
ss | 秒 |
E | 星期 |
常用方法
方法名 | 作用 |
format(Date date) | 将Date对象按日期模板转换为字符串 |
parse(String str) | 将满足日期模板的字符串转换为Date对象 |
String patten = "yyyy/MM/dd HH:mm:ss E";
simpleDateFormat sdf = new SimpleDateFormat(patten);
String format = sdf.format(new Date());
Date date = sdf.parse("2000/5/3 2:1:3 星期一");
Calendar类
日历字段
值 | 作用 |
Calender.YEAR | 年份 |
Calender.MONTH | 月份(0~11表示1~12月) |
Calender.DATE | 日期 |
Calender.DAY_OF_WEEK | 星期几(1~7表示周日到周六) |
Calender.HOUR | 12进制小时 |
Calender.HOUR_OF_DAY | 24进制小时 |
Calender.MINUTE | 分钟 |
Calender.SECOND | 秒 |
Calender.DAY_OF_MONTH | 本月第几天 |
Calender.DAY_OF_YEAR | 本年第几天 |
Calender.WEEK_OF_MONTH | 本月第几周 |
Calender.WEEK_OF_YEAR | 本年第几周 |
常用方法
方法名 | 作用 |
get(int field) | 根据日历字段获取对应的值 |
getTime() | 获取对应的Date对象(Calendar对象转换为Date对象) |
getMaximum(int field) | 获取指定日历字段支持的最大值 |
getActualMaximum(int field) | 获取指定日历字段在当前日期下的实际最大值 |
set(int field,int value) | 将指定的日历字段设置为指定值 |
set(int year,int month,int date) | 同时设置日历对象的年月日 |
setTime(Date date) | 将Date对象作为参数设置日历对象的信息 |
包装类
- 包装类就是原始类型对应的类型,通常用于字符串与原始类型之间的转换。
- 包装类就是八大原始类型首字母大写,其中需要注意的是int和char,int对应的包装类为Interger,char对应的包装类为Character。
- 包装类被final修饰,不能被继承。
- Character的构造方法只有一个,参数为char类型;其余包装类除了参数为自己本身的原始类型外还有参数为String的构造方法。
- 除了Character类,其余类都有静态方法parse原始类型(String str)。
- 除了Boolean类,其余包装类都有MAX_VALUE和MIN_VALUE这两个静态属性,用于获取对应类型支持的最大最小值
- 所有包装类都重写了toString()方法,用于将包装类对象转换为String对象
转换
字符串转原始类型
使用对应的包装类调用parse原始类型(字符串)
String num="123";
byte b = Byte.parseByte(num);
short s = Short.parseShort(num);
int i = Integer.parseInt(num);
long l = Long.parseLong(num);
float f = Float.parseFloat(num);
double d = Double.parseDouble(num);
boolean flag = Boolean.parseBoolean(num);
原始类型转字符串
//+拼接一个空白字符串
int num1 = 123;
String str1 = num1 + "";
//调用toString()方法
int num2 = 123;
Integer integer = new Integer(num2);
String str2 = integer.toString();
//String.valueOf()
int num3 = 123;
String str3 = String.valueOf(num3);
装箱拆箱
手动
//装箱
int i = 123;
Integer integer = Interger.valueOf(i);
//拆箱
Integer integer = new Integer(123);
int i = integer.intValue();
自动
//装箱
Integer anInt = 345;
//拆箱
int i = anInt;
自动装箱方式创建包装类对象,赋值范围在byte范围[-128,127]内,将这个值保存在缓冲区中,如果多个对象使用同一个数值,共享这个数据,使用同一个地址,使用==判断结果为 true。引用类型对象比较值是否相同时,建议使用重写的equals方法,==判断的只是内存地址。
异常
异常大体上分为Error错误和Exception异常。假如出现xxxxError是无法通过额外的代码解决,只能修改源码;如果出现xxxxException,可以通过额外的代码去解决。
Exception异常主要分为两个类型,一个是运行时异常RuntimeException,可以通过编译,可以不 用处理,运行时可能抛出异常对象;另一个是编译时异常,无法通过编译,必须处理异常后才能编译运行。
运行时异常名 | 出现场景 |
NullPointerException 空指针异常 | 用空对象null调用属性或方法 |
ArrayIndexOutOfBoundsException 数组下标越界异常 | 使用数组时,下标超出范围 |
NumberFormatException 数字格式异常 | 使用包装类调用parse方法做转换时,无法将参数转换。 |
InputMismatchException 输入不匹配异常 | 使用Scanner接收控制台输入时,不满足接收的类型。 |
ClassCastException 对象转型异常 | Person p = (Person)Object obj; |
ArithmeticException 算术运算异常 | 0当分母 |
编译时异常名 | 出现场景 |
SQLException 数据库SQL相关异常 | 操作数据库时 |
IOException 输入输出流异常 | 使用流对象时 |
FileNotFoundException 文件未找到异常 | 方法的参数为文件时 |
处理异常
try-catch-finally语句
try{
//可能出现异常的代码
}catch(异常类 异常对象){
//如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}catch(异常类 异常对象){
//如果出现异常对象,且与catch小括号中的异常类型匹配,就会执行这里的代码
}finally{
//无论程序是否会抛出异常,都要执行的代码
}
throws关键字
在方法参数部分之后,添加 throws 异常类型1,异常类型2...
throws和throw
- throws表示用于声明方法有可能出现的异常。使用时写在方法的小括号之后。
- throw用于手动抛出异常对象。使用时,写在方法体中,常用于满足某种情况时,强制中断程序。用法:throw 异常对象;
集合
集合的根接口为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 | 移除集合中的指定元素 |
List接口
常用方法名 | 返回值 | 作用 |
get(int index) | Object | 根据指定索引获取对应的元素 |
set(int index,Object obj) | Object | 使用obj替换index上的元素,返回被替换的元素 |
add(int index,Object obj) | void | 将obj添加到index上 |
remove(int index) | Object | 移除指定索引的元素 |
indexOf(Object obj) | int | 得到某元素第一次出现的索引,没有返回-1 |
lastIndexOf(Object obj) | int | 得到某元素最后一次出现的索引,没有返回-1 |
subList(int from,int to) | List | 截取[from,to)区间内的元素,返回子集合 |
ArrayList实现类
常用构造方法 | 说明 |
ArrayList() | 创建一个Object类型的空数组。在调用添加方法后,才会更改该数组大小为10 |
ArrayList(int initialCapacity) | 创建一个指定容量的Object数组,如果参数为负,会抛出IllegalArgumentException异常 |
ArrayList中的常用方法,就是Collection接口和List接口中定义的方法
LinkedList实现类
常用构造方法 | 说明 |
LinkedList() | 创建一个空链表 |
于LinkedList既实现了List接口,又实现了Deque接口,所以还有Deque接口中的一些方法
实现Deque接口的方法 | 说明 |
addFirst(Object obj) | 添加头元素 |
addLast(Object obj) | 添加尾元素 |
removeFirst() | 移除头元素 |
removeLast() | 移除尾元素 |
getFirst() | 得到头元素 |
getLast() | 得到尾元素 |
remove() | 移除头元素 |
pop() | 移除头元素 |
push(Object obj) | 添加头元素 |
peek() | 得到头元素 |
poll() | 移除头元素 |
offer(Object obj) | 添加尾元素 |
ArrayList和LinkedList
- 这两个类都是List接口的实现类,保存的元素有序可重复,允许保存null
- ArrayList采用数组实现,随机读取效率高,插入删除效率低,适合用于查询
- LinkedList采用双向链表实现,插入删除时不影响其他元素,效率高,随机读取效率低,适合用于频繁更新集合
set接口
- 无序集合,元素不可以重复,允许保存null,没有索引。
- Set接口中没有自己定义的方法,都是继承于Collection接口中的方法
哈希码
- 如果两个对象的hashCode不同,这两个对象一定不同
- 如果两个对象的hashCode相同,这两个对象不一定相同
HashSet实现类
常用构造方法 | 说明 |
HashSet() | 创建一个空集合,实际是创建一个HashMap对象 |
HashSet中没有属于自定义的方法,都是重写了父接口Set和Collection中的方法。
TreeSet实现类
常用构造方法 | 说明 |
TreeSet() | 创建一个空集合,实际是创建一个TreeMap对象 |
能使用Collection和Set中的方法,除此之外,还有独有的方法
常用方法名 | 作用 |
fisrt() | 得到集合中的第一个元素 |
last() | 得到集合中的最后一个元素 |
ceil(Object obj) | 得到比指定元素obj大的元素中的最小元素 |
floor(Object obj) | 得到比指定元素obj小的元素中的最大元素 |
Map接口
- Map称为映射,数据以键值对的形式保存。保存的是键与值的对应关系。
- 键称为Key,值称为Value,键不能重复,键允许出现一个null作为键,值无限制。
- 键和值都是引用类型
常用方法名 | 作用 |
size() | 得到键值对的数量 |
clear() | 清空所有键值对 |
put(Object key,Object value) | 向集合中添加一组键值对 |
get(Object key) | 在集合中根据键得到对应的值 |
remove(Object key)/remove(Object key,Object key) | 根据键或键值对移除 |
keyset() | 获取键的集合 |
values() | 获取值的集合 |
containsKey(Object key) | 判断是否存在某个键 |
containsValue(Object value) | 判断是否存在某个值 |
entrySet() | 得到键值对的集合 |
HashMap实现类
常用构造方法 | 说明 |
HashMap() | 创建一个空的映射集合,默认大小为16,加载因子为0.75 |
常用方法参考Map中的方法
遍历集合中元素的方式
遍历List集合
ArrayList<String> nameList = new ArrayList();
nameList.add("Tom");
nameList.add("Jerry");
nameList.add("LiHua");
nameList.add("Danny");
//方式一:普通for循环
for (int i = 0; i < nameList.size(); i++) {//从0遍历到size()
String name = nameList.get(i);//通过get(int index)获取指定索引的元素
System.out.println(name);
}
//方式二:增强for循环
for (String name : nameList) {
System.out.println(name);
}
//方式三:迭代器
//Collection类型的集合对象.iterator(),获取迭代器
Iterator<String> iterator = nameList.iterator();
// iterator.hasNext()判断集合中是否还有下一个元素
// iterator.next();获取下一个元素
while (iterator.hasNext()) {
String name = iterator.next();
System.out.println(name);
}
遍历Set集合
Set hs = new HashSet();
hs.add(123);
hs.add("hello");
hs.add(null);
hs.add(987);
//方式1:增强for循环
for(Object o : hs){
System.out.println(o);
}
//方式2:迭代器
Iterator<Object> it = hs.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
遍历Map集合
Map<Integer, User> hm = new HashMap<>();
User u1 = new User("admin", "123123");
User u2 = new User("tom", "123123");
User u3 = new User("jerry", "123123");
hm.put(1001, u1);
hm.put(1002, u2);
hm.put(1003, u3);
//遍历hashMap
for (Integer id : hm.keySet()) {
System.out.println(id + "\t" + hm.get(id).getUsername());
}
//得到当前hashmap对象中的所有键值对的集合
Set<Map.Entry<Integer, User>> entries = hm.entrySet();
//遍历键值对
for (Map.Entry<Integer, User> entry : entries) {
System.out.println(entry);
}
泛型
集合类或接口 集合变量名 = new 集合实现类();
List<String> list = new ArrayList();
//当前集合只能保存String类型的元素
list.add("sdfsdf");
//list.add(123);//无法添加
List<Integer> list2 = new ArrayList();
list2.add(123);
Collections集合工具类
常用方法 | 说明 |
Collections.shuffle(List list) | 打乱List集合中元素的顺序 |
Collections.sort(List list) | 对List集合中的元素进行排序,元素必须实现Comparable接口 |
Collections.swap(List list,int a,int b) | 交换List集合中元素的索引 |
Collections.replaceAll(List list,Object oldObj,Object newObj) | 替换List集合中的旧元素为新元素 |
Collections.reverse(List list) | 将List集合中的元素反转 |
Collections.fill(List list , Object obj) | 使用指定元素填充List集合 |
Collections.rotate(List list , int n) | 将集合中最后n个元素放在最前 |
Collections.max(Collection col)/min(Collection col) | 得到集合中的最大/最小值,集合中的元素必须实现Comparable接口 |
集合与数组的转换
集合转换为数组
//使用Collection接口中的toArray()方法
Object[] obj = 集合对象.toArray();
List<Integer> list = new ArrayList();
list.add(123);
list.add(63);
list.add(3);
Integer[] nums =(Integer[]) list.toArray();
数组转换为集合
int[] nums ={11,2,66,3,6,21};
List list = new ArrayList();
for(int i:nums){
list.add(i);
}
一组数据转换为集合
//使用Arrays工具类中的asList(一组数据)方法
//通常将数组中的数据直接作为参数
List<String> strings = Arrays.asList("XX", "aa", "qq", "xx");
文件类File
常用构造方法 | 说明 |
File(String pathName) | 根据文件的完整路径创建File对象 |
File(String parent,String child) | 根据文件的父目录路径和自身路径创建File对象 |
File(File parent,String child) | 根据文件的父目录对应的File对象和自身路径创建File对象 |
常用方法 | 说明 |
exists() | 判断文件是否存在 |
isFile() | 判断是否为文件 |
isDirectory() | 判断是否为目录 |
getName() | 获取文件名 |
getPath() | 获取文件相对路径 |
getAbsolutePath() | 获取文件绝对路径 |
getParent() | 获取父目录的名称 |
getParentFile() | 获取父目录对象 |
lastModified() | 获取最后一次修改时间对应的毫秒数 |
length() | 获取文件所占字节 |
isHidden() | 判断文件是否隐藏 |
delete() | 删除文件或空目录 |
renameTo(File newFile) | 将原文件重命名且移动到指定目录 |
mkdir() | 创建目录 |
list() | 获取某个目录下的第一层子文件的名称的数组 |
listFiles() | 获取某个目录下的第一层子文件对象的数组 |
流
- 用于表示计算机硬盘与内存之间传输数据的通道。
- 将内存中的数据存入到硬盘中,称为写write,也称为输出Output。
- 将硬盘中的数据存入到内存中,称为读read,也称为输入Input。
字节输入流
InputStream FileInpuStream、ObjectInputStream
字节输出流
OutputStream FileOutputStream、ObjectOutputStream
字符输入流
Reader FileReader、BufferedReader、OutputStreamWriter
字符输出流
Writer FileWriter、BufferedWriter、InputStreamReader
按方向分类
- 输入流:InputStream、Reader 将硬盘中的数据读取到内存中
- 输出流:OutputStream、Writer 将内存中的数据写入到硬盘中
按类型分类
- 字节流:InputStream、OutputStream 读写非文本类型文件。如图片、音视频、其他文件等。
- 字符流:Reader、Writer 读写纯文本类型文件。如txt、md等
如要将硬盘中某个txt文件中的内容读取到程序中,使用Reader
如要将硬盘中的某个图片读取到程序中,使用InputStream
如要将程序中的文本写入到硬盘中为txt类型文件时,使用Writer
如要将程序中的数据写入到硬盘中为非文本文件时,使用OutputStream
流的四个父类的特点
- 这四个父类都是在java.io包下,都是抽象类,不能直接创建其对象,使用其子类创建对象
- 这四个父类中都定义了close()方法,用于关闭流对象,释放资源
- 输入流(InputStream和Reader)都有read()方法读取数据到内存中,输出流都有write()方法写入数 据到硬盘中
- 输出流(OutputStream和Writer)都有flush()方法,用于将流中的数据冲刷到硬盘中
- 所有的流中,以Stream结尾,都是字节流,数据以字节传输;以Reader或Writer结尾的,都是字符流,数据以字符传输
- 读取硬盘中的数据,使用输入流,读取的文件必须存在;将数据写入到硬盘中,使用输出流,文件可以不存在,但父目录必须存在。
- 读入或写入文本时,使用字符流;读取或写入非文本时,使用字节流
FileInputStream文件字节输入流
常用构造方法 | 说明 |
FileInputStream(String pathName) | 根据文件名创建流对象 |
FileInputStream(File file) | 根据文件对象创建流对象 |
常用方法 | 说明 |
read() | 读取一个字节,返回读取到的字节 |
read(byte[] bytes) | 按字节数组读取,返回读取到的字节数量,读取到的内容保存在字节数组中 |
close() | 关闭流对象 |
FileOutputStream文件字节输出流
常用构造方法 | 说明 |
FileOutputStream(String pathname) | 根据文件名创建输出流对象,写入时覆盖原内容 |
FileOutputStream(String pathname,boolean append) | 根据文件名创建输出流对象,第二个参数为true,写 入时追加在原内容之后 |
FileOutputStream(File file) | 根据文件对象创建输出流对象,写入时覆盖原内容 |
FileOutputStream(File file,boolean append) | 根据文件对象创建输出流对象,第二个参数为true, 写入时追加在原内容之后 |
常用方法 | 作用 |
write(int i) | 写入一个指定字节 |
write(byte[] bytes) | 写入一个字节数组 |
write(byte[] bytes,int off,int len) | 写入字节数组中从off开始的len个字节 |
flush() | 将流中的数据冲刷到硬盘中 |
close() | 关闭流对象 |
注意
- 在通过FileInputStream对象使用read(byte[] bytes)方法时,每次读取指定数组的字节,将读取到的字节保存在字节数组中,该方法返回读取到的字节数量。如果最后一次读取的字节数不足字节数组的大小时,只会将读取到内容覆盖数组中最前的几个元素。所以会导致读取到的内容多于实际内容。
- 在通过FileOutputStream对象使用write(byte[] bytes)方法时,会将字节数组中的所有内容写入到输出流中,在最后一次写入时,可能会写入多余的内容。所以在写入时,最好使用write(byte[] bytes,int off,int lef)方法,表示将字节数组中的内容,从off开始写入len个。
FileReader文件字符输入流
常用构造方法 | 说明 |
FileReader(String fileName) | 根据文件名创建文件字符输入流对象 |
FileReader(File file) | 根据文件对象创建文件字符输入流对象 |
常用方法 | 作用 |
ready() | 判断是否还有下一个字符 |
read() | 读取下一个字符,返回读取到的字符 |
read(char[] chars) | 按字符数组读取,返回读取到的字符数量,读取到的字符保存在字符数组中 |
close() | 关闭流对象 |
FileWriter文件字符输出流
常用构造方法 | 作用 |
FileWriter(String fileName) | 按文件名创建字符输出流对象,覆盖写入 |
FileWriter(String fileName,boolean append) | 按文件名创建字符输出流对象,如果append为true, 表示追加写入 |
FileWriter(File file) | 按文件对象创建字符输出流对象,覆盖写入 |
FileWriter(File file,boolean append) | 按文件对象创建字符输出流对象,如果append为 true,表示追加写入 |
常用方法 | 作用 |
write(String str) | 按字符串写入 |
flush() | 将流中的数据冲刷到硬盘中的文件,必须调用该方法或close方法后,才能真正写入 |
close() | 关闭流对象 |
BufferedReader缓冲字符输入流
常用构造方法 | 作用 |
BufferedReader(Reader in) | 创建一个带有缓冲区(大小为8192的char数组)的字符输入流对象, 参数为Reader类型对象,Reader是抽象类,所以实际参数为 Reader的子类,如FileReader,在FileReader对象中定义要读取的文件 |
BufferedReader(Reader in,int size) | 创建一个指定缓冲区(字符数组)大小的字符输入流对象 |
常用方法 | 作用 |
ready() | 判断是否还有字符 |
readLine() | 读取整行字符 |
close() | 关闭流对象 |
BufferedWriter缓冲字符输出流
常用构造方法 | 说明 |
BufferedWriter(Writer writer) | 创建一个自带缓冲区的字符输出流对象,参数为一个Writer对象, Writer是一个抽象类,实际参数为Writer的子类,如FileWriter,在 FileWriter中定义要将输入写入的目标文件 |
BufferedWriter(Writer writer,int size) | 创建一个指定缓冲区大小的字符输出流对象 |
常用方法 | 作用 |
write(String str) | 写入字符串 |
newLine() | 换行 |
flush() | 冲刷流中的数据到硬盘 |
close() | 关闭流对象 |
ObjectOutputStream对象字节输出流(序列化)
被序列化的对象,必须要实现Serializable接口。
构造方法 | 说明 |
ObjectOutputStream(OutputStream os) | 创建一个对象字节输出流对象,参数为一个字节输出 流对象,由于OutputStream是抽象类,所以使用其子类,如FileOutputStream对象,在其中定义要写入的文件 |
常用方法 | 作用 |
writeObject(Object obj) | 将一个对象写入到本地文件中 |
close() | 关闭流对象 |
ObjectInputStream对象字节输入流(反序列化)
常用构造方法 | 说明 |
ObjectInputStream(InputStream is) | 创建一个对象字节输入流对象,参数为一个字节输入流对 象,由于InputStream是抽象类,所以使用其子类,如 FileInputStream对象,在其中定义要读取的文件 |
常用方法 | 作用 |
readObject() | 读取序列化后的文件,返回类型为Object |
close() | 关闭流对象 |
转换流
- OutputStreamWriter 将字节输出流转换为字符输出流
- InputStreamReader 将字节输入流转换为字符输入流
- 转换流的使用 如果只提供了一个字节流,但要向其中写入或读取字符时,就可以使用转换流将字节流转换为字符流。 使用字符流读写字符时比字节流更方便。
Socket类和ServerSocket类
都属于Socket(套接字)对象,表示网络中的某个端点
- Socket指普通端
- ServerSocket指服务器端
进程和线程
进程Process
- 进程就是操作系统中执行的程序。一个程序就是一个执行的进程实体。
- 每个运行中的进程,都有属于它独立的内存空间,各个进程互不影响。
线程Thread
- 线程是一个进程中的执行单元,一个进程中可以有多个线程。
- 多个线程可以访问同一个进程中的资源。 每个线程都有一个独立的栈空间,这些线程所在的栈空间位于同一个进程空间中。
多线程
- 如果一个进程中,同时在执行着多个线程,就称为多线程。 多线程可以提高程序执行效率。
Java中的线程Thread类
- Java中,线程以对象的形式存在。
- Thread类表示线程类
获取线程对象
- 获取当前正在运行的线程对象
Thread ct = Thread.cuurentThread();
- 创建一个线程对象
常用构造方法 | 说明 |
Thread() | 创建一个默认的线程对象 |
Thread(String name) | 创建一个指定名称的线程对象 |
Thread(Runnable target) | 将一个Runnable对象包装为线程对象 |
Thread(Runnable target,String name) | 将一个Runnable对象包装为线程对象同时设置线程名 |
线程常用方法
方法 | 作用 |
getId() | 获取线程id |
getName() | 获取线程名,默认Thread-n |
getPriority() | 获取线程优先级,默认为5 |
getState() | 获取线程状态 |
setName(String str) | 设置线程名 |
setPriority(int priority) | 设置线程优先级,范围在1-10,值越大越优先执行 |
isDaemon() | 判断线程是否为守护线程 |
setDaemon(boolean f) | 参数为true表示设置线程为守护线程 |
start() | 让线程进入就绪状态 |
run() | 线程获得执行权时执行的方法(线程要做的事情) |
Thread.sleep(long m) | 设置当前线程休眠m毫秒 |
Thread.currentThread() | 获取当前执行的线程对象 |
Thread.yield() | 线程让步 |
实现多线程
方式一:继承Thread类
- 创建一个类,继承Thread类
- 重写Thread类中的run()方法
- 创建自定义的线程子类对象后,调用start()方法
方式二:实现Runnable接口
由于Java中是单继承,如果某个类已经使用了extends关键字去继承了另一个类,这时就不能再通过extends继承Thread实现多线程。 就需要实现Runnable接口的方式实现多线程。
- 自定义一个类,实现Runnable接口
- 重写run()方法,将多线程要执行的内容写在该方法中
- 创建Runnable接口的实现类对象
- 使用构造方法Thread(Runnable target)或Thread(Runnable target,String name)将上一步创建的Runnable实现类对象包装为Thread对象
方式三:使用匿名内部类
如果不想创建一个Runnable接口的实现类,就可以使用匿名内部类充当Runnable接口的实现类
线程的生命周期
线程的初始化到终止的整个过程,称为线程的生命周期。
新生状态
当线程对象被创建后,就进入了新生状态。
就绪状态
当某个线程对象调用了start()方法后,就进入了就绪状态。 在这个状态下,线程对象不会做任何事情,只在等他CPU调度。
运行状态
当某个线程对象得到CPU时间片(CPU执行这个线程的机会所给的时间),则进入运行状态,开始执行 run()方法。不会等待run()方法执行完毕,只会在指定的时间内尽可能地执行run()方法。只要调用玩run()方法后,就会再进入就绪状态。
阻塞状态
如果某个线程遇到了sleep()方法或wait()方法时,就会进入阻塞状态。 sleep()方法会在指定时间后,让线程重新就绪。 wait()方法只有在被调用notify()或notifyAll()方法唤醒后才能重新就绪。
终止状态
当某个线程的run()方法中的所有内容都执行完,就会进入终止状态,意味着该线程的使命已经完成。
多线程访问同一个资源
出现问题
由于线程调用start()方法后,就进入就绪状态。如果获得了CPU时间片,就开始调用run()方法,调用 run()方法后,就会再次进入就绪状态,不会等待run()方法执行完毕,所以在线程A执行run()方法的时候,线程B也开始执行了,这样就会出现数据共享的问题。 因为现在所有的线程都是异步(同时)执行。
如何解决
让线程同步(排队)执行即可。这样一来,某个线程执行run()方法的时候,让其他线程等待run()方法的内容执行完毕。
synchronized关键字
这个关键字可以修饰方法或代码块
- 修饰方法
写在方法的返回值之前,这时该方法就称为同步方法。
- 修饰代码块
写在一个独立的{}前,这时该段内容称为同步代码块。
原理
- 每个对象默认都有一把"锁",当某个线程运行到被synchronized修饰的方法时,该对象就会拥有这把锁,在拥有锁的过程中,其他线程不能同时访问该方法,只有等待其结束后,才会释放这把锁。
- 使用synchronized修饰后的锁称为"悲观锁"。
- 方法被synchronized修饰后,称为同步方法,就会让原本多线程变成了单线程(异步变为同步)。
死锁
定义两个线程类,线程A先获取资源A后,在获取资源B;线程B先获取资源B后,再获取资源A。 如果对资源A和资源B使用了synchronized进行同步,就会在线程A获取资源A的时候,线程B无法获取资源A,相反线程B在获取资源B的时候,线程A无法获取资源B,所以两个线程都不会得到另一个资源。
解决方式
方式一
让两个线程获取资源的顺序保持一致。
方式二
让两个线程在获取资源A和B之前,再获取第三个资源,对第三个资源使用synchronized进行同步,这样 某个线程在获取第三个资源后,将后续内容执行完毕,其他线程才能开始执行。