java基础面试题及答案,java基础面试题(经典)
墨初 知识笔记 121阅读
维护性。

解答接口Interface和抽象类Abstract Class都是面向对象编程中的高级特性它们都不能直接实例化需要通过子类或实现类来实例化。
接口接口是一种完全抽象的类它只包含抽象方法在 Java 8 之后接口也可以包含默认方法和静态方法。一个类可以实现多个接口实现接口的类必须实现接口中的所有方法。

抽象类抽象类是一种特殊的类它可以包含抽象方法和非抽象方法。抽象方法是没有实现的方法需要子类来提供实现。一个类只能继承一个抽象类。
接口和抽象类的主要区别如下
实现接口的类需要实现接口中的所有方法而继承抽象类的子类只需要实现抽象类中的抽象方法。一个类可以实现多个接口但只能继承一个抽象类。接口中的所有方法默认都是 public 的而抽象类中的方法可以有不同的访问修饰符。总的来说接口更多地被用来定义行为即方法而抽象类既可以定义行为也可以定义状态即属性。在设计类的层次结构时我们通常会使用抽象类而在定义一组相关的行为时我们通常会使用接口。
问题 30. 什么是构造函数它与普通方法有什么区别解答构造函数是一种特殊的方法用于初始化新创建的对象。在 Java 中构造函数的名称必须与类名相同并且没有返回类型。
构造函数与普通方法的主要区别如下
名称构造函数的名称必须与类名相同而普通方法可以有任何有效的标识符作为名称。
返回类型构造函数没有返回类型而普通方法必须有返回类型。
调用方式构造函数在创建对象时自动调用无需手动调用。而普通方法需要手动调用。
用途构造函数主要用于初始化对象的状态即设置属性的初始值。而普通方法用于描述对象的行为。
例如以下是一个简单的类其中包含一个构造函数和一个普通方法
public class MyClass { private int value; // 构造函数 public MyClass(int value) { this.value value; } // 普通方法 public void displayValue() { System.out.println(Value: value); }}
在这个例子中MyClass
的构造函数接受一个参数 value
并将其赋值给对象的 value
属性。displayValue
是一个普通方法用于打印对象的 value
属性。
解答方法重载和方法重写是 Java 中两种重要的特性。
方法重载Overloading在同一个类中如果有多个方法的名称相同但参数列表不同参数的数量、类型或顺序不同那么这些方法就被称为重载方法。方法重载允许我们使用同一个方法名执行不同的操作。
方法重写Overriding在子类中如果有一个方法与父类的某个方法的名称、参数列表和返回类型都相同那么这个方法就被称为重写方法。方法重写允许我们在子类中改变父类的行为。
方法重载和方法重写的主要区别如下
应用场景方法重载发生在同一个类中方法重写发生在父类和子类之间。参数列表方法重载要求参数列表不同方法重写要求参数列表相同。返回类型方法重载对返回类型没有特殊要求方法重写要求返回类型相同或是父类方法返回类型的子类型。访问修饰符方法重载对访问修饰符没有特殊要求方法重写要求子类方法的访问级别不能低于父类方法的访问级别。总的来说方法重载是静态的它在编译时就已经确定了具体调用哪个方法而方法重写是动态的它在运行时才确定具体调用哪个方法。
问题 32. 什么是 static 关键字它有什么用途解答static
是 Java 中的一个关键字它可以用来修饰类的成员成员变量和成员方法也可以用来创建静态代码块。
static
关键字用来声明独立于对象的静态变量无论一个类实例化多少对象它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static
变量。静态方法static
关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据然后计算这些数据。静态代码块static
关键字还可以形成静态代码块以优化程序性能。static
代码块在类加载的时候就运行了而且只运行一次同时运行时机是在构造函数之前。 总的来说static
关键字主要有以下几个作用
解答在 Java 中final
是一个关键字它可以用来修饰类、方法和变量。
final
类如果一个类被声明为 final
那么它不能被继承。这意味着没有其他类可以是这个类的子类。final
类通常表示最终的、不可改变的实体例如 String
类和 Integer
类都是 final
类。
final
方法如果一个方法被声明为 final
那么它不能被子类重写。但是子类可以继承 final
方法。
final
变量如果一个变量被声明为 final
那么它的值就不能被修改它就成为了一个常量。我们必须在声明 final
变量时或在构造函数中初始化它。
final
关键字提供了一种方式可以明确表示某个实体不应该被改变。这对于创建不可变的对象和防止意外修改非常有用。
解答this
和 super
是 Java 中的两个特殊关键字它们在处理类和对象时非常有用。
this
关键字this
是一个引用变量它指向当前对象。在实例方法或构造函数中this
通常用于引用当前对象的变量或方法。当类的成员变量与局部变量重名时我们可以使用 this
来区分它们。此外this
还可以用于在一个构造函数中调用另一个构造函数。
super
关键字super
是一个引用变量它指向当前对象的父类。我们可以使用 super
来访问父类的变量和方法。当子类需要调用父类的构造函数或者需要访问父类的方法时我们可以使用 super
。此外如果子类重写了父类的方法我们也可以通过 super
来调用父类的原始方法。
总的来说this
和 super
都是用于在类的内部引用对象自身或其父类的特殊关键字。
解答内部类也称为嵌套类是定义在另一个类中的类。根据内部类的位置和特性我们可以将内部类分为四种成员内部类、静态内部类、方法内部类和匿名内部类。
内部类有以下几个主要用途
封装内部类可以访问外部类的所有成员包括私有成员因此我们可以使用内部类来隐藏复杂的实现细节提供简单的接口。
增强封装性和可读性内部类可以将相关的类组织在一起这样可以使代码更易于阅读和维护。
支持多重继承Java 不支持多重继承但我们可以使用内部类来模拟多重继承。
实现回调内部类常常用于实现回调。在 GUI 编程和多线程编程中我们经常需要在某个特定的时间点执行某个特定的任务这时我们就可以使用内部类。
总的来说内部类是一种高级特性它可以使我们的代码更加整洁、灵活和易于维护。
问题 36. 什么是匿名内部类解答匿名内部类是一种没有名字的内部类它通常用于只需要使用一次的场合。
匿名内部类通常用于以下两种类型的场合
实现接口匿名内部类可以在定义一个类的同时实现一个接口。例如我们可以在创建一个线程时使用匿名内部类来实现 Runnable 接口。
继承类匿名内部类可以在定义一个类的同时继承一个类。例如我们可以在创建一个图形界面的按钮时使用匿名内部类来继承 ActionListener 类。
匿名内部类的语法格式如下
new 父类名或接口名() { // 方法重写 Override public void method() { // 执行语句 }}
匿名内部类是一种简洁的语法它可以让我们的代码更加简洁和易于阅读。但是由于匿名内部类没有名字所以它只能在定义的地方使用不能在其他地方引用这限制了它的使用范围。
问题 37. 什么是访问修饰符解答访问修饰符是 Java 中的关键字用于设置类、方法和变量的访问权限。Java 提供了四种访问修饰符public、private、protected 和默认没有关键字也称为 package-private。
public
被 public
修饰的类、方法或变量可以在任何地方被访问。
private
被 private
修饰的类只有内部类可以声明为 private、方法或变量只能在其定义的类中被访问。
protected
被 protected
修饰的类只有内部类可以声明为 protected、方法或变量可以在同一个包中的任何类以及其他包中的子类中被访问。
默认package-private如果一个类、方法或变量没有显式声明访问修饰符那么它的访问权限就是默认的。默认访问权限允许同一个包中的类访问但不允许其他包中的类访问。
访问修饰符是面向对象编程的重要特性它们可以保护对象的状态防止外部直接访问对象的内部数据从而提高代码的安全性和可维护性。
2.2、Java异常相关 问题 38. 简述 Java 中的异常机制以及 Excption 与 Error 区别解答Java 中的异常机制是一种用于处理程序运行时可能出现的错误情况的机制。在 Java 中异常是通过使用 try
、catch
和 finally
关键字以及 throw
和 throws
语句来处理的。
当在代码中发生异常时会创建一个异常对象这个对象包含了关于异常的详细信息例如异常类型和发生异常的地方。然后这个异常对象会被抛出运行时系统会寻找合适的代码来处理这个异常。
Java 的异常可以分为两大类Exception
和 Error
。
Exception
这是程序可以处理的异常。它分为两种类型检查型异常Checked Exception和运行时异常Runtime Exception。检查型异常是指编译器要求我们必须处理的异常例如 IOException
。运行时异常是编译器不要求我们处理的异常例如 NullPointerException
。
Error
这是程序通常无法处理的严重问题如 OutOfMemoryError
。这些问题在通常的情况下程序无法恢复和处理。
总的来说Java 的异常处理机制提供了一种结构化和易于管理的方式用于处理程序运行时的错误情况。
问题 39. Java 中的异常有哪些种类解答Java 中的异常主要分为两大类Checked Exception
和 Unchecked Exception
。
Checked Exception
这种类型的异常在编译时期就会被检查也就是说如果在代码中可能抛出的异常没有被捕获或者抛出那么编译器将会报错。这种类型的异常通常是由外部错误引起的比如文件不存在FileNotFoundException
、网络连接失败IOException
等这些异常都需要程序员显式地进行处理否则程序无法编译通过。
Unchecked Exception
这种类型的异常在编译时期不会被检查也就是说即使代码中可能抛出的异常没有被捕获或者抛出编译器也不会报错。Unchecked Exception
又可以分为两种Runtime Exception
和 Error
。
Runtime Exception
这种异常通常是由程序逻辑错误引起的比如空指针访问NullPointerException
、下标越界IndexOutOfBoundsException
等这些异常是可以通过改进程序来避免的。
Error
这种异常通常是由严重的系统错误或者虚拟机错误引起的比如内存溢出OutOfMemoryError
、栈溢出StackOverflowError
等这些异常是程序无法处理的。
总的来说Java 中的异常种类繁多不同种类的异常需要采取不同的处理方式理解这些异常的特性和分类对于编写健壮的代码非常重要。
问题 40. 请解释一下 Java 的异常层次结构解答Java 的异常层次结构主要由 java.lang.Throwable
类及其子类构成。Throwable
类是所有异常和错误的超类。它有两个主要的子类Error
和 Exception
。
Error
Error
类及其子类表示 Java 运行时系统的内部错误和资源耗尽错误。应用程序通常不会抛出这类异常也不会去尝试捕获它。例如OutOfMemoryError
、StackOverflowError
等。
Exception
Exception
类及其子类表示程序可能会遇到的问题需要程序员进行处理。Exception
又可以分为两类Checked Exception
和 Unchecked Exception
。
Checked Exception
这些异常在编译时会被检查必须被显式捕获或者抛出。例如IOException
、SQLException
等。
Unchecked Exception
这些异常在编译时不会被检查不需要显式捕获或者抛出。Unchecked Exception
主要包括 RuntimeException
及其子类例如NullPointerException
、IndexOutOfBoundsException
等。
这种层次结构使得我们可以通过捕获异常的超类来捕获一类异常也可以通过捕获具体的异常类来精确处理某个异常。
问题 41. 简述 Java 中 Thow 与 Thorws 区别解答throw
和 throws
是 Java 中用于处理异常的两个关键字它们的用途和使用方式有所不同。
throw
throw
关键字用于在代码中显式地抛出一个异常。我们可以使用 throw
关键字抛出一个具体的异常对象这个异常对象必须是 Throwable
类或其子类的实例。throw
语句后面必须立即跟着一个异常对象。
throw new Exception(This is an exception);
throws
throws
关键字用于声明一个方法可能会抛出的异常。在方法签名的末尾使用 throws
关键字后面跟着可能会抛出的异常类型。一个方法可以声明抛出多种类型的异常多个异常类型之间用逗号分隔。
public void readFile() throws IOException, FileNotFoundException { // method body}
总的来说throw
是在代码中抛出一个具体的异常而 throws
是在声明一个方法时指明该方法可能会抛出的异常类型。
解答在 Java 中我们可以通过继承 Exception
类或其子类来自定义异常。以下是创建自定义异常的基本步骤
创建一个新的类其名称通常以 “Exception” 结尾以表明这是一个异常类。
让这个类继承 Exception
类或其子类。如果这个异常需要被显式捕获那么应该继承 Exception
类如果这个异常是运行时异常那么应该继承 RuntimeException
类。
提供类的构造函数。至少应该提供两个构造函数一个无参数的构造函数和一个带有 String
参数的构造函数这个 String
参数表示异常的详细信息。
以下是一个自定义异常的例子
public class MyException extends Exception { public MyException() { super(); } public MyException(String message) { super(message); }}
在这个例子中我们创建了一个名为 MyException
的自定义异常类它继承了 Exception
类并提供了两个构造函数。当我们需要抛出这个异常时可以使用 throw
关键字如throw new MyException(This is my exception);
。
解答try
、catch
和 finally
是 Java 中用于处理异常的关键字。
try
try
块用于包含可能会抛出异常的代码。如果 try
块中的代码抛出了异常那么 try
块后面的代码将不会被执行程序会立即跳转到对应的 catch
块。
catch
catch
块用于捕获和处理异常。每个 try
块后面可以跟随一个或多个 catch
块。如果 try
块中的代码抛出了异常那么程序会查找第一个能处理这种类型异常的 catch
块然后执行这个 catch
块中的代码。
finally
finally
块包含的代码总是会被执行无论 try
块中是否抛出了异常无论 catch
块是否执行。finally
块通常用于放置清理代码比如关闭文件、释放资源等。
解答如果 try
块中有 return
语句那么 finally
块的代码仍然会被执行。这是因为 finally
块的代码总是在 try
或 catch
块中的 return
语句之前执行。但是如果 finally
块中也有 return
语句那么这个 return
语句会覆盖 try
或 catch
块中的 return
语句方法会返回 finally
块中的 return
语句的值。
解答反射是 Java 提供的一种强大的工具它允许运行中的 Java 程序对自身进行自我检查并且可以操作类、方法、属性等元素。反射机制主要提供了以下功能
在运行时判断任意一个对象所属的类在运行时构造任意一个类的对象在运行时判断任意一个类所具有的成员变量和方法在运行时调用任意一个对象的方法生成动态代理。反射的主要用途
开发通用框架许多大型框架如 Spring、MyBatis 等的底层都会用到反射它们通过反射去创建对象调用方法这样框架使用者就只需要进行简单的配置而不需要关心底层的复杂实现。
开发工具类例如我们可以通过反射编写一个通用的 toString 工具方法用于生成任意对象的字符串表示。
实现动态代理Java 的动态代理机制就是通过反射实现的它可以在运行时动态地创建一个接口的实现类。
虽然反射非常强大但是反射操作会比非反射操作慢很多所以我们应该在必要的时候才使用反射。
问题 46. Java 中反射的实现原理是什么Java 的反射机制是基于 Java 虚拟机JVM中的类信息Class Information实现的。
在 Java 中当一个类被加载到 JVM 中时JVM 会为这个类生成一个 Class
对象。这个 Class
对象包含了类的所有信息包括类的名称、包、父类、接口、构造器、方法、字段等。这些信息在类被加载时从类的字节码文件中提取出来并保存在 Class
对象中。
当我们使用反射去获取一个类的信息或操作一个类时实际上是通过操作这个类对应的 Class
对象来实现的。例如我们可以通过 Class
对象的 getMethod
方法获取类的方法通过 newInstance
方法创建类的实例通过 getField
方法获取类的字段等。
因此Java 的反射机制的实现原理就是通过操作 Class
对象来操作类的信息。这也是为什么我们在使用反射时首先需要获取类的 Class
对象。
解答Java 反射的实现主要涉及 java.lang
和 java.lang.reflect
这两个包中的类。以下是一些主要的类及其作用
java.lang.Class
这是反射的核心类它代表了正在运行的 Java 应用程序中的类和接口。我们可以通过 Class
对象获取类的名称、父类、接口、构造器、方法、字段等信息也可以通过 Class
对象创建类的实例。
java.lang.reflect.Constructor
这个类代表类的构造器。我们可以通过 Constructor
对象获取构造器的参数类型也可以通过 Constructor
对象创建类的实例。
java.lang.reflect.Method
这个类代表类的方法。我们可以通过 Method
对象获取方法的名称、返回类型、参数类型等信息也可以通过 Method
对象调用方法。
java.lang.reflect.Field
这个类代表类的字段。我们可以通过 Field
对象获取字段的名称、类型、修饰符等信息也可以通过 Field
对象获取和设置字段的值。
java.lang.reflect.Modifier
这个类代表类、方法、字段的修饰符。我们可以通过 Modifier
类获取修饰符的字符串表示也可以判断修饰符是否包含某个关键字如 public
、static
等。
以上这些类提供了丰富的方法使得我们可以通过反射获取和操作类的几乎所有信息。
问题 48. 如何通过反射创建对象解答在 Java 中我们可以通过 Class
类的 newInstance
方法或 Constructor
类的 newInstance
方法来通过反射创建对象。
以下是两种方法的示例
使用Class
类的 newInstance
方法 try { Class<?> cls Class.forName(java.lang.String); String str (String) cls.newInstance();} catch (Exception e) { e.printStackTrace();}
在这个例子中我们首先通过 Class.forName
方法获取了 String
类的 Class
对象然后通过 Class
对象的 newInstance
方法创建了 String
类的实例。
Constructor
类的 newInstance
方法 try { Class<?> cls Class.forName(java.lang.String); Constructor<?> constructor cls.getConstructor(String.class); String str (String) constructor.newInstance(Hello, World!);} catch (Exception e) { e.printStackTrace();}
在这个例子中我们首先获取了 String
类的 Class
对象然后通过 Class
对象的 getConstructor
方法获取了 String
类的构造器最后通过 Constructor
对象的 newInstance
方法创建了 String
类的实例。
需要注意的是这两种方法都可能抛出异常所以我们需要捕获或抛出这些异常。
问题 49. 简述 Java 反射创建对象和 new 创建对象的区别解答Java 反射创建对象和使用 new
关键字创建对象都可以用来实例化类但是它们之间存在一些重要的区别
创建对象的方式不同
使用new
关键字创建对象时我们在编译时就知道要创建的类的类型。使用反射创建对象时我们在编译时不需要知道要创建的类的类型可以在运行时动态地创建任何类的对象。 性能差异
使用new
关键字创建对象的性能要比使用反射创建对象的性能高。这是因为反射操作需要在运行时解析类的信息这会消耗更多的 CPU 和内存资源。 安全性差异
使用new
关键字创建对象时我们可以直接访问类的公有成员但不能访问类的私有成员。使用反射创建对象时我们可以访问类的公有成员也可以通过一些特殊的操作访问类的私有成员。这提供了更大的灵活性但也可能带来安全问题。 应用场景不同
在大多数情况下我们都会使用new
关键字创建对象因为这样更简单、更高效。反射主要用于开发框架、工具类或需要动态创建对象的场景例如实现依赖注入、动态代理等。 问题 50. 介绍一下 Spring 中使用 Java 反射的原理 解答Spring 框架广泛地使用了 Java 的反射机制主要用于以下几个方面
依赖注入Spring 通过读取配置文件或注解获取到 Bean 的全类名然后通过反射机制实例化对象并通过反射设置对象的属性或调用方法实现依赖注入。
事件监听Spring 的事件监听机制也是基于反射实现的。当事件发生时Spring 会通过反射调用监听器的处理方法。
AOPSpring 的 AOP面向切面编程也是基于反射实现的。Spring 通过反射创建代理对象并通过反射调用目标方法和切面方法。
数据绑定Spring MVC 在处理请求时会根据请求参数名和 Bean 属性名进行匹配然后通过反射设置 Bean 的属性值实现数据绑定。
Bean 的生命周期管理Spring 通过反射调用 Bean 的初始化方法和销毁方法管理 Bean 的生命周期。
Spring 通过反射使得我们只需要进行简单的配置就可以实现复杂的功能大大提高了开发效率。