写在前边:本文是阅读《码出高效》第二章面向对象,整理的笔记。如有错误,请留言。
目录
类:
类的定义
内部类
访问权限控制
类关系
序列化
方法
方法签名
参数
构造方法
类内方法
同步和异步
覆写
重载
数据类型
包装类型
JIT是啥:编译器。
JDK的发展(只写影响力大的):划时代影响的是 JDK5,推出并发包。
JRE是啥:java运行环境,包括JVM,核心类库,核心配置工具。
类:
类的定义
类的定义由 访问级别,类型,类名,是否抽象,是否静态,泛型标识,继承或实现关键字,父类或者接口名称。类的访问级别有public 和无访问修饰符,类型分为 class interface enum。
java类主要有成员和方法组成。推荐先定义变量,再定义方法。因为共有方法是类的调用者和维护者关心的核心部分,所以首屏展示。保护方法虽然只被子类关心,但也可能是模板设计模式下的核心方法,因此仅次于public 。私有方法对外部来说是黑盒实现,因此不需要被特别关注。最后是set和get方法,因为承载的信息量最少,所以放在最后()也是必须放在最后。
接口与抽象类
接口与抽象类的共同点是都不能被实例化,但是可以定义引用变量指向实例对象。
二者的区别:
抽象类是摸板式设计,接口是契约式设计。
继承是单继承,接口可以是多个接口。为什么接口就可以是多个呢。在这几原则中有一个接口隔离原则,就是将接口合理的拆分,这样可以避免臃肿的接口,因为接口中的方法都是要实现的,如果一个接口有太多的方法,那么继承者就要付出不用但是要实现的代价,所以我们采用合理划分,再合理组合,典型的堆积木的思想。严格遵循设计原则的好处是,给我们的重构和维护,带来了很大的帮助。
内部类
在一个 .java文件中,只能定义一个类名和文件名完全一致的公开类,使用public class 关键字来修饰。在面向对象的语言中,任何一个类都可以在自己的类内部再定义一个类,前者为外部类,后者为内部类。
demo
我们需要知道的是,不管是什么类型的内部类,都会编译成为一个独立的 .class 文件,如下:
访问权限控制
封装要求我们把有限的方法和成员公开给外部,这也是第米特法则的内在要求。
综合来看,对于访问权限,能小则小。就像是自己的小孩一样,能够在自己的眼皮底下玩,就不要让他都大马路上玩。试想一下,一个private方法,我们可以只考虑小范围就删除,但是对于public修饰的方法,能随便删除么?
对于访问权限控制,特地有如下要求:
下边谈一下自己对设计的理解:我们在设计的时候最好有大局观,不能只想着把自己的模块做完了就可以了。更应该为大局着想,更因该为长远考虑。将封装的理念发挥到极致,不管是成员还是方法,越是在可控范围内越安全,因为你放在全局,如果比的地方没有用的话,就是一种污染。
this 和 super
默认具有无参构造方法,但是如果写了有参构造,那么无参构造就一定要有。
在一个构造方法中,this 和 super 只能出现一个。
类关系
类之间要么有关系,要么没关系。但是难点在于怎么确定类有没有关系。
类的关系只有 : 继承(extends)
实现(implements)
组合(类是成员变量)
聚集(类是成员变量)
依赖(import)
序列化
在《并发编程的艺术》这本书中看到过这样一句话:序列化是一种机制。
在内存中,数据对象只有转换为二进制流才可以进行数据的持久化和网络的传输。将对象转换为二进制流就是序列化,将二进制流转化为对象就是反序列化。
常见的序列化手段:
1. java原生序列化 (有性能考虑,以及不支持跨语言,所以不推荐,也不做介绍)
2.Hessian序列化 :支持动态类型,跨语言,基于对象传输的网络协议。hessian特性:
Hessian优势所在:
Hessian问题所在:
3. JSON系列化
方法
方法签名
只包含方法名,和参数列表。是JVM 标识的唯一索引。,不包括返回值。
参数
对于多个参数,规定逗号后边必须要有一个空格。
可变参数:在JDK1.5引入,为了解决反射机制和printf方法,适用于不确定参数个数的场景。但是极不建议使用可变参数。
参数到底应该如何正确的使用:
构造方法
构造方法是与类同名的特殊方法,在创建对象时调用,可以通过不同的构造方法实现创建不同的对象。
构造方法的特征:
、
注意:接口中不能有构造方法,抽象类中可以定义。枚举类中,构造方法是特殊的,不能public修饰,因为默认是private,绝对单例的。不允许外部以创建对象的方式生成枚举对象。
一个类可以有不同参数的构造方法,这成为重载。
单一职责:构造方法不允许有其他的业务逻辑。
创建类对象时,会先执行父类和子类的静态代码块,然后再执行父类和子类的构造方法,静态代码块只执行一次。
类内方法
实例方法,静态方法,静态代码块。
1.实例方法:有称为是非静态方法。他必须依赖与对象,类内部各个方法之间可以相互调用,可以直接读写变量,但是不包括this。当 .class文件加载后,实例方法并不会被分配方法入口地址,只有在对象创建后才会被分配。实例方法可以调用静态变量和静态方法。
2.静态方法,类加载后就分配了内存空间。因为生命周期的限制,使用静态方法需要注意几点:静态方法中不能使用实例成员变量和实例方法。静态方法不能使用this 和super关键字,指两个关键子指代被创建出来的对象。
通常静态方法用于定义工具类的方法,静态方法如果使用了可修改的对象,就会在并发时存在问题。所以静态方法和单例是相伴而生的。
3. 静态代码块:静态代码块在类加载的时候被调用,只执行一次,静态代码块比构造方法要执行的早。静态代码快不能存在任何方法体内。
可以使用静态代码块实现判断类加载,属性初始化,环境配置等。
getter和setter
统一化的获取数据和修改数据
同步和异步
覆写
覆写也可以叫重写:发生在父类和子类中。表现形式是方法名参数都相同,但是实现功能有锁改变。
如果某个类覆写了父类的某个方法,则方法表中的方法引用会指向子类的实现处,代码通常这样来调用子类的方法:
这样称为向上转型。
向上转型需要注意的点:
想要覆写父类的方法需要满足以下条件:
- 访问权限不能变小。这句话怎么理解呢:就是父类的方法的访问权限是public,子类不能使用private来修饰覆写的方法。
- 返回类型能够向上转型为父类的返回类型
- 异常也要能够向上转型为父类的异常
- 方法名,参数类型以及个数都必须一致
总结覆写:
重载
重载的表现形式为在同一个类中,方法名相同,但是参数类型不同,或者个数不同,或者都不同。
重载容易理解,但是有一个注意点:就是当参数个数相同时,那么就是只有类型相同,这时候就需要一个匹配原则:
数据类型
基本数据类型 8+1
以上是八种,还有一个叫 引用句柄 refvar 默认是 null,占用 4B。
区分refvar 和真正对象引用的的区别:
真正对象引用占12个字节,但由于都是8的倍数,所以引用类型初始化空间16B,用来存储基本信息,称为对象头
引用句柄顶多存放引用类型的首地址,一个引用对象可以被多个引用句柄指向,如果引用对象没有被任何引用句柄指向,马上就要被垃圾回收了。
对象头:
包装类型
注意点:
对于包装类型的比较都用eques()
在程序中如何正确使用数据类型:
各种类型的缓存都是有范围的,只用Integer包装类可以改缓存的范围:
- 字符串