Javase集合的一些小结

6.集合

6.1集合概念

Java中对于各种数据结构的实现,就是我们用到的集合。

集合大概相当于c语言中的结构体,可以储存同一个类型的东西,比如你定义了一个类people,他有年龄和身高,性别的属性,经过实例化后,想要输出这谢人,数组就不够用了,集合刚好可以表示这些东西.

数组还有个缺点是必须连续的内存,而且数组被定义后长度不会再变化,我们通常都需要可以变长的容器来表示数据.

6.2集合体系

在这里插入图片描述

集合可以分为单列结合和双列集合,上面是单列集合的体系,双列集合又叫map,它可以分为 Treemap,hashmap和hashtable.

单列集合又可以分为值可以重复的List和值不可以重复的Set.

List下面又有 数组列表(Arraylist)和数组链表(Linkedlist) ,vector.

Set下面有Hashset和Treeset

6.3collection接口和list类

collection接口包含List和Set2种,其中List是有序的可重复的集合,Set是无序的不可重复的集合.

Collection接口中有一些2中共有的方法,比如

boolean类型的都是成功返回true,失败false的

boolean add(Object element);//增加元素值,成功返回ture,失败false;
boolean addAll(Collection c);//把一个集合添加到另一个集合中去
boolean remove(Object element);//删除某一个指定元素值
boolean removeAll(Collection c);//删除指定集合 不包含时,删除相交的元素
void clear();//清空集合
int size();//返回集合的长度
boolean isEmpty();//判断集合是否为空
boolean contains(Object element);//判断一个元素是否在集合中
boolean containsAll(Collection c);//判断一个集合是不是在这个集合中
boolean retainAll(Collection c);//求交集,集合数据发生变化返回true,不变返回false

List继承了Collection接口,有三个实现的类
ArrayList数组列表,数据采用数组方式存储。
LinkedList链表
Vector数组列表,添加同步锁,线程安全的.

6.3.1ArrayList

ArrayList实现了长度可变的数组,在内存中分配连续的空间。遍历元素和随机访问元素的效率比较高,但是他增删元素的效率很低,

在这里插入图片描述
删除是同理的操作,他需要移动的元素很多,增删多的时候就不建议用Arraylsit了.

Arraylist 常用的一些方法:

add(int index, E element)//指定位置曾加指定值
get(int index)//获取某个下表的元素的值
indexOf(Object o)//获取某个值的下表索引
lastIndexOf(Object o)//获取最后一个出现的某个值的下标索引
remove(int index)// 删除并返回指定位置元素
removeRange(int fromIndex, int toIndex) //删除指定区间的元素(子类继承使用)
set(int index, E elemen)//用指定的元素替换此列表中指定位置的元素

实例:

public class a {
    public static void main(String[] args) {
        Collection<String> a=new <String>ArrayList();
        Collection <String> b=new <String>ArrayList();
        b.add("c");
        b.add("d");
        b.add("b");
        a.add("a");//向集合添加元素
        a.add("b");//可以有重复元素
//        System.out.println( a.removeAll(b));//移除所有a里面包含b的东西,数组变化了为true,没有变化为false;
        System.out.println(a);
//        System.out.println(a.containsAll(b));
        //System.out.println(a.addAll(b));//吧b添加到a里
        //System.out.println(a.contains("b"));//判断集合是否包含这个元素
        //a.clear();//清空集合
        //System.out.println(a.remove("b"));//删除这个元素,删除成功为true,失败为false;
        //System.out.println(a.isEmpty());//集合是否为空
        //System.out.println(a.size());//集合长度
//        System.out.println(a);//输出集合
    }
}

arraylist中add()的工作原理

他会检测数组够用吗,如果不够用会增大1.5倍的容量然后继续操作

ArrayList扩容机制,在第一次使用Add方法的时候,系统会进行一次扩容,容量为10,当我们添加元素超过10的时候,他会再进行扩容,扩容量为上一次容量的1.5倍,第二次为15,第三次为22等.

6.3.2LinkedList

LinkedList采用链表存储方式。插入、删除元素时效率比较高.

他的增删只需要找下标即可,但他的查找很慢,需要从第一个或者最后一个开始一个一个找.
在这里插入图片描述

add(int index,Object element)//向指定索引位置添加指定的值
addFirist(Object element)//往头节点增加值
addLast(Object element)//往尾节点增加值
get(int index)//获取某个索引位置的数据的值
removeFirst()//删除第一个节点
removeLast()//删除最后一个节点
remove(int index)//删除某个索引及其值
getFirst()//获取第一个节点的值
getLast()//获取最后一个节点的值

实现方法和上面的ArrayList差不多就不写了

6.3.3vector

vector 是添加了同步锁的一个顺序数组容器.

add(E e) //将指定的元素追加到此Vector的末尾。
add(int index, E element) //在此Vector中的指定位置插入指定的元素。 
capacity() //返回此向量的当前容量。  
clear() //从此Vector中删除所有元素。
contains(Object o) //如果此向量包含指定的元素,则返回 true 。 
elementAt(int index) //返回指定索引处的组件。 
equals(Object o) //将指定的对象与此向量进行比较以获得相等性。 
equals(Object o) //将指定的对象与此向量进行比较以获得相等性。 
indexOf(Object o) //返回此向量中指定元素的第一次出现的索引,如果此向量不包含元素,则返回-1。 
indexOf(Object o, int index) //返回此向量中指定元素的第一次出现的索引,从 index向前 index ,如果未找到该元素,则返回-1。 
set(int index, E element) //用指定的元素替换此Vector中指定位置的元素。 
toArray() //以正确的顺序返回一个包含此Vector中所有元素的数组。 

实现方法和上面的ArrayList差不多就不写了

6.3.4迭代器

迭代器iterator,专业遍历集合

迭代器有3个方法:hasnext()有没有下一个

next()拿到下一个的值,remove()删除

使用方法

  public static void main(String[] args) {
        ArrayList <String> a=new ArrayList();
        a.add("a");
        a.add("b");
        a.add("c");
        a.add("d");
        a.add("e");
       Iterator it= a.iterator();//返回一个迭代器对象
       while(it.hasNext()){//当他有下一个元素为真的时候
           String b=(String)it.next();//把下一个元素赋给b
           System.out.println(b);//输出b
       }

    }

6.3.5对单列集合遍历的三种方法

for()循环遍历

 for(int i=0;i<a.size();i++){//循环开始
           String b=a.get(i);//获取i个位置的值赋给b
           System.out.println(b);//输出b
       }

增强for遍历

for(String b:a){//结构就是这样
          System.out.println(b);
      }

迭代器遍历

上面已有就不写了

还有一个逆序输出一个集合的

ListIterator <String>it=a.listIterator(a.size());       
while(it.hasPrevious()){            
      String b=it.previous();//把前驱赋给一个字符串b//            
       if(b.equals("a")){//               
         a.remove("a");//               
            break;//           
                 }          
System.out.println(b);        }

6.4Set类

Set接口继承了Collection接口。
Set中所存储的元素是不重复的,但是是无序的, Set中的元素是没有索引的
Set接口有两个实现类
HashSet类中的元素不能重复,即彼此调用equals方法比较,都返回false。
底层数据结构是哈希表+链表
哈希表依赖于哈希值存储.
可以给Set集合中的元素进行指定方式的排序。存储的对象必须实现Comparable接口。
TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树.

6.4.1HashSet类

Hashset元素不能重复,在添加元素的时候,怎么判断他是否重复呢,这里会用到2个方法,hashcode()和equals();

在一般的比较方法的时候,都是通过equals()方法进行比较,但是他的效率有点低,比如说String a=“abcdwdadad”,String b=“agagagagg”;如果用equals方法去比较的话,他是一位一位的比较,他的效率就会很低。但是他是安全的方法,而我们可以把他转换位hash值,比较它们的哈希值,但是这个方法又不安全,比如说

Stirng a=”通话“,String b=“重地”,在经过equals方法比较后,他们会返回true,即表明,这2个字符串的哈希值是一样的,而他们其实是不一样的,所以hashcode()方法不太安全。但是他效率高,我们为了更好的比较hashset中的元素是否重复,所以我们把2个方法结合起来。先用hashcode方法转化他们的哈希值,比较他们的哈希值,如果哈希值不相同,则这两个元素也就不重复,如果哈希值相同的时候,我们在调用equals方法去比较他们是不是真的相同,这就是hashset判断是否元素重复的方法。

hashset的底层实现是hashmap。

hashset也有一些常用的方法,比如add()

add(E e) //将指定的元素添加到此集合(如果尚未存在)。
clear() //从此集合中删除所有元素。
contains(Object o)// 如果此集合包含指定的元素,则返回 true 。 
contains(Object o) //如果此集合包含指定的元素,则返回 true 。 
remove(Object o) //如果存在,则从该集合中删除指定的元素。 
size() //返回此集合中的元素数(其基数)。 

实现一个hashset的实例

public class person {
    private int age;
    private String name;
    @Override
    public String toString() {
        return "person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        person person = (person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(age, name);
    }

    public person(int age, String name) {
        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;
    }
}

可以写一个person类,把person类装入一个hashset中,必须要重写hashcode和equals方法和一些构造方法等

 public static void main(String[] args) {
        HashSet<person>a=new HashSet<>();
        person b=new person(1,"sb");
        person b1=new person(2,"sd");
        person b2=new person(3,"sa");
        person b3=new person(4,"sc");
        person b4=new person(1,"sb");
        a.add(b);
        a.add(b1);
        a.add(b2);
        a.add(b3);
        a.add(b4);
        System.out.println(a);
 }
他不能有重复的值所有不会有5个值
[person{age=2, name='sd'}, person{age=3, name='sa'}, person{age=4, name='sc'}, person{age=1, name='sb'}]

6.4.2Treeset

可以给Set集合中的元素进行指定方式的排序。存储的对象必须实现Comparable接口。
TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树)

Treeset实现的排序需要重写comparable方法例如下面代码,如果需要得到某种有顺序的结果可以选用treeset

public class Car implements Comparable<Car>{
    private  int id;//car类可以充当泛型,他有属性id和name
    private String name;
    public int getId() {//生成一下他的一些方法和构造函数和comparable方法
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Car(int id, String name) {
        this.id = id;
        this.name = name;
    }
    public String toString() {//toString是为了方便输出表达
        return "treeset{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
    @Override
    public int compareTo(Car o) {
        return this.name.compareTo(o.name);//给name排序
//        return this.id-o.id;给id排序
    }
}

下面的treeset方法调用car类

public class treesettest {
    public static void main(String[] args) {
        TreeSet<Car> a=new TreeSet<>();
        Car car1=new Car(1,"bm1");
        Car car2=new Car(2,"bm2");
        Car car3=new Car(3,"bm3");
        Car car4=new Car(4,"bm4");
        Car car5=new Car(1,"bm5");
        a.add(car1);
        a.add(car2);
        a.add(car3);
        a.add(car4);
        a.add(car5);
        System.out.println(a);
    }
}
[treeset{id=1, name='bm1'}, treeset{id=2, name='bm2'}, treeset{id=3, name='bm3'}, treeset{id=4, name='bm4'}, treeset{id=1, name='bm5'}]这是那name排序的结果
[treeset{id=1, name='bm1'}, treeset{id=2, name='bm2'}, treeset{id=3, name='bm3'}, treeset{id=4, name='bm4'}]这是那id排序的结果

6.4.3set接口的一些遍历方法

增强for

迭代器

和list中的增强for和迭代器使用方法基本相同的

6.5Map接口

map类是双列结构,是由键-值对组成的一系列结构。

将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值

Map接口常用的方法

V put(K key,V value)//增加一对键-值对 key是键,value是值
V remove(Object key)//删除键,也就删除了值了
void clear()//清空所有
boolean containsKey(Object key)//判断是否包含这个键
boolean containsValue(Object value)//判断是否包含这个值
boolean isEmpty()//判断是否位空
int size()//返回map的长度
V get(Object key)//得到某个键的值
Collection<V> values()//把所有的值返回一个collection集合
Set<K> keySet()//把所有的键返回一个set集合
Set<Map.Entry<K,V>> entrySet(//把键值对放进一个entry类型的set集合

3种方法实现了Map接口

(1)HashMap
HashMap中元素的key值不能重复, 排列顺序是不固定的,可以存储一个为null的键。
(2)TreeMap
TreeMap中所有的元素都保持着某种固定的顺序,如果需要得到一个有序的Map就应该使用TreeMap,key值所在类必须实现Comparable接口。
(3) HashTable
实现了同步。不能存储为null的键

6.5.1Hashmap

Hashmap是集hashset ,链表,红黑树于一身的数据结构.

为什么他的查找速度很快呢,因为

哈希冲突:如果两个不同的元素,通过哈希函数得出的实际存储地址相同怎么办?也就是说,当我们对某个元素进行哈希运算,得到一个存储地址,然后要进行插入的时候,发现已经被其他元素占用了,其实这就是所谓的哈希冲突,也叫哈希碰撞。而HashMap即是采用了链地址法,也就是数组+链表的方式。

下面是hashmap底层方法的一些理解

在这里插入图片描述

这里的(1)表示hashtable结构,他也是个数组结构,它默认16个,当你存入一个98的时候,对98mod16得到的结果为2,所以把他存入2下面的链表里,加入还要存入一个34,对他mod一下,余数为2,再把它存入2下面的链表种,当好多余数为2的数据是,下面的链表就会越来越差,这也导致了很多数据操作很麻烦,比如遍历的话。所以当链表的数据超过7个的时候 我们会自动把他转化成一个红黑树,他是自平衡的,所以遍历起来就会方便一点.

这就是比较简略的原理了.

他还有最大容量 2^30,负载因子0.75,当哈希表容量到达整数数组的0.75时,进行扩容,扩容为原来的2倍.

下面是一个图

img

hashmap还有一些其他的常用方法:

entrySet() //返回此地图中包含的映射的Set视图。 
get(Object key)//返回到指定键所映射的值,或 null如果此映射包含该键的映射。 
keySet() //返回此地图中包含的键的Set视图。
put(K key, V value)// 将指定的值与此映射中的指定键相关联。 
remove(Object key) //从该地图中删除指定键的映射(如果存在)。 
remove(Object key) //从该地图中删除指定键的映射(如果存在)。 
remove(Object key) //从该地图中删除指定键的映射(如果存在)。 

6.5.2Treemap

Treemap是一个能比较元素大小的map集合,会对传入的key值进行大小排序,其中的排序可以是元素的自然排序还可以是自定义排序,比如你定义了一个Treemap他的键为id,值为一串字母,它也可以id排序,也可以对字母排序的.如果需要得到一个有序的map就该使用treemap,其中,key值必须实现comparable接口。

Treemap是实现了红黑树结构的,是一颗二叉树。

下面是对他排序的一些实现

public class sort implements Comparable<sort>{
    private int age;
    public sort(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "sort{" +
                "age=" + age +
                '}';
    }
    @Override
    public int compareTo(sort o) {
        return this.age-o.age;
    }
}
public class Treemap {
    public static void main(String[] args) {
        TreeMap<sort,String> a=new TreeMap();//同样泛型里可以传泛型类
        a.put(new sort(1),"a");
        a.put(new sort(9),"u");
        a.put(new sort(4),"n");
        a.put(new sort(7),"c");
        a.put(new sort(6),"v");
        System.out.println(a.toString());
    }
}
{sort{age=1}=a, sort{age=4}=n, sort{age=6}=v, sort{age=7}=c, sort{age=9}=u}

基本和上面的Treeset实现方法类似不过这里的是双列集合而已.sort里面也可以定义多个属性,给多个属性都可以排序.

6.5.3Hashtable

Hashtable也叫哈希表,是Hashmap的一部分,他的数据结构是一个数组.

6.6.Collections类

Collections类是可以同时对list和set结构同时操作的一个类,就和数组中的Arrays类一样。

它有一些常用的方法

addAll(Collection<? super T> c, T... elements);//把后面的元素都可以加到前面的类里
binarySearch(List<? extends Comparable<? super T>> l ist, T key)//求第几个索引的第几个数
sort(List<T> l ist)//排序
sort(List<T> l ist, Comparator<? super T> c)//自定义排序
swap(List<?> l ist, int i, int j)//交换第i个第j个的值
copy(List<? super T> dest, List<? extends T> src) //把后面的集合里的数据复制到前面集合里去,会覆盖前面集合里面的数据; 注意 dest size需大于等于src.size
emptyList()//返回为空的集合,不能添加数据,只是为了避免空指针异常
fill(List<? super T> list, T obj)//那后面的数把前面集合里面的所有数据替代掉
max(Col lection<? extends T> col l)//集合中的最大值
min(Col lection<? extends T> col l)//集合中的最小值
replaceAll(List<T> list, T oldVal, T newVal)//旧值替换新值
reverse(List<?> list)//逆序排序

Collections类的一些实现.

 public static void main(String[] args) {
        List<Integer> a=new ArrayList<>();//必须是list类和set类的单列集合才能操作。
        Collections.addAll(a,1,3,5,2,4);
        List<Integer> b=new ArrayList<>();
        Collections.addAll(a,5,6,7,8,9);
//       Collections.sort(a);
//        System.out.println(a);
//        Integer b=Collections.binarySearch(a,2);
//        Collections.swap(a,2,3);
//        Collections.copy(a,b);
//        List c=Collections.emptyList();
//        Collections.fill(a,5);
//        Collections.max(a);
//        System.out.println(Collections.max(a));
//        System.out.println(Collections.min(a));
//         Collections.replaceAll(a,3,2);
        Collections.reverse(a);
        System.out.println(a);
    }

addAll(a,5,6,7,8,9);
// Collections.sort(a);
// System.out.println(a);
// Integer b=Collections.binarySearch(a,2);
// Collections.swap(a,2,3);
// Collections.copy(a,b);
// List c=Collections.emptyList();
// Collections.fill(a,5);
// Collections.max(a);
// System.out.println(Collections.max(a));
// System.out.println(Collections.min(a));
// Collections.replaceAll(a,3,2);
Collections.reverse(a);
System.out.println(a);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值