《码出高效》Chapter2面向对象-读书笔记
先看个面向对象的程序。下面代码,执行test方法,结果是什么?
class Parent{ void f1(){ f2(); } private void f2() { System.out.println("parent"); } } class Child extends Parent{ public void f2() { System.out.println("child"); } } @Test public void test(){ Child child=new Child(); child.f1(); }
然后,我们将 Parent#f2 的可访问性 改为 protect 或 public, 执行test方法,结果又是什么?
(答案见文末)
下面是正文↓
《码出高效Java开发手册》第2章 面向对象
面向对象的抽象、封装、继承、多态的理念,使企业应用大规模化成为可能,有效地降低了软件开发成本、维护成本和复用成本。OOP实践了软件工程的三个主要目标:可维护性、可重用性和可扩展性。
OOP理念 |
抽象 封装 继承 多态 |
抽象是程序员的核心素质之一,体现在对业务的建模能力,以及对架构的宏观掌控力。 抽象是OO思想最基础的能力,正确而严谨的业务抽象和建模分析能力,是后续的封装、继承、多态的基础。在OO的思维中,抽象分为归纳(具体到本质,个性到共性)和演绎(与归纳相反)。 封装,遵从迪米特法则。 继承:LSP。不当继承会出现方法污染和方法爆炸。所以,提倡组合优先原则来扩展类的能力(优先采用组合/聚合的关系来复用其他类的能力---OOD7大设计原则之一:合成复用原则(Composite Reuse Principe-CRP) / 组合优先于继承原则 / 多组合少继承)。 多态:就是同一种事物表现出的多种形态。对不同类的对象(它们都实现相同的接口或继承相同的父类/抽象类)发出相同的消息将会有不同的行为。多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。 多态可以让应用程序具有良好的扩展性。 |
OO语言的代表-Java | ||
类 | 类的定义 | |
接口与抽象类 |
接口:can-do。Dog can Run;Bird can Fly。 抽象类:同基类,is-a。Dog is an Amimal;Cuckoo(布谷鸟) is a Bird. |
|
内部类 |
静态内部类:static class StaticInnerClass{} 成员内部类 private class InstanceInnerClass{} 局部内部类:定义在方法里 或 lambda表达式里 匿名内部类:如 (new Thread(){}).start() |
|
访问权限控制 |
封装可访问性。封装使OO的世界变得单纯,对象与对象之间的关系变得简单,高内聚低耦合,利于扩展。 访问权限控制符:public/protected/private/无修饰符 |
|
this与super |
this与super两个关键字起指代作用,通常可以省略。 可指代构造方法。此时,两者不能同时出现,且只能出现一次,且必须出现在方法体的第一行。 this还可以指代当前对象,比如同步代码块→synchronized(this){...} |
|
类关系 |
【继承 / 实现 / 组合 / 聚合 / 依赖 / 关联】 继承:extends(is-a) 实现:implements(can-do) 组合:类是成员变量(contains-a) 聚合:类是成员变量(has-a) 依赖:除组合与聚合以外的单向弱关系(depends-a)。比如使用其他类的属性/方法,或以其作为方法的参数输入,或作为方法的返回值输出。 关联:互相平等的依赖关系(links-a) 随着业务和架构的发展,类与类的关系是会发生变化的,必须用发展的眼光看待类图。在业务重构过程中,往往会把原来强组合的关系拆开来,供其他模块调用,这就是类图的一种演变。 |
|
对象序列化 |
内存中的对象只有转换为二进制流才可以进行数据持久化或网络传输。 序列化-Serialization,反序列化-Deserialization 常见的序列化方式有三种: Java原生序列化。 Hessian序列化。 JSON序列化。 序列化通常会通过网络传输对象,需要对敏感数据进行安全处理,避免受到攻击(可使用对称/非对称加密方式)。不需要进行序列化传输的,可以加 transient 关键字。 |
|
方法 | 方法签名 | 方法名+参数列表(参数个数、参数类型) |
参数 |
防御式编程理念:在方法内,对方法调用方传入的参数保持理性上的不信任。首先做参数预处理:
|
|
类内方法 |
构造方法 静态方法 实例方法 ----- getter/setter方法 静态代码块:only once |
|
同步&异步 |
同步调用是刚性调用,是阻塞式操作,必须等待调用方法体执行结束。 异步调用是柔性调用,是非阻塞式操作。 异步调用通常用着某些耗时长的操作上,这个耗时方法的返回结果,可以使用某种机制反向通知来实现,或者再一个线程主动轮询。 反向通知方式,需要异步系统与调用系统之间进行耦合。而主动轮询呢,对于没有执行完的任务会不断地请求,从而加大执行机器的压力。 某些框架提供了丰富的异步处理方式,或者是把同步任务拆解成多个异步任务等。 |
|
覆写 | override, “一大两小” 一大:子类方法的访问权限≥父类方法; 两小:子类方法 抛出的异常、返回值 ≤ 父类方法 | |
重载 | ||
泛型 | 类型擦除 | |
数据类型 |
基本类型 primitive type |
8个:boolean byte char short int long double float |
包装类型 wrapper type |
高频区间数据缓存: 例如,Integer会缓存[-128,127]之间的值,对于Integer var=?在这个区间的赋值,Integer对象由内部私有静态类IntegerCache.cache产生,会复用已有对象,这个区间的Integer值可以用==比较, 这个区间外的所有数据都会在堆上产生,并不会复用已有对象。(@seemore 听说,你也一直钟爱着equals。。。) 当基本类型自动装箱时,例如Integer var=?这种直接赋值,其实是调用的Integer的静态工厂方法valueOf(int), 这个方法的逻辑是先判断入参是否在缓存区间里,在则直接返回缓存中的Integer对象,否则new一个Integer对象。 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
|
|
字符串 |
文章开头代码:
• Parent#f2为private时,输出:parent
解释:尽管子类 Child
重写了父类 Parent
中的 f2()
方法,但由于 f2()
方法在父类 Parent
中被声明为 private
,因此它不是可见的,也不能被子类覆盖。因此,当调用 child.f1()
时,实际上调用的是父类 Parent
中的 f1()
方法,就是说,在父类中的 f1()
方法内部调用的是父类 Parent
中的 f2()
方法。
• 改动Parent#f2为protect或public后,输出:child
解释:将 Parent
类中的 f2()
方法的访问修饰符从 private
改为 protected
或 public
,使子类 Child
可以覆盖该方法,因此实际上会调用子类 Child
中的 f2()
方法。
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/16884935.html