h5网站建设模板/个人如何优化网站有哪些方法
目录
第十二章 集合
学习目标
1. 集合框架的由来
2. 集合框架的继承体系
3. Collection接口
3.1 Collection接口的常用方法
4. Iterator接口
4.1 Iterator接口的抽象方法
4.2 获取迭代器接口实现类
4.3 迭代器的实现原理
4.4 并发修改异常
4.5 集合存储自定义对象并迭代
5. List接口
5.1 List接口的特点
5.2 List接口自己的方法(带有索引)
5.3 List集合的特有迭代器
5.4 List接口的实现类的数据结构
6. ArrayList实现类
6.1 ArrayList集合的特点
6.2 ArrayList源码解析
6.2.1 ArrayList类的成员变量
6.2.2 ArrayList集合类的构造方法
6.2.3 ArrayList集合类的方法add()
7. LinkedList实现类
7.1 LinkedList集合的特点
7.2 LinkedList集合特有方法
7.3 LinkedList源码解析
7.3.1 LinkedList集合的成员变量
7.3.2 LinkedList集合的成员内部类Node(结点)
7.3.4 LinkedList集合的方法add()添加元素
7.3.5 LinkedList集合的方法get()获取元素
8. Set接口
8.1 Set集合存储和遍历
8.2 Set接口实现类HashSet类
8.3 对象的哈希值
8.4 String类的哈希值
8.5 哈希值的相关问题
8.6 哈希表的数据结构
8.7 哈希表存储对象的过程
8.8 哈希表存储自定义的对象
8.9 哈希表源码
8.10 哈希表面试的问题
9. 红黑树
9.1 TreeSet集合使用
9.2 TreeSet存储自定义对象
10. LinkedHashSet
11. Collections工具类
12. 泛型 Generic
12.1 泛型的安全机制
12.2 泛型中的 E 问题
12.3 自定义泛型类
12.4 泛型方法
12.5 泛型接口
12.6 泛型通配符
12.7 泛型限定
13. 增强型的for循环
13.1 for的格式
14. Map接口
14.1 Map接口方法
14.2 Map集合的遍历——键找值
14.3 Map集合的遍历——键值对映射关系
15. HashMap 实现类
16. Hashtable 实现类
17. LinkedHashMap 实现类
18. Vector 实现类
19. TreeMap 实现类
20. Properties 实现类
第十二章 集合
学习目标
-
认识集合框架
-
List集合的结构
-
ArrayList集合使用
-
ArrayList源码解析
-
LinkedList集合使用
-
LinkedList源码解析
-
对象的哈希值
-
哈希表数据结构
-
Collections工具类
-
了解泛型及其定义
-
哈希表确定对象唯一性
-
HashSet源码解析
-
红黑树结构Red/Black Tree Visualization
-
对象的自然顺序与比较器
1. 集合框架的由来
JDK1.2版本后,出现这个集合框架,到JDK1.5后,大幅度优化。
-
集合本质上是存储对象的容器
-
数组也能存储对象,数组弊端就是定长
-
解决数组的问题,开发出来集合框架,集合框架无需考虑长度
-
集合和数组的区别与共同点
-
集合,数组都是容器,都可以存储数据
-
集合只存储引用数据类型,不存储基本数据类型(如int,就会换成包装类Integer)
-
数组可以存储基本类型,也可以存储引用类型
-
数组定长,集合容器变长
-
牢记:数据多了存数组,对象多了存集合
-
集合学习的关键点
-
怎么存储数据
-
怎么取出数据
-
选择哪种容器
-
2. 集合框架的继承体系
3. Collection接口
是所有单列集合的顶级接口,任何单列集合都是他的子接口,或者是实现类,该接口中定义的方法,是所有单列集合的共性方法。
Collection<E> 尖括号就是泛型,E我们要写,集合存储的数据类型
3.1 Collection接口的常用方法
方法的定义 | 方法作用 |
---|---|
boolean add(E) | 元素添加到集合 |
void clear() | 清空集合容器中的元素 |
boolean contains(E) | 判断元素是否在集合中 |
boolean isEmpty() | 判断集合的长度是不是0,是0返回true |
int size() | 返回集合的长度,集合中元素的个数 |
boolean remove(E) | 移除集合中指定的元素,移除成功返回true |
T[] toArray(T[] a) | 集合转成数组 |
(1) boolean add(E)
/**
* boolean add(E) 元素添加到集合中
* 返回值,目前都是true
*/
public static void collectionAdd(){//接口多态创建集合容器对象,存储的数据类型是字符串Collection<String> coll = new ArrayList<>();//集合对象的方法add添加元素coll.add("hello");coll.add("world");coll.add("java");coll.add("money");coll.add("wife");/*** 输出语句中,输出集合对象,调用的是方法toString()* 看到的内容是一个完整的字符串, 不叫遍历* 遍历时一个个过,一个个输出*/System.out.println(coll);
}
(2)void clear(),int size(),boolean isEmpty()
/*** void clear() 清空集合中的所有元素* int size() 集合的长度*/public static void collectionClear(){Collection<Integer> coll = new ArrayList<>();coll.add(1);coll.add(2);coll.add(3);System.out.println(coll);System.out.println("集合的长度::"+ coll.size());//长度coll.clear();System.out.println(coll);System.out.println("集合的长度::"+ coll.size());System.out.println("集合是空吗?" + coll.isEmpty());//长度=0,isEmpty()返回true}
(3)boolean contains(),boolean remove()
/*** boolean contains(E) 判断是否包含* boolean remove(E) 移除元素*/
public static void collectionContains(){//接口多态创建集合容器对象,存储的数据类型是字符串Collection<String> coll = new ArrayList<>();//集合对象的方法add添加元素coll.add("hello");coll.add("wife");coll.add("world");coll.add("java");coll.add("money");coll.add("wife");//判断集合中是否包含某个元素boolean b = coll.contains("world");System.out.println("b = " + b);//移除集合中的元素//删除成功返回true,如果有多个相同的对象,删除最先遇到的那个boolean b1 = coll.remove("wife");System.out.println("b1 = " + b1);System.out.println(coll);
}
4. Iterator接口
迭代器接口 Iterator,为集合进行遍历的。迭代器技术是所有Collection集合的通用遍历形式。
4.1 Iterator接口的抽象方法
-
boolean hasNext() 判断集合中是否有下一个可以遍历的元素,如果有返回true
-
E next() 获取集合中下一个元素
-
void remove() 移除遍历到的元素
4.2 获取迭代器接口实现类
迭代器就是为了遍历集合而产生。集合的顶层接口Collection中定义了方法:方法的名字就是 iterator(),返回值是Iterator接口类型, 返回的是Iterator接口实现类的对象
Collection接口中的方法摘要 :public Iterator iterator() ; 返回迭代器接口实现类的对象使用的对象ArrayList,实现接口Collection,重写方法iterator();
public static void main(String[] args) {//迭代器遍历集合//接口多态创建集合容器对象,存储的数据类型是字符串Collection<String> coll = new ArrayList<>();//集合对象的方法add添加元素coll.add("hello");coll.add("world");coll.add("java");coll.add("money");coll.add("wife");//1 遍历 集合对象,调用方法iterator() 获取迭代器接口的实现类对象Iterator<String> it = coll.iterator();//2 迭代器对象的方法,判断集合是否有下元素//boolean b = it.hasNext();//System.out.println(b);//3 迭代器对象的方法,取出元素//String str = it.next();//System.out.println(str);//条件,集合中有下一个元素就可以while ( it.hasNext() ){String str = it.next();System.out.println(str);}
}
4.3 迭代器的实现原理
每个集合容器,内部结构不同,但是迭代器都可以进行统一的遍历实现
结论:迭代器是隐藏在集合的内部的(即为成员内部类),提供公共的访问方式。
//Iterator接口的源码和ArrayList中的iterator的源码
interface Iterator{boolean hasNext();E next();void remove();
}public class ArrayList {public Iterator iterator(){return new Itr();}private class Itr implements Iterator{boolean hasNext(); //重写E next(); //重写void remove(); //重写}}
图1:ArrayList的内部类实现接口Iterator的源码图片
4.4 并发修改异常
如何不发生这个异常
异常的产生原因:在迭代器遍历集合的过程中,使用了集合的功能,改变了集合的长度造成。
public static void main(String[] args) {//迭代器遍历集合//接口多态创建集合容器对象,存储的数据类型是字符串Collection<String> coll = new ArrayList<>();//集合对象的方法add添加元素coll.add("hello");coll.add("world");coll.add("java");coll.add("money");coll.add("wife");//迭代器遍历集合Iterator<String> it = coll.iterator();while ( it.hasNext() ){String str = it.next();//判断,遍历到的集合元素是不是javaif (str.equals("java")){//添加元素 出现并发修改异常coll.add("add");}System.out.println(str);}
}
4.5 集合存储自定义对象并迭代
public static void main(String[] args) {//创建集合,存储自定义的对象Collection<Person> coll = new ArrayList<>();//集合的方法add存储Person对象coll.add( new Person("张三",21) );coll.add( new Person("李四",22) );coll.add( new Person("王五",23) );//迭代器遍历集合Iterator<Person> iterator = coll.iterator();while (iterator.hasNext()){Person person = iterator.next();System.out.println(person);System.out.println(person.getName());}
}
/*** 定义私有成员* get set方法* 无参数构造方法** 满足以上的三个条件 ,这个类,换一个名字,叫JavaBean*/
public class Person {private String name;private int age;public Person(){}public Person(String name, int age) {this.name = name;this.age = age;}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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}
5. List接口
List接口,继承Collection接口,是单列集合。
5.1 List接口的特点
-
这个接口的集合都具有索引
-
这个接口中的元素允许重复
-
这个接口中的元素是有序的
-
元素不会排序 ,有序指的是 ,元素存储和取出的顺序是一致的
-
List接口的所有实现类,都具有以上三个特征
5.2 List接口自己的方法(带有索引)
(1)void add(int index ,E e);
/**
* List接口的方法 add(int index, E e)
* 指定的索引位置,添加元素
*
* IndexOutOfBoundsException 集合越界异常 长度是size()
* StringIndexOutOfBoundsException 字符串越界异常 长度是 length()
* ArrayIndexOutOfBoundsException 数组越界异常 长度是 length
*/
public static void listAdd(){List<String> list = new ArrayList<>();list.add("a") ;//集合的尾部添加list.add("b");list.add("c");list.add("d");list.add("e");System.out.println(list);//指定的索引上,添加元素 ,3索引添加元素list.add(3,"QQ");System.out.println(list);
}
(2)E get(int index);
/*** List接口的方法 E get(int index)* 返回指定索引上的元素* List集合可以使用for循环像数组一样的方式遍历*/public static void listGet(){List<String> list = new ArrayList<>();list.add("a") ;//集合的尾部添加list.add("b");list.add("c");list.add("d");list.add("e");//List接口方法get取出元素//String s = list.get(3);//System.out.println(s);for(int i = 0 ; i < list.size() ; i++){System.out.println(list.get(i));}}
(3)E
set(int index,E e); E remove(int index);
/*** List接口方法* E set (int index , E e) 修改指定索引上的元素,返回被修改之前的元素* E remove(int index) 移除指定索引上的元素, 返回被移除之前的元素*/public static void listSetRemove(){List<String> list = new ArrayList<>();list.add("a") ;//集合的尾部添加list.add("b");list.add("c");list.add("d");list.add("e");System.out.println(list);//修改指定索引上的元素,3索引String str = list.set(3,"https://www.baidu.com");System.out.println(list);System.out.println(str);//删除指定索引上的元素,删除3索引str = list.remove(3);System.out.println(list);System.out.println(str);}
5.3 List集合的特有迭代器
List接口中的方法 listIterator() 返回迭代器,迭代器的接口是ListIterator,List集合的专用迭代器。
-
ListIterator迭代器接口的方法
-
boolean hasNext()
-
E next()
-
boolean hasPrevious() 判断集合中是否有上一个元素,反向遍历
-
E previous() 取出集合的上一个元素
-
/*** List接口的方法:* listIterator() List集合的特有迭代器* 反向遍历*/public static void iterator(){List<String> list = new ArrayList<>();list.add("a") ;//集合的尾部添加list.add("b");list.add("c");list.add("d");list.add("e");//获取特有迭代器接口实现类对象ListIterator<String> lit = list.listIterator();//先要正向遍历while (lit.hasNext()){String s = lit.next();System.out.println(s);}System.out.println("=============");//判断上一个元素while (lit.hasPrevious()){//取出元素String s = lit.previous();System.out.println(s);}}
5.4 List接口的实现类的数据结构
LinkedList(链表)
-
数组 :
-
有索引,数组中元素的地址是连续,查询速度快
-
数组的长度为固定,新数组创建,数组元素的复制,增删的效率慢
-
-
链表
-
链表没有索引,采用对象之间内存地址记录的方式存储
-
查询元素,必须通过第一个节点依次查询,查询性能慢
-
增删元素,不会改变原有链表的结构,速度比较快
-
6. ArrayList实现类
6.1 ArrayList集合的特点
ArrayList类实现接口ListArrayList具备了List接口的特性 (有序,重复,索引)
-
ArrayList集合底层的实现原理是数组,大小可变 (存储对象的时候长度无需考虑)。
-
数组的特点:查询速度快,增删慢。
-
数组的默认长度是10个,每次的扩容是原来长度的1.5倍。
-
ArrayList是线程不安全的集合,运行速度快。
6.2 ArrayList源码解析
6.2.1 ArrayList类的成员变量
private static final int DEFAULT_CAPACITY = 10; //默认容量
private static final Object[] EMPTY_ELEMENTDATA = {};//空数组
transient Object[] elementData; //ArrayList集合中的核心数组
private int size; //记录数组中存储个数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //数组扩容的最大值
6.2.2 ArrayList集合类的构造方法
//无参数构造方法
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //数组没有长度
//有参数的构造方法
public ArrayList(int 10) {if (initialCapacity > 0) {//创建了10个长度的数组this.elementData = new Object[10];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}
}
6.2.3 ArrayList集合类的方法add()
new ArrayList<>().add("abc"); //集合中添加元素
public boolean add("abc") {//检查容量 (1)ensureCapacityInternal(size + 1); //abc存储到数组中,存储数组0索引,size计数器++elementData[size++] = "abc";//数组扩容为10return true;
}
//检查集合中数组的容量, 参数是1
private void ensureCapacityInternal(int minCapacity = 1) {//calculateCapacity 计算容量,方法的参是数组 , 1// ensureExplicitCapacity (10) 扩容的ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//计算容量方法, 返回10
private static int calculateCapacity(Object[] elementData, int minCapacity = 1) {//存储元素的数组 == 默认的空的数组 构造方法中有赋值if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//返回最大值 max(10,1)return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;
}
//扩容
private void ensureExplicitCapacity(int minCapacity = 10) {modCount++;// 10 - 数组的长度0 > 0if (minCapacity - elementData.length > 0)//grow方法(10) 数组增长的grow(minCapacity);
}
//增长的方法,参数是(10)private void grow(int minCapacity = 10) {//变量oldCapacity保存,原有数组的长度 = 0int oldCapacity = elementData.length; // 0//新的容量 = 老 + (老的 / 2)int newCapacity = oldCapacity + (oldCapacity >> 1);// 0// 0 - 10 < 0 新容量-计算出的容量if (newCapacity - minCapacity < 0)newCapacity = minCapacity; //新容量 = 10//判断是否超过最大容量if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:
//数组的赋值,原始数组,和新的容量elementData = Arrays.copyOf(elementData, newCapacity);}
7. LinkedList实现类
7.1 LinkedList集合的特点
LinkedList类实现接口List,LinkedList具备了List接口的特性 (有序,重复,索引)
-
LinkedList底层实现原理是链表,双向链表
-
LinkedList增删速度快
-
LinkedList查询慢
-
LinkedList是线程不安全的集合,运行速度快
7.2 LinkedList集合特有方法
集合是链表实现,可以单独操作链表的开头元素和结尾元素
-
void addFirst(E e) 元素插入到链表开头
-
void addLast(E e) 元素插入到链表结尾
-
E getFirst() 获取链表开头的元素
-
E getLast() 获取链表结尾的元素
-
E removeFirst() 移除链表开头的元素
-
E removeLast() 移除链表结尾的元素
-
void push(E e)元素推入堆栈中
-
E pop()元素从堆栈中弹出
public static void main(String[] args) {linkedPushPop();
}
//- void push(E e)元素推入堆栈中
//- E pop()元素从堆栈中弹出public static void linkedPushPop(){LinkedList<String> linkedList = new LinkedList<String>();//元素推入堆栈中linkedList.push("a"); //本质就是addFirst() 开头添加linkedList.push("b");linkedList.push("c");System.out.println("linkedList = " + linkedList);String pop = linkedList.pop(); // removeFirst()移除开头System.out.println(pop);System.out.println("linkedList = " + linkedList);
}//- E removeFirst() 移除链表开头的元素
//- E removeLast() 移除链表结尾的元素
public static void linkedRemove(){LinkedList<String> linkedList = new LinkedList<String>();linkedList.add("a"); //结尾添加linkedList.add("b"); //结尾添加linkedList.add("c"); //结尾添加linkedList.add("d"); //结尾添加System.out.println("linkedList = " + linkedList);//移除开头元素,返回被移除之前String first = linkedList.removeFirst();//移除结尾元素,返回被移除之前的String last = linkedList.removeLast();System.out.println("first = " + first);System.out.println("last = " + last);System.out.println("linkedList = " + linkedList);
}//- E getFirst() 获取链表开头的元素
//- E getLast() 获取链表结尾的元素
public static void linkedGet(){LinkedList<String> linkedList = new LinkedList<String>();linkedList.add("a"); //结尾添加linkedList.add("b"); //结尾添加linkedList.add("c"); //结尾添加linkedList.add("d"); //结尾添加System.out.println("linkedList = " + linkedList);//获取开头元素String first = linkedList.getFirst();//获取结尾元素String last = linkedList.getLast();System.out.println("first = " + first);System.out.println("last = " + last);System.out.println("linkedList = " + linkedList);
}// void addFirst(E e) 元素插入到链表开头
// void addLast(E e) 元素插入到链表结尾
public static void linkedAdd(){LinkedList<String> linkedList = new LinkedList<String>();linkedList.add("a"); //结尾添加linkedList.add("b"); //结尾添加linkedList.add("c"); //结尾添加linkedList.add("d"); //结尾添加System.out.println("linkedList = " + linkedList);//结尾添加linkedList.addLast("f");linkedList.add("g");//开头添加linkedList.addFirst("e");System.out.println("linkedList = " + linkedList);
}
7.3 LinkedList源码解析
7.3.1 LinkedList集合的成员变量
transient int size = 0; //集合中存储元素个数计数器
transient Node<E> first; //第一个元素是谁
transient Node<E> last; //最后一个元素是谁
7.3.2 LinkedList集合的成员内部类Node(结点)
//链表中,每个结点对象
private static class Node<E> {E item; //我们存储的元素Node<E> next; // 下一个结点对象Node<E> prev; // 上一个结点对象//构造方法,创建对象,传递上一个,下一个,存储的元素Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}
}
7.3.4 LinkedList集合的方法add()添加元素
//添加元素 e 存储元素 abc
//再次添加元素 e
void linkLast(E "abc") {//声明新的节点对象 = lastfinal Node<E> l = last; // l = null l "abc"节点//创建新的节点对象,三个参数, 最后一个对象,"abc", 上一个对象nullfinal Node<E> newNode = new Node<>(l, e, null);//新节点赋值给最后一个节点last = newNode;if (l == null)//新存储的几点赋值给第一个节点first = newNode;elsel.next = newNode;size++;modCount++;
}
7.3.5 LinkedList集合的方法get()获取元素
//集合的获取的方法
//index是索引, size 长度计数器
Node<E> node(int index) {//索引是否小于长度的一半,折半思想if (index < (size >> 1)) {Node<E> x = first;for (int i = 0; i < index; i++)x = x.next;return x;} else {Node<E> x = last;for (int i = size - 1; i > index; i--)x = x.prev;return x;}
}
8. Set接口
Set集合,是接口Set,继承Collection接口。Set集合不存储重复元素。
Set集合存储的数据是无序、不重复、无索引。
无序指的是存储和取出的顺序不一样,但是由于使用迭代器遍历,Set集合的输出会根据自然顺序输出,例如“a”自然排序在“b”之前,所以先输出“a”。
Set接口下的所有实现类,都会具有这个特性。
Set接口的方法,和父接口Collection中的方法完全一样。
8.1 Set集合存储和遍历
public static void main(String[] args) {//Set集合存储并迭代Set<String> set = new HashSet<String>();//存储元素方法 addset.add("b");set.add("a");set.add("c");set.add("d");set.add("d");System.out.println("set = " + set);Iterator<String> it = set.iterator();while (it.hasNext()){System.out.println(it.next());}}
8.2 Set接口实现类HashSet类
-
HashSet集合类的特点 :
-
实现Set接口,底层调用的是HashMap集合
-
HashSet的底层实现原理是哈希表
-
HashSet不保证迭代顺序,元素存储和取出的顺序不一定
-
线程不安全,运行速度快
-
图二:创建HashSet其实就是创建HashMap
8.3 对象的哈希值
每个类继承Object类,Object类定义方法:
public native int hashCode(); // C++语言编写,不开源
方法使用没有区别:方法返回int类型的值,就称为哈希值
哈希值的结果不知道是怎么计算的,调用toString()方法的时候,返回的十六进制数和哈希值是一样的,@1b6d3586叫哈希值 (根本和内存地址是无关的)
public static void main(String[] args) {Person p = new Person();int code = p.hashCode();// int 变量 460141958 (是什么,无所谓, 数字就是对象的哈希值)System.out.println(code);// com.atguigu.hash.Person@1b6d3586System.out.println(p.toString());}
可以重写父类的hashCode()方法,再输出该哈希值或toString()方法
/*** 重写父类的方法* 返回int值*/public int hashCode(){return 9527;}
8.4 String类的哈希值
字符串类重写方法hashCode(),自定义了哈希值,哈希值的计算方法是:
h = 31 * 上一次的计算结果 + 字符数组中元素的ASCII码值
*31 的目的,减少相同哈希值的计算
String类的哈希值:
//字符串String对象的哈希值private static void stringHash(){String s1 ="abc";String s2 ="abc";System.out.println(s1 == s2); //T//String类继承Object,可以使用方法hashCodeSystem.out.println(s1.hashCode() == s2.hashCode()); //T/*** String类继承Object类* String类重写父类的方法 hashCode() 自己定义了哈希值*/System.out.println(s1.hashCode());System.out.println(s2.hashCode());System.out.println("=============");/*** 字符串内容不一样,有没有可能计算出相同的哈希值* String s1 ="abc";* String s2 ="abc";*/String s3 = "通话";String s4 = "重地";//1179395//1179395System.out.println(s3.hashCode());System.out.println(s4.hashCode());System.out.println(s3.equals(s4));}
8.5 哈希值的相关问题
问题 : ① 两个对象A、B 两个对象哈希值相同,equals方法一定返回true吗?
② 两个对象A、B 两个对象equals方法返回true,两个对象的哈希值一定相同吗?
结论 : 两个对象的哈希值相同,不要求equals一定返回true. 两个对象的equals返回true,两个对象的哈希值必须一致
Sun 公司官方规定 : 上面的结论
8.6 哈希表的数据结构
数组 + 链表的组合体
class Node{E element; //存储的元素Node next; //下一个元素
}
main(){Node[] node = new Node[5];
}
-
哈希表的底层数组长度默认是16个,扩容为原来长度的2倍
-
加载因子默认是0.75F,数组中存储元素的个数达到长度的75%就扩容
8.7 哈希表存储对象的过程
public static void main(String[] args) {Set<String> set = new HashSet<String>();//存储对象set.add("abc");set.add("bbc");set.add(new String("abc"));set.add("通话");set.add("重地");System.out.println("set = " + set);
}
8.8 哈希表存储自定义的对象
需要重写自定义类的hashCode()和equal()两个方法
public class Student {private int age;private String name;public Student(){}public Student( String name,int age) {this.age = age;this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;if (age != student.age) return false;return name != null ? name.equals(student.name) : student.name == null;}@Overridepublic int hashCode() {int result = age;result = 31 * result + (name != null ? name.hashCode() : 0);return result;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}
}
public static void main(String[] args) {Set<Student> set = new HashSet<Student>();//存储Student的对象set.add(new Student("a1",201));set.add(new Student("a2",202));set.add(new Student("a2",202));set.add(new Student("a3",203));set.add(new Student("a4",204));System.out.println("set = " + set);
}
8.9 哈希表源码
HashSet集合本身不具备任何功能,内部调用了另一个集合对象HashMap
- 构造方法无参数
public HashSet() {map = new HashMap<>();
}
- HashMap类的成员变量
//哈希表数组的初始化容量,16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 16
static final int MAXIMUM_CAPACITY = 1 << 30; //最大容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;//价值因子
static final int TREEIFY_THRESHOLD = 8;//阈值,转红黑树
static final int UNTREEIFY_THRESHOLD = 6;//阈值,解除红黑树
static final int MIN_TREEIFY_CAPACITY = 64;//阈值,转红黑树
- HashMap内部类Node
//节点
static class Node<K,V> implements Map.Entry<K,V> {final int hash; //对象哈希值final K key; //存储的对象V value; //使用Set的集合,value没有值Node<K,V> next; //链表的下一个节点
}
-
Set集合存储方法add(),调用的是HashMap集合的方法put()【大致了解就行】
//HashMap存储对象的方法put,Key存储的元素,V是空的对象
public V put(K key, V value) {//存储值,传递新计算哈希值,要存储的元素return putVal(hash(key), key, value, false, true);
}
//传递存储的对象,再次计算哈希值//尽量降低哈希值的碰撞
static final int hash(Object key) { int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
//存储值,重写计算的哈希值,要存储值
final V putVal(int hash, K key, V value, boolean false,boolean true) {//Node类型数组, Node类型数组 n, iNode<K,V>[] tab; Node<K,V> p; int n, i;//tab =Node[]=nullif ((tab = table) == null || (n = tab.length) == 0){//n=赋值为 tab数组=resize()方法返回数组,默认长度的数组16n = (tab = resize()).length;// 16//数组的长度-1 & 存储对象的哈希值,确定存储的位置//判断数组的索引上是不是空的if ((p = tab[i = (n - 1) & hash]) == null)//数组索引 赋值新的节点对象,传递计算的哈希值,存储的对象tab[i] = newNode(hash, key, value, null);else{//数组的索引不是空,要存储的对象,已经有了//判断已经存在的对象,和要存储对象的哈希值和equals方法if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))//遍历该索引下的链表,和每个元素比较hashCode和equals}}
}
8.10 哈希表面试的问题
JDK7版本和JDK8版本的哈希表的区别
-
JDK7没有转红黑树
-
JDK8转成红黑树
-
转成树的两个参数
-
当一个数组中存储的链表长度>=8 转树
-
数组的整体长度超过64
-
-
树转回链表
-
链表的长度 <=6
-
-
-
JDK7元素采用头插法,JDK8元素采用尾插法
9. 红黑树
红黑树(Red-Black-Tree)
-
二叉树,本质就是链表
-
查询速度快
-
每个一个节点,只有两个子节点,左和右
-
树长偏了
-
-
自然平衡二叉树
-
二叉树的基础上,改进,保证树是平衡的
-
-
红黑树
-
每个节点有颜色,要么红,要么是黑
-
根节点必须是黑色
-
叶子节点必须是黑色
-
变量表示颜色,true黑色,false红色
-
9.1 TreeSet集合使用
TreeSet集合,底层是红黑树结构,依赖于TreeMap的实现
红黑树特点查找速度快,线程不安全
可以对存储到红黑树的元素进行排序,元素的自然顺序 abcd.. 字典顺序
public static void treeSetString(){Set<String> set = new TreeSet<>();//存储元素set.add("abcd");set.add("ccdd");set.add("z");set.add("wasd");set.add("bbaa");System.out.println("set = " + set);}
9.2 TreeSet存储自定义对象
/**
* TreeSet集合存储Student对象
*/
public static void treeSetStudent(){Set<Student> set = new TreeSet<Student>();set.add(new Student("a",10));set.add(new Student("b",20));System.out.println("set = " + set);
}
程序出现了异常,类型的转换异常 ClassCastException
异常原因,Student类不能进行类型的转换,有接口没有实现java.lang.Comparable.
类实现接口Comparable,这个类就具有了自然顺序。
-
Student类具有自然顺序
-
实现接口Comparable,重写方法compareTo
-
/*** 重写方法compareTo* 返回int类型* 参数 : 要参与比较的对象* this对象和student对象** 红黑树,后来的对象是this,原有的对象是参数*/public int compareTo(Student student){return this.age - student.age;}
-
自定义比较器
-
java.util.Comparator接口
-
/*** 自定义的比较器* 实现接口,重写方法*/
public class MyCom implements Comparator<Student> {@Override/*** TreeSet集合自己调用方法* 传递参数* Student o1, Student o2* o1是后来的对象* o2是已经有的对象*/public int compare(Student o1, Student o2) {return o1.getAge() - o2.getAge();}
}
Set<Student> set = new TreeSet<Student>( new MyCom());
图三:TreeSet集合的构造器
10. LinkedHashSet
底层的数据结构是哈希表,继承HashSet
LinkedHashSet数据是双向链表有序的集合,存储和取出的顺序一样
public static void main(String[] args) {Set<String> set = new LinkedHashSet<>();set.add("b");set.add("e");set.add("c");set.add("a");set.add("d");System.out.println("set = " + set);
}
11. Collections工具类
-
java.util.Collection 集合的顶级接口
-
java.util.Collections 操作集合的工具类
-
工具类的方法全部静态方法,类名直接调用
-
主要是操作Collection系列的单列集合,少部分功能可以操作Map集合
-
/*** 集合操作的工具类* Collections* 工具类有组方法: synchronized开头的** 传递集合,返回集合* 传递的集合,返回后,变成了线程安全的集合*/
public class CollectionsTest {public static void main(String[] args) {sort2();}//集合元素的排序,逆序public static void sort2(){List<Integer> list = new ArrayList<Integer>();list.add(1);list.add(15);list.add(5);list.add(20);list.add(9);list.add(25);System.out.println("list = " + list);//Collections.reverseOrder() 逆转自然顺序Collections.sort(list,Collections.reverseOrder());System.out.println("list = " + list);}//集合元素的排序public static void sort(){List<Integer> list = new ArrayList<Integer>();list.add(1);list.add(15);list.add(5);list.add(20);list.add(9);list.add(25);System.out.println("list = " + list);Collections.sort(list);System.out.println("list = " + list);}//集合元素的随机交换位置public static void shuffle(){List<Integer> list = new ArrayList<Integer>();list.add(1);list.add(15);list.add(5);list.add(20);list.add(9);list.add(25);System.out.println("list = " + list);Collections.shuffle(list);System.out.println("list = " + list);}//集合的二分查找public static void binarySearch(){List<Integer> list = new ArrayList<Integer>();list.add(1);list.add(5);list.add(9);list.add(15);list.add(20);list.add(25);int index = Collections.binarySearch(list, 15);System.out.println(index);}
}
12. 泛型 Generic
泛型技术是JDK版本一大升级,源自于JDK1.5
泛型就是集合类<泛型>
//无泛型写法
public static void main(String[] args) {/*** JDK没有泛型技术,就是这样写* 集合可以存储任何数据类型* 添加元素的数据类型是Object*/List list = new ArrayList();list.add("a");list.add(1);Iterator it = list.iterator();while (it.hasNext()){Object obj = it.next();//不能类型转换System.out.println(obj);}
}
12.1 泛型的安全机制
软件升级:安全性提高,修复Bug错误,改善用户体验,增加功能,提升性能
JDK1.5里程碑版本
泛型作用:强制了集合存储固定的数据类型
泛型的书写格式:
集合类<存储的数据类型> 变量名 = new 集合类<存储的数据类型>();类型可以不写:钻石操作符
加入泛型后,程序的安全性提升了
public static void main(String[] args) {/*** JDK没有泛型技术,就是这样写* 集合可以存储任何数据类型* 添加元素的数据类型是Object*/List<String> list = new ArrayList<String>();list.add("a");list.add(1); //编译错误,数据类型不匹配Iterator<String> it = list.iterator();while (it.hasNext()){String obj =it.next(); //类型转换不需要System.out.println(obj);}}
-
使用泛型的好处:
-
安全性提高了
-
程序的代码量减少
-
避免了类型的强制转换
-
程序的问题,由运行时期,提前到编译时期
-
12.2 泛型中的 E 问题
E没有什么实际价值,只是一个变量而已
特殊:等待接收指定的数据类型
//ArrayList<E>
//创建对象
ArrayList<String> al = new ArrayList<String>();
//E 不在是E了,变成Stringpublic boolean add(String e) {}
12.3 自定义泛型类
/*** 定义类,类名叫工厂* 自定义泛型类* Factory<什么都可以写> 只是变量名而已*/
public class Factory<QQ> {private QQ q;public void setQ(QQ q){this.q = q;}public QQ getQ(){return q;}
}
public static void main(String[] args) {//创建对象Factory类对象// Factory factory = new Factory();//没有泛型,QQ就是ObjectFactory<String> factory = new Factory<String>();factory.setQ("abc");String s = factory.getQ();System.out.println(s);Factory<Double> factory2 = new Factory<Double>();factory2.setQ(1.5);Double q = factory2.getQ();System.out.println(q);
}
12.4 泛型方法
/*** 泛型的方法,方法参数上*/
public class Factory<Q> {/** 静态方法* Q是非静态的, Q的数据类型,是new的时候指定的** 静态方法参数中的泛型,不能和类一样* 静态方法的泛型,需要在方法上单独定义* 写在返回值类型的前面*/public static <T> void staticMethod(T q){System.out.println(q);}public void print(Q q){System.out.println(q);}
}
12.5 泛型接口
-
实现类实现接口,不实现泛型
-
实现类实现接口,同时指定泛型
//泛型接口
public interface Inter <T> {public abstract void inter(T t);
}
/*** 实现接口,不理会泛型* 对象创建的时候,指定类型*/
public class InterImpl<T> implements Inter<T>{public void inter(T t){System.out.println(t);}
}
/*** 实现接口,同时指定泛型*/
public class InterImpl2 implements Inter<String> {public void inter(String s) {System.out.println("s=="+s);}
}
public class GenericTest {public static void main(String[] args) {Inter<String> in = new InterImpl<String>();in.inter("ok");Inter in2 = new InterImpl2();in2.inter("kkk");}
}
实现接口,但是不实现泛型,会在调用方法传入参数时才确认数据类型,即参数类型会变成Object。
12.6 泛型通配符
?指可以是任意引用类型
//泛型的通配符
public class GenericTest {public static void main(String[] args) {List<String> stringList = new ArrayList<String>();stringList.add("abc");stringList.add("bbc");List<Integer> integerList = new ArrayList<Integer>();integerList.add(1);integerList.add(2);each(stringList);each(integerList);}/*** 定义方法,可以同时迭代器 遍历这两个集合* 方法的参数,是要遍历的集合,不确定是哪个集合* 定义参数,写接口类型,不要写实现类*/public static void each(List<?> list){Iterator<?> it = list.iterator();while (it.hasNext()){Object obj = it.next();System.out.println(obj);}}
}
12.7 泛型限定
泛型限定:限制的是数据类型
-
<? extends Company> 传递类型可以是Company或者是他的子类
-
<? extends E>传递E类型或者是E的子类,泛型上限限定
-
<? super E >传递E类型或者是E的父类,泛型下限限定
public static void main(String[] args) {//创建集合,存储员工对象//开发部的List<Development> devList = new ArrayList<Development>();//存储开发部员工对象Development d1 = new Development();d1.setName("张三");d1.setId("开发部001");Development d2 = new Development();d2.setName("张三2");d2.setId("开发部002");devList.add(d1);devList.add(d2);//财务部集合List<Financial> finList = new ArrayList<Financial>();Financial f1 = new Financial();f1.setName("李四");f1.setId("财务部001");Financial f2 = new Financial();f2.setName("李四2");f2.setId("财务部002");finList.add(f1);finList.add(f2);System.out.println(devList);System.out.println(finList);each(devList);each(finList);// List<Integer> integerList = new ArrayList<>();// integerList.add(1);// each(integerList);
}
/*** 要求 : 定义方法* 同时遍历2个集合* 遍历的同时取出集合元素,调用方法work()* ? 接收任何一个类型* 只能接收 Company和子类对象* 明确父类,不能明确子类*/
public static void each(List<? extends Company> list){Iterator<? extends Company> it = list.iterator();while (it.hasNext()){//取出元素Company obj =it.next();obj.work();}
}
13. 增强型的for循环
JDK1.5出现的特性:循环的特性 (少些代码)
Collection是单列集合的顶级接口,但是到JDK1.5后,为Collection找了个爹
java.lang.Iterable接口:实现接口,就可以成为 "foreach"语句的目标
Collection、List、Set都继承了接口,包括数组
Iterable接口定义了foreach()和iterator()两个方法
13.1 for的格式
for(数据类型 变量名 : 集合或者数组){}
-
遍历数组
/*** for循环遍历数组* for(数据类型 变量名 : 集合或者数组){}*/public static void forArray(){int[] arr = {1,3,5,7,9};for(int i : arr){System.out.println(i+1);}System.out.println("arr=="+arr[0]);}
-
遍历集合
/* for循环遍历集合*/public static void forList(){List<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");for(String s : list){System.out.println(s);}}
14. Map接口
java.util.Map接口,是双列集合的顶级接口。
Map集合容器每次存储2个对象,一个对象称为键(Key),一个对象称为值(Value)。
在一个Map的集合容器中,键保证唯一性,不包含重复键,每个键只能对应一个值
14.1 Map接口方法
-
V put(K,V)存储键值对,存储重复键,返回被覆盖之前的值
/**
* put方法,存储键值对
* Map接口的实现类HashMap
*/
public static void mapPut(){//创建对象,指定键的数据类型,值的数据Map<String,Integer> map = new HashMap<String,Integer>();map.put("a",1);map.put("b",2);map.put("c",3);map.put("d",4);
//相同键,返回被覆盖的值Integer value = map.put("c",5);System.out.println("map = " + map);System.out.println("value = " + value);
}
-
V get(K)通过键获取值,参数传递键,找这个键对应的值,没有这个键返回null
/**
* V get(K)通过键获取值,参数传递键,找这个键对应的值,没有这个键返回null
*/
public static void mapGet(){//创建对象,指定键的数据类型,值的数据Map<String,Integer> map = new HashMap<String,Integer>();map.put("a",1);map.put("b",2);map.put("c",3);map.put("d",4);//键找值Integer value = map.get("f");System.out.println(value);
}
-
boolean containsKey(K)判断集合是否包含这个键,包含返回true
-
boolean containsValue(V)判断集合是否包含这个值,包含返回true
-
int size() 返回集合长度,Map集合中键值对的个数
-
V remove(K)移除指定的键值对,返回被移除之前的值
-
Collection<V> values() Map集合中的所有的值拿出,存储到Collection集合
/*boolean containsKey(K)判断集合是否包含这个键,包含返回true
- boolean containsValue(V)判断集合是否包含这个值,包含返回true
- int size() 返回集合长度,Map集合中键值对的个数
- V remove(K)移除指定的键值对,返回被移除之前的值
- Collection<V> values() Map集合中的所有的值拿出,存储到Collection集合
*/
public static void mapMethod(){//创建集合,键是整数,值是StringMap<Integer,String> map = new HashMap<Integer, String>();map.put(1,"a");map.put(2,"b");map.put(3,"c");map.put(4,"d");map.put(5,"e");//boolean containsKey(K)判断集合是否包含这个键,包含返回trueboolean b = map.containsKey(1);System.out.println("集合中包含键:"+b);//boolean containsValue(V)判断集合是否包含这个值,包含返回trueb = map.containsValue("c");System.out.println("集合中包含值:"+b);//size()返回集合的长度int size = map.size();System.out.println("集合长度:"+size);//V remove(K)移除指定的键值对,返回被移除之前的值String value = map.remove(1);System.out.println("被删除之前的:"+value);System.out.println(map);//Collection<V> values() Map集合中的所有的值拿出,存储到Collection集合Collection<String> coll = map.values();for(String s : coll){System.out.println(s);}
}
14.2 Map集合的遍历——键找值
-
实现思想 :
-
Map接口定义了方法 keySet() 所有的键,存储到Set集合
-
遍历Set集合
-
取出Set集合元素 Set集合的元素是Map集合的键
-
Map集合方法get()传递键获取值
-
/*** - Map接口定义了方法 keySet() 所有的键,存储到Set集合* - 遍历Set集合* - 取出Set集合元素 **Set集合的元素是Map集合的键*** - Map集合方法get()传递键获取值*/
public static void mapKeySet(){Map<String,String> map = new HashMap<String, String>();map.put("a","java");map.put("b","c++");map.put("c","php");map.put("d","python");map.put("e","erlang");//Map接口定义了方法 keySet() 所有的键,存储到Set集合Set<String> set = map.keySet();//遍历Set集合Iterator<String> it = set.iterator();//取出Set集合元素 **Set集合的元素是Map集合的键**while (it.hasNext()){String key = it.next();//Map集合方法get()传递键获取值String value = map.get(key);System.out.println(key+"==="+value);}
}
14.3 Map集合的遍历——键值对映射关系
-
实现思想 :
-
Map接口的方法 Set< Map.Entry<Key,Value> > entrySet()【泛型可以多个表示】
-
方法返回Set集合,集合中存储的元素,比较特别
-
存储的是Map集合中,键值对映射关系的对象,内部接口 Map.Entry
-
-
遍历Set集合
-
取出Set集合的元素
-
是Map.Entry接口对象
-
接口的对象方法:getKey(),getValue()
-
-
public static void mapEntrySet(){Map<String,String> map = new HashMap<String, String>();map.put("a","java");map.put("b","c++");map.put("c","php");map.put("d","python");map.put("e","erlang");//Map接口的方法 Set< Map.Entry<Key,Value> > entrySet()Set<Map.Entry<String,String>> set = map.entrySet();//- 遍历Set集合Iterator<Map.Entry<String,String>> it = set.iterator();while (it.hasNext()){//取出Set集合的元素Map.Entry<String,String> entry = it.next();//- 接口的对象方法: getKey() ,getValue()String key = entry.getKey();String value = entry.getValue();System.out.println(key +"==="+ value);}}
15. HashMap 实现类
-
HashMap集合特点
-
是哈希表结构【Set和Map的底层数据结构都是是哈希表】
-
保证键唯一性,用于键的对象,必须重写hashCode,equals方法【伞公司写的hashCode方法不对外开放的,所以不知道写了什么。但是能确定的一点是,只要是桐哥类建立的对象,他们的哈希值都是一样的。所以保证键唯一性需要重写hashCode,equals方法】
-
线程不安全集合,运行速度快
-
集合运行使用null,作为键或者值
-
/*** HashMap集合* 键是Person,值是String*/public static void hashMap2(){Map<Person,String> map = new HashMap<Person, String>();map.put(new Person("a",20),"广东");map.put(new Person("b",22),"香港");map.put(new Person("b",22),"贵港");map.put(new Person("c",24),"澳门");map.put(new Person("d",26),"深圳");System.out.println("map = " + map);}/*** HashMap集合* 键是字符串,值是Person*/public static void hashMap1(){Map<String, Person> map = new HashMap<String, Person>();map.put("a",new Person("张三",20));map.put("b",new Person("张三",20));map.put("c",new Person("张三",20));map.put(null,null);//Set<String> set = map.keySet();for(String key : map.keySet()){//Person person = map.get(key);System.out.println(key+"==="+map.get(key));}System.out.println("==============");//Set<Map.Entry<String,Person>> set = map.entrySet();for(Map.Entry<String,Person> entry : map.entrySet()){System.out.println(entry.getKey()+"==="+entry.getValue());}
16. Hashtable 实现类
Map接口的实现类Hashtable,Hashtable类诞生于JDK1.0版本,Map接口诞生于JDK1.2版本。 Hashtable类从JDK1.2开始,改进为实现Map接口。
-
Hashtable类的特点
-
底层数据结构是哈希表
-
线程安全的,运行速度慢,被更加先进的HashMap取代
-
不允许null值,null键,存储null直接抛出空指针异常。
-
17. LinkedHashMap 实现类
LinkedHashMap继承HashMap实现Map接口,LinkedHashMap底层实现原理是哈希表,双向链,存取有序。其它的特性和父类HashMap一样。
public static void main(String[] args) {Map<String,String> map = new LinkedHashMap<String, String>();map.put("aa","qq");map.put("123","qq");map.put("bbb","qq");System.out.println(map);
}
18. Vector 实现类
List接口的实现Vector,命运和Hashtable一样。
-
Vector类的特点
-
底层实现结构是数组
-
数组的默认容量是10,每次扩容是原来的长度*2
-
线程安全,运行速度慢,被ArrayList取代
-
19. TreeMap 实现类
-
TreeMap集合的特点
-
底层实现是红黑树结构 (添加查询速度比较快)
-
存储到TreeMap中元素,对键进行排序
-
排序依据 :
-
对象的自然顺序,作为键的对象,实现了接口Comparable
-
自己提供比较器,实现接口Comparator,优先级高
-
-
线程不安全的,运行速度快
-
/*** TreeMap集合存储对象* Student作为键,字符串是值* 自定义的比较器排序*/public static void treeMap2(){Map<Student,String> map = new TreeMap<Student, String>( new MyCom() );map.put(new Student("a",20),"广东");map.put(new Student("b",19),"广西");System.out.println("map = " + map);}/*** TreeMap集合存储对象* Person作为键,字符串是值*/public static void treeMap1(){Map<Person,String> map = new TreeMap<Person, String>();map.put(new Person("a",20),"广东");map.put(new Person("b",19),"广西");System.out.println("map = " + map);}
/*** 自定义的比较器,实现接口 Comparator*/
class MyCom implements Comparator<Student>{/*** 方法compare 是TreeMap调用* 传递参数,后来的对象传递到s1, 已经有的对象传递到s2*/public int compare(Student s1, Student s2){return s1.getAge() - s2.getAge();}}
/*** 进行比较:* compareTo方法由,集合TreeMap调用* 传递相关的参数 集合中后来的对象是this,先来的对象是参数 p*/public int compareTo(Person p){return this.age - p.age;}
20. Properties 实现类
-
Properties集合特点
-
继承Hashtable,实现Map接口
-
底层是哈希表结构
-
线程是安全的,运行速度慢
-
集合没有泛型的写法,键和值的数据类型锁定为String类型
-
集合有自己的特有方法
-
此集合可以和IO流对象结合使用,实现数据的持久存储
-
方法和IO相关:load(输入流)
-
/*** 集合遍历* Properties类的方法 stringPropertyNames() [等效于map.keySet()] 返回Set集合* Set集合存储的是 Properties集合的所有键*/public static void prop3(){Properties prop = new Properties();prop.setProperty("a","1");prop.setProperty("b","2");prop.setProperty("c","3");Set<String> set = prop.stringPropertyNames();for(String key : set){System.out.println(key +"=="+ prop.getProperty(key));}}/*** 集合取出元素* Properties集合取出方法 getProperty(String key)*/public static void prop2(){Properties prop = new Properties();prop.setProperty("a","1");prop.setProperty("b","2");prop.setProperty("c","3");System.out.println(prop);String value = prop.getProperty("a");System.out.println(value);}/*** 集合存储键值对* Map接口,存储方法put* Properties集合存储方法 setProperty(String key,String value)*/public static void prop1(){Properties prop = new Properties();prop.setProperty("a","1");prop.setProperty("b","2");prop.setProperty("c","3");System.out.println(prop);}
相关文章:

Java的第十二篇文章——集合
目录 第十二章 集合 学习目标 1. 集合框架的由来 2. 集合框架的继承体系 3. Collection接口 3.1 Collection接口的常用方法 4. Iterator接口 4.1 Iterator接口的抽象方法 4.2 获取迭代器接口实现类 4.3 迭代器的实现原理 4.4 并发修改异常 4.5 集合存储自定义对象并…...

docker 镜像制作 与 CI/CD
目录 镜像到底是什么? 使用docker创建镜像 步骤: 1、编辑Dockerfile(Dockerfile是docker制作镜像的配方文件) 2、编辑requirements.txt文件 3、编辑app.py文件,我们的程序文件 4、生成镜像文件 5、查看生成的镜…...

Spring Boot 异常报告器解析
基于Spring Boot 3.1.0 系列文章 Spring Boot 源码阅读初始化环境搭建Spring Boot 框架整体启动流程详解Spring Boot 系统初始化器详解Spring Boot 监听器详解Spring Boot banner详解Spring Boot 属性配置解析Spring Boot 属性加载原理解析Spring Boot 异常报告器解析 创建自定…...

瑞亚太空活动公司RSA与英国国防与安全加速器达成量子项目合作
(图片来源:网络) 瑞亚太空活动公司(RSA)与英国国防与安全加速器(DASA)签署了合作协议,主要开发名为“无限交换”的可操纵量子真空的技术项目。这是RSA在英国签订的第一份合同&…...

Shapley值法介绍及实例计算
Shapley值法介绍及实例计算 为解决多个局中人在合作过程中因利益分配而产生矛盾的问题,属于合作博弈领域。应用 Shapley 值的一大优势是按照成员对联盟的边际贡献率将利益进行分配,即成员 i 所分得的利益等于该成员为他所参与联盟创造的边际利益的平均值…...

不用手动改 package.json 的版本号
“为什么package.json 里的版本还是原来的,有没有更新?”,这个时候我意识到,我们完全没有必要在每次发布的时候还特意去关注这个仓库的版本号,只要在发布打tag的时候同步一下即可 node.js 部分,我们得有一个…...

gitlab Can‘t update,dev has no tracked branch
代码仓库迁移到gitlab后本地更改仓库地址后 拉取代码报错: Can’t update,dev has no tracked branch: 解决办法: 在当前项目的目录下运行命令: git branch -u git dev --set-upstream-toorigin/dev第一个dev是本地分支名字&…...

sql批量操作
SQl: 1,在某一字段后批量增加内容:UPDATE 表名 SET 字段 CONCAT(字段,要增加的内容) 例:UPDATE b8_niuniu_permission SET game_ids CONCAT(game_ids,,3) (或者后面可以加where条件) 2,批量修改某一字段…...

数据库监控与调优【九】—— 索引数据结构
索引数据结构-B-Tree索引、Hash索引、空间索引、全文索引 二叉树查找 对于相同深度的节点,左侧的节点总是比右侧的节点小。在搜索时,如果要搜索的值key大于根节点(图中6),就会在右侧子树里查找;key小于根…...

哈工大计算机网络传输层详解之:流水线机制与滑动窗口协议
哈工大计算机网络传输层详解之:流水线机制与滑动窗口协议 哈工大计算机网络课程传输层协议详解之:可靠数据传输的基本原理哈工大计算机网络课程传输层协议详解之:TCP协议哈工大计算机网络课程传输层协议详解之:拥塞控制原理剖析 …...

Unity Mac最新打苹果包流程
作者介绍:铸梦xy。IT公司技术合伙人,IT高级讲师,资深Unity架构师,铸梦之路系列课程创始人。 IOS详细打包流程1.申请APPID2.申请开发证书3.创建描述文件 IOS详细打包流程 1.申请AppID 2.创建证书 3.申请配置文件(又名描…...

【MySQL数据库 | 第二十篇】explain执行计划
目录 前言: explain: 语法: 总结: 前言: 上一篇我们介绍了从时间角度分析MySQL语句执行效率的三大工具:SQL执行频率,慢日志查询,profile。但是这三个方法也只是在时间角度粗略的…...

学Python能做哪些副业?我一般不告诉别人!建议存好
前两天一个朋友找到我吐槽,说工资一发交完房租水电,啥也不剩,搞不懂朋友圈里那些天天吃喝玩乐的同龄人钱都是哪来的?确实如此,刚毕业的大学生工资起薪都很低,在高消费、高租金的城市,别说存钱&a…...

简化 Hello World:Java 新写法要来了
OpenJDK 的 JEP 445 提案正在努力简化 Java 的入门难度。 这个提案主要是引入 “灵活的 Main 方法和匿名 Main 类” ,希望 Java 的学习过程能更平滑,让学生和初学者能更好地接受 Java 。 提案的作者 Ron Pressler 解释:现在的 Java 语言非常…...

【服务器】springboot实现HTTP服务监听
文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…...

浅谈常见的加密算法及实现
浅谈常见的加密算法及实现 简介: 随着公司业务的发展,系统用户量日益增多,系统安全性问题一直在脑子里反复回旋,以前系统用户少影响面小,安全方面也一直没有进行思考和加固,现如今业务发展了,虽…...

FTP协议详解
简介 FTP(File Transfer Protocol,文件传输协议) 是 TCP/IP 协议组中的协议之一。FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。其中FTP服务器用来存储文件,用户可以使用FTP客户端通过FTP协…...

网络安全|渗透测试入门学习,从零基础入门到精通—渗透中的开发语言
目录 前面的话 开发语言 1、html 解析 2、JavaScript 用法 3、JAVA 特性 4、PHP 作用 PHP 能做什么? 5、C/C 使用 如何学习 前面的话 关于在渗透中需要学习的语言第一点个人认为就是可以打一下HTML,JS那些基础知识,磨刀不误砍柴…...

八大排序算法之归并排序(递归实现+非递归实现)
目录 一.归并排序的基本思想 归并排序算法思想(排升序为例) 二.两个有序子序列(同一个数组中)的归并(排升序) 两个有序序列归并操作代码: 三.归并排序的递归实现 递归归并排序的实现:(后序遍历递归) 递归函数抽象分析: 四.非递归归并排序的实现 1.非递归归并排序算法…...

基于SpringBoot+Html的前后端分离的学习平台
✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景介绍: 在知识大爆炸的现代,怎…...

MySQL实战解析底层---“order by“是怎么工作的
目录 前言 全字段排序 rowid排序 全字段排序 VS rowid排序 前言 在开发应用的时候,一定会经常碰到需要根据指定的字段排序来显示结果的需求以举例市民表为例,假设你要查询城市是“杭州”的所有人名字,并且按照姓名排序返回前1000个人的姓…...

Linux和Shell:开源力量与命令行之美
目录 一、概述二、Linux的简单介绍三、Shell的简单介绍四、Linux和Shell的应用领域五、Shell编程结语: 一、概述 Linux和Shell是开源世界中不可或缺的两个重要组成部分。Linux作为一种自由和开放的操作系统,以其稳定性、安全性和可定制性而备受推崇。而S…...

服务负载均衡Ribbon
服务负载均衡Ribbon Ribbon 介绍Ribbon 案例Ribbon 负载均衡策略Ribbon 负载均衡算法设置自定义负载均衡算法 Ribbon 介绍 Ribbon 是一个的客服端负载均衡工具,它是基于 Netflix Ribbon 实现的。它不像 Spring Cloud 服务注册中心、配置中心、API 网关那样独立部署…...

hibernate vilidator主要使用注解的方式对bean进行校验
hibernate vilidator主要使用注解的方式对bean进行校验,初步的例子如下所示: package com.learn.validate.domain; import javax.validation.constraints.Min; import org.hibernate.validator.constraints.NotBlank; public class Student { //在需要校…...

华为HCIP第一天---------RSTP
一、介绍 1、以太网交换网络中为了进行链路备份,提高网络可靠性,通常会使用冗余链路,但是这也带来了网络环路的问题。网络环路会引发广播风暴和MAC地址表震荡等问题,导致用户通信质量差,甚至通信中断。为了解决交换网…...

Jmeter(二) - 从入门到精通 - 创建测试计划(Test Plan)(详解教程)
1.简介 上一篇文章已经教你把JMeter的测试环境搭建起来了,那么这一篇我们就将JMeter启动起来,一睹其芳容,首先我给大家介绍一下如何来创建一个测试计划(Test Plan)。 2.创建一个测试计划(Test Plan&#x…...

Autosar诊断实战系列06-详解Dem中Event的NvM存储
本文框架 前言1. Dem触发NvM存储的基本流程2. Dem触发NvM存储的layout格式及内容2.1 Event在NvM中的layout格式2.2 Event在NvM中的存储内容2.3 Dem中Event与DTC的存储关系3.组合式Event(多个Event对应一个DTC)的存储处理3.1 仅分配一个Memory Entry3.2 检索方式3.3 一对一方式前…...

04 todoList案例
React全家桶 一、案例- TODO List 综合案例 功能描述 动态显示初始列表添加一个 todo删除一个 todo反选一个 todotodo 的全部数量和完成数量全选/全不选 todo删除完成的 todo 1.1 静态组件构建 将资料包中的todos_page/index.html中核心代码添加到Todo.jsx文件中,…...

海睿思分享 | 浅谈企业数据质量问题
一、数据质量问题场景 在日常工作中,业务领导经常通过BI系统来了解各项业务的业绩情况。倘若某天,他打开某张核心报表,发现当日某个区域的数据一直是空白的。BI开发人员经过几个小时的排查分析,发现是当日该区域的销售数据存在产…...

神经网络:激活函数
在计算机视觉中,激活函数是神经网络中的一种非线性函数,用于引入非线性变换和非线性特性到网络中。激活函数的作用、原理和意义如下: 1. 引入非线性变换: 神经网络的线性组合层(如卷积层和全连接层)只能表…...