Java - 范型&序列化

  1. 对象的内存分配与构造(初始化):Java的对象不像是C++的引用,毕竟引用不空,而更像是指向堆上的结构体的指针。总是先申请了对象空间,然后才对这块内存进行构造的。Java对象总是在堆上的,而结构体(包括数组)在C++里还可能是在栈上的。Java对象的数据成员的初始化就是对其进行赋值,而C++的赋值与初始化有所区别 ---- C++的语言规范(有些编译器就)不支持直接初始化数据成员,而是用一种初始化列表的形式(现代C++提供了大括号初始化语法的统一),数据成员最好是在地化(为此,还专门重载了new操作符:new (ptr) Type)地构造,而若是赋值初始化的话,可能存在额外的数据拷贝。最后,C++中如果存在初始化列表,那么对应数据成员的列表初始化或者类内(直接赋值)初始化就不再被调用了,而Java则会按顺序依次做一遍(默认初始化为0、false和null,然后按在代码中出现的顺序执行field初始化和初始化块,最后执行构造函数体。
  2. 桥方法与重载类型:桥方法是Java在继承体系中实现协变返回类型与解决覆盖泛型方法对动态绑定的影响(被覆盖的方法使用更通用的类型,而在被覆盖的方法中调用更具体类型的方法,并用强制类型转换提供具体类型)的机制。返回值类型协变是编译器仅给自己开放的权限,实际上,JVM就是将返回值类型也作为重载因子的。
  3. 泛型
    31. 泛型类型擦除及其限制:
    311. 只能用var o = (Type<ParamType>[]) new Type<?>[10]的方式构造泛型类型的数组(不推荐)。因为擦除后的对象不具有类型信息,可以存放任意类型的元素,而泛型容器类型本身指定和记录着元素的类型,所以推荐使用泛型容器。i.e. 数组元素不具备泛型类型记录能力,泛型容器的泛型ok。
    312. 无法构造泛型参数“类型”的对象或者数组,用于构造对象的具体类型只能通过一个Class类型的参数传入,而且,我们现在有lambda表达式与函数式接口协助。
    313. 同样也无法抛出泛型类型的对象,即便它扩展自Throwable也不行;其原因也许在于捕获机制对精确到更具体的类型的追求。
    32. 通配符类型(give/take):
  4. 接口能力的扩展:Java 8和9之后,已经可以为仅作为abstract方法集合的接口添加static和private的方法了,二者分别取代了之前的util和helper的额外定义。而对于非static即instance方法,在需要新增public方法的时候,必要加default标记并提供方法定义以兼容旧的应用代码,否则,就类似于C/C++中未定义符号的情况了。比如,util类的方法Arrays.asList,如今可以用接口的静态方法List.of替换;而helper类的构造new AbstractMap.SimpleImmutableEntry也能用接口的静态方法Map.entry替换。
  5. 一个例子 ---- Comparable<>(compareTo)与Comparator<>(compare):Comparable是sort方法排序默认被排序元素实现了的接口,而Comparator是需要额外提供的。Comparator类的方法分为三类:
    51. compare,一个instance方法(abstract),Comparator作为functional interface,仅此一个抽象方法。
    52. 一些static,类似于工厂方法,可用于生成Comparator对象。
    53. 一些instance方法(default):用于Comparator对象的拼接。
  6. 对象序列化
    序列化的两种接口,一种是一个无内容的按照Java内置方式的如下图所示的序列号,另一种是具有自定义接口的




最后,想贴一张图片,是之前读书的时候给Java核心技术的作者提的bug收到的回信,虽然感觉这套书写的确实不够好,尤其是中文版本翻译更烂,但还是耐着性子基本读完了一遍这套上下册教材,英文版,GUI编程的部分跳过了。这个过程固然快乐,类似爱出风头的想法也趋势我给华为公司的Go安全编码规范提过bug和建议被采纳,当然,抛去不重要的出风头,更重要的是我喜欢这种刨根问底式的思考和提炼。就像我所喜欢的哲学那样,在问过一个为什么之后,还是要继续再问一个问什么,问完还问;这不但是快乐的,也应该是正确的吧。

posted @ 2022-08-12 02:11  joel-q  阅读(34)  评论(0编辑  收藏  举报