java学习继承
2020-05-20 17:05:28
1.子类和超类存在is-a关系,子类is-a超类
2.子类可以重用超类中已经编写的部分代码,并将超类中所有域都保留下来
3.子类中的方法不能够直接访问超类的私有域,尽管每个子类对象都拥有名字和超类相同的域,但是在子类的方法中并不能够直接访问超类的相关域;只有超类的相关方法可以访问它的私有部分;如果子类一定要访问超类的私有域,就必须借助公有的接口,超类中相关域的访问器就是这样一个接口
4.调用超类中与子类相同名称的方法必须加关键字super
5.super与this的概念并不相似,this是一个对象引用,super是一个调用超类方法的特殊关键字,并不是是一个对象的引用,不能将super赋值给另一个对象变量;在this和super调用其他类的构造器的时候,使用方式类似
6.子类构造器
由于子类的构造器不能够访问超类的私有域,所以必须利用超类的构造器对这部分私有域进行初始化,可以通过super实现对超类构造器的调用;如果子类的构造器没有显式的调用超类的构造器,则将自动的调用超类默认(无参)的构造器,如果超类中没有无参的构造器,并且在子类中没有显式的调用超类的其他构造器,就会报错
7.多态,一个变量可以指示多种实际类型的现象被称为多态;在运行时能够自动选择调用那个方法的现象称为动态绑定
8.由一个公共超类派生出来的所有类的集合被称为继承层次,在继承层次中,从某个特定的类到其祖先的路径被称为该类的继承链
9.is-a规则,表明子类的每个对象也是超类的对象,另一种表述是置换法则,它表明程序中出现的超类对象在任何地方都可用子类对象置换
10.在java程序设计语言中,对象变量是多态的
11.虽然超类和子类对象变量可以引用同一个对象,但是在编译器会对不同的对象变量的类型进行区分,这意味着超类对象变量不能够调用子类对象变量的方法;不能将一个超类的引用赋给子类变量(逻辑上有问题)
12.理解方法调用
编译器查看对象的声明类型和方法名,有可能会出现方法名相同但是参数不同的方法,编译器会将对象所在类中的所有相同方法名的方法和其超类中的访问属性为public且名与该方法相同的方法一一列举
接下来,编译器将查看调用方法时提供的参数类型,如果存在,就选这个方法,这个过程是重载解析;如果欸有找到,或者发现有很多个匹配,就会报告错误
如果是private方法,static方法,final方法或者构造器,那么编译器将可以准确的知道应该用哪个方法,这种调用方式被称为静态绑定
当程序运行的时候,并且采用动态绑定调用方法时,虚拟机一定会调用与对象变量所引用对象的实际类型中最适合的那个类的方法,子类匹配,如果没有,超类匹配,依次类推
虚拟机预先为每个类创建了方法表,其中列出了所有的方法的签名和实际调用方法
如果调用super.f(),编译器会对隐式参数超类的方法表进行搜索
13.在覆盖的时候,子类方法的可见性一定不能低于超类方法的可见性,如果超类方法时public,覆盖的子类方法一定要是public
14.有时候,可能是希望阻止人们利用某个类定义子类,不允许扩展的类被称为final类。如果在定义类的时候使用final修饰符就表明这个类时final类,final类中所有的方法自动的称为final方法,但是域不会;
类中的方法也可以被声明为final,这样做,子类就不会覆盖这个方法
15.将方法或类声明为final主要目的是:确保它们不会在子类中改变语义
16.进行类型转换的唯一原因是:在短暂忽视对象实际类型之后,使用对象的全部功能
17.强制转换对象类型,只能在继承层次内进行类型转换;在将超类转换成子类前,应该使用instanceof进行检查
18.一般情况下,应该尽量少用类型转换和instanceof运算符
19.如果自下往上在类的继承层次中上移,位于上层的类更具有通用性,甚至可能更加抽象;从某种角度看,祖先类更加通用,人们之将它作为派生其他类的基类,而不作为想使用的特定的类
抽象类,包含一个或多个抽象方法的类本身必须被声明为抽象的;抽象方法使用abstract关键字,就不需要具体的实现方法了,抽象方法充当一个占位的角色,它们的具体实现在子类中
抽象类中可以包含具体的数据和具体方法
20.扩展抽象类可以有两种选择,一种是将超类的抽象类方法部分定义或不定义,这样子类必须也标记为抽象类;另一种是定义全部的 抽象方法,这样一来,子类就不是抽象的了
21.类即使没有抽象方法,也可以定义为抽象类,抽象类不能够实例化;需要注意的是,可以定义一个抽象类的对象变量,但是它只能够引用非抽象子类的对象
22.由于不能构造抽象类对象,在编译器看来,抽象类对象是它的子类型,而不是抽象类对象本身
23.不能够省略超类中的抽象方法,仅在子类中定义,就不能够通过抽象超类的对象变量调用抽象类中省略,子类实现的方法;编译器只允许调用类中声明的方法
24.人们希望超类中的某些方法可以允许被子类访问,或者允许子类的方法访问超类中的某个域,为此,需要将这些方法或域声明为protected
25.访问修饰符
private:仅本类可见
public:对所有类可见
protected:对本包和所有子类可见
无修饰符(默认):对本包可见
26.在java中,只有基本数据类型不是对象
27.随处可见toString()方法的原因是只要对象与一个字符串通过操作符“+”连接起来,java编译就会自动的调用toString方法,以便获得这个对象的字符串描述
28.如果x是任意一个对象,并调用system.out.println(x),println()方法就会直接的调用x.toString(),并打印输出字符串
29.java ==如果比较对象变量,则会比较它们是否为同一个引用
30.泛型数组列表,能够自动的调节数组容量的大小;数组列表管理着对象引用的一个内部数组,如果这个数组将满,数组列表就会自动创建一个更大的数组,并将所有的对象从较小的数组中拷贝到较大的数组中
31.数组列表的下标从0开始,get()和set()分别是访问器和更改器,不能够添加数组列表中的内容
32.基于兼容性的考虑,编译器在对类型转换进行检查之后,如果没有发现违反规则的现象,就将所有的类型化数组列表转换成原始的数组列表对象,在程序运行时,所有的数组列表都是一样的,即没有虚拟机中的类型参数
33.泛型不允许是基本类型
34.自动装箱,将一个基本类型添加到相应的对象包装器类型的变量时,会将基本类型自动转换为包装器类型;相反的过程称为自动拆箱
35.反射,能够分析类能力的程序称为反射
运行时分析类的能力
在运行时查看对象
实现通用的数组操作代码
利用Method对象
36.在程序运行期间,java运行时系统始终为所有对象维护一个被称为运行时的类型标识,这个信息跟踪着每个对象所属的类,虚拟机利用运行时类型信息选择相应的方法执行,可以通过专门的java类访问这些信息。保存这些信息的类被称为Class
37.虚拟机为每个类型管理一个Class对象,有三种方法获得Class对象
Object类的getClass()方法将会返回一个Class类型的实例,这种方法适用于可以获取到对象变量
还可以调用静态方法forName()获得类名对应的Class对象,这类方法适用于可以获取到对象类型的字符串名字
如果T是任意的Java类型,T.class将代表匹配的类对象,这类方法适用于类名直接获取类对象
38.一个Class对象实际上代表一个类型,而这个类型未必一定是一种类,例如int不是一个类,但是int.class是一个Class类型的对象
39.newInstance()方法会调用一个默认的构造器(无参的构造器)初始化新创建的对象,如果这个类没有默认的构造器,就会抛出一个异常
40.反射机制最重要的内容,分析类的结构
41.java数组会记住每个元素的类型,即创建数组时new表达式中使用的元素类型;将一个数组临时的强转为其它类型的数组,再转回来是可以的,但是从一开始就是一个类型的数组却永远不能转换成另一个类型的数组
42.Obiect类是所有对象的基类,所有的对象(包括数组对象)都可以赋值给一个Object类的变量,Object[]是一个对象型的数组,它可以被赋值为任何对象类数组,但是基本数据类型的数组是无法赋值的
43.继承的设计技巧
将公共操作和域放在超类
不要使用受保护的域
使用继承实现“is-a”关系
除非所有继承的方法都有意义,否则不要使用继承
在覆盖方法时,不要改变预期的行为
使用多态,而非类型信息
不要过多的使用反射