[学习笔记]Java继承机制

来源:互联网 发布:淘宝直播快速申请成功 编辑:程序博客网 时间:2024/05/01 18:33

类间关系

在类之间,常见有三种关系:依赖(uses-a),聚合(has-a),继承(is-a)。
如果一个类的方法需要操作另一个类的对象,就称之为一个类依赖于另一个类,比如订单的生成需要查看账户的信用状况,比如员工类的工作需要操作公司电脑类等。应该尽可能减少类之间的依赖关系,降低耦合性,提高程序健壮性。
如果一个类包含另一个类,就称之为聚合关系,比如订单类包含了物品项,比如汽车类包含了发动机类等。
如果一个类是另一个类的一种,就称之为继承关系,比如程序员是员工的一种,数学老师是老师的一种,员工或者老师的属性和行为程序员和数学老师都具备。

继承

概述

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承单独的那个类即可。这时,那个单独类就是父类,而剩下的都是继承了这个父类的子类。

格式

class Son extends Father {}
子类可以直接访问父类中的非私有的属性和行为。

作用

1. 继承的出现提高了代码的复用性。
2. 继承的出现让类与类之间产生了关系,提供了多态的前提。
3. 继承也同样破坏了封装性,可以适当使用final和private关键字限制子类对父类数据的操作。

千万不要为了获取其他类的功能简化代码而继承。必须类间有所属关系“is a”才可以继承。

多继承和多实现

1. Java只支持单继承,不支持多继承(多父类),但是可以多层继承(可以有父亲,爷爷,曾祖等)。
2. 因为多继承容易带来安全隐患:当多个父类定义相同方法,则子类对象不确定运行哪一个。但是Java保留了这种机制,并用另一种体现形式来表示:多接口实现。

使用步骤

1. 要想使用一个继承体系中的功能,先查阅父类的描述,通过了解共性方法,就可以知道该体系的基本功能,这个体系已经可以基本使用了。
2. 在具体调用时,要创建最子类的对象。因为:1. 可能父类不能创建对象。2. 创建子类对象可以使用更多功能,包括基本的和特有的,即查阅父类功能,创建子类对象使用功能。

继承限制

  1. 构造器均为私有的类不可以被继承。
  2. 声明为final的类不可以被继承。
  3. 枚举类不可以被继承。

继承对成员数据的影响

实例域

如果子类中出现非私有同名实例域,访问子类变量用this,访问父类变量用super,俩引用均在方法区。

方法

如果子类中出现非私有一模一样的方法,子类对象调用该方法会运行子类方法,父类方法被重写。可以使用重写(覆盖)特性,保留父类功能定义,并重写功能内容来实现。比如升级更新,使用继承加重写的方式来升级,不可修改以往源程序代码。

重写(覆盖)

  1. 方法重写,参数列表必须完全与被重写方法的相同。
  2. 方法重写,返回值类型必须完全与被重写方法的相同。
  3. 方法重写,必须保证方法权限不小于被重写方法权限。
  4. 声明为final的方法不能被重写。
  5. 声明为static的静态方法不能被继承,也不能被重写,但可以重新定义,建议直接用类名调用。
  6. 如果一个方法不能被继承(比如私有方法),那么该方法不可以被重写。
  7. 重写的方法不可以抛出被重写方法没有声明的新的强制性异常,也不可以抛出比父类声明的更广泛的强制性异常,如果需要,应在内部捕捉处理。
  8. 重写推荐加上@Override标志。

重写和重载的区别

  1. 重写实现了父类子类间方法的多态性,提高程序的灵活性和扩展性。
    重载提高一个类中方法的灵活性和扩展性。
  2. 重写不可以更改参数列表。
    重载的参数列表则必须不一致。
  3. 重写不可以更改返回值类型。
    重载则无限制。
  4. 重写方法的访问权限不可以小于被重写方法的权限。
    重载则无限制。
  5. 重写方法不可以抛出父类未声明的异常,也不可以抛出比父类声明异常更广泛的异常。
    重载则无限制。

构造器

子类构造器第一行有条隐式语句:super();,即先执行父类空参数构造器,再执行子类构造器。
因为父类中的数据子类可以直接使用,所以子类对象建立时,需要先查看父类如何对数据进行初始化,即需要先访问父类的无参数构造器。如果要访问父类中指定的构造器,可以手动定义super语句方式来指定。

一般面向对象注重封装,所以实例域私有化,并提供方法访问,一般子类中直接调用父类中的构造器和方法。

注意

1. 子类构造器中一定有且仅有一个super或this方法,并且一定在第一行的位置。
2. 子类所有的构造器,默认都会访问父类中空参数构造器,因为子类每一个构造器内的第一行都有一句隐式super();当父类中没有空参数构造器时,子类必须手动通过super或者this语句形式来指定要访问的构造器。子类实例化肯定会访问父类中的构造器。

示例

class Father {
int x = 1;
 
Father() {
System.out.println("Father Class create!");
}
 
Father(double x) {
System.out.println("Father Class double create!");
}
 
Father(String x) {
System.out.println("Father Class String create!");
}
 
void show() {
System.out.println("show in Father: x = " + x);
}
}
 
class Son extends Father {
int x = 2;
 
Son() {
// 隐式super();
System.out.println("Son Class create!");
}
 
Son(int x) {
// 隐式super();
System.out.println("Son Class Int create!");
}
 
Son(String x) {
// 显式调用Father类构造器,此时无隐式super();
super(x);
}
 
void show() {
super.show();
System.out.println("x = " + x);
System.out.println("super.x = " + super.x);
}
}
 
public class ExtendsDemo {
public static void main(String[] args) {
Son s1 = new Son();
System.out.println("s1.x = " + s1.x);
System.out.println("------------------");
Son s2 = new Son(5);
System.out.println("------------------");
// Son s3 = new Son(5.5); //错误,子类没有浮点数参数构造器
Son s4 = new Son("a");
System.out.println("------------------");
s4.show();
}
}

运行结果

Father Class create!
Son Class create!
s1.x = 2
------------------
Father Class create!
Son Class Int create!
------------------
Father Class String create!
------------------
show in Father: x = 1
x = 2
super.x = 1

Object类

概述

Object是所有对象的直接或间接父类,传说中的上帝。该类中定义的肯定是所有对象都具备的功能。

作用

1. 可以重写父类方法,实现特定需求。
2. 可以向上转型为Object类,实现多种类的统一操作,提高程序扩展性。(多态)

示例

/*
* Object是所有对象的直接或间接父类,传说中的上帝。
* 该类中定义的肯定是所有对象都具备的功能。
*/
 
class Demo // extends Object
{
private int num;
 
Demo(int num) {
this.num = num;
}
 
public boolean equals(Object obj) // 覆盖Object类的equals函数,传入参数向上转型
{
if (!(obj instanceof Demo))
return false;
else {
return this.num == ((Demo) obj).num; // 使用子类成员变量,向下转型
}
}
}
 
 
class D {}
 
 
public class ObjectDemo {
public static void main(String[] args) {
Demo d1 = new Demo(1);
Demo d2 = new Demo(1);
D d = new D();
System.out.println("d1.equals(d2) = " + d1.equals(d2));
System.out.println("d1.equals(d) = " + d1.equals(d));
System.out.println("d.equals(d1) = " + d.equals(d1));
System.out.println("d1.toString() = " + d1.toString());
System.out.println("自定义toString():" + d1.getClass().getName() + "@"
+ Integer.toHexString(d1.hashCode()));
}
}

运行结果

d1.equals(d2) = true
d1.equals(d) = false
d.equals(d1) = false
d1.toString() = Demo@15db9742
自定义toString():Demo@15db9742
0 0
原创粉丝点击