java2面_java面经---java基础二

泛型

泛型的优点

泛型是JDK 1.5引入的新特性,那么Java之所以引入它我认为主要有三个作用

①.类型检查,它将运行时类型转换的ClassCastException通过泛型提前到编译时期。

②.避免类型强转。

③.最重要的是它可以通过泛型可以增加代码的复用性,比如我们常用的List不需要去编写IntList,DobleList等等

https://juejin.im/post/6844904155316764685 结合记忆

泛型 List 与 List 这两个的getClass是否相等

Array中可以使用泛型吗

不可以,虚拟机本身的实现就不支持泛型数组。因为数组是协变,类型擦除后就没法满足数组协变的原则。

协变是指比如说一个int类型的数组可以插入一个double类型的数值,编译能够通过,但是运行时会出错。因为数组内建了编译期和运行时的检查;但是在使用泛型时,类型信息在编译期被擦除了,运行时也就无从检查。因此,泛型将这种错误检测移入到编译期。

List 和 List 的区别

List属于原始类型,它不会进行安全类型检查,也不存在泛型类型的限制。

List泛型为Object,它会进行安全类型检查,而且受泛型的限制。

super T>和 extends T>

泛型的继承关系可以把ArrayList向上转型为List,但是不能把ArrayList向上转型为ArrayList.举一个简单例子:苹果是水果,但是装苹果的盘子不等于装水果的盘子。因此 extends T>和 super T>就是一种通配符,来描述”水果盘子“和”苹果盘子“之间发生关系。

extends T>:接受所有泛型类型为T或者T的子类,就是说这时候苹果盘子可以赋值给水果盘

不能往里存,只能往外取。因为编译器只知道容器内是Fruit或者派生类,具体什么类型不清楚,因为编译器看到Plate赋值以后,盘子里没有被标上“苹果”。而是标上一个占位符:CAP#1,来表示获取Fruit或者Fruit子类,具体是什么类不知道,所以无论想往里插Apple还是Meat还是fruit都不知道是否与CAP#1匹配,所以就都不允许。

818d940de1610fc5d46eab6872633056.png

super T>:接受所有泛型类型为T或者T的父类,就是说这时候水果盘子可以赋值给苹果盘子

可以往里存,但往外取只能放在Object对象里。

985fad20cd927b545482b613d4b23e88.png

因为下界规定了元素的最小粒度的下限,既然元素是Fruit的基类,那么往里存粒度比Fruit小的都可以了,但是往外读取的时候只有Object对象才能装。

PECS原则:频繁向外读取内容的,适合用上界Exends,经常往里插的适合下界Super

备注理解:(通配符一般用在泛型方法中,在传入前就已经准备好插值了,所以这些限制不成为编程的绊脚石)

泛型擦除

java选择泛型的实现方式叫做"类型擦除式泛型",简单来说就是Java在编译期擦除了所有的泛型信息,这样Java就不需要产生新的类型到字节码, 所有的泛型类型最终都是一种裸类型,在Java运行时根本就不存在泛型信息。比如说在编译时把ArrayList还原会ArrayList泛型类型实际上就是Object,只在元素访问,修改是自动插入一些强制类型转换和检查的指令。其实现泛型有两种方式,另外一种是叫做具现化式泛型,即平行地加一套泛型化版本的新类型。但是由于java二进制向后兼容性的特点,加入新容器的维护成本过大所以选择了泛型擦除的方式。

泛型擦除会带来2个问题,一个是继承中方法的重写问题,另一个就是类型信息擦除之后如何获取信息的问题。针对重写问题,编译器会生成一个桥方法解决,即编译器自己生成重写方法,调用重载方法。针对类型类型信息擦除之后如何获取信息的问题。因为类型信息被擦除,所以我们无法正常通过反射去获取类型,但是它会在类,字段,以及方法形参保存泛型信息,依然可以拿到。对于局部变量可以使用匿名内部类的方式,从而在在类信息中保留泛型信息。

//这个类是 HashMap 的子类,泛型参数限定为了 String 和 Integer

Map map = new HashMap() {};

Type type=map.getClass().getGenericSuperclass();

ParameterizedType parameterizedType= ParameterizedType.class.cast(type);for(Type typeArgument : parameterizedType.getActualTypeArguments()) {

System.out.println(typeArgument.getTypeName());

}/*Output

java.lang.String

java.lang.Integer*/

反射

https://zhuanlan.zhihu.com/p/137892576

异常都有几大类?运行时的空指针会抛异常吗?IO Exception异常发生需要自己去捕获

异常包括两大类运行时异常RuntimeException(受检异常)和非运行时异常CheckException(非受检异常)

运行时异常是RuntimeException类及其子类,如 NullPointerException、IndexOutOfBoundsException等, 这些异常是不检查的异常, 编译器不要求捕获,这些大都是逻辑错误,应该从逻辑上尽可能避免,可以通过编译,运行时会抛出异常

非运行时异常是Exception的子类,如IOException、SQLException等,编译器要求我们必须这些异常进行catch 处理,否则不能通过编译.

Object方法

Object()方法,构造函数

registerNatives(),当该类被加载的时候,调用该方法完成对该类中本地方法的注册。

clone()方法,创建并返回此对象的一个副本,副本对象与原对象分别占用不同的堆空间。

getClass()方法

equals()方法,判断两个对象的地址是否相等

hashcode()方法,返回该对象的哈希码

toString(),返回该对象的字符串表示,classname+@+hash码

wait(...) / notify() / notifyAll() 线程睡眠和唤醒

finalize(),该方法被定义成一个空方法,该方法只会在垃圾回收时才会执行,而对象可能是不被垃圾回收的。所以如果我们想在不再需要某对象前做一些事情,可以重写该方法。

序列化与反序列化

是什么为什么怎么用

https://www.cnblogs.com/javazhiyin/p/11841374.html

Serializable序列化接口没有任何方法或者字段,只是用于标识可序列化的语义。实现了Serializable接口的类可以被ObjectOutputStream转换为字节流,同时也可以通过ObjectInputStream再将其解析为对象。

如何不让某个成员序列化

实现Serilizable接口,在不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化

JDK新特性

https://zhuanlan.zhihu.com/p/107748332

泛型和多态的区别

多态是在继承层面上的,即根据实际运行类型来确定具体的实现,可以事先根据具体的类型编写逻辑

泛型是用来增强容器的适配器,在编译前进行检查,由于事先并不知道类型T具体的类型,所以无法写一些特定的逻辑代码

for和foreach的效率哪个高

for是使用下标(偏移量)定位的.

foreach是使用迭代器来遍历的

对于ArrayList支持随机访问的数据类型,使用for的下标访问会比foreach的迭代器遍历的方式稍快一些,因为迭代器需要计算next的地址。

而对于LinkedList只支持顺序查找的数据类型,由于它不支持随机访问,所以基于下标的访问每次都会从头查询,此时使用for就会效率非常低,而使用foreach进行高效的next地址运算效率会比for高很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值