Java面试题背诵

一、Java基础

Q1:Java语言的优点?

  • 平台无关性,摆脱硬件束缚,“一次编写,到处运行”。
  • 相对安全的内存管理和访问机制,避免大部分内存泄漏和指针越界
  • 热点代码检测和运行时编译及优化,使程序随运行时间增长获得更高性能
  • 完善的应用程序接口,支持第三方类库。

 Q2:Java如何实现平台无关?

JVM:Java编译器可生成与计算机体系结构无关的字节码指令,字节码文件不仅可以轻易地在任何机器上解释执行,还可以动态地转换成本地机器代码,转换是由JVM实现的,JVM是平台相关的,屏蔽了不同操作系统的差异。

语言规范:基本数据类型大小有明确规定,例如int永远为32位,而C/C++中可能是16位、32位,也可能是编译器开发商指定的其它大小。Java中数值类型有固定字节数,二进制数据以固定格式存储和传输,字符串采用标识的Unicode格式存储。

Q3:JDK和JRE的区别?

 JDK:Java Development Kit,开发工具包。提供了编译运行Java程序的各种工具,包括编译器、JRE及常用类库,是JAVA核心。

JRE:Java Runtime Environment,运行时环境,运行Java程序的必要环境,包括JVM、核心类库、核心配置工具。

Q4:Java按值调用还是引用调用?

 按值调用指方法接受调用者提供的值,按引用调用指方法接受调用者提供的变量地址。

Java总是按值调用,方法得到的是所有参数值的副本,传递对象时实际上方法接受的是对象引用的副本。方法不能修改基本数据类型的参数,如果传递了一个int值,改变值不会影响实参,因为改变的是值的一个副本。

可以改变对象参数的状态,但不能让对象参数引用一个新的对象。如果传递了一个int数组,改变数组的内容会影响实参,而改变这个参数的引用并不会让实参引用新的数组对象。

Q5:浅拷贝和深拷贝的区别? 

浅拷贝:只复制当前对象的基本数据类型及引用变量,没有复制引用变量指向的实际对象。修改克隆对象可能影响原对象,不安全。 

深拷贝:完全拷贝基本数据类型和引用数据类型,安全。

Q6:什么是反射? 

 在运行状态中,对于任意一个类都能知道它的所有属性和方法,对于任意一个对象都能调用它的任意方法和属性,这种动态获取信息及调用对象方法的功能称为反射。缺点是破坏了封装性以及泛型约束。反射是框架的核心,Spring大量使用反射。

 Q7:Class类的作用?如何获取一个Class对象?

 在程序运行期间,Java运行时系统为所有对象维护一个运行时类型标识,这个信息会跟踪每个对象所属的类,虚拟机利用运行时类型信息选择要执行的正确方法,保存这些信息的类就是Class,这是一个泛型类。

获取Class对象:(1)类名.class。(2)对象的getClass方法。(3)Class.forName(类的全限定名)

Q8:什么是注解?什么是元注解?

注解是一种标记,使类或接口附加额外信息,帮助编译器和JVM完成一些特定功能,例如@Override标识一个方法是重写方法。

元注解是自定义注解的注解,例如:

@Target:约束作用位置,值是ElementType枚举常量,包括METHOD方法、VARIABLE变量、TYPE类/接口、PARAMETER方法参数、CONSTRUCTORS构造方法和LOCAL_VARIABLE局部变量等。

@Rentention:约束生命周期,值是RetentionPolicy枚举常量,包括SOURCE源码、CLASS字节码和RUNTIME运行时。

@Documented:表明这个注解应该被javadoc记录。

Q9:什么是泛型,有什么作用?

泛型本质是参数化类型,解决不确定对象具体类型的问题。泛型在定义处只具备执行Object方法的能力。
泛型的好处:

(1)类型安全,放置什么出来就是什么,不存在ClassCastException 。

(2)提升可读性,编码阶段就显式知道泛型集合、泛型方法等处理的对象类型。

(3)代码重用,合并了同类型的处理代码。

Q10:泛型擦除是什么? 

泛型用于编译阶段,编译后的字节码文件不包含泛型类型信息,因为虚拟机没有泛型类型对象,所有对象都属于普通类。例如定义List<Object>List<String>,在编译后都会变成List

定义一个泛型类型,会自动提供一个对应原始类型,类型变量会被擦除。如果没有限定类型就会替换为Object,如果有限定类型就会替换为第一个限定类型,例如<T extends A & B>会使用A类替换T。 

Q11 :JDK8新特性有哪些?

Lambda表达式:允许把函数作为参数传递到方法,简化匿名内部类代码。

函数式接口:使用@FunctionalInterface标识,有且仅有一个抽象方法,可被隐式转换为Lambda表达式。

方法引用: 可以引用已有类或对象的方法和构造方法,进一步简化lambda表达式。

接口:接口可以定义default修饰的默认方法,降低了接口升级的复杂性,还可以定义静态方法。

注解:引入重复注解机制,相同注解在同地方可以声明多次。注解作用范围也进行了扩展,可作用于局部变量、泛型、方法异常等。

类型推测:加强了类型推测机制,使代码更加简洁。

Optional类:处理空指针异常,提高代码可读性。

Stream类:引入函数式编程风格,提供了很多功能,使代码更加简洁。方法包括forEach遍历、count统计个数、filter按条件过滤、limit取前n跳过前n个元素、map映射加工、concat合并stream流等。

日期:增强了日期和时间API,新的java.time包主要包含了处理日期、时间、日期/时间、时区、时刻和时钟等操作。


JavaScript:提供了一个新的JavaScript引擎,允许在JVM上允许特定JavaScript应用。

Q12:异常有哪些分类?

所有异常都是 Throwable 的子类,分为 Error 和 Exception。Error 是 Java 运行时系统的内部错误和资源耗尽错误,例如 StackOverFlowError 和 OutOfMemoryError,这种异常程序无法处理。

Exception 分为受检异常和非受检异常,受检异常需要在代码中显式处理,否则会编译出错,非受检异常是运行时异常,继承自 RuntimeException。

受检异常:① 无能为力型,如字段超长导致的 SQLException。② 力所能及型,如未授权异常 UnAuthorizedException,程序可跳转权限申请页面。常见受检异常还有 FileNotFoundException、ClassNotFoundException、IOException等。

非受检异常:① 可预测异常,例如 IndexOutOfBoundsException、NullPointerException、ClassCastException 等,这类异常应该提前处理。② 需捕捉异常,例如进行 RPC 调用时的远程服务超时,这类异常客户端必须显式处理。③ 可透出异常,指框架或系统产生的且会自行处理的异常,例如 Spring 的 NoSuchRequestHandingMethodException,Spring 会自动完成异常处理,将异常自动映射到合适的状态码。

二、数据类型 

Q1:Java有哪些基本数据类型?

数据类型内存大小默认值取值范围
byte1B(byte)0-128~127
short2B(short)0-2^15~2^15-1
int4B0-2^63~2^63-1
float4B0.0F\pm 1.7E+38
double8B0.0D\pm 1.7E+38
char

英文1B,中文UTF-8占3B.

GBK占2B

‘\u0000’'\u0000' ~ '\uFFFF'
boolean单个变量4B/数组1Bfalsetrue、false

JVM 没有 boolean 赋值的专用字节码指令,boolean f = false 就是使用 ICONST_0 即常数 0 赋值。单个 boolean 变量用 int 代替,boolean 数组会编码成 byte 数组。

Q2:自动装箱/拆箱是什么?

每个基本数据类型都对应一个包装类,除了 int 和 char 对应 Integer 和 Character 外,其余基本数据类型的包装类都是首字母大写即可。

自动装箱: 将基本数据类型包装为一个包装类对象,例如向一个泛型为 Integer 的集合添加 int 元素。

自动拆箱: 将一个包装类对象转换为一个基本数据类型,例如将一个包装类对象赋值给一个基本数据类型的变量。

比较两个包装类数值要用 equals ,而不能用 ==

Q3:String 是不可变类为什么值可以修改?

String 类和其存储数据的成员变量 value 字节数组都是 final 修饰的。对一个 String 对象的任何修改实际上都是创建一个新 String 对象,再引用该对象。只是修改 String 变量引用的对象,没有修改原 String 对象的内容。

 Q4:字符串拼接的方式有哪些?

① 直接用 + ,底层用 StringBuilder 实现。只适用小数量,如果在循环中使用 + 拼接,相当于不断创建新的 StringBuilder 对象再转换成 String 对象,效率极差。

② 使用 String 的 concat 方法,该方法中使用 Arrays.copyOf 创建一个新的字符数组 buf 并将当前字符串 value 数组的值拷贝到 buf 中,buf 长度 = 当前字符串长度 + 拼接字符串长度。之后调用 getChars 方法使用 System.arraycopy 将拼接字符串的值也拷贝到 buf 数组,最后用 buf 作为构造参数 new 一个新的 String 对象返回。效率稍高于直接使用 +

③ 使用 StringBuilder 或 StringBuffer,两者的 append 方法都继承自 AbstractStringBuilder,该方法首先使用 Arrays.copyOf 确定新的字符数组容量,再调用 getChars 方法使用 System.arraycopy 将新的值追加到数组中。StringBuilder 是 JDK5 引入的,效率高但线程不安全。StringBuffer 使用 synchronized 保证线程安全。

Q5:String a = "a" + new String("b")创建了几个对象? 

常量和常量拼接仍是常量,结果在常量池,只要有变量参与拼接结果就是变量,存在堆。

使用字面量时只创建一个常量池中的常量,使用 new 时如果常量池中没有该值就会在常量池中新创建,再在堆中创建一个对象引用常量池中常量。因此 String a = "a" + new String("b") 会创建四个对象,常量池中的 a 和 b,堆中的 b 和堆中的 ab。

 三、面向对象

Q1:谈一谈你对面向对象的理解

面向过程让计算机有步骤地顺序做一件事,是过程化思维,使用面向过程语言开发大型项目,软件复用和维护存在很大问题,模块之间耦合严重。面向对象相对面向过程更适合解决规模较大的问题,可以拆解问题复杂度,对现实事物进行抽象并映射为开发对象,更接近人的思维。

例如开门这个动作,面向过程是 open(Door door),动宾结构,door 作为操作对象的参数传入方法,方法内定义开门的具体步骤。面向对象的方式首先会定义一个类 Door,抽象出门的属性(如尺寸、颜色)和行为(如 open 和 close),主谓结构。

面向过程代码松散,强调流程化解决问题。面向对象代码强调高内聚、低耦合,先抽象模型定义共性行为,再解决实际问题。

Q2:面向对象的三大特性?

封装是对象功能内聚的表现形式,在抽象基础上决定信息是否公开及公开等级,核心问题是以什么方式暴漏哪些信息。主要任务是对属性、数据、敏感行为实现隐藏,对属性的访问和修改必须通过公共接口实现。封装使对象关系变得简单,降低了代码耦合度,方便维护。

迪米特原则就是对封装的要求,即 A 模块使用 B 模块的某接口行为,对 B 模块中除此行为外的其他信息知道得应尽可能少。不直接对 public 属性进行读取和修改而使用 getter/setter 方法是因为假设想在修改属性时进行权限控制、日志记录等操作,在直接访问属性的情况下无法实现。如果将 public 的属性和行为修改为 private 一般依赖模块都会报错,因此不知道使用哪种权限时应优先使用 private。

继承用来扩展一个类,子类可继承父类的部分属性和行为使模块具有复用性。继承是"is-a"关系,可使用里氏替换原则判断是否满足"is-a"关系,即任何父类出现的地方子类都可以出现。如果父类引用直接使用子类引用来代替且可以正确编译并执行,输出结果符合子类场景预期,那么说明两个类符合里氏替换原则。

多态以封装和继承为基础,根据运行时对象实际类型使同一行为具有不同表现形式。多态指在编译层面无法确定最终调用的方法体,在运行期由 JVM 动态绑定,调用合适的重写方法。由于重载属于静态绑定,本质上重载结果是完全不同的方法,因此多态一般专指重写。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值