1.Java面试题—基础知识、面向对象、【容器】、泛型 & 异常 & 反射 & 注解、IO & 【设计模式】

本文目录如下:

一、Java 基础知识


1、Java基础

JDK 和 JRE 有什么区别?

  • JDK:包含 JRE,提供了 Java程序开发工具包,用于 编写编译运行 Java 代码
  • JRE:提供了 Java 的 运行环境,主要包括 Java 虚拟机Java 基础类库

Java8 相比于之前版本有哪些新的特性?

JDK各版本新特性

  • Lambda表达式
  • 方法引用
  • Stream流

2、数据类型

Java中的 基础类型 有哪些?

点击查看

基础类型有 8 种:

  • 整数类型: byte(8位), short(16位), int(32位), long(64位)
  • 浮点类型: float(32位), double(64位)
  • 逻辑类型: boolean(8位)
  • 文本类型: char(16位)

  • 一个字节(byte) => 8个二进制位 (bit–比特)
  • String 不是 基本数据类型,而是一个 类(class)

自动装箱与拆箱的作用?原理是什么?

  • 作用:自动完成 基本数据类型包装类 的转换。
  • 原理:以 Integer 为例,装箱 的时候会自动调用 Integer.valueOf() 方法

为什么 基本类型 需要 包装类?

  • 基本类型 不能在 泛型集合 中使用。
  • 基本类型 不符合 面向对象思维

Java 中如何进行 整型大数字 运算?

java的大数字运算

  • BigInteger: 整型大数字 运算。
  • BigDecimal: 浮点数大数字 运算。
  • 原理BigInteger 内部使用 int[] 数组来存储任意大小的 整型数据

针对浮点型数据运算出现的误差的问题,怎么解决 (BigDecimal)?

BigDecimal为何能解决浮点数运算时精度丢失问题

  • 使用 BigDecimal 进行 浮点型数据 运算。
  • 原理:将 浮点型数据 扩大 N倍 让它转换成 BigInteger 类型 数据,并记录 小数点位置 即可。

为什么浮点数运算的时候会 丢失精度?

计算机在表示一个数字时,宽度 是有限的,例如 无限循环的小数 在计算机中存储时,只能被 截断,所以就会导致 小数精度损失


3、String【重要】

String 为什么是不可变的?

String 内部是一个 char数组,并且被 privatefinal修饰,因此 创建后不可改变不可以继承


String、StringBuilder、StringBuffer 的区别?

点击查看

  • String 创建的是不可变的对象,每次 操作 都会生成新的 String 对象。
  • StringBufferStringBuilder 可以在原有对象的基础上进行操作
  • StringStringBuffer线程安全 的,而 StringBuilder非线程安全 的。
  • StringBuilder 的性能高于 StringBuffer

String、StringBuilder、StringBuffer 使用场景?

对于三者使用的总结:

  • String:操作 少量数据
  • StringBuilder单线程 操作 大量数据
  • StringBuffer多线程 操作 大量数据

字符串常量池 的作用了解吗?

字符串常量池JVM 针对 字符串 (String类) 专门开辟的一块区域,可以避免 重复创建字符串,从而 提升性能减少内存消耗


4、方法 & 关键字

Java中到底是 值传递 还是 引用传递?

为什么说Java中只有值传递?

Java 中是 值传递 的,只不过当参数是 对象 时,值的内容对象的地址


final 关键字有什么作用?

点击查看

  • final修饰变量: 该 变量初始化不可更改。(常量)
  • final修饰方法: 该 继承类 不能 修改 此方法。
  • final修饰: 该类 不可被继承。该类所有 成员方法 都将被 隐式修饰final 方法。

static 关键字有什么作用?

点击查看

static 修饰的东西被我们称为 类成员,它会随着 类的加载加载,比如:静态变量静态方法静态代码块

  • static修饰 变量: 即 静态变量,属于 类的变量,不依赖于任何对象就可以进行访问。仅当 类初次加载时 会被 初始化
  • static修饰 方法: 即 静态方法,属于 类的方法,不依赖于任何对象就可以进行访问。
  • static修饰 代码块: 即 静态代码块, 可以 优化程序性能类初次加载时,会执行每个 static静态代码块
  • 静态导包:采用 static 导入包后,可以直接使用 方法名 调用类的方法,就好像是该类自己的方法一样使用即可。

super() 和 this() 的区别?

super()和this() 的区别?

  • 相同之处super()this() 都必须在构造方法的第一行,且不能同时出现。
  • 查找范围不同super() 只能查找 父类,而 this() 会先查找 本类,如果找不到则会去 父类 中查找。

静态方法 和 非静态方法 之间的可调用关系是怎样的?

静态方法与非静态方法的相互调用

  • 非静态方法 可以调用 静态方法
  • 静态方法 不可以调用 非静态方法

  • 静态方法 是属于 的,在 类加载 的时候就会 分配内存
  • 非静态方法 是属于 对象 的,只有在 对象实例化 之后才存在。

二、面向对象

1、面向对象基础

如何理解面向对象编程?

Java三大特性:封装,继承与多态

面向对象编程 三大特性 – 封装继承多态

  • 封装万物皆对象,任何事物都可以在 代码 中用 表示,将事物拥有的 属性行为 隐藏起来。
  • 继承:从 父类 中派生出 子类子类 能吸收 父类 的所有 属性行为,并能扩展 新的能力
  • 多态:通过将 子类的对象 作为 父类的对象 实现 多态

面向对象 和 面向过程 的区别?

  • 面向过程:分析出 解决问题 所需要的 方法,然后一步一步 执行这些 方法
  • 面向对象:会先 抽象对象,然后用 对象执行方法 的方式解决问题。

重载 和 重写 有什么区别?

  • 重载 发生在本类,重写 发生在 父类与子类 之间;
  • 重载方法名 相同,参数列表 必须不同,返回值 可以不同。
  • 重写方法名 相同, 参数列表 必须相同。

抽象类 和 普通类 有哪些区别?

  • 抽象类 不能直接 实例化,只能被 继承
  • 抽象类 可以包含 抽象方法 (不需要实现方法体),且 继承者 必须实现 抽象方法

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

抽象类和接口有什么区别
接口中成员 (变量&方法) 的特点

  • 子类 通过 implements 实现 接口子类 通过 extends 继承 抽象类
  • 一个类可以实现多个 接口,但只能继承一个 抽象类
  • 接口 中的方法都是 抽象的抽象类 中可以 具体实现方法(非抽象)。
  • 抽象类的方法 可以用 publicprotected 修饰 。接口方法 只能用 public 修饰符。

接口 只能 继承接口,而不是 实现接口


为什么要使用克隆?

  • 克隆 会创建一个 副本对象,对 副本对象 进行操作不会影响 原来的对象
  • clone() 默认是 浅拷贝

深拷贝 和 浅拷贝 区别了解吗?什么是 引用拷贝?

点击查看

  • 浅拷贝浅拷贝 会在堆上创建一个 新的对象,但是 浅拷贝 会共用 内部对象
  • 深拷贝:深拷贝会 完全复制整个对象,包括 内部对象
    在这里插入图片描述

2、Object

Object 类的常见方法有哪些?

  • equals():用于比较 对象内存地址 是否相等。String类 中用于比较 字符串的值 是否相等。
  • hashCode():用于返回对象的 哈希码
  • wait():暂停 线程 的执行。
  • notify():唤醒一个在此对象监视器上等待的 线程
  • clone():用于 拷贝对象

== 和 equals() 的区别是什么?

点击查看

  • == 对于 基本类型 来说是 值比较,对于 对象 来说是比较的是 内存地址
  • equals() 比较的是 内存地址,但是对于 String类 来说是 值比较
    equals() 内部就是 ==,但是 String类 重写了 equals() 方法】

hashCode() 有什么用?

  • hashCode() :获取 对象哈希码
  • hashCode() 可以通过 哈希吗初步判断 对象 是否相等
    【需要通过 equal() 进一步判断 是否真的相等

3、序列化

什么是 序列化?什么情况下需要序列化?

  • 序列化:将 Java对象 转换成 字节流 的过程。
  • 反序列化:将 字节流 转换成 Java对象 的过程。

Java对象 需要 在网络上传输 或者 持久化存储 时,就需要对 Java对象 进行序列化 处理。


哪些 变量 不会被 序列化?

  • 静态变量static 关键字 修饰的 变量,不属于任何 对象,不会被 序列化
  • 瞬态变量transient 关键字 修饰的 变量,不会被 序列化

三、容器

1、容器基础

Java容器 都有哪些?

JavaSet(集合), List(列表)Map(映射) 的区别: 查看详情

  • List集合: 有序、可重复 的集合;
  • Set集合: 无序、不可重复 的集合;
  • Map集合: 键值对集合Key 不可重复,Value 可重复;
    在这里插入图片描述

Collection 和 Collections 有什么区别?

点击查看

  • Collection集合 的顶层 接口(interface)
  • Collections 类是 Java 中集合的 工具类, 包括 sort()reverse() 等方法。

2、List【重要】

数组(Array) 和 ArrayList 有何区别?

点击查看

  • 数组 容量是 固定 的; ArrayList 容量大小可 自动调整
  • 数组 可存储 基本类型对象; ArrayList 只能存储 对象
  • ArrayList 可以使用 泛型 来确保 类型安全Array 则不可以。

ArrayList 和 LinkedList 的区别是什么?

  • ArrrayList 基于 数组, 支持 随机访问
  • LinkedList 基于 双向循环链表,不支持 随机访问
  • ArrayList查询效率 很高;LinkedList插入、删除效率 很高。

项目中一般不会使用 LinkedList,一般都可以使用 ArrayList 代替 LinkedList,并且通常性能会更好!


谈一下 ArrayList扩容机制 的扩容机制?

Java–ArrayList扩容的原理

初始大小加载因子扩容倍数
ArrayList1011.5倍
Vector1012倍

ArrayList 和 Vector 的主要区别是什么?

  • 线程安全Vector线程安全 的,ArrayList 不是 线程安全 的。
  • 性能Vector 因为方法都是 同步 的,所以 效率不高

Vector、HashTable、synchronizedMap、StringBuffer 如何实现线程安全的?

Java高并发综合

  • 通过 synchronized 关键字修饰每个方法。
  • 缺点:因为方法都是 同步 的,所以 效率不高

3、Map【面试专用,日常不重要】

简介一下 HashMap?

  • HashMap 是一种基于 Map接口 实现的 哈希表 数据结构,主要用来存放 key-value 键值对

HashTable 和 ConcurrentHashMap 有什么区别?

Java–HashMap保证线程安全的方法

  • HashtableConcurrentHashMap 都是线程安全的。
  • Hashtable 使用 synchronized 修饰 get/put方法性能很差
  • ConcurrentHashMap 每次只给一个 桶 (数组项) 加锁,性能很好

HashMap 和 TreeMap 有什么区别?

HashMap,TreeMap,LinkedHashMap的区别

  • HashMap:底层是 数组 + 链表 + 红黑树,基本可以达到 常数时间 的性能。
  • TreeMap:提供了 有序的元素,底层是 红黑树,默认按 key 升序排序,也可以根据 key 进行 搜索

HashMap原理 - 说一下 HashMap 的数据结构?

HashMap原理技术知识整理

  • HashMap 底层存储结构 初始链表散列: (数组 + 链表) 的结构 (链地址法 解决 哈希冲突)。
  • 链表长度大于8数组长度大于等于64, 该链表会转为 红黑树提高查询效率

HashMap原理 - 为什么加载因子为 0.75?

目的尽量取得 提高空间利用率减少查询成本 的平衡。

  • 加载因子: 决定了 HashMap扩容阀值,如果 数组长度16,那么扩容阈值为 16 * 0.75=12,也就存储 12元素 的时候 扩容
  • 设为0.75的依据: 用 0.75 作为 加载因子,每个碰撞位置的 链表长度 超过 个概率非常低,小于 千万分之一

HasmMap 扩容时, 会重新进行重新 Hash分配,并且会遍历 Hash表 中所有的元素,是非常耗时的。在编写程序中,要尽量避免 resize.


HashMap原理 - HashMap 何时扩容?

Java–HashMap扩容的原理

HashMap 扩容的条件:

  • 初次使用 时容量为 0,会进行 扩容,设置初始容量为 16
  • 触发 加载因子,会进行 扩容
  • 链表长度大于8,且 数组长度<64,会进行 扩容

扩容 都是针对 数组长度 而言的,而不是 HashMap容量


HashMap原理 - 谈一下 HashMap 扩容的原理?

扩容的原理: 判断 旧数组容量 是否已经达到最大 (2^30)了

  • 若达到最大值,则修改 数组大小Integer的最大值 (2^31-1),以后就不会再进行扩容。
  • 若没达到,则修改 数组大小 为原来的 2倍
  • :数组是无法自动扩容的,所以HashMap 扩容的本质是创建一个 新的数组 装填元素。

HashMap原理 - 链表中结点数大于8时,会发生什么事 | 扩容 和 转换为红黑树?

Java–HashMap扩容的原理

链表深度 过大时(长度>8), 查询效率变低,需要 扩容转换为红黑树

  • 链表长度大于8,且 数组长度<64 会进行 扩容
  • 链表长度大于8,且 数组长度>=于64,会转化为 红黑树,来 提高查询效率

HashMap原理 - 红黑树 的原理了解吗?

红黑树(RB-tree)比AVL树的优势在哪?

  • 红黑树 是一种特殊的 平衡二叉树。 用 非严格的平衡增删节点 时候的 降低旋转次数,任何 不平衡 都会在 三次旋转 之内解决。
  • 红黑树 中不仅有 自旋 操作,还有 变色 操作,因此能够降低 旋转次数

四、泛型 & 异常 & 反射 & 注解

1、泛型

Java 中的泛型(两万字超全详解)

什么是泛型?

  • 泛型参数化类型,即 数据类型 被设置为 一个参数数据类型 从外部传入。
  • 泛型 可以用在 接口方法 中,分别被称为 泛型类泛型接口泛型方法

为什么要使用泛型?

泛型 提供了一种类型 安全检测机制传入参数 要和 数据类型 匹配,否则 编译器 会报错。


2、异常

常见的异常类有哪些?

常见的异常类有哪些?

  • NullPointerException空指针 异常。
  • IndexOutOfBoundsException:数组 下角标越界 异常。
  • IOException:当发生某种 IO异常 时抛出。
  • SQLException数据库 相关的异常。

Java的异常匹配机制?

Java异常匹配机制遵循以下规则:

  • 最具体匹配:JVM会寻找与抛出的异常类型 最具体的catch块。如果找到了一个完全匹配的catch块,则执行该块中的代码。如果没有找到完全匹配的catch块,JVM会继续搜索 该异常类型的父类
  • 单一匹配:一旦找到了匹配的catch块,就会执行该块中的代码,并且不会执行后续的catch块,即使它们也可能匹配。
  • finally块:finally块是可选的,但它提供了无论是否发生异常都会执行的代码块。这通常用于执行清理操作,如关闭文件、释放资源等。

Exception 和 Error 有什么区别?

Throwable 有两个直接的子类: java.lang.Errorjava.lang.Exception

  • ErrorJVM内部 的严重问题,比如 资源不足 等,无法恢复
  • Exception:通过处理 可以恢复Exception 可分 Checked ExceptionUnchecked Exception
    • Checked ExceptionIOExceptionSQLException 等。
      【这种 异常 必须在程序中 捕获 (catch)抛出 (throws)
    • Unchecked ExceptionNullPointerExceptionIndexOutOfBoundsException 等。
      处理 或者 不处理 都可以】

catch 里 return 了,finally 是否执行?

  • 无论是否 捕获异常finally 块里的语句都会被 执行
  • 当在 trycatch 中遇到 return 语句时,finally代码块 都将在 方法返回之前 被执行。

3、反射

Java反射 (通俗易懂)

谈谈 Java 中的 反射?

Java 的 反射机制 可以获取 任意对象属性方法,可以调用这些 属性方法


获取 Class类 的三种方式?

创建实例对象:Person p = new Person(),获取方式:

  • Class clazz = p.getClass();
  • Class clazz = Person.class;
  • Class clazz = Class.forName("类的全路径");最安全,性能最好

使用反射机制的场景有哪些?

  • Spring BootMyBatis 等框架中都 大量使用反射机制
  • 注解 (@) 的实现也用到了 反射机制

4、注解

什么是注解?

Annotation (注解) 可以看作是一种 特殊的注释,主要用于修饰 方法变量,提供 特定信息 供程序在 编译运行 时使用。


注解的解析方法有哪几种?

注解 只有 被解析后 才会 生效,常见的 解析方法 有两种:

  • 编译时直接扫描:编译器在 编译代码 的时候扫描对应的 注解 并处理,例如:@Override
  • 运行期通过反射处理框架中的注解 都是通过 反射 来处理的,例如:@Controller@Service

五、IO & 设计模式

1、IO

Java 中 IO 流分为几种? | 字节流 与 字符流的区别?

Java–IO–字节流与字符流的区别

两种:字节流字符流

  • 字节流8 位传输以 字节 为单位输入输出数据。
    适用场景图片音频Java 相关类InputStreamOutputStream
  • 字符流16 位传输以 字符 为单位输入输出数据。
    适用场景文本文件Java 相关类ReaderWriter

其中:

  • InputStream / Reader: 所有的 输入流 的基类。
  • OutputStream / Writer: 所有 输出流 的基类。

什么是 字节缓冲流?

  • 缓冲流:将数据加载至 缓冲区,一次性 读取/写入 多个字节,可以避免 频繁的 IO 操作
  • 字节缓冲输入流:采用 装饰器模式 来增强 InputStream 对象的功能,即 BufferedInputStream

BIO、NIO、AIO 有什么区别?

Java–BIO、NIO、AIO–区别/使用/实例

  • BIO同步阻塞 IO: 并发处理能力低
  • NIO同步非阻塞 IO: 提供 非阻塞面向缓冲基于通道 (Channel )I/O,实现了 IO多路复用
    【适用于 数目多、时间短IO操作,例如:聊天服务器
  • AIO异步非阻塞 IO

注:当 连接数较少并发程度较低 时,NIO 的性能并不一定优于 BIO


简单介绍一下 NIO?

Java NIO 核心知识总结

  • NIO 提供 非阻塞面向缓冲通道 (Channel )I/O
  • NIO 使用 少量线程 处理 多个 Channel 连接,大大提高了 并发能力

NIO核心组件

  • Buffer (缓冲区)NIO 读写数据 都是通过 缓冲区 进行操作的。读操作Channel 中的 数据 填充到 Buffer 中,写操作 相反。类似于 BIO 中的 缓冲流
  • Channel (通道)Channel 是一个 双向数据传输通道数据传输 过程由 Selector 进行控制。
  • Selector (选择器):允许 一个线程 处理 多个 ChannelSelector 是基于 事件驱动I/O 多路复用模型
    在这里插入图片描述

2、设计模式【重要】

说几个常用的设计模式?

常用的设计模式汇总,超详细!

  • 单例模式: 一个应用程序中,某个类的 实例对象 只能有一个。
  • 装饰器模式: 对已有的业务逻辑 进一步的封装,使其增加额外的功能。【依赖继承实现, 不断加料
  • 适配器模式: 把一个类的接口变换成客户端所期待的另一种接口。(创建一个中间类来解决无法调用的问题)
  • 观察者模式: 目标对象 发生变化时,会通知 观察者观察者 从而作出相应 任务

单例模式的写法?

单例模式Java实战–6种写法

饿汉式

  • 支持多线程
  • 不支持懒加载
  • 性能很高

静态内部类 (推荐)

  • 支持多线程Classloder机制 保证 实例初始化 时只有 一个线程
  • 支持懒加载
  • 性能很高
public class Singleton {
	// 内部类也是私有的
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    // 构造方法一定是 私有的
    private Singleton() {
    }
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

简单说说 静态代理 和 动态代理 (简单说说 代理模式)?

Java代理模式–静态代理与动态代理的使用 【依赖 接口 实现】

代理模式 的优点:

  • 可以隐藏 目标服务具体实现
  • 可以在不修改 目标服务代码 的情况下能够做一些 额外的增强
    在这里插入图片描述

静态代理: 代理类 在程序运行前就已经存在。【静态代理案例

  • 缺点: 需要为每个 目标服务 写一个 代理类代码复杂

动态代理: 代理类 在程序运行时 动态创建


反射的应用:动态代理?

JDK动态代理,步骤如下:

  1. 自定义 InvocationHandler 重写 invoke() 方法invoke() 方法 里调用 目标服务,并 附加一些逻辑
// 如果不附加逻辑的话,这段代码甚至可以不用任何更改
public class MyInvocationHandler implements InvocationHandler {

    private final Object target;

    public MyInvocationHandler (Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("正在执行的方法是:" + method.getName());
        Object result = method.invoke(target, args);
        return result;
    }
}
  1. 通过 Proxy.newProxyInstance() 方法 创建代理对象
    【传入什么 对象,生成的就是什么对象的 代理类
public class JdkProxyFactory {

	// 用于获取代理类的方法
	// 传入什么对象,生成的就是什么对象的 代理类
    public static Object getProxy(Object target) {
    	// 参数2: interfaces: 代理类需要实现哪些接口
    	// 参数3: InvocationHandler: 用于实现 代理类 中的 方法调用。
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new MessageInvocationHandler(target));
    }

	// 测试
    public static void main(String[] args) {
        // 生成代理类
        SmsService smsS ervice = (SmsService)JdkProxyFactory.getProxy(new SmsServiceImpl());
        // 调用代理类方法
        smsService.send("jdk动态代理");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

页川叶川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值