Java编程思想之七复用类

复用代码是Java众多引人注目的功能之一。但要想成为极具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它还必须做更多的事情。 使用类而不破坏程序代码:

  • 在新类中产生现有对象。由于新的类是由现有类的对象组成,所有这种方法称为组合。
  • 按照现有类的类型来创建新类。无需改变现有类的形式,采用现有类的形式并在其中添加新代码。这种方法是继承。

7.1 组合语法

组合只需要将对象引用置于新类中就可以了。 但编译器并不是简单的为每一个引用都创建默认对象。如果想初始化这些引用,可以在代码中下列位置进行:

  • 在定义对象的地方。
  • 在类的构造器中。
  • 就在正要使用这些对象之前,这种方式称为惰性初始化。
  • 使用实例初始化。

7.2 继承语法

除非已明确指出要从其他类中继承,否则就是在隐式的从Java的标准根中类Object进行继承。 这种声明是通过在类主体的左边花括号之前,书写后面紧随基类名称的关键字extends而实现的。当这么做时,会自动得到基类中所有域和方法。 Javay用super关键字表示超类的意思。C#中用base。

7.2.1 初始化基类

当创建了一个导出类对象时,该对象包含了一个基类的子对象。这个子对象与你用基类直接创建的对象是一样的。二者区别在于,后者来自于外部,而基类的子对象被包装在导出类对象内部。 在构造器中调用基类构造器来执行初始化,而基类构造器具有执行基类初始化所需要的所有知识和能力。Java会自动在导出类的构造器中插入对基类构造器的调用。 即使你不为导出类创建构造器,编译器也会为你合成一个默认的构造器,该构造器将调用基类的构造器。

带参数的构造器

如果没有默认的基类构造器,或者想调用一个带参数的基类构造器,就必须使用关键字super显式的编写调用基类构造器的语句,并且配以适当的参数列表。

7.3 代理

这是继承于组合之间的中庸之道,因为我们将一个成员对象置于所要构造的类中,但与此同时我们在新类中暴露了该成员对象的所有方法。

1public class SpaceShipDelegation { 2 SpaceShipControls spaceShipControls=null; 3 public SpaceShipDelegation(SpaceShipControls controls){ 4 this.spaceShipControls=controls; 5 } 6 public void up(int i){ 7 spaceShipControls.up(i); 8 } 9 public void down(int i){ 10 spaceShipControls.down(i); 11 } 12} 13class SpaceShipControls{ 14 void up(int velocity){} 15 void down(int i){} 16}

7.4 结合使用组合和继承

7.4.1 确保正确清理

Java中没有C++中析构函数的概念。析构函数是一种在对象被销毁时可以被自动调用的函数。 在清理方法中,还必须注意对基类的清理方法和成员对象清理方法的调用顺序,以防止某个对象依赖于另一个子对象情形发生。首先,执行类的所有特定的清理动作,其顺序同生成顺序相反。然后,调用基类的清理方法。

一旦涉及垃圾回收,能够信赖的事就不会很多了。垃圾回收器可能永远也无法被调用,即使被调用,它也可能以任何它想要的顺序来回收对象。最好的办法是除了内存外,不能依赖垃圾回收器去做任何事。如果需要进行清理,最好事编写自己的清理方法,但不要使用finalize()。

7.4.2 名字屏蔽

如果Java的基类拥有某个已被多次重载的方法名称,那么在导出类中重新定义该方法名称并不会屏蔽在基类中的任何版本。无论是在该层的基类中对方法进行定义,重载机制都可以正常工作。 当你想要覆写某个方法时,可以使用@Override这个注解。它可以防止你在不需要进行重载时意外进行了重载。

7.5 在组合与继承之间选择

组合和继承都允许在新的类中放置子对象,组合是显式的这样做,而继承是隐式的做。 组合技术通常用于想在新类中使用现有类的功能,但新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口。

7.6 protected关键字

对于任何继承于此类的导出类或其他任何位于同一包内的类来说,它是可以访问的。

7.7 向上转型

将导出类转换成基类。 导出类是基类的一个超集,它可能比基类含有更多的方法,但它必须至少具备基类中所含有的方法。

7.7.2 组合与继承

该用组合还是继承,一个最清晰的判断办法就是是否需要从新类向基类进行向上转换。

final关键字

final可以用于三种情况:数据、方法、类

7.8.1 final数据

使数据恒定不变是有用的:

  • 1.一个永不改变的编译时常量
  • 2.一个再运行时被初始化的值,而你不希望它被改变

在编译期常量这种情况,编译器可以将该常量值带入任何可能用到它的计算式中,也就是可以在编译时执行计算式,这就减轻了运行时的负担。在对这个常量进行定义时,必须初始化。 一个是static又是final的域只占据一段不能改变的存储空间。 对于对象引用,final引用恒定不变,对象自身可以被修改。

空白final

Java允许生成"空白final",空白final指被声明为final但又未给定初始值的域。无论什么情况,编译器都确保final在使用前必须被初始化。

1public class BlankFinal { 2 private final int i=0; 3 private final int j;//必须进行初始化 4 private final Poppet p; 5 public BlankFinal(){ 6 j=1; 7 p=new Poppet(1); 8 } 9 10 public BlankFinal(int x){ 11 j=x; 12 p=new Poppet(x); 13 } 14 15 public static void main(String[] args){ 16 new BlankFinal(); 17 new BlankFinal(2); 18 } 19} 20 21class Poppet{ 22 private int i; 23 Poppet(int ii){ 24 i=ii; 25 } 26}
final参数

Java允许在参数列表中以声明的方式将参数指明为final,这就意味着你无法在方法中更改参数引用所指向的对象。

1public class FinalArguments { 2 void with(final Gizmo g){ 3 //g=new Gizmo();不能赋值。 4 } 5 6 int without(final int i){ 7 //i+=1;不能改变 8 return i+1; 9 } 10} 11 12class Gizmo{ 13 public void spin(int i){ 14 System.out.println(i); 15 } 16}
7.8.2 final方法

使用final方法的原因有两个:

  • 把方法锁定,以防止任何继承类修改它的含义。保持继承中使方法保持不变,并且不会被覆盖。
  • 效率。将一个方法指定为final,就是同意将针对该方法的所有调用都转为内嵌调用。但在现在的虚拟机中,不需要使用final方法来进行优化了。
final和private关键字

private方法都隐式的指定是final。

7.8.3 final类

当将某个类整体定义为final时,就表面此类不能被继承。

7.9 初始化及类的加载

在对导出类进行加载时,会先对基类进行加载。如果该基类还有自身的基类,那么第二个基类就会被加载。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Java日期时间API系列31

  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前

java常用类(2)

三、时间处理相关类Date类:计算机世界把1970年1月1号定为基准时间,每个度量单位是毫秒(1秒的千分之一),用long类型的变量表示时间。Date分配Date对象并初始化对象,以表示自从标准基准时间(称为“历元”(epoch),即1970年1月1日08:00:00GMT)以来的指定毫秒数。示例:packagecn.tanjian