Java基础知识(9)- 面向对象(一)

继承(Extends)、重写(Override)、重载(Overload)


1. 继承(Extends)

    1) 继承的概念

        继承是 Java 面向对象编程技术的一块基石,因为它允许创建分等级层次的类。

        继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

        类的继承格式:

            class Parent {
            }
    
            class Sub extends Parent {
            }

        使用关键字 extends ,子类 Sub 继承了父类 Parent。


    2) 继承的特点

        (1) 子类继承了父类所有非 private 的属性和方法。
        (2) 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
        (3) 子类可以用自己的方式重写父类的方法。
        (4) Java 的继承是单继承,但是可以多重继承:
            a) 单继承就是一个子类只能继承一个父类,即子类只能有一个直接父类,extends 关键字后面只能有一个类名;
            b) 多重继承,列如:类A的有自己的子类 B,B可以自己的子类C,C可以 ...
        (5) 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系紧密,代码独立性差)。


    3) IS-A 关系

        IS-A:一个对象是另一个对象的一个分类。

        下面是使用关键字 extends 实现继承。

            class Human {
            }

            class Male extends Human {
            }

            class Boy extends Male {
            }

        基于上面的例子,以下说法是正确的:

            Human 类是 Male 类的父类, Male 类是 Human 类的子类。
            Boy 类既是 Male 类的子类又是 Human 类的子类。

        分析以上示例中的 IS-A 关系,如下:

            Man IS-A Human
            Boy IS-A Male
            因此: Boy IS-A Human

        通过使用 instanceof 关键字,能够确定 Male,Boy 是 Human 类的实例, 也就是 IS-A Human。

1 public static void main(String args[]) {
2     Male m = new Male();
3     Boy b = new Boy();
4     System.out.println(m instanceof Human);
5     System.out.println(b instanceof Human);
6 }

        输出:

            true
            true


    4)HAS-A 关系

        HAS-A 代表类和它的成员之间的从属关系。

            class Group {}

            public class Boy extends Male {
                private Group group;
            }

        Boy 类和 Group 类是 HAS-A 关系( Boy 有一个 group),这样就不用将 Group 类的全部代码粘贴到 Boy 类中了,并且 Group 类也可以重复使用到其它类中。


    5) 关键字

        继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。

        (1) extends关键字

            在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,extends 只能继承一个类。

        (2) implements关键字

            使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)

        (3) instanceof 关键字

            使用 instanceof 关键字判断一个对象是否为一个类(或接口、抽象类、父类)的实例,语法格式如下所示。

                boolean result = obj instanceof Class

            其中,obj 是一个对象,Class 表示一个类或接口。obj 是 class 类(或接口)的实例或者子类实例时,结果 result 返回 true,否则返回 false。

            下面 instanceof 关键字的几种用法:

                (1) 声明一个 class 类的对象,判断 obj 是否为 class 类的实例对象(很普遍的一种用法);
                (2) 声明一个 class 接口实现类的对象 obj,判断 obj 是否为 class 接口实现类的实例对象;
                (3) obj 是 class 类的直接或间接子类

        (4) super 关键字

            子类不能继承父类的构造方法,如果要调用父类的构造方法,可以使用 super 关键字。super 可以用来访问父类的构造方法、普通方法和属性。

            super 关键字的功能:
                (1) 在子类的构造方法中显式的调用父类构造方法
                (2) 访问父类的成员方法和变量。

        (5) this 关键字

            当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配一个引用自身的指针,这个指针的名字就是 this。

            this 的作用:

                (1) 使用 this 来区分当前对象,比如在构造函数和对象实例的方法中,实例变量和局部变量名字冲突时,可以给实例变量加上 this. 前缀;
                (2) 在构造器中使用 this 来调用对象本身的其他构造器;
                (3) 返回类的引用。如在代码中,可以使用return this来返回某个类的引用。此时,这个this关键字就代表类的名称;

            不能在 static 方法中使用 this 关键字。

            Static 方法是类方法,先于任何的实例(对象)存在。即Static方法在类加载时就已经存在了,但是对象是在创建时才在内存中生成,而 this 指代的是当前对象。

            在方法中定义使用的this关键字,它的值是当前对象的引用.也就是说你只能用它来调用属于当前对象的方法或者使用this处理方法中成员变量和局部变量重名的情况.

            而且 this 和 super 都无法出现在 static 修饰的方法中,static 修饰的方法是属于类的,该方法的调用者可能是一个类,而不是对象。

        (6) final 关键字

            final 关键字声明类可以把类定义为不能继承,用于修饰方法,该方法不能被子类重写:

            声明类:

                final class 类名 {//类体}

            声明方法:

                修饰符(public/private/default/protected) final 返回值类型 方法名() {//方法体}

            注: 实例变量也可以被定义为 final,被定义为 final 的变量不能被修改。被声明为 final 类的方法自动地声明为 final,但是实例变量并不是 final。


    6) 构造函数

        构造函数(或称构造方法,或称构造器),是一种特殊的方法。主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总与 new 运算符一起使用在创建对象的语句中。
        
        构造函数的作用和特点:

            (1) 构造函数的主要作用是完成对象的初始化工作;
            (2) 构造函数的名称必须与类名相同,包括大小写;
            (3) 构造函数没有返回值,也不能用 void 修饰;
            (4) 一个类可以定义多个构造方法,如果在定义类时没有定义构造方法,则编译系统会自动插入一个无参数的默认构造器,这个构造器不执行任何代码;
            (5) 构造方法可以重载,以参数的个数、类型或顺序的不同;


2. 重写(Override)

    在子类中如果创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为方法重写(Override),又称为方法覆盖。

    当父类中的方法无法满足子类需求或子类具有特有功能的时候,需要方法重写。

    下面程序演示了重写:

 1 class Male extends Human {
 2 
 3     public void display() {
 4     }
 5 
 6     public static void test() {
 7     }
 8 }
 9 
10 class Boy extends Male {
11 
12     @Override
13     public void display() {
14     }       
15 
16     // 父类的 static 方法不能被重写,可以被再次声明和定义
17     //@Override
18     public static void test() {
19     }
20 }

 

    1)@Override

    是伪代码,表示方法重写, 使用 @Override 标签的好处:

        1) 作为注释,帮助自己检查是否正确的复写了父类中已有的方法;
        2) 便于别人理解代码;
        3) 编译器可以给你验证 @Override 下面的方法名是否是你父类中所有的,如果没有则报错;


    2) 重写的规则

        (1) 参数列表与被重写方法的参数列表必须完全相同;
        (2) 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同);
        (3) 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected;
        (4) 父类的成员方法只能被它的子类重写;
        (5) 声明为 final 的方法不能被重写;
        (6) 声明为 static 的方法不能被重写,但是能够被再次声明和定义,父类和子类有各自同名的 static 方法;
        (7) 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法;
        (8) 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法;
        (9) 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以;
        (10) 构造方法不能被重写;


3. 重载(Overload)

    重载(Overload) 是在一个类里面,方法名字相同,而参数不同,返回类型可以相同也可以不同。最常用的地方就是构造函数的重载。

    下面程序演示了重写:

 1 public class Male extends Human {
 2 
 3     @Override
 4     public void display() {
 5     }
 6 
 7     // 重载本类的 display()
 8     public void display(String str) {
 9     }  
10 }   


    1) 重载的规则

        (1) 被重载的方法必须改变参数列表(参数个数或类型不一样);
        (2) 被重载的方法可以改变返回类型;
        (3) 被重载的方法可以改变访问修饰符;
        (4) 被重载的方法可以声明新的或更广的检查异常;
        (5) 方法能够在同一个类中或者在一个子类中被重载;
        (6) 无法以返回值类型作为重载函数的区分标准;


    2) 重载与重写的区别

        项目         重载方法    重写方法
        参数列表    必须修改    不能修改
        返回类型    可以修改    不能修改
        异常          可以修改    可以减少或删除,一定不能抛出新的或者更广的异常
        访问          可以修改    不能做更严格的限制(可以降低限制)

实例:

  1 public class App {
  2     public static void main( String[] args ) {
  3 
  4         Male m = new Male("Male name");
  5         Boy b = new Boy("Boy name");
  6         System.out.println("Male is an instance of Human: " + (m instanceof Human));
  7         System.out.println("Boy is an instance of Human: " +(b instanceof Human));
  8 
  9         b.display();
 10         b.display("Boy: Overload display(String str)");
 11         b.displayParent();
 12 
 13         b.test();   // Boy 类的 static test()
 14         Male m2 = b;
 15         m2.test();  // Male 类的 static test()
 16     }
 17 }
 18 
 19 // final 类不能继承, 即最终类
 20 final class Group {
 21 
 22 }
 23 
 24 class Human {
 25     private String name;
 26 
 27     // 构造函数
 28     public Human(String name) {
 29         // this 指向自己的引用
 30         this.name = name;
 31     }
 32 
 33     public String getName() {
 34     return name;
 35     }
 36 
 37     public static void test() {
 38         // 不能在 static 方法中使用 this 关键字
 39         //System.out.println("Human: test() -> name = " + this.name);
 40     }
 41 }
 42 
 43 class Male extends Human {
 44 
 45     // 构造函数
 46     public Male(String name) {
 47         super(name);
 48     }
 49 
 50     public String getName() {
 51         return super.getName();
 52     }
 53 
 54     // final 方法不能被子类重写(Override)
 55     final public void testFinalFunction() {
 56         System.out.println("Male: test final function");
 57     }
 58 
 59     public void display() {
 60         System.out.println("Male: display()");
 61     }
 62 
 63     // static test() 方法不能被子类重写(Override)
 64     public static void test() {
 65         System.out.println("Male: static test()");
 66     }
 67 }
 68 
 69 class Boy extends Male {
 70     // final 类 Group 不能被继承,
 71     // 一般作为实例变量或类变量使用
 72     private Group group;
 73 
 74     // 构造函数
 75     public Boy(String name) {
 76         // 使用 super 调用父类构造方法
 77         super(name);
 78     }
 79 
 80     public String getName() {
 81         // 访问父类的成员方法
 82         return super.getName();
 83     }
 84 
 85     /*
 86     // 不能重写(Override)父类的 final 方法
 87     @Override
 88     public void testFinalFunction() {
 89         System.out.println("Boy: test final function");
 90     }
 91     */
 92 
 93     // 重写(Override)
 94     @Override
 95     public void display() {
 96         System.out.println("Boy: Override display()");
 97     }
 98 
 99     // 重载(Overload)
100     public void display(String str) {
101         System.out.println(str);
102     }
103 
104     // 使用 super 关键字可以调用父类的被重写方法
105     public void displayParent() {
106         super.display();
107     }
108 
109     // 父类的 static test() 方法不能被重写(Override),可以被再次声明和定义
110     //@Override
111     public static void test() {
112         System.out.println("Boy: static test()");
113     }
114 }


输出:

    Male is an instance of Human: true
    Boy is an instance of Human: true
    Boy: Override display()
    Boy: Overload display(String str)
    Male: display()
    Boy: static test()
    Male: static test()

上一篇:Java多态


下一篇:关于多态的理解