前言
第二章主要是讲面向对象,也就是oop,这个概念其实很多人已经听腻了,都是非常基础的知识,本章就是讲一些java以及很多编程语言的基础设计思想
目录
正文
oop理念
面向对象是在早期滥用面向过程编程后出现的,面向过程的代码,互相耦合严重,无法复用,于是出现了先搭框架和条件的面向对象编程
面向对象传统具有三大特性:封装、继承、多态,或者说四大,加一个抽象特性
抽象:就是提取事物基本属性的能力
封装:就是降低模块的耦合,增加内聚力
继承:就是通过父子类来使得模块更有复用性
多态:就是在复用性基础上添加了扩展性
object类:
任何类的默认父类,概括了一个事物需要的方法,从社会科学来说:
我是谁?getClass ()说明身份,toString()展示信息
我是谁?Object()方法生产对象,clone()复制对象
我到哪里去?finalize()方法销毁对象
clone()方法还分为浅拷贝,一般深拷贝,彻底深拷贝
· 一般浅拷贝就是只复制基本数据类型及其引用变量,内存空间指向相同;深拷贝就是复制了指向的内存空间,而彻底深拷贝,需要覆写 clone () 方法实现引用对象的深度遍历式拷贝。
hashCode 和 equals用于比较和别人是否一样的方法
wait和notify用于通信协作的方法
初识Java
- 类的定义:
访问级别:public和无访问控制符
类型:class,interface,enum - 类的组成:成员、方法,getter,setter方法
- 接口与抽象类:为对实体类进一步抽象,只保留公共行为和特征
两者异同是一个经常考察的知识点,如下图
- 抽象类是一种is-a的关系,比如老鹰是鸟,那么鸟是抽象类,老鹰继承它
接口是一种can-do,比如老鹰和鸟都能飞,那么飞是接口 - 抽象类定义了一些共通的东西,一份宽松模板,实现它后还可以分出自己的独有东西
接口是一种严格的契约,实现它必须严格遵守接口里的东西
- 当难以决定是否用接口或者抽象类时,优先用接口,之后再用抽象类实现接口,组合接口的特性,如上图
类
内部类
-
定义类名通常只能与类文件同名,在类内部再定义类就是内部类,类别:静态,成员,局部,匿名
-
编译产生的类文件,数字编号是同名内部类
-
-
定义内部类的好处是定义域不会扩散到类外,可以通过外部类.内部类访问,内部类可以访问外部类属性和方法,在jdk源码里内部类比较常见
访问权限控制
- 此处较简单,一个表就可以覆盖
( I )如果不允许外部直接通过 new 创建对象 , 构造方法必须是 privale
( 2 )工具类不允许有 public 或 default 构造方法
( 3 )类非 static 成员变量并且与子类共享 必须是 protected
( 4 )类非 static 成员变量并且仅在本类使用 ,必须是 private
( 5 )类 static 成员变量如果仅本类使用 ,必须是 private
( 6 )若是 static 成员变量 ,必须考虑是否为 final
( 7 )类成员方法只供类内部调用 ,必须是 private
( 8 )类成员方法只对继承类公开 ,那么限制为 protected
this和super
对象初始化时,需要到达object类,利用的就是this和super
如图为this和super的一些特性异同
类关系
类之间的关系主要有五种:
[ 继承 ] extends (is-a )
·[ 实现 ] implements (can - do )
·[ 组合 ] 类是成员变量 ( contains - a )
·{ 聚合 } 类是成员变量( has - a )
·[ 依赖 ] import 类 ( use-a )
序列化
- 序列化主要是为了传输时二进制化,反序列化就是将二进制流恢复为对象数据,使用场景主要在RPC框架的数据传输上
- 常见序列化方式:java原生序列化,实现Serializable接口,不可跨语言,性能一般
Hessian序列化:可跨语言,性能较好
JSON序列化:转换为JSON字符串,可读性较好,安全性较差
方法
- 方法签名:主要是方法名称和参数列表,用来标识方法,调用时寻找方法
- 参数:分形参和实参,比如一个方程xy+z=10,x=1,那么x是形参,1就是实参
- 参数的处理:通常不保证传入参数和规定一致,就需要进行参数预处理,这里有两种方法:入参保护,就是控制参数数量规格,不合就返回错误信息,参数校验:检查参数会耗费性能,需要合理规定场景
构造方法
- 构造方法时新建对象时会调用的方法,要求如下:
方法名与类名相同
没有返回类型
不能被继承,重写;不能被直接调用
类默认提供无参构造
构造方法可私有 - 父子类静态代码块和构造方法执行顺序,注意如果再次对象实例化,静态代码块不会重复执行,只会执行一遍构造方法
类内方法
方法分三类:实例方法,静态方法,静态代码块
- 实例方法:实例方法可以互相调用,可以调用静态变量和方法
- 静态方法:不能调用实例成员和方法,不能使用super和this关键字,工具类为了线程安全通常会用静态方法
- 静态代码块:类加载时先于构造方法执行,可访问静态变量和方法
getter和setter
- 为成员变量提供读取和修改,好处是利于封装和统一控制,在POJO类中常见
- 有一些易错点:
在getter和setter里添加业务逻辑,比如修改值,不利于排查
同时定义isXxx()和getXxx ()
不同类里有同样的属性名,引起歧义
同步与异步
同步操作是阻塞式的,异步是非阻塞的,一些耗时长的操作使用反向通知,需要别的系统进行耦合,轮询则耗费性能,就可以用一个缓存队列,把同步变成异步操作
覆写
override,叫做覆写是利于与重构分别,子类覆写了父类方法,调用时就会指向子类方法,也叫做向上转型
- 覆写需要满足四个条件:
- 访问权限不能变小,否则子类无法执行父类方法
- 访问类型能向上转型为父类类型
- 异常可以向上转型为父类异常
- 方法名,参数类型和个数必须一致,这里和重载有区别,重载是名相同,参数列表可以不同
重载
重载就是同一个类中,多个方法同名不同参
- 需要注意的是对于一些优先级高的方法,例如可变参数,无参方法,JVM调用的顺序如下:
泛型
泛型就是类型参数化,有时不确定对象类型,就可变部分来复用代码
如图使用对象类型的参数,传入对象,这样容易产生类型转换错误,使用泛型后
这样避免的object输入输出类型转换错误,还可有如下好处
数据类型
基本数据类型
数据类型分基本和引用数据类型,基本就是八大,boolean,byte,char,short ,int,long,float,double,此书中认为refvar也是一种基本数据类型,如下表为各种类型的参数
包装类型
八种基本类型都有包装类型,体现了java一切皆对象的设计理念,包装类型可以解决一些hashcode获取哈希值之类的问题,比如getclass获取类
- 包装类比较,推荐使用equals,因为在-128到127之间可以用==,但之外都在堆上产生
- 除float和double外,其他包装类赋值,底层调用valueof方法
这里就是在缓存区间内就直接返回,否则new一个对象
以下是各类型的缓存区间
在选择包装类和基本数据类型时,选择方式如下
字符串
- 字符串主要有三种:String 、StringBuilder、StringBuffer
- String对象赋值后,会放到常量池中,下次申请创建对象时,会从池中取并返回
- StringBuffer可在源对象上修改,线程安全
- StringBuilder是非线程安全的,需要进行手动加锁,操作效率比StringBuffer高
- 在循环内,拼接字符串推荐使用StringBuilder的append方法,如下图会new一个StringBuilder对象,append后再返回toString,降低性能