1、父类型引用指向子类型对象,只能调用父类有的方法,不能调用子类独有的方法。输出结果取决于子类实例到底什么样。


<span style="font-family:Microsoft YaHei;">package com.cry.practice;

import static com.cry.utils.Print.*;

class A {
    void f1() {
        println("a");
    }
}

public class B extends A {

    void f1() {
        println("b");
    }

    void f2() {
        println("bbbb");
    }

    public static void main(String[] args) {
        A a = new B();
        a.f1();
        //! a.f2();   这是错误的!A类型引用根本无法调用f2()
    }
    /*
        Output:
        b
    *///:~

}
</span>

2、关于跨包继承,是否能重写,是否能调用的实验:



项目目录:



java跨模块调用Service java跨包调用类_子类



A.java:



<span style="font-family:Microsoft YaHei;">package com.cry.another;

import static com.cry.utils.Print.println;

public class A {

    protected void f1(){
        println("a");
    }

}
</span>



B.java:

<span style="font-family:Microsoft YaHei;">package com.cry.practice;

import com.cry.another.A;

import static com.cry.utils.Print.*;

public class B extends A {

    // 重写父类的方法总是可行的,不管父类中该方法是什么访问权限。
    // 但要保证子类中该方法的访问权限大于等于父类
    protected void f1() {
        println("b");
    }

    public void f2() {
        f1();   //这样调用正确

        //! A a = new A();
        //! a.f1();     错误,你不能调用另一个A类对象的f1(),因为f1()是protected的。
    }

    public static void main(String[] args) {
        B b = new B();
        b.f2();
    }
    /*
        Output:
        b
    *///:~

}
</span>


3、只要是用final修饰的数据,初始化之后就再也不能更改,不管是在什么地方,什么访问权限。只要是final修饰的变量在声明时就必须明确的初始化。


<span style="font-family:Microsoft YaHei;">class A {
//    final int v;  //ERROR!

    private final int v1 = 1;
    protected final int v2 = 1;
    public final int v3 = 1;
    final int v4 = 1;

    public void f() {
//        v1 = 2;   //ERROR!
//        v2 = 2;   //ERROR!
//        v3 = 2;   //ERROR!
//        v4 = 2;   //ERROR!
}</span>




4、父类的private成员,子类不能直接访问,但是如果父类有public修饰的getter/setter,子类则可以直接使用。比如下面的例子,可以说明,一个子类实例中确实包含一个名为val的int型数据实体,一个子类实例实际上包含一个父类实例在其中,但是父类的private修饰部分,子类却无法直接访问。面向对象的程序设计中,我们应当持这样的态度:“我们除了把private部分看成该类内部的实现结构之外,其他任何时候都不必考虑另一个类的private”。(注:JAVA的@Override注解似乎对这一问题有奇妙作用,日后研究)。或者可以说,private将类与类之间完全隔离开,哪怕它们是父子类。


<span style="font-family:Microsoft YaHei;">package com.cry.practice;

import static com.cry.utils.Print.println;

class A {
    private int val;

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }
}

public class B extends A {

//    val = 5;  //ERROR!

    void f() {
//        val = 5;  //ERROR!
        setVal(1);
    }

    public static void main(String[] args) {
        B b = new B();
        b.f();
        println(b.getVal());
        b.setVal(5);
        println(b.getVal());
    }
}
/*
    Output:
    1
    5
 *///:~</span>





5、final方法,子类根本不能重写,但子类可以调用。也就是说子类仍具有该final方法,只不过该方法的含义截止在父类那“一代”,子嗣无法修改。这满足了设计中这样的需求:锁定一个方法,以防止任何继承类修改它的含义,确保了该方法在继承中行为不变且不被覆盖。


<span style="font-family:Microsoft YaHei;">package com.cry.practice;

import static com.cry.utils.Print.println;

class A {
    public final void f(){
        println("AAA");
    }
}

public class B extends A{
//    public void f(){} //ERROR!编译器直接报错,final方法不能被子类重写

    public static void main(String[] args) {
        B b = new B();
        b.f();  //但是子类可以使用这个final方法,这是没问题的。
    }
}
/*
    Output:
    AAA
 *///:~</span>






6、private修饰的东西别的类就是不能访问到,子类也不能访问到,“同名重写覆盖”它,其实编译器只是认为子类有了一个新方法。



package com.cry.practice;

import static com.cry.utils.Print.*;

class Son extends Father{
    public void f(){
        println("son");
    }
}

public class Father {
    private void f(){
        println("father");
    }

    public static void main(String[] args) {
	    Father o1 = new Father();
        Father o2 = new Son();
        Son o3 = new Son();

        o1.f();
        o2.f();
        o3.f();
    }
    /*
        Output:
        father
        father
        son
     *///:~
}



7、关于抽象类的一个基本小例子, 注意其数据访问权限和初始化顺序。



记住三不相容:



1、abstract不能与private同用,因为private不可被子类访问,也不可被重写(子类可以同名覆盖,但那相当于子类自己的新方法),而abstract是需要被重写的抽象方法。
2、abstract不能与final同用,因为final修饰的不能被重写,而abstract是需要被重写的抽象方法。
3、abstract不能与static同用,static修饰的方法归该类所有而非某个具体对象,并且也只归该类所有。如果该方法是protected或public,子类可以继承或调用,但不能重写(子类可以同名覆盖,但那相当于子类自己的新方法),而abstract表示期望被子类实现,所以不可同时使用。



package com.cry.practice;

import static com.cry.utils.Print.*;

//如果包含抽象方法,那这个类在声明时就必须用abstract修饰,否则IDE报错。
abstract class Student {
    public String type = "student";
    public abstract void introduce();
}

public class Tom  extends Student{

    public static void main(String[] args) {
        Tom tom = new Tom();
        tom.introduce();
    }

    //如果一个非抽象类继承了抽象类,那就必须给出抽象方法的定义。
    @Override
    public void introduce() {
        //抽象类也是类,其中已经具体定义的数据成员可以访问,其子类的整个初始化过程也按标准进行。
        println("Tom is a " + type);
    }
    /*
        Output:
        Tom is a student
     *///:~
}