Java基础学习笔记(三)

异常

  • Exception 和 Error 有什么区别?

    在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable 类有两个重要的子类:

    • Exception :程序本身可以处理的异常,可以通过 catch 来进行捕获。Exception 又可以分为 Checked Exception (受检查异常,必须处理) 和 Unchecked Exception (不受检查异常,可以不处理)。
    • ErrorError 属于程序无法处理的错误 ,我们没办法通过 catch 来进行捕获不建议通过catch捕获 。例如 Java 虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)等 。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。
  • Throwable 类常用方法有哪些?

    • String getMessage(): 返回异常发生时的简要描述
    • String toString(): 返回异常发生时的详细信息
    • String getLocalizedMessage(): 返回异常对象的本地化信息。使用 Throwable 的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与 getMessage()返回的结果相同
    • void printStackTrace(): 在控制台上打印 Throwable 对象封装的异常信息
  • 异常使用有哪些需要注意的地方?

    • 不要把异常定义为静态变量,因为这样会导致异常栈信息错乱。每次手动抛出异常,我们都需要手动 new 一个异常对象抛出。
    • 抛出的异常信息一定要有意义。
    • 建议抛出更加具体的异常比如字符串转换为数字格式错误的时候应该抛出NumberFormatException而不是其父类IllegalArgumentException
    • 使用日志打印异常之后就不要再抛出异常了(两者不要同时存在一段代码逻辑中)。

泛型

  • 什么是泛型?有什么作用?

    Java 泛型(Generics) 是 JDK 5 中引入的一个新特性。使用泛型参数,可以增强代码的可读性以及稳定性。

    编译器可以对泛型参数进行检测,并且通过泛型参数可以指定传入的对象类型。比如 ArrayList<Person> persons = new ArrayList<Person>() 这行代码就指明了该 ArrayList 对象只能传入 Person 对象,如果传入其他类型的对象就会报错。

  • 泛型的使用方式有哪几种?

    泛型一般有三种使用方式:泛型类泛型接口泛型方法

  • 项目中哪里用到了泛型?

    • 自定义接口通用返回结果 CommonResult<T> 通过参数 T 可根据具体的返回类型动态指定结果的数据类型
    • 定义 Excel 处理类 ExcelUtil<T> 用于动态指定 Excel 导出的数据类型
    • 构建集合工具类(参考 Collections 中的 sort, binarySearch 方法)。

反射

  • 何谓反射?

    反射之所以被称为框架的灵魂,主要是因为它赋予了我们在运行时分析类以及执行类中方法的能力。通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。

  • 反射的优缺点?

    反射可以让我们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利。

    不过,反射让我们在运行时有了分析操作类的能力的同时,也增加了安全问题,比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。

  • 反射的应用场景?

    正是因为反射,你才能这么轻松地使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。另外,像 Java 中的一大利器注解的实现也用到了反射。

注解

  • 何谓注解?

    Annotation (注解) 是 Java5 开始引入的新特性,可以看作是一种特殊的注释,主要用于修饰类、方法或者变量,提供某些信息供程序在编译或者运行时使用。

    注解本质是一个继承了Annotation 的特殊接口。

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

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

    • 编译期直接扫描 :编译器在编译 Java 代码的时候扫描对应的注解并处理,比如某个方法使用@Override 注解,编译器在编译的时候就会检测当前的方法是否重写了父类对应的方法。
    • 运行期通过反射处理 :像框架中自带的注解(比如 Spring 框架的 @Value@Component)都是通过反射来进行处理的。

SPI

  • 何谓 SPI?

    SPI 即 Service Provider Interface ,字面意思就是:“服务提供者的接口”,我的理解是:专门提供给服务提供者或者扩展框架功能的开发者去使用的一个接口。

    SPI 将服务接口和具体的服务实现分离开来,将服务调用方和服务实现者解耦,能够提升程序的扩展性、可维护性。修改或者替换服务实现并不需要修改调用方。

    很多框架都使用了 Java 的 SPI 机制,比如:Spring 框架、数据库加载驱动、日志接口、以及 Dubbo 的扩展实现等等。

  • SPI 和 API 有什么区别?

    当实现方提供了接口和实现,我们可以通过调用实现方的接口从而拥有实现方给我们提供的能力,这就是 API ,这种接口和实现都是放在实现方的。

    当接口存在于调用方这边时,就是 SPI ,由接口调用方确定接口规则,然后由不同的厂商去根据这个规则对这个接口进行实现,从而提供服务。

  • SPI 的优缺点?

    通过 SPI 机制能够大大地提高接口设计的灵活性,但是 SPI 机制也存在一些缺点,比如:

    • 需要遍历加载所有的实现类,不能做到按需加载,这样效率还是相对较低的。
    • 当多个 ServiceLoader 同时 load 时,会有并发问题。

序列化和反序列化

  • 序列化和反序列化

    • 序列化: 将数据结构或对象转换成二进制字节流的过程
    • 反序列化:将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程

    下面是序列化和反序列化常见应用场景:

    • 对象在进行网络传输(比如远程方法调用 RPC 的时候)之前需要先被序列化,接收到序列化的对象之后需要再进行反序列化;
    • 将对象存储到文件之前需要进行序列化,将对象从文件中读取出来需要进行反序列化;
    • 将对象存储到数据库(如 Redis)之前需要用到序列化,将对象从缓存数据库中读取出来需要反序列化;
    • 将对象存储到内存之前需要进行序列化,从内存中读取出来之后需要进行反序列化

    序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中。

  • 如果有些字段不想进行序列化怎么办?

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

    transient 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。

    关于 transient 还有几点注意:

    • transient 只能修饰变量,不能修饰类和方法。
    • transient 修饰的变量,在反序列化后变量值将会被置成类型的默认值。例如,如果是修饰 int 类型,那么反序列后结果就是 0
    • static 变量因为不属于任何对象(Object),所以无论有没有 transient 关键字修饰,均不会被序列化。
  • 常见序列化协议有哪些?

    JDK 自带的序列化方式一般不会用 ,因为序列化效率低并且存在安全问题。比较常用的序列化协议有 Hessian、Kryo、Protobuf、ProtoStuff,这些都是基于二进制的序列化协议。

    像 JSON 和 XML 这种属于文本类序列化方式。虽然可读性比较好,但是性能较差,一般不会选择。

  • 为什么不推荐使用 JDK 自带的序列化?

    • 不支持跨语言调用 : 如果调用的是其他语言开发的服务的时候就不支持了。
    • 性能差 :相比于其他序列化框架性能更低,主要原因是序列化之后的字节数组体积较大,导致传输成本加大。
    • 存在安全问题 :序列化和反序列化本身并不存在问题。但当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码。

I/O

  • Java IO 流了解吗?

    IO 即 Input/Output,输入和输出。数据输入到计算机内存的过程即输入,反之输出到外部存储(比如数据库,文件,远程主机)的过程即输出。数据传输过程类似于水流,因此称为 IO 流。IO 流在 Java 中分为输入流和输出流,而根据数据的处理方式又分为字节流和字符流。

    Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。

    • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
    • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

语法糖

  • 什么是语法糖?

    语法糖(Syntactic sugar)

    代指的是编程语言为了方便程序员开发程序而设计的一种特殊语法,这种语法对编程语言的功能并没有影响。实现相同的功能,基于语法糖写出来的代码往往更简单简洁且更易阅读。

    Java 中最常用的语法糖主要有泛型、自动拆装箱、变长参数、枚举、内部类、增强 for 循环、try-with-resources 语法、lambda 表达式等。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值