进阶语法
集合
TODO 集合
生活中也有集合的概念。是一个动词
Java中的集合是一个名词,数据的一种容器,用于容纳数据
Java提供了完整的集合框架
TODO 问题:什么时候需要一个容纳数据的容器,也就是集合对象?
Java集合框架中就包含了对不确定个数的数据处理的集合类
TODO 问题:如果只是为了容纳数据,可以是直接使用数组,为什么要学习集合?
数组使用起来不方便。在数据个数不确定的场合,数组使用起来不是很方便
TODO 总结:对不确定的有关系的数据进行相同的逻辑处理的场合,使用集合是一个不错的选择
TODO 根据数据的不同,Java的集合分为2大体系:
1. 单一数据体系 : Collection接口定义了相关的规则
2. 成对出现的数据体系 : Map接口定义了相关的规则
所谓的成对的数据,就是2个数据有关系,可以根据第一个数据关联到第二个数据
也称之为键值对数据 ,(123123, zhangsan) => (key, value)
容器类
1. Collection接口
常用的子接口
List :按照插入顺序保存数据,数据可以重复的
具体的实现类: ArrayList, LinkedList
Set : 集,无序保存,数据不能重复
具体的实现类 HashSet
Queue : 队列
具体的实现类:ArrayBlockingQueue
2. Map接口
具体的实现 : HashMap, Hashtable
集合 - Collection - List
TODO 集合 - Collection - List
ArrayList : Array + List
TODO List : 列表,清单
按照数据插入顺序进行存储
TODO Array : 数组,阵列
TODO 创建第一个集合对象:ArrayList
ArrayList list = new ArrayList(3);
1. 不需要传递构造参数,直接new就可以,底层数组为空数组
2. 构造参数需要传递一个int类型的值,用于设定底层数组的长度
3. 构造参数需要传递一个Collection集合类型的值,用于将其他集合中的数据放置在当前集合中
TODO 增加数据
add方法可以增加数据,只要将数据作为参数传递到add方法即可
添加数据时,如果集合中没有任何的数据,那么底层会创建长度为10的数组
list.add("zhangsan");
TODO 访问集合中的数据
获取集合中数据的条数
System.out.println(list.size());
获取指定位置的数据,可以采用索引的方式
System.out.println(list.get(1));
遍历集合中的数据
for ( int i = 0; i < list.size(); i++ ) {
System.out.println("集合中的数据:" + list.get(i));
}
TODO 如果循环遍历集合数据时,不关心数据的位置,那么可以采用特殊的for循环
for (循环对象:集合) {}
for ( Object obj : list ) {
System.out.println("集合中的数据:" + obj);
}
TODO 修改数据
将指定位置的数据进行修改,set方法需要传递2个参数,第一个参数表示数据的位置,第二个参数修改的值。
方法会返回结果,这个结果就是更新前的值
Object oldVal = list.set(1, "lisi");
System.out.println("修改前的值:" + oldVal);
TODO 删除数据
将指定位置的数据进行删除,remove方法需要传递1个参数,参数表示数据的位置。
方法会返回结果,这个结果就是删除的值
Object removeVal = list.remove(1);
System.out.println("删除的值:" + removeVal);
TODO 打印集合对象
System.out.println(list);
ArrayList的常用方法
add方法可以传递2个参数的,第一个参数表示数据增加的位置(索引),第二个参数表示数据
list.add(1, "zhaoliu");
把另外一个集合加入到该集合里面: list.addAll( otherList );
size方法表示集合内部数据的数量
System.out.println(list.size());
清空集合中的数据(全都不要,和removeall不同)
list.clear();
删除 指定 集合中的数据
list.removeAll(otherList);
判断集合中的数据是否为空
System.out.println(list.isEmpty());
用于判断集合中是否存在某条数据,返回布尔类型的值
System.out.println(list.contains("zhangsan123"));
用于获取数据在索引中的第一个位置,如果数据不存在,那么返回-1
System.out.println(list.indexOf("zhangsan123"));
复制新集合
Object[] objects = list.toArray();
Object clone = list.clone();//克隆出来的集合里面内容相同,但是数组类型为空,故需强转成ArrayLIst
ArrayList list1 = (ArrayList)clone;
LinkedList : Linked(连接) + List
LinkedList : Linked(连接) + List
构建集合对象
LinkedList list = new LinkedList();
增加第一个数据
list.addFirst("lisi"); //增加第一个数据
list.add(1, "wangwu");
TODO 获取数据
System.out.println(list.getFirst()); //获取第一个
System.out.println(list.getLast());// 获取最后一个
TODO 获取数据(遍历数据)
System.out.println(list.get(1));
for ( int i = 0; i < list.size(); i++ ) {
System.out.println(list.get(i));
}
for ( Object obj : list ) { //集合中的每一个数据都取出来,无规律
System.out.println(obj);
}
修改数据
list.set(1, "zhaoliu");
删除数据
list.remove("zhangsan");
TODO 打印集合数据
System.out.println(list);
// 想指定的位置增加数据
list.add(1, "zhaoliu");
list.addFirst("1");
list.addLast("2");
LinkedList list1 = new LinkedList();
list1.add("zhangsan1");
list1.add("lisi2");
list1.add("wangwu3");
list.addAll(list1);
System.out.println(list.remove("1"));
System.out.println(list.remove()); // 删除第一个
list.removeFirst();删除第一个
list.removeLast();删除最后一个
list.remove(1);删除指定位置
System.out.println(list.size());
System.out.println(list.isEmpty());
list.clear();//清空
list.contains("1");//包含
list.element(); // 获取第一个数据
list.indexOf("");//获取数据的位置
list.lastIndexOf("");//获取数据的最后一个位置
list.push("aaa"); // 添加数据
System.out.println(list.pop()); // 弹出数据
System.out.println(list);
泛型语法
o instanceof Person6 //判断o是否是Person6类型的
ArrayList<Person6> list = new ArrayList();
表示集合中只能存放Person6类型的集合,可以调用Person6相关内容,不能存放其它内容。
TODO 泛型和类型的区别
有时,也把泛型称之为类型参数,类型存在多态的使用方式,但是泛型没有多态的概念
①类型存在多态的使用
②泛型没有多态
Sort排序(集合)
// List对象进行排序,需要传递一个实现了比较器接口的对象
list.sort(new NumberComparator());
//排序是需重写一个比较方法
class NumberComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
TODO 如果第一个数比第二个数大,那么返回结果为正数,表示升序
return o1 - o2;
TODO 如果第一个数比第二个数小,那么返回结果为负数,表示降序
return o2 - o2;
TODO 如果第一个数和第二个数一样大,那么返回结果为0
}
}
集合 - Collection - Set
TODO LinkedList和ArrayList插入数据速率的比较
增加第一条数据,LinkedList会比ArrayList快
增加第二条数据,ArrayList会比LinkedList快
增加第三条数据,ArrayList会比LinkedList快
增加第四条数据(超过容量),LinkedList会比ArrayList快
插入数据,LinkedList会比ArrayList快
HashSet
TODO 集合 - Collection - Set(面向单一数据)
HashSet : Hash + Set //存储是无序的
Hash : 哈希算法,散列算法
ArrayList : 数组
LinkedList :底层不是数组
创建 HashSet set = new HashSet();
TODo 增加数据
set.add("zhangsan");
set.add("zhangsan");
set.add("lisi");
set.add("wangwu");
TODo 修改数据
不能直接修改,只能先删除在增加
TODo 删除数据
set.remove("wangwu");
TODo 查询数据
for (Object o : set) {
System.out.println(o);
}
TODO 集合 - Collection - Set 方法
HashSet set = new HashSet();
ArrayList list = new ArrayList();
添加成员
list.add("zhangsan");
list.add("lisi");
list.add("wamngwu");
set.addAll(list);
集合变成数组
Object[] objects = set.toArray();
System.out.println(set.isEmpty());
//set.clear();
set.contains("zhangsan");
System.out.println(set.size());
Object clone = set.clone(); //克隆,只包括里面的内容,不包括类的属性
System.out.println(clone);
System.out.println(set);
HashSet 底层数据结构为 数组 + 链表
集合 - Collection - Queue
TODO 集合 - Collection - Queue
ArrayBlockingQueue : Array + Blocking(阻塞,堵住) + Queue
ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
add方法如果增加数据增加不了,直接发生错误。
queue.add("zhangsan");
boolean zhangsan = queue.offer("zhangsan"); //offer()返回的是bool类型,成功为true
queue.poll()//取出队伍里第一个数据(可以理解成删除)
queue.take() //拿数据可以进行输出,但是拿出之后,后续代码不会执行,仍然是阻塞状态
queue.size()
queue.isEmpty()
queue.clear();
queue.contains()
集合 - Map
HashMap
TODO 集合 - Map(面向 (k,v)键值对数据)
HashMap : Hash + Map(底层:数组 + 单向链表)
数据存储是无序
HashMap map = new HashMap();
添加数据:put //map.put("zhangsan", "1");
修改数据,put方法也可以修改数据,返回值就是被修改的值(如果添加两个数据k值相等,则后添加的数据把前一个添加的数据覆盖掉,返回前一个的v值) 如果是第一次添加,返回值为空
// TODO 查询数据
System.out.println(map.get("zhangsan"));//得到v值
// TODO 删除数据
map.remove("zhangsan");
HashMap包括红黑树
// 添加数据
map.putIfAbsent("b", "2"); //不能覆盖,添加数据的时候如果里面没有与其k值相等的正常添加,如果有与其相等的则什么都不做
//替换,修改
Object b = map.replace("c", "4");
// TODO 获取map集合中所有的key
Set set = map.keySet();
for (Object k : set) {
System.out.println(map.get(k));
}
//包含
map.containsKey("zhangsan")
Collection values = map.values();// 取到其中所有的v值
map.containsValue("1")
// TODO 获取键值对对象
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
Hashtable
TODO 集合 - Map
Hashtable
使用:Hashtable table = new Hashtable();
table.put(null, null);
HashMap map = new HashMap();
map.put(null, null);
table.put()
table.get()
table.remove()
//he HashMap的区别
TODO 1. 实现方式不一样的 : 继承父类不一样
TODO 2. 底层结构的容量不同: HashMap(16), Hashtable(11)
TODO 3. HashMap的K,V都可以为null, Hashtable的K, V不能是null
TODO 4. HashMap的数据定位采用的是Hash算法,但是Hashtable采用的就是hashcode
TODO 5. HashMap的性能较高,但是Hashtable较低
迭代器
// TODO 迭代器
Iterator<String> iterator = keys.iterator();
// hasNext方法用于判断是否存在下一条数据
while (iterator.hasNext()) {
// 获取下一条数据
String key = iterator.next();
if("b".equals(key)) {
// remove方法只能对当前数据删除,不能同时更新,用迭代器删除可以同时更新
iterator.remove();
}
System.out.println(map.get(key));
}
TODO 集合 - 问题
1. java.lang.IllegalArgumentException
设定集合容量时,如果参数为负数,就会发生错误
ArrayList list = new ArrayList(-1);
2. java.util.NoSuchElementException
从链表结构中获取数据,如果没有数据的场合,那么会发生异常
LinkedList list = new LinkedList();
System.out.println(list.getFirst());
3. java.lang.IndexOutOfBoundsException
从集合中获取数据,索引不是按照底层的数据结构设定,而是按照数据的个数决定
ArrayList list = new ArrayList();
list.add("zhangsan");
list.get(3);
4 java.util.ConcurrentModificationException
对Map集合进行操作过程中,对数据进行了修改,就会发生错误。
Exception
TODO 集合 - Exception
容量 :不能小于0
ArrayList list = new ArrayList(10);
如果访问的集合是数组,那么索引范围就是0 到数组长度-1
如果访问的集合是List,那么索引范围就是0 到数据长度-1
System.out.println(list.get(3));
NoSuchElementException
LinkedList list1 = new LinkedList();
list1.add("a");
System.out.println(list1.getFirst());
HashMap一旦循环遍历时,那么如果修改数据,就会发生错误
IO
TODO Java 数据 + 流(转)操作
数据从哪里来,到哪里去
TODO IO
I : Input, 输入(In)
O : Output 输出(Out)
Stream : 流转
文件流
TODO Java IO - 文件流
TODO File : 文件类型(文件,文件夹),属于java.io
创建文件对象, 使用文件路径关联系统文件
String filePath = "D:\\idea2022\\java-top-speed\\data";
File file = new File(filePath);
System.out.println(file);
文件对象的操作
//TODO 判断当前文件对象是否为文件
System.out.println(file.isFile());
//TODO 判断当前文件对象是否为文件夹
System.out.println(file.isDirectory());
TODO 判断文件对象是否存在关联
System.out.println(file.exists());
//TODO 创建多级文件目录
file.mkdirs();
// TODO 创建新文件
file.createNewFile();
//获取文件名字
System.out.println(file.getName());
//最后修改时间
System.out.println(file.lastModified());
//当前文件绝对路径
System.out.println(file.getAbsolutePath());
//文件长度
System.out.println(file.length());
//判断是否是一个文件夹
file.isDirectory()
Java IO - 文件复制
// TODO Java IO - 文件复制
// TODO 数据源文件对象
File srcFile = new File("D:\\idea2022\\java-top-speed\\data\\word.txt");
// TODO 数据目的地文件对象(自动生成)
File destFilt = new File("D:\\idea2022\\java-top-speed\\data\\word.txt.copy");
// TODO 文件输入流(管道对象)
FileInputStream in = null;
// TODO 文件输出流(管道对象)
FileOutputStream out = null;
try {
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFilt);
// TODO 打开阀门,流转数据(输入),阀门在输入一个之后自动关闭
int data = -1;
// TODO 如果文件数据已经全部读取完毕后,那么再去读取数据,读取的结果就是-1,表示无效(结尾)
正规传输写法,利用whil
while ( (data = in.read()) != -1 ) {
out.write(data);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if ( in != null ) {
try {
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if ( out != null ) {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
缓冲区
// TODO 缓冲输入流(管道对象)
BufferedInputStream buffIn = null;
// TODO 缓冲输出流(管道对象)
BufferedOutputStream buffOut = null;
// TODO 缓冲区(水桶)
byte[] cache = new byte[1024];
try {
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFilt);
buffIn = new BufferedInputStream(in);
buffOut = new BufferedOutputStream(out);
// TODO 打开阀门,流转数据(输入)
//
int data = -1;
while ( (data = buffIn.read(cache)) != -1 ) {
buffOut.write(cache, 0, data);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if ( buffIn != null ) {
try {
buffIn.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if ( buffOut != null ) {
try {
buffOut.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
字符流
// TODO Java IO - 文件复制 - 字符串
// TODO 数据源文件对象
File srcFile = new File("D:\\idea2022\\java-top-speed\\data\\word.txt");
// TODO 数据目的地文件对象(自动生成)
File destFilt = new File("D:\\idea2022\\java-top-speed\\data\\word.txt.copy");
// TODO 字符输入流(管道对象)
BufferedReader reader = null;
// TODO 字符输出流(管道对象)
PrintWriter writer = null;
try {
reader = new BufferedReader(new FileReader(srcFile));
writer = new PrintWriter(destFilt);
// TODO 打开阀门,流转数据(输入)
// 读取文件中的一行数据(字符串)
String line = null;
while ( (line = reader.readLine()) != null ) {
System.out.println(line);
writer.println(line);
}
// 刷写数据:把内部缓冲区的数据全部输出到目的地
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if ( reader != null ) {
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if ( writer != null ) {
writer.close();
}
}
序列化和反序列化
// TODO Java IO - 文件复制 - 序列化 & 反序列化
// TODO 数据文件对象
File dataFile = new File("D:\\idea2022\\java-top-speed\\data\\obj.dat");
// TODO 对象输出流(管道对象)
ObjectOutputStream objectOut = null;
FileOutputStream out = null;
// TODO 对象输入流
ObjectInputStream objectIn = null;
FileInputStream in = null;
try {
// out = new FileOutputStream(dataFile);
// objectOut = new ObjectOutputStream(out);
// Java中只有增加了特殊的标记的类,才能再写文件中时进行序列化操作
// 这里的标记其实就是一个接口
// User user = new User(); //自行创建一个user类
// objectOut.writeObject(user);
// objectOut.flush();
// TODO 从文件中读取数据转换成对象
in = new FileInputStream(dataFile);
objectIn = new ObjectInputStream(in);
Object o = objectIn.readObject();
System.out.println(o);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if ( objectOut != null ) {
try {
objectOut.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Exception
// TODO Java IO
// FileNotFoundException, IOException
FileInputStream in = null;
// ClassNotFoundException, NotSerializableException
ObjectInputStream objIn = null;
ObjectOutputStream objOut = null;
try {
in = new FileInputStream("xxx");
in.read();
objOut.writeObject();
objIn.readObject();
} catch (Exception e) {
} finally {
if ( in != null ) {
try {
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}