第5章 继承

来源:互联网 发布:管家婆远程桌面该软件 编辑:程序博客网 时间:2024/05/18 20:45

1.类、超类、子类

(1)在java中,所有继承都是公有继承,没有C++中的私有继承和保护继承。
(2)子类不能不能访问超类的私有域
(3)子类可以对超类的方法进行重写(override)
(4)关键字this:引用隐式参数;调用该类的其它构造器
关键字super:调用超类的方法;调用超类的构造器
(5)多态:一个对象变量可以指示多种实际类型
动态绑定:在运行时可以自动选择调用哪个方法


1.1 继承层次

java不支持多继承。

1.2 多态

"is-a"规则的另一种表述法是置换法则,它表明程序中出现超类对象的任何地方都可以用子类对象置换。
不能将一个超类的引用赋值给子类变量。


1.3 动态绑定

调用对象方法过程:
(1)编译器查看对象的声明类型和方法名。假设调用x.f(param),且隐式参数x声明为C类的对象.需要注意的是:有可能存在多个名字为f,但参数类型不一致的方法。例如,可能存在方法f(int)和方法f(String)。编译器将会一一列举所有C类中名为f的方法和其超类中访问属性为 public 且名为f的方法(超类中的私有方法不可访问)。
    至此,编译器已获得所有可能被调用的候选方法。
(2)接下来,编译器将查看调用方法时提供的参数类型。如果在所有名为f的方法中存在一个与提供的参数类型完全匹配就选择这个方法。这个过程被称为重载解析(overloading resolution)。例如对于调用x.f("hello"),编译器将会挑选f(String),而不是f(int)。由于允许类型转换(int 可以转换成 double,Manager可以转换成Employee),所以这个过程可能很复杂。如果编译器没有找到与参数类型匹配的方法,或者发现经过类型转换后有多个方法与之匹配,就会报告一个错误。

    至此,编译器已获得需要调用的方法名字和参数类型。

(3)如果是 private 方法,static 方法,final 方法 或构造器,那么编译器将可以准确地知道应该调用哪个方法,我们将这种调用方式称为静态绑定(static binding)。与此对应的是,调用的方法依赖于隐式参数的实际类型,并且在运行时实现动态绑定。在上面个列举的示例中,编译器采用动态绑定的方式生成一条调用f(String)的指令。
(4)当程序运行,并且采用动态绑定调用方法时,虚拟机一定调用与x所引用对象的实际类型最合适的那个类的方法。假设x的实际类型是D,它是C类的子类,如果D类定义了方法f(String),就直接调用它;否则,将在D类的超类中寻找f(String),以此类推。
    每次调用方法都要进行搜索,时间开销相当大。因此,虚拟机预先为每个类创建了一个方法表(method table),其中列出了所有方法的签名和实际调用的方法。这样一来,在真正调用方法的时候,虚拟机仅仅查找这个表就可以了。在前面的示例中,虚拟机搜索D类的方法表,以便寻找与调用f(String)相匹配的方法。这个方法既有可能是D.f(String),也有可能是X.f(String),这里的X是D的超类。这里需要提醒一点,如果调用 super.f(param),编译器将对隐式参数超类的方法表进行搜索。


1.4 阻止继承:final类和方法

不允许扩展的类为final类,定义类时使用final修饰符。
类中特定方法声明为final,子类将不能重写这个方法(final类中的所有方法自动成为final方法,不包括域)。
将方法或类声明为final的主要目的是:确保它们不会在子类中改变语义。

1.5 强制类型转换

·只能在继承层次内进行类型转换
·在将超类转换为子类之前,应该使用instanceof进行检查
if (staff[1] instanceof Manager){boss = (Manager) staff[1];...}

1.6 抽象类

abstract关键字
抽象类可以包含具体数据和具体方法。
抽象类不能被实例化。
可以定义一个抽象类的对象变量,但是它只能调用非抽象的子类对象。

1.7 受保护访问

protected修饰符
Java用于控制可见性的4个访问修饰符:
(1)仅对本类可见:private
(2)对所有类可见:public
(3)对本包和所有子类可见:protected
(4)对本包可见:默认,不需要修饰符

2.Object:所有类的超类

2.1 equals方法
 Java语言规范要求equals方法具有下面的特性:
    1.自反性:对于任何非空引用x,x.equals(x)应该返回 true
    2.对称性:对于任何引用x和y,当且仅当y.equals(x)返回 true,x.equals(y)也应该返回 true
    3.传递性:如果x.equals(y)返回 true,y.equals(z)返回 true,则x.equals(z)也应该返回 true
    4.一致性:如果x和y引用的对象没有发生变化,反复调用x.equals(y)返回同样的结果
    5.对于任意非空引用x,x.equals(null)应该返回 false

编写一个完美的equals方法的建议
    1.显式参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量。
    2.检测 this 与 otherObject是否引用同一个对象。
    3.检测otherObject是否为 null,如果为 null,返回 false 。这项检测是必要的。
    4.比较 this 与 otherObject是否属于同一个类。如果equals的语义在每个子类中有所改变,就使用getClass检测; 如果所有的子类都拥有统一的语义,就使用 instanceof 检测。
  5.将otherObject转换为相应的类类型变量。
  6.对所有需要比较的域进行比较。使用==比较基本类型域,使用equals比较对象域.如果所有的域都匹配,就返回 true;否则返回 false。如果在子类中重定义equals,就要在其中包含调用 super.equals(other)。

2.2 toString方法

3.泛型数组列表

ArrayList是一个采用类型参数的泛型类。
Java中ArrayList类的用法
ArrayList<T> a与T a[ ]:
·不必指出数组的大小
·使用add添加元素
·使用size()代替length()计算元素数目
·使用a.get(i)替代a[i]访问元素

4.对象包装器和自动装箱

Integer,Double,Float,Long,Character,Byte,Short,Void,Boolean.前6个派生于超类Number。
ArrayList见括号内不允许是基本类型,不允许写成ArrayList<int>,可以声明成ArrayList<Integer>。

Integer.parseInt(String)    //返回字符串表示的整型数值
Integer.parseInt(String,int)    //第2个参数表示进制
Double,Float,Long,Short,Byte有同样的方法。

5.参数数量可变的方法

//printf定义public class PrintStream{public PrintStream printf(String fmt,Object... args){return format(fmt,args);}}
这里的...是java代码的一部分,它表明这个方法可以接受任意数量的对象。

6.枚举类

package enums;    import java.util.Scanner;    public class EnumTest  {      public static void main(String[] args)      {          Scanner in = new Scanner(System.in);          System.out.print("Enter a size: (SMALL, MEDIUM, LARGE, EXTRA_LARGE) ");          String input = in.next().toUpperCase();          Size size = Enum.valueOf(Size.class, input);          System.out.println("size = " + size);          System.out.println("ordinal = " + size.ordinal());          System.out.println("abbreviation = " + size.getAbbreviation());          if (size == Size.EXTRA_LARGE)              System.out.println("Good job--you paid attention to the ");      }  }  enum Size  {      SMALL("S"), MEDIUM("M"), LARGE("L"), EXTRA_LARGE("XL");        private Size(String abbreviation) { this.abbreviation = abbreviation; }      public String getAbbreviation() { return abbreviation; }      private String abbreviation;  }  

7.反射

8.继承设计的技巧

(1)将公共操作和域放在超类
(2)不要使用受保护的域
(3)使用继承实现"is-a"关系
(4)除非所有继承的方法都有意义,否则不要使用继承
(5)在覆盖方法时,不要改变预期的行为
(6)使用多态,而非类型信息
(7)不要过多的使用反射
原创粉丝点击