集合2——List体系和Set体系


对象数组

  • 对象数组指的就是存储引用类型的数组

对象数组的使用

/*
 *对象数组(引用数组):该数组中存储的是引用类型因此我们叫它对象数组或者引用数组 
 *  引用数组中存储的是对象的地址值而不是对象 
 */
public class Demo {
	public static void main(String[] args) {
       //1.定义一个Student类型的数组
		//int[]  arr = new int[3]
		Student[] stus=new Student[2];
		
	   //2.给数组中的元素赋值
		//arr[0]=3;
		stus[0]=new Student("张三",13); 
		stus[1]=new Student("李四",24);
		
	   //3.遍历这个引用数组
	    /*
		 * for(int i=0;i<arr.length;i++){
		 *    System.out.println(arr[i])
		 * }
		 */
		for(int i=0;i<stus.length;i++){
			System.out.println(stus[i]);
		}
	}
}

内存图

在这里插入图片描述

List体系

List接口介绍

api中介绍:有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。与 set 不同,列表通常允许重复的元素

  • List接口:

    • 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。
    • 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
    • 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
  • List接口的常用子类有:

    • ArrayList集合

    • LinkedList集合

ArrayList类

ArrayList实现原理(思想)
  • ArrayList集合特点:

    底层使用是一个引用数组(Object[])

  • 扩容思想:

​ 新建一个集合的时候,底层会开辟长度为10的数组,调用add()方法会不断的往数组中添加元素当添加了10个元素,再添加第11个元素的时候,数组满了,无法存入,此时会新建一个长度为原来长度1.5倍的数组(10+10/2),接着会把原有元素拷贝到新数组中,再把第11个元素追加到末尾
在这里插入图片描述

ArrayList中特有方法

在这里插入图片描述

  • 增加元素方法

    add(Object e):向集合末尾处,添加指定的元素

    add(int index, Object e):向集合指定索引处,添加指定的元素,原有元素依次后移

  • 删除元素删除

remove(Object e):将指定元素对象,从集合中删除,返回值为被删除的元素

remove(int index):将指定索引处的元素,从集合中删除,返回值为被删除的元素

  • 替换元素方法

    set(int index, Object e):将指定索引处的元素,替换成指定的元素,返回值为替换前的元素

  • 查询元素方法

    get(int index):获取指定索引处的元素,并返回该元素

方法演示:

import java.util.ArrayList;
public class Demo {
    public static void main(String[] args) {
        //list中可以存储任意数据类型,必须是对象
        ArrayList list = new ArrayList();
        list.add(12);//12是Integer一个对象,自动装箱
        list.add("abc");
        list.add("def");
        list.add("abc");
        System.out.println(list);//[12, abc, def, abc]
        list.add(3,"zzz");
        System.out.println(list);//[12, abc, def, zzz, abc]
        System.out.println( list.get(1));//abc
        list.set(3,"www");
        System.out.println(list);//[12, abc, def, www, abc]
        list.remove("abc");
        System.out.println(list);//[12, abc, def, www, abc]
    }
}
ArrayList存储自定义对象
public class Person {
    private int id;
    private String name;
    //构造方法
    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }
    //getter()和setter()
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    //重写toString()
    @Override
    public String toString() {
        return "Person{" + "id=" + id + ", name='" + name + '\'' + '}';
    }
}


import java.util.ArrayList;
import java.util.Iterator;
public class PersonDemo {
    public static void main(String[] args) {
        ArrayList<Person> list = new ArrayList<Person>();
        list.add(new Person(01,"张三"));
        list.add(new Person(02,"李四"));
        Iterator it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //Person{id=1, name='张三'}
        //Person{id=2, name='李四'}
    }
}
ArrayList特点

​ 查询元素较快:因为底层是数组,数组有索引

​ 增删元素较慢:

​ 添加慢,因为每次添加都需要移动大量的元素,导致浪费内存资源,效率低

  • 添加慢的原因:
    在这里插入图片描述
  • 删除慢的原因:
    在这里插入图片描述

LinkedList类

LinkedList实现思想

​ 底层使用一个链表,第一个元素记录下一个元素的地址值最终形成一条链子
在这里插入图片描述

LinkedList特有方法
/*
 * LinkedList:
 *    原理:
 *      LinkedList底层使用是链表数据结构
 * LinkedList<E>成员方法:
 *  void addFirst(E e):不断往链表的头部添加,遍历集合的时候从链头开始遍历
    void addLast(E e):不断地往链表尾部追加,遍历集合的时候从链头开始遍历
 *  
 *  E getFirst()//取链头的第一个元素,但是不会删掉链头元素
    E getLast() //取炼尾(最后一个)的元素,但是不会删掉链尾的元素
    
    E removeFirst()//取链头的第一个元素,但是会删掉链头的元素
    E removeLast() //取链尾的的元素,但是会删掉链尾的元素
  
 */
LinkedList特点

查询元素相对ArrayList较慢:因为链表都是从头开始查

增删元素相对ArrayList较快:因为链表仅仅需要改变元素中记录的地址值,而不需要移动大量元素,节省内存开销提高效率

  • LinkedList增删元素原理:
    在这里插入图片描述

栈和队列数据结构

栈:特点:元素后进先出(先进后出) :手枪弹夹

队列:特点:元素先进先出(后进后出):银行叫号

Set体系

学习Collection接口时,记得Collection中可以存放重复元素,也可以不存放重复元素,那么我们知道List中是可以存放重复元素的。那么不重复元素给哪里存放呢?那就是Set接口,它里面的集合,所存储的元素就是不重复的。

Set接口介绍

查阅HashSet集合的API介绍:此类实现Set接口,由哈希表支持(实际上是一个 HashMap集合)。HashSet集合不能保证的迭代顺序与元素存储顺序相同。

即特点为:无序,不重复

HashSet类

HashSet基本使用

HashSet依然具有集合通用的特点:利用add添加元素,使用迭代器遍历,使用增强for遍历

方法列表:

	add()		remove()		contains()		clear()		size()
  • Set无序,所有没有下标的获取方式。因此没有get(i)

  • Set中不能查看一个元素

/*
 * Set接口:没有索引,存储的元素唯一,存取顺序不一定一致
 *   HashSet:没有索引,保证元素唯一,存的顺序和取的顺序不一定一致
 *   成员方法:
 *     Iterator<E> iterator() 
 */
import java.util.HashSet;
import java.util.Iterator;
public class Demo {
    public static void main(String[] args) {
        HashSet<String> hs=new HashSet<String>();
        hs.add("aa");
        hs.add("bb");
        hs.add("cc");
        //1.获取迭代器对象
        Iterator<String> it=hs.iterator();
        //2.循环遍历
        //迭代器
        while(it.hasNext()){
            String str=it.next();
            System.out.println(str);
        }
        /*增强for
        for(String str : hs){
            System.out.println(str);
        }
        */
    }
}
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
//Set集合过滤字符串
public class Demo {
    //Scanner输入字符串去重
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入字符串:");
        String str = input.nextLine();
        //1.String-->Char[]
        char[] cs = str.toCharArray();
        //2.Set集合
        Set<Character> set = new HashSet<>();
        //3.将每个字符放在Set中
        for (int i = 0 ; i < cs.length ; i++){
            set.add(cs[i]);//add()自带过滤重复
        }
        System.out.println(set);
    }
}

add()判断对象是否重复,依赖contains()

contains()底层依赖equals(),重写equals()就能在Set集合中解决对象重复的问题

哈希算法
  • 哈希算法相对于普通查找更快
    在这里插入图片描述
  • 哈希算法保证唯一原理
    在这里插入图片描述
HashSet存入字符串保证唯一原理

存入HashSet的字符串依赖两个方法,一个是hashCode()方法,一个是equals()方法,注意这两个方法出自Object类,但是String都把这两个方法重写了,String的类的hashCode()方法不再像Object类的hashCode()方法返回内存地址值,而是根据一定的算法计算字符串中字符的ASCII码值,String类的equals()方法就是比较两个字符串的内容

import java.util.HashSet;
/*
 * HashSet唯一原理
 *   先调用hashCode()方法比较元素的哈希值
 *   如果添加的元素哈希值与集合中的元素的哈希值不同,直接存入
 *   如果添加的元素哈希值与集合中的元素的哈希值相同
 *      调用equals()方法比较两个元素的内容
 *         equals()返回true,说明两个元素内容相同,认为重复,不存
 *         equals()返回false,说明两个元素内容不同,存
 *   Object类中原始的hashCode()返回的就是内存地址值
 */
public class Demo {
    public static void main(String[] args){
        HashSet<String> hs=new HashSet<String>();
        hs.add("ab");//当存入第一个ab时候直接存入
        hs.add("ab");//当存入第二ab的时候,先调用hashCode()方法获取两个元素哈希值,比较发现相同
        //在调用equals方法比较,"ab".euqlas("ab")//true,第二个ab就不存

        hs.add("bc");//当存入bc的时候,先调用hashCode()方法获取两个元素哈希值
        //比较发现不同,直接存入    
        System.out.println(hs);//[ab, bc]
        System.out.println("ab".hashCode());//3105
        System.out.println("bc".hashCode());//3137
    }
}
HashSet存取自定义对象保证唯一原理

当我们存储自定义对象中出现同名同年龄的,利用HashSet不能去重:

因为Person利用的是从Object类中继承的hashCode方法,获取的是元素的地址值比较

而每个Person都是新new的Person,地址值均不同

public class Person /*extends Object*/ {
    private String name;
    private int age;

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

}


import java.util.HashSet;
/*
 * 利用HashSet存储自定义对象
 */
public class PersonDemo {
    public static void main(String[] args) {
        //1.创建HashSet集合
        HashSet<Person> hs=new HashSet<Person>();

        //2.创建3个Person对象
        /*Person p=new Person("张三",12);
         *hs.add(p);
         */
        hs.add(new Person("张三",12));//匿名对象
        hs.add(new Person("张三",12));//调用hashCode()方法获取哈希值(内存地址值),去比较
        //第二个Person对象的哈希值和第一个Person的哈希值不同
        //第二个Person直接存入
        hs.add(new Person("王五",16));

        //3.遍历HashSet集合
        for(Person p : hs){
            System.out.println(p.getName()+" "+p.getAge());
        }
        //张三 12
        //张三 12
        //王五 16
    }
}

我们尝试改写(重写)原有的hashCode与equals方法保证同名同年龄的人被过滤掉

public class Person /*extends Object*/ {
    private String name;
    private int age;

    public Person(String name, int age) {
        super();
        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;
    }
    /*我们在重写hashCode()一般用上这个类的所有属性来产生哈希值*/
	/*@Override
	public int hashCode() {
		 //return 10;
		return name.hashCode() + age;
	}*/
    /*
     *return 10,让所有元素都产生了相同哈希值,所有元素都得去调用
     *equals()比较
     * 对于new Person("张三", 12)还有new Person("王五", 16)
     *  两者的姓名和年龄都不同,没必要再去调用equals比较
     */

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }


    /*
     * euqual方法的重写与之前的相同
     *  如果两个人的姓名和年龄均相同,认为是同一个人,返回true
     *  如果两个人的姓名和年龄至少有一个不同返回false
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

import java.util.HashSet;
public class PersonDemo {
    public static void main(String[] args) {
        // 1.创建HashSet集合
        HashSet<Person> hs = new HashSet<Person>();

        // 2.创建3个Person对象
        Person p1=new Person("张三", 12);
        Person p2=new Person("张三", 12);
        Person p3=new Person("王五", 16);
        hs.add(p1);//p1直接存入
        hs.add(p2);//存入p2,需要调用hashCode()方法获取p1,p2的哈希值
        //哈希值相同,需要再去比较equals(),返回true,认为相同元素,不存
        hs.add(p3);//存入p3,需要调用hashCode()方法获取p3,p1的哈希值
        //不同,直接将p3存入

        System.out.println(p1.hashCode());//776222
        System.out.println(p2.hashCode());// 776222
        System.out.println(p3.hashCode());// 938522

        // 3.遍历HashSet集合
        for (Person p : hs) {
            System.out.println(p.getName() + " " + p.getAge());
        }
        //王五 16
        //张三 12
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值