> 文章列表 > 2023最新面试题-Java-2

2023最新面试题-Java-2

2023最新面试题-Java-2

基础语法

1. Java有哪些数据类型

定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同 大小的内存空间。   细化的数据类型就是占用空间的基本元素。
分类:
基本数据类型
  • 数值型
    整数类型(byte,short,int,long)
    浮点类型(float,double)
  • 字符型(char)
  • 布尔型(boolean)
引用数据类型
  • 类(class)   eg:String
  • 接口(interface)
  • 数组([])

 1-24-8-4-2-1 空间大小对称记忆

2. switch 是否能作用在 byte 上,是否能作用在 long 上,是否 能作用在 String 上

在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入 了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整 型(long)在目前所有的版 本中都是不可以的。

3. 用最有效率的方法计算 2 乘以 8

2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次 方)。
    public static void main(String[] args) {System.out.println(2<<3);}

 

4. Math.round(11.5) 等于多少?Math.round(-11.5) 等于多少

Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍 五入的原理是在参数上加 0.5 然后进行下取整。 四舍五入 >0.5统一加0.几, <0.5 统一减0.几。

5. float f=3.4;是否正确

不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于 下转型(down-casting, 也称为窄化)会造成精度损失,因此需要强制类型转 换float f =(float)3.4; 或者写成 float f =3.4F;

6. short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗

涉及Java的强制类型转换  支持向上自动转型

对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才 能赋值给 short 型。 而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其 中有隐含的强制类型转换。

7.注释

定义:用于解释说明程序的文字
分类
单行注释 格式: // 注释文字
多行注释 格式: /* 注释文字 */
文档注释 格式:/ 注释文字 */

8. 访问修饰符 public,private,protected,以及不写(默认)时的 区别

定义:Java中,可以使用访问修饰符来保护对类、变量、方法和构造方法的访 问。Java 支持 4 种不同的
访问权限。
分类:
private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部 类)
default (即缺省,什么也不写,不使用任何关键字): 在同一包内可见,不使用 任何修饰符。使用
对象:类、接口、变量、方法。
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意: 不能修饰类(外部
类)。
public : 对所有类可见。使用对象:类、接口、变量、方法

9. final 有什么用?

用于修饰类、属性和方法;
  • 被final修饰的类不可以被继承
  • 被final修饰的方法不可以被重写
  • 被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引
  • 用指向的内容是可以改变的

10. final finally finalize区别

1. final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修
饰变量表示该变量是一个常量不能被重新赋值。
2. finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法
finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代
码。
3. finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾
回收器来调用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一
个对象是否可回收的最后判断。

11. this与super的区别

  • super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函 数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
  • this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的 形参与类中的成员数据同名,这时需用this来指明成员变量名)
  • super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其 它构造方法。
  • super()和this()均需放在构造方法内第一行。
  • 尽管可以用this调用一个构造器,但却不能调用两个。
  • this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造 函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意 义,编译器也不会通过。
  • this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:
  • static变量,static方法,static语句块。
  • 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

12. static存在的主要意义

static的主要意义是在于创建独立于具体对象的域变量或者方法。以致于即使没有创建对象,也能使用属 性和调用方法!
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中 的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static 块,并且只会执行一次。为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时 候 执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

因此比较常见的static应用场景有:

1、修饰成员变量
2、修饰成员方法
3、静态代码块
4、修饰类【只能修饰内部类也就是静态内部类】
5、静态导包

static注意事项

1、静态只能访问静态。 2、非静态既可以访问非静态的,也可以访问静态的。

13. 抽象类和接口的对比

抽象类是用来捕捉子类的通用特性的。接口是抽象方法的集合。
从设计层面来说,抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。

相同点

  • 接口和抽象类都不能实例化
  • 都位于继承的顶端,用于被其他实现或继承
  • 都包含抽象方法,其子类都必须覆写这些抽象方法

 不同点

参 数
抽象类
接口
声明
抽象类使用abstract关键字声明
接口使用interface关键字声明
实现
子类使用extends关键字来继承抽象类。如果子类
不是抽象类的话,它需要提供抽象类中所有声明
的方法的实现
子类使用implements关键字来实现
接口。它需要提供接口中所有声明的
方法的实现
构
造
器
抽象类可以有构造器
接口不能有构造器
访
问
修
饰
符
抽象类中的方法可以是任意访问修饰符
接口方法默认修饰符是public。并且
不允许定义为 private 或者
protected
多
继
承
一个类最多只能继承一个抽象类
一个类可以实现多个接口
字
段
声
明
抽象类的字段声明可以是任意的
接口的字段默认都是 static 和 final
的
备注:Java8中接口中引入默认方法和静态方法,以此来减少抽象类和接口之间 的差异。

14. 抽象类能使用 final 修饰吗?

不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承, 这样彼此就会产生矛
盾,所以 final 不能修饰抽象类

15. 创建一个对象用什么关键字?对象实例与对象引用有何不同?

new关键字,new创建对象实例(对象实例在堆内存中),对象引用指向对象实 例(对象引用存放在栈 内存中)。一个对象引用可以指向0个或1个对象(一根 绳子可以不系气球,也可以系一个气球);一个 对象可以有n个引用指向它(可以 用n条绳子系住一个气球)
没有对象引用,丢失跟可达性就代表是可以回收的对象。

变量与方法

16. 成员变量与局部变量的区别有哪些

 变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上 讲,变量其实是内存中的 一小块区域

成员变量:方法外部,类内部定义的变量

局部变量:类的方法中的变量。 成员变量和局部 变量的区别。

作用域

成员变量:针对整个类有效。
局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)

存储位置

成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结 束后,就自动释放。

 生命周期

成员变量:随着对象的创建而存在,随着对象的消失而消失。
局部变量:当方法调用完,或者语句结束后,就自动释放。

初始值

成员变量:有默认初始值。
局部变量:没有默认初始值,使用前必须赋值。

使用原则

在使用变量时需要遵循的原则为:就近原则 首先在局部范围找,有就使用;接着在成员位置找。

17. 静态变量和实例变量区别

静态变量: 静态变量由于不属于任何实例对象,属于类的,所以在内存中只会 有一份,在类的加载过程 中,JVM只为静态变量分配一次内存空间。
实例变量: 每次创建对象,都会为每个对象分配成员变量内存空间,实例变量 是属于实例对象的,在内 存中,创建几次对象,就有几份成员变量。

18 静态方法和实例方法有何不同?

静态方法和实例方法的区别主要体现在两个方面:
1. 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使 用"对象名.方法名"的方式。而 实例方法只有后面这种方式。也就是说,调 用静态方法可以无需创建对象。
2. 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量 和静态方法),而不允许访 问实例成员变量和实例方法;实例方法则无此 限制

19. 内部类的分类有哪些

内部类可以分为四种:成员内部类、局部内部类、匿名内部类和静态内部类。

静态内部类

定义在类内部的静态类,就是静态内部类。
1 public class Outer {
2
3 private static int radius = 1;
4
5 static class StaticInner {
6 public void visit() {
7 System.out.println("visit outer static variable:" + radius);
8 }
9 }
10 }
静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量; 静态内部类的创建方 式,new 外部类.静态内部类(),如下:
1 Outer.StaticInner inner = new Outer.StaticInner();
2 inner.visit

成员内部类

 定义在类内部,成员位置上的非静态类,就是成员内部类。

1 public class Outer {
2
3 private static int radius = 1;
4 private int count =2;
5
6 class Inner {
7 public void visit() {
8 System.out.println("visit outer static variable:" + radius);
9 System.out.println("visit outer variable:" + count);
10 }
11 }
12 }
成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公 有。成员内部类依赖于外 部类的实例,它的创建方式外部类实例.new 内部类(),如 下:
1 Outer outer = new Outer();
2 Outer.Inner inner = outer.new Inner();
3 inner.visit();

局部内部类

 定义在方法中的内部类,就是局部内部类

1 public class Outer {
2
3 private int out_a = 1;
4 private static int STATIC_b = 2;
5
6 public void testFunctionClass(){
7 int inner_c =3;
8 class Inner {
9 private void fun(){
10 System.out.println(out_a);
11 System.out.println(STATIC_b);
12 System.out.println(inner_c);
13 }
14 }
15 Inner inner = new Inner();
16 inner.fun();
17 }
18 public static void testStaticFunctionClass(){
19 int d =3;
20 class Inner {
21 private void fun(){
22 // System.out.println(out_a); 编译错误,定义在静态方法中的局部类不可以访问外
部类的实例变量
23 System.out.println(STATIC_b);
24 System.out.println(d);
25 }
26 }
27 Inner inner = new Inner();
28 inner.fun();
29 }
30 }
定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法 中的局部类只能访问外 部类的静态变量和方法。局部内部类的创建方式,在对应 方法内,new 内部类(),如下:
1 public static void testStaticFunctionClass(){
2 class Inner {
3 }
4 Inner inner = new Inner();
5 }

匿名内部类

 匿名内部类就是没有名字的内部类,日常开发中使用的比较多。

1 public class Outer {
2
3 private void test(final int i) {
4 new Service() {
5 public void method() {
6 for (int j = 0; j < i; j++) {
7 System.out.println("匿名内部类" );
8 }
9 }
10 }.method();
11 }
12 }
13 //匿名内部类必须继承或实现一个已有的接口
14 interface Service{
15 void method();
16 }
除了没有名字,匿名内部类还有以下特点:
  • 匿名内部类必须继承一个抽象类或者实现一个接口。
  • 匿名内部类不能定义任何静态成员和静态方法。
  • 当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。
  • 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方 法。

匿名内部类创建方式: 

1 new 类/接口{
2 //匿名内部类实现部分
3 }
内部类的优点
  • 我们为什么要使用内部类呢?因为它有以下优点:
  • 一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据!
  • 内部类不为同一包的其他类所见,具有很好的封装性;
  • 内部类有效实现了“多重继承”,优化 java 单继承的缺陷。
  • 匿名内部类可以很方便的定义回调。

20. 重载(Overload)和重写(Override)的区别。重载的方法能 否根 据返回类型进行区分?

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态 性,而后者实现的是运行 时的多态性。
重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不 同、顺序不同),与方法 返回值和访问修饰符无关,即重载的方法不能根据返回 类型进行区分
重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛 出的异常小于等于父 类,访问修饰符大于等于父类(里氏代换原则);如果父类 方法访问修饰符为private则子类中就不是重 写。

21. == 和 equals 的区别是什么

 == : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同 一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)

equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况: 情况1:类没有覆盖
equals() 方法。则通过 equals() 比较该类的两个对象时, 等价于通过“==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象 的内容相等;若它们的内 容相等,则返回 true (即,认为这两个对象相等)。
举个例子:
1 public class test1 {
2 public static void main(String[] args) {
3 String a = new String("ab"); // a 为一个引用
4 String b = new String("ab"); // b为另一个引用,对象的内容一样
5 String aa = "ab"; // 放在常量池中
6 String bb = "ab"; // 从常量池中查找
7 if (aa == bb) // true
8 System.out.println("aa==bb");
9 if (a == b) // false,非同一对象
10 System.out.println("a==b");
11 if (a.equals(b)) // true
12 System.out.println("aEQb");
13 if (42 == 42.0) { // true
14 System.out.println("true");
15 }
16 }
17 }
说明:
  • String中的equals方法是被重写过的,因为object的equals方法是比较的对象的 内存地址,而 String的equals方法比较的是对象的值。
  • 当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要 创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建 一个String对象。

22. hashCode 与 equals (重要)

 HashSet如何检查重复

两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?
hashCode和equals方法的关系
面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时 必须重写hashCode方 法?
hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整 数。这个哈希码的作用是 确定该对象在哈希表中的索引位置。hashCode() 定义 在JDK的Object.java中,这就意味着Java中的任何 类都包含有hashCode()函数。
散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出 对应的“值”。这其中就利用 到了散列码!(可以快速找到所需要的对象)

为什么要有 hashCode

 我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode:

 当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对 象加入的位置,同时也 会与其他已经加入的对象的 hashcode 值作比较,如果 没有相符的hashcode,HashSet会假设对象没 有重复出现。但是如果发现有相 同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相 等的对 象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不 同的话,就会重 新散列到其他位置。。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速 度。

对象的相等与指向他们的引用相等,两者有什么不同?

  • 对象的相等 比的是内存中存放的内容是否相等。
  • 引用相等 比较的是他们指向的 内存地址是否相等。