day03

复用类

7.7向上转型

  1. 由导出类转型成基类,在继承图上是向上移动的,因此一般称为向上转型.
  2. 由于向上转型是从一个较专用类型向通用类型转换,所以总是很安全的,也就是说,导出类是基类的一个超集.它可能比基类含有更多的方法,它必须至少具备基类中所含有的方法.再向上转型的过程中,类借口唯一可能发生的事情是丢失方法,而不是获取它们.这就是为什么编译器在"未曾明确表示转型"或"未曾制定特殊标记"的情况下,仍然允许向上转型的原因.
  3. 再论组合与继承:生成和使用程序代码最有可能采用的方法就是直接将数据和方法包装进一个类中,并使用该类的对象.应当慎用继承这一技术,一个最清晰判断是否要使用继承的方法就是问一问自己是否需要从新类向基类进行向上转型.如果必须向上转型,则继承是必要的;但如果不需要,则应当好好考虑自己是否需要继承.

7.8final关键字

class Value{
    int i;
    public Value(int i){this.i = i;}
}
public class FinalData {
    private static Random rand = new Random(47);
    private String id;
    public FinalData(String id){this.id = id;}
    //Can be compile-time constants;
    private final int valueOne = 9;
    private static final int VALUE_TWO = 9;
    private static final int VALUE_THREE = 99;
    //tYPICAL PUBLIC constant
    public final int i4 = rand.nextInt(20);
    static final int INT_5 = rand.nextInt(20);
    private Value v1 = new Value(11);
    private final Value v2 = new Value(22);
    private static final Value VAL_3  = new Value (33);
    //Arrays
    private final int []a = {1,2,3,4,5,6};
    public String toString(){
        return id + ": " + "i4 = " + i4 + " , INT_5 = " +INT_5;
    }

    public static void main(String[] args) {
        FinalData fd1 = new FinalData("fd1");
        //!fd1.valueOne++;//Error:can't change value
        fd1.v2.i++;//Object isn't constant!
        fd1.v1 = new Value(9);//OK -- not final
        for (int i = 0; i < fd1.a.length; i++) {
            fd1.a[i]++;//Object isn't constant!
        }
        //! fd1.v2 = new Value(0);//Error: Can't
        //! fd1.VAL_3 = new Value(1);//change reference
        //! fd1.a = new int[3];
        print(fd1);
        print("Creating new FinalData");
        FinalData fd2 =  new FinalData("fd2");
        print(fd1);
        print(fd2);
    }
}

[图片上传失败...(image-f88b83-1535024645933)]

  1. 对于对象引用,final使引用恒定不变.一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象.然而,对象自身却是可以被修改的.如上图
  2. 使用final方法的原因有两个:
    1. 第一个原因是把方法锁定,以防任何继承类修改它的含义.这是处于设计的考虑,想要确保在继承中使方法行为保持不变,并且不会被覆盖.
    2. 第二个原因是效率.不过现在已经不需要final方法来进行优化了.
  3. 类中所有的private方法都隐式地指定为是final的.由于无法取用private方法,所以也就无法覆盖它.
  4. 如果某方法为private,它就不是基类接口的一部分.他仅是一些隐藏于类中的程序代码,只不过时具有相同的名称而已.
//两个类中的private final方法并不作为接口出现只是各自的方法,如果用向上转型来调用会出现错误
class WithFinals{
    //Identical to "private" alone;
    private final void f(){print("WithFinals.f()");}
    //Also automatically "final"
    private void g(){print("WithFinal.g()");}
}
class OverridingPrivate extends WithFinals{
     private final void f(){
        print("OverridingPrivate.f()");
    }
    private void g(){
        print("OverridingPrivate.g()");
    }
}

7.9 继承和初始化

  1. 运行过程:在Beetle上运行Java时,所发生的第一件事情就是试图访问Beetle.main()(一个static方法).于是加载器开始启动并找出Beetle类的编译代码(在名为Beetle.class的文件中).在对它进行加载的过程中,编译器注意到它有一个基类(这是由于关键字extends得知的),于是它继续进行加载.不管你是否打算产生一个该基类的对象,这都要发生(请尝试将对创建代码注释掉,以证明这一点). 如果该基类还有其自身的基类,那么第二个基类就会被加载,如此类推.接下来,根基类中的static初始化即会被执行,然后是下一个导出类,以此类推.这种方式很重要,因为导出类中的static初始化可能会依赖于基类成员能否被正确初始化.

多态

最重要的一点就是 编译看左边,运行看右边(域操作不是)

  1. 在有多态的类中,编译器怎样才能指导加载的是哪一个类呢?实际上编译器无法得知.有必要研究一下绑定问题.
  2. 将一个方法调用同一个方法主体关联起来称作绑定.若在程序执行前进行绑定(如果有的话,由编译器和连接程序实现),叫做前期绑定.困惑(因为它是面向过程的语言中不需要选择就默认的绑定方式.)
  3. 要知道究竟调用那个方法,办法就是后期绑定.它的含义就是在运行时根据对象的类型进行绑定.后期绑定也叫做动态绑定或者运行时绑定.
  4. java中除了static方法和final方法(private方法属于final方法)之外,其他所有方法都是后期绑定.这意味着通常情况下,我们不必判定是否应该进行后期绑定--它会自动发生.

类似于Shape s = new Circle();

  1. 只有非private方法才可以被覆盖;但是还需要密切注意覆盖private方法的现象,这时虽然编译器不会报错,但是也不会按照我们所期望的来执行.确切的说,在导出类中,对于基类中的private方法,最好采用不同的名字.
//当Sub对象转型为Super引用时,任何域访问操作都将由编译器解析,因此不是多态的.   当然这种情况很少遇到首先,你通常会将所有的域都设置成private,因此不能直接访问它们,其副作用是只能调用方法来访问.另外你可能不会对基类中的域和导出类中的域赋予相同的名字,因为这种做法容易令人混淆.
class Super{
    public int field = 0;
    public int getField(){return field;}
}
class Sub extends Super{
    public int field = 1;
    public int getField(){return field;}
    public int getSuperField(){return super.field;}
}
public class FieldAccess {
    public static void main(String[] args) {
        Super sup = new Sub();
        System.out.println("sup.field = " + sup.field + ", sup.getField() = " + sup.getField() );
        Sub sub = new Sub();
        System.out.println("sub.field = " + sub.field + ", sub.getField() = " + sub.getField() + ", sub.getSuperFild = " + sub.getSuperField());

    }
}/*Output:
sup.field = 0,sup.getField() = 1
sub.field = 1,sub.getField() = 1,sub.getSuperField() = 0
*///:~
  1. 如果某个方法是静态的,它的行为就不具有多态性.
  2. 静态方法是于类,而并非与单个的对象相关联的.

你可能感兴趣的:(day03)