java基础面试题

0. 思维导图

java基础面试题_第1张图片

1. JDK、JRE、JVM三者区别和联系♥

  • 分别解释(区别):
    • jdk:java开发工具包,包含了jre和一堆开发工具,比如javac/java等。
    • jre:java运行环境,包含jvm和java核心类库
    • jvm:java虚拟机,把字节码文件解释成具体平台的机器指令执行。
  • 联系:
    • JVM不能单独解释字节码文件,解释字节码文件的时候需要调用解释所需要的类库lib。在JDK下面的jre目录里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和lib合起来就称为jre。

2. 基本数据类型和引用数据类型的区别♥

  1. 存储位置的不同

    • 对于在方法中声明的变量,如果是基本数据类型,那么变量名和值都是存放在栈中,如果是引用数据类型,变量名存放在栈中,而指向的对象是存放在堆中。
  2. 传递方式的不同

  • 调用方法时,如果传递的参数是基本数据类型,那么就是按数值传递,如果传递的参数是引用数据类型,那么就是按引用传递,但是也不是说引用数据类型是引用传递,在java中只有值传递。

3. 8种基本数据类型、字节大小♥

  • byte:占用1个字节
  • short:占用2个字节
  • int:占用4个字节
  • long:占用8个字节
  • float:占用4个字节
  • double:占用8个字节
  • char:占用2个字节
  • boolean:占用大小取决于java虚拟机

4. 访问修饰符权限♥

public > protected > default > private

  • private:在同一个类内可见。
  • 默认:在同一个包的类可见
  • protected:对同一个包的类和不同的子类可见
  • public:对所有类可见

5. java中方法的参数传递机制♥♥

  • 参数传递机制包括两种:值传递和引用传递

    • 值传递是指在调用函数的时候传递的是实际参数的值,那么在函数中对它进行修改,不会影响到实际参数
    • 引用传递是指在调用函数的时候传递的是实际参数的地址,那么在函数中对它进行修改,会影响到实际参数
  • 但是在java中只有值传递参数

    • 为什么这样说呢?都知道数据类型分为两大类,基本数据类型和引用数据类型
      • 如果参数是基本数据类型,那么传过来的就是这个参数的一个副本,如果在函数中改变了副本的值明显不会改变原始的值。
      • 如果参数是引用数据类型,那么传过来的就是这个引用参数的一个副本,这个副本存放的是参数的地址。在函数中仅仅是改变了地址中的值,那么原始的值会改变,但是地址仍然没有改变。

6. final关键字

  • final有三种用法:修饰类、变量和方法。

    • 修饰类的时候,表示它不可以被继承
    • 修饰变量的时候,表示它不能被修改(对于基本数据类型,就是值不能被修改,对于引用数据类型,就是引用不能被修改)
    • 修饰方法的时候,表示它不能再子类中被重写
  • 补充题:final、finally、finalize的区别是什么?

    • finally作为异常处理的一部分,通常放在try…catch的后面,附带一个语句块用来表示这个语句最终一定被执行,可以将释放外部资源的代码写在finally块中
    • finalize是Object类中的一个方法,在垃圾回收器准备释放对象占用的内存时,首先会调用对象的finalize()方法,做一些清理的工作

7. static关键字的作用是什么♥

  • static有四种用法:修饰成员变量、成员方法、代码块和内部类。
    • 修饰成员变量的时候,就是将其变为类的成员,可以用类.变量的方式使用,如果有数据需要被共享给所有对象使用时,可以使用static修饰。
    • 修饰成员方法的时候,就是将其变为类的方法,可以用类.方法的方式调用,static方法中不能使用this和super关键字,只能访问本类中的静态变量和静态方法。
    • 修饰代码块的时候,在类被加载的时候,就会被执行,并且只会执行一次。
    • 修饰内部类的时候,在静态内部类中,无法直接访问外部类的非静态变量和非静态方法,如果要访问的话,必须new一个外部类对象,使用new出来的对象来访问,但是可以直接访问外部类的静态变量和静态方法。

8. compareble和comparator区别

  • 思想:Comparable是内部比较器,而Comparator是外部比较器;解释一下的话,如果一个类本身实现了Comparable接口(只有一个方法compareTo),就说明它本身支持排序,使用的时候调用Collections.sort或者Arrays.sort;如果本身没有实现Comparable接口,那么可以通过外部比较器Comparator(比如实现compare方法)来进行排序,使用的时候也是一样,但是要传入外部比较器对象。
  • 使用场景:实现Comparable接口的方式比实现Comparator接口的耦合度要高一些。(如果要修改比较算法,那么comparable还需要在实现类中修改,而comparator不需要在实现类中修改)

9. Object 类有哪些方法♥

  • equals方法:比较两个对象是否相等
  • hasCode:返回对象的哈希码值
  • toString方法:返回对象的字符串表示
  • clone:实现对象的浅拷贝
  • finalize方法:用于释放资源
  • getClass方法:获取当前对象所属的字节码文件对象

10. java的深拷贝和浅拷贝的区别♥♥♥

  • 对于基本类型,深拷贝和浅拷贝都是一样的,都是对原始数据的复制,修改原始数据,不会对复制数据产生影响。两者的区别,在于对引用类型的复制

    • 对于浅拷贝,只会复制引用,没有复制指向的对象,所以对原始对象的修改,会对复制对象产生影响;
    • 对于深拷贝,它是复制该引用指向的对象,所以修改原始对象,不会对复制对象产生影响;
  • 实现方式:继承Cloneable接口,重写clone方法,因为Object中的clone方法是浅拷贝,所以对于浅拷贝实现就是在clone方法中直接调用super.clone()就可以了;对于深拷贝,一般需要调用强制类型转换操作;

11. java中==和equials的区别♥♥♥

  • 对于基本数据类型,==比较的是对应的值,对于引用数据类型,==比较的是地址值。

  • equals方法如果未被重写,其作用和==一致,但是通常会重写该方法,比如String类型,equals方法可以用来比较变量值

  • 补充题1:为什么要重写equals方法要重写hashcode方法

    • 因为hashcode中有一个规定:如果两个对象相等,那么他们的hashcode值一定相等,如果只重写了equals方法,那么当两个对象的属性值相等的时候会返回true,但是显然如果没有重写hashcode方法,hashcode值明显不一样,这样就会和规定产生矛盾。
  • 补充题2:为什么有equals方法还需要hashcode方法

    • 他们通常是在集合插入元素时配合使用的,在插入对象的时候,先调用该对象的hashcode方法,得到哈希码值,如果table中不存在该哈希码值,那么直接插入,但是如果table中存在哈希码值,就会继续调用equals方法,判断两个对象是否真的相同,相同的就不存,不相同就存进去。

12. String、StringBuffer、StringBuilder的区别♥♥♥

  • String类采用final修饰的字符数组来保存字符串,属于不可变类,一旦修改了String的值,就会产生新的String对象
  • StringBuilder类采用无final修饰的字符数组来保存字符串,属于可变类,修改值的时候,直接在元对象上进行操作
  • StringBuffer类和StringBuilder类基本一样,唯一的不同就是StringBuffer中的方法都是用synchronized修饰的,因此是线程安全的。
  • 应用场景:如果需要经常修改字符串,就使用StringBuffer和StringBuilder,优先选择StringBuilder,效率最高,但是多线程使用共享变量的时候,优先选择StringBuffer,保证线程安全。

13. 简述面向对象三大特征♥♥

  • 给出定义:

    • 它和面向过程,是两种不同的处理问题的角度。面向过程更关注事情的每一个步骤和顺序,而面向对象更关注事情有哪些参与者,也就是对象,以及各自需要做什么。
  • 举例:

    • 比如对于洗衣机洗衣服这件事,面向过程会将任务拆解成一系列的步骤,打开洗衣机->放衣服->放洗衣粉->启动洗衣机->清洗->烘干;那么面向对象会拆成人和洗衣机两个对象,人要做的事情:打开洗衣机,放衣服,放洗衣粉,启动洗衣机,而洗衣机需要做的事情:清洗。
  • 总结例子:

    • 从这个例子可以看出,面向过程比较直接,而面向对象更具有复用性,扩展性,但是性能开销更大。
  • 三大特性:

    • 封装:把自己的属性和方法让可信的类或对象操作,对不可信的隐藏。比如用private修饰成员变量就是一种封装,这样让外面的对象不能直接访问对象的成员变量。
      • 作用:隐藏了类的内部实现机制,对外界而言,它的内部细节是隐藏的,暴露给外界的只是它的访问方法。
    • 继承:就是从已有的类中派生出新的类,新的类可以使用已有的类的属性和方法,并且还能扩展新的属性和方法
    • 多态:就是一个父类能够引用不同的子类
      • 三个条件:继承、方法重写,父类引用指向子类对象
      • 缺点:父类引用无法调用子类特有的功能

14. java中方法重载和重写的区别♥

  • 定义:

    • 重载:就是让类以统一的方式处理不同类型数据的一种手段,调用方法时通过传递给它们的 不同个数和类型的参数来决定具体使用哪个方法,重载是一个类中多态性的一种表现。
    • 重写:当子类需要修改父类的一些方法进行扩展时,这样的操作就称为重写。
  • 区别:

    • 重载发生在同一个类中,而重写发生在有继承关系的子类中
    • 重载的方法参数列表不同(包括参数顺序、个数、类型),而重写的方法参数列表(包括参数顺序、个数、类型)相同
    • 重载的方法返回值类型和访问修饰符都没有限制,而重写子类方法的返回值类型必须和父类相同,对于访问修饰符,子类的访问访问要大于父类的访问范围
  • 扩展:

    • 对于重载而言,在方法调用之前,就已经确定所要调用的方法,也叫做静态绑定(早绑定)编译
    • 对于多态而言,在方法调用时,才会确定所要调用的具体方法,也叫做动态绑定运行。

15. 抽象类和接口的区别♥

  • 区别:

    • 抽象类既可以定义抽象方法,也可以定义普通成员方法;而接口中只能定义抽象方法
    • 抽象类中的成员变量可以时各种类型的,而接口中的成员变脸只能是public static final常量类型的
  • 使用场景:当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。

16. 集合之间的继承关系♥♥

  • 集合分为单列集合Collection接口和双列集合Map接口
    • Collection接口又包括List和Set子接口,List可以存放重复的元素,Set不能存放重复的元素

      • List接口有两个实现类,分别是ArrayList和LinkedList,ArrayList底层是数组,LinkedList底层是链表
      • Set接口有两个实现类,分别是HashSet和TreeSet,HashSet是无序的,TreeSet是有序的
    • Map接口有两个实现类,分别是HashMap和TreeMap,HashMap是无序的,TreeMap是有序的

17. ArrayList和LinkedList区别♥♥

  • ArrayList是基于动态数组(动态数组实际上是新建一个新的符合要求大小的数组)的数据结构,而LinkedList是基于链表的数据结构
  • ArrayList存储元素在内存空间是连续的,而LinkedList存储元素在内存空间是不连续的
  • ArrayList适合随机访问(下标的方式),不适合插入删除操作,因为这样会移动大量的元素,而LinkedList不适合随机访问,适合插入和删除操作。

18. ArrayList扩容过程♥♥

  • 当我们创建ArrayList对象,调用空参构造方法的时候,首先初始化的数组带大小为0,第一次添加元素的时候,会将数组的长度扩充为10,当添加的元素超过10个的时候,首先会扩容到15,一次类推,每次扩容为原来长度的1.5倍,最大能扩容的长度为Integer.MAX_VALUE
  • 源码: int newCapacity = oldCapacity + (oldCapacity >> 1);

19. HashMap底层实现♥♥♥

  • 在jdk1.8之前,hashmap由数组+链表数据结构组成,在jdk1.8之后hashmap由数组+链表+红黑树数据结构组成;当我们创建hashmap对象的时候,jdk1.8之前会创建一个长度为16的Entry数组,jdk1.8以后就不是初始化对象的时候创建数组了,而是在第一次put元素的时候,首先调用hashcode方法计算出key的hash值,然后对数组长度取余,计算出向Node数组中存储数据的索引值;如果计算出的索引位置处没有数据,则直接将数据存储到数组中;如果计算出的索引位置处已经有数据了,此时会比较两个key的hash值是否相同,如果相同,底层就会调用equals方法比较两个key的内容是否相等,如果相等,就将后添加的数据的value覆盖之前的value;如果不相同,就继续向下和其他数据的keyhash值比较,如果都不相等,就划出一个节点储存数据;如果链表长度大于阈值8,并且数组长度大于64,则将链表变为红黑树。

20. HashMap扩容过程♥♥♥

  • 什么时候需要扩容
    • 当hashmap中的元素个数超过数组长度 X 加载因子时,就会进行数组扩容,默认情况下当hashmap中的元素个数超过16 X 0.75=12的时候
    • 当hashmap中的其中一个链表的对象个数如果超过了8个,此时如果数组长度还没有达到64,那么hashmap会先扩容解决,如果已经达到了64,那么这个链表会变为红黑树,节点类型又Node变为TreeNode类型。

21. HashMap中为啥用红黑树不用二叉排序树或者平衡树♥

  1. 如果使用二叉排序树,极端情况下会形成一条链,那么失去了将链表转换为树结构的意义。
  2. 在进行插入删除时,红黑树需要更少的旋转次数就可以达到自平衡,因此效率更高,但是在进行查询的时候,由于平衡二叉树的高度严格平衡,因此它的查找效率更高,基于插入删除查找效率的一个综合考虑,hashmap就采用的红黑树数据结构。

22. TreeMap底层实现

  • TreeMap底层实现是红黑树,由于红黑树是一种特殊的二叉排序树,所以默认情况下会按照key进行升序排列;由于红黑树的插入、删除、遍历时间复杂度都为O(logN),所以性能上会低于HashMap。
  • 使用场景:如果对map进行插入、删除或查找的操作更频繁,HashMap是更好的选择;如果需要对map按照key值进行有序的输出,TreeMap是更好的选择。

23. HashMap和Hashtable的区别♥

  • HashMap方法没有synchronized修饰,线程不安全,而HashTable线程安全
  • HashMap允许key和value为null,而HashTable不允许
  • HashMap的初始化容量为16,而HashTable的初始化容量为11;HashMap扩容时是当前容量翻倍,HashTable扩容时时容量翻倍-1

24. Hashtable怎么保证线程安全的♥

  • HashTable底层在只要和数据交互的方法上面都加上了synchronized关键字,来保证线程安全的。当一个线程调用该方法时,就会拿到锁对象,当其他线程也来调用此方法时,会进入阻塞状态,知道当前线程执行完该方法才会释放这把锁。

25. ConcurrentHashMap原理♥♥♥

  • concurrentHashMap主要是解决了hashMap线程不安全的问题,我主要说一下concurrentHashMap是如何保证线程安全的,在jdk1.8的时候【锁粒度就是每个元素】,底层是数组+链表+红黑树,首先根据key计算数组对应的下标,如果下标没有元素,就利用CAS来保证线程安全,如果有元素,那么采用的是synchronize同步锁的方式来保证线程安全。

26. java反射机制♥♥♥

  • 反射让我们在代码运行的时候,可以知道任意一个类有哪些属性和方法,并且能够调用任意一个类的属性和方法,这种动态获取信息以及动态调用方法或属性的功能就称为反射机制。
  • 获取Class对象有三种方式:【在运行期间,一个类只有一个Class对象产生】
    • Object类中的getClass方法
    • 类名.class
    • Class.forName(“带包名的类路径”)
  • 获取类的所有构造方法:Class对象.getDeclaredConstructors()
  • 获取类的所有成员变量:Class对象.getDeclaredFields()
  • 获取类的所有成员方法:Class对象.getDeclaredMethods()

27. 异常体系♥♥

java基础面试题_第2张图片

28. 常见的IO模型♥

java基础面试题_第3张图片
java基础面试题_第4张图片

29. 设计模式♥

java基础面试题_第5张图片
java基础面试题_第6张图片

30. 一致性hash算法♥♥

java基础面试题_第7张图片

你可能感兴趣的:(#,java基础,java,开发语言)