继承
继承的原则
- 一个很好的经验:“类B是类A的一个特殊化吗?”
- 如果是则让类B做类A的子类
class Human
{
public String name = "彭晨";
public int age = 22;
}
class Student extends Human
{
public double score = 99;
}
class Postgraduate extends Student
{
public String daoshi = "郝斌";
}
class M
{
public static void main(String[] args)
{
Postgraduate gd = new Postgraduate();
System.out.printf("%s %d %f %s\n",gd.name,gd.age,gd.score,gd.daoshi);
}
}
程序运行示例:
————————————————————————————————————————
彭晨 22 99.000000 郝斌
————————————————————————————————————————
-
一个新类从已有的类那里获得其已有的属性和方法,这种现象叫做类的继承
-
这个新类被称为子类或者派生类,已有的那个类叫做父类或者叫做基类
-
继承的好处
- 代码得到极大的重用
- 形成一种类的层次体系结构
- 为多态创造条件(OOP第三个特点)
-
继承的实现方式
-
class SubClass extends SuperClass
-
{
…
-
}
-
同包继承权限问题(重点)
- 子类的所有方法内部都可以访问父类除私有成员以外的所有成员,所谓子类的所有方法也包括子类的私有方法
- 通过子类对象名可以访问
- 父类除私有成员外的所有成员
- 子类本身的除私有成员外的所有成员
- 附注,私有成员包括私有属性和私有方法
- 子类可以继承父类除私有属性和私有方法以外的所有成员
- 父类的私有成员不可以被子类继承,其他的成员都可以被子类继承
- 不同包继承问题等讲到包再说!!
class A
{
public int i;
protected int j;
private int k;
public void g()
{
}
protected void f()
{
}
private void b()
{
}
}
class B extends A
{
private void m()
{
i = 20;
j = 30;
// k =40; //error k 在 A 中是 private 访问控制
g();
f();
}
}
class M
{
public static void main(String[] args)
{
B bb = new B();
bb.i = 10;
bb.j = 40;
bb.b();
bb.m();
bb.k = 3;
}
}
程序运行示例:
————————————————————————————————————————
M.java:39: 错误: 找不到符号
bb.b();
^
符号: 方法 b()
位置: 类型为B的变量 bb
M.java:40: 错误: m() 在 B 中是 private 访问控制
bb.m();
^
M.java:41: 错误: k 在 A 中是 private 访问控制
bb.k = 3;
^
3 个错误
————————————————————————————————————————
子类访问父类成员的三种方式
- 在子类内部访问父类成员
- 通过子类对象名访问父类成员
- 通过子类的类名访问父类成员
经验证,子类通过上述三种方式的任何一种都无法访问父类私有成员,因此我们可以得出结果:
私有成员无法被子类继承
class A
{
public static int i;
protected int j;
private static int k;
}
class B extends A
{
public static void g()
{
i = 20;
// k = 20;
}
}
class M
{
public static void main(String[] args)
{
//B bb = new B();
//bb.i = 99;//OK
B.g();
System.out.printf("%d\n",B.k);
/**
程序运行示例:
———————————————————————————
k 在 A 中是 private 访问控制
System.out.printf("%d\n",B.k);
^
1 个错误
————————————————————————————
*/
System.out.printf("%d\n",B.i);
/**
程序运行示例:
———————————————————————————
20
————————————————————————————
*/
}
}
super()相关
class A
{
public int i;
public int j;
public A()
{
}
public A(int i,int j)
{
this.i = i;
this.j = j;
}
}
class B extends A
{
public int k;
public void f(int i)
{
// super(i);
/**
程序运行示例:
———————————————————————————————————————
M.java:22: 错误: 对super的调用必须是构造器中的第一个语句
super(i);
^
1 个错误
————————————————————————————————————————
*/
}
public B(int i,int j,int k)
{
// this.i = i; //一定要明白为什么i前面可以加this
// this.j = j;
// A(i,j);
/**
程序运行示例:
———————————————————————————————————————
M.java:24: 错误: 找不到符号
A(i,j);
^
符号: 方法 A(int,int)
位置: 类 B
1 个错误
————————————————————————————————————————
*/
// super(i,j);//OK
/**
程序运行示例:
———————————————————————————————————————
10 39 22
————————————————————————————————————————
*/
this.k = k;
}
}
class M
{
public static void main(String[] args)
{
B bb = new B(10,39,22);
System.out.printf("%d %d %d\n",bb.i,bb.j,bb.k);
}
}
上述代码总结:
1、 每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候 就会报错。
2、如果显示的写出super()语句,则必须保证该语句是第一条语句,否则会出错
3、super();如果不写,则编译器会自动添加,所以此时如果父类没有无参的构造函数就会出错。
4、既可以显示写super();前提是父类必须有无参的构造函数
5、调用父类的构造函数的语句必须借助于super(),不能直接写父类的的类名,该与C++不同
6、一个构造函数中不能写多个super(参数列表)语句;
总结
- 私有不能被继承
- 私有物理上已经被继承过来,只不过逻辑上程序员不能去访问它
- 因此继承必须慎重,否则会浪费内存
- Java只支持单继承,不允许多重继承(这一缺陷通过接口来稍稍弥补了一下)
- 单继承就是一个类只能有一个父类
- 多继承就是一个类可以多个父类
- 可以有多层继承,即一个类可以继承某一个类的子类,如类B继承了类A,类C又可以继承类B,那么类C也间接继承了类A
- 子类可以继承父类所有的成员变量和成员方法,但子类永远无法继承父亲的构造方法,在子类的构造方法中可使用语句super(参数列表)调用父类的构造方法。