基础面试题一

目录

一、为什么重写equals()一定要重写hashCode() 

二、==和equals比较的区别

三、为啥有时会出现4.0-3.6等于0.000001

四、final关键字作用


一、为什么重写equals()一定要重写hashCode() 

equals()方法:作用:用来比较该类的两个对象是否相等

                        实现:equals未被重写就直接进行引用比较

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

    public static void main(String[] args) {
        Person p1 = new Person("阿伦");
        Person p2 = new Person("阿伦");
        System.out.println(p1.equals(p2));
    }

    static class Person {

        public Person(String name) {
            this.name = name;
        }
        private String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.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 Objects.equals(name, person.name);
        }
    }

}

输出为true

可以看到重写了equals,只要类型相同,name相同,就认定两个对象是同一个,而不是默认用内存地址比对。

为什么要重写hashCode

根据hashCode的key是唯一的,去重的,我们打印上边代码,通过两个相同应该就是同一个对象

public static void main(String[] args) {
        Person p1 = new Person("阿伦");
        Person p2 = new Person("阿伦");
        Map<Person, String> map = new HashMap<>();
        map.put(p1, p1.getName());
        map.put(p2, p2.getName());
        System.out.println("map长度:" + map.size());
        map.forEach((key, value) -> {
            System.out.println(key.getName());
        });
    }

原因:hashcode的内部是一个数组,但是它的查找速度非常快,因为hashmap对key进行hash后,得到一个整数值

我们没有重写hashcode,虽然equals以两个对象name值是否相同,但是hashmao存值的时候是通过hashcode进行计算的,所以上面的两个值返回的hashcode是不同的

所以我们要把hashcode 的计算方法改为name计算:

public class TestDemo {

    public static void main(String[] args) {
        Person p1 = new Person("阿伦");
        Person p2 = new Person("阿伦");
        System.out.println(p1.hashCode());
        System.out.println(p2.hashCode());
        Map<Person, String> map = new HashMap<>();
        map.put(p1, p1.getName());
        map.put(p2, p2.getName());
        map.get(p1);
        System.out.println("map长度:" + map.size());
        map.forEach((key, value) -> {
            System.out.println(key.getName());
        });
    }

    static class Person {

        public Person(String name) {
            this.name = name;
        }
        private String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.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 Objects.equals(name, person.name);
        }
        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    }
}

总结:根据业务重写equals后,一定要将hashcode用相同规则做hash,防止在一些需要用到对象的hashcode的地方造成问题。

重写equals和hashcode的原则:

  • 自反性:x.equals(x)==true,自己调用自己相等
  • 对称性:x.equals(y)==y.equals(x),两个对象结果应该一样
  • 传递性:如果x.equals(y) == true y.equals(z) == true 则 x.equals(z) == true,x和y相等,y和z相等,则x和z相等
  • 一致性:如果x对象和y对象有成员变量num1和num2,其中重写了equals方法,只有num1参加运算,修改num2的值不影响结果。

二、==和equals比较的区别

  1. equals()方法比较的是两个对象值   而==比较的两个引用是否指向同一个对象   有些同学要问了  为什么直接=字符串和new()字符串难道不同吗?  对的 第二点就是new和=的区别
  2. 用=时 会在字符常量串常量池中创建 如 string  s="123"; 字符串常量池不属于堆也不属于栈  这样就会在字符串常量池创建“123”(如果字符串常量池中已经有“123” 就把s引用指向它)。再创建一个string s1=“123”;会把s1的引用指向已经存在的“123”;而不会再创建一个 这样s和s1的引用都是一样的 用==也可以判断出来用new()时  不管字符串常量池中有没有  都到从堆内存中开辟一块空间存放 new一次 开辟一次 所以 String str1=new String("str"); String str2=new String ("str");是不同的两块空间 所以引用也就不相同的
  3. ==只会判断两个引用是否指向同一个对象(也就是同一块内存地址) 所以这时候用==是false

 结论:

  1. ==用于比较两个引用是否指向同一个对象   equals用于比较两个对象是否相等
  2. 由于字符串特殊 在字符串常量池中的字符串可以使用==也可以使用equals 推荐不管哪种方式 只要是比较字符串就用equals

三、为啥有时会出现4.0-3.6等于0.000001

浮点数采用二进制数表示,而在二进制系统中无法精确表示分数1/10

就好像十进制无法精确表示分数1/3一样

0.1不能写成1/(2^n)的和的形式

一般精确用:biginteger 和  bigdecimal 这两个类。

四、final关键字作用

  1. 修饰一个引用:
    1. 引用为常量,该值无法改变
    2. 引用为数组,该对象本身属性能改变,但指向的地址不能修改
    3. 引用的类成员必须赋值
  2. 修饰方法:
    1. 最终方法,无法没重写
  3. 修饰类:
    1. 最终类,无法被继承
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值