常见面试题

1. 面向对象

面向对象的编程语言有封装、继承、抽象、多态等4个特征。

  1. 封装:把描述一个对象的属性和行为的代码封装在一个模块中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。
  2. 抽象: 把现实生活中的对象抽象为类。分为过程抽象(属性)和数据抽象(方法)。
  3. 继承:子类继承父类的特征和行为。子类可以有父类的方法,属性(非private)。子类也可以对父类进行扩展,也可以重写父类的方法。缺点就是提高代码之间的耦合性。
  4. 多态:指同一个接口,使用不同的实例而执行不同操作方法覆盖和重载体现了多态性。

2.JDK、JRE、JVM

  • JDK:Java开发工具,JDK由JRE和Java工具等组成。
  • JRE:Java运行时环境,JRE由bin(JVM)和lib等组成。
  • JVM:Java虚拟机

3.==和equals

  • ==比较的是栈中的值,即基本数据类型比较的是值,引用类型比较的是地址值。
  • equals在Object类中也是调用==的,在没有重新equals的情况下两者是一样的。
  • 一般情况下都会重写equals方法让其比较引用类型时是比较值。
String str1 = "Hello";
String str2 = new String("Hello");
String str3 = str2;

// 因为str1的是存在堆中的常量池里,而str2是在堆中,所有两个的地址值是不相等的

str1 == str2; // false
str1 == str3; // false
str2 == str3; // true
str1.equals(str2); // true
str1.equals(str3); // true
str2.equals(str3); // true

4.fianl的作用

  • 修饰类后该类不能被继承。
  • 修饰方法后该方法不能被重写,但可以重载。
  • 修饰变量后该变量值不能被修改。
    1. 修饰全局变量
      • 如果是类变量(静态变量),必须在声明时就赋值,或者在静态代码块中赋值。
      • 如果是成员变量,必须在声明时赋值,或者在代码块中赋值,或者在构造方法中赋值。
    2. 修饰局部变量
      • 系统不会为局部变量初始化,所有修饰局部变量声明时可以不赋值,在使用时在指定值(之后的代码不可以再对变量赋值)。
    3. 修饰基本数据类型和引用类型
      • 修饰基本数据类型其数值一旦初始化便不能再改变。
      • 修饰引用类型则不能再让其指向另一个对象(地址值不能改变),但可以改变对象的值,比如修饰数值时不能使用等号修改数值对象,但可以通过下标改变数组的值。

5.为什么局部内部类和匿名内部类只能访问局部final变量

  • 外部类和内部类是同级别,在编译时内部类也会生成一个class文件,所以内部类不会随着方法的结束而消亡,但方法结束后局部变量会被销毁,这样内部类访问的局部变量就不存在了。
  • 实际上内部类在编译时会将局部变量复制一份到class文件中,为了防止复制后的值不变,就只能使用fianl修饰该变量,所以只能访问局部final变量。

6.String、StringBuffer、StringBuilder区别及使用场景

  • String是final修饰的,不可变,每次操作都会产生新的String对象。
  • StringBuffer和StringBuilder都是在原对象上操作的,不会浪费内存。
  • StringBuffer是线程安全的,方法都是synchronized修饰的,StringBuilder是线程不安全的。
  • 优先使用StringBuilder,多线程使用共享变量时使用StringBuffer。

7.重载和重写的区别

重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同。与方法返回值和访问修饰符无关。

重写:发生在父子类中,方法名和参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类,如果父类方法访问修饰符为private,则子类不能重写该方法。

8.接口和抽象类的区别

  • 抽象类可以存在普通成员函数,而接口只能存在public abstract 方法。
  • 抽象类只能继承一个,接口可以实现多个。
  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的。
  • 接口的设计目的是对类的行为进行约束,之约束行为的有无,不对如何实现进行限制,表达的是like的关系。
  • 抽象类的设计目的是代码复用,先存在子类,然后将子类共性的部分抽取出来作为抽象类,表达的是is的关系

9.List和Set的区别

  • List:有序,按对象进入的顺序保存对象,可重复,允许多个null元素对象,可以使用Iterator变量元素,也可以使用get方法获取指定元素
  • Set:无需,不可重复,最多允许一个null元素对象,只能通过Iterator获取元素。

10.hashCode和equals

hashCode()的作用是获取哈希码,返回一个int整数,哈希码的作用是确定该对象在哈希表中的位置,hashCode()定义在JDK的Object.java中,Java中任何类都包含有hashCode()函数。

  • 两个对象相等,则hashcode也一定相同。
  • 两个对象相等,对两个对象分别调用equals方法都返回true。
  • 两个对象有相同的hashcode,它们不一定是相等的。

11.HashSet如何检查重复

  • 对象加入时,HashSet会先计算对象的hashcode值来判断对象加入的位置,查看该位置是否有值,如果没有,HashSet会假设对象没有重复出现,如果有值,这时会调用equals()方法来检查两个对象是否真的相同,如果相同,HashSet就不会让其加入操作成功,如果不同,就好重新计算到集体位置,这样大大减少equal的次数,提高执行速度。

12.ArrayList和LinkedList区别

ArrayList

  • 基于动态数组,连续内存存储,适合下标访问(随机访问)。
  • 扩容机制,因为数组长度固定,超出数组长度存数据时需要新建数组,将老数组的数据拷贝到新数组,新数组长度为老数组的1.5倍。
  • 插入数据时,如果不是尾部插入,会涉及元素的复制移动,性能低下,如果使用尾插法并指定初始容量可以极大提升性能,甚至超过LindedList。

LinkedList

  • 基于链表,可以存储在分散的内存中,适合做数据插入及删除,不适合查询。
  • 遍历时尽量使用iterator而不要使用for循环,因为每次for循环体内每次通过get方法取得元素都要重新遍历,性能消耗极大。
  • 尽量不要使用indexOf等返回元素索引,并利用其进行遍历,使用indexOf对list进行了遍历,即使结果为空也会遍历整个列表。

13.HashMap和HashTable的区别?底层实现是什么?

  1. 区别:

    • HashMap方法没有synchronized修饰,线程不安全,HashTable线程安全。
    • HashMap允许key和value为null,HashTable不允许。
  2. 底层实现:数组+链表+红黑树实现

    • 插入时,计算key的hash值,二次hash然后对数组长度取模,对应得到数组下标。
    • 如果没有产生hash冲突(下标位置没有元素),则直接创建Node存入数组。
    • 如果产生hash冲突,先进行equal比较,相同则取代元素,不同则判断链表高度插入链表,链表高度到达8,并且数组长度达到64则转变为红黑树,长度低于6则将红黑树转回链表。
    • key为null,存在下标0的位置。
    • 有数组扩容机制。

14.CocurrentHashMap原理,jdk7和jdk8版本的区别

jdk7:

  • 数据结构:ReentrantLock + Segment + HashEntry,一个Segment中包含一个HashEntry数组,没有HashEntry又是一个链表结构。
  • 查找:二次hash,第一次Hash定位到Segment,第二次Hash定位到元素所在的链表头部,再使用equals对比。
  • 锁:Segment分段锁,Segment继承了ReentranLock,锁定操作的Segment,其他Segment不受影响,并发为Segment个数,可以通过构造函数指定,数组扩容不会影响其他Segment。
  • 读:get方法无需加锁,有volatile保证

jdk8:

  • 数据结构:synchronized + CAS + Node + 红黑树,Node的val和next都用volatile修饰,保证可见性。
  • 查找,替换,赋值操作都使用CAS。
  • 锁:锁链表的head节点,不影响其他元素读写,扩容时,阻塞所有的读写操作,并发扩容。
  • 读:Node的val和next使用volatile修饰,读写线程对该变量相互可见。数组用volatile修饰是为了保证扩容时被线程感知。

15.如何实现一个IOC容器

实现:

  1. 配置文件中指定需要扫描的包路径。
  2. 递归包扫描获取class文件,并添加到一个Set集合中。
  3. 遍历这个Set集合,获取类上有指定注解的类并交给IOC容器,定义一个安全的Map存储这些对象。
  4. 遍历这个IOC容器,获取到每个类的实列,判断里面需要依赖对象的类的实列,进行递归注入。

IOC的概念:

  • IoC(Inversion of Control),意为控制反转,不是什么技术,而是一种设计思想。Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制
  • 谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
  • 为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

16.什么是字节码?采用字节码的好处是什么?

  • 编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换成特定系统的机器码执行。这种供虚拟机理解的代码叫做字节码(即扩展名为.class的文件)。
  • Java语言通过字节码的方式,在一定程度上解决传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点,实现跨平台。

17.Java类加载器

JDK自带有三个类加载器:BootStrapClassLoader、ExtClassLoader、AppClassLoader

  • BootStrapClassLoader:是ExtClassLoader的父类加载器,默认负责加载%JAVA_HOME%/lib下的jar包和class文件。
  • ExtClassLoader:是AppClassLoader的父类加载器,默认负责加载%JAVA_HOME%/lib/ext下的jar包和class类。
  • AppClassLoader:是自定义加载器的父类,负责加载classpath下的类文件。系统类加载器、线程上下文加载器。
  • 自定义类加载器想要实现双亲委派除了继承ClassLoader类还要指定parent为AppClassLoader。

18.双亲委派机制

双亲委派:当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

好处

  • 主要是为了安全性,防止用户篡改Java的一些核心类。
  • 同时可以避免类的重复加载。

19.Java中的异常体系

  • Java中的所有异常都来自顶级父类Throwable。
  • Throwable下有两个子类Exception和Error。
  • Error是程序无法处理的错误,一旦出现,则程序将被迫停止运行。
  • Exception不会导致程序停止,分为两部分RuntimeException运行时异常和CheckedException检查异常。
  • RunTimeException常常发生再程序运行过程,会导致程序当前线程执行失败,CheckedException常常发生再程序编译过程中,会导致程序编译不通过。

20.GC如何判断对象可以被回收

  • 引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数器减1,计数为0时可以回收。
  • 可达性分析法:从GC Roots开始向下搜索,搜索所走过哦的路径称为引用链,当一个对象到GC Root没有任何引用链相连时,则证明此对象不可用,虚拟机就判断是可回收对象。

GC Root的对象有

  • 虚拟机栈中引用的对象。
  • 方法区中类静态属性引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中JNI引用的对象。

可达性分析算法中是需要进行至少两次标记过程的,对象被发现与GC Root没有引用链相连时,会先进行标记,然后被标记的对象进入由虚拟机自动建立的Finalizer队列中判断是否覆盖或者执行过了finalize方法,如果没有覆盖或者已经执行过finalize方法,则直接回收,否则对象被放进F-Queue队列,由一低优先级线程去执行队列中对象的finalize方法(“执行”是指虚拟机会触发这个方法,但不承诺会等待它允许结束)。执行finalize方法完毕后,GC会对F-Queue队列中的对象进行第二次小规模标记,判断是否可达,不可达则回收,可达则移出队列。

posted @ 2021-03-07 22:18  quanht  阅读(58)  评论(0)    收藏  举报