【JAVA企业级开发】Java List<>集合中泛型为对象时,使用containsAll方法来判断一个Llist<>集合是否包含另一个List<>集合会出现的问题

一containsAll方法

今天上班的时候遇到一个坑,我把java list集合中存入对象,然后用containsAll 方法进行比较时,明明一个List集合包含另一个List集合的元素,但是结果总是返回 false。

1部分代码块如下

@Override
    @Transactional(rollbackFor = Exception.class)
    public boolean validate(Account account) {
        boolean flag = false;
        String acc = account.getAccount();
        String pass = account.getPassword();
        if (acc != "" && pass != "") {
            AccountExample accountExampleAcc = new AccountExample();
            accountExampleAcc.createCriteria().andAccountEqualTo(acc);
            List<Account> accs1 = accountMapper.selectByExample(accountExampleAcc);
            AccountExample accountExamplePass = new AccountExample();
            accountExamplePass.createCriteria().andPasswordEqualTo(pass);
            List<Account> accs2 = accountMapper.selectByExample(accountExamplePass);
            if (accs2.containsAll(accs1)&&accs1.size()!=0&&accs2.size()!=0) {
                flag = true;
            } else {
                flag = false;
            }
            return flag;
        } else {
            return false;
        }

    }

2查看 containsAll()方法源码

containsAll():

public boolean containsAll(Collection<?> c) {
    for (Object e : c)
        if (!contains(e))
            return false;
    return true;
}

contains(e) :

 public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

indexOf(o):

 public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

equals:

  public boolean equals(Object obj) {
        return (this == obj);
    }

到这里发现到equals调用的是Object.java 的equals方法,比较对象,比较对象的内存地址,我们知道即使相等的对象内存地址并不相同,所以一定会false;

二 equals方法

1Java中equals和==的区别

java中的数据类型,可分为两类:
在这里插入图片描述

①.基本数据类型,也称原始数据类型。

byte,short,char,int,long,float,double,boolean

对于基本类型来说,他们存储在jvm的栈中,因此 他们之间的比较,应用双等号(==),比较的是变量的内容,也就是比较的变量的值。

②.复合数据类型,也称引用数据类型

String,Integer,Date,List<>,Map................

对于引用类型来说, JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地址, 对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值,因为对象内容存储在jvm的堆中,栈中只是存储对象的引用(地址,地址的类型为字符串),即栈中地址字符串是引用堆的地址,所以无论是==还是equals比较的都是栈中的内容,即对象的引用,也就是比较的是两个对象的地址。除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。

但是根据创建对象的方式不同可以分为两种情况:

Integer使用表达式创建对象:equals方法比较之后相等
. 在这里插入图片描述

Integer使用new方法创建对象:equals方法比较之后不相等

在这里插入图片描述

③这里会引入两个新的问题

1.为什么表达式创建和new创建,会让==比较产生不同的结果。

这是因为jvm在程序运行的时候会创建一个缓冲池,当使用表达式创建的时候,程序会在缓冲池中寻找相同值的对象,如果找到,就把这个对象的地址赋给当前创 建的对象,因此,c和d实际上都指向了c的引用。因此在使用==时会返回true。

当用new创建对象时,是在堆中重新分配内存,因此栈中的引用是不相同的,所以,a和b引用的是值相同的不同对象。所以a = =b返回false

2.既然equals比较的是引用,那么a.equals(b)为什么返回true。
因为在一些Object的子类库当中这个方法被覆盖掉了,如String,Integer,Date,在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了,而是直接比较值。 即在Integer里,重写了equals方法!

2重写equal方法

所以List加入是Account 对象的话,如果要使用containsAll方法时,在Account对象中重写equals 方法即可;



/**
 * Created by @author LiuChunhang on 2020/7/18.
 */
package fengbo.entity;

import java.io.Serializable;
import java.util.Objects;

/**
 * Created by @author LiuChunhang on 2020/7/14.
 */
public class Account implements Serializable {
    private Integer id;

    private String account;

    private String password;

    private String enterprise;


    private String phone;

    private String mail;

    private int status;

    public Account() {
    }

    public Account(Integer id, String account, String password, String enterprise, String phone, String mail, int status) {
        this.id = id;
        this.account = account;
        this.password = password;
        this.enterprise = enterprise;
        this.phone = phone;
        this.mail = mail;
        this.status = status;
    }


    public Integer getId() {
        return id;
    }

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

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account == null ? null : account.trim();
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }

    public String getEnterprise() {
        return enterprise;
    }

    public void setEnterprise(String enterprise) {
        this.enterprise = enterprise == null ? null : enterprise.trim();
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone == null ? null : phone.trim();
    }

    public String getMail() {
        return mail;
    }

    public void setMail(String mail) {
        this.mail = mail == null ? null : mail.trim();
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", account='" + account + '\'' +
                ", password='" + password + '\'' +
                ", enterprise='" + enterprise + '\'' +
                ", phone='" + phone + '\'' +
                ", mail='" + mail + '\'' +
                ", status=" + status +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Account account1 = (Account) o;
        return status == account1.status &&
                id.equals(account1.id) &&
                account.equals(account1.account) &&
                password.equals(account1.password) &&
                enterprise.equals(account1.enterprise) &&
                phone.equals(account1.phone) &&
                mail.equals(account1.mail);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, account, password, enterprise, phone, mail, status);
    }
}


上面的代码展示了Student类的重写后的equals方法和hashcode方法,建议大家用eclipse或idea自动生成,尽量不要自己敲因为很有可能会出错。

三重写equals一定要重写hashcode

1以下是关于hashcode的一些规定

两个对象相等,hashcode一定相等

两个对象不等,hashcode不一定不等

hashcode相等,两个对象不一定相等

hashcode不等,两个对象一定不等

2 重写hashcode的原因

所以我们重写过equals方法之后,让两个内存地址不一样的对象相等之后,他们的hashcode值也应该相等!
但是默认的hashcode方法是根据对象的内存地址经哈希算法得来的,他们的hashcode不一定相等,所以我们才有了重写hashcode的必要性!

3总结

哈希集合要保证元素唯一性吧。对象放入集合,先经过hash运算,得到index,找到数组对应位置,还要和此位置的对象进行比较,不一样就插入到后面形成链表,一样的话就不用插入了。比较用到的是equals方法。重写了equals()方法,但不重写hashcode()方法,那可能两个相同的对象放入到了不同的位置,元素的唯一性就不存在了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牵牛刘先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值