onjava
一、对象的概念
1.1组合与聚合:
组合和聚合都属于关联关系的一种,只是额外具有整体-部分的意义。至于是聚合还是组合,需要根据实际的业务需求来判断。可能相同超类和子类,在不同的业务场景,关联关系会发生变化。只看代码是无法区分聚合和组合的,具体是哪一种关系,只能从语义级别来区分。聚合关系中,整件不会拥有部件的生命周期,所以整件删除时,部件不会被删除。再者,多个整件可以共享同一个部件。组合关系中,整件拥有部件的生命周期,所以整件删除时,部件一定会跟着删除。而且,多个整件不可以同时共享同一个部件。这个区别可以用来区分某个关联关系到底是组合还是聚合。两个类生命周期不同步,则是聚合关系,生命周期同步就是组合关系。
1.2 如果子类只覆盖了基类的方法 这种是比较好的 是is-a的关系 可以完全用子类代替基类 但是如果子类自己实现了新的方法 那么就是is-like-a 这种不能用基类访问新添加的方法 所以不能说完全相同
四、运算符
4.1 在 Long 型和 Integer 型中这很容易实现,调用其静态的 toBinaryString() 可以得到二进制字符串
4.2 移位运算符面向的运算对象也是二进制的“位”。它们只能用于处理整数类型(基本类型的一种)。左移位运算符 <<
能将其左边的运算对象向左移动右侧指定的位数(在低位补 0)。右移位运算符 >>
则相反。右移位运算符有“正”、“负”值:若值为正,则在高位插入 0;若值为负,则在高位插入 1。Java 也添加了一种“不分正负”的右移位运算符(>>>),它使用了“零扩展”(zero extension):无论正负,都在高位插入 0。这一运算符是 C/C++ 没有的。
4.3 如果移动 char、byte 或 short,则会在移动发生之前将其提升为 int,结果为 int。仅使用右值(rvalue)的 5 个低阶位。这可以防止我们移动超过 int 范围的位数。若对一个 long 值进行处理,最后得到的结果也是 long。
五、初始化和清理
5.1 构造方法只可以在其他构造方法第一行 使用this来进行调用 并且只能调用一个
5.2 finalize()
会在垃圾回收的时候被调用 我们不应该依赖这个方法做垃圾回收 这个方法是用来处理本地方法的 比如我们本地方法使用了malloc 由于free是c++的函数 所以我们需要在
finalize里面调用本地方法去执行free 不然就可能内存泄漏。
5.3 java的堆类似与传送带分配空间,所以分配空间的效率非常高,之所以能够是这种模型是因为垃圾回收工具,它在工作时一边回收内存,一边使堆中的对象紧凑排列,这样"堆指针"就可以很容易地移动到更靠近传送带的开始处,也就尽量避免了页面错误。垃圾回收器通过重新排列对象,实现了一种高速的、有无限空间可分配的堆模型。
5.4 对于可变参数来说 如果你有一组事物,可以把它们当作列表传递,而如果你已经有了一个数组,该方法会把它们当作可变参数列表来接受。可变参数的个数可以为 0
七、复用
7.1 如果需要向上转型才考虑使用继承 其他情况使用组合 组合还可以自由变化基类引用指向的子类
7.2 final
7.2.1 一个被 static 和 final 同时修饰的属性只会占用一段不能改变的存储空间。
7.2.2 对于基本类型,final 使数值恒定不变,而对于对象引用,final 使引用恒定不变。一旦引用被初始化指向了某个对象,它就不能改为指向其他对象。但是,对象本身是可以修改的,这一限制同样适用数组,数组也是对象。
7.2.3 public 意味着可以在包外访问,static 强调只有一个,final 说明是一个常量。 在类里初始化static只会初始化一次 不加static可能初始化多次
7.2.4 final方法子类不能重写 final类无法被其他类继承(出于安全考虑)
九、多态
9.1 类的初始化顺序
9.1.1 基类构造器被调用。这个步骤被递归地重复,这样一来类层次的顶级父类会被最先构造,然后是它的派生类,以此类推,直到最底层的派生类。
9.1.2 按声明顺序初始化成员。
9.1.3 调用派生类构造器的方法体。
就是说先是基类的构造 然后是初始化成员 然后是自己的构造
十、接口
10.1 接口同样可以包含属性,这些属性被隐式指明为 static 和 final。
10.2 接口中可以有默认实现(java8) 这样之前实现接口的类还可以照常使用
10.3 接口中允许添加静态方法 (比如接口A有个方法a 还有个静态方法 传入一个A数组 循环调用a)
10.4 接口和抽象类的区别
特性 | 接口 | 抽象类 |
---|---|---|
组合 | 新类可以组合多个接口 | 只能继承单一抽象类 |
状态 | 不能包含属性(除了静态属性,不支持对象状态) | 可以包含属性,非抽象方法可能引用这些属性 |
默认方法 和 抽象方法 | 不需要在子类中实现默认方法。默认方法可以引用其他接口的方法 | 必须在子类中实现抽象方法 |
构造器 | 没有构造器 | 可以有构造器 |
可见性 | 隐式 public | 可以是 protected 或友元 |
尽可能的使用接口而不是抽象类(如果都是方法没有属性的话)
10.5 接口是可以继承接口的 也是使用extends 可以继承多个用逗号隔开
十三、函数式编程
13.1 lambda表达式可以作为接口的实现 比如 static Body bod = h -> h + " No Parens!"; 这个Body接口有一个方法 这个方法有一个入餐 返回值是个string类型
可以用任意的满足接口参数+返回值的lambda表达式给接口负值 前提是接口里只能有一个方法!!!
13.2 (a,b,c) -> a.two(b,c) == A.two(b,c) 就是如果方法是要调用a这个类里的一个方法 可以这样转换
13.3 被 Lambda 表达式引用的局部变量必须是 final
或者是等同 final
效果的。(类中的变量就不需要是final的,简单的包装类如Integer不行)
14.4 可以进行函数组合 compose代表apply之前的操作 andThen代表apply之后的操作
Function<String,Integer> f = i -> Integer.parseInt(i);
Function<Integer,String> b = i -> i+"bbb";
Function<String,Double> c = i -> Double.valueOf(1.1);
Double apply = b.compose(f).andThen(c).apply("123");
十四、Stream
14.1 boxed可以将普通类型变成包装类型得流、
14.2 Stream.generate可以将Supplier<T> 变成T类型得流
14.3 IntStream.range(a,b) 可以得到范围得int 左闭右开 如果想包含右面得要用rangeclose
14.4 Random 可以用nextInt限制最大值 也可以用ints来限制范围 int如果是1个参数 或者三个参数得第一个参数代表流得大小
14.5 可ji以n使用正则表达式将字符串分割变成流 比如 all -> Pattern.compile("[ .,?]+").splitAsStream(all) 这个方法得返回值是Stream<String> 所以会和flatmap一起使用
或者使用(line -> Arrays.stream(line.split("\\W+") 这种方式代替
14.6 IntStream.concat 可以以参数得形式组合两个流 比如IntStream.concat( rand.ints(0, 100).limit(i), IntStream.of(-1) )
14.7 流中可以装empty Stream.empty()
14.8 Optional 的map和flatmap的区别是 前者系统帮忙生成Optional对象 后者我们需要传入func进去自己生成Optional对象
14.9 可以使用forEachOrdered 保证按照原始顺序执行(只针对与并行流)
14.10 reduce方法可以把一个集合聚合起来 (T,T) -> T 两个t代表第一个和第二个参数
14.11 串行流findfirst和findany都是第一个
14.12 数字流(mapToInt这种)生成的流 可以使用average,max,min,sum这些方法