Java Interview 200 Questions —— Day01 —— 备战2022年秋招 —— 经典 200 问

📖 day01 大纲

1️⃣ JDK、JRE、JVM 之间的区别

2️⃣ hashCode() 与 equals() 之间的关系

3️⃣ String、StringBuffer、StringBuilder 的区别

4️⃣ 泛型中 extends 和 super 的区别

5️⃣ == 和 equals() 方法的区别

📑 JDK、JRE、JVM 之间的区别

JDK(Java SE Development Kit)

  • Java 标准开发包,它提供了编译、运行 Java 程序所需的各种工具和资源,包括 Java 编译器、Java运行时环境,以及常用的 Java 类库等

JRE(Java Runtime Environment)

  • Java 运行环境,用于运行Java 的字节码文件。JRE 中包括了 JVM 以及 JVM 工作所需要的类库,普通用户而只需要安装 JRE 来运行 Java 程序,而程序开发者 必须安装 JDK 来编译、调试程序。

JVM(Java Virtual Machine)

  • Java 虚拟机 ,是 JRE 的一部分,它是整个 Java 实现跨平台的最核心的部分,负责运行字节码文件。

📚 具体流程

我们写 Java 代码,用 txt 就可以写,但是写出来的 Java 代码,想要运行,需要先编译成字节码,那就需要编译器,而 JDK 中就包含了编译器 javac ,编译之后的字节码,想要运行,就需要一个可以执行字节码的程序,这个程序就是 JVM (Java 虚拟机),专门用来执行 Java 字节码的。

📚 注意点

1️⃣ 如果我们要开发 Java 程序,那就需要 JDK ,因为要编译 Java 源文件

2️⃣ 如果我们只想运行已经编译好的 Java 字节码文件 ,就是 *.class 文件,那么就只需要 JRE

3️⃣ JDK 中包含了 JRE ,JRE 中包含了 JVM

4️⃣ 另外,JVM 在执行 Java 字节码时,需要把字节码解释为 机器指令,而不同的操作系统的机器指令有可能不一样,所以就导致不同操作系统上的 JVM 是不一样的,所以我们在安装 JDK 时 需要选择操作系统。

5️⃣ JVM 是用来执行 Java 字节码的,所以凡是某个代码编译之后是 Java 字节码,那就都能在 JVM 上运行。

📑 hashCode() 与 equals() 之间的关系

Demo 示例

User.java

/***
 * @author: Alascanfu
 * @date : Created in 2022/6/30 13:08
 * @description: User 实体类 用于演示 hashCode() 与 equals() 之间的关系
 * @modified By: Alascanfu
 **/
public class User {
    private String name ;
    
    public User(String name ){
        this.name = name ;
    }
    
    public String getName(){
        return name ;
    }
    /**
     * 如果两个 User 对象的 name 属性 相同则认为二者 equals
     * */
    @Override
    public boolean equals(Object obj) {
        User user = (User) obj;
        return user.getName().equals(this.name);
    }
}

Main.java

/***
 * @author: Alascanfu
 * @date : Created in 2022/6/30 13:12
 * @description: Main 类 用于演示 hashCode() 与 equals() 之间的关系
 * @modified By: Alascanfu
 **/
public class Main {
    public static void main(String[] args) {
        HashMap<User, String> map = new HashMap<>();
        map.put(new User("Alascanfu"),"201901094106");

        System.out.println(map.get(new User("Alascanfu"))); // null
    }
}

运行结果

在这里插入图片描述

这里拿到的是 null ,这是为什么呢?

通过查看源码

HashMap 中的 get() 方法

public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}

实际上 在 map 的 get() 方法实际首先会通过 getNode() 去判断二者的 hashCode() 是否相同。

final Node<K,V> getNode(int hash, Object key)

do {
    // 这里就是判断 两个 对象的 hash 值是否相等
    // 注意这里是 && 短路逻辑与 是先要进行判断 hash 值是否相等 若相等才会进行后续判断
    if (e.hash == hash &&
        ((k = e.key) == key || (key != null && key.equals(k))))
        return e;
} while ((e = e.next) != null);

上面提出了 hash 值并非一致相等 ,hash值是根据对象进行所返回的一个 hashCode

  • 故我们需要对User 对象中的 hashCode() 方法进行重写,针对 name 属性的值生成对应的 hashCode。这样就保证 name 相同的值 生成的 hashCode 也是相同的。

User.java 中重写 hashCode() 方法

@Override
public int hashCode() {
    return name.hashCode();
}

此时再去运行测试运行

在这里插入图片描述

📚 理论知识如何在面试中回答?—— ⭐ 背这里的

  • 如果两个对象的 hashCode 不相同,那么这两个 对象肯定是不同的两个对象(即equals()一定返回 false)。

  • 如果两个对象的 hashCode 相同,不代表这两个对象一定是同一个对象,也可能是两个对象。(即 equals() 可能返回 true 可能 返回 false)

  • 如果两个对象的相等,那么他们的 hashCode 就一定相同。

扩展

在 Java 的一些集合类的实现中,在比较两个对象是否相等时,会根据上面的原则,先调用对象的 hashCode 进行比较,如果不相同,直接认为这两个对象不相同,如果 hashCode 相同,那么就会进一步调用 equals() 方法进行比较。而 equals 方法,就是用来最终确定两个对象是否相等,通常 equals() 方法的实现会比较重,逻辑比较多 ,而 hashCode() 主要就是得到一个 哈希值,实际上就是一串数字,所以在比较两个对象是否相等时,通常会先根据 hashCode 进行粗略比较。

📚 注意点:所以如果我们重写了 equals()方法,那么就要注意 hashCode() 方法,一定要保证能遵守上述规则。

📑 String、StringBuffer、StringBuilder 的区别

1️⃣ String 是不可变的 ,如果尝试去修改就会生成一个字符串对象,StringBuilder 与 StringBuffer 是可变的。

2️⃣ StringBuffer 是线程安全的,StringBuilder 是线程不安全的,所以在单线程环境下 StringBuilder 更高效。

**为什么 String 是不可变的 => **String为什么是不可变的

StringBuffer 为什么是线程安全的?——因为其中的每个方法都加上了 synchronized 同步关键字,进而每个方法都是同步方法,保证了StringBuffer的线程安全性。

📑 泛型中 extends 和 super 的区别

1️⃣ <? extends T>:表示包括 T 在内的任何 T 的子类。

2️⃣ <? super ?> : 表示包括 T 在内的任何 T 的父类。

快速了解泛型

MyList.java

/***
 * @author: Alascanfu
 * @date : Created in 2022/6/30 14:30
 * @description: MyList 类用于快速了解理解泛型
 * @modified By: Alascanfu
 **/
public class MyList<E> {
    // ...
    
    public void add(E data){
        // ... 
    }
    
    // ...
}

📚 在类上标注了泛型 <E> 用于让用户指定 E 代表的数据类型(即 在类中 E 就代表传入的数据类型)——可以是八大基本数据类型,也可以是引用数据类型。

Main.java

public class Main {
    public static void main(String[] args) {
        // 这里指明泛型类型为 BigDecimal 这个精度类 jdk 中自带的
        MyList<BigDecimal> myList = new MyList<>();
        // 使用的时候 参数类型也就泛化为 指明的泛型类型 BigDecimal
        myList.add(new BigDecimal(1));
    }
}

根据修改泛化extends 或 super 类型来指明其泛化的范围

例如此时将其修改为 extends number

public class MyList<E extends Number> {
    // ...
    
    public void add(E data){
        // ...
    }
    
    // ...
}

那么说明我们用户在指定类型泛化时 只可以是 Number 这个抽象类本身或其子类类型

在这里插入图片描述

此时编译报错——Type parameter 'java.lang.String' is not within its bound; should extend 'java.lang.Number'

在这里插入图片描述

此时就是合法的。

当然我们也可以进行测试判断对个对象的类是否相同

public class Main {
    public static void main(String[] args) {
        MyList<Integer> myList1 = new MyList<>();
        myList1.add(1);
        MyList<Double> myList2 = new MyList<>();
        myList2.add(1.0);
    
        System.out.println(myList1.getClass().equals(myList2.getClass()));// true 
    }
}

这里的返回结果是 true 说明在通过对象获取其类 Class 时 是忽略掉泛型的。

📑 == 和 equals() 的区别

1️⃣ == :如果是基本数据类型,比较是值,如果是引用数据类型,比较的是引用地址

2️⃣ equals: 具体看各个类重写 equals 方法之后的逻辑比较,比如 String 类,虽然是 引用数据类型,但是 String 中重写了 equals 方法,方法内部比较的是字符串中的各个字符是否全部相等。

String.equals() 方法源码

public boolean equals(Object anObject) {
    // 如果是基本数据类型值相等 就返回 true
    if (this == anObject) {
        return true;
    }
    // 如果其类型是 String 类型的对象则在进行比较
    if (anObject instanceof String) {
        // 强制类型转换用于后续判断
        String anotherString = (String)anObject;
        // 获取 原字符串的长度
        int n = value.length;
        // 判断字符长度是否相等
        if (n == anotherString.value.length) {
            // 将两个 String 对象的字符数组中的每个字符依次比较
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Alascanfu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值