前提:所有集合继承Iterable的含义是所有集合都是可以迭代的
集合不能直接存放基本数据类型,也不能直接存储java对象,集合中存放的是Java对象的内存地址(引用)
集合在Java中本身就是一个对象
集合数组的区别:
1、java.util.Collection
Collection接口下的集合:可重复无下标
List(接口)集合:List集合存储元素特点是有序(存储顺序)可重复,有序是因为存储元素有下标,
Set(接口)(对应Map)集合:Set集合存储元素的特点是无序不可重复,无下标
SortedSet(接口)(对应SortedMap)集合:首先是无序不可重复,但集合中元素是可排序的
List和Set区别:
(1)、List,Set都是继承自Collection接口,Map则不是
(2)、List特点:元素有放入顺序,元素可重复 ,Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉,(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)
(3).Set和List对比:
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
(4)、ArrayList与LinkedList的区别和适用场景
Arraylist:
优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。
LinkedList:
优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景
缺点:因为LinkedList要移动指针,所以查询操作性能比较低。
适用场景分析:
当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。
集合选用:
List接口
Collection公共有
/*
1、Collection中存放什么元素
使用泛型之前,可以存放Object所有子类(不能存基本数据类型,也不能存对象,存的是地址)
使用泛型之后,只能存放某个具体的类型
2、常用方法
boolean add(Object e)//往集合添加元素
int size();//获取集合中元素个数
void clear();// 清空集合
boolean isEmpty();//判断集合是否为空,空返回true
boolean contians(Object obj)判断是否包含obj,包含返回true
Object toArray();//转化成数组
add()//往集合加元素
*/
import java.util.ArrayList;
import java.util.Collection;
public class CollectionTest01 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(1200);//自动装箱 Integer x = new Integer(1200);
c.add(3.14);
c.add(new Object());
c.add(true);//自动装箱
/*System.out.println("集合中元素的个数"+c.size());
c.clear();
System.out.println("集合中元素的个数"+c.size());
c.add("hello");//元素个数+1
System.out.println("集合中元素的个数"+c.size());
c.add("浩克");
System.out.println(c.contains("浩克"));
System.out.println(c.contains("浩克2"));
System.out.println(c.isEmpty());
*/
Object[] objs=c.toArray();
for(int i=0;i<objs.length;i++){
Object o=objs[i];
System.out.println(o.toString());
}
}
}
迭代器
在执行 .next()方法时,指向下一个元素
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
迭代
Iterator有三个方法hasNext(),next(),remove(),主要是前两个
迭代器:负责遍历/迭代集合中的元素。最初并没有指向第一个元素,而是指向第一个元素的前一个位置
*/
public class CollectionTest02 {
public static void main(String[] args) {
//以下的遍历方式/迭代方式,是所有Collection通用的一种方式
//Map集合中不能使用。在所有Collection及其子类
Collection c=new ArrayList();//后面的集合无所谓,主要看前面的Collection接口怎么遍历
c.add("ad");
c.add("qwe");
c.add(100);
c.add(3.14);
c.add(new Object());
//对集合c进行遍历
//第一步:获取集合对象的迭代器Iterator
Iterator it=c.iterator();
//通过上面的迭代器对象开始迭代/遍历集合
/*
以下两个方法是迭代器对象的方法
boolean hasNext();//如果仍有元素可以迭代,就返回true
Object next();//返回迭代的下一个元素。迭代器会往下走一位i,并将指向的元素返回
*/
boolean hasNext=it.hasNext();
while(it.hasNext()) {
Object obj = it.next();
System.out.println(obj);
}
}
}
注:一旦集合内元素发生变化,需要重新获取迭代器
以下代码会出现ConcurrentModificationException异常
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest66 {
public static void main(String[] args) {
Collection c66=new ArrayList();
Iterator it= c66.iterator();//在这个位置获取迭代器
c66.add(10);
c66.add(20);
c66.add(30);
//Iterator it= c66.iterator();
while(it.hasNext()){
Object obj=it.next();
System.out.println(obj);
}
}
}
但是调用迭代器的remove()方法时不同
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
//迭代器也有remove方法,同时删除迭代器快照的元素和集合元素,保持迭代器和集合统一
public class CollectionTest66 {
public static void main(String[] args) {
Collection c66=new ArrayList();
//Iterator it= c66.iterator();//在这个位置获取迭代器
c66.add(10);
c66.add(20);
c66.add(30);
Iterator it= c66.iterator();
while(it.hasNext()){
Object obj=it.next();
//c66.remove(obj);直接删除,会出现异常。因为直接删除,没有和迭代器的快照统一
it.remove();//删除迭代器指向的当前元素
System.out.println(obj);
}
System.out.println(c66.size());//0
}
}
contains方法 (Collection)
import java.util.ArrayList;
import java.util.Collection;
/*
研究contains方法
boolean contains(Object o)//判断集合是否包含某个对象o,包含返回true,不包含返回false
*/
public class CollectionTest04 {
public static void main(String[] args) {
Collection c4 =new ArrayList();
String s1=new String("asd");
c4.add(s1);
String s2=new String("zxc");
System.out.println("当前元素个数"+c4.size());
String s3=new String("asd");
//System.out.println(s3.equals(s1));//true
System.out.println(c4.contains(s3));//true,contains底层调用equals方法,栈里的s1和s3指向堆里两个String对象
// 但这两个对象指向字符串常量区同一块地方
//s3并未放入集合c4中,所以c4并不包含s3,但是由于调用String类equals方法
//所以误认为s3是s1,(比的是内容)
}
}
contains 续
import java.util.*;
public class CollectionTest05 {
public static void main(String[] args) {
Collection c5=new ArrayList();
//创建用户对象
User u1=new User("jack");
User u2=new User("jack");
c5.add(u1);
//System.out.println(c5.contains(u2));//false,因为底层调equals方法,u1.equals(u2)
//User类没有重写equals方法,所以调用Object的equals比较内存地址
System.out.println(c5.contains(u2));//重写User的equals方法之后,返回true
c5.add(u2);
}
}
class User{
private String name;
public User(){}
public User(String name){
this.name=name;
}
@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);
}
}
remove方法也会调用equals方法
/*
remove方法也会调用equals方法来找到要删除的对象,只删除一次
*/
import java.util.*;
public class CollectionTest06 {
public static void main(String[] args) {
Collection c6=new ArrayList();
c6.add(new String("hello"));
c6.add(new String("hello"));
c6.add(new String("hello"));
String s2="hello";
c6.remove(s2);
System.out.println(c6.size());//2,因为底层remove方法调用的equals方法
}
}
以上为Collection共有
ArrayList特有
import java.util.*;
/*
ArrayList集合
1、默认初始容量为10 (底层先创建长度0,当添加第一个元素的时候,初始化容量为10)
2、底层是Object[]数组
3、构造方式new ArrayList();或new ArrayList(20);
4、优点:检索效率高
缺点:随机增删效率低,无法存储大数据量(因为数组,难找空间)
注:add()方法在集合已经装满的时候调用,集合会扩容,增加量为原容量的50%(原容量右移1位)
尽量少扩容,影响效率。
*/
public class ArrayListTest01 {
public static void main(String[] args) {
//三种构造方法
//默认容量10
List list1=new ArrayList();
System.out.println(list1.size());//0,size()获取的是集合中当前元素个数,不是获取容量
//指定容量20
List list2=new ArrayList(20);
System.out.println(list2.size());//0
//其天集合转换构造ArrayList集合
Collection c=new HashSet();
c.add(100);
List list3=new ArrayList(c);
}
}
LinkedList
import java.util.LinkedList;
import java.util.*;
/*
1、有个first保存第一个node内存地址
有个last保存最后一个node内存地址
2、无初始化容量,first和last都是null
3、非线程安全
优点:随即增删效率高,适用于大数据和频繁随机增删的情况
缺点:不能数学计算被查找元素内存地址,每次都要从头遍历,效率低
注:无论是LinkedList还是ArrayList,不用关心具体是哪一个集合
因为要面向接口编程,调用接口中的方法
*/
public class LinkListTeswt01 {
public static void main(String[] args) {
List l1=new LinkedList<>();
l1.add(100);
l1.add(200);
for(int i=0;i< l1.size();i++){
System.out.println(l1.get(i));
}
}
}
Vector (线程安全,效率低较少使用)
底层数据结构是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素
有子类 Stack栈数据结构
泛型机制
*只在编译阶段起作用,运行阶段无用
使用好处:集合中存储的元素类型统一,集合中取出的元素是泛型指定的类型,不再需要向下转型。大多是业务中,集合元素是统一的。这种泛型被大家认可。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericTest {
public static void main(String[] args) {
//不使用泛型
List l1=new ArrayList();
//准备对象
Cat c=new Cat();
Bird b=new Bird();
//添加到集合中
l1.add(c);
l1.add(b);
//遍历
Iterator it1=l1.iterator();
while(it1.hasNext()){
//需要向下转型
Object obj=it1.next();
//Animal a=it.next();报错,因为.next取出来的是Object类对象
if(obj instanceof Animal){
Animal a=(Animal)obj;
a.move();
}
}
//使用泛型之后List<Animal>之后,表示List集合中只允许存放Anim类的数据
//用泛型来指定集合中存放的数据类型
List<Animal> l2=new ArrayList<Animal>();
//l2.add("asd");报错,因为“asd”不是Animal类对象
l2.add(c);
l2.add(b);
//表示迭代器迭代的是Animal类型
Iterator<Animal> it2=l2.iterator();//必须加<Animal>,这样it.next()出来的就是Animal类对象
while(it2.hasNext()){
//这里不再需要判断是不是Animal类型,**也不需要强制类型转换,可以直接调用
Animal a=it2.next();
a.move();
}
}
}
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("鸟在飞行");
}
}
泛型2–钻石表达式
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
JDK8之后引入了自动类型推断机制,又称为钻石表达式
*/
public class GenericTest2 {
public static void main(String[] args) {
//ArrayList<这里的类型会自动推断>
List<Animal> l3= new ArrayList<>();
l3.add(new Cat());
l3.add(new Bird());
//遍历
Iterator<Animal> it=l3.iterator();
while(it.hasNext()){
Animal a=it.next();
a.move();
}
}
}
泛型3–自定义泛型
public class GenericTest3<asdasdasdasd>{//< >内随便写,表示能使用泛型
public void doSome(asdasdasdasd o){
System.out.println(o);
}
public static void main(String[] args) {
GenericTest3<String> gt =new GenericTest3<>();
gt.doSome("aasd"); //doSome()传入的参数是上面规定的String类
//类型不匹配
//gt.doSome(100);
}
}
通用泛型
创建类的时候规定泛型
public class VO<T>{
private Integer total;
private List<T> dataList;
}
Set接口
Set不保存重复的元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set接口不保证维护元素的次序。
HashSet
底层数据结构采用哈希表实现,元素无序且唯一,需要重写hashCode和equals()方法。
/*
HashSet
无序不可重复
实际放入HashMap的key部分
参照HashMap
*/
import java.util.HashSet;
import java.util.Set;
public class HashSetTest {
public static void main(String[] args) {
Set<String> strs=new HashSet<>();
strs.add("hello3");
strs.add("hello1");
strs.add("hello2");
strs.add("hello4");
strs.add("hello1");
//遍历
for(String s:strs){
System.out.println(s);//变得无序,且去掉重复
}
}
}
hello1
hello4
hello2
hello3
TreeSet
底层数据结构采用二叉树来实现,元素唯一且已经排好序;唯一性同样需要重写hashCode和equals()方法。
/*
实现SortedSets接口的实现类
无序不可重复
元素会自动按照大小顺序排序
称为可排序集合
参照TreeMap
*/
public class HashSetTest {
public static void main(String[] args) {
Set<String> strs=new TreeSet<>();
strs.add("A");
strs.add("B");
strs.add("Z");
strs.add("Y");
strs.add("Z");
strs.add("K");
for(String s:strs){
System.out.println(s);
}
}
}
输出:
A
B
K
Y
Z
2、java.util.Map
Map相对于Collection。Map为键值对形式。key=value,key不能重复。
Map集合以key和value的键值对方式存储
key和value都是引用数据类型
key和value都是存储对象的内存地址
key起主导地位,value是key的附属品
常用方法:
V put(K key,V value)//添加键值对
V get(Object key)//通过key获取value
void clear() //清空
boolean containsKey(Object key)//判断是否包含某个key
boolean containsValue(Object value)//判断是否包含某个value
boolean isEmpty()
V remove(Object key)/通过key删除键值对
int size() //获取键值对数量
Set keySet() //获取所有key,所有的key是个Set集合
Collection values() //获取所有value
Set<Map.Entry<K,V>> entrySet() //将Map集合转换成Set集合
以(key=value)的形式存储在Set集合
Set集合中元素类型是Map.Entry<K,V> (静态内部类)
public class MapTest {
public static void main(String[] args) {
//创建HashMap对象
Map<Integer,String> map=new HashMap();
//添加键值对
map.put(1,"zhangsan");//1自动装箱
map.put(2,"lisi");
map.put(3,"wangwu");
//通过key获取value
String value=map.get(2);
System.out.println(value);
//获取键值对数量
System.out.println("数量"+map.size());
//通过可以删除
map.remove(2);
System.out.println("数量"+map.size());//2
//判断是否包含某个key,contains方法底层调用equals方法比对
//自定义的类需要重写equals方法
System.out.println(map.containsKey(4));//false
//判断是否包含某个value,contains方法底层调用equals方法比对
System.out.println(map.containsValue("zhangsan"));//true
//获取所有value
Collection<String> values=map.values();
for(String s:values){
System.out.println(s);
}
//
//清空
map.clear();
System.out.println("数量"+map.size());
}
}
Map集合的遍历
/*
1、获取所有key,通过key遍历value
2、通过Set<Map.Entry<K,v>> entrySet()方法
*/
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest02 {
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(1,"zhangsan");
map.put(2,"lisi");
map.put(3,"wangwu");
map.put(4,"zhaoliu");
/*第一种方式,获取所有key,通过key遍历value
Set<Integer> keys=map.keySet();
Iterator<Integer> it=keys.iterator();
while(it.hasNext()){
Integer key=it.next();
//通过key获取value
String value=map.get(key);
System.out.println(key+"="+value);
}
*/
/*第一种方式foreach
Set<Integer> keys=map.keySet();
for(Integer key:keys){
System.out.println(key+"="+map.get(key));
}
*/
/*第二种方法Set<Map.Entry<K,v>> entrySet()方法
* 把Map集合全转化成Set集合
* Set集合中元素类型是Map.Entry<Integer,String>
*/
//返回Set集合
Set<Map.Entry<Integer,String>> set=map.entrySet();
//迭代器
Iterator<Map.Entry<Integer,String>> it=set.iterator();
while(it.hasNext()){
Map.Entry<Integer,String> node=it.next();
Integer key=node.getKey();
String value=node.getValue();
System.out.println(key+"="+value);
}
//也可以用foreach,效率高
for(Map.Entry<Integer,String> node:set){
System.out.println(node.getKey()+"="+node.getValue());
}
}
}
HashMap
1、底层是哈希表
2、主要掌握
map.get(k)
1)先调用k的hashCode()方法得出hash值,通过hash算法转换成数组下标。快速定位
2)如果这个位置什么都没有,则返回null;如果这个位置有单向链表,则拿key和单向链表的每一个节点equals
如果所有节点都返回false,那么get方法返回null,只要有一个节点的k和参数k相等,则这个节点的value
就是要找的value
map.put(k,v)
1)先将k,v封装进Node对象中
2)调用hashCode()方法得出hash值,通过哈希函数将hash值转化成下标,下表位置如果没有元素
就把Node添加进去,如果有链表,此时会拿key和链表上各node的key比较,如果没有相同的
就把这个新节点添加到链尾。如果有相同的,则用新节点的value"覆盖"旧节点的value
**因为要equals比较,所以需要重写equals()方法,要计算hash值,所以需要重写hashCode()方法
3、HashMap集合key部分特点:
无序:因为put()方法添加元素,不一定挂到那个下标下面
不可重复:put()方法的覆盖保证不覆盖
4、放在HashMap集合key部分的元素相当于是HashSet集合
HashSet集合中的元素也需要重写equals()和hashCode()方法
5、HashMap默认初始化容量是16,默认加载因子是0.75
加载因子是HashMap底层数组容量到达75%的时候扩容
6、HashMap初始化容量必须是2倍(扩容是左移位操作),为了达到散列均匀,提高HashMap存取效率
7、允许key为null,重复的null值的key对应的value也会覆盖
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
public class HashMapTest {
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(111,"zhangsan");
map.put(222,"lisi");
map.put(333,"wangwu");
map.put(444,"zgaoliu");
map.put(222,"king");
System.out.println(map.size());//4,key重复的时候,后一次覆盖前一次
//遍历
Set<Map.Entry<Integer,String>> set =map.entrySet();
for(Map.Entry<Integer,String> entry:set){
//无序不重复
System.out.println(entry.getKey()+"="+entry.getValue());
}
}
}
需要重写equals()和hashCode()方法
/*
重写equals()和hashCode()方法
如果equals()方法重写了,那么hashCode()方法也要重写
equals()方法如果返回值是true,那么hashCode()返回值也要相同
equals()和hashCode()直接用IDEA生成,“同时生成”
*/
import java.util.HashSet;
import java.util.Set;
public class HashMapTest02 {
public static void main(String[] args) {
Student s1=new Student("zhangsan");
Student s2=new Student("zhangsan");
//重写equals()之前
//s1.equals(s2);//false
//重写quals()之后
s1.equals(s2);//true
//hashCode重写之前,值不相同
System.out.println("s1的hashcode="+s1.hashCode());
System.out.println("s2的hashcode="+s2.hashCode());
//s1.equals(s2)为true,表示是s1和s2相同,那么往HashSet中放只能放进去一个
Set<Student> students=new HashSet<>();
students.add(s1);
students.add(s2);
System.out.println(students.size());//2,与只能放进去一个相悖,所以需要重写hashCode方法
//1,重写之后s1.hashCode()与s2.hashCode()相同
}
}
import java.util.Objects;
public class Student {
private String name;
public Student() {
}
public Student(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
//equals()
//hashCode()
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return Objects.equals(getName(), student.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName());
}
}
Hashtable
和HashMap区别:
1、Hashtable的key和value都不能为null,HashMap的都可以
2、Hashtable的方法都带有synchronized,线程安全,但效率低
3、Hashtable和HashMap底层都是哈希表数据结构,Hashtable初始化容量是11,默认加载因子是0.75
扩容是原容量*2+1
子类;
Properties类
import java.util.Properties;
/*
掌握常用方法即可
Properties是Map集合,继承Hashtable。Properties的key和value都是String类型
Properties被称为属性对象
Properties是线程安全的
常用方法:
存:setProperty(String key,String value)
取:getProperty(String key)
*/
public class PropertiesTest {
public static void main(String[] args) {
Properties p = new Properties();
//存
p.setProperty("username", "root");
p.setProperty("password", "123");
//取
String s1 = p.getProperty("username");
String s2 = p.getProperty("password");
System.out.println(s1);
System.out.println(s2);
}
}
TreeSet
TreeSet集合(继承Collection接口、Set接口、SortedSet接口)
1、底层实际是TreeMap,TreeMap集合底层是二叉树
2、放到TreeSet集合的元素实际是放到TreeMap集合的key部分
3、TreeSet集合中的元素 无序不可重复,但是会按照元素大小顺序自动排序,称为可排序集合
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<String> ts=new TreeSet<>();
ts.add("zhangsan");
ts.add("lisi");
ts.add("wangwu");
ts.add("zhangliu");
//遍历,输出升序
for(String s:ts){
System.out.println(s);
}
TreeSet<Integer> ts2=new TreeSet<>();
ts2.add(100);
ts2.add(500);
ts2.add(300);
//遍历,输出升序
for(Integer i:ts2){
System.out.println(i);
}
}
}
TreeSet对自定义类进行排序1
/*
以下程序对自定义类型无法排序
因为大小没有说明,会出现Exception in thread "main" java.lang.ClassCastException: class Person cannot be cast to class java.lang.Comparable (Person is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
at java.base/java.util.TreeMap.compare(TreeMap.java:1563)
出现这个异常是因为没有实现java.lang.Comparable接口
*/
import java.util.TreeSet;
public class TreeSetTest02 {
public static void main(String[] args) {
Person p1=new Person(20);
Person p2=new Person(22);
Person p3=new Person(21);
TreeSet<Person> persons=new TreeSet<>();
persons.add(p1);
persons.add(p2);
persons.add(p3);
//遍历
for(Person p:persons){
System.out.println(p);
}
}
}
class Person{
int age;
public Person(int age) {
this.age = age;
}
public Person() {
}
//重写toString
@Override
public String toString() {
return "Person" +
"age=" + age;
}
}
TreeSet对自定义类进行排序2
/*
以下程序可以对自定义类型排序
因为实现了Comparable接口,重写了compareTo()方法
*/
import java.util.TreeSet;
public class TreeSetTest02 {
public static void main(String[] args) {
Customer c1=new Customer(20);
Customer c2=new Customer(22);
Customer c3=new Customer(21);
TreeSet<Customer> customers=new TreeSet<>();
customers.add(c1);
customers.add(c2);
customers.add(c3);
//遍历
for(Customer p:customers){
System.out.println(p);
}
}
}
//放在TreeSet中的元素需要实现java.lang.Comparable接口
//并且实现compareTo()方法,equals()方法可以不写
class Customer implements Comparable<Customer>{
int age;
public Customer(int age) {
this.age = age;
}
public Customer() {
}
//重写toString
@Override
public String toString() {
return "Customer" +
"age=" + age;
}
//需要编写比较的逻辑和规则,k.compareTo(t.key)
@Override
/*compareTo的返回值
返回=0,表示相同会覆盖
返回>0,会在右子树找
返回<0,会在左子树找
*/
public int compareTo(Customer o) {//c1.compareTo(c2)
//this就是c1,c就是c2
int age1=this.age;
int age2=o.age;
/*
if(age1==age2)return 0;
if(age1<age2)return 1;
else return -1;
*/
//相当于写成
return this.age-o.age;
//降序return this.age-o.age;
}
}
TreeSet集合中元素可排序的’第二种方法":比较器
import java.util.Comparator;
import java.util.TreeSet;
/*
使用比较器
*/
public class TreeSetTest04 {
public static void main(String[] args) {
//创建TreeSet集合的时候需要使用比较器
TreeSet<Wugui> wuguis=new TreeSet<>(new WuguiComparator());
wuguis.add(new Wugui(1000));
wuguis.add(new Wugui(700));
wuguis.add(new Wugui(800));
for(Wugui w:wuguis){
System.out.println(w);
}
}
}
//class Wugui implements Comparable{ 原来方法
class Wugui {
int age;
public Wugui(int age) {
this.age = age;
}
@Override
public String toString() {
return "Wugui{" +
"age=" + age +
'}';
}
}
//单独编写比较器,比较器实现java.util.Comparator接口。
// 对比Comparable()方法是java.lang包下的
class WuguiComparator implements Comparator<Wugui>{
@Override
public int compare(Wugui o1, Wugui o2) {
//指定比较规则
return o1.age-o2.age;
}
}
总结:Comparable和Comparator选择:
当比较规则不会发生改变的时候,或则比较规则只有一个的时候,选择Comparable接口
当比较规则有多个的时候,选择Comparator比较器,符合OCP原则
Collection工具类:Collections
java.util.Collection 集合接口
java.util.Collections 集合工具类
import java.util.;
/
Collections.sort( );排序,参数需要是List集合类型
*/
public class CoolectionsTest {
public static void main(String[] args) {
//ArratList原本不是线程安全的
List list=new ArrayList<>();
//变成线程安全的
Collections.synchronizedList(list);
list.add(“bac”);
list.add(“acb”);
list.add(“abc”);
//排序,自定义的类,需要先实现Comparable接口
//Collections.sort()的参数必须是List集合类型
Collections.sort(list);
for(String s:list){
System.out.println(s);
}
//如果对Set集合排序
Set set=new HashSet<>();
set.add(“king1”);
set.add(“king4”);
set.add(“king2”);
set.add(“king3”);
//将Set转化成ArrayList集合
List list1=new ArrayList<>(set);
//可以实现排序
Collections.sort(list1);
for(String s:list1){
System.out.println(s);
}
}
}
总结
ArrayList:底层是数组
LinkList:底层是双向链表
Vesctor:底层是数组,线程安全,效率较低
HashSet:底层是HashMap,实际放到HashMap集合的key部分
TreeSet:底层是TreeMap,实际是放到TreeMap集合的key部分
HashMap:底层是哈希表
Hashtable:底层是哈希表,线程安全,效率较低
Properties:继承的Hashtable,key和value只能存储String
TreeMap:底层是二叉树数据结构,TreeMap集合的key可以自动按照大小排序
掌握:
每个集合创建
向集合添加元素
从集合取出元素
遍历集合
主要的集合类:
ArrayList
LinkedList
HashSet:HashMap的key,存储在HashMap集合的key元素需要同时重写hashCode()和equals()方法
TreeSet
Hashmap
Properties
TreeMap
集合之间的转化
在new的时候,把原先的集合当作构造函数的参数传入
Map不能直接转Set,需要调Map.keySet()