Java基础面试重点-1

0. 符号:

@*@:记忆模糊,验证后特别标注的知识点。

@&@:容易忘记知识点。

*:重要的知识点。

1. 简述一下Java面向对象的基本特征(四个),以及你自己的应用?

  • 抽象:是将一类对象的共同特征总结出来构造类的过程。
  • 继承:基本概念解释,继承是多态的条件。
  • 封装:基本概念解释,侧重:隐藏实现细节、公开使用方式 。
  • 多态:是指不同子类对象对同一消息做出不同的响应。本质就是处理参数,多态符合里氏替换原则、接口打破单继承 。[必要条件:继承、重写、对象上转型。实现方式:接口实现、继承重写,同类重载]

应用体现:

设计原则、设计模式

2. 程序的设计原则(六原则一法则):

  • 单一职责原则:每个类都应该只有一个职责,类只关注自身的职责。
  • 开闭原则:对功能的拓展开放,对修改关闭的原则。
  • 里氏代换原则:对继承关系中子类限制的描述。父类出现的地方,子类就能出现。子类出现的地方,父类未必能出现。
  • 依赖倒置原则:尽量依赖上层的接口和抽象类,不要依赖具体实现类。
  • 接口隔离原则:单一接口,功能专一。
  • 合成/聚合复用原则:优先使用聚合或合成关系复用代码。
  • 最小知道法则:一个对象应当对其他对象有尽可能少的了解(低耦合)。

拓展点:

合成与聚合的区别(UML):合成是一种强依赖的特殊聚合,如果整体不存在了,则部分也不存在了;例如, 公司不存在,则部门也将不存在

3. Java中重写和重载的区别?

  • 说一下概念
  • Tips:
    • 重载返回值类型必须相同(@*@ )
    • 重载:参数个数与参数类型均相同的方法只能有一个。

拓展点:

构造器可以重载,但是不可以重写,因为一个类的构造器不能被继承,所以它不能被重写。

4. final、finally和finalize的理解:

  • final 修饰变量(局部变量、修饰参数列表、成员变量),不能被修改,一般修饰静态成员变量。
  • final 修饰方法,不能被重写。
  • final 修饰类,不能被继承。
  • 局部内部类中,使用的变量得是final修饰的,JDK1.8中可以省略final,但是不能产生实际上的修改。

  • finally是异常处理中的一个关键字,作用是定义一些无论异常是否出现都会执行的代码。

  • finalize():垃圾收集器在销毁对象时调用,通过重写finalize()方法,可以整理系统资源或者执行其他清理工作。

拓展点:

finally语句块中应该尽量避免使用return返回结果,它会吞掉异常信息。原因:finally语句块中的return/抛出异常的优先级最高,程序会优先返回finally语句块中的立即结束语句的结果,此时try-catch语句块中的return/抛出异常(立即结束语句)的结果无效。

5. 怎样声明一个类不会被继承,什么场景下会用?

  • final修饰的类不能有子类,大部分都是出于安全考虑。例如String类。

  • 接口不能继承一般类。

6. 接口和抽象类的区别?

  • 相同:
    • 抽象类和接口都不能被实例化。(@&@ 20230129)
  • 不同点:
    • 抽象类(abstract),接口(interface);
    • 抽象类可有部分方法的实现,接口则不可以有(JDK1.8可以);
    • 抽象类可有构造方法,接口不可以;
    • 抽象类是单继承(java中的类都是单继承),接口可以多继承接口;
    • 抽象类的属性和方法可以使用private、默认、protected、public修饰符

7. equals()和==区别?为什么重写equal要重写hashcode?

区别:

  • == 是运算符;equals是Object类的方法。
  • == 用于基本数据类型和引用类型;equals只能用于引用类型。

  • == 两端是基本数据类型,就是判断值是否相同。
  • equals在重写之后,判断两个对象的属性值是否相同。equals如果不重写,其实就是 ==

为什么重写equal要重写hashcode?

  • 首先源码注释要求:如果根据 equals(Object) 方法判断是相等的,这两个对象中的每个对象调用hashCode()的哈希值必须相等。
  • 具体原因:hashCode()生成哈希码目的,就是保证同一个类的不同对象的哈希值是不相同的。如果不重写hashCode(),会出逻辑上认为是同一个对象,但是Hash码却不相同。
  • 此外(可以不提):重写hashcCode()后,可以自定义哈希码的生成规则,可以通过对象的属性值计算出哈希码。

8. 描述一下Object类中常用的方法?

  • toString、hashCode、equals、clone(需要实现cloneable接口)、finalized(GC自救)、wait、notify、notifyAll。
  • 注意要解释每个方法的作用。

9. 代码块以及代码块和构造方法的执行顺序

代码块分类(四种):(@&@)

  • 普通代码块:类中方法的方法体。
  • 构造代码块:类中的"{}",对象每次实例化时执行一次。
  • 静态代码块:类中的"static{}",类加载的时执行一次。
  • 同步代码块:"用synchronized() {}"。

执行顺序原则:

  • 先父类,后子类。
  • 先静态,后普通。
  • 先(静态)成员变量,后(静态)代码块,最后构造方法。

10. 什么是序列化?

  • 概念:把对象转换为字节序列的过程。
  • 用途:
    • 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中。
    • 在网络上传送对象的字节序列。
  • Tips:实体类都要实现序列化接口。

某些字段不想序列化怎么办:

使用transient关键字修饰。

transient的作用是:

  • 阻止实例中那些用此关键字修饰的变量序列化。
  • transient只能修饰变量,不能修饰类和方法。

11. Java中的参数传递时传值呢?还是传引用?

概念:

值传递:是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

引用传递:是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

Java是值传递:

Java中只有值传递,没有引用传递_java编程思想中的值传递与引用传递-CSDN博客

拓展点:

使用集合或Map作为方法入参,传递给多个方法时,注意方法内部对入参的修改,影响方法计算结果

12. 说一下反射,反射会影响性能吗?

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

反射这种运行时动态的功能可以说是非常重要的,可以说无反射不框架。

反射方式实例化对象和属性赋值和调用方法肯定比直接的慢,但是程序运行的快慢原因有很多,不能主要归于反射,如果你只是偶尔调用一下反射,反射的影响可以忽略不计。

反射使用:

... ... Field f = stuClass.getDeclaredField("字段名"); //获得私有字段 Object obj = stuClass.getConstructor().newInstance(); //获得对象 f.setAccessible(true);//暴力反射,解除私有限定 f.set(obj, "18888889999"); //赋值 ... ...

13. 内部类层次结构图:

14. 当子类构造方法使用this调用其它构造方法,就不能再调用父类的无参构造方法(super())?

  • 是的,this() 和super() 都必须是子类构造方法的第一行代码。
  • 然后介绍一下:this的三个作用。super的两个作用(调用父类的构造方法、调用父类的隐藏的成员变量和方法)

  • 其实,子类的构造方法无论再怎么调用其它构造方法,最终都会调用到父类的构造方法(隐式调用)。

15. 为什么要求一个类必须显示的书写无参构造方法?

  • 方便子类继承:子类构造方法中,往往默认使用super()调用父类的无参构造方法,super()往往可以省略不写,但是父类中如果没有定义构造方法,子类中就要显示写出super()并传参数。
  • 反射创建对象,一般用无参构造方法。
  • 自定义构造方法时,程序员可能会忽略已经没有空参构造方法。

16. String、StringBuffer和StringBuilder的区别是什么?String为什么是不可变的?

可变性:

String类中使用final关键字修饰字符数组,所以不可变的。

private final char value[];

StringBuilder与StringBuffer都继承自AbstractStringBuilder类,没有用final关键字修饰字符数组,所以可变。

char[] value;

线程安全性:

  • String中的对象是不可变的,理解为常量,线程安全。
  • StringBuffer对方法加上同步锁,线程安全的。
  • StringBuilder并没有对方法加同步锁,线程不安全的。

性能:

  • String进行改变时,都会生成一个新的String对象,然后将指针指向新的String对象。
  • StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象。
  • 相同情况下使用StringBuilder相比使用StringBuffer仅能获得 10%~15%左右的性能提升,但却要冒多线程不安全的风险。

使用总结:

  • 操作少量的数据 -> String
  • 单线程操作字符串缓冲区下操作大量数据 -> StringBuilder
  • 多线程操作字符串缓冲区下操作大量数据 -> StringBuffer

扩容机制(StringBuffer StringBuilder):

  • 新容量 = 旧容量 * 2 + 2
  • 为什么要进行+2 ? 防止初识容量为0

17. 包装类缓存问题(Integer)?

    1. Integer与new Integer不会相等。
    1. 两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false。
    1. 两个都是new出来的Integer,都为false。
    1. Int和Integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比。

  • Integer i2 = 128在编译时,会Integer i2 = Integer.valueOf(128),即使用拆封箱的概念。
  • Integer 会把 -128 ~127的数组缓存在内存中,见静态内部类IntegerCache。

  • 还有哪些包装类有缓存?
    • Byte short Long Integer Character 都有缓存。

18. 简述一下自定义异常的应用场景?

  • 说自己微服务定义的异常体系。

19. Java异常层次结构图:

20. 运行时异常和一般异常(受检异常,检查型异常)的区别是什么?

  • 运行时异常(RuntimeException):程序运行过程中,可能出现的异常,默认情况下,会自动处理(即不需要try-catch语句捕获和throws声明)[运行时异常是非受检异常]。
  • 受检异常(CheckedException):除了运行时异常以外,其它Exception类及其子类都属于受检异常。这种异常需要try-catch语句捕获和throws声明,否则编译不会通过。
  • 一般来讲,如果没有特殊的要求,我们建议使用RuntimeException异常。
相关推荐
天天扭码1 分钟前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶1 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺6 分钟前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序13 分钟前
vue3 封装request请求
java·前端·typescript·vue
陈王卜31 分钟前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、31 分钟前
Spring Boot 注解
java·spring boot
java亮小白199736 分钟前
Spring循环依赖如何解决的?
java·后端·spring
飞滕人生TYF42 分钟前
java Queue 详解
java·队列
武子康1 小时前
大数据-230 离线数仓 - ODS层的构建 Hive处理 UDF 与 SerDe 处理 与 当前总结
java·大数据·数据仓库·hive·hadoop·sql·hdfs
武子康1 小时前
大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本
java·大数据·数据仓库·hive·hadoop·mysql