List的子类
常见的有:ArrayList、LinkedList
ArrayList
特点
- 底层是数组
- 查找快
- 增删慢
- 不同步、效率高
补充
因为ArrayList可以一直存储内容,所以ArrayList是会自己扩容。
那么什么地方能触发这个扩容?应该是在添加的时候(因为不添加,就永远不会超过这个容量)
在添加方法add中我们找到了int newCapacity = oldCapacity + (oldCapacity >> 1);
这是在ArrayList长度不够用的时候,会将容量扩容为1.5倍。
如果要是存的内容过多,那么可以直接使用ensureCapacity(int minCapacity)手动扩容
LinkedList
- 底层是列表
- 查找慢
- 增删快
- 不同步、效率高
特有方法
void addFirst(E e); //指定元素插入到开头
void addList(E e);//指定元素插入到结尾
Object getFirst();//获取第一个元素
Object getLast();//获取最后一个元素
Object removeFirst();//删除且返回第一个元素
Object removeLast();//删除且返回最后一个元素
泛型
泛型就是模仿数组的做法,在创建对象的时候就声明好了一个类型
泛型是一种特殊化的类型,它将类型的声明推迟到了客户端创建对象或者方法的时候。
泛型是一种参数化的类型,它可以当作参数传递,在使用之前我们不知道是什么类型,但是在所有的时候就知道。
格式:
<泛型>
注意:泛型类型只能是引用数据类型,一般被声明为K V E T
泛型类
修饰符 class 类名<泛型1,泛型2>{
}
好处
- 省去了类型强制转换的麻烦
- 将运行时期的异常提前到编译过程中(类型强制转换)
泛型方法
修饰符 <参数类型> 返回值类型 方法名(参数列表){
}
package top.zunmx.d1;
// ALC-Master
class ObjectTool<TYPE> {
public <关晓彤, T> void test(关晓彤 gxt, T a) {
System.out.println("hello test:" + gxt + "---" + a);
}
}
public class FanXingFunc {
public static void main(String[] args) {
ObjectTool ot = new ObjectTool();
ot.test("gxt-String", 5); // 和声明object效果一样呀
ot.<String, Integer>test("world", 3);
ot.<Integer>test(123456, 2);
}
}
泛型通配符
?
? extends
? super T
Set接口
元素不能重复的Collection
元素不保证有序
set的遍历方式
- toArray
- toArray(T[] a)
- iterator
- 增强for
HashSet
不保证元素的有序性,可以存null值
不同步所以效率较高
HashSet保证元素唯一性的原理
HashSet存储Java官方自带的类---可以去重
HashSet存储自定义类的重复性---没有去重
思考过程:
- 因为这些对象都是new创建出来的,地址都是不一样的,所以认为是不同的对象可以存入。所以我们重写重写equals方法(equals方法保证只要内容相同,就是同一个对象)重写之后发现并没有调用equals方法。
- 再想HashSet应该和hash有关(之前见过hashcode方法),那么重写hashcode方法,看是否能够去重。(相同的对象hashCode一定相同)我们可以先将重写的hashCode方法都统一返回一个同一个值(相当于对象的hashCode值相同了),去重了。
结论:在存入一个元素之前,先比较hashCode值是否相同,如果hashCode值不同,那么就当作是不同的对象,直接存入,如果hashCode值相同,那么此时不一定是同一个对象,还需要通过equals来比较内容是否相同,如果内容不同,那就是不同的对象,可以直接存入,如果内容相同,那么就认为是同一个对象。就不能存入了
hashCode方法
- 同一对象多次调用hashCode方法时,必须一致地返回相同的整数
- 如果两个对象相等,那么每个对象调用hashCode方法都必须生成相同的整数结果。
- 如果两个对象不相等,那么对这两个对象的任一对象上调用hashCode方法不要求一定生成不同的整数结果,但是为了性能考虑,一般都会生成不同的整数结果。
LinkedHashSet
具有可预知迭代顺序,也就说保证了元素插入的有序性。
不同步,所以效率较高
Vector
底层是数组,查找快,增删慢
不同步,效率较高
Map
双列集合
Collection 和 Map 区别:Collection是单列的集合,可以存储有序或者无须,可以重复,也可以不重复。可以一次存入两个元素,这两个分别叫做Map的键Key和值Value对。
常用方法
添加功能
V put(K key ,V value);
// 注意:如果存在,则替换
// 向Map集合中添加一个键值对,如果键已经存在,那么此键已经存在了,那么此键对应的值会被覆盖掉。返回值为被替换的值。
Map<String,String> map = new HashMap<>();
map.put("杨过", "小龙女");
map.put("郭靖", "黄蓉");
map.put("浩克", "黑寡妇");
删除功能
void clear(); //从映射表中移除所有的映射关系
V remove(Object key);//从此映射中移除指定键的映射关系(如果存在)。
Map<String, String> map = new HashMap<>();
map.put("9527", "华安");
map.put("9528", "我为什么站起来了");
map.put("9529", "曹达华");
String value = map.remove("9529");
System.out.println(value);
System.out.println(map);
判断功能
boolean containsKey(Object key) ;
// 如果此映射包含对于指定键的映射关系,则返回 true。
boolean containsValue(Object value) ;
// 如果此映射将一个或多个键映射到指定值,则返回 true。
Map<String,String> map = new HashMap<>();
map.put("杨过", "小龙女");
map.put("郭靖", "黄蓉");
map.put("浩克", "黑寡妇");
System.out.println(map.containsKey("浩克"));
System.out.println(map.containsKey("傻子"));
System.out.println(map.containsValue("小龙女"));
System.out.println(map.containsValue("傻子"));
获取功能
int size() ;
//返回此映射中的键-值映射关系数。
boolean isEmpty() ;
//如果此映射不包含键-值映射关系,则返回 true
V get(Object key);
//返回指定键所映射的值;如果对于该键来说,此映射不包含任何映射关系,则返回 null。
遍历方式
- 方式1
Set<K> keySet() ;
// 返回此映射中所包含的键的 Set 视图。
V get(Object key);
//返回指定键所映射的值;如果对于该键来说,此映射不包含任何映射关系,则返回 null。
Map<String, String> map = new HashMap<>();
map.put("张幼仪", "徐志摩");
map.put("林徽因", "徐志摩");
map.put("陆小曼", "徐志摩");
map.put("黄蓉", "郭靖");
map.put("迪丽热巴", "李大壮");
Set<String> set = map.keySet();
for (String key : set) {
System.out.println(key + "\t<==>\t" + map.get(key));
}
System.out.println("<------------------>");
Iterator<String> it = set.iterator();
while(it.hasNext()) {
String key = it.next();
System.out.println(key + "\t<==>\t" + map.get(key));
}
- 方式2
Set<Map.Entry<K,V>> entrySet() ;
// 返回此映射所包含的映射关系的 Set 视图。
Map<String, String> map = new HashMap<>();
map.put("张幼仪", "徐志摩");
map.put("林徽因", "徐志摩");
map.put("陆小曼", "徐志摩");
map.put("黄蓉", "郭靖");
map.put("迪丽热巴", "李大壮");
Set<Entry<String, String>> entrySet = map.entrySet();
for (Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey()+"\t<==>\t"+entry.getValue());
}
流程
- 创建集合对象
- 向集合对象中插入元素
HashMap
可以存入null键和null值的
不同步,所以效率高
HashMap唯一性
- HashMap的键如果是官方提供的类,那么呢个保证键的唯一性
- HashMap的键如果是自定义类,那么不能保证键的唯一性,必须要对这个自定义类进行equals和hashCode进行重写,才可以保证键的唯一性
注意:
在Java中0开头的数字代表8进制 如007合法 008不合法
在Java中0x开头的数字代表16进制 如0xff合法 0xfg不合法
HashMap和HashSet关系
HashSet中的Add方法实际上是使用HashMap的put方法,并且是Put方法的键,值为new Object
LinkedHashMap
具有可预知的迭代顺序
LinkedHashMap<String, String> lhm = new LinkedHashMap<>();
lhm.put("1杨过", "小龙女");
lhm.put("3郭靖", "黄蓉");
lhm.put("md", "1w");
lhm.put("2浩克", "黑寡妇");
Set<Entry<String, String>> entrySet = lhm.entrySet();
for (Entry<String, String> entry : entrySet) {
System.out.println(entry);
}
Collections工具类
static int binarySearch(List list, Tkey);
static int frequency(Collection ,Object o); // 元素出现的频率
static T max(Collecton coll);
static T min(Collecton coll);
static boolean replaceAll(List list,T oldVal, T newVal);
static void reverse();
static void shuffled(List list);
static void sort(List list);
异常
Java中可以解决的叫做异常Exception,解决不了的叫做错误error
graph LR
A[Throwable]-->B[Error]
B-->E[子类]
A-->C[Exception]
C-->D[RuntimeException]-->G[子类]
C-->F[编译时异常]-->H[子类]
Java中默认的异常处理
遇到一个问题,如果我们不解决的话,Jvm虚拟机会自动帮我们解决。虚拟机会将遇到问题的异常类名和错误内容以及具体位置给打印在控制台上。并结束程序
Java中手动处理异常
手动处理异常有两种方案
try---catch
throws ...
/*格式1*/
try{
可能会出现异常的代码;
}catch(异常类名 异常对象名){
接收到异常之后进行解决;
}
/*格式2*/
try{
可能会出现异常的代码;
}catch(异常类名 异常对象名){
接收到异常之后进行解决;
}catch(异常类名 异常对象名){
接收到异常之后进行解决;
}
catch(异常类1 | 异常类2 | ... e) // 缩小范围
注意事项:
- try是尝试的意思,里面放的是可能会出现异常的代码,但是这个代码一定要尽可能地少。
- catch 是捕获的意思,它会捕获try遇到的异常对象,并且进行处理
- jdk7以后开始出现异常解决方案
- catch中的异常必须是平级的
- 一般用这种格式处理相似类型的异常进行统一处理
编译时异常和运行时异常
运行时异常:代码运行之后才出来的异常,这种异常都是RuntimeException的子类。这样的异常不需要通过异常解决方案来处理(手动处理) 只需要认真一点就可以解决了。
编译时异常:在IDE代码编辑界面时就报错的异常,这种异常都是除了RuntimeException之外的所有的Exception的子类,这种编译时异常一定要手动处理
Throwable常见方法
String getMessage();//返回此 throwable 的详细消息字符串。
String toString();//返回此 throwable 的简短描述。
void printStackTrace();// 将此 throwable 及其追踪输出至标准错误流。
throws关键字
写一个方法,里面可能有一些错误,这些错误我们需要让方法的使用者知道,而在Java让在方法的使用者知道的方式就是通过throws 关键字.【方法的声明者】
//格式:
修饰符 返回值类型 方法名(参数列表) throws 异常类名,异常类名2...{
}
注意:
- throws是用在方法声明上,并且是放在方法声明的最后面
- throws后面跟的是异常类名,可以跟多个
- throws只是代表了可能会出现这个问题(也就是说可能出现,也可能不出现)
- 一般不要在main方法中throws
我们使用的方法有时会有一些异常,这些异常有的我们可以解决,有的我们不能[没有权限、资格]解决。我们可以使用throws抛出去。后续方法的调用者会处理这个异常(也就是说我们不解决,可以通过throws让别人来解决)
throw关键字
throw关键字是用来制造异常
格式:
throw new 异常类名();
throw new ArrayIndexOutOfBoundsException();
throws 和 throw区别
| throw | throws |
|---|---|
| 一定会发生异常 | 有可能会发生异常 |
| 用在方法中的 | 用在方法声明上 |
| throw后面跟着异常对象名,只能有一个 | 后面跟的是类名,可以跟多个 |
finally关键字
格式
try{
}catch(){
}finally{
}
finally中的代码一定会执行,通常finally中放的都是关闭IO流,数据库对象等操作。
final\finally\finalize区别
- finally 通常结合try--catch来使用,放在finally中的内容一定会执行
- final可以修饰类、方法、变量
- 类:不能被继承
- 方法:不能被重写
- 修饰变量:变量变成了常量
- finalize 和垃圾回收相关的方法
异常
自定义异常
异常时Java官方定义好的一些类,这类时堆一些常见问题进行的解释,但是还有一些问题,比如家里的小孩成绩考了160,这明显不合理,这种异常官方肯定没有,只能自己来定义这样的异常。要想自定义异常肯定要使这和异常体系产生关联性,所以需要使用继承。
编译时异常:除了RuntimeException 之外的其它Exception子类
运行时异常:RuntimeException 的子类
File类
文件和目录路径名的抽象表示形式
路径:路径就是文件或文件为值的字符串表示形式
构造方法
File(File parent, String child) ;
// 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
File(String pathname) ;
//通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
File(String parent, String child) ;
//根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
File f = new File("z:\\a\\a.txt");
System.out.println(f);
File f1 = new File("z:\\");
File f2 = new File(f1,"a\\a.txt");
System.out.println(f2);
File f3 = new File("z:\\","a\\a.txt");
System.out.println(f3);
常见方法
创建功能
boolean createNewFile() ;
//当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。
boolean mkdir() ;
//创建此抽象路径名指定的目录。
boolean mkdirs() ;
// 创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。
File f = new File("z:/a/hello.java");
try {
if (f.createNewFile()) {
System.out.println("[√]文件创建成功");
} else {
System.out.println("[×]文件创建失败");
}
} catch (IOException e) {
System.out.println("[!]文件创建失败---exception");
}
File f1 = new File("z:/a/b");
if(f1.mkdir()) {
System.out.println("[√]文件夹创建成功");
}else {
System.out.println("[×]文件夹创建失败");
}
File f2 = new File("z:/a/b/c/d/e/f");
if(f2.mkdirs()) {
System.out.println("[√]文件夹组创建成功");
}else {
System.out.println("[×]文件夹组创建失败");
}
删除功能
boolean delete() ;
// 删除此抽象路径名表示的文件或目录。
//如果删除文件夹,里面有文件就删除不了,只能删除空文件夹
判断功能
boolean isAbsolute();
// 测试此抽象路径名是否为绝对路径名。
boolean isDirectory();
// 测试此抽象路径名表示的文件是否是一个目录。
boolean isFile();
// 测试此抽象路径名表示的文件是否是一个标准文件。
boolean isHidden();
// 测试此抽象路径名指定的文件是否是一个隐藏文件
boolean canRead();
// 测试应用程序是否可以读取此抽象路径名表示的文件。
boolean canWrite();
// 测试应用程序是否可以修改此抽象路径名表示的文件。
重命名功能
boolean renameTo(File dest);
//重新命名此抽象路径名表示的文件。 如果路径不同就是移动操作
//如果是同级目录下会重命名
//如果不是同级目录,会重命名且移动
File f = new File("Z:/a/hello.java");
File ff = new File("Z:/a/b/1.java");
f.renameTo(ff);
获取功能
String getName() ;
// 返回由此抽象路径名表示的文件或目录的名称
String getPath() ;
// 将此抽象路径名转换为一个路径名字符串。
File getAbsoluteFile() ;
// 返回此抽象路径名的绝对路径名形式。
String getAbsolutePath() ;
// 返回此抽象路径名的绝对路径名字符串。
long length() ;
// 返回由此抽象路径名表示的文件的长度。
String[] list() ;
// 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
File[] listFiles() ;
// 返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
long lastModified();
// 返回此抽象路径名表示的文件最后一次被修改的时间。
IO流
I=input O=output
Java中把输入和输出抽象成了“流”的概念,并将相关的类都放在IO包中。这个输入输出也就是读取和写入。
对于内存来说:只要是进内存的,都是一个写数据(输入),只要是出内存,就是输出。
对于具体使用来说:可以针对Java程序来说,那就是从别的地方到Java程序就是读取(输入),从Java程序到别的地方就是写入(输出)
分类
- 按照流向
- 输入流
- 字节输入流
- 字符输入流
- 输出流
- 字节输出流
- 字符输出流
- 按照数据类型
- 字节流
- 字节输入流
- 字节输出流
- 字符流
- 字符输入流
- 字符输出流
如何选择流?
如果用电脑的记事本打开能看得懂,那么就用那么就用字符流
如果打开什么都看不懂就用字节流
IO流的抽象基类
字节流:
字节输入流:InputStream
字节输出流:OutputStream
字符流:
字符输入流:Reader
字符输出流:Writer
注意:
所有字节流的子类的后缀都是InputStream和OutputStream结尾的。
所有字符流的子类的后缀都是Reader和Writer结尾的。
字节流
文件字节输出流 FileOutputStream
构造方法
FileOutputStream(File file) ;
//创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String name) ;
//创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(File file, boolean append) ;
//创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String name, boolean append) ;
//创建一个向具有指定 name 的文件中写入数据的输出文件流。
System.out.println("构造1:");
FileOutputStream fos = new FileOutputStream(f);
System.out.println(fos);
System.out.println("构造2:");
FileOutputStream fos2 = new FileOutputStream("z:/a.txt");
System.out.println(fos);
常见方法
void write(byte[] b);
// 将 b.length 个字节从指定 byte 数组写入此文件输出流中。
void write(byte[] b, int off, int len) ;
// 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
// off 为偏移量,可以认为是索引,但是一定要注意编码。
void write(int b) ;
// 将指定字节写入此文件输出流。
// 1.create IO Stream object
FileOutputStream fos = new FileOutputStream("text.txt");
// 2.use write function
byte[] bys = { 97, 98, 99 };
String str = "\r\nThis is demo string 中国.\r\n";
fos.write(bys);
fos.write(str.getBytes());
fos.write(str.getBytes(), 22, 4);
fos.close();
总结:
- 输出流是不用先创建文件,会在写入文件的时候,帮助我们新建一个文件。
- 使用IO流的书写步骤
- 创建FOS对象(导包)
- 使用write/read方法进行写入/读取
- 使用close关闭流
字节输出流中遇到的几个小问题:
如何换行
windows 默认换行:\r\n
Linux默认换行:\n
MacOS默认换行:\r
如何追加
使用FileOutputStream构造方法的第二个参数,true代表追加
文件字节输入流
FileInputStream 从文件系统中的某个文件中获得输入字节。
FileInputStream 用于读取诸如图像数据之类的原始字节流。
构造方法
FileInputStream(File file) ;
//通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
FileInputStream(String name) ;
//通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
常见方法
int read() ;
// 从此输入流中读取一个数据字节。
int read(byte[] b) ;
// 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
注意:read() 返回值-1时代表无法读取,一般都是到头了。
package top.zunmx.d2;
import java.io.FileInputStream;
import java.io.IOException;
// ALC-Master
public class IO1 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("read.txt");
/* v1 */
// int r = fis.read();
// System.out.print((char)r);
// r = fis.read();
// System.out.print((char)r);
// r = fis.read();
// System.out.print((char)r);
// r = fis.read();
// System.out.print((char)r);
// r = fis.read();
// System.out.print((char)r);
/* v2 */
int read = -1;
while ((read = fis.read()) != -1) {
System.out.print((char) read);
}
fis.close();
}
}
FileInputStream fis = new FileInputStream("read.txt");
byte[] b = new byte[8]; // 一次读取一个数组
/*
* 其中返回值为内容的长度。 真正的数据是数组b,而返回值read是存入数组的长度。
*/
int read = -1;
while ((read = fis.read(b)) != -1) {
// System.out.println(read);
System.out.print(new String(b, 0, read)); }
文件的拷贝
拷贝就是将一个文件从一个地方复制到了另一个地方。
IO流可以实现以上操作。
拷贝的过程:
- 从源文件中读取文本内容到流中
- 从流中读取内容写入到目标文件中
总结:也就是说先用输入流读,再用输出流写
package top.zunmx.d3;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
// ALC-Master
public class P1 {
public static void main(String[] args) throws IOException {
File f = new File("z:/ord");
FileInputStream fis;
FileOutputStream fos;
FileOutputStream fos2;
File[] listFiles = f.listFiles();
for (File file : listFiles) {
fis = new FileInputStream(file);
fos = new FileOutputStream("z:/new2one/" + file.getName());
int b = 0;
while ((b = fis.read()) != -1) {
fos.write(b);
}
fis = new FileInputStream(file);
fos2 = new FileOutputStream("z:/new2[1024]/" + file.getName());
byte[] b2 = new byte[1024];
int len = -1;
while ((len = fis.read(b2)) != -1) {
fos2.write(b2, 0, len);
}
}
}
}
字节缓冲流
通过代码我们发现,一次读写一个字节数组的效率明显比一次读写一个字节高很多,就是因为数组起到了作用。Java中有类似的解决方法,就是字节缓冲流。字节缓冲流实在内部维持了一个数组。
字节缓冲输出流BufferedOutputStream
该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
构造方法
BufferedOutputStream(OutputStream out) ;
// 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size) ;
// 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。
常见方法
void flush() ;
// 刷新此输出流并强制写出所有缓冲的输出字节。
void write(byte[] b) ;
// 将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[] b, int off, int len) ;
// 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
abstract void write(int b) ;
// 将指定的字节写入此输出流。
字节缓冲输入流BufferedInputStream
构造方法
BufferedInputStream(InputStream in) ;
//创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
BufferedInputStream(InputStream in, int size) ;
//创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
常见方法
int read();// 一次读取一个字节
int read(byte[]b);// 一次读取一个字节数组
// 真正的数据是存储在数组中的,返回值是每次存入数组中数据的长度
速度顺序
1.没有缓冲的一次读写一个字节
3.没有缓冲的一次读写一个字节数组
2.有缓冲的一次读写一个字节
4.有缓冲的一次读写一个字节数组
一个IO流的标准写法
所谓标准写法也就是加上了try---catch异常处理
package top.zunmx.d3;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
// ALC-Master
public class end {
public static void main(String[] args) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream("text.txt"));
bos = new BufferedOutputStream(new FileOutputStream("new.txt"));
// 一次读写一个字符数组,带缓冲的字节流.
byte[] b = new byte[1024];
int len = 0;
while ((len = bis.read(b)) != -1) {
bos.write(b, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}

评论 0
还没有评论,来说点什么吧。