admin管理员组

文章数量:1122996

GP

零.晨考复习

1. 接口的定义规范interface 接口名 {成员变量 【缺省属性】public static final成员方法 【缺省属性】public abstract}2. 类遵从接口的格式和关键字class 类名 implements 接口名 {必须实现 接口中缺省属性为 public abstract 修饰方法}3. 接口有哪些特殊用法1. 类可以通过遵从多个接口,不同的接口使用 , 隔开2. 接口可以继承,并且允许多继承3. default 关键字在接口中修饰方法,对应的方法有方法体4. 多态概述和用途编译看左,运行看右父类的引用数据类型变量指向子类对象接口的引用数据类型变量指向遵从接口的实现类对象5. 泛型在增强单一方法的格式和要求权限修饰符 [static] <自定义泛型占位符> 返回值类型 方法名(形式参数列表) {方法体;}【严格要求】形式参数列表中,必须有一个参数对应的针对于自定义泛型6. 类带有自定义泛型的情况下,泛型对应具体数据类型的约束方式需要通过实例化对象方式约束类名<具体数据类型> 类对象 = new 类名<>() IDEA类名<具体数据类型> 类对象 = new 类名<具体数据类型>() Eclipse7. static 修饰静态成员方法有什么特征1. 推荐通过类名直接调用,不建议使用类对象调用2. 可以直接使用类内的其他静态资源3. 不可以使用类内的其他非静态资源4. 通常用于工具类封装,节省实例化对象所需的空间和时间8. final 修饰成员方法有什么要求不能被子类重写,一般是最终方法

一.集合

集合体系

1.1集合解决的问题

针对与目前的数据情况下,存储大量数据类型一致的元素,使用的方式 ==> 【数组】
但是数组存在很多弊端1.数组支持数据类型单一2.数组容量不可变3.数组对应的配套方法较少
集合就可以解决以上问题提供了多种多样的底层构建关注不同的性能方式提供大量的方法配合集合使用,提高开发效率

1.2集合继承结构

interface Collection<E>Java 中所有集合的底层接口,带有泛型 E ==> Element 元素
--| interface List<E>	有序,可重复
----| class ArrayList<E>  底层数据存储结构数组
----| class LinkedList<E> 底层数据存储结构为带有【链表头的双向链表】
----| class Vector<E>     底层数据存储结果数组,同时【线程安全,效率低】
--| interface Set<E>    无序,不可重复
----| class HashSet<E> 底层存储数据结构为哈希表结构[设想execl表格]
----| class TreeSet<E> 底层存储数据结构为平衡二叉树

1.3Collection 相关方法

增add(E e);添加在实例化对象过程中约束泛型对应具体数据类型元素对象。addAll(Collection<? extends E> c);添加参数集合到当前调用方法集合中,要求参数集合对象存储数据类型必须是当前集合对象实例化过程中,约束泛型对应具体数据类型,或者其他子类类型。
删remove(Object obj);在当前集合中,删除指定元素removeAll(Collection<?> c);在当前集合中,删除参数集合和当前集合的交集retainAll(Collection<?> c);在当前集合中,仅保留参数集合和当前集合的交集clear();清空当前集合中所有数据内容
查int size();当前集合中有效元素个数boolean isEmpty();判断当前集合是否为空boolean contains(Object obj);判断参数对象是否在当前集合中存在boolean containsAll(Collection<?> c);判断参数集合是否是当前集合的子集合Object[] toArray();返回当前集合中所有元素对象为Object类型的数组

练习:

package com.qf.list;import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import org.w3c.dom.ls.LSOutput;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;public class Demo1 {public static void main(String[] args) {/*Collection 是一个接口,无法实例化对象,可以使用接口的实现类对象来演示方法情况*/Collection<String> c = new ArrayList<>();c.add("晏曲烩面");c.add("大盘鸡");c.add("班记油泼面");c.add("阿生哥螺蛳粉永安街总店");c.add("洛馍村");c.add("文化路和任寨北街刘记羊肉汤");System.out.println(c);Collection<String> c2 = new ArrayList<>();c2.add("栖三餐厅");c2.add("上品牛排");c2.add("俄式厨房");c.addAll(c2);System.out.println(c);Collection<String> c3 = new ArrayList<>();c3.add("大盘鸡");c3.add("班记油泼面");c3.add("上品牛排");c.remove("洛馍村");System.out.println(c);/*        c.removeAll(c3);System.out.println(c);c.retainAll(c3);System.out.println(c);// []c3.clear();System.out.println(c3);// []
*/System.out.println(c3);// [大盘鸡, 班记油泼面, 上品牛排]System.out.println(c.size());// 8System.out.println(c.isEmpty());// falseSystem.out.println(c3.size());// 3System.out.println(c3.isEmpty());// falseSystem.out.println(c.contains("洛馍村"));// falseSystem.out.println(c.containsAll(c3));// trueObject[] objects = c.toArray();Arrays.stream(objects).forEach(System.out::print);// 晏曲烩面大盘鸡班记油泼面阿生哥螺蛳粉永安街总店文化路和任寨北街刘记羊肉汤栖三餐厅上品牛排俄式厨房}}

1.4List集合相关方法

List 集合有一个非常明显的特征: 【下标】

​ List 集合底层主要的结构 一种是数组,一种是双向链表

增add(E e);添加在实例化对象过程中约束泛型对应具体数据类型元素对象。addAll(Collection<? extends E> c);添加参数集合到当前调用方法集合中,要求参数集合对象存储数据类型必须是当前集合对象实例化过程中,约束泛型对应具体数据类型,或者其子类类型。add(int index, E e);在指定下标位置,添加在实例化对象过程中约束泛型对应具体数据类型元素对象。addAll(int index, Collection<? extends E> c);在指定下标位置,添加参数集合到当前调用方法集合中,要求参数集合对象存储数据类型必须是当前集合对象实例化过程中,约束泛型对应具体数据类型,或者其子类类型。
删E remove(int index);在当前List集合中,删除指定下标元素,返回值是被删除元素对象本身remove(Object obj);在当前集合中,删除指定元素removeAll(Collection<?> c);在当前集合中,删除参数集合和当前集合的交集retainAll(Collection<?> c);在当前集合中,仅保留参数集合和当前集合的交集clear();清空当前集合中所有数据内容
改E set(int index, E e);在 List 集合中,使用符合实例化对象过程中约束泛型对应具体数据类型对象,替换指定下标元素,返回值是被替换元素对象本身
查int size();当前集合中有效元素个数boolean isEmpty();判断当前集合是否为空boolean contains(Object obj);判断参数对象是否在当前集合中存在boolean containsAll(Collection<?> c);判断参数集合是否是当前集合的子集合Object[] toArray();返回当前集合中所有元素对象的Object类型数组E get(int index);在当前集合中,获取指定下标元素int indexOf(Object obj);获取指定元素在当前集合中第一次出现的下标位置int lastIndexOf(Object obj);获取指定元素在当前集合中最后一次出现的下标位置List<E> subList(int fromIndex, int toIndex);从 fromIndex 下标开始,到 toIndex 下标结束,获取子集合对象,要求要头不要尾

list.remove(“道口烧鸡”):删其中一个,不会全部删除

package com.qf.list;import java.util.ArrayList;
import java.util.List;public class Demo2 {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("重庆火锅");list.add("成都火锅");list.add("北京涮锅");list.add("广东打边炉");list.add(2,"南阳方城炝锅烩面");System.out.println(list);// [重庆火锅, 成都火锅, 南阳方城炝锅烩面, 北京涮锅, 广东打边炉]List<String> list2 = new ArrayList<>();list2.add("安阳扁粉菜");list2.add("道口烧鸡");list2.add("红焖羊肉");list2.add("许昌十八碗");list2.add("虾子面");list.addAll(2,list2);System.out.println(list);// [重庆火锅, 成都火锅, 安阳扁粉菜, 道口烧鸡, 红焖羊肉, 许昌十八碗, 虾子面, 南阳方城炝锅烩面, 北京涮锅, 广东打边炉]list.addAll(2, list2);// 允许重复list.remove("道口烧鸡");System.out.println("remove操作:" + list);// remove操作:[重庆火锅, 成都火锅, 安阳扁粉菜, 红焖羊肉, 许昌十八碗, 虾子面, 安阳扁粉菜, 道口烧鸡, 红焖羊肉, 许昌十八碗, 虾子面, 南阳方城炝锅烩面, 北京涮锅, 广东打边炉]String str = list.set(3,"洛阳牛肉汤");System.out.println(str);// 红焖羊肉System.out.println(list);// [重庆火锅, 成都火锅, 安阳扁粉菜, 洛阳牛肉汤, 许昌十八碗, 虾子面, 安阳扁粉菜, 道口烧鸡, 红焖羊肉, 许昌十八碗, 虾子面, 南阳方城炝锅烩面, 北京涮锅, 广东打边炉]System.out.println(list.indexOf("道口烧鸡"));// 7System.out.println(list.lastIndexOf("虾子面"));// 10List<String> list3 = new ArrayList<>();list3.add("虾子面");list3.add("北京涮锅");list3.add("洛阳牛肉汤");System.out.println(list.containsAll(list3));// trueList<String> strings = list.subList(2, 5);System.out.println(strings);// [安阳扁粉菜, 洛阳牛肉汤, 许昌十八碗]}}

1.5Set集合特征

Set 集合使用的方法都是 Collection 中包含的方法
【无序,不可重复】
Set 集合有两个实现类:HashSet 底层是一个哈希表结构TreeSet 底层是一个树形结构。TreeSet 存储元素有数据要求1. 存储数据有自然顺序。2. 存储数据比较方式。

TreeSet存储元素问题解决

Comparable 接口,【增强接口】遵从当前接口的类可以认为是可比较的,可排序的,有比较方式的

public interface Comparable<T> {
/*** Comparable 要求实现的方法,用于比较当前类型** @param t 增强类对应的数据类型* @return 返回值为 0 表示两个元素大小关系一致,其他无所谓*/int compareTo(T t); 
}

在需要排序,比较的结构中,会自动调用 compareTo 方法。

Person.java

public class Person implements Comparable<Person> {private Integer id;private String name;private Integer age;// 补充 Constructor Setter and Getter method/*当前 Person 类 遵从 Comparable 接口要求实现的方法,方法参数是泛型通过【严格约束方式】在遵从接口的过程中,约束泛型对应的具体数据类型为Person*/@Overridepublic int compareTo(Person o) {System.out.println("Person 遵从 Comparable 接口实现 compareTo 方法,满足排序需求");/*this 表示调用当前方法的类对象, o 参数 Person 对象。return this.age - o.age;*/return o.age - age;}
}

TreeSet 存储 Comparable 增强的类对象

/*** TreeSet 存储元素演示** @author Anonymous 2023/2/28 14:42*/
public class Demo4 {public static void main(String[] args) {TreeSet<Person> set = new TreeSet<>();set.add(new Person(1, "张三", 16));set.add(new Person(2, "张三", 36));set.add(new Person(3, "张三", 26));set.add(new Person(4, "张三", 6));set.add(new Person(5, "张三", 66));set.add(new Person(6, "张三", 56));System.out.println(set);}
}

增强 TreeSet,在实例化 TreeSet 构造方法中,提供 Comparator 接口的实现类对象,作为 TreeSet 增强。

Comparator 接口实现类对象,是给 TreeSet 提供处理目标类型的【比较器】

@FunctionalInterface
public interface Comparator<T> {
/*** Comparator 比较器方法,用于提供给需要排序的存储结构,执行排序算法提供比较操作规范和约束** @param o1 用户指定处理类型参数对象* @param o2 用户指定处理类型参数对象* @return 返回值为 0 表示两个元素大小关系一致,其他无所谓*/int compare(T o1, T o2);
}

Comparator 接口使用需要实现类来完成(JDK1.8 之前), JDK 1.8 之后可以用 Lambda表达式,方法引用

案例代码

package com.qfedu.b_collection;import java.util.Comparator;
import java.util.TreeSet;/*
针对于实现类遵从 Comparator 并且在遵从接口的过程中,【严格约束】
泛型对应的具体数据类型,当前数据类型为 Person ,针对于 Person 类型
的比较器,可以提供给 TreeSet 构造方法使用*/
class MyComparator implements Comparator<Person> {@Overridepublic int compare(Person o1, Person o2) {System.out.println("自定义比较器工作");return o1.getAge() - o2.getAge();}
}/*** @author Anonymous 2023/2/28 14:58*/
public class Demo5 {public static void main(String[] args) {// 自定义比较器 Comparator 接口的实现类对象作为 TreeSet 构造方法参数// 增强 TreeSet 结构,当前 TreeSet 可以存储 Person 类型TreeSet<Person> set = new TreeSet<>(new MyComparator());TreeSet<Person> set = new TreeSet<>(new Comparator<Person>() {@Overridepublic int compare(Person o1, Person o2) {System.out.println("匿名内部类自定义比较器工作");return o1.getAge() - o2.getAge();}});TreeSet<Person> set = new TreeSet<>((o1, o2) -> o1.getAge() - o2.getAge());TreeSet<Person> set = new TreeSet<>(Comparatorparing(Person::getAge));TreeSet<Person> set = new TreeSet<>(Demo5::test);set.add(new Person(1, "张三", 16));set.add(new Person(2, "张三", 36));set.add(new Person(3, "张三", 26));set.add(new Person(4, "张三", 6));set.add(new Person(5, "张三", 66));set.add(new Person(6, "张三", 56));set.forEach(System.out::println);}public static int test(Person o1, Person o2) {System.out.println("方法引用");return o1.getAge() - o2.getAge();}
}

2.ArrayList性能分析和源码实现

2.1源码实现

底层是数组

增add(E e);添加在实例化对象过程中约束泛型对应具体数据类型元素对象。addAll(Collection<? extends E> c);添加参数集合到当前调用方法集合中,要求参数集合对象存储数据类型必须是当前集合对象实例化过程中,约束泛型对应具体数据类型,或者其子类类型。add(int index, E e);在指定下标位置,添加在实例化对象过程中约束泛型对应具体数据类型元素对象。addAll(int index, Collection<? extends E> c);在指定下标位置,添加参数集合到当前调用方法集合中,要求参数集合对象存储数据类型必须是当前集合对象实例化过程中,约束泛型对应具体数据类型,或者其子类类型。
删E remove(int index);在当前List集合中,删除指定下标元素,返回值是被删除元素对象本身remove(Object obj);在当前集合中,删除指定元素removeAll(Collection<?> c);在当前集合中,删除参数集合和当前集合的交集retainAll(Collection<?> c);在当前集合中,仅保留参数集合和当前集合的交集clear();清空当前集合中所有数据内容
改E set(int index, E e);在 List 集合中,使用符合实例化对象过程中约束泛型对应具体数据类型对象,替换指定下标元素,返回值是被替换元素对象本身
查int size();当前集合中有效元素个数boolean isEmpty();判断当前集合是否为空boolean contains(Object obj);判断参数对象是否在当前集合中存在boolean containsAll(Collection<?> c);判断参数集合是否是当前集合的子集合Object[] toArray();返回当前集合中所有元素对象的Object类型数组E get(int index);在当前集合中,获取指定下标元素int indexOf(Object obj);获取指定元素在当前集合中第一次出现的下标位置int lastIndexOf(Object obj);获取指定元素在当前集合中最后一次出现的下标位置List<E> subList(int fromIndex, int toIndex);从 fromIndex 下标开始,到 toIndex 下标结束,获取子集合对象,要求要头不要尾

2.2实现过程问题

package com.qfedu.c_arrayList;import java.util.Arrays;/*** @author Anonymous 2023/2/28 15:55*/
public class MyArrayList<E> {/*** 底层用于存储元素的 Object 类型数组数据,可以支持任意类型* 【目前】定义时直接初始化容量为 10*/private Object[] elementsData;/*** DEFAULT_CAPACITY 初始化底层数组默认容量,值为 10*/private static final int DEFAULT_CAPACITY = 10;/*** MyArrayList 底层数组允许的最大容量*/private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;/*** 记录当前集合中有效元素个数*/private int size = 0;/*** 无参数构造方法,实例化对象底层数组容量为 DEFAULT_CAPACITY*/public MyArrayList() {elementsData = new Object[DEFAULT_CAPACITY];}/*** 用户提供底层数组容量,用于实例化集合对象** @param initCapacity 用户指定的数组容量*/public MyArrayList(int initCapacity) {if (initCapacity < 0 || initCapacity > MAX_ARRAY_SIZE) {throw new IllegalArgumentException("用户提供的容量参数不合法");}elementsData = new Object[initCapacity];}/*** 添加一个元素当前集合中** @param e 泛型约束限制的添加元素* @return 添加成功返回 true*/public boolean add(E e) {// return add(size, e);if (size == elementsData.length) {grow(size + 1);}elementsData[size++] = e;return true;}/*** 在指定下标位置添加另一个集合** @param index 指定下标位置* @param c     添加到当前集合的参数集合,要求集合中的元素内容和当前集合一致* @return 添加成功返回 true*/public boolean addAll(int index, MyArrayList<? extends E> c) {if (index < 0 || index > size) {throw new ArrayIndexOutOfBoundsException("数组下标越界异常");}// 1. 判断目前数组剩余容量是否满足添加操作需求if (size + c.size() > elementsData.length) {grow(size + c.size());}// 2. 从指定下标位置开始移动数据,移位for (int i = size - 1; i >= index; i--) {elementsData[i + c.size()] = elementsData[i];/*1 2 3 4 5 6 0 0 0 0 0{1, 2, 3} ==> index = 21 2 1 2 3 3 4 5 6 0 0arr[5 + c.size()] = arr[5];arr[4 + c.size()] = arr[4];arr[3 + c.size()] = arr[3];arr[2 + c.size()] = arr[2];*/}// 3. 放入数据到底层数组中int count = 0;for (int i = index; i < index + c.size(); i++) {elementsData[i] = c.get(count++);}// 4. 有效元素个数 + 添加元素情况size += c.size();return true;}/*** 添加参数集合到当前集合中,要求参数集合中存储的数据类型和当前集合数据类型一致** @param c 参数集合,要求集合存储数据类型一致* @return 添加成功返回 true*/public boolean addAll(MyArrayList<? extends E> c) {return addAll(size, c);}
/*public boolean add(int index, E e) {}
*//*** 返回集合中有效元素个数** @return 集合中有效元素个数*/public int size() {return size;}/*** 判断当前集合是否为空集合** @return 如果为空集合,返回 true,如果不是,返回 null*/public boolean isEmpty() {return 0 == size;}/*** 清空整个集合*/public void clear() {elementsData = new Object[size];size = 0;}/*** 获取当前集合中制定下标的元素** @param index 指定下标* @return 返回集合存储的元素对象*/@SuppressWarnings("unchecked")public E get(int index) {if (index < 0 || index > size) {throw new ArrayIndexOutOfBoundsException("下标越界");}/*添加操作所有的方法元素都是 E 类型,从数组中提取元素是 Object 类型数据为了方便使用,强转为 E 类型,类型转换没有任何的问题*/return (E) elementsData[index];}/*** 返回当前集合的字符串信息描述** @return 集合字符数据内容*/@Overridepublic String toString() {return Arrays.toString(elementsData);}/*** 从指定下标开始,到指定下标结束截取子集合,要头不要尾** @param fromIndex 指定的开始下标* @param toIndex   指定的结束下标* @return 子集合对象*/public MyArrayList<E> subList(int fromIndex, int toIndex) {if (fromIndex > toIndex || fromIndex < 0 || toIndex > size) {throw new ArrayIndexOutOfBoundsException("数组下标越界");}// 根据当前限制的下标范围,实例化 MyArrayList 对象MyArrayList<E> subList = new MyArrayList<>(toIndex - fromIndex);for (int i = fromIndex; i < toIndex; i++) {subList.add(get(i));}return subList;}/*** 私有化底层扩容方法,在添加数据的操作过程中,控制底层数组容量** @param minCapacity 最小容量要求*ArrayList底层数组扩容方法流程概述:*/private void grow(int minCapacity) {// 1. 获取当前底层数组容量int oldCapacity = elementsData.length;// 2. 计算得到新数组容量 大约 1.5 倍int newCapacity = oldCapacity + oldCapacity / 2;// 3. 判断新数组容量是否满足当前添加数据要求 ==> 原数组容量 + 当前添加的元素个数if (newCapacity < minCapacity) {newCapacity = minCapacity;}// 4. 判断新数组容量是否超出 MAX_ARRAY_SIZE 【错误提示】if (newCapacity > MAX_ARRAY_SIZE) {throw new OutOfMemoryError();}// 5. 创建新数组Object[] newArray = new Object[newCapacity];// 6. 从原数组中移动数据到新数组,使用 size 更合适,是有效元素个数,避免无效拷贝for (int i = 0; i < size; i++) {newArray[i] = elementsData[i];}// 7. 新数组地址保存到底层数组引用数据类型变量中。elementsData = newArray;}
}
package com.qfedu.c_arrayList;import org.junit.Test;/*** @author Anonymous 2023/2/28 17:56*/
public class MyArrayListTest {@Testpublic void test1() {MyArrayList<String> list = new MyArrayList<>();list.add("热干面");list.add("扁粉菜");list.add("酸辣粉");list.add("牛肉面");System.out.println(list);MyArrayList<String> list1 = new MyArrayList<>();list1.add("担担面");list1.add("biangbiang面");list1.add("油泼面");list1.add("老碗面");list1.add("刀削面");list1.add("湖南牛肉面");list1.add("老北京方便面");list1.add("老北京炸酱面");list.addAll(1, list1);System.out.println(list);MyArrayList<String> subList = list.subList(2, 8);System.out.println(subList);}
}

2.3ArrayList性能分析

​ 1.数据添加有可能导致扩容,扩容效率低。

​ 2.在数组中添加元素,会导致数据整体向后移,效率低

​ 1.在数组中删除元素,会导致数据整体向前移,效率低

​ 2.删除操作会导致有效元素个数和当前底层数组容量占比降低,浪费内存空间。

​ 数组缩容方法:trimToSize();

改/查

​ E set(int index , E e)

​ 数组下标操作效率极高,修改,查询极高
list.add(“牛肉面”);

    System.out.println(list);MyArrayList<String> list1 = new MyArrayList<>();list1.add("担担面");list1.add("biangbiang面");list1.add("油泼面");list1.add("老碗面");list1.add("刀削面");list1.add("湖南牛肉面");list1.add("老北京方便面");list1.add("老北京炸酱面");list.addAll(1, list1);System.out.println(list);MyArrayList<String> subList = list.subList(2, 8);System.out.println(subList);
}

}


## 2.3ArrayList性能分析增​				1.数据添加有可能导致扩容,扩容效率低。​				2.在数组中添加元素,会导致数据整体向后移,效率低删​				1.在数组中删除元素,会导致数据整体向前移,效率低​				2.删除操作会导致有效元素个数和当前底层数组容量占比降低,浪费内存空间。​				数组缩容方法:trimToSize();改/查​				E set(int index , E e)​				数组下标操作效率极高,修改,查询极高

本文标签: GP