泛型

1、什么是泛型

泛型( generics) 是 JDK1.5 中引⼊的⼀个新特性, 允许在定义类和接口的时候使⽤类型参数,声明的类型参数在使⽤时⽤具体的类型来替换。

2、举一个泛型的例子

以 List 接口为例,我们可以将 String、 Integer 等类型直接放入 List 中, 如果不⽤泛型, 存放 String 类型要写⼀个 List 接口, 存放 Integer 要写另外⼀个 List 接口, 而泛型很好的解决了这了个问题。

3、什么是类型擦除?

虚拟机中没有泛型,只有普通类和普通方法,所有泛型类的类型参数在编译时都会被擦除,泛型类并没有自己独有的 Class 类对象

4、泛型带来的问题

重载

  • 如果两个方法的形参使用的是同一个泛型,只是泛型中具体类型不同,那它是无法通过编译的,因为在编译之后,他们的具体类型都会被擦除,所以会导致两个方法的特征签名一样

catch

  • 由于类型信息被擦除,JVM 是无法区分两个异常泛型类的,对于 JVM 来说,它们都是同一个类型的。所以无法执行与异常对应的 catch 语句。

静态变量

  • 经过类型擦除,所有的泛型类实例都关联到同一份字节码上,泛型类的所有静态变量都会变成共享的。

泛型中 K T V E?Object 等的含义

K - Key(键)
T - Type(Java 类)
V - Value(值)
E - Element (在集合中使用,因为集合中存放的是元素)
N - Number(数值类型)
? - 表示不确定的 Java 类型(无限制通配符类型)
S、U、V - 2nd、3rd、4th types
Object - 是所有类的根类,任何类的对象都可以设置给该 Object 引用变量,使用的时候可能需要类型强制转换,但是用使用了泛型 T、E 等这些标识符后,在实际用之前类型就已经确定了,不需要再进行类型强制转换。

限定通配符和非限定通配符

限定通配符 对类型进行限制,泛型中有两种限定通配符:

  • <? extends T> :表示类型的上界,即类型必须为 T 类型或者 T 子类,只能取值,不能放,因为你无法确定 T 有几个子类,所以放入任何类型都会报错
  • <? super T> :类示类型的下界,即类型必须为 T 类型或者 T 的父类,可以存放元素,但是只能存放当前类或者子类的实例

泛型类型必须用限定内的类型来进行初始化,否则会导致编译错误。

非限定通配符 表示可以用任意泛型类型来替代,类型为 <T>

List 和 List 之间的区别
  1. 在编译时编译器不会对原始类型进行类型安全检查,但是会对带参数的类型进行检查。通过使用 Object 作为类型,可以告知编译器该方法可以接受任何类型的对象,比如 String 或 Integer
  2. 你可以把任何带参数的类型传递给原始类型 List,但不能把List<String> 传递给接受 List<Object> 的方法,因为会产生编译错误。

List<?> 和 List之间的区别

List<?> 是一个未知类型的 List,而 List<Object>其实是任意类型的 List。你可以把 List<String>L ist<Integer> 赋值给 List<?> , 却不能把 List<String> 赋值给 List<Object> 。[

](http://hollischuang.gitee.io/tobetopjavaer/#/basics/java-basic/Wildcard-Character?id=%e9%99%90%e5%ae%9a%e9%80%9a%e9%85%8d%e7%ac%a6%e5%92%8c%e9%9d%9e%e9%99%90%e5%ae%9a%e9%80%9a%e9%85%8d%e7%ac%a6)

异常

1、Java中异常分为哪两种?

编译时异常
运行时异常

2、异常的处理机制有几种?

异常捕捉:try…catch…finally,异常抛出:throws。

3、如何自定义一个异常

继承一个异常类,通常是 RumtimeException 或者 Exception

4、try catch finally,try 里有 return,finally 还执行么?

执行,并且 finally 的执行早于 try 里面的 return

当 try 语句和 finally 语句中都有 return 语句时,在⽅法返回之前,finally 语句的内容将被执⾏,并且 finally 语句的返回值将会覆盖原始的返回值

  1. 不管有没有出现异常,finally 块中的代码都会执行;
  2. 当 try 和 catch 中有 return 时,finally 仍然会执行
  3. finally 中最好不要包含 return,否则程序会提前退出,返回值不是 try 或 catch 中保存的返回值。
  4. finally 正常情况下,return 后面的表达式执行完之后,会先将结果保存起来,然后执行 finally 中的代码,finally 中的代码不会影响到返回值,等 finally 的代码执行完后,return 就会将之前保存的结果返回。


5、Excption 与 Error

它们都是 Java 异常处理的重要⼦类, 各⾃都包含⼤量⼦类。均继承自 Throwable 类。

Error表⽰系统级的错误, 是 Java 运⾏环境内部错误或者硬件问题, 它是Java虚拟机抛出的。
Exception 表⽰程序需要捕捉、 需要处理的异常, 是由与程序设计的不完善⽽出现的问题, 程序必须处理的问题,主要分为两种

6、运行时异常 与 被检查异常

运行时异常

  • RuntimeException 及其子类都被称为运行时异常
  • 程序在运行期间可能会出现这种异常,即使没有「通过 throws 声明抛出它」,也「没有用 try-catch 语句捕获它」,它也会编译通过,编译器不会检查它。

被检查异常

  • Exception类本身,以及Exception的子类中除了「运行时异常」之外的其它子类都属于被检查异常
  • Java 编译器会检查它。此类异常,要么通过 throws 进行声明抛出,要么通过 try-catch 进行捕获处理,否则无法通过编译

7、throw 与 thorws 区别

两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

位置不同

  • 而 throw 用在函数内,后面跟的是异常对象。
  • throws 用在函数上,后面跟的是异常类,可以跟多个

功能不同

  • throw 会抛出具体的问题对象,执行到 throw,功能就已经结束了,会将具体的问题对象抛给调用者。
  • throws 用来声明异常,让调用者只知道该功能可能出现的问题,可以提前给出处理方式;

发生几率

  • throw 表示抛出了异常,执行 throw 则一定抛出了某种异常对象。
  • throws 表示出现异常的一种可能性,不代表一定会发生这些异常;

8、Error 与 Exception 区别?

Error 和 Exception都是 Java 错误处理机制的一部分,都继承了 Throwable 类。
Exception 表示的异常,可以通过程序来捕捉,或者优化程序来避免。
Error 表示的是系统错误,不能通过程序来进行错误处理。

IO

Java 中 IO 流分为⼏种?

按照流的流向分,可以分为输⼊流和输出流;
按照操作单元划分,可以分为字节流和字符流;
按照流的⻆⾊划,可以分为节点流和处理流。

既然有了字节流,为什么还要有字符流?

字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程⾮常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流就⼲脆提供了⼀个直接操作字符的接⼝,⽅便我们平时对字符进⾏流操作。如果⾳频⽂件、图⽚等媒体⽂件⽤字节流⽐较好,如果涉及到字符的话使⽤字符流⽐较好。

BIO、NIO、AIO 有什么区别

BIO (Blocking I/O)
同步阻塞 I/O 模式,数据的读取写⼊必须阻塞在⼀个线程内等待其完成。在活动连接数不是特别⾼(⼩于单机 1000)的情况下,这种模型是⽐较不错的,可以让每⼀个连接专注于⾃⼰的 I/O 并且编程模型简单,也不⽤过多考虑系统的过载、限流等问题。线程池本身就是⼀个天然的漏⽃,可以缓冲⼀些系统处理不了的连接或请求。但是,当⾯对⼗万甚⾄百万级连接的时候,传统的 BIO 模型是⽆能为⼒的。因此,我们需要⼀种更⾼效的 I/O 处理模型来应对更⾼的并发量。

NIO (Non-blocking/New I/O)
NIO 是⼀种同步⾮阻塞的 I/O 模型,在 Java 1.4 中引⼊了NIO 框架,对应 java.nio 包,提供了 Channel , Selector,Buffer 等抽象。NIO 中的 N 可以理解为 Non-blocking,不单纯是 New。它⽀持⾯向缓冲的,基于通道的 I/O 操作⽅法。NIO 提供了与传统 BIO 模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和ServerSocketChannel 两种不同的套接字通道实现,两种通道都⽀持阻塞和⾮阻塞两种模式。阻塞模式使⽤就像传统中的⽀持⼀样,⽐较简单,但是性能和可靠性都不好;⾮阻塞模式正好与之相反。对于低负载、低并发的应⽤程序,可以使⽤同步阻塞 I/O 来提升开发速率和更好的维护性;对于⾼负载、⾼并发的(⽹络)应⽤,应使⽤ NIO 的⾮阻塞模式来开发

AIO (Asynchronous I/O)
AIO 也就是 NIO 2。在 Java 7 中引⼊了 NIO 的改进版 NIO 2,它是异步⾮阻塞的 IO 模型。异步 IO 是基于事件和回调机制实现的,也就是应⽤操作之后会直接返回,不会堵塞在那⾥,当后台处理完成,操作系统会通知相应的线程进⾏后续的操作。AIO 是异步 IO 的缩写,虽然 NIO 在⽹络操作中,提供了⾮阻塞的⽅法,但是 NIO 的 IO ⾏为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程⾃⾏进⾏ IO 操作,IO 操作本身是同步的。查阅⽹上相关资料,我发现就⽬前来说 AIO 的应⽤还不是很⼴泛,Netty 之前也尝试使⽤过 AIO,不过⼜放弃了。