集合本身是一个对象,一个容器,它用来存储对象的引用也就是对象的地址,不存储对象本身和基本数据类型。
Java中每一个不同的集合,底层对应了不同的数据结构。在不同的集合中存储元素,等于数据放到了不同的数据结构中。
常见的数据结构:数组、二叉树、链表、哈希表等。例如ArrayLIst()底层是数组,LinkedList()底层是链表。不同数据结构的存储方式不一样。
Java中已经实现了数据结构,只需要学会合理使用。
所有的集合类和集合接口都在java.util包下。
Java中集合分为两类:一类是单个方式存储元素,它的超级父接口是Collection;一类是以键值对(键和值一一对应)的方式存储元素,它的超级父接口是Map。
掌握集合的继承结构图。泛化关系就是继承关系。
单个方式存储元素的继承结构图
键值对的继承结构图
总结所有实现类:
List集合存储元素特点:有序可重复,元素有下标,存进去的顺序和取出来的顺序一样。可重复是指存进去1,可以再存一个1.
Set集合存储元素特点:无序不可重复,存进去和取出来的顺序不一定相同,元素没有下标。
SortSet集合存储元素特点:由于继承了Set集合,所以它的特点也是无序不可重复。但是放在SortSet集合中的元素可以自动按照大小顺序排序。
放在集合中的元素是一定要重写equals方法的。
package Collection;
import java.util.ArrayList;
import java.util.Collection;
/*
Collection中常用方法
*/
public class Test01 {
public static void main(String[] args) {
//创建一个集合对象
//Collection c=new Collection; 接口是不能实例化的
//多态,父类引用指向子类
Collection c=new ArrayList();
//测试Collection接口中的常用方法
//add,往集合里加元素
c.add(1200);//这里实际上存的是一个对象地址,自动装箱了。
c.add(true);
c.add(new Object());
//获取集合中元素的个数
System.out.println("集合中元素的个数是:"+c.size());
//清空集合
c.clear();
System.out.println("集合中元素的个数是:"+c.size());//0
//再添加元素
c.add("hello");
c.add("浩克");
c.add(1);
System.out.println("集合中元素的个数是:"+c.size());//3
//判断集合中是否包含某一元素,输出一个布尔值
boolean flag1=c.contains("hello");//true
System.out.println(flag1);
boolean flag2=c.contains("绿巨人");//false
System.out.println(flag2);
//删除集合中某一个元素
c.remove(1);
System.out.println("集合中元素的个数是:"+c.size());//2
//判断集合是否为空,集合中是否存在元素
System.out.println(c.isEmpty());//false
c.clear();
System.out.println(c.isEmpty());//true
c.add("abc");
c.add("def");
c.add("100");
c.add("HelloWorld!");
//把集合转化为一个数组
Object[]objects=c.toArray();
//遍历数组
for (Object o:objects) {
System.out.println(o);
//这里自动重写了,o.toString
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2fK4hLRX-1585303209870)(C:\Users\Princekin Yan\AppData\Roaming\Typora\typora-user-images\image-20200319212121162.png)]
package Collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
//集合的遍历/迭代专题,重要指数*****
public class Test02 {
public static void main(String[] args) {
//注意:以下讲解的遍历方式、迭代方式,是所有Collection通用的一种方式
//在Map集合中不能用,在所有的Collection以及子类中使用
//创建集合对象
Collection c=new ArrayList();//重点在前面Collection的接口,如何遍历
//添加元素
c.add("abc");
c.add("def");
c.add(100);
c.add(new Object());
//对集合进行遍历、迭代
//第一步:获取集合对象的迭代器对象Iterator,迭代器是一个对象
//因为Collection继承的Iterable接口中有iterator方法,所以可以调用,返回一个迭代器
Iterator iterator=c.iterator();
//第二步:通过以上获取的迭代器对象开始迭代、遍历集合(重要)
/*
迭代器对象Iterator中的两个方法
boolean hasNext() 如果仍有元素可以迭代,返回true
Object next()返回迭代的下一个元素
*/
boolean hasNext=iterator.hasNext();
while (iterator.hasNext()){
//无论存进去是什么,取出来都是Object
Object object=iterator.next();
System.out.println(object);
}
}
}
/*=======================================================*/
package Collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
/*
集合的迭代、遍历
*/
public class Test03 {
public static void main(String[] args) {
//创建集合对象
Collection c1=new ArrayList();
//添加元素
c1.add(1);
c1.add(2);
c1.add(3);
c1.add(4);
//迭代集合
Iterator it=c1.iterator();
while (it.hasNext()){
Object obj=it.next();
// if(obj instanceof Integer){
// System.out.println("Integer类型");
// }
//存进去什么类型取出来还是什么类型,只不过输出时转为了String
//这里println会调用toString方法
System.out.println(obj);
}
//HashSet集合,无序不可重复
Collection c2=new HashSet();
c2.add(100);
c2.add(200);
c2.add(300);
c2.add(200);
c2.add(400);
c2.add(100);
Iterator it2=c2.iterator();
while (it2.hasNext()){
System.out.println(it2.next());
//存进去和取出来的顺序不一定相同,重复的元素不能存储
}
}
}
当集合的结构发生改变时,迭代器必须重新获取,否则会出现异常。
package Collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test06 {
public static void main(String[] args) {
//创建集合,
Collection c=new ArrayList();
//此时获取的迭代器,指向的是集合中没有元素时的迭代器
// Iterator iterator=c.iterator();
// 一定要注意,集合结构发生改变,迭代器必须重新获取
//否则会有异常Exception in thread "main" java.util.ConcurrentModificationException
//添加元素
c.add(1);
c.add(2);
c.add(3);
//重新获取迭代器
Iterator iterator=c.iterator();
while(iterator.hasNext()){
Object obj= iterator.next();
System.out.println(obj);
}
}
}
package Collection;
import java.util.ArrayList;
import java.util.Collection;
/*
深入集合的contains方法
boolean contains(Object o)
判断集合中是否包含某对象,如果包含返回true,不包含返回false
contains方法是用来判断集合中是否包含某个元素的,它在底层调用了equals方法进行比对。
*/
public class Test04 {
public static void main(String[] args) {
//创建集合对象
Collection c=new ArrayList();
//向集合里存储元素
String s1=new String("abc");//0x111
String s2=new String("def");//0x222
c.add(s1);
c.add(s2);
//集合中元素个数
System.out.println("集合中元素个数是:"+c.size());
String x=new String("abc");//0x555
System.out.println(c.contains(x));
//返回是true,因为contains调用了equals方法
//实际上是判断它集合中是否包含“abc”
}
}
Collection接口中的remove方法和contains方法底层都会调用equals方法。放在集合中的元素要重写equals方法,重写比较的是内容,不重写比较的是地址。也就是说equals是需要重写的。
package Collection;
import java.util.ArrayList;
import java.util.Collection;
/*
测试contains方法
*/
public class Test05 {
public static void main(String[] args) {
Collection c=new ArrayList();
User u1=new User("jack");
User u2=new User("jack");
c.add(u1);
//判断集合是否包含u2
System.out.println(c.contains(u2));
/*
在没有重写equals之前,这个结果是false。调用的是Object的equals方法,比较的是对象的地址
在重写equals方法之后,就比较内容了。名字一样就不再比较内容了。
*/
}
}
class User{
private String name;
public User(String name){
this.name=name;
}
//重写equals方法,则调用重写的equals方法
//这个equals方法比较的是内容
public boolean equals(Object o){
if(o==null||!(o instanceof User)) return false;
if(o==this) return true;
User u=(User)o;
//如果名字一样,就不再比较对象的内存地址了。
return u.name.equals(this.name);
}
}
package Collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
/*
测试remove方法
*/
public class Test05 {
public static void main(String[] args) {
Collection c=new ArrayList();
//创建一个字符串
String s1=new String ("hello");
//字符串放进集合中
c.add(s1);
//创建一个新的字符串
String s2=new String("hello");
//删除s2
c.remove(s2);
//集合中元素个数
System.out.println(c.size());//0
}
}
class User{
private String name;
public User(String name){
this.name=name;
}
//重写equals方法,则调用重写的equals方法
//这个equals方法比较的是内容
// public boolean equals(Object o){
// if(o==null||!(o instanceof User)) return false;
// if(o==this) return true;
// User u=(User)o;
// //如果名字一样,就不再比较对象的内存地址了。
// return u.name.equals(this.name);
// }
//alt +ins 自动插入equals方法重写
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(name, user.name);
}
}
package Collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
//在迭代元素的过程中,一定要使用迭代器的remove()方法删除元素,不要使用集合自带的remove方法
public class Test06 {
public static void main(String[] args) {
//创建集合,
Collection c=new ArrayList();
//添加元素
c.add(1);
c.add(2);
c.add(3);
//重新获取迭代器
Iterator iterator=c.iterator();
while(iterator.hasNext()){
Object obj= iterator.next();
/*
c.remove(obj);
删除元素,删除之后集合的结构发生了改变,应该重新获取迭代器
但是,循环下一次的时候并没有重新获取迭代器,所以会出现异常
*/
iterator.remove();
//删除的一定是迭代器指向的当前元素
//使用迭代器删除,会更新迭代器和集合
System.out.println(obj);
}
System.out.println(c.size());//0
}
}
package List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/*
List接口中常用方法
1.List集合存储元素特点:有序可重复,从0开始,以1递增。
可重复存储相同元素。
2.List特色的方法:
void add(int index,E element)
Object get(int index)
int indexOf(Object o)
int LastIndexOf(Object o)
Object remove(int index)
Object set(int index, Object elment)
现在以理解为主,开发时遇到再查找文档
*/
public class Test01 {
public static void main(String[] args) {
//List list=new LinkedList();
List list=new ArrayList();
//添加元素
list.add("A");
list.add("C");
list.add("B");
list.add("C");//向列表尾部添加元素
//特有方法
list.add(1,"King");//在指定位置添加元素,效率较低
Iterator it=list.iterator();
while (it.hasNext()){
Object obj=it.next();
System.out.println(obj);
}
//根据下标获取元素
// Object obj=list.get(0);
// System.out.println(obj);
//因为有下标,所以List集合有自己比较特殊的遍历方式,通过下标遍历
for (int i=0;i<list.size();i++){
Object obj=list.get(i);
System.out.println(obj);
}
//获取指定对象第一次出现处的索引。
System.out.println(list.indexOf("King"));//1
//获取指定对象最后一次出现处的索引
System.out.println(list.lastIndexOf("C"));//4
//删除指定下标位置的元素
list.remove(1);
//修改指定位置的元素
list.set(2,"queen");
for (int i=0;i<list.size();i++){
Object obj=list.get(i);
System.out.println(obj);
}
}
}
package Collection.List;
import java.util.ArrayList;
import java.util.List;
/*
ArrayLIst集合:
1.初始化容量为10,底层先创建了一个长度为0的数组,当添加第一个元素时,初始化容量为10
2.集合底层是一个Object[]数组
3.构造方法
new ArrayList();
new ArrayList(20);
4.ArrayList集合的扩容:原容量的1.5倍
ArrayList底层是数组,扩容效率低,建议在使用时预估计元素个数
这是比较重要的优化策略
5.数组优点:检索效率比较高
6.数组缺点:随机增删元素效率比较低,
无法存储大数据量
7.向数组末尾添加元素,效率很高,不受影响
*/
public class ArrayListTest01 {
public static void main(String[] args) {
//默认初始化容量是10
List list1=new ArrayList();
//指定容量为20
List list2=new ArrayList(20);
//size()方法获取的是当前集合中元素的个数,不是集合的容量。
System.out.println(list2.size());//0
}
}
把线程安全的变成线程非安全的
List list1=new ArrayList();//线程非安全的
Collections.synchronizedList(list1);//变成线程安全的
ArrayList的构造方法
package Collection.List;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
/*
集合ArrayList的构造方法
*/
public class ArrayListTest02 {
public static void main(String[] args) {
List list1=new ArrayList();
//指定初始化容量100
List list2=new ArrayList(100);
//创建一个HashSet集合
Collection c=new HashSet();
c.add(100);
c.add(200);
c.add(300);
//把c作为参数传入
//通过这个构造方法,就可以将HashSet转换成List集合
List list3=new ArrayList(c);
}
}
对于链表数据结构来说,基本的单元节点是Node,对于单向链表来说,任何一个节点Node中都有两个属性:第一,存储的数据;第二,下一个节点的内存地址。
链表优点:随机增删元素效率较高,因为不涉及到大量元素位移。
链表缺点:查询效率较低,每一次查询某个元素的时候都需要从头节点开始往下遍历。
package Collection.List;
import java.util.LinkedList;
import java.util.List;
/*
链表的优点:
由于链表上的元素在空间存储上内存地址不连续,所以随机增删元素的时候不会有大量元素位移
因此随机增删效率较高
在以后的开发中,如果遇到随机增删集合元素情况较多,建议使用LinkedList
链表的缺点:
每一次查找元素,都是从头开始遍历,直到找到为止,所以LinkedList查找效率较低。
ArrayList:具有检索优势,但是线程不安全。
LinkedList:具有随机增删优势。
但是添加元素一般都从末尾添加。所以ArrayList用的多
*/
public class LinkedListTest01 {
public static void main(String[] args) {
//LinkedList集合底层也有下标
//ArrayList之所以检索效率高是因为底层数组发挥的作用
//LinkedList集合照样有下标,但是检索效率比较低,因为只能从头节点开始遍历
List list=new LinkedList();
list.add("a");
list.add("b");
list.add("c");
for (int i=0;i<list.size();i++){
Object object=list.get(i);
System.out.println(object);
}
// LinkedList集合中没有初始化容量
// 最初这个链表中没有没有任何元素。first和last引用都是null
}
}
双向链表的基本单元还是Node,
节点包含三个部分:上一个节点的内存地址,数据,下一个节点的内存地址。
对于数据结构,不需要深入理解,掌握方法就可以开发。
大多数情况下,集合中元素类型中元素类型是统一的,需要使用泛型
package Collection.Generic;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/*
泛型这种语法机构,主要是在编译阶段起作用,给编译器看。
使用泛型的好处是,集合中存储的元素类型同一,从集合中取出的类型是泛型制定的类型。
泛型的缺点:导致集合中存储的元素缺乏多样性。
大多数情况下,集合中元素类型中元素类型是统一的,需要使用泛型
*/
public class Test {
public static void main(String[] args) {
//使用泛型List 之后,表示List集合中只允许存储Animal类型的数据
//使用泛型之后,集合中的数据类型统一了
List<Animal>mylist=new ArrayList<Animal>();
Cat cat=new Cat();
Bird bird=new Bird();
mylist.add(cat);
mylist.add(bird);
//获取迭代器
//这表示迭代类型是Animal
Iterator<Animal> iterator=mylist.iterator();
while (iterator.hasNext()){
//使用泛型之后,每一次迭代返回的数据都是Animal类型
Animal a=iterator.next();
/*
*Object obj=iterator.next();
*if(obj InstanceOf Animal)
* Animal a=(Animal)obj;
* */
//这里不需要强制类型转换,直接调用
a.move();
//调用子类的方法还需要转型
if(a instanceof Bird){
((Bird) a).fly();
}
}
}
}
class Animal{
public void move(){
System.out.println("动物在动!");
}
}
class Cat extends Animal{
public void catchMouse(){
System.out.println("猫抓老鼠!");
}
}
class Bird extends Animal{
public void fly(){
System.out.println("鸟在飞!");
}
}
泛型可以自定义
package Collection.Generic;
/*
泛型是可以自定义的
泛型的标识符通常用E、T
element和type
*/
//在类中使用泛型
public class Test02<E> {
//方法中泛型与类中保持一致
public void doSomething(E e){
System.out.println(e);
}
public static void main(String[] args) {
Test02<String> test02=new Test02<>();
//调用doSomething方法中只能是字符串类型
test02.doSomething("abc");
//不用泛型,就是Object类型
Test02 test=new Test02();
test.doSomething(new Object());
}
}
package Collection.HashSet;
import java.util.HashSet;
import java.util.Set;
/*
演示一下HashSet的特点,无序不可重复
*/
public class Test01 {
public static void main(String[] args) {
Set<String> strings=new HashSet<>();
//添加元素
strings.add("hello1");
strings.add("hello1");
strings.add("hello1");
strings.add("hello5");
strings.add("hello4");
strings.add("hello3");
//遍历
for (String s:strings) {
System.out.println(s);
}
/*
输出:
hello1
hello4
hello5
hello3
1.存储时顺序和取出来顺序不一样
2.不可重复
3.实际上是存储到HashMap的key部分
*/
}
}
package Collection.HashSet;
import java.util.Set;
import java.util.TreeSet;
/*
TreeSet集合存储元素的特点:
1.无序不可重复,但是存储元素自动按照大小顺序排序!
称为:可排序集合
2.无序指的是没有下标,存入和取出的顺序不同
*/
public class Test02 {
public static void main(String[] args) {
Set<String> strings=new TreeSet<>();
strings.add("A");
strings.add("A");
strings.add("C");
strings.add("D");
strings.add("B");
strings.add("B");
for (String s:strings) {
System.out.println(s);
}
/*
A
B
C
D
*/
}
}
package Map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/*
Map接口中常用的方法
1.Map和Collection没有继承关系
2.Map集合以key和value的方式存储数据
key和value都是引用数据类型。
都是存储对象的内存地址
key起主导作用,value是key的附属
3.Map接口中常用方法:
V put(K key,V value)
void clear()
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty
V get(Object key)通过key获取value
boolean isEmpty()
Set keySet() 获取Map集合中所有的key
V put(K key,V value)
V remove(Object key) 通过key删除键值对
int size()
Collection values() 获取Map集合中所有的value,返回一个Collection
Set> entrySet()将Map集合转换成Set集合,Map.Entry是一个静态内部类
*/
public class Test01 {
public static void main(String[] args) {
//创建Map集合对象
Map<Integer,String>map=new HashMap<>();
//向Map中添加键值对
map.put(1,"zhangsan1");
map.put(2,"zhangsan2");
map.put(3,"zhangsan3");
map.put(4,"zhangsan4");
//通过key获取value
String value=map.get(2);
System.out.println(value);
//zhangsan2
//获取键值对数量
System.out.println(map.size());//4
map.remove(2);
System.out.println(map.size());//3
//判断是否包含某个key,value
System.out.println(map.containsKey(2));//false
System.out.println(map.containsValue("zhangsan1"));//true
//contains方法底层调用的都是equals方法,自定义类型需要重写equals方法
System.out.println(map.containsValue(new String("zhangsan1")));//true
//获取所有的value
Collection<String>values=map.values();
for (String s:values) {
System.out.println(s);
/*
zhangsan1
zhangsan3
zhangsan4
*/
}
//清空集合
map.clear();
System.out.println(map.size());//0
}
}
package Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*
Map集合的遍历
*/
public class Test02 {
public static void main(String[] args) {
//第一种方式,通过遍历key来遍历value
Map<Integer,String>map=new HashMap<>();
//向Map中添加键值对
map.put(1,"zhangsan1");
map.put(2,"zhangsan2");
map.put(3,"zhangsan3");
map.put(4,"zhangsan4");
//遍历map集合,获取所有的key,所有的key是一个Set集合
Set<Integer> keys=map.keySet();
//遍历所有的key,获取value
//迭代器
Iterator<Integer>iterator=keys.iterator();
while (iterator.hasNext()){
Integer key=iterator.next();
//通过key来获取value
String value=map.get(key);
System.out.println(key+"="+value);
/*
1=zhangsan1
2=zhangsan2
3=zhangsan3
4=zhangsan4
*/
}
//增强for循环
for(Integer key:keys){
System.out.println(key+"="+map.get(key));
/*
1=zhangsan1
2=zhangsan2
3=zhangsan3
4=zhangsan4
*/
}
//第二种方法:Set> entrySet()
/*
这个方法是吧map集合直接全部转换成Set集合。
Set集合中元素的类型是:Map.Entry
*/
Set<Map.Entry<Integer,String>> set=map.entrySet();
//遍历Set集合,每一次取出一个Node
//迭代器
Iterator<Map.Entry<Integer,String>> iterator2=set.iterator();
while (iterator2.hasNext()){
Map.Entry<Integer,String> node =iterator2.next();
Integer key=node.getKey();
String value=node.getValue();
}
//增强for
for(Map.Entry<Integer,String> node:set){
Integer key=node.getKey();
String value=node.getValue();
System.out.println(key+"="+value);
/*
1=zhangsan1
2=zhangsan2
3=zhangsan3
4=zhangsan4
*/
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-puelY4dg-1585303209874)(C:\Users\Princekin Yan\AppData\Roaming\Typora\typora-user-images\image-20200326152815573.png)]
package collection.HashMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
HashMap集合
1.HashMap的底层是哈希表的数据结构
2.哈希表:
是一个数组和单向链表的结合体
数组:查询效率高,随机增删效率低
单向链表:随机增删效率高,查询效率低
哈希表将以上两种数据结构融合在一起
3.哈希表:一维数组,数组中每一个元素是一个单向链表
4.最主要掌握的是:存取的两个方法
map.put(k,v)
v=map.get(k)
增删都在链表上完成,查询也只是部分扫描
5.HashMap集合的key部分特点:
无序、不可重复
为什么会无序?因为不一定会挂在哪个单向链表上
equals方法来保证HashMap集合的key不可重复
如果key重复了,value会覆盖
放在HasMap集合中key部分的元素,其实就是放到了HashSet集合中。
所以HashSet集合中的元素也需要重写hashCode()+equals()方法
6.哈希表HashMap使用不当时,无法发挥性能
hashCode()返回值是数组的下标,如果hashCode()返回值固定,哈希表相当于一个链表
如果每一个hashCode()返回值都不同,相当于一个数组
7.重点:放在HashMap集合key部分的元素,以及放在HashSet集合中的元素,需要同时重写hashCode和equals方法。
8.HashMap的默认容量是16(2的4次),默认加载因子是0.75(了解),当容量达到75%时,数组开始扩容
*/
public class Test01 {
public static void main(String[] args) {
//测试HashMap集合key部分的元素特点
//Integer是key,它的hashCode和equals都重写了
Map<Integer,String> map=new HashMap<>();
map.put(1,"zhangsan1");
map.put(2,"zhangsan2");
map.put(3,"zhangsan3");
map.put(1,"lisi");//key重复的时候value会自动覆盖
map.put(5,"wangwu");
System.out.println(map.size());//4
//遍历
Set<Map.Entry<Integer,String>> set=map.entrySet();
for (Map.Entry<Integer,String> entry:set){
System.out.println(entry.getKey()+"="+entry.getValue());
//验证结果就是:HashMap集合key部分元素,无序不可重复
}
}
}
package collection.HashMap;
import java.util.HashSet;
import java.util.Set;
/*
1.向Map集合中存取,首先调用的是hashCode方法,然后是equals方法
put(k,v)时,当数组下标对应位置是null,不需要调用equals方法
get(k)时,如果单向链表上只有一个元素,也不用调用equals方法
2.注意:
如果一个类的equals()方法重写了,那么hashCode()方法也必须重写
并且equals方法返回如果是true,hashCode返回值必须一样
*/
//终极结论,放在HashMap集合key部分、以及HashSet中的元素,要同时重写hashCode和equals
public class Test02 {
public static void main(String[] args) {
Student student1=new Student("zhangsan");
Student student2=new Student("zhangsan");
//重写equals方法之前
//System.out.println(student1.equals(student2));//false
//重写equals方法之后
System.out.println(student1.equals(student2));//true
System.out.println(student1.hashCode());//885284298 重写:-1432604525
System.out.println(student2.hashCode());//1389133897 重写:-1432604525
// s1.equals(s2)结果已经是true,表示s1和s2是一样的,
//那么往HashSet集合中放,按理说只能放一个
Set<Student> students=new HashSet<>();
students.add(student1);
students.add(student2);
System.out.println(students.size());//不重写hashCode,结果是2,不符合HashSet存储特点
//所以equals重写了,hashCode()必须重写
//重写之后结果是1
}
}
/*====================================================================*/
package collection.HashMap;
import java.util.Objects;
public class Student {
private String name;
public Student(){
}
public Student(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//equals重写,如果名字一样,表示同一个学生
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
package collection.HashMap.properties;
import java.util.Properties;
/*
掌握properties属性类的相关方法
Properties是一个Map集合,继承Hashtable,Properties的key与value都是String类
Properties称为属性类对象,线程安全
*/
public class Test01 {
public static void main(String[] args) {
//掌握两个方法,一个存一个取
Properties properties=new Properties();
properties.setProperty("User","name");
properties.setProperty("password","123");
//通过key来获取value
String USer=properties.getProperty("User");
String password=properties.getProperty("password");
System.out.println(USer+password);
}
}
package collection.TreeSet;
import java.util.TreeSet;
/*
1.TreeSet集合底层实际上是一个TreeMap
2.TreeMap集合底层是一个二叉树
3.放到TreeSet集合中的元素:无序不可重复,但是可以按照元素大小顺序自动排序
称为可排序集合。
*/
public class Test01 {
public static void main(String[] args) {
//创建一个TreeSet集合
TreeSet<String >ts=new TreeSet<>();
//添加String
ts.add("zhangsan4");
ts.add("zhangsan1");
ts.add("zhangsan2");
ts.add("zhangsan3");
for (String s:ts){
System.out.println(s);
/*
zhangsan1
zhangsan2
zhangsan3
zhangsan4
自动排序了
*/
}
}
}
package collection.TreeSet;
import java.util.TreeSet;
/*
自定义排序类型
*/
public class Test02 {
public static void main(String[] args) {
Person person1=new Person(25);
Person person2=new Person(35);
Person person3=new Person(37);
Person person4=new Person(45);
//创建TreeSet集合
TreeSet<Person> persons=new TreeSet<>();
//添加元素
persons.add(person1);
persons.add(person2);
persons.add(person3);
persons.add(person4);
//这里要注意实现Compareble接口,对象才可以排序,否则会报错
//如果没有排序,二叉树就无法存元素
//遍历
for(Person p:persons){
System.out.println(p);
/*
Person{age=25}
Person{age=35}
Person{age=37}
Person{age=45}
*/
}
}
}
//实现接口并且重写比较的方法
class Person implements Comparable<Person>{
private int age;
public Person(){
}
public Person(int age){
this.age=age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//需要在这个方法中编写比较的逻辑,或者说比较规则
//按照年龄排序
/*
k.compareTo(t.key)
用参数key和集合中每一个k进行比较,返回值:-1,0,1
*/
@Override
public int compareTo(Person p){
return this.age-p.age;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
}
package collection.TreeSet;
import collection.HashMap.Student;
import java.util.TreeSet;
/*
先按照年龄升序,如果年龄一样,在按照姓名升序
*/
public class Test03 {
public static void main(String[] args) {
TreeSet<Student0> students=new TreeSet<>();
//添加元素
students.add(new Student0("zhangsan1",15));
students.add(new Student0("zhangsan3",19));
students.add(new Student0("zhangsan2",19));
students.add(new Student0("zhangsan4",25));
for (Student0 s:students){
System.out.println(s);
/*
Student{name='zhangsan1', age=15}
Student{name='zhangsan2', age=19}
Student{name='zhangsan3', age=19}
Student{name='zhangsan4', age=25}
*/
}
}
}
class Student0 implements Comparable<Student0>{
String name;
int age;
public Student0(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/*
返回值很重要,返回0,表示元素相同,返回大于0,在右子树上找
返回小于零,会继续在左子树上找。
*/
@Override
public int compareTo(Student0 o) {
if(this.age==o.age){
//排序规则
//当年龄相同,按照姓名比较,String类型可以直接调用compareTo()方法
return this.name.compareTo(o.name);
}else{
return this.age-o.age;
}
}
}
package collection.TreeSet;
import java.util.Comparator;
import java.util.TreeSet;
/*
TreeSet集合中元素可排序的第二种方式:使用比较器
*/
public class Test04 {
public static void main(String[] args) {
// TreeSettortoises=new TreeSet<>();
// 这样不行,没有通过构造方法传递一个比较器进去
//需要给构造方法传递一个比较器进去
//TreeSet tortoises=new TreeSet<>(new TotoiseComparator());
//使用匿名内部类
TreeSet<Tortoise>tortoises=new TreeSet<>(new Comparator<Tortoise>() {
@Override
public int compare(Tortoise o1, Tortoise o2) {
return o1.age-o2.age;
}
});
//添加元素
tortoises.add(new Tortoise(1000));
tortoises.add(new Tortoise(800));
tortoises.add(new Tortoise(100));
tortoises.add(new Tortoise(400));
//遍历
for (Tortoise s:tortoises){
System.out.println(s);
}
}
}
class Tortoise{
int age;
public Tortoise(int age){
this.age=age;
}
@Override
public String toString() {
return "Tortoise{" +
"age=" + age +
'}';
}
//单独在这里编写一个比较器
//比较器实现Comparator排序接口
}
//class TotoiseComparator implements Comparator{
// @Override
// public int compare(Tortoise o1, Tortoise o2) {
// return o1.age-o2.age;
// }
// 也可以使用匿名内部类
}
TreeSet集合中实现排序的两种方法:
Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。
Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。
两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了.
如果比较规则只有一个,使用Comparable排序接口;如果比较规则有多个,使用Comparator比较器。
TreeSet和TreeMap是自平衡二叉树,遵循左小右大原则存放。
遍历二叉树的三种方式:按照根的位置
前序遍历:根左右
中序遍历:左根右
后续遍历:左右根
TreeSet集合和TreeMap集合,Iterator迭代器采用中序遍历方式
package collection.Collections;
import collection.HashMap.Student;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
Collection 集合接口
Collections 集合工具类,方便集合的操作
*/
public class Test01 {
public static void main(String[] args) {
//ArrayList集合不是线程安全的
List<Student> list=new ArrayList<>();
//变成线程安全的
Collections.synchronizedList(list);
list.add(new Student("zhangsan1"));
list.add(new Student("zhangsan2"));
list.add(new Student("zhangsan4"));
list.add(new Student("zhangsan3"));
//排序
//注意,对list集合中的元素排序,需要保证list集合中的元素实现了Comparable接口
Collections.sort(list);
for(Student s:list){
System.out.println(s);
}
//对Set集合怎么排序呢?
Set<String> set=new HashSet<>();
set.add("Baby");
set.add("Honey");
set.add("girl");
//将set集合转换为List集合
List<String>list1=new ArrayList<>(set);//set作为参数传进去
Collections.sort(list1);
for (String s:list1){
System.out.println(s);
}
}
static class Student implements Comparable<Student>{
public String name;
public Student() {
}
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Student o) {
return this.name.compareTo(o.getName());
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
}