阶段一/常用工具/集合

目录

应用场景

集合框架的体系结构

Collection

Map

集合和数组的区别

List概述

Set概述

HashSet

Iterator(迭代器)

hashCode 和 equals

关于getClass()和.class的作用

自定义对象

删除元素 


 

应用场景

  • 无法预测存储数据的数量
  • 同时存储具有一对一关系的数据
  • 需要进行数据的增删改查
  • 需要解决数据重复问题,可以直接使用集合Set完成

集合框架的体系结构

Collection

主要用于存储类的对象。

Collection下有三个子接口,分别是List,Queue和Set,List和Queue中可以存储有序且重复的数据,Set中存储的数据是无序且不允许重复。

  • List接口的主要实现类包括ArrayList和LinkedeList,LinkedList同时实现了Queue接口
    • ArrayList的底层实现是数组,因此在内存中是连续存储的。查询速度快,但增加和删除速度慢。
    • LinkedList底层是基于双向链表的,增加和删除速度快,查询速度慢。
  • Set接口主要实现类有HashSet和TreeSet
    • HashSet是基于哈希表实现的,数据是无序的,HashSet元素可以是null,但只能有一个null。
    • TreeSer基于二叉树实现的,可以实现数据的自动排序,确保集合元素处于排序状态,不允许放入空值。
    • HashSet的性能优于TreeSet,一般情况下建议使用HashSet,如果需要使用排序功能建议使用TreeSet。

Map

主要用于存储键值对的数据。

Map的主要实现类包括HashMap和TreeMap,其中HashMap基于哈希表实现,TreeMap基于红黑树实现。

  • HashMap适用于在Map中插入、删除和定位元素。
  • TreeMap适用于按自然顺序或自定义顺序对键值进行遍历
  • HashMap比TreeMap性能好,所以HashMap使用更多一些,如果需要对数据经排序可以使用TreeMap。
  • 集合和数组的区别

  • 数组的长度是固定的,集合的长度可以动态扩展。
  • 数组只能存储相同数据类型的数据,而集合可以存储不同数据类型的数据。
    • 集合加上范型,也就限制了集合中只能存储这一种数据类型的数据。
  • 数组可以存储基本数据类型数据和引用类型数据,而集合只能是引用类型。
public class list {
    public static void main(String[] args){
        List list = new ArrayList();
        list.add(new String("hello"));
        // 至于我们看到list.add(1)也没报错,是因为自动装箱操作,将基本数据类型转换为对应的包装器类对象了。
        list.add(1);
        list.add(new Double(10));
        System.out.println("********************");
        for(int i = 0; i < list.size(); i++){
            System.out.println("" + list.get(i) +" , "
                    + list.get(i).getClass());
        }
        System.out.println("********************");
    }
}

输出:

********************
hello , class java.lang.String
1 , class java.lang.Integer
10.0 , class java.lang.Double
********************

从上面我们可以看出,可以存放不同类型的对象,至于我们看到list.add(1)也没报错,是因为自动装箱操作,将基本数据类型转换为对应的包装器类对象了。

List概述

List

  • List是元素有序并且可以重复的集合,称为序列
  • List可以精确的控制每个元素的插入位置,或删除某个位置的元素
  • List的两个主要实现类是ArrayList和LinkedList

ArrayList

  • 底层是有数组实现的
  • 动态增长,以满足应用程序的需求
  • 在列表尾部插入或删除非常有效
  • 更适合查找和更新元素
  • ArrayList中的元素可以为null

下面是leetcode上的一个例题,关于List的元素任然是List,以及增强型for循环使用,当然也有下标索引取值的方法

public class Generate118 {
    public static List<List<Integer>> generate(int numRows) {
        List<List<Integer>> ans = new ArrayList<>();
        for(int i = 0; i < numRows; i++){
            List<Integer> temp = new ArrayList<>((i + 1));
            if(i == 0){
                temp.add(1);
                ans.add(temp);
            }else{
                temp.add(1);
                for(int j = 1; j < i; j++){
                    temp.add(ans.get(i - 1).get(j - 1) + ans.get(i - 1).get(j));
                }
                temp.add(1);
                ans.add(temp);
            }
        }
        return ans;
    }
    public static void main(String[] args){
        List<List<Integer>> ans = generate(5);
        for(List<Integer> temp: ans){
            for(int one: temp){
                System.out.print(one + " ");
            }
            System.out.println();
        }
    }
}

输出

1 
1 1 
1 2 1 
1 3 3 1 
1 4 6 4 1 

Set概述

Set是元素无序并且不可以重复的集合,被称为集。

HashSet

  • HashSet是Set的一个重要实现类,称为哈希集
  • HashSet中的元素无序并且不可以重复
  • HashSet中只允许一个null元素
  • 具有良好的存取和查找性能
  • 若我们尝试向hashSet里面添加重复的元素,并不会报错,只不过hashSet中不会多出一个相同元素。
  • HashSet底层是基于HashMap实现的

Iterator(迭代器)

  • Iterator接口可以以统一的方式对各种集合元素进行遍历
  • hasNext()方法检测集合中是否还有下一个元素
  • next()方法返回集合中的下一个元素
  • 迭代器在使用时要注意,迭代器是不断向后走的,如果需要多次使用一个迭代器,需要每次使用前都要把迭代器指向set的初始位置。it=catSet.iterator();
public class WordDemo {
    public static  void main(String[] args){
        // 将英文单词添加到HashSet中
        Set words = new HashSet();
        // 向集合中添加元素
        words.add("blue");
        words.add("red");
        words.add("black");
        words.add("white");
        pringInfo(words, "");
        // 在集合中插入一个新的单词
//        words.add("green");
        words.add("white"); // 并不会报错,只是不会插入
        pringInfo(words, "插入重复元素后,");
    }
    public static void pringInfo(Set words, String operator){
        // 显示集合中的元素
        System.out.println(operator + "集合中的元素个数为:" + words.size());
        Iterator it = words.iterator();
        // 遍历迭代器并输出元素
        while(it.hasNext()){
            System.out.print(it.next() + " , ");
        }
        System.out.println("\n=========================\n");
    }
}

输出

集合中的元素个数为:4
red , blue , white , black , 
=========================

插入重复元素后,集合中的元素个数为:4
red , blue , white , black , 
=========================

hashCode 和 equals

hashCode()方法用于给对象返回hash code值,equals()方法用于判断其他对象与该对象是否相等。为什么需要这两个方法呢?我们知道HashSet中是不允许添加重复元素的,那么当调用add()方法向HashSet中添加元素时,是如何判断两个元素是不同的。这就用到了hashCode()和equals()方法。在添加数据时,会调用hashCode()方法得到hash code值,通过这个值可以找到数据存储位置,该位置可以理解成一片区域,在该区域存储的数据的hashCode值都是相等的。如果该区域已经有数据了,就继续调用equals()方法判断数据是否相等,如果相等就说明数据重复了,就不能再添加了。如果不相等,就找到一个位置进行存储。
这些是基于哈希算法完成的,它使得添加数据的效率得到了提升。假设此时Set集合中已经有两个100个元素,那么如果想添加第101个元素,如果此时没有使用哈希算法,就需要调用equals()方法将第101个元素与前100个元素依次进行比较,如果元素更多,比较所耗费的时间就越长。
如果两个对象相等,那么他们的hashCode值一定相等。反之,如果两个对象的hashCode值相等,那么这两个对象不一定相等,还需要使用equals()方法进行判断。
如果不重写hashCode()方法,默认每个对象的hashCode()值都不一样,所以该类的每个对象都不会相等 。

关于getClass()和.class的作用

@Override
public boolean equals(Object obj) {
    // 判断对象是否相等,相等则返回true,不用继续比较属性了
    if(this == obj)
        return true;
    // 判断obj是否是Cat类的对象
    if(obj.getClass() == Cat.class){
        Cat temp = (Cat) obj;
        if(this.hashCode() == temp.hashCode())
                return (getName().equals(temp.getName())
                && (getMonth() == temp.getMonth())
                && getSpecies().equals(temp.getSpecies()));
    }
    return false;
}

关于if(obj.getClass() == Cat.class)

      首先,来看一下Class类。在Java中,万事万物皆对象,每个类都有一个相应的Class对象。通过Class类,可以获得一个类的基本信息,比如属性、方法和构造方法等。这些都属于Java反射的内容,在后面的课程中将会学习到。
getClass()是Object类的方法,该方法的返回值类型是Class类,通过getClass()方法可以得到一个Class类的对象。而.class返回的也是Class类型的对象。所以,如果obj.getClass()和Cat.class返回的内容相等,说明是同一个对象。
既然都可以得到Class的对象,关于getClass()和.class的区别:getClass()方法,有多态能力,运行时可以返回子类的类型信息。.class是没有多态的,是静态解析的,编译时可以确定类型信息。

下面我们来说说,为什么不用if(obj isinstanceof Cat),obj.getClass()==Cat.class与obj instanceof Cat并不是等价的。obj.getClass==Cat.class就是判断obj是Cat类型的,而obj instanceof Cat中obj可以是Cat子类的对象。若用obj isinstanceof Cat来判断,则只要obj是Cat或其子类,且这三个属性相等就会被判为相等,其实他们都有可能不是同一类型的对象,而obj.getClass()是有多态能力,运行时可以返回子类的类型信息,.class是没有多态的,是静态解析的,此时若obj是Cat的子类就不可以了,保证了他们是同一类型的对象

自定义对象

关于自定义对象,若我们想利用Set的不能添加重复元素的属性,则必须重写洗定义对象的hashCode方法和equals方法,至于之前用String类型的对象没有重写,是因为String类已经帮我们重写过了。

public class Cat {
    private String name;
    private int month;
    private String species;

    public Cat(String name, int month, String spcies) {
        this.name = name;
        this.month = month;
        this.species = spcies;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public String getSpecies() {
        return species;
    }

    public void setSpecies(String spcies) {
        this.species = spcies;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", month=" + month +
                ", spcies='" + species + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object obj) {
        // 判断对象是否相等,相等则返回true,不用继续比较属性了
        if(this == obj)
            return true;
        // 判断obj是否是Cat类的对象
        if(obj.getClass() == Cat.class){
            Cat temp = (Cat) obj;
            if(this.hashCode() == temp.hashCode())
                return (getName().equals(temp.getName())
                && (getMonth() == temp.getMonth())
                && getSpecies().equals(temp.getSpecies()));
        }
        return false;
    }

    @Override
    public int hashCode() {
        final int prime = 33;
        int result = 1;
        result = prime * result + month;
        result = prime * result + ((name == null) ? 0: name.hashCode());
        result = prime * result + ((species == null) ? 0: species.hashCode());
        return result;
    }
}
public class CatTest {
    public static void main(String[] args){
        Cat huahua = new Cat("花花", 12, "英短");
        Cat fanfan = new Cat("凡凡", 3, "中华田园猫");

        // 将宠物猫对象放入HashSet中
        Set cats = new HashSet();
        cats.add(huahua);
        cats.add(fanfan);
        printInfo(cats, "");
        // 再添加一个与花花属性一样的猫
        Cat huahua_copy = new Cat("花花", 12, "英短");
        // 添加重复数据
        cats.add(huahua_copy);
        printInfo(cats, "");
    }

    public static void printInfo(Set cats, String operator){
        // 显示集合中的元素
        System.out.println(operator + "集合中的元素个数为:" + cats.size());
        Iterator it = cats.iterator();
        // 遍历迭代器并输出元素
        while(it.hasNext()){
//            Cat cat = (Cat)it.next();
//            System.out.print(cat.getName() + " , ");
            System.out.print((Cat)it.next() + " , ");
        }
        System.out.println("\n=========================\n");
    }
}

输出:重写了hashCode和equals方法,则就不会添加重复元素了。

集合中的元素个数为:2
Cat{name='花花', month=12, spcies='英短'} , Cat{name='凡凡', month=3, spcies='中华田园猫'} , 
=========================

集合中的元素个数为:2
Cat{name='花花', month=12, spcies='英短'} , Cat{name='凡凡', month=3, spcies='中华田园猫'} , 
=========================

删除元素 

/**
* Java中是不允许一边遍历一遍进行修改集合中的元素,会出现数据的不一致性的问题。
* 对于Set集合,如果删除的是集合中最后一个元素,是不会进行报错的。
* 而在删除数据后,集合的存储结构就发生变化了,如果再遍历就会出错的。
* 解决方案是:在删除数据后,使用break;语句跳出循环。
*/
// 删除花花二代的信息,若只有一条符合要求
for(Cat oneCat: cats){
    if(oneCat.getName().equals("花花二代")){
        cats.remove(oneCat);
        break;
    }
}
printInfo(cats, "删除花花二代后的,");

// 若多条符合要求,用新的HashSet来存储需要被删除的对象,再通过removeAll
Set<Cat> removeCats = new HashSet<Cat>();
for(Cat oneCat: cats){
    if(oneCat.getMonth() < 5){
        removeCats.add(oneCat);
    }
}
cats.removeAll(removeCats);
printInfo(cats, "删除小于5个月后的,");

 

 

 

 

 

未完,待续

参考: 慕课网-Java工程师

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值