Java-String类的常用方法总结
一、String类
String类在java.lang包中,java使用String类创建一个字符串变量,字符串变量属于对象。java把String类声明的final类,不能有类。String类对象创建后不能修改,由0或多个字符组成,包含在一对双引号之间。
二、String类对象的创建
字符串声明:String stringName;
字符串创建:stringName = new String(字符串常量);或stringName = 字符串常量;
三、String类构造方法
1、public String()
无参构造方法,用来创建空字符串的String对象。
1 String str1 = new String();
2、public String(String value)
用已知的字符串value创建一个String对象。
1 String str2 = new String("asdf"); 2 String str3 = new String(str2);
3、public String(char[] value)
用字符数组value创建一个String对象。
1 char[] value = {"a","b","c","d"};
2 String str4 = new String(value);//相当于String str4 = new String("abcd");
4、public String(char chars[], int startIndex, int numChars)
用字符数组chars的startIndex开始的numChars个字符创建一个String对象。
1 char[] value = {"a","b","c","d"};
2 String str5 = new String(value, 1, 2);//相当于String str5 = new String("bc");
5、public String(byte[] values)
用比特数组values创建一个String对象。
1 byte[] strb = new byte[]{65,66};
2 String str6 = new String(strb);//相当于String str6 = new String("AB");
四、String类常用方法
1、求字符串长度
public int length()//返回该字符串的长度
1 String str = new String("asdfzxc");
2 int strlength = str.length();//strlength = 7
2、求字符串某一位置字符
public char charAt(int index)//返回字符串中指定位置的字符;注意字符串中第一个字符索引是0,最后一个是length()-1。
1 String str = new String("asdfzxc");
2 char ch = str.charAt(4);//ch = z
3、提取子串
用String类的substring方法可以提取字符串中的子串,该方法有两种常用参数:
1)public String substring(int beginIndex)//该方法从beginIndex位置起,从当前字符串中取出剩余的字符作为一个新的字符串返回。
2)public String substring(int beginIndex, int endIndex)//该方法从beginIndex位置起,从当前字符串中取出到endIndex-1位置的字符作为一个新的字符串返回。
1 String str1 = new String("asdfzxc");
2 String str2 = str1.substring(2);//str2 = "dfzxc"
3 String str3 = str1.substring(2,5);//str3 = "dfz"
4、字符串比较
1)public int compareTo(String anotherString)//该方法是对字符串内容按字典顺序进行大小比较,通过返回的整数值指明当前字符串与参数字符串的大小关系。若当前对象比参数大则返回正整数,反之返回负整数,相等返回0。
2)public int compareToIgnore(String anotherString)//与compareTo方法相似,但忽略大小写。
3)public boolean equals(Object anotherObject)//比较当前字符串和参数字符串,在两个字符串相等的时候返回true,否则返回false。
4)public boolean equalsIgnoreCase(String anotherString)//与equals方法相似,但忽略大小写。
1 String str1 = new String("abc");
2 String str2 = new String("ABC");
3 int a = str1.compareTo(str2);//a>0
4 int b = str1.compareTo(str2);//b=0
5 boolean c = str1.equals(str2);//c=false
6 boolean d = str1.equalsIgnoreCase(str2);//d=true
5、字符串连接
public String concat(String str)//将参数中的字符串str连接到当前字符串的后面,效果等价于"+"。
1 String str = "aa".concat("bb").concat("cc");
2 相当于String str = "aa"+"bb"+"cc";
6、字符串中单个字符查找
1)public int indexOf(int ch/String str)//用于查找当前字符串中字符或子串,返回字符或子串在当前字符串中从左边起首次出现的位置,若没有出现则返回-1。
2)public int indexOf(int ch/String str, int fromIndex)//改方法与第一种类似,区别在于该方法从fromIndex位置向后查找。
3)public int lastIndexOf(int ch/String str)//该方法与第一种类似,区别在于该方法从字符串的末尾位置向前查找。
4)public int lastIndexOf(int ch/String str, int fromIndex)//该方法与第二种方法类似,区别于该方法从fromIndex位置向前查找。
1 String str = "I am a good student";
2 int a = str.indexOf('a');//a = 2
3 int b = str.indexOf("good");//b = 7
4 int c = str.indexOf("w",2);//c = -1
5 int d = str.lastIndexOf("a");//d = 5
6 int e = str.lastIndexOf("a",3);//e = 2
7、字符串中字符的大小写转换
1)public String toLowerCase()//返回将当前字符串中所有字符转换成小写后的新串
2)public String toUpperCase()//返回将当前字符串中所有字符转换成大写后的新串
1 String str = new String("asDF");
2 String str1 = str.toLowerCase();//str1 = "asdf"
3 String str2 = str.toUpperCase();//str2 = "ASDF"
8、字符串中字符的替换
1)public String replace(char oldChar, char newChar)//用字符newChar替换当前字符串中所有的oldChar字符,并返回一个新的字符串。
2)public String replaceFirst(String regex, String replacement)//该方法用字符replacement的内容替换当前字符串中遇到的第一个和字符串regex相匹配的子串,应将新的字符串返回。
3)public String replaceAll(String regex, String replacement)//该方法用字符replacement的内容替换当前字符串中遇到的所有和字符串regex相匹配的子串,应将新的字符串返回。
1 String str = "asdzxcasd";
2 String str1 = str.replace('a','g');//str1 = "gsdzxcgsd"
3 String str2 = str.replace("asd","fgh");//str2 = "fghzxcfgh"
4 String str3 = str.replaceFirst("asd","fgh");//str3 = "fghzxcasd"
5 String str4 = str.replaceAll("asd","fgh");//str4 = "fghzxcfgh"
9、其他类方法
1)String trim()//截去字符串两端的空格,但对于中间的空格不处理。
1 String str = " a sd ";
2 String str1 = str.trim();
3 int a = str.length();//a = 6
4 int b = str1.length();//b = 4
2)boolean statWith(String prefix)或boolean endWith(String suffix)//用来比较当前字符串的起始字符或子字符串prefix和终止字符或子字符串suffix是否和当前字符串相同,重载方法中同时还可以指定比较的开始位置offset。
1 String str = "asdfgh";
2 boolean a = str.statWith("as");//a = true
3 boolean b = str.endWith("gh");//b = true
3)regionMatches(boolean b, int firstStart, String other, int otherStart, int length)//从当前字符串的firstStart位置开始比较,取长度为length的一个子字符串,other字符串从otherStart位置开始,指定另外一个长度为length的字符串,两字符串比较,当b为true时字符串不区分大小写。
4)contains(String str)//判断参数s是否被包含在字符串中,并返回一个布尔类型的值。
1 String str = "student";
2 str.contains("stu");//true
3 str.contains("ok");//false
5)String[] split(String str)//将str作为分隔符进行字符串分解,分解后的字字符串在字符串数组中返回。
1 String str = "asd!qwe|zxc#";
2 String[] str1 = str.split("!|#");//str1[0] = "asd";str1[1] = "qwe";str1[2] = "zxc";
五、字符串与基本类型的转换
1、字符串转换为基本类型
java.lang包中有Byte、Short、Integer、Float、Double类的调用方法:
1)public static byte parseByte(String s)
2)public static short parseShort(String s)
3)public static short parseInt(String s)
4)public static long parseLong(String s)
5)public static float parseFloat(String s)
6)public static double parseDouble(String s)
例如:
1 int n = Integer.parseInt("12");
2 float f = Float.parseFloat("12.34");
3 double d = Double.parseDouble("1.124");
2、基本类型转换为字符串类型
String类中提供了String valueOf()方法,用作基本类型转换为字符串类型。
1)static String valueOf(char data[])
2)static String valueOf(char data[], int offset, int count)
3)static String valueOf(boolean b)
4)static String valueOf(char c)
5)static String valueOf(int i)
6)static String valueOf(long l)
7)static String valueOf(float f)
8)static String valueOf(double d)
例如:
1 String s1 = String.valueOf(12);
2 String s1 = String.valueOf(12.34);
3、进制转换
使用Long类中的方法得到整数之间的各种进制转换的方法:
Long.toBinaryString(long l)
Long.toOctalString(long l)
Long.toHexString(long l)
Long.toString(long l, int p)//p作为任意进制
String 方法
#substring
public String substring(int beginIndex)
返回一个新的字符串,它是此字符串的一个子字符串。该子字符串始于指定索引处的字符,一直到此字符串末尾。
#StringBuilder
n.append(x) 添加字符
n.insert(n.length(), x) 在指定索引处开始添加字符
如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。 在 StringBuilder 上的主要操作是 append 和 insert 方法。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符添加或插入到字符串生成器中。append 方法始终将这些字符添加到生成器的末端;而 insert 方法则在指定的点添加字符。 例如,如果 z 引用一个当前内容为"start"的字符串生成器对象,则该方法调用 z.append("le") 将使字符串生成器包含"startle",而 z.insert(4, "le") 将更改字符串生成器,使之包含"starlet"。 通常,如果 n引用 StringBuilder 的实例(StringBuilder n = new StringBuilder();),则 n.append(x) 和 n.insert(n.length(), x) 具有相同的效果。 每个字符串生成器都有一定的容量。只要字符串生成器所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区。如果内部缓冲区溢出,则此容量自动增大。 将StringBuilder的实例用于多个线程是不安全的。如果需要这样的同步,则建议使用StringBuffer。[1] StringBuilder类可以用于在无需创建一个新的字符串对象情况下修改字符串。StringBuilder不是线程安全的,而StringBuffer是线程安全的。但StringBuilder在单线程中的性能比StringBuffer高。
单列集合:collection--->List,set
List--->
Vector类: 底层数组, 有索引, 内存空间连续分配, 所以查询快, 增删慢, 线程安全, 效率低
ArrayList底层为数组, 有索引, 内存空间连续分配, 所以查询快, 增删慢, 线程不安全, 效率高
LinkedList底层链表, 查询慢, 增删快
Set--->
HashSet类: 底层Hash表, 元素无序(存取顺序不同),
元素不可重复(用hashCode()和equals()方法来判断)
TreeSet类: 底层二叉树结构, 元素可以排序
排序的前提:
- 1.元素具备比较性
- 实现Comparable接口, 重写compareTo()方法
- 2.集合具备比较性
- 定义一个适用于被比较元素的Comparator比较器接口实现类, 重写compare()方法
- compare和compareTo方法的返回值是int:
- 0相同
- <0 小
- >0 大
LinkedHashSet
有序,没有索引,具有HashSet的元素不可重复特点,
---
Iterator 接口
boolean hasNext(): 判断是否有下一个元素
E next(): 获取下一个元素
void remove(): 删除迭代器返回的最后一个元素
ListIterator接口
void add(E e): 使用迭代器添加元素到集合
void remove(): 使用迭代器删除元素
迭代器对象 Iterator it = 集合对象.iterator();
注意添加元素的时候要用迭代器添加,而不是集合
IO-File
字符流
|_ Reader
|_ FileReader # 文件字符输入流
|_ BufferedReader # 缓冲文件字符输入流
|_ Writer
|_ FileWriter # 文件字符输出流
|_ BufferedWriter # 缓冲文件字符输出流
字节流
|_ InputStream
|_ FileInputStream # 文件字节输入流
|_ BufferedInputStream # 缓冲文件字节输入流
|_ OutputStream
|_ FileOutputStream # 文件字节输出流
|_ BufferedOutputStream # 缓冲文件字节输出流
File: 文件或目录的抽象表示
- java.io.File类:
- 是文件和目录的路径名的抽象表现形式(也就是文件和目录在Java中的形式, 既能表示文件, 也能表示目录)
- 构造方法(创建了File对象, 并将其指向该路径. 不会在磁盘上创建这个文件)
- File File(String pathname): 使用指定的路径名创建一个File对象.
- File File(String parent, String child): 根据指定的父路径和文件路径创建File对象.
- File File(File parent, String child): 根据指定的父路径File对象和文件路径创建File对象
- 常用成员方法
- 创建:
- boolean createNewFile(): 创建一个新文件. 返回是否创建成功
- boolean mkdir(): 创建目录, 返回是否创建成功
- boolean mkdirs(): 创建多层目录, 包括指定路径中缺少的父级目录. 返回是否创建成功
- 注意: 创建目录就只创建目录, 不会创建文件. 即使有a.txt也会把他作为目录名创建目录
- 删除
- boolean delete(): 删除文件或目录. 返回是否删除成功
- 注意: 删除是永久删除, 回收站没有
- 获取
- String getPath(): 获取创建File对象时使用的路径(创建时是相对路径则返回相对路径, 是绝对路径则返回绝对路径)
- String getAbsolutePath(): 获取File对象的绝对路径字符串
- File getAbsoluteFile(): 获取包含绝对路径的File对象
- String getParent(): 获取File对象的父路径字符串
- File getParentFile(): 获取File对象的父路径的File对象
- String getName(): 获取File对象代表的文件名或目录名(不含上层目录)
- long length(): 获取File对象所表示的文件的大小, 单位byte
- 注意: 如果File对象是一个目录, 则返回值不确定; 如果文件不存在, 则返回0L
- long lastModified(): 获取文件上次修改时间
- 判断
- boolean exists(): 判断文件或目录是否存在
- boolean isAbsolute(): 判断File中保存的是否是绝对路径
- 注意: 无论该文件是否真实存在, 只判断创建File时使用的路径字符串
- boolean isDirectory(): 判断该File对象是否为目录
- boolean isFile(): 判断该File对象是否为文件
- boolean isHidden(): 判断该文件或目录是否为隐藏的
- 修改
- boolean renameTo(File dest): 修改文件名
- 重要获取功能
- String[] list(): 获取当前路径下所有文件和目录名称(不包括父路径). File对象必须是目录, 否则会报错
- File[] listFiles(): 获取当前路径下的所有文件和目录的File对象. File对象必须是目录
- static File[] listRoots(): 返回系统的所有根路径. windows系统就是各种盘符
- 字节流
- InputStream
- 操作文件的子类: FileInputStream类
- int read(): 读取一个字节, 读完返回-1
- 注意返回值是int类型, 而不是byte
- int read(byte[] b): 读取字节到数组中, 返回读取的长度. 读完返回-1
- close(): 释放资源
- OutputStream
- 操作文件的子类: FileOutputStream类
- void write(byte b): 写一个字节
- void write(byte[] b, int offset, int len): 从字节数组的指定索引开始写入指定长度个字节
- close(): 释放资源
- 注意: 他们读写的是: byte, byte[]
- 路径
- 绝对路径
- 以盘符开头: E:\\a\\a.txt
- 相对路径
- 以斜杠开头: \\a\\a.txt
- 以文件/目录名开头: a.txt, src
- 项目根目录: .
- 重点练习
- listFiles()相关的三个练习
- 递归打印目录下的所有.java文件
- 递归删除目录
- 递归复制目录
IO总结.
- IO体系结构(终结版)
# 按照流的用途分:
文件输入输出流
|_ 字节流
|_ FileInputStream
|_ FileOutputStream
|_ 字符流
|_ FileReader
|_ FileWriter
缓冲输入输出流
|_ 字节流
|_ BufferedInputStream
|_ BufferedOutputStream
|_ 字符流
|_ BufferedReader
|_ BufferedWriter
对象输入输出流
|_ 字节流
|_ ObjectInputStream
|_ ObjectOutputStream
打印输出流
|_ 字节流
|_ PrintStream
|_ 字符流
|_ PrintWriter
转换流
|_ 字符流
|_ InputStreamReader
|_ OutputStreamWriter
# 体系结构:
字节流
|_ InputStream # 字节输入流
| |_ FileInputStream # 专门操作文件的字节输入流
| |_ BufferedInputStream # 带有缓冲区的字节输入流, 效率高
| |_ ObjectInputStream # 对象输入流
|
|_ OutputStream # 字节输出流
|_ FileOutputStream # 专门操作文件的字节输出流
|_ BufferedOutputStream # 带有缓冲区的字节输出流, 效率高
|_ ObjectOutputStream # 对象输出流
|_ PrintStream # 字节打印流
字符流
|_ Reader # 字符输入流
| |_ BufferedReader # 带有缓冲区的字符输入流, 效率高
| |_ InputStreamReader # 将字节流转换为字符流输入的转换输入流
| |_ FileReader # 专门操作文件的字符输入流
|
|_ Writer # 字符输出流
|_ BufferedWriter # 带有缓冲区的字符输出流, 效率高
|_ OutputStreamWriter # 将字符流转换为字节流输出的转换输出流
|_ FileWriter # 专门操作文件的字符输出流
|_ PrintWriter # 字符打印流
标准流:
OutputStreamWriter:字符流通向字节流的桥梁,文件内容打印到控制台,以写出字符流的方式编写代码(char, char[], String), 而底层以字节流写出到文件(byte, byte[])**
InputStreamReader:是字节流通向字符流的桥梁,控制台录入到文件,以读取字符流的方式编写代码(char, char[], String), 而底层以字节流读取(byte, byte[])
打印流:
PrintStream: 字节打印流
- 自动换行. println(). 会根据系统自动确定换行符
- 自动刷新. 通过构造方法的配置可以实现(只在调用println(), printf(), format()时有用)
- 也是包装流, 类似于BufferedWriter, 自身没有写出功能
- 可以把字节输出流转换为字符输出流
- 不能输出byte字节, 可以输出其他任意类型(要输出字节可以使用PrintStream)
- 关流不会抛出异常(此类中的方法不会抛出 I/O 异常,尽管其某些构造方法可能抛出异常)
- 标准流
- System.err: 标准错误流. (命令行输出错误信息)
- System.in: 标准输入流. (键盘输入)
- 是InputStream类, 属于字节输入流
- System.out: 标准输出流. (控制台输出)
- 是OutputStream的子类PrintStream, 属于字节输出流
- 转换流
- InputStreamReader: 字节输入流转字符输入流
- 是Reader的子类, 属于字符输入流
- OutputStreamWriter: 字符输出流转字节输出流
- 是Writer的子类, 属于字符输出流
- 特点
- 转换流也是包装类, 需要传入实际的输入输出流对象
- 打印流
- PrintStream: 字节打印流
- PrintWriter: 字符打印流
- 注意
- 打印是输出操作, 所以打印流只有输出, 没有输入
- PrintWriter打印流的特点
- 可以自动换行, println(). 会根据系统自动确定换行符
- 不能输出字节, 可以输出其他任意类型(要输出字节需要使用PrintStream)
- 通过构造方法的配置可以实现自动刷新(flush)(只在调用println, printf, format时有用)
- 也是包装流, 自身没有写出功能
- 可以把字节输出流转换为字符输出流
- 关流不会抛出异常(此类中的方法不会抛出 I/O 异常,尽管其某些构造方法可能抛出异常)
- 方法
- 构造方法
- PrintWriter PrintWriter(String filepath)
- PrintWriter PrintWriter(Writer out, boolean autoFlush): 创建对象, 同时设置是否自动刷新
- PrintWriter(OutputStream out, boolean autoFlush): 创建对象, 同时设置是否自动刷新
- 成员方法
- void write(String s): 写一个字符串
- void print(String s): 输出字符串, 没有换行
- void println(String s): 输出字符串并换行. 如果启动了自动刷新, 则会执行自动刷新写入数据
- void printf(Locale l, String format, Object... args): 使用指定格式字符串和参数将格式化的字符串写入输出流. 如果启动了自动刷新, 则会执行自动刷新写入数据
- void format(Locale l, String format, Object... args): 使用指定格式字符串和参数将格式化的字符串写入输出流. 如果启动了自动刷新, 则会执行自动刷新写入数据
- 对象操作流
- 作用: 读写对象到文件
- ObjectInputStream: 对象输入流
- ObjectOutputStream: 对象输出流
- 注意
- 使用对象输出流写出对象到文件, 该文件只能使用对象输入流读取对象
- 只能将实现了java.io.Serializable接口的对象写入流中
- Serializable接口
- 标记接口, 用于标记该类可以序列化
- private static final long serialVersionUID: 序列版本号. 用于确定对象和类定义是否一致
- InvalidClassException用对象读取流时发生该异常的原因:
1. 该类的序列版本号与从流中读取的类描述符的版本号不匹配
2. 该类包含未知数据类型(即可能添加了新的成员变量或方法)
3. 该类没有可访问的无参数构造方法
- 方法
- 构造方法:
- ObjectOutputStream ObjectOutputStream(OutputStream out): 创建对象输出流
- ObjectInputStream ObjectInputStream(InputStream in): 创建对象输入流
- 成员方法
- void writeObject(Object o): 将对象写入对象输出流
- Object readObject(): 从对象输入流读取对象, 一次只读取一个对象. 当读不到时抛出EOFException.
- 读取对象异常的优化操作
- 在对象流中只保存一个对象, 通过该对象保存其他对象
- 比如用集合存储多个同类型的对象
- 定义一个类, 其中包含不同类型的其他类型对象
- Properties
- 继承Hashtable<K, V>, 实现Map<K, V>
- 作用: 以键值对方式保存信息到文本文件
- 应用场景: 作为程序的配置文件
- 注意
不能存null的键和值
- 只能保存英文字符和符号, 默认使用ISO-8859-1编码, 存中文会显示乱码
- 注意: 如果配置文件保存为.txt, 会变成GBK编码, 可以显示中文. 但一般都存为.properties, 使用ISO-8859-1, 显示不了中文
- 键和值都是字符串
- 方法
- 构造方法
- Properties Properties()
- 成员方法
- 可以使用Map的方法
- String getProperty(String key): 根据键获取值. 如果找不到该键, 则返回null
- String getProperty(String key, String defaultValue): 根据键获取值, 如果值不存在, 则使用指定的默认值
- void setProperty(String key, String value): 设置键值对
- void load(InputStream in): 从字节输入流中读取Properties
- void load(Reader reader): 从字符输入流中读取Properties
- void list(PrintStream out): 将Properties输出到指定的字节打印输出流. 会自动加一个-- listing properties --文件头
- void list(PrintWriter out): 将Properties输出到指定的字符打印输出流. 会自动加一个-- listing properties --文件头
- void store(Writer writer, String comments): 将Properties输出到指定的输出流, 并添加一个注释. 如果不想要注释可传null. 无论有没有注释, 都会添加时间字符串的注释
- void store(OutputStream os, String comments): 同上, 只是流不同
- list方法和store方法的区别
- list只能接收打印流(PrintStream, PrintWriter)
- store可以接收任何输出流(OutputStream, Writer)
- Properties读写操作步骤
- 写出到文件
- 创建Properties对象, 添加键值对, 使用list()或store()保存到文件中
- 从文件读取
- 创建Properties对象, 使用load()从文件加载数据, 使用getProperty()根据指定键获取值, 或使用遍历Map的方式遍历所有键和值
- 编码表
- 作用: 将计算机二进制数据转换为不同语言的字符
- 常见编码表
- ASCII: 美国标准码. 包含26个英文字母的大写和小写, 数字, 符号
- ISO-8859-1: 西方语言编码
- GB2312: 国标码
- GBK: 国标扩展码
- Unicode: 万国码. 支持多国语言字符.
- UTF-8: Unicode的一种实现方式, 长度可变的码表, 一个字符占用1个或2个字节
- ANSI: 本地编码表. 根据系统设置决定编码表
- Java String类对于字节和编码的操作
- byte[] getBytes(): 获取字符串的byte数组, 使用默认编码
- byte[] getBytes(String charsetName): 获取字符串的byte数组, 使用指定编码
- String String(byte[] bytes): 将byte数组转化为字符串, 使用默认编码
- String String(byte[] bytes, String charsetName): 将byte数组转换为字符串, 使用指定编码
- String String(byte[] bytes, int offset, int len, String charsetName): 将byte数组的一部分转换为字符串, 使用指定编码
- 乱码
- 原因: 读的编码与写的编码不一致
- 解决方法: 保证读和写的编码一致, 即可解决
- 处理乱码的2种方式:
1. String通过指定编码转为byte数组, 然后再创建String: (GBK字符串转UTF-8字符串写入文件)
- 先将String通过目标编码转为byte数组: byte[] bys = "月薪过万".getBytes("UTF-8");
- 再将byte数组转换为String: String str = new String(bys);
- 写入到文件: fw.write(str);
2. OutputStreamWriter可以指定编码写入文件, 免去使用String通过编码转换为byte数组的步骤
- OutputStreamWriter OutputStreamWriter(OutputStream out, String charsetName): 创建转换流对象, 并指定编码
IO总结
- 标准流
- System.err: 标准错误流. (命令行输出错误信息)
- System.in: 标准输入流. (键盘输入)
- 是InputStream类, 属于字节输入流
- System.out: 标准输出流. (控制台输出)
- 是OutputStream的子类PrintStream, 属于字节输出流
- 转换流
- InputStreamReader: 字节输入流转字符输入流
- 是Reader的子类, 属于字符输入流
- OutputStreamWriter: 字符输出流转字节输出流
- 是Writer的子类, 属于字符输出流
- 特点
- 转换流也是包装类, 需要传入实际的输入输出流对象
- 打印流
- PrintStream: 字节打印流
- PrintWriter: 字符打印流
- 注意
- 打印是输出操作, 所以打印流只有输出, 没有输入
- PrintWriter打印流的特点
- 可以自动换行, println(). 会根据系统自动确定换行符
- 不能输出字节, 可以输出其他任意类型(要输出字节需要使用PrintStream)
- 通过构造方法的配置可以实现自动刷新(flush)(只在调用println, printf, format时有用)
- 也是包装流, 自身没有写出功能
- 可以把字节输出流转换为字符输出流
- 关流不会抛出异常(此类中的方法不会抛出 I/O 异常,尽管其某些构造方法可能抛出异常)
- 方法
- 构造方法
- PrintWriter PrintWriter(String filepath)
- PrintWriter PrintWriter(Writer out, boolean autoFlush): 创建对象, 同时设置是否自动刷新
- PrintWriter(OutputStream out, boolean autoFlush): 创建对象, 同时设置是否自动刷新
- 成员方法
- void write(String s): 写一个字符串
- void print(String s): 输出字符串, 没有换行
- void println(String s): 输出字符串并换行. 如果启动了自动刷新, 则会执行自动刷新写入数据
- void printf(Locale l, String format, Object... args): 使用指定格式字符串和参数将格式化的字符串写入输出流. 如果启动了自动刷新, 则会执行自动刷新写入数据
- void format(Locale l, String format, Object... args): 使用指定格式字符串和参数将格式化的字符串写入输出流. 如果启动了自动刷新, 则会执行自动刷新写入数据
- 对象操作流
- 作用: 读写对象到文件
- ObjectInputStream: 对象输入流
- ObjectOutputStream: 对象输出流
- 注意
- 使用对象输出流写出对象到文件, 该文件只能使用对象输入流读取对象
- 只能将实现了java.io.Serializable接口的对象写入流中
- Serializable接口
- 标记接口, 用于标记该类可以序列化
- private static final long serialVersionUID: 序列版本号. 用于确定对象和类定义是否一致
- InvalidClassException用对象读取流时发生该异常的原因:
1. 该类的序列版本号与从流中读取的类描述符的版本号不匹配
2. 该类包含未知数据类型(即可能添加了新的成员变量或方法)
3. 该类没有可访问的无参数构造方法
- 方法
- 构造方法:
- ObjectOutputStream ObjectOutputStream(OutputStream out): 创建对象输出流
- ObjectInputStream ObjectInputStream(InputStream in): 创建对象输入流
- 成员方法
- void writeObject(Object o): 将对象写入对象输出流
- Object readObject(): 从对象输入流读取对象, 一次只读取一个对象. 当读不到时抛出EOFException.
- 读取对象异常的优化操作
- 在对象流中只保存一个对象, 通过该对象保存其他对象
- 比如用集合存储多个同类型的对象
- 定义一个类, 其中包含不同类型的其他类型对象
- Properties
- 继承Hashtable<K, V>, 实现Map<K, V>
- 作用: 以键值对方式保存信息到文本文件
- 应用场景: 作为程序的配置文件
- 注意
不能存null的键和值
- 只能保存英文字符和符号, 默认使用ISO-8859-1编码, 存中文会显示乱码
- 注意: 如果配置文件保存为.txt, 会变成GBK编码, 可以显示中文. 但一般都存为.properties, 使用ISO-8859-1, 显示不了中文
- 键和值都是字符串
- 方法
- 构造方法
- Properties Properties()
- 成员方法
- 可以使用Map的方法
- String getProperty(String key): 根据键获取值. 如果找不到该键, 则返回null
- String getProperty(String key, String defaultValue): 根据键获取值, 如果值不存在, 则使用指定的默认值
- void setProperty(String key, String value): 设置键值对
- void load(InputStream in): 从字节输入流中读取Properties
- void load(Reader reader): 从字符输入流中读取Properties
- void list(PrintStream out): 将Properties输出到指定的字节打印输出流. 会自动加一个-- listing properties --文件头
- void list(PrintWriter out): 将Properties输出到指定的字符打印输出流. 会自动加一个-- listing properties --文件头
- void store(Writer writer, String comments): 将Properties输出到指定的输出流, 并添加一个注释. 如果不想要注释可传null. 无论有没有注释, 都会添加时间字符串的注释
- void store(OutputStream os, String comments): 同上, 只是流不同
- list方法和store方法的区别
- list只能接收打印流(PrintStream, PrintWriter)
- store可以接收任何输出流(OutputStream, Writer)
- Properties读写操作步骤
- 写出到文件
- 创建Properties对象, 添加键值对, 使用list()或store()保存到文件中
- 从文件读取
- 创建Properties对象, 使用load()从文件加载数据, 使用getProperty()根据指定键获取值, 或使用遍历Map的方式遍历所有键和值
- 编码表
- 作用: 将计算机二进制数据转换为不同语言的字符
- 常见编码表
- ASCII: 美国标准码. 包含26个英文字母的大写和小写, 数字, 符号
- ISO-8859-1: 西方语言编码
- GB2312: 国标码
- GBK: 国标扩展码
- Unicode: 万国码. 支持多国语言字符.
- UTF-8: Unicode的一种实现方式, 长度可变的码表, 一个字符占用1个或2个字节
- ANSI: 本地编码表. 根据系统设置决定编码表
- Java String类对于字节和编码的操作
- byte[] getBytes(): 获取字符串的byte数组, 使用默认编码
- byte[] getBytes(String charsetName): 获取字符串的byte数组, 使用指定编码
- String String(byte[] bytes): 将byte数组转化为字符串, 使用默认编码
- String String(byte[] bytes, String charsetName): 将byte数组转换为字符串, 使用指定编码
- String String(byte[] bytes, int offset, int len, String charsetName): 将byte数组的一部分转换为字符串, 使用指定编码
- 乱码
- 原因: 读的编码与写的编码不一致
- 解决方法: 保证读和写的编码一致, 即可解决
- 处理乱码的2种方式:
1. String通过指定编码转为byte数组, 然后再创建String: (GBK字符串转UTF-8字符串写入文件)
- 先将String通过目标编码转为byte数组: byte[] bys = "月薪过万".getBytes("UTF-8");
- 再将byte数组转换为String: String str = new String(bys);
- 写入到文件: fw.write(str);
2. OutputStreamWriter可以指定编码写入文件, 免去使用String通过编码转换为byte数组的步骤
- OutputStreamWriter OutputStreamWriter(OutputStream out, String charsetName): 创建转换流对象, 并指定编码
多线程
- 概念
- 进程: Process, 一个应用程序在内存中的执行区域
- 线程: Thread, 进程中的一条执行路径
- 并发: 并行发生, 同时发生, 多线程就可以实现并发
- 同步: 注意并不是同时的意思, 同步是指一步接一步的执行, 一个执行完毕再开始执行下一个. 单线程就是同步
- 异步: 不是一步一步执行, 而是同时执行多步, 每个步骤何时结束不确定. 多线程就是异步
- 阻塞: 上一行代码正在执行, 还没有执行完毕, 程序就阻塞在这里了, 下一行代码必须等上一行不再阻塞后才能执行
- 单线程和多线程的特点
- 单线程: 同一时间只做一件事, 安全性高, 效率低
- 多线程: 同一时间做多个事情, 安全性低, 效率高
- 多线程的实现方式
1. 继承Thread类, 重写run方法
2. 实现Runnable接口(仍然是创建Thread类对象), 重写run方法
- java.lang.Thread类: 实现了Runnable接口
- 构造方法
- Thread Thread(): 创建Thead对象
- Thread Thread(Runnable r): 通过Runnable对象创建Thread对象
- Thread Thread(Runnable r, String threadName): 通过Runnable对象创建Thread对象并指定线程名
- 成员方法
- void start(): 启动线程, 即让线程开始执行run()方法中的代码
- String getName(): 获取线程的名称
- void setName(String name): 设置线程名称
- 静态方法
- static Thread currentThread(): 返回对当前正在执行的线程对象的引用
- static void sleep(long millis): 让所在线程睡眠指定的毫秒
- 多线程中的常见问题
1. 资源共享: 卖票问题
- 共享资源定义位置: 共享资源要定义在多个线程能够共同使用的地方, 如:
- 多个Thread共用同一个Runnable实现类对象, 则定义为Runnable实现类的非静态成员变量
- 如果只用Thread子类, 则可以定义为Thread子类的静态成员变量
- 操作共享数据的线程安全问题: 使用同步解决
- 同步代码块
- synchronized (锁对象) {}
- 锁对象
- 必须是多个线程共享的对象:
- 一个类的Class对象
- 如果是实现Runnable, 则可以是this
- 同步方法
- public (static) synchronized void method() {}
- 锁对象
- 静态同步方法, 锁对象是: 方法所在类的Class对象
- 非静态同步方法, 锁对象是: this
网络编程总结
- Socket
- 套接字
- 用于描述IP地址和端口, 是一种网络编程机制, 通信的两端都会有Socket
- 网络通信3要素
- 传输协议
- IP地址
- 端口号
- 常见通信协议
- UDP
- 它是一种无连接的不可靠协议
- 数据传输大小限制为64K(一个包)
- 不需要建立连接即可传输
- 数据发送速度快, 发送方只发送数据, 不检查接收方是否真正接收到数据, 所以数据有丢包的情况
- 这种方式适合实时性要求强的场合, 比如网络电话, 网络游戏等环境, 这种协议延迟很小
- TCP
- 它是一种需要建立连接的可靠协议
- 没有数据传输大小的限制
- 在传输前需要先建立连接(三次握手)
- 它的重发机制保证了数据传输的准确性, 但因为需要接收方发回验证信息, 所以数据发送时间长, 数据流量大
- 这种方式适合准确性要求强的场合, 比如金融系统, 视频点播, 用户可以等待数据传输但是不能忍受错误
- java.net.InetAddress类: 用于表示IP地址对象, 可以获取主机名, IP地址等信息
- 静态方法
- static InetAddress getLocalHost(): 获取本机的InetAddress对象
- static InetAddress getByName(String host): 根据主机名或IP的字符串获取主机的InetAddress对象
- static InetAddress getLoopbackAddress(): 获取回环地址的InetAddress对象
- 成员方法
- String getHostAddress(): 返回主机的IP地址
- String getHostName(): 返回主机名
- UDP相关类
- java.net.DatagramSocket类: 基于UDP协议的Socket
- 构造方法
- DatagramSocket(): 创建DatagramSocket对象, 随机分配端口号
- DatagramSocket(int port): 创建DatagramSocket对象, 指定端口号
- 成员方法
- void send(DatagramPacket p): 发送数据包
- void receive(DatagramPacket p): 接收数据, 数据保存在DatagramPacket对象中
- void close(): 关闭通信, 释放资源
- java.net.DatagramPacket类: UDP数据包
- 构造方法
- DatagramPackage(byte[] msg, int msgLength, InetAddress host, int port): 创建数据包对象, 指定数据, 目标主机对象, 端口
- DatagramPacket(byte[] buf, int length): 创建数据包对象, 接收数据为length的数据, 存入byte数组中
- 成员方法
- byte[] getData(): 获取包中的数据, 以byte数组形式
- int getLength(): 获取数据包中数据的长度, 即byte数组的长度
- int getPort(): 获取发送方端口号
- InetAddress getAddress(): 获取数据包发送方的InetAddress对象
- TCP相关类
- java.net.Socket类: 基于TCP协议的Socket
- 构造方法
- Socket(InetAddress add, int port)
- 成员方法
- OutputStream getOutputStream(): 获取输出流对象, 用于发送数据
- InputStream getInputStream(): 获取输出流, 即接收数据
- void close(): 释放资源
- java.net.ServerSocket: TCP服务端
- 构造方法
- ServerSocket(int port)
- 成员方法
- Socket accept(): 监听数据, 会阻塞. 收到数据后返回Socket对象
- void close(): 关闭Socket
- UDP收发数据步骤
- 发送端
1. 为发送端创建Socket对象(DatagramSocket):
- DatagramSocket udp = new DatagramSocket();
2. 创建数据并打包:
- DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port);
3. 发送数据:
- DatagramSocket对象的void send(DatagramPackage p)
4. 释放资源:
- DatagramSocket对象的void close()
- 接收端
1. 创建接收端Socket对象:
- DatagramSocket DatagramSocket(int port)
2. 接收数据
- 创建包对象: DatagramPacket datagramPackage(byte[] buf, int length)
- 接收包: DatagramSocket对象的void receive(DatagramPacket p), 该方法会阻塞等待接收数据
3. 解析数据
- 获取发送端信息
- DatagramPacket对象的InetAddress getAddress(): 获取客户端
- DatagramPacket对象的byte[] getData(): 获取数据
- DatagramPacket对象的int getLength(): 获取数据长度
4. 输出数据
5. 释放资源:
- DatagramSocket对象的void close()
- TCP收发数据步骤
- 客户端
1. 创建客户端Socket对象(建立连接):
- Socket Socket(InetAddress add, int port)
2. 获取输出流对象:
- Socket对象的OutputStream getOutputStream()
3. 发送数据:
- OutputStream对象的void write(byte[] b)
4. 释放资源:
- OutputStream对象的close()
- Socket对象的close()
- 服务端
1. 创建服务端ServerSocket对象:
- ServerSocket ServerSocket(int port)
2. 监听数据:
- ServerSocket对象的Socket accept(), 获取客户端Socket对象
- 监听时是阻塞的
3. 获取输入流对象:
- Socket对象的InputStream getInputStream()
4. 获取数据:
- InputStream对象的int read(byte[] buf)
5. 输出数据:
- 将获取的字节数组转换为String打印输出
6. 释放资源:
- Socket对象的void close()方法
- ServerSocket对象的void close()方法
反射总结
- 反射
- 概念: 在程序运行时, 获取任何一个类的所有属性和方法(包括私有的). 调用任意一个对象的所有属性和方法(包括私有的)
- 前提:
- 获得字节码对象
- 获取字节码对象的3种方法
1. 对象.getClass()
2. 类名.class
3. Class.forName(String fullClassName)
- 反射能干的事
- 获取一个类的字节码对象, 通过该字节码对象:
- 获取一个类的构造方法(public或全部权限的)
- 创建一个类的对象
- 获取一个类的成员属性(public或全部权限的)
- 获取属性值
- 设置属性值
- 获取一个类的成员方法(public或全部权限的)
- 调用成员方法
- 反射使用的相关类和方法
- java.lang.Class类: 类的字节码对象
- 获取构造方法
- Constructor<?>[] getConstructors(): 以数组形式返回该类中所有public的构造方法. 如果没有public的, 则数组长度为0
- Constructor<?>[] getDeclaredConstructors(): 以数组形式返回该类中所有权限的构造方法, 包括private的. 如果该类是接口, 基本类型, 数组, void, 则数组长度为0
- Constructor<T> getConstructor(Class<?>... parameterTypes): 根据参数列表返回指定的public的构造方法. 参数列表填写参数的字节码对象
- Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes): 根据参数列表返回指定的所有权限的构造方法, 包括private的. 参数列表填写参数的字节码对象
- 获取成员属性
- Field[] getFields(): 获取所有public的成员变量
- Field[] getDeclaredFields(): 获取所有权限的成员变量, 包括private的
- Field getField(String fieldName): 通过指定的成员变量名获取指定的public的成员变量
- Field getDeclaredField(String fieldName): 通过指定的成员变量名获取指定的所有权限的成员变量, 包括private的
- 获取成员方法
- Method[] getMethods(): 返回所有public的方法数组
- Method[] getDeclaredMethods(): 返回所有权限的方法数组
- Method getMethod(String name, Class<?>... parameterTypes): 获取public的方法, 传入方法名和方法形参字节码对象
- Method getDeclaredMethod(String name, Class<?>... parameterTypes): 获取所有权限的指定方法, 传入方法名和方法形参字节码对象
- 创建对象
- T newInstance(): 使用该类的无参构造创建一个对象
- java.lang.reflect.Constructor类: 构造方法对象
- T newInstance(): 通过无参构造方法对象创建一个类的对象
- T newInstance(Object... initargs): 通过有参构造方法对象创建一个类的对象, 传入构造方法所需的参数列表
- void setAccessible(boolean canAccess): 设置为true时禁用Java的访问安全检查, 可以访问所有权限的构造方法
- java.lang.reflect.Field类: 成员变量对象
- Object get(Object obj): 获取指定对象的属性值
- void set(Object obj, Object value): 将指定对象的属性值设置为指定的值
- void setAccessible(boolean canAccess): 设置为true时禁用Java的访问安全检查, 可以访问所有权限的成员属性
- java.lang.reflect.Method类: 成员方法对象
- Object invoke(Object obj, Object... args): 调用指定对象的成员方法
- void setAccessible(boolean canAccess): 设置为true时禁用Java的访问安全检查, 可以访问所有权限的成员方法
- JavaBean
- 就是一个类
- 作用: 用于封装和存储数据
- 规范
- 类必须是public修饰的
- 成员变量必须是private的
- 必须有public的set/get方法
- 至少提供一个无参构造方法
- 实现Serializable接口(当对象需要通过IO流传输时)
- Jar包
- Java ARchive, 后缀名为.jar, 是一个压缩文件, 里面包含编译后的class文件和说明信息
- 作用: jar包中是写好的代码编译出来的class文件, 有了这些类文件, 就可以调用其中的方法
- 导入jar包的步骤
- 项目根目录下创建名为lib的目录
- 复制jar文件, 粘贴到项目根目录下的lib目录下
- 选中项目中的jar包, 右键, 选择Build Path, 点击Add to Build Path. 此时项目中的Referenced Libraries中会出现jar包名称的奶瓶, 说明已经添加成功
- 导入的jar包整个项目都能使用
- BeanUtils
- Apache组织提供的第三方类库Commons中的一个组件
- 作用:
- 利用反射技术给一个类的对象的成员属性赋值或获取值, 用于快速封装数据到JavaBean
- BeanUtils类常用的3个方法
- static void setProperty(Object bean, String name, Object value): 给JavaBean对象的成员属性赋值, 传入对象, 成员属性名, 属性值
- static String getProperty(Object bean, String name): 获取JavaBean成员属性的属性值, 传入对象, 成员属性名, 返回属性值的字符串形式
- static void populate(Object bean, Map properties): 给JavaBean对象的成员属性赋值, 传入对象, Map的key是属性名, value是属性值
|
|