1、 Hash表
图上所指的这个变化,是针对JDK1.8中的HashMap特别提出的
2、 Map
Map常用有HashMpa和TreeMap
put之前如果key为引入数据类型,我们需要同时改写equals和hashCode方法,否则可能会出现equals方法为true但是他依旧存储了2个key进去
public class IDCard{
private String idNumber;
public IDCard(String idNumber){
this.idNumber=idNumber;
}
public String getIdNumber(){
return idNumber;
}
public void setIdNumber(String idNumber){
this.idNumber=idNumber;
}
@Override
public boolean equals(Object o){
if(this==o)return true;
if(o==null||getClass()!=o.getCalss()) return false;
IDCard idCard=(IDCard)o;
return Objects.equals(idNumber,idCard.idNumber);
}
//@Override
//public int hashCode(){
// return Objects.hash(idNumber);
//}
}
public static void main(String[] args){
Map map=new Map();
IDCard id1=new IDCard("3201021993");
IDCard id2=new IDCard("3201021993");
System.out.println(id1.hashCode());//1163157884
System.out.println(id1.hashCode());//1956725890 System.out.println(id2.equals(id1));//true map.put(id1,"123"); map.put(id2,"123"); System.out.println(map.size()); }
2.1、 关于map的put方法
put方法:在进行put的时候,我们会先将key执行hashCode方法,返回一个hash码值,通过计算,会最终获得到他存在于我们数组中的具体数组下标位置。hash码值是通过Object类下的一个方法,hashCode()return的一个int数。也就是说如果我们想要确定这个元素应该插入散列表中数组的位置,我们就要重写他的hashCode方法。接下来,我们看当前数组位置是否有值,如果没有值则直接插入到对应的位置。
举个例子:如果你的身份证号相同(equals方法比较相同)可是你的对象内存地址不同(Object的hashCode不同)那么你依旧有可能会插入到同一个map中,因为map在执行put调用equals之前会判断当前数组是否为空内容。
确定了数组位置之后并发现当前是存在元素的,那么就会和元素进行equals方法进行比较,比较之后如果找到了相同的key(equals结果为true)那么我们会将这个元素的value进行修改。
如果不存在true,那么会直接插入。察隅会比较如果当前是单独元素,那么就直接将link到元素后面形成列表,如果当前是一个元素列表,并且这个列表的长度已经到7,那么我们就会将这个元素插入到这个列表中,并且将这个列表进化成红黑树。(进化到红黑树的逻辑是JDK1.8新增的,之前的版本不存在)
2.1、 关于map的get方法
get方法,我们会根据传入的值(key)先通过kay的hashCode算法去获取的hash值,再通过计算得出具体对应存储的数据下标。
比如说:我们要查字典,查“我”,我们有几种方法:逐页查询,或者,我们通过拼音确定wo在第160,那么我们从160页开始查询。 找到位置之后,我们取看这个数组下标位置的元素是否为空,如果为空,则直接返回找不到,如果有东西,那么我们逐个查询,如果是链表就正常循环查找,如果是红黑树,就会使用二分法查找比较。
总结:所以说HashMap即有用ArrayList的查询效率快(它实现通过列表位置去寻找到对用的位置)又拥有LinkedList的快速增删。因为他实际增删和数组增删无关,他是通过列表熔断或者是向树中插入。
2.3、 HashMap原理总结
我们的HashMap如过存在使用一个引用数据类型作为key的话,我们需要同时改写equals和hashCode方法,这个方法我们可以不用首手写,我们可以直接使用IDEA代码生成工具,Alt+insert选择equals and hashCode
2.4、 遍历打印map信息
public static void main(String[] args){
Map<Integer,String> map=new HashMap<>;
map.put(1,"123");
map.put(4,"123");
map.put(5,"123");
map.put(6,"123");
//通过map的keySet()方法,可以将map中的所有key返回成为一个set
Set<Integer> keys = map.keySet();
//通过迭代器遍历set
Ierator<Integer> iterator =key.iterator();
While(iterator.HashNext()){
Integer key=interator.next();
System.out.println("key="+key+",value="+map.get(key));
}
System.out.println("===========1===============");
//方法1:通过增强for循环
for(Integer key:keys){
System.out.println("key="+key+",value="+map.get(key))
}
System.out.println("===========2===============");
//方法2:通过Map.EntrySet
Set<Map.Entry<Integer,String>> entries = map.entrySet();
//迭代器
Iterator<Map.Entry<Integer>,String>> entriesI=entries.iterator();
While(entriesI.hashNext()){
Map.Enty<Integer,String> entrie=entriesI.next();
System.out.println("key="+entrie.getKey()+",value="+entrie.getValue()):
}
System.out.println("===========3===============");
//增强循环
for(Map.Entry<Integer,String> m:entries){
System.out.println("Key="+m.getKey()+",Value="+m.getValue());
}
}
3、 泛型
泛型是用于约定代码,约定指定参数写指定类型的一种功能。
//泛型在声明时声明,实例化的时候可以省略泛型内容,会根据你声明的来。
List<Integer> List=new ArrayList<>();
//此时,由于ArrayList的add方法时这样的:
public boolean add(E e){
ensureCapacityInternal(size+1); //Increments modCount!
elementData[size++]=e;
returrn true;
}
//并且ArrayList的类的声明是这样的
public class ArrayList<E> extends AbstractList<E>
implement List<E>,RandomAccess,Colneable,java.io.Serializable
//所以我们声明的这个Integer为E——泛型类容,由于add方法形参为(E e)所以,只能传入Interger对象
list.add(1);
//不能执行添加Integer以外的数据类型
//比如0.5是double或者Double对象所以不能插入这个集合中
//list.add(0.5);
泛型声明
public class pet<这是泛型标识符可以随便写 extends Animal>{
public void paly(这是泛型标识符可以随便写 animal){
System.out.println("你在和动物玩"+animal);
}
//方法泛型
public <E extends Animal>void getPet(E e){
System.out.println(e);
}
}
public class Dog extends Animal {
}
public class Cat extends Animal{
}
public class Car{
}
public static void main(String[] args){
Pet<Cat> catPet=new Pet<>();
Cat cat=new Car();
Dog god=new Dog();
Car car=new Car();
catPet.play(cat);
//不能传递dog因为泛型约定是Cat
//catPet.play(dog);
Pet<Dog> dogPet=new Pet<>();
dogPet.play(dog);
//不能传递cat因为泛型约定是Dog
//dogPet.play(cat);
//由于Pet的泛型定义时我们要求泛型必须继承Animal
//而Car类并未继承Animal所以Car无法作为泛型声明
//Pet<Car> pet=new Pet<>();
catPet.getPet(dog);
catPet.getPet(cat);
//此时这个不能写,因为方法泛型约定了,参数必须继承Animal
//catPet.getPet(car);
}
<T extends Comparable<? super T>>
//泛型中的extends垢面可以写类或者接口,写类就是要求继承这个类,写接口就是要求继承这个接口
//泛型中写?代表某一个类,过着说这个类要求,比图上述泛型<?super T>就说明,我们的这个泛型T
//必须是实现一个泛型为 T的父类或者说是T本身类的 Comparable接口
//super关键字为超类,如<E super T>就是要求E这个类是T类的父类或者是T本身
4、 Collections.sort方法
sort方法在Collections工具类中存在两个重载方法,一个方法是要求
public static <T extends Comparable<? super T>> void sort(List<T> List){
List.sort(null);
}
第一个方法,参数只要传递一个集合,要求这个集合中的泛型对象必须是实现了Comparable接口,这个接口的中文是“可比较的”,当你实现了“可比较的”接口你需要重写一个方法,叫做compareTo的方法,这个是我们的比较规则,比如::
public class User implements Comparable<User>{
private String name;
private int 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;
}
public User(){
}
@Override
public String toString(){
retuen "User{"+
"name='"+name+'\''+
",age="+age+
'}';
}
//compareTo方法为重写比较大小的方法
//会根据你的返回结果进行大小的比较
//这个方法是返回一个int类型,不过他只会在一你这个数字和0的关系
//如果等于0,说明这两个对象一样大
//否则,大于0或者小于0,存在两个大小关系
@Override
public int compareTo(User o){
//假如我们的规则是根据年龄排序,那么我们就可以写
//if(this.age==o.age){
// return 0;
//}else if(this.age>o.age){
// return 1;
//}else{
// return -1;
//}
//由于该方法只在乎你是否比0大,座椅哦我们就可以直接写成
//return this.age-o.age
//如果我们修改规则,如果年龄相等,按照姓名来排序
if(this.age!=o.age){
return this.age-o.age;
}else{
return this.name.compareTo(o.name);
}
}
}
//测试方法
public static void main(String[] args){
Lsit<User> list = new ArrayList<>();
list.add(new User("zhangsan1",18));
list.add(new User("lise",17));
list.add(new User("wangwu",20));
list.add(new User("zhangsan2",18));
for(User user:list){
System.out.print(user);
}
Collections.sort(list);
System.out.println();
System.out.println("排序后:");
for(User user:list){
System.out.print(user);
}
}
如果想要使用第一个方法,那么我们正确的步骤是:
首先在我们List所储存的泛型类,将这个类实现接口Comparable
第二部,由于实现了这个接口,所以你需要去重写他的抽象方法compareTo(T t)方法
完成了这两步,你就可以直接使用我们的Collections.sort(list);这个方法了
另一个方法是:
public static <T> void sort(List<T> List,Comparator<? super T> c){
List.sort(c);
}
第二个方法,需要传递两个参数,第一个参数是一个集合,这里不要求list的泛型实现了Comparable接口(可比较的),但是你需要给他一个比较规则,就是一个比较器。Comparator 这个“比较器”是让我们可以进行写规则的地方。
我们可以新写一个类,这个类是实现了比较器的类,比如:
public class MyComparator implements Comparator{
@Override
public int compare(Object o1,Object o2){
//这了写规则
return ((User)o1).getAge()-((User)o2).getAge();
}
}
//测试方法
public static void main(String[] args){
Lsit<User> list = new ArrayList<>();
list.add(new User("zhangsan1",18));
list.add(new User("lise",17));
list.add(new User("wangwu",20));
list.add(new User("zhangsan2",18));
for(User user:list){
System.out.print(user);
}
//新建的比较器,这个比较器是我们自己写的,他的规则是根据用户的年龄排序
MyComparator myComparator = new MyComparator();
//此时我们的User类就可以不用去实现Comparable(可比较的这个接口)
Collections.sort(list,myComparator);
System.out.println();
System.out.println("排序后:");
for(User user:list){
System.out.print(user);
}
}
!!!!!当我不想为了一个简答的规则,去写一个新的类,而且这个新的类我又不用在别的地方,有什么简单的放啊么?👇
Lambda表达式 JDK1.8新特性
public static void main(String[] args){
Lsit<User> list = new ArrayList<>();
list.add(new User("zhangsan1",18));
list.add(new User("lise",17));
list.add(new User("wangwu",20));
list.add(new User("zhangsan2",18));
for(User user:list){
System.out.print(user);
}
//list的泛型没有任何约束
Collections.sort(list,(a,b)->{
//这里的规则,要看你来,这里的a,b你也可以以写成x,y都可以
//接下来,这个a,b或者x,y就是你的集合中的泛型对象。
//但是lambda表达式只推荐你在里面写非常简单的代码,
//如果逻辑复杂,推荐你还是使用其他方法
return a.getAge()-b.getAge();
});
//此时就搞定了,这个就是Lambda表达式,箭头函数
System.out.println();
System.out.println("排序后:");
for(User user:list){
System.out.print(user);
}
}
其他方法
public static void main(String[] args){
//创建集合
List<String> list=new ArrayList<String>();
//增加10个不同单词
List.add("this");
List.add("is");
List.add("collection");
List.add("test");
List.add("and");
List.add("we");
List.add("can");
List.add("learn");
List.add("how");
List.add("to");
//打印输出集合中最大元素和最小元素
String strMax=(String) Collections.max(list);
String strMin=(String) Collections.min(list);
System.out.println("最大值"+strMax);
System.out.println("最小值"+strMin);
//按升序打印输出集合中的所有元素
Collections.sort(list);
System.out.println("集合升序");
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
System.out.println(Collections.binarySearch(list,"this"));
//按降序打印输出集合中的所有元素
Collections.reverse(list);
System.out.println("集合降序");
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
5、 List的常用方法
主要!!!start
//添加元素
boolean add(E e);//在集合的末尾处添加一个元素
void add(int index,E e);//向坐标为index的位置添加元素
//向集合的末尾处添加一个集合(可以是List,可以是Map,只要是Collection的实现都有可以)
boolean addAll(Collection<? extends E> c);
boolean addAll (int index,Collection<? extends E> c);//向坐标为index的位置添加一组元素
//从此列表中删除所有元素,无返回,调用即删除
void clear();
//是否包含元素
boolean contains(Object o);//是否包含该元素
boolean containsAll(collection<?> c);//是否包含所有元素
//返回比较两个内容是否相同
boolean equals(Object 0);
//获取坐标位置的值,如果下标超过元素数量 异常:IndexOutOfBoundsException
E get(int index);
//返回此列表中指定元素的第一次出现索引,如果此列表不包含元素,则返回-1
int indexOf(Object o);//正向查找
int lastIndexOf(Object o);//反向查找
//判断是否为空
boolean isEmpty();
//获取list的迭代器
Iterator<E> iterator();
//删除
E remove(int index);
boolean remove(Object o);
boolean removeAll(collection<?> c);
//仅保存集合内容
boolean ratainAll(collection<?> c);
//设置坐标元素成指定元素
E set(int index,E element);
//获取长度
int size();
//需要传递一个比较器,可以使用箭头函数
default void sort(Comparator<? super E>c);
//截取集合通过坐标位置和String一样[),左边包含,右边不包含
List<E> subList(int fromIndex,int toIndex);
//转数组
Object[] toArray();
<T> T[] toArray(T[] a);
主要!!!end
public static void main(String[] args){
List<Integer> list=new ArrayList<>();
//添加元素,add()
//add(E)
list.add(123);
list.add(9);
list.add(5);
list.add(8);
list.add(1,1);
List<Integer> list1=new ArrayList<>();
//添加元素,add()
//add(E)
list1.add(124);
list1.add(125);
list.addAll(list1);
//list.clear();
for(Integer i:list){
//System.out.println(i);
}
//System.out.println(list.contains(123));
//System.out.println(list.containsAll(list1));
//list1.add(168);
//System.out.println(list.containsAll(list1));
//list1.clear();
//System.out.println(list.containsAll(list1));
//System.out.println(list.equals(list));
List<Integer> list2=new LinedLiset<>();
//添加元素,add()
//add(E)
list2.addAll(list1);
//System.out.println(list1==list2);
//System.out.println(list1.equals(list2));
//System.out.println(list2.get(1));
for(Integer i:list){
System.out.println(i);
}
System.out.println(------------------------);
list=list.subList(2,3);
for(Integer i:list){
System.out.println(i);
}
System.out.println("-------------------------");
Integer[] is=new Integer[10];
is=list.toArray(is);
for(Integer i:is){
System.out.println(i);
}
}
集合求交集
public static void main(String[] args){
list<Integer> list1=new ArrayList<>();
list<Integer> list2=new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
//定义交集,先拷贝一个需要寻找交集内容的集合
List <Integer> intersection=(ArrayList<Integer>)list1;
//执行retainAll可以获取二者交集到intersecton
intersection.retainAll(list2);
for(int i:intersection){
System.out.println(i);
}
}
集合求并集
public static void main(String[] args){
list<Integer> list1=new ArrayList<>();
list<Integer> list2=new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
//定义交集,先拷贝一个需要寻找交集内容的集合
List <Integer> intersection=(ArrayList<Integer>)((ArrayLsit<Integer>)list1).clone();
//执行retainAll可以获取两者交集到intersection
intersection.retainAll(list);
System.out.println("交集:");
for(int i:intersection){
System.out.println(i);
}
System.out.println("-------------------------");
//forEach方法
public static void main(String[] args){
List<User> list=new ArrayList<>();
list.add(new User("123",123));
list.add(new User("124",124));
list.add(new User("125",125));
list.forEach(y->x.setAge(x.gatAge()+1));
list.forEach(b->System.out.println(b));
}
主要!!!strat
List<E> list=Arrays.asList(E...e);//将动态封装成List集合
ArrayList arr=...;
ArryList();
ArrayList(int capacity);
ArrayList(Collection<R> list);
//删除满足参数函数条件的元素
//arr.removeIf(Predicator<E> filter);
//删除姓名为zl的学员
//list.removeIf((a)->a.getName().equals("zl"));
//删除年龄小于20岁的学员
//list.removeIf((a)->a.getAge()<20);
//案例
//public static void main(String[] args){
// List<User> list=new ArrayList<>();
// list.add(new User("123",123));
// list.add(new User("124",124));
// list.add(new User("125",125));
// list.removeIf(abc->abc.getAge()>123);
// list.forEach(x->System.out.println(x));
//}
//修剪数组长度为元素实际数量
arr.trimToSize();
//是否村子重复
//如果是,有几个重复
LinkedList<E> list=...
LinkedList();
LinkedList(Collection<E> list);
LinkedList:链表
lsit.addFirst(E e);//头部追加
list.addLast(E e);//尾部追加
Iterator<E> it=list.decendingIterator();//逆向迭代器
E e=list.getFirst();//提取但不删除第一个节点元素
E e=list.getLast();//提取但不删除最后一个节点元素
E e=list.polFirst();//提取并删除第一个节点元素
E e=list.pollLast();//提取并删除最后一个节点元素
E e=list.removeFirstOccurrence(Object obj);//删除第一个匹配节点元素
E e=list.removeLastOccurrence(Object obj);//删除最后一个匹配节点元素
E e=list.removeFirst();//删除第一个节点元素,空报异常
E e=list.removeLast();//删除最后一个节点元素,空报异常
e=list.removeLastOccurrence(Object obj);//删除最后一个匹配节点元素 E e=list.removeFirst();//删除第一个节点元素,空报异常 E e=list.removeLast();//删除最后一个节点元素,空报异常
主要!!!end
6、 Map方法
HashMap<K,V> map =...
HashMap()
HashMap(int initalCapacity)
HashMap(Map(K,V) map)
V v=map.put(K key,V value);//添加键值对
//如果K已存在,V覆盖原有值,并将其返回,不存在返回null
map.putAll(Map<K,V> sub);//添加子Map
V v=map.putIfAbsent(K key,V value);//不存在key添加,否则返回value
Set<Map.Entry<K,V>> set=map.entrySet();//提取所有键值对
Set<K> keys=map.keySet();//提取所有键
Collection<V> values=map.values();//提取所有值
V v=map.get(Object key);//根据键提取值
V v=map.getOrDefault(Object key,V defaultValue);//根据键提取值,不存在返回默认值
int size=map.size();//互殴去键值对的数量
map.clear();//清空
boolean empty=map.isEmpty();//是否为空
boolean has=map.containKey(Object key);//是否存在键
V v=map.remove(Object key);//根据key删除,存在返回键对应的值,否则返回null
boolean yes=map.replace(Object key,Object value);//键值都匹配返回true,否则false
//插入不会判断,这个方法是用于值存在才替换
boolean yes=map.replace(Object key,Object value,Object newValue);
//该方法等同于如下代码:
//if((map.get(key)).equals(value)){
// map.put(key,newValue);
//}
//如 果键值都存在,则替换并返回true,否则返回false
//如果键存在,则替换并返回原值,否则返回null
V v=map。replace(Object key,Object value);