泛型
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 之间的区别
- 在编译时编译器不会对原始类型进行类型安全检查,但是会对带参数的类型进行检查。通过使用 Object 作为类型,可以告知编译器该方法可以接受任何类型的对象,比如 String 或 Integer
- 你可以把任何带参数的类型传递给原始类型 List,但不能把
List<String>
传递给接受 List<Object>
的方法,因为会产生编译错误。
List<?> 和 List之间的区别List<?>
是一个未知类型的 List,而 List<Object>
其实是任意类型的 List。你可以把 List<String>
、 L ist<Integer>
赋值给 List<?>
, 却不能把 List<String>
赋值给 List<Object>
。[
异常
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 语句的返回值将会覆盖原始的返回值
- 不管有没有出现异常,finally 块中的代码都会执行;
- 当 try 和 catch 中有 return 时,finally 仍然会执行
- finally 中最好不要包含 return,否则程序会提前退出,返回值不是 try 或 catch 中保存的返回值。
- 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,不过⼜放弃了。
- 在编译时编译器不会对原始类型进行类型安全检查,但是会对带参数的类型进行检查。通过使用 Object 作为类型,可以告知编译器该方法可以接受任何类型的对象,比如 String 或 Integer
- 你可以把任何带参数的类型传递给原始类型 List,但不能把
List<String>
传递给接受List<Object>
的方法,因为会产生编译错误。
List<?> 和 List之间的区别List<?>
是一个未知类型的 List,而 List<Object>
其实是任意类型的 List。你可以把 List<String>
、 L ist<Integer>
赋值给 List<?>
, 却不能把 List<String>
赋值给 List<Object>
。[
异常
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 语句的返回值将会覆盖原始的返回值
- 不管有没有出现异常,finally 块中的代码都会执行;
- 当 try 和 catch 中有 return 时,finally 仍然会执行
- finally 中最好不要包含 return,否则程序会提前退出,返回值不是 try 或 catch 中保存的返回值。
- 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,不过⼜放弃了。
List<?>
是一个未知类型的 List,而 List<Object>
其实是任意类型的 List。你可以把 List<String>
、 L ist<Integer>
赋值给 List<?>
, 却不能把 List<String>
赋值给 List<Object>
。[
异常
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 语句的返回值将会覆盖原始的返回值
- 不管有没有出现异常,finally 块中的代码都会执行;
- 当 try 和 catch 中有 return 时,finally 仍然会执行
- finally 中最好不要包含 return,否则程序会提前退出,返回值不是 try 或 catch 中保存的返回值。
- 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,不过⼜放弃了。