美文网首页
Java 相关面试题

Java 相关面试题

作者: _Sisyphus | 来源:发表于2018-09-15 16:36 被阅读0次

    HashCode 和 equals 方法

    参考:
    https://blog.csdn.net/SEU_Calvin/article/details/52094115
    https://blog.csdn.net/jing_bufferfly/article/details/50868266
    https://blog.csdn.net/anmoyyh/article/details/76019777
    https://blog.csdn.net/zzg1229059735/article/details/51498310

    1. 是什么?

    HashCode是用于查找使用的,而equals是用于比较两个对象是否相等的。

    HashCode:按某种规则生成的 int 类型的数值,(用于确定对象存储地址)。
    equals :比较两个对象内容是否相等,用于保证元素不重复。

    2. 为什么需要重写
    • 重写 hashCode:
      相等的对象具有相等的hashCode这一原则。而hashCode 默认实现是根据对对象内存地址换算出的值。
      减少了 equals 比较的次数,提高了效率。
      若 HashCode 相同再去调用 equals,如果不同,那没就不必在进行 equals 的比较了.
    • 重写 equals:
      默认比较的地址值,但是我们一般需要比较内容是否相等。

    二者关系:

    1. 如果两个对象 equals,那么它们的 hashCode 值一定相同
    2. 如果两个对象的 hashCode 相同,它们并不一定 equals

    存过程:

    1. 先调用元素的 hashCode 方法,定位它存放的位置
    2. 如果这个位置无元素,就放入该位置
    3. 如果这个位置已经有元素了,则调用它的 equals 方法与新元素进行比较:
    • 如果相同的话就不存了。
    • 如果不同(Hash key相同冲突),那么在这个 Hash key 的位置产生一个链表,将所有产生相同 HashCode 的对象放到这个单链表上去,串在一起。

    这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。

    取过程:

    1. hashcode不重复:
      通过 hashCode 直接找到存放的位置了
    2. hashcode重复:
      先通过 hashCode 来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过 equals 来在这个桶里找到我们要的类。

    问题:重写了equals(),为什么还要重写hashCode()呢?

    违反了 hashCode 通用约定(相等的两个对象必须具有相等的散列码),导致该类无法结合所有基于散列的集合一起正常工作(HashMap、HashSet、HashTable)。

    你要在一个桶里找东西,你必须先要找到这个桶,不通过重写hashcode()来找到桶,光重写equals()有什么用啊 。

    3. 如何重写?重写的原则

    重写 equals 原则:

    1. 使用 == 操作符判断参数是否是这个对象的引用。

    2. 使用 instance of 操作符判断”参数是否是正确的类型“。

    3. 把参数转换成正确的类型。

    4. 对于参数中的各个字段,判断其是否和对象中的字段相匹配;

      @Override
      public boolean equals(Object o) {
          if (o == this) return true;
          if (!(o instanceof User)) {
              return false;
          }
          User user = (User) o;
          return user.name.equals(name) &&
                  user.age == age &&
                  user.passport.equals(passport);
      }
      

    重写 hashCode原则:

    • 为不相等的对象产生不相等的 hashCode。

        @Override
        public int hashCode() {
             int result = 17;
             result = 31 * result + name.hashCode();
             result = 31 * result + age;
             result = 31 * result + passport.hashCode();
             return result;
        }
      

    HashSet (HashMap)怎么判断集合元素重复?

    HashSet不能添加重复的元素,当调用add(Object)方法时候:

    1. 先比较 hashCode 是否相同,hashCode 不同则表示对象不同,直接添加
    2. hashCode 相同则继续比较 equals 方法:
      • 返回 true: 说明元素重复,就不添加
      • 返回 false:说明元素不重复,就添加

    数组和链表的区别?

    数组:长度固定,元素在内存中连续存储。

    • 优点:查找效率比较高;
    • 缺点:长度固定不灵活,插入、删除数据效率低。

    链表:长度可变,是动态申请内存空间 ,元素通过指针关联

    • 优点:动态申请或者删除内存空间,对于数据增加和删除比数组灵活
    • 缺点:查询慢

    加密算法相关

    MD5:

    MD5 -- message-digest algorithm 5 (信息-摘要算法),特点是不管文件多大,经过MD5后都能生成唯一的MD5值;项目中用于对密码进行加密保存,容易被反查,所以一般会加盐值。

    BASE64:

    对数据内容进行编码来适合传输,是一种编码算法。常见于邮件、http加密

    HMAC:

    HMAC(Hash Message Authentication Code,散列消息鉴别码,基于密钥的Hash算法的认证协议。实现原理:用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。

    非对称加密 RSA:

    公钥加密、私钥解密;
    优点:非对称算法,加密程度高。
    缺点:进行的都是大数计算,速度慢
    应用场景:对安全性要求较高的数据加密和数字签名,如 支付宝、银行

    对称加密

    对称加密算法,又称秘钥加密:用一个秘钥来管理信息的加密解密。

    优点:算法公开、计算量小、加密速度快、加密效率高。
    缺点:秘钥泄露就会被破解。
    应用场景:

    • 将敏感信息保存到本地的时候加密,取出的时候还原。
    • 或上传一些敏感数据到服务器时候,服务端使用同样的算法就可以解密。

    常用算法:
    DES :安全度在现代已经不够高
    3DES:算法强度提高了很多,但是其执行效率低下
    AES:算法加密强度大,执行效率高,使用简单,实际开发中建议选择AES 算法。

    多线程相关

    1. 进程和线程的区别

    • 进程是 CPU 资源分配的最小单位,线程是 CPU 执行的最小单位。
    • 进程之间不能共享资源,而线程共享所在进程的地址空间和其它资源。
    • 一个进程内可拥有多个线程,进程可开启进程,也可开启线程。
    • 一个线程只能属于一个进程,线程可直接使用同进程的资源,线程依赖于进程而存在。

    2. run() 和 start() 方法区别

    • run() :仅仅是封装被线程执行的代码,直接调用时普通方法
    • start()::首先启动了线程,然后由 JVM 去调用该线程的 run() 方法,调用两次抛出异常

    3. 线程调度模型

    • 分时调度模型:
      所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
    • 抢占式调度模型:
      优先让优先级高的线程使用 CPU ,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些。
      Java 使用的是抢占式调度模型

    4. 三个线程保证顺序执行

    • Thread.join() 方法 :join() 方法放到 start() 后面

    • newSingleThreadExecutor

       ExecutorService executor = Executors.newSingleThreadExecutor();
       executor.submit(t1);
       executor.submit(t2);
       executor.submit(t3);
       executor.shutdown();
      
    • 同步锁+生产者消费者模型

    • 信号量

    5. Java 开启线程的方式

    1. 继承 Thread 类
    2. 实现 Runable 接口
      • 避免 Java 单继承带来的局限性。
      • 把线程同程序的代码、数据分离,较好的体现了面向对象的设计思想,适合多个相同的程序代码去处理同一资源的情况。
    3. Callable:结合线程池

    6. 死锁问题及其代码
    死锁:指两个或两个以上的线程在执行过程中,因争夺资源产生的一种互相等待现象。

    相关文章

      网友评论

          本文标题:Java 相关面试题

          本文链接:https://www.haomeiwen.com/subject/tnozgftx.html