Java核心技术学习笔记第五章继承

继承

类、超类和子类

1."is-a"关系是继承的一个明显的特征
2.用关键字extends表明正在构造的新类派生于一个已存在类,已经存在的这个类叫超类或父类,新类称为子类,子类的功能比超类要多。
3.应当要将一般的方法放在超类中
4.用super关键字来调用超类的方法
5.super不是一个对象的引用,不能将值super赋值给另外一个对象变量,而this可以是一个对象的引用。super只是一个指示编译器调用超类方法的关键字。
6.继承可以在超类的基础上增加字段、增加方法或覆盖超类的方法但绝对不会删除任何字段或方法。
7.因为子类不能访问超类的私有字段,所以子类的构造器必须通过一个构造器来初始化这些方法,使用super调用构造器的语句必须是子类构造器的第一句。
8.如果没有显示地调用超类的构造器,则自动调用超类无参数构造器,如果超类没有无参数构造器则会报错。

多态

1.一个对象变量可以指示多种实际类型参数的现象称为多态。在运行时能够自动地选择适应的方法叫***动态绑定***。
2.由一个超类派生出来的所有类的集合叫***继承层次***,从一个特定的类到他的祖先的路径叫***继承链***
3.子类的每个对象也是超类的对象,这是"is-a"的另一种表述是替换原则,它指出超类对象的地方都可以使用子类对象替换。不能将超类的引用赋值给子类变量是不合法的。
4.如果一个子类的引用赋值超类变量,则这个子类对象特有的方法将没办法调用
5.如果一个子类对象数组引用了一个父类对象数组,使用父类对象数组赋值,当调用子类的方法时就会报错。

理解方法调用

1.编译器查看对象的声明类型和方法名。编译器会一一列举所有可以调用方法
2.编译器确定调用中提供的参数类型,如果存在一个与锁提供参数类型完全匹配的方法,就选择这个方法。这个过程称为重载解析。如果没有找到与参数类型匹配的方法,就会报错。。
3.在覆盖一个方法的时候,允许子类将覆盖的方法的返回类型改为返回类型的子类型,通常说这是这个方法有可协变得返回类型。而且子类方法不能低于超类方法的可见性。
4.如果是private方法,static方法,final方法或构造器,编译器准确知道调用哪个方法,这个过程叫静态绑定。如果要依赖于隐式参数的类型,这个调用过程叫动态绑定。
5.每次调用要完成以上过程,开销会很大。所以虚拟机预先为每个类计算了一个方法表,其中列出了所有方法的签名和要调用的实际方法。这样一来,在真正调用的时候,虚拟机查找这个方法表就可以
6.如果调用super.f(param)那么将对隐式参数超类的方法表进行搜索。

阻止继承:final类和方法

1.如果一个类加上了final那么这个类就是final类,这个类不能被继承,类中的方法也可以被声明为final,如果这样子类就不能覆盖超类的方法。
2.一个类加上了final修饰符后,类中的方法将自动加上final。但是字段不会自动增加final。
3.如果一个类声明为final,那么这个类确保不会在子类中改变语义。除了一个类有足够的理由使用多态性,否则应该将所有的方法声明为final关键字,这样可以优化动态绑定带来的系统开销。如果一个方法没有被覆盖并且很短的好,系统会对他优化处理,这个过程叫内联。
4.新的虚拟机中的即使编译比传统的强得多,这种编译器可以准确类之间的继承关系,并能检测出是否确定覆盖给定的方法。如果方法很简短并频繁调用时,这个编译器就会对这个方法进行内联处理。如果新增加一个类,并且覆盖了这一个方法,那么优化器将取消这个方法的内联,这个过程会很慢。

强制类型转换

1.进行强制类型转换的唯一原因是:要在暂时忽视对象的实际类型,使用对象的全部功能
2.进行强制类型的条件1:只能在继承层次内进行强制类型转换2:在将超类转换成子类之前,应该使用instance of进行检查。

抽象类

1.如果自下而上在类的继承层次中上移,位于更上层的类更具有一般性,我们可以把通用的字段和方法(不管是不是抽象的)放在超类中,然后这个超类使用abstract定义为抽象类。
2.包含一个或者多个抽象方法的类就一定要被声明为抽象类,抽象类可以包含字段和具体方法。
3.扩展抽象类有两种方式。一种是在子类中保留抽象部分或者所有抽象方法仍未定义,这样就必须将子类也标记为抽象类。第二种是将抽象类的所有方法实现,子类就不在抽象了。
4.抽象类不能实例化,如果声明一个抽象类型的变脸,这个变量只能引用非抽象子类的对象
5.如果省略在抽象类定义的抽象方法,就不能在抽象类型变量上调用它。

受保护访问

1.如果某个方法只允许同一个包下的子类使用或者希望允许子类访问超类某个字段,那么可以使用protected关键字。
2.要谨慎使用protected字段,如果一个人使用你的类并将此类进行扩展,那么其他类都可以使用保护字段。如果你修改了超类的实现,那么就会影响扩展的子类。
四个访问符访问范围

访问符可见范围
public对本包和所有类可见
private只有本类可以访问
protected对本包和所有子类可见
默认对本包可见

Object所有类的超类

1.如果一个类没有明确指定超类,那么Object就被认为是这个类的超类
2.只有基本类型不是对象
3.Object类中实现的equals方法确定两个对象的引用是否相等,不过经常需要基于状态

相等测试与继承

一.equals的五个特性
1.自反性:对于任何非空引用x,x.equals(x)应该返回true;
2.对称性:对于任何引用x和y,当且仅当y.equals(x)返回true,x.equals(y)返回true;
3.传递性:对于任何引用x,y,z,如果x.equals(y)返回true,那y.equals(z)也返回true;
4.一致性:如果x和y引用的对象没有发生变化,反复调用x.equals(y)应该返回同样的结果;
5.对于任意非空引用x,x.equals(null)应该返回false
二.编写相等可以分为两种情况:
1.如果子类可以有自己的相等性概念,则对称性需求将强制使用getClass检测
2.如果由超类觉得相等性概念,那么就可以使用instance of
3.编写一个完美equals的方法的建议
1.显示参数命名为otherObject,稍后转换成另一个名为other的变量。
2.检测this与otherObject是否相等if(this==otherObject)return true。
3.检测otherObject是否为null,如果为null,返回false。
4.比较this与otherObject的类。如果equals的语义可以在子类中改变,那就用getClass检测if(getClass()!=otherObject.getClass())return false。
如果全部拥有相同的语义,可以使用instance of检测:if(!(otherObject instanceof ClassName) return false。
5.将otherObject转化为ClassName(otherObject) other=className(otherObject)。
6.现在根据相等性概念,基本类型用==比较基本类型字段,使用Objects.equals比较对象字段(Objects.equals(a,b)如果a,b不为null,那就调用a.euqals(b),如a,b都为null,返回true。
7.如果子类重新定义equals,就要在其中包含一个super.equals(other)调用。
8.重新定义equals时传入的对象应为Object类型,如果不是传入的Object类型,那么就不是重写方法,而是定义另外一个方法。

hasCode方法

1.散列码是由对象导出的一个整形值。散列码是没有规律的,两个不同的对象,x.hasCode和y.hasCode基本不会相同。
2.Object类默认的hasCode()方法返回的是地址值得出散列码。
3.hasCode方法应该返回一个整数,要合理的组合实例字段的散列码,以便能够让不同对象产生的散列码分布更加均匀。
4.Objects.hashCode()可以避免null对象,也可以避免基本类型创建对应的包装对象。
5.用Objects.hash()并提供所有这些参数,这个方法会依次调用Objects.hashCode,并组合这些散列值。
6.数组可以用Arrays.hashCode方法计算一个数列,这个数列码由数组元素的散列码组成。

toString方法

1.toString方法,它会返回表示对象值的字符串
2.只要对象与一个字符串通过操作符"+"连接起来,那么编译器就会自动调用toString方法来获得这个对象的描述。
3.只要调用System.out.println(x)那么x也会自动x.toString
4.数组继承了Object.toString方法,会返回[I@1a46e30 I表明是一个整形数组,补救的方法是可以调用Arrays.toString静态方法,如果是多维数组,则需要调用Arrays.deepToString方法
5.强烈每个类编写一个toString方法,这样使用这个类的程序员会从这个日志记录中受益匪浅.

泛型数组列表

1.为了解决动态更改数组的问题,使用ArrayList。ArrayList类似于数组,但在添加或删除元素时能够自动调整数组容量。
2.ArrayList是一个有类型参数的泛型类。为了指定数组列表保存的元素对象类型,需要用一对尖括号将类名括起来追加到ArrayList后面。
3.声明方法ArrayList staff=new ArrayList,也可以采用菱形语法,ArrayList staff=new ArrayList<>,也可以用var声明var staff=ArrayList
4.当数组的空间可能会用尽,则数组会自动创建一个更大的数组,并把对象从小数组中拷贝到大数组中。
5.如果已经知道或能够估计出数组可能储存的元素数量,就可以填充数组前ensureCapacity方法,这样在这个预计的大小前增加数组元素就不会带来很大的开销,也可以在创建的时候进行指定
ArrayList staff=new ArrayList(100);
6.当确定数组列表确定长度不会发生改变的时候,可以调用trimToSize()方法,一旦调用这个方法后数组会削减到这个大小,如果在增添新的元素,会带来很大的开销。
7.添加完所有元素之后可以调用toArray方法把集合变成数组
8.集合使用set方法和get方法更改和获取元素,只用增添了元素后才能进行更改
9.在没有泛型的时候,增添元素的时候没有泛型检查,当接收到一个不是同一类型的元素将他进行强制转换的时候就会发生错误。
10.ArrayList的插入和删除操作元素效率很低,但对于小的数组列表来说,不用太过担心。如果元素比较多的,要使用链表。

对象包装器与自动装箱

1.有时候,需要将int基本类型转换成对象。所有基本类型都有一个与之对应的类,这些类被称为包装类。数字值性基本类型的包装类都派生于Number,包装器类是不可变的,包装类是final,不能派生它们的子类
2.尖括号中的类型参数不允许是基本类型,所以就要用到包装器。
3.当直接向数组列表添加元素时,编译器会自动将list.add(3);转化为list.add(Integer.valueOf(3)),这个过程称为自动装箱
4.当将一个Integer赋值给一个int类型时,会自动进行拆箱
5.也可以将包装类进行算术运算,进行算术运算时先进行拆箱,然后进行计算,当计算完后自动装箱。
6.不要用==来比较两个包装类的数值是否相当,只有当Java把经常使用的对象包装到同一个对象的时候才会相等,要判断是否相等应该用equals方法
7.自动装箱规范要求boolean、byte、char<=127,介于-128和127之间的short和int被包装固定的对象中
8.如果包装器类引用一个null,所以自动装箱的时候可能会抛出一个NullPointerException异常
9.自动装箱和自动拆箱是编译器的工作,编译器在生成字节码的时候将自动加入必要方法的调用
10.不可以试图用传入包装类的方式来改变传入方式的值,因为包装类是不可改变的,包装器里的内容不可以改变
11.如果想编写一个修改数值参数值的方法可以使用org.omg.CORBA里的某个holder类型,包括IntHolder、BooleanHolder,每个持有者里有一个公共的字段value,可以使用这个方法更改其中的值。

参数数量可变的方法

1.可以使用省略号…是Java的一部分,它表明这个方法可以接受任何数量的对象。相当于是一个数组
2.当如果一个已有的方法的最后一个参数是数组的时候,可以使用省略号的写法,而且不会破坏任何已有的代码

枚举类

1.典型的例子 public enum Size{SAMLL,MEDIUM,LARGE,EXTRA_LARGE}这个声明定义的类型是一个类,他刚好有4个实例,不可能构建新的对象。因此在比较的时候并不需要调用equals,直接使用"=="就可以了
2.可以为枚举类型添加字段,方法,构造器,构造器只是在构造枚举常量时调用。构造器总是私有的,可以省略private。
3.可以使用toString方法返回枚举的常量名
4.可以使用valueOf方法将一个字符串设置成枚举类型。
5.使用静态方法values,它将返回一个包含全部枚举值的数组。

继承的设计技巧

1.将公共操作和字段放在超类中
2.不要使用保护字段protected机制并不能够带来更多的保护,这有两方面的原因。第一,子类集合是无限制的,任何一个人都可以由你的类派生一个子类,然后访问实例字段,破坏了封装性。
第二,在Java中,在同一个包中所有类的可以访问protected字段,而不管是不是它的子类。protected方法对于指示那些不提供乙肝用途而在子类重新定义的方法很有用。
3.使用继承实现"is-a"关系,使用继承可以节省许多代码,但是使用继承必须要满足"is-a"的关系
4.除非所有继承的有意义,否则不要使用继承
5.在覆盖方法时不要改变预期的行为,不要偏离最初的设计想法
6.使用多态,而不要使用类型信息,使用多态方法或接口实现代码比使用多个类型检测更容易维护
7.不要滥用反射。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值