[JAVA学习笔记] 类与对象 - 继承

OOP的继承特性使OOP语言的代码具有可拓展性,拓展类也称为继承(inheritance)或子类化(subclass)。在Java中,默认情况下所有类都是可以拓展的,也可以使用final关键子来防止类被子类化。

extends

在类声明时我们使用extends关键字来拓展类,其位置位于子类名后,父类名前,例如:

public class Child entends Parents{
    ......
}

所有没有拓展父类的Java类都将自动拓展java.lang.Object类作为父类,即Object是Java中的最终超类,在上面的代码中,Parents的父类就是Object

is-a关系

子类和超类具有is-a关系,例如Fruit类包含所有水果,那么Peach、Orange、Banana都是Fruit类的子类,因此Peach、Orange、Banana与Fruit便是is-a关系。
is-a关系不可逆,我们可以说Peach是Fruit,但是不能说Fruit就是Peach,在代码中我们可以这么理解:

public class Fruit{
    public void eat();  //Fruit具有eat的方法
}

class Peach extends Fruit{ //Peach是Fruit的子类
    public void pink();
    //Peach具有pink的方法,但是也继承了eat的方法
}

Fruit peach1 = new Peach(); //Peach是Fruit的子类,存在is-a关系
Peach peach2 = new Peach();  //正常创建对象
Peach fruits = new Fruit(); //由于is-a关系不可逆,因此这行代码是错误的!

子类继承了其超类所有的公共方法和字段,以上面的代码为例,存在如下的情况:

Peach aPeach = new Peach();
aPeach.eat();  //Peach继承了Fruit的eat方法

可访问性

在子类中我们可以访问其超类的publicprotected级别的方法和字段,但是不能访问private级别的方法和字段,如果子类和超类位于同一个包中,子类也可以访问到超类默认级别的方法和字段。例如:

public class A{
    public static int test1(){...};
    protected static int test2(){...};
    private static int test3(){...};
}

class B extends A{
    public void test(){
        test1();  //B可以访问到A的public方法
        test2(); //B可以访问到A的protected方法
        test3(); //B无法访问到A的private方法
    }
}

同时这种关系是子类与父类间的,我们无法通过A的子类B来访问到A的非公开方法,例如在上面的代码基础上:

public class C{
    public static void main(String[] args){
        B obj = new B();
        obj.test2();  //无法编译,无法从外部访问A的protected方法
    }
}

重写与重载

重载不等同于重写:方法的重写发生在父类与子类中,而重载发生在本类;重载的方法名必须相同,重写的方法名相同且返回值类型必须相同;重载的参数列表不同,重写的参数列表必须相同。

方法重载

方法重载的定义是如果有两个方法的方法名相同,但参数不一致,哪么可以说一个方法是另一个方法的重载
对于定义我们可以有以下的理解:

  • 方法名相同
  • 方法的参数类型,参数个数不同
  • 方法的返回类型可以不相同
  • 方法的修饰符可以不相同
  • main方法也可以被重载

方法重载例子如下:

public class Person {

    String name;   //name字段
    int age;     //age字段

    public Person(){   //无参构造方法,命名与类名一致
        this.name = "Jack";
        this.age = 18;
    }

    public Person(String name){    //重载 构造方法1(含一个参数name)
        this.name = name;
        this.age = 18;
    }

    public Person(String name, int age){  //重载 构造方法2(含两个参数name,age)
        this.name = name;
        this.age = age;
    }

    public static void main(String[] args) {
        Person mine = new Person();  //创建对象引用mine,此时调用 无参构造方法
        Person he = new Person("Lucy");  //创建对象引用he,此时调用构造方法1
        Person anybody = new Person("Helen", 3); //创建对象引用anybody,此时调用构造方法2
        System.out.println("My name is " + mine.name + " and age is " + mine.age);   //输出mine对象的字段
        System.out.println("His name is " + he.name + " and age is " + he.age);   //输出he对象的字段
        System.out.println("Your name is " + anybody.name + " and age is " + anybody.age);  //输出anybody的字段
    }

}

方法重写

当拓展一个类时,我们可以在子类中修改父类的方法,这个操作便称为方法的重写,但是子类中编写的方法与父类的方法要具有相同的签名(相同返回类型,名称相同,参数列表相同)。需要注意的是重写时方法的权限可以从低到高,但是不能从高到低,也就是说,子类重写方法的权限不能低于父类被重写方法原本的权限
权限的大小顺序如下:Public > Protected > 默认 > private
和继承的权限特点是相同的,我们可以在子类中重写父类publicprotected级别的方法,如果父子类位于同一个包中,也可以重写默认级别的方法。

public class Override{
    public static void main(String[] args){
        System.out.println("This is Class A print:");
        A a = new A();
        a.echo("Test");
        System.out.println("This is Class B print:");
        A b = new B();
        b.echo("Test");
    }

}

class A{
    public void echo(String str){
        System.out.println(str);
    }
}

class B extends A{
    public void echo(String str){
        System.out.println("Override is " + str);
    }
}

运行结果如下

超类的调用

我们可以通过super关键字来实现在子类中对超类成员的调用,以菜鸟教程的例程为例:

class Country {
    String name;
    void value() {
       name = "China";
    }
}
  
class City extends Country {
    String name;
    void value() {
        name = "Shanghai";
        super.value();  //调用父类的方法
        System.out.println(name);
        System.out.println(super.name);
    }
  
    public static void main(String[] args) {
       City c=new City();
       c.value();
    }
}

调用超类的构造方法:

class Person { 

    //构造方法(1) 
    Person() { 
        System.out.println("父类无参数构造方法"); 
    }
    
    //构造方法(2) 
    Person(String name) { 
       System.out.println("父类含一个参数的构造方法:" + name); 
    }
} 
    
public class Chinese extends Person { 
    Chinese() { 
       super();  //调用父类构造方法(1) 
       System.out.println("调用父类无参数构造方法"); 
    } 
    
    Chinese(String name) { 
       super(name); //调用父类具有相同形参的构造方法(2) 
       prt("调用父类含一个参数的构造方法:" + name); 
    } 
    
    
    public static void main(String[] args) { 
       Chinese cn = new Chinese(); 
       cn = new Chinese("codersai"); 
    } 
}

转换

将子类的一个实例转换为他的父类类型,这个过程称为向上转换(upcast)。相反,将一个类的实例类型转换为其子类的类型便叫做向下转换(downcast)

class Parents{
    ......
}

class Child extends Parents{
    ......
}

public class Cast{
    public static void main(String[] args){
        //向上转换
        Child child1 = new Child();
        Parents parents1 = child1;   //由Child类型的child1变为Parents类型的parents1
        //向下转换
        //只有当父类引用已经指向子类实例时才能进行向下转换
        Parents parents = child1;  //parents指向了Child的一个实例
        //向下转换强制要求在括号内写入子类型
        Child child2 = (Child) parents;  //由Parents类型的parents变为Child类型的child2
    }
}

final类

类声明中,我们使用final可以使其变为最终类,无法被继续继承和拓展。

instanceof

instanceof运算符可以检验某个对象是否是指定的类型,常用于if语句中,例如

public class Test{
    public static void main(String[] args){
        String a = "Ye";
        if (a instanceof java.lang.String){
            System.out.println("Yes");
        }else{
            System.out.println("No");
        }
    }
}

同时,子类也是属于其父类的类型,因此也可以判断一个实例是否属于某个父类类型中。

class Parten{
    ......
}

class Child extends Partens{
    ......
}

public class Test{
    public static void main(String[] args){
        Child child = new Child();
        if (child instanceof Parents){  //判断child实例是否属于Parents类型
            System.out.println("Yes");
        }else{
            System.out.println("No");
        }
    }
}
posted @ 2021-09-08 04:43  Ye'sBlog  阅读(160)  评论(0编辑  收藏  举报