7.6.1容器和数组的区别
1,变量: 存储单个数据 数组: 存储多个数据 引用数据类型 定长,长度一旦确定不可改变 有序,有索引 存储相同数据类型的数据 2, 集合|容器: 存储多个数据 容量可以多少进行动态的变动 存储任意引用数据类型数据
public class Class01_Container { public static void main(String[] args) { ArrayList list = new ArrayList(); //添加元素 list.add("你好"); list.add(123456); list.add(null); list.add(true); list.add(3.14156); System.out.println(list); //查询数据个数 System.out.println(list.size()); list.add("你好"); list.add(null); System.out.println(list); System.out.println(list.size()); //获取索引位置的元素 System.out.println(list.get(5));
7.6.2Collection接口
1, Collection 集合层次结构中的根接口。 集合表示一组对象,称为其元素 。
2,一些常见方法有:
添加 add
删除 remove
记数 size
包含 contains
清空 clear
是否空 isEmpty
public class Class01_Collection { public static void main(String[] args) { Collection col1 = new ArrayList(); Collection col2 = new ArrayList(); //添加元素 col1.add(123); col1.add(456); col1.add("你是"); col1.add(true); //在数据中添加元素 System.out.println(col1.add(null)); col2.add('A'); col2.add('B'); col2.add('C'); System.out.println(col1); System.out.println(col2); //boolean addAll(Collection<? extends E> c) col1.addAll(col2); //System.out.println(col1); //System.out.println(col2); //boolean contains(Object o) 如果此collection包含指定的元素,则返回 true 。 System.out.println(col1.contains(123)); //boolean containsAll(Collection<?> c) 如果此集合包含指定集合中的所有元素,则返回 true 。 //System.out.println(col1.containsAll()); //boolean isEmpty() 如果此集合不包含任何元素,则返回 true 。 System.out.println(col2.isEmpty()); //col2.clear(); System.out.println(col2.isEmpty()); //boolean remove(Object o) 从此集合中移除指定元素的单个实例(如果存在)(可选操作)。 System.out.println(col1.remove("你是")); System.out.println(col1); //boolean removeAll(Collection<?> c) 删除此集合的所有元素,这些元素也包含在指定的集合中(可选操作)。 //boolean retainAll(Collection<?> c) 仅保留此集合中包含在指定集合中的元素(可选操作)。 col2.add('D'); System.out.println(col1.retainAll(col2)); System.out.println(col1); System.out.println(col2); //Object[] toArray() 返回包含此集合中所有元素的数组。 System.out.println(Arrays.toString(col1.toArray())); //遍历方式 //foreach for (Object obj:col2){ System.out.println(obj); } //Iterator<E> iterator() 返回此集合中元素的迭代器。 //1)获取某一个集合的迭代器 Iterator in = col1.iterator(); //是否存在下一个元素 while (in.hasNext()){ //获取下一个元素 System.out.println(in.next()); } } }
7.6.3List
1,List有序可重复的
2,List : 有序集合(也称为序列 )。 特点 : 有序,可重复 ,可以根据索引操作.. 新增功能 : 新增了一些根据索引操作的方法 遍历方式 : for foreach iterator
public class Class01_List { public static void main(String[] args) { //创建一个list集合 List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); list.add(1); System.out.println(list); System.out.println(list.size()); //void add(int index, E element) 将指定元素插入此列表中的指定位置(可选操作)。 list.add(2,5); System.out.println(list); //E get(int index) 返回此列表中指定位置的元素。 System.out.println(list.get(0)); //int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。 //int lastIndexOf(Object o) 返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。 System.out.println(list.indexOf(3)); System.out.println(list.lastIndexOf(2)); //static <E> List<E> of(E... elements) 返回包含任意数量元素的不可修改列表。 List<Integer> list2 = List.of(1,3,5,7,9); System.out.println(list2); //E remove(int index) 删除此列表中指定位置的元素(可选操作)。 //boolean remove(Object o) 从该列表中删除指定元素的第一个匹配项(如果存在)(可选操作)。 System.out.println(list.remove(1)); System.out.println(list); //E set(int index, E element) 用指定的元素替换此列表中指定位置的元素(可选操作)。 System.out.println(list.set(0,2)); System.out.println(list); //List<E> subList(int fromIndex, int toIndex) 返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。 结束索引不包含 System.out.println(list.subList(2,4)); System.out.println(list); //普通for循环遍历 for (int i = 0;i<list.size();i++){ System.out.println(list.get(i)); } //增强for循环遍历 for (Integer num :list){ System.out.println(num); } //迭代器 Iterator<Integer> s = list.iterator(); //是否存在下一个元素 while (s.hasNext()){ //获取下一个元素 System.out.println(s.next()); } } }
7.6.4手写ArrayList,自定义容器类
class MyContainer{ //存储数据的结构 private String[] elementData; //记录集合中数据的个数 private int size; public MyContainer() { } /** * 添加 * @param value 要添加的数据 */ public void add(String value) { //判断是否为第一次添加数据 if(elementData==null || size==0){ elementData = new String[1]; elementData[0] = value; size++; return; } //不是第一次添加数据,原elementData指向数据对象,原数组中存在数据 //记录原数组对象地址 String[] temp = elementData; //创建新数组 elementData = new String[size+1]; //原数组中数据拷贝到新数组 //i 作为原数组索引同时也能作为新数组水印 for(int i=0;i<size;i++){ elementData[i] = temp[i]; } //新数据添加到新数组最后 elementData[size] = value; //长度+1 size++; } //根据索引获取数据 public String get(int index){ if(index<0 || index>=size){ throw new IndexOutOfBoundsException(index+"索引越界啦!!!"); } return elementData[index]; } //根据索引修改数据 //根据索引删除数据 //返回数据的个数 public int size(){ return this.size; } @Override public String toString() { return Arrays.toString(elementData); } }
7.6.5泛型
1, 泛型 : jdk1.5新增 参数化类型 : 数据的类型作为参数传递 泛型通过一对<>配置 泛型只能设置引用数据类型 泛型可以提高稳定与可读性
public class Class01_Generic { public static void main(String[] args) { //泛型可以提高稳定与可读性 ArrayList<String> num = new ArrayList<>(); num.add("ABC"); num.add("BCD"); num.add("CDE"); //遍历增强for循环 for (String str : num){ System.out.println(str); } //Iterator迭代器遍历 Iterator<String> s1 = num.iterator(); while (s1.hasNext()){ System.out.println(s1.next()); } } }
7.6.6ArrayList
1, ArrayList : 有序,可重复,存在索引 底层结构: 数组 特点: 根据索引查询效率高,增删效率低 应用场景:适合用在大量做查询,少量做增删的场景 扩容: 默认的初始容量为10 , 每次扩容原容量的1.5倍int newCapacity = oldCapacity + (oldCapacity >> 1); 新增方法: void forEach(Consumer<? super E> action)
2,遍历方式: 1)for 2)foreach 3)iterator 4)listIterator
public class Class01_ArrayList { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); list.add(6); System.out.println(list); //增强for循环 list.forEach(System.out::println); //普通for循环 for (int i = 0;i<list.size();i++){ System.out.println(list.get(i)); } //iterator Iterator<Integer> str = list.iterator(); while (str.hasNext()){ System.out.println(str.next()); } } }
7.6.7LinkedList
1,LinkedList : list接口实现类: 有序,可重复
2, 底层结构: 双向链表 特点 : 查询效率低,增删效率高 应用场景 : 适合用在大量做增删少量做查询的位置 新增功能 : 新增了一些操作链表头尾的方法 遍历 : 与list相同
public class Class01_LinkedList { public static void main(String[] args) { //创建接口对象 LinkedList<String> list = new LinkedList<>(); //添加元素 list.add("你好"); list.add("高兴"); list.add("开心"); list.add("快乐"); System.out.println(list); //查询头节点 System.out.println(list.getFirst()); //查询尾节点 System.out.println(list.getLast()); //删除数据节点 System.out.println(list.removeFirst()); System.out.println(list); } }
7.6.8Set
1,Set : 无序,不可重复 无序: 存放的顺序与内部真实存储对的顺序不一致 新增内容 : static <E> Set<E> of(E... elements) 返回包含任意数量元素的不可修改集。 遍历方式: foreach iterator
public class Class01_Set { public static void main(String[] args) { Set<String> str = new HashSet<>(); str.add("你好"); str.add("13456"); str.add("高兴"); str.add(null); System.out.println(str); //static <E> Set<E> of(E... elements) 返回包含任意数量元素的不可修改集。 System.out.println(Set.of(1,2,3,4,5)); //增强for循环遍历foreach for (String s : str) { System.out.println(s); } //迭代器遍历iterator Iterator<String> s = str.iterator(); while (s.hasNext()){ System.out.println(s.next()); } } }
7.6.9TreeSet
-
TreeSet : 底层结构 : 红黑树(平衡二叉树) 特点 : 自动对数据做默认的升序排序 应用场景: 想要实现去重,并且对数据需要默认排序情况 遍历方式: 1)foreach 2)iterator
public class Class01_TreeSet { public static void main(String[] args) { TreeSet<Integer> set = new TreeSet<>(); set.add(3); set.add(2); set.add(1); set.add(4); set.add(6); set.add(5); /* TreeSet set1 = new TreeSet(); set1.add(1); set1.add("你好"); set1.add(false); set1.add(null); System.out.println(set1);*/ System.out.println(set); //E ceiling(E e) 返回此set中大于或等于给定元素的 null元素,如果没有这样的元素,则 null 。 System.out.println(set.ceiling(0)); //E floor(E e) 返回此set中小于或等于给定元素的最大元素,如果没有这样的元素,则 null 。 System.out.println(set.floor(7)); //E first() 返回此集合中当前的第一个(最低)元素。 //E last() 返回此集合中当前的最后一个(最高)元素。 System.out.println(set.first()); System.out.println(set.last()); //E higher(E e) 返回此集合中的最小元素严格大于给定元素,如果没有这样的元素,则 null 。 //E lower(E e) 返回此集合中的最大元素严格小于给定元素,如果没有这样的元素,则 null 。 System.out.println(set.higher(2)); System.out.println(set.lower(6)); //E pollFirst() 检索并删除第一个(最低)元素,如果此组为空,则返回 null 。 //E pollLast() 检索并删除最后一个(最高)元素,如果此集合为空,则返回 null 。 System.out.println(set); System.out.println(set.pollFirst()); System.out.println(set); //foreach遍历 for (Integer num:set){ System.out.println(num); } //iterator遍历 Iterator s = set.iterator(); while (s.hasNext()){ System.out.println(s.next()); } } }
7.7内部比较器和外部比较器
-
比较器: 1.内部比较器|自然排序 : 实现Comparable<T>接口,重写compareTo(T o)方法,方法体中制定比较规则 2.外部比较器|自定义排序 实现Comparator<T>接口,重写compare方法,方法体中制定比较规则
-
使用TreeSet存储Javabean数据,测试使用 要求实现比较规则,有外部找外部,没有外部,默认找内部比较规则
-
注意: TreeSet去重,排序,都根据比较规则实现 如果指定外部比较规则,使用外部比较规则,没有指定外部,使用内部比较规则,都不在,抛出类型转换异常ClassCastException
import java.util.*; public class Class01_Work { public static void main(String[] args) { TreeSet<Person> set = new TreeSet<>(new test()); set.add(new Person("李亮",21,"男")); set.add(new Person("丁天赐",17,"男")); set.add(new Person("时应霞",22,"女")); set.add(new Person("范兆康",20,"男")); set.add(new Person("吴玉涛",23,"男")); System.out.println(set); } } //外部比较器 class test implements Comparator<Person>{ @Override public int compare(Person o1, Person o2) { return o1.getAge()-o2.getAge(); } } //定义人类 class Person implements Comparable<Person>{ private String name; private int age; private String sex; public Person() { } public Person(String name, int age, String sex) { this.name = name; this.age = age; this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name) && Objects.equals(sex, person.sex); } @Override public int hashCode() { return Objects.hash(name, age, sex); } //内部比较器 @Override public int compareTo(Person o) { return this.getAge()-o.getAge(); } }
7.7.1HashSet
-
底层结构: 哈希表(数组+链表+红黑树) 特点: 查询增删效率高,无序,去重 应用场景: 适合用在去重,无序,增删查效率较高情况
-
存储Javabean类型数据实现去重: 需要Javabean类型重写hashcode与equals方法,需要根据对象的属性值进行计算|判断,不能根据对象地址
-
思考: 重写hashcode与equals以后 两个对象hashcode相等,equals就一定相等? 不一定 两个对象equals相等,hashcode一定相等? 一定\
-
注意: javabean的定义规范: 重写hashcode与equals方法
public class Class01_HashSet { public static void main(String[] args) { HashSet<Person> set = new HashSet<>(); set.add(new Person("丁天赐",17,"男")); set.add(new Person("时应霞",22,"女")); set.add(new Person("范兆康",20,"男")); set.add(new Person("吴玉涛",23,"男")); set.add(new Person("吴玉涛",23,"男")); set.add(new Person("楚凯凯",25,"男")); System.out.println(set); System.out.println("你好".hashCode()); System.out.println(new Person().hashCode()); System.out.println(new Person().hashCode()); System.out.println(new Integer(1233).hashCode()); } }
7.7.2Map
-
Map 存储键值对类型数据 键值对: K-V 映射关系 K : 键 -> 唯一的,不可重复,无序的 --> map中的所有key拿出来构成一个Set集合 V : 值 -> 可重复,无序的 --> map中的所有键值对的value拿出来构成一个Collection集合
-
一个key只能对应一个value,如果想要一个key对应多个value可以value定义为数组|集合 如果key相同,value覆盖
-
遍历: 1.values() Collection<V> values() 返回此映射中包含的值的Collection视图。 2.keySet() Set<K> keySet() 返回此映射中包含的键的Set视图。 3.entrySet() Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射的Set视图。
public class Class01_Map { public static void main(String[] args) { Map<Integer,String> map = new HashMap<>(); map.put(1,"老丁"); map.put(2,"老李"); map.put(3,"老范"); map.put(4,"老吴"); map.put(5,"老楚"); map.put(5,"范兆康"); // 如果key相同,value覆盖 System.out.println(map); //boolean containsKey(Object key) 如果此映射包含指定键的映射,则返回 true 。 //boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true 。 System.out.println(map.containsValue("老范")); System.out.println(map.containsKey(1)); //V get(Object key) 返回指定键映射到的值,如果此映射不包含键的映射,则返回 null 。 System.out.println(map.get(5)); //static <K,V> /Map<K,V> of(K k1, V v1, K k2, V v2) 返回包含两个映射的不可修改的映射。 System.out.println(Map.of(1,"hehe",2,"haha")); //V remove(Object key) 如果存在,则从该映射中移除键的映射(可选操作)。 System.out.println(map.remove(5)); System.out.println(map); /* 遍历: 1.values() Collection<V> values() 返回此映射中包含的值的Collection视图。 2.keySet() Set<K> keySet() 返回此映射中包含的键的Set视图。 3.entrySet() Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射的Set视图。 */ //1.values() : 只能遍历value,不能遍历key //增强for循环, Collection<String> values = map.values(); for (String num : values){ System.out.println(num); } //2.keySet(),获取Key和Values的值 Set<Integer> set = map.keySet(); Iterator<Integer> it = set.iterator(); while (it.hasNext()){ Integer i = it.next(); System.out.println(i+"------>"+map.get(i)); } //3.entrySet() Set<Map.Entry<Integer,String>> entry = map.entrySet(); for (Map.Entry<Integer,String> entry1 : entry){ System.out.println(entry1.getKey()+"------>"+entry1.getValue()); } } }
7.7.3HashMap
-
HashMap : 基于哈希表的Map接口的实现。 此实现提供了所有可选的映射操作,并允许null值和null键。 底层: 哈希表(数组+链表+红黑树) 特点: 查询,增删效率高,无序的,根据key去重 线程不安全
-
容量Capacity | 初始容量(16) DEFAULT_INITIAL_CAPACITY : 哈希表数组结构第一次默认大小 加载因子loadFactor|默认加载因子DEFAULT_LOAD_FACTOR : 0.75 大小: 集合中数据的个数 扩容临界值threshold|阀值 : size = Capacity*loadFactor 实现扩容 扩容机制 : newCap = oldCap << 1,每次扩容原容量的2倍
-
去重 : HashMap中键值对的key为javabean的时候,要求key的类型重写hashcode与equals方法
-
注意: map的去重根据key实现,HashMap的哈希表中计算位桶的索引,判断是否重复都是根据key,与value无关,只有存储数据构建新节点的时候或者key相同value覆盖的时候才有value有关
public class Class01_HashMap { public static void main(String[] args) { //创建对象,键值对 HashMap<Teacher,String> map = new HashMap<>(); //添加数据 map.put(new Teacher("丁天赐",17,"语文"),"语文"); map.put(new Teacher("李亮",21,"数学"),"数学"); map.put(new Teacher("范兆康",22,"英语"),"英语"); map.put(new Teacher("吴玉涛",23,"物理"),"物理"); map.put(new Teacher("楚凯凯",52,"化学"),"化学"); map.put(new Teacher("时应霞",22,"政治"),"政治"); map.put(new Teacher("罗宇航",18,"Java"),"Java"); map.put(new Teacher("罗宇航",18,"Java"),"Java+大数据"); //打印数据 System.out.println(map); Set<Teacher> set = map.keySet(); Iterator<Teacher> it = set.iterator(); while (it.hasNext()){ Teacher i = it.next(); System.out.println(i+"----->"+map.get(i)); } }; } //定义教师类 class Teacher { private String name; private int age; private String subject; public Teacher() { } public Teacher(String name, int age, String subject) { this.name = name; this.age = age; this.subject = subject; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Teacher teacher = (Teacher) o; return age == teacher.age && Objects.equals(name, teacher.name) && Objects.equals(subject, teacher.subject); } @Override public int hashCode() { return Objects.hash(name, age, subject); } @Override public String toString() { return "Teacher{" + "name='" + name + '\'' + ", age=" + age + ", subject='" + subject + '\'' + '}'; } }
7.7.4Hashtableh和HashMap的区别
-
Hashtable : 底层结构: 哈希表
-
HashMap与Hashtable之间的区别: 1.继承体系不同 2.存储键值对中对null值的要求不同 HashMap中null值可以作为键值对 Hashtable中null值不能作为键值对 3.同步情况不同 HashMap线程不安全,不同步 Hashtable线程安全的哈希表 4.初始容量,扩容机制不同 HashMap初始容量16 扩容: 每次扩容原容量的2倍 Hashtable初始容量11 扩容: 每次扩容原容量的2倍+1 int newCapacity = (oldCapacity << 1) + 1; 5.计算key的hash值,与位桶索引的方式不同 HashMap : int hash = (h = key.hashCode()) ^ (h >>> 16); int index = (n - 1) & hash; Hashtable : int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length;
-
HashMap线程不安全问题: 1.可以使用Hashtable 2.Collections工具类中 synchronizedMap(Map<K,V> m) 3.juc高级并发编程包 ConcurrentHashMap<K,V> --> 推荐
7.7.5TreeMap
-
TreeMap : 底层结构 : 红黑树 特点: 自动做升序排序,无序的,去重的
-
注意: 无论是排序,还是去重都是根据兼职对的key计算 排序去重问题: 都是根据键值对的key实现,要求key的类型实现内部比较器,或者定义TreeMap指定使用外部比价器
-
TreeSet底层就是由TreeMap维护的,就是TreeMap键值对的key
public class Class01_TreeMap{ public static void main(String[] args) { TreeMap<School,String> map = new TreeMap<>(new Comparator<School>() { @Override public int compare(School o1, School o2) { return o1.getId()-o2.getId(); } }); //Lambda表达式 map = new TreeMap<School,String>((o1, o2) -> { return ((School)o1).getId()-((School)o2).getId(); }); map.put(new School(20,1105),"1105"); map.put(new School(26,1103),"1103"); map.put(new School(15,1102),"1102"); map.put(new School(40,1106),"1106"); map.put(new School(10,1101),"1101"); //输出数据 System.out.println(map); //迭代器遍历 Set<School> set = map.keySet(); Iterator<School> num = set.iterator(); while (num.hasNext()){ School i = num.next(); System.out.println(i+"----->"+map.get(i)); } } } //定义班级对象 class School implements Comparable<School>{ private int People; private int id; public School() { } public School(int people, int id) { People = people; this.id = id; } public int getPeople() { return People; } public void setPeople(int people) { People = people; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; School school = (School) o; return People == school.People && Objects.equals(id, school.id); } @Override public int hashCode() { return Objects.hash(People, id); } @Override public String toString() { return "School{" + "People=" + People + ", id='" + id + '\'' + '}'; } @Override public int compareTo(School o) { return this.getId() - o.getId(); }
7.7.6Properties
-
Properties : Properties类表示一组持久的属性。 Properties可以保存到流中或从流中加载。 属性列表中的每个键及其对应的值都是一个字符串。 Properties常用做配置文件使用
-
定义使用步骤: 1.src下新建文件 xx.properties 2.创建Properties类型的对象 3.调用load(InputStream|Reader) 4.根据key获取value getProperty(key)
public class Class01_Properties { public static void main(String[] args) throws IOException { //创建对象 Properties pro = new Properties(); /* pro.setProperty("李亮","23"); pro.setProperty("范兆康","22");*/ //输出 //System.out.println(pro); //从流中加载数据 pro.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("map01/db.Properties")); System.out.println(pro.getProperty("name")); System.out.println(pro.getProperty("age")); } }
7.7.7Collections
-
Collections 此类仅包含对集合进行操作或返回集合的静态方法。 静态工厂 类似Arrays 常见的简答题: 问Collection与Collections的区别
public class Class01_Collections { public static void main(String[] args) { /* void sort(List) //对List容器内的元素排序,排序的规则是按照升序进行排序。 void shuffle(List) //对List容器内的元素进行随机排列 void reverse(List) //对List容器内的元素进行逆续排列 void fill(List, Object) //用一个特定的对象重写整个List容器 int binarySearch(List, Object)//对于顺序的List容器,采用折半查找的方法查找特定对象 */ //创建一个List对象 List<Integer> list = new ArrayList<>(); list.add(1); list.add(5); list.add(4); list.add(2); list.add(3); System.out.println(list); //自然排序 Collections.sort(list); System.out.println(list); //随机排序 /*Collections.shuffle(list); System.out.println(list);*/ //逆序排列 Collections.reverse(list); System.out.println(list); //二分搜索法 System.out.println(Collections.binarySearch(list,3)); //填充 Collections.fill(list,4); System.out.println(list); } }