java学习笔记---第五章继承

 第五章   继承

 

1.       类、超类和子类

●实例认识

      关键字super调用超类

      使用super调用构造器的语句必须是子类构造器的第一条语句

      如果子类的构造器没有显式的调用超类的构造器,则将自动调用超类默认的构造器。如果残类没有不带参数的构造器,并且在子类中没有显式的调用超类的其他构造器,则编译器将报错

      多态:一个对象变量可以引用多种类型的现象

      动态绑定:在运行时能够自动的选择调用适当的方法的现象

●多态:

      “is-a”规则:表明子类的每个对象也是超类的对象

              置换规则:程序中出现超类对象的任何地方都可以用子类对象置换

       这里看com.valentine.lesson.manager包中的一个例子,将受益匪浅

●动态绑定:

  方法调用过程的详细描述:  

(1) 编译器查看对象声明的类型和方法名

(2) 编译器将查看调用方法时提供的参数类型,

调用参数类型和提供的参数完全匹配的方法,这个过程称为重载解析

   方法和名字和参数列表被称为方法的签名

(3) 如果方法是privatestaticfinal或者构造器,那么编译器将可以准确地知道应该调用哪个方法,这种调用方法称为静态绑定

(4) ★当程序运行,并且采用动态绑定调用方法时,虚拟机一定调用与x所引用对象的实际类型最合适的那个方法。

假设x的实际类型是D,它是C的子类。如果D类定义了方法就直接调用它,否则将在D类的超类中寻找方法,以此类推

注:此处说明了多态方法的调用是一个自下而上的调用顺序。

 

      虚拟机为每个类创建了一个方法表,在运行时调用e.getsalary()过程为:

(1) 虚拟机提供对象e实际类型的方法表

(2) 虚拟机搜索定义getSalary签名的类,此时虚拟机知道应该调用那个方法

(3) 虚拟机调用方法

     在覆盖一个方法的时候,子类方法不能低于超类方法的可见性。特别是,如果超类方法是public,那么子类的方法声明一定要是public。否则编译器将会把它解释为试图减弱访问权限

●阻止继承:final类和final方法

      不允许扩展的类被称为final类,阻止人们利用某个类定义子类。

   类中的方法也可以被声明为finalfinal方法子类不能覆盖这个方法

   将方法或类声明为final的主要原因:确保他们不会在子类中改变语义

 

   内联:

     如果一个方法没有被覆盖而且很短,编译器就能够对它进行优化处理,这个过程称为内联。如果方法很简短、被频繁调用且没有真正的被覆盖,那么即时编译器就会将这个方法进行内联处理

●强制类型转换:将某个类的对象引用转换成另外一个类的对象引用

      唯一原因:在暂时忽视对象的实际类型以后,使用对象的全部功能

      将子类的引用赋给一个超类变量编译器是允许的,但是将超类的引用赋给一个子类变量,必须进行强制类型转换.

      应养成在转换之前适用instanceof运算符的好习惯

      在一般情况下应尽量少用类型转换和instanceof运算符

●抽象类:

      包含一个或多个抽象方法的类本身必须被声明为抽象的

      不管是不是抽象的,建议尽量将功能放置在超类中。尤其应该将大家都有的域和方法放置在抽象超类中。

      抽象方法充当着占位的角色,它们的具体实现在子类中。

      即使不含抽象方法,也可以将类声明为抽象类。

      抽象类不能被实例化

      可以定义一个抽象类的对象变量,但是它只能引用非抽象子类的对象(多态)

 

 

2.       所有类的超类:Object

equals方法:

       Object类中,这个方法仅仅判断两对象是否具有相同的引用

●相等测试与继承:

       Java规范要求equals方法具有下面的特性:

(1) 自反性

(2) 对称性

(3) 传递性

(4) 一致性

(5) 一个非空对象一定不等于一个空对象

              注意在覆盖时参数的参数类型要和覆盖的方法一致,否则就变成了一个重载

hashCode方法: 

       散列码:由对象导出的一个整形值

       每个对象都有一个默认的散列码,其值为对象的存储地址

       字符串的散列码是由内容导出的

toString方法:返回表示对象值得字符串

       格式:类的名字,随后是一对方括号括起来的域值

       toString调用:只要对象与一个字符串通过+号连接起来,编译器就会自动地调用toString方法,以便获得这个对象的字符串描述。在println方法中也直接调用toString方法

       ★强烈建议为自己编写的每一个类增加toString方法

      

       

3.       泛型数组列表

   

       泛型数组列表

       ArrayList是一个采用类型参数的泛型类,为了指定数组列表保存的元素对象类型,需要用一对尖括号将类名括起来夹在后面

       如果已经清楚或能够估计出数组可能存储的元素数量,就可以在填充数组之前调用ensureCapacity方法

        一旦能够确认数组列表的大小不再发生变化,就可以调用trimToSize方法

●访问数组列表元素:

      数组列表自动扩展容量的便利增加了访问元素语法的复杂程度

      数组元素列表依然使用for循环来遍历

      有时候我们可以使用toArray方法将数组元素拷贝到一个数组中

 

 

 

4.       对象包装器与自动打包

●包装器:Integer,Long,Float,Double,Short,Byte,Character,Void,Boolean

      一旦构造了包装器,就不允许更改在包装在其中的值

      对象包装器类还是final的,因此不能定义他们的子类

      自动打包与自动拆包

      ==运算符也可以应用于对象包装器对象,只不过检测的是对象是否指向同一个存储区域

      打包和拆包是编译器认可的,而不是虚拟机。编译器在生成类的字节码时,插入必要的方法调用,虚拟机只是执行这些字节码

 

●参数数量可变的方法

      省略号java代码的一部分,它表明这个方法可以接收任意数量的对象

 

 

 

5.       反射

●反射:能够分析类能力的程序被称为反射

      可以用反射:

          在运行时分析类的能力

          在运行时查看对象

          实现数组的操作代码

          利用Method对象

Class

      程序运行期间,java运行时系统始终为所有的对象维护一个被称为运行时的类型标识,这个信息保存着每个对象所属的类足迹。虚拟机利用运行时信息选择相应的方法执行

      可以通过专门的java类访问这些信息,保存这些信息的类被称为Class

          ⑴ 使用Object类中的getClass()方法返回一个Class类型的实例

          ⑵ 利用静态方法forName获得字符串对应的Class对象

          ⑶ 如果T是任意的java类型,那么T.class将代表匹配的类对象

      一个class对象实际上表示的是一个类型,而这个类型未必一定是一种类。

      方法newInstance()可以用来快速地创建一个类的实例,newInstance方法调用默认的构造器,如果不存在默认的构造器就会抛出一个异常

 

●使用反射分析类的能力

     

 

 

 

6.       枚举类

在比较两个枚举类型时,永远不要调用equals,而直接使用==就可以了

最有用的方法:toString  能够返回枚举常量名

7.       继承设计技巧

●将公共操作和域放置在超类

●不要使用受保护域

      任何人都可以有某个类派生一个子类,并编写代码直接访问protected的实例域,从而破坏了封装性

      在同一个包中的所有类都可以访问,失去封装性

●使用继承实现“is-a”关系,非is-a关系不要使用继承

●除非所有继承的方法都有意义,否则不要使用继承

●在覆盖方法时,不要改变预期行为(不要违反置换原则)

●使用多态,而非类型信息

      不要动不动就是用instanceof

●不要过多地使用反射

      反射功能对于编写系统程序来说极其实用,但是通常不实用于编写应用程序。反射机制很脆弱,编译器很难帮助人们发现程序中的错误。任何错误只能在运行时才能被发现,并导致异常

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值