大数据面试题题集-java基础篇

java基础面试题分为几大模块、分别是:

  • Java 概念基础
  • Java 集合
  • Java 并发
  • Java 网络
  • Java 虚拟机

Java 概念基础

java 面向对像软件开发的优点:
  • 代码开发模块化,更易维护和修改。
  • 代码复用性强。
  • 增强代码的可靠性和灵活性。
  • 增加代码的可读性。
请说说面向对象的特征:
  • 封装
    封装,给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法来改变它内部的数据。在 Java 当中,有 4 种修饰符:default、public、private 和 protected。每一种修饰符给其他的位于同一个包或者不同包下面对象赋予了不同的访问权限。
    下面列出了使用封装的一些好处:

    • 通过隐藏对象的属性来保护对象内部的状态。
    • 提高了代码的可用性和可维护性,因为对象的行为可以被单独的改变或者是扩展。
    • 禁止对象之间的不良交互提高模块化。
  • 继承
    继承,给对象提供了从基类获取字段和方法的能力。继承提供了代码的重用行,也可以在不修改类的情况下给现存的类添加新特性。

  • 多态
    多态,是编程语言给不同的底层数据类型做相同的接口展示的一种能力。一个多态类型上的操作,可以应用到其他类型的值上面。

  • 抽象
    抽象,是把想法从具体的实例中分离出来的步骤,因此,要根据他们的功能而不是实现细节来创建类。

重载和重写的区别?
  1. 重写(override)
    • 方法名、参数、返回值相同。
    • 子类方法不能缩小父类方法的访问权限。
    • 子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
    • 存在于父类和子类之间。
    • 方法被定义为 final 不能被重写
  2. 重载(overload)
    • 参数类型、个数、顺序至少有一个不相同。
    • 不能重载只有返回值不同的方法名。
    • 存在于父类和子类、同类中。
Java 中,什么是构造方法?什么是构造方法重载?什么是拷贝构造方法?
  1. 构造方法
    当新对象被创建的时候,构造方法会被调用。每一个类都有构造方法。在程序员没有给类提供构造方法的情况下,Java 编译器会为这个类创建一个默认的构造方法。
  2. 构造方法重载
    Java 中构造方法重载和方法重载很相似。可以为一个类创建多个构造方法。每一个构造方法必须有它自己唯一的参数列表。
  3. 拷贝构造方法
    Java 不支持像 C++ 中那样的拷贝构造方法,这个不同点是因为如果你不自己写构造方法的情况下,Java 不会创建默认的拷贝构造方法。
JDK、JRE、JVM 分别是什么关系?
  1. JDK
    JDK 即为 Java 开发工具包,包含编写 Java 程序所必须的编译、运行等开发工具以及 JRE。开发工具如:
    • 用于编译 Java 程序的 javac 命令。
    • 用于启动 JVM 运行 Java 程序的 Java 命令。
    • 用于生成文档的 Javadoc 命令。
    • 用于打包的 jar 命令等等。
  2. JRE
    JRE 即为 Java 运行环境,提供了运行 Java 应用程序所必须的软件环境,包含有 Java 虚拟机(JVM)和丰富的系统类库。系统类库即为 Java 提前封装好的功能类,只需拿来直接使用即可,可以大大的提高开发效率。
  3. JVM
    JVM 即为 Java 虚拟机,提供了字节码文件(.class)的运行环境的支持
为什么 Java 被称作是“平台无关的编程语言”?

Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程。
- Java 源文件( .java))被编译成能被 Java 虚拟机执行的字节码文件( .class)文件
- Java 被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java 虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。

Java 中的几种基本数据类型是什么?各自占用多少字节?

Java 支持的数据类型包括基本数据类型和引用类型。
基本数据类型如下:

  • 整数型:byte、short、int、long
  • 字符型:char
  • 浮点类型:float、double
  • 布尔类型:boolean
  • 整数型:默认int 型,小数默认double型。float和long必须加后缀

引用声明的变量是指该变量在内存中实际存储的是一个引用地址,实体在堆中。

  • 引用类型包括类、接口、数组等。
  • 特别注意,String 是引用类型不是基本类型。
什么是值传递和引用传递?
  • 值传递,是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。
  • 引用传递,一般是对于对象型变量而言的,传递的是该对象地址的一个副本,并不是原对象本身。
是否可以在 static 环境中访问非 static 变量?

static 变量在 Java 中是属于类的,它在所有的实例中的值是一样的。当类被 Java 虚拟机载入的时候,会对 static 变量进行初始化。
如果你的代码尝试不用实例来访问非 static 的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。

char 型变量中能不能存贮一个中文汉字?为什么?
  • 在 C 语言中,char 类型占 1 个字节,而汉字占 2 个字节,所以不能存储。
  • 在 Java 语言中,char 类型占 2 个字节,而且 Java 默认采用 Unicode 编码,一个 Unicode 码是 16 位,所以一个 Unicode 码占两个字节,Java 中无论汉字还是英文字母,都是用 Unicode 编码来表示的。所以,在 Java 中,char 类型变量可以存储一个中文汉字。
String、StringBuffer、StringBuilder 的区别?

Java 平台提供了两种类型的字符串:String 和 StringBuffer/StringBuilder,它们可以储存和操作字符串。

  • String ,是只读字符串,也就意味着 String 引用的字符串内容是不能被改变的。
  • StringBuffer/StringBuilder 类,表示的字符串对象可以直接进行修改。StringBuilder 是 Java 5 中引入的,它和 StringBuffer 的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被 synchronized 修饰,因此它的效率也比 StringBuffer 要高。
    StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。 相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
什么是自动拆装箱?

自动装箱和拆箱,就是基本类型和引用类型之间的转换。Integer/Bolean valueOf()
为什么要转换?
如果你在 Java5 下进行过编程的话,你一定不会陌生这一点,你不能直接地向集合( Collection )中放入原始类型值,因为集合只接收对象。

  • 通常这种情况下你的做法是,将这些原始类型的值转换成对象,然后将这些转换的对象放入集合中。使用 Integer、Double、Boolean 等这些类,我们可以将原始类型值转换成对应的对象,但是从某些程度可能使得代码不是那么简洁精炼。
  • 为了让代码简练,Java5 引入了具有在原始类型和对象类型自动转换的装箱和拆箱机制。
  • 但是自动装箱和拆箱并非完美,在使用时需要有一些注意事项,如果没有搞明白自动装箱和拆箱,可能会引起难以察觉的 Bug 。
int 和 Integer 有什么区别?
  • int 是基本数据类型。
  • Integer 是其包装类,注意是一个类。
equals 与 == 的区别?
  • 值类型(int,char,long,boolean等)的话
    • 都是用 == 判断相等性。
  • 对象引用的话
    • == 判断引用所指的对象是否是同一个。
    • equals 方法,是 Object 的成员函数,有些类会覆盖(override) 这个方法,用于判断对象的等价性。例如 String 类,两个引用所指向的 String 都是 “abc” ,但可能出现他们实际对应的对象并不是同一个(和 JVM 实现方式有关),因此用 == 判断他们可能不相等,但用 equals 方法判断一定是相等的。
final、finally、finalize 的区别?
  1. final
    final ,是修饰符关键字。
    • 如果一个类被声明为 final ,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract 的,又被声明为 final的
    • 将变量或方法声明为 final,可以保证它们在使用中不被改变。被声明为 final 的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为 final的方法也同样只能使用,不能重写。

另外,在早期的 Java 实现版本中,会将 final 方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的 Java 版本已经不需要使用 final 方法进行这些优化了)。类中所有的 private 方法都隐式地指定为 final
2. finally
在异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。
在以下 4 种特殊情况下,finally块不会被执行:
- 在 finally 语句块中发生了异常。
- 在前面的代码中用了 System.exit() 退出程序。
- 程序所在的线程死亡。
- 关闭 CPU 。
3. finalize
finalize ,是方法名。
Java 允许使用 finalize() 方法,在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。
- 它是在 Object 类中定义的,因此所有的类都继承了它。
- 子类覆盖 finalize() 方法,以整理系统资源或者执行其他清理工作。
- finalize() 方法,是在垃圾收集器删除对象之前对这个对象调用的。

抽象类和接口有什么区别?

从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。

  • Java 提供和支持创建抽象类和接口。它们的实现有共同点,不同点在于:接口中所有的方法隐含的都是抽象的,而抽象类则可以同时包含抽象和非抽象的方法。
  • 类可以实现很多个接口,但是只能继承一个抽象类。类可以不实现抽象类和接口声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
  • 抽象类可以在不提供接口方法实现的情况下实现接口。
  • Java 接口中声明的变量默认都是 final 的。抽象类可以包含非 final 的变量
  • Java 接口中的成员函数默认是 public 的。抽象类的成员函数可以是 private、proteted 或者是 public
  • 接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含 #main(String[] args) 方法的话是可以被调用的。
继承和组合的区别在哪?
  • 继承:指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系。在 Java 中,此类关系通过关键字 extends 明确标识,在设计时一般没有争议性。
  • 组合:组合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即 has-a 的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。
    • 比如,计算机与 CPU 、公司与员工的关系等。
    • 表现在代码层面,和关联关系是一致的,只能从语义级别来区分。
      因为组合能带来比继承更好的灵活性,所以有句话叫做“组合优于继承”。
讲讲类的实例化顺序?

初始化顺序如下:

  • 父类静态变量
  • 父类静态代码块
  • 子类静态变量
  • 子类静态代码块
  • 父类非静态变量(父类实例成员变量)
  • 父类构造函数
  • 子类非静态变量(子类实例成员变量)
  • 子类构造函数
什么是 Java IO ?

Java IO 相关的类,在 java.io 包下,具体操作分成面向字节(Byte)和面向字符(Character)两种方式。如下图所示:
在这里插入图片描述

什么是 Java 序列化?

Q:你知道的任何一个框架的序列化是怎么做的?为什么这些框架不用Java原生的序列化?
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。

  • 可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。
  • 序列化是为了解决在对对象流进行读写操作时所引发的问题。

另外,我们不能将序列化局限在 Java 对象转换成二进制数组,例如说,我们将一个 Java 对象,转换成 JSON 字符串,或者 XML 字符串,这也可以理解为是序列化。

如何实现 Java 序列化?

如下的方式,就是 Java 内置的序列化方案,实际场景下,我们可以自定义序列化的方案,例如说 Google Protobuf 。
将需要被序列化的类,实现 Serializable 接口,该接口没有需要实现的方法,implements Serializable 只是为了标注该对象是可被序列化的。

  • 序列化
    • 然后,使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象
    • 接着,使用 ObjectOutputStream 对象的 #writeObject(Object obj) 方法,就可以将参数为 obj 的对象写出(即保存其状态)。
  • 反序列化
    • 要恢复的话则用输入流。
Java 序列话中,如果有些字段不想进行序列化怎么办?

对于不想进行序列化的变量,使用 transient 关键字修饰。

  • 当对象被序列化时,阻止实例中那些用此关键字修饰的的变量序列化。
  • 当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。
  • transient 只能修饰变量,不能修饰类和方法。
error 和 exception 有什么区别?CheckedException 和 RuntimeException 有什么区别?

Java 的异常体系,基于共同的祖先 java.lang.Throwable 类。如下图所示:
在这里插入图片描述

  • Error(错误),表示系统级的错误和程序不必处理的异常,是 Java 运行环境中的内部错误或者硬件问题。
    • 例如:内存资源不足等。
    • 对于这种错误,程序基本无能为力,除了退出运行外别无选择,它是由 Java 虚拟机抛出的。
  • Exception(异常),表示需要捕捉或者需要程序进行处理的异常,它处理的是因为程序设计的瑕疵而引起的问题或者在外的输入等引起的一般性问题,是程序必须处理的。Exception 又分为运行时异常,受检查异常。
    • RuntimeException(运行时异常),表示无法让程序恢复的异常,导致的原因通常是因为执行了错误的操作,建议终止逻辑,因此,编译器不检查这些异常。
    • CheckedException(受检查异常),是表示程序可以处理的异常,也即表示程序可以修复(由程序自己接受异常并且做出处理),所以称之为受检查异常。
异常的使用的注意地方?
  • 不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
  • 对可以恢复的情况使用受检异常,对编程错误使用运行时异常
  • 避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
  • 优先使用标准的异常
  • 每个方法抛出的异常都要有文档
  • 保持异常的原子性
  • 不要在catch中忽略掉捕获到的异常
Throwable 类常用方法?
  • #getMessage() 方法:返回异常发生时的详细信息。
  • #getCause() 方法:获得导致当前 Throwable 异常的 Throwable 异常。
  • #getStackTrace() 方法:获得 Throwable 对象封装的异常信息。
    • #printStackTrace() 方法:在控制台上打印。
请列出 5 个运行时异常?
  • NullPointerException
  • IndexOutOfBoundsException
  • ClassCastException
  • ArrayStoreException
  • BufferOverflowException
throw 与 throws的区别 ?
  • throw ,用于在程序中显式地抛出一个异常。
  • throws 每个方法必须显式指明哪些异常没有处理,以便该方法的调用者可以预防可能发生的异常
异常处理中 finally 语句块的重要性

不管程序是否发生了异常, finally 语句块都会被执行,甚至当没有catch 声明但抛出了一个异常时, finally 语句块也会被执行。
finally 语句块通常用于释放资源, 如 I/O 缓冲区, 数据库连接等等。

异常被处理后异常对象会发生什么?

异常对象会在下次 GC 执行时被回收。

说说反射的用途及实现?

Java 反射机制主要提供了以下功能:

  • 在运行时构造一个类的对象。
  • 判断一个类所具有的成员变量和方法。
  • 调用一个对象的方法。
  • 生成动态代理。

反射的应用很多,很多框架都有用到:

  • Spring 框架的 IoC 基于反射创建对象和设置依赖属性。
  • Spring MVC 的请求调用对应方法,也是通过反射。
  • JDBC 的 Class#forName(String className) 方法,也是使用反射。
反射中,Class.forName 和 ClassLoader 区别?

这两者,都可用来对类进行加载。差别在于:

  • Class#forName(…)方法,除了将类的 .class 文件加载到JVM 中之外,还会对类进行解释,执行类中的 static 块
  • ClassLoader 只干一件事情,就是将 .class 文件加载到 JVM 中,不会执行 static 中的内容,只有在 newInstance 才会去执行 static 块。Class#forName(name, initialize, loader) 方法,带参函数也可控制是否加载 static 块,并且只有调用了newInstance 方法采用调用构造函数,创建类的对象。
Java 对象创建的方式?
  • 使用 new 关键字创建对象。
  • 使用 Class 类的 newInstance 方法(反射机制)。
  • 使用 Constructor 类的 newInstance 方法(反射机制)。
  • 使用 clone 方法创建对象。
  • 使用(反)序列化机制创建对象。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值