this&super
- 关键字this的两个含义
- 指示隐式参数的引用,也就是当前对象实例
- 调用当前类的其他构造方法
- 关键字super的两个含义
- 调用超类的方法
- 调用超类的构造方法
is-a规则
is-a规则用来判断是否将数据设计为继承关系。另一种表述是替换原则,他指出程序中出现超类对象的任何地方都可以用子类对象来替换
多态的在编译时可能出现问题
方法调用
例如x.f(args),x声明为类C的一个对象
- 查找x实际声明类型和其超类所有名为f的可访问方法
- 编译器根据args参数类型来匹配,如果没有找到直接对应的类型则会寻找类型转换后能匹配的方法,如果有多个方法匹配则会报错。这个过程称为重载解析
方法覆盖
- 方法的名字和参数列表成为方法的签名,不包含返回类型
- 覆盖方法时,需要保证返回类型与父类相同或者为其子类
- 子类方法可见性不能低于父类方法的可见性
静态绑定
private、static、final、构造器方法在调用时,编译器可以准确知道应该调用哪个方法
动态绑定
- 调用的方法依赖于隐式参数的实际类型,就是在运行时利用动态绑定来查询调用哪个方法
- 程序运行并且采用动态绑定调用方法时,虚拟机要先查找对象实际类型是否有匹配的方法,再调用其超类是否有匹配的方法
- 虚拟机为每个类预先计算了一个方法表,来节省搜索方法的时间花销
final
- final定义的类不允许被继承,所有方法默认为final方法,属性不会默认为final
- final定义的方法不允许被覆盖
- final定义的属性构造对象之后不允许修改,引用类型属性不允许修改引用地址,但是引用变量的内容可以修改
- 使用final可以进行内联优化
强制类型转换
- 从上往下转换时先用 instanceof 判断再转换
abstract
- 有一个或者多个abstract方法的类必须定义为abstract类
- abstract类可以没有abstract方法
- abstract类不能实例化,只能引用非抽象子类的实例
protected
- protected只能修饰属性和方法
- protected修饰的属性和方法可以由同包的其他类通过实例化对象来访问,还可以在子类定义的方法中访问
equals()方法
- 需要通过对象状态来判断是否相等时,需要重写equals方法,满足自反性、传递性、对称性、一致性、null值返回false
- 用“==”判断引用地址是否相等
- 判断比较对象是否为空
- 如果equals语义可以在子类中改变,则用用getClass()方法判断所属类是否相同
- 如果所有子类都有相同的相等性语义,可以使用instanceof 检测
- 比较属性值时,基本类型用“==”判断值是否相等,引用类型用Objects.equals(a,b)方法来判断是否相等,数组类型可以使用Arrays.equals(a,b)
hashCode()方法
- Object默认的hashCode()方法是根据对象存储地址得出的
- String重写了hashCode()方法,是根据内容得出的
- equals与hashCode方法要有一致性,a.equals(b)为true时,a.hashCode 必须等于 b.hashCode()
- 重写hashCode()方法时,Objects.hashCode(arg)方法可以对单个实例属性计算值,Objects.hash(args...)可以同时对多个实例属性计算hashCode值,数组类型字段Arrays.hashCode()方法
toString()方法
- 重写toString方法打印类名时,推荐使用getClass().getName()来获取类型,这样子类也可以使用
- 一维数组推荐使用Arrays.toString(arg)
- 多维数组推荐使用Arrays.deepToString(args)
可变长参数
- 可以定义基本类型:int...
- 允许将数组作为最后一个参数传递给有可变参数的方法
反射
Class类
- 每一种类型都有一个唯一的Class对象
- 获取Class的三种方式
- object.getClass()
- T.class
- Class.forName()
继承的设计技巧
- 将公共操作和字段放在超类中
- 不要使用protected字段(会破坏封装性,不安全,任意继承的子类和同包类都可以访问)
- is-a关系是判断是否继承的基础
- 除非所有继承的方法都有意义,否则不要使用继承
- 再覆盖方法时,不要改变预期的行为
- 尽量使用多态,不要使用类型信息判断来调用同类型方法
- 不要滥用反射