乱七八糟的想法#
封装、继承、多态是面向对象语言的重要特征。
封装最重要的就是对外部隐藏一些不必要和不许修改的成员,而公开一些对外部有用的成员。Java中使用private来实现隐藏。
继承是父类经过扩展生成一个子类,子类可能比父类具有更多的属性,java教材上说,子类将获得父类的全部成员变量和方法,而不能获得父类的构造器,那么:
- 父类方法具有private访问权限,则方法对其子类是隐藏的,子类无法访问该方法。这时有一个问题,一个public权限的父类方法中调用了private权限的方法,而这个public权限的方法被子类继承,如果这时子类调用这个方法,那private权限的方法不是被执行了吗?
- 父类一个成员变量具有private访问权限, 那么这个变量对于子类也是隐藏的,子类无法访问这个变量。但是,在创建子类对象时,系统会为这个成员变量创建存储空间吗?
小实验:
class Superclass
{
private int a = 0;
public int b = 1;
protected int c = 2;
int d = 3;
public Superclass()
{
System.out.println("Superclass Constructor!!");
System.out.println(a+" "+b+" "+c+" "+d);
call();
}
private void test()//一个private方法
{
System.out.println("Private test!");
}
public void call()
{
System.out.println("Superclass Call!!");
this.test();
}
}
class Subclass extends Superclass
{
public int a = 3;
private int b = 2;
int c = 1;
protected int d = 3;
public Subclass()
{
System.out.println("Subclass Constructor!!");
}
public void call()
{
System.out.println("Subclass call");
super.call();
}
public void test()
{
System.out.println("Override??");
}
public static void main(String[] args)
{
Subclass test = new Subclass();
test.call();
}
}
运行结果:
Superclass Constructor!!
0 1 2 3
Subclass call
Superclass Call!!
Private test!
Subclass Constructor!!
Subclass call
Superclass Call!!
Private test!
- 这个java程序中,在父类Superclass中定义了一个私有方法test(),子类中定义了一个公共方法test(),可以看到,这时子类并没有Override这个方法,所以在super()调用父类构造器时,执行的是父类中的私有方法,同样,在call()方法中调用test()时,执行的同样是父类中的私有方法。但这时,并不能说子类获得了这个方法,因为子类根本没有权限访问修改它。
- 这时,如果将private方法改变为public权限,这时运行结果变为:
0 1 2 3
Subclass call
Superclass Call!!
Override??
Subclass Constructor!!
3 2 1 3
Subclass call
Superclass Call!!
Override??
此时,父类的test()方法被子类Override,这时,在执行super()和super.call()时,调用的是子类的test()方法。
- 同时,父类的所有成员变量在子类对象被创建时,均被分配了存储空间,包括private权限的的变量,只是,这个变量不能被子类访问,只能在父类方法中被访问,因此,子类也并没有获得这个变量。
需要注意的问题#
- 关于继承
- 方法Override时,子类方法的返回值类型应比父类方法返回值类型更小或相等,抛出异常应比父类方法声明抛出的异常类更小或相等,访问权限应比父类的大或相等,方法名和形参列表必须相同,覆盖方法和被覆盖方法应同为类方法或者实例方法。
- 子类不会获得父类的构造器,但子类构造器会调用父类的构造器,不论是否显式的调用super(),这样一层层深入,每个对象在创建时,都会调用Object类的构造器。
3.父类中的方法被子类Override时,在父类中调用该方法时,会执行子类中的覆盖方法,如上面的例子就是这种情况。