继承理论说明:
- 继承主要解决的问题就是:共性的抽取,实现代码复用
- Java中提供一个关键字
extends
,用这个关键字,我们可以让一个类和另一个类建立起父子关系
关于继承如下 3 点请记住:
- 1、子类拥有父类对象所有的属性和方法(包括
私有属性
和私有方法
),但是父类中的私有属性和方法子类是无法访问,只是拥有。- 2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
- 3、子类可以用自己的方式实现父类的方法。
Q&A
Q:子类是否可以继承父类的构造器?
A:不可以,子类有自己的构造器,父类构造器用于初始化父类对象。
Q:子类是否可以继承父类的私有成员?
A:可以,只是不能直接访问。
Q:子类是否可以继承父类的静态成员?
A:子类可以直接使用父类的静态成员,但是不能继承父类的静态成员(共享并不是继承)。
Q:Java中为什么不支持多重继承?
A:若子类继承的两个父类中有一个同名方法时,无法选择调用哪一个方法。
Q:Java中为什么支持多层继承(A继承B,B继承C)?
A:即使B和C中有同名方法,A可以通过就近原则来调用B的方法。
上实例:
父类
解释:父类中有构造方法、静态方法、实例方法
public class A {
public A() {
System.out.println("大家好,这是【父类-A】的【构造方法】");
}
// 父类A的静态类方法
public static void sayHello() {
System.out.println("大家好,这是【父类-A】的【静态】类方法");
}
// 父类A的实例方法
public void sayHello2() {
System.out.println("大家好,这是【父类-A】的【实例】方法");
}
}
子类
解释:子类中有构造方法、与父类同名的静态方法、重写父类的方法
public class B extends A {
public B() {
System.out.println("大家好,这是【子类-B】的【构造方法】");
}
// 子类B静态类方法
public static void sayHello() {
System.out.println("大家好,这是【子类-B】的【静态方法】");
}
// 子类B的实例方法
public void sayHello2() {
System.out.println("大家好,这是【子类-B】的【实例方法】");
}
}
测试
第一种情况:
public static void main(String[] args) {
B b = new B();
System.out.println("--------");
A a = new B();
}
执行结果:
大家好,这是【父类-A】的【构造方法】
大家好,这是【子类-B】的【构造方法】
--------
大家好,这是【父类-A】的【构造方法】
大家好,这是【子类-B】的【构造方法】
第二种情况:(静态方法)
public static void main(String[] args) {
B b = new B();
A a = b;
System.out.println("----");
A.sayHello();
a.sayHello();
System.out.println("======");
B.sayHello();
b.sayHello();
}
执行结果:
大家好,这是【父类-A】的【构造方法】
大家好,这是【子类-B】的【构造方法】
----
大家好,这是【父类-A】的【静态】类方法
大家好,这是【父类-A】的【静态】类方法
======
大家好,这是【子类-B】的【静态方法】
大家好,这是【子类-B】的【静态方法】
如果注掉子类B的静态方法(就是去掉),
执行结果:
大家好,这是【父类-A】的【构造方法】
大家好,这是【子类-B】的【构造方法】
----
大家好,这是【父类-A】的【静态】类方法
大家好,这是【父类-A】的【静态】类方法
======
大家好,这是【父类-A】的【静态】类方法
大家好,这是【父类-A】的【静态】类方法
说明:
1、静态方法不能继承
2、如果父类中有静态方法,子类中没有,但是子类可以调用父类的静态方法
3、如果父类中有静态方法,子类中也有跟父类相同的静态方法,那么父类不管是 类名调用 还是 实例调用 都是调用的父类的静态方法
子类不管是 类名调用 还是 实例调用 都是调用子类的静态方法
第三种情况:(成员方法)
public static void main(String[] args) {
A a = new B(); // 创建子类对象 指向 父类
a.sayHello2();
System.out.println("------");
A a1 = new A(); // 创建父类对象
a1.sayHello2();
System.out.println("=======");
B b = new B(); // 创建子类对象
b.sayHello2();
}
执行结果:
大家好,这是【父类-A】的【构造方法】
大家好,这是【子类-B】的【构造方法】
大家好,这是【子类-B】的【实例方法】
------
大家好,这是【父类-A】的【构造方法】
大家好,这是【父类-A】的【实例】方法
=======
大家好,这是【父类-A】的【构造方法】
大家好,这是【子类-B】的【构造方法】
大家好,这是【子类-B】的【实例方法】
成员变量、成员方法的调用
在子类方法中访问成员(成员变量、成员方法)满足:
就近原则
- 先在
子类局部
范围找- 然后在
子类成员
范围找- 最后在
父类成员
范围找,如果父类范围还没有找到则报错- 如果子类和父类中有
同名变量
,根据就近原则
访问的是子类
的成员变量,另外也可以通过关键字来访问该成员变量(子类使用this.变量名
,父类使用super.变量名
)
子类访问父类私有成员变量
上面说:子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有
那么我们怎么才能访问到父类的私有属性呢?
class A{ //父类A
private int value=10; //声明一个私有变量value并赋值为10
public int getvalue() { //声明一个公有成员方法getvalue,返回value
return value;
}
}
class B extends A{ //A的子类B
}
public class myfirst {
public static void main(String[] args) {
B b=new B(); //创建子类B的一个实例对象
System.out.println("子类通过父类提供的公共接口访问A中的私有字段value:"+b.getvalue());
}
}
执行结果:
子类通过父类提供的公共接口访问A中的私有字段value:10
使用super关键字
- 1、使用
super
调用父类中重写的方法、访问父类中被隐藏的字段
子类重写了父类中的某一个方法,隐藏父类中的字段,假如想在子类中访问到父类中被重写的方法和隐藏父类的字段,可以在子类中通过使用关键字super来调用父类中被重写的方法和访问父类中被隐藏的字段。例如:
package first;
class A{
public String name="张飞"; //添加成员变量
public void say() { //添加成员方法say
System.out.println("我是父类A成员方法say");
}
}
class B extends A{
public String name="关羽"; //与父类中同名的字段,隐藏父类
public void say(){ //重写方法say
super.say(); //使用super关键字调用父类中的方法
System.out.println("我是子类B成员方法say");
System.out.println("父类的name名字:"+super.name); //使用super关键字访问父类中的变量
}
}
public class myfirst {
public static void main(String[] args) {
B b=new B(); //创建子类的一个实例对象
b.say(); //调用子类中重写的方法
System.out.println("子类的name名字:"+b.name); //调用子类中的name
}
}
执行结果:
我是父类A成员方法say
我是子类B成员方法say
父类的name名字:张飞
子类的name名字:关羽
- 2、使用super调用父类的无参数构造方法/有参数构造方法
子类不继承其父类的构造方法。
- 当使用无参数的super()时,父类的无参数构造方法就会被调用;
- 当使用带有参数的super()方法时,父类的有参数构造方法就会被调用。
class SuperClass { //创建父类SuperClass
private int n; //声明一个私有变量n
SuperClass(){ //父类无参数构造方法
System.out.println("这是父类SuperClass无参数构造方法");
}
SuperClass(int n) { //父类有参数构造方法
System.out.println("这是父类SuperClass有参数构造方法");
this.n = n;
}
}
class SubClass extends SuperClass{ // SubClass类继承SuperClass类
private int n; //声明一个私有变量n
SubClass(){ // 自动调用父类的无参数构造器
System.out.println("这是子类无参数构造方法");
}
public SubClass(int n){ //子类有参数构造方法
super(300); //调用父类中带有参数的构造器
System.out.println("这是子类有参数构造方法"+n);
this.n = n;
}
}
public class myfirst {
public static void main(String[] args) {
SubClass sc1 = new SubClass(); //创建子类SubClass实例对象,调用其无参数构造方法
SubClass sc2 = new SubClass(100); //创建子类SubClass实例对象,调用其有参数构造方法
}
}
执行结果:
这是父类SuperClass无参数构造方法
这是子类无参数构造方法
这是父类SuperClass有参数构造方法
这是子类有参数构造方法100
注意:
- 如果要初始化父类中的字段,可以在子类的构造方法中通过关键字super调用父类的构造方法;
- 对父类的构造放的调用必须放在子类构造方法的第一行;
- 如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器;
- 如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表;
- 子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。
典型例题
public class A {
public A() {
System.out.println("1.A类的构造方法");
}
{
System.out.println("2.A类的构造块");
}
static {
System.out.println("3.A类的静态方法");
} }
public class B extends A {
public B() {
System.out.println("4.B类的构造方法");
}
{
System.out.println("5.B类的构造块");
}
static {
System.out.println("6.B类的静态方法");
} } public static void main(String[] args) {
System.out.println("7.start......");
new B();
new B();
System.out.println("8.end.....");
}
执行结果:
7.start......
3.A类的静态方法
6.B类的静态方法
2.A类的构造块
1.A类的构造方法
5.B类的构造块
4.B类的构造方法
2.A类的构造块
1.A类的构造方法
5.B类的构造块
4.B类的构造方法
8.end.....
参考:
https://blog.csdn.net/weixin_52122271/article/details/114285424