Java特性之继承

1、初步理解继承

1)我们假设有一个Person类和一个Student类。从现实生活的来看,Student是Person的一种,Student有着Person的一些属性和方法。所以我们在已经写好Person类的前提下再写Student类的时候就可以用到继承机制。继承后,Student获得Person的全部功能(属性和方法),我们只需在Student类中写其特有功能。

2)在OOP的术语中,我们把Person称为超类(super class),父类(parent class),基类(base class),把Student称为子类(subclass),扩展类(extended class)。

2、怎么实现继承?

通过extends关键字

class Person {
    //属性
    //方法
}

class Student extends Person {
    //新增的特有属性
    //新增特有方法
}

3、继承树

1)我们在定义Person类的时候没有使用extends,是因为在Java中,没有明确写出extends的类,编译器默认加上extends Object。也就是说,Person类是继承自Object类的。除了Object,其他的类都会继承自某个类。这里的继承关系是:Object-->Person-->Student       

2)Java中规定一个类只能继承自一个父类,一个类不可以有多个父类。但是可以有多个类继承自同一个类。(就好像一个儿子只能有一个父亲,而一个父亲可以有多个儿子)。只有Object类特殊,它没有父类。 

3)在eclipse中,将光标停在想要查看的类名旁边,按ctrl+T,就可以看到类与类的继承关系了。

4、子类中属性的访问、protected

1)子类无法访问父类的private字段和方法。(非private字段是可以访问的)

class Person {
    private String name;
}

class Student extends Person {
    public String hello() {
        return "Hello, " + this.name; //像这样编译时就会报错
    }
}

2)要想让子类可以访问父类的字段,只需将父类中private修饰符改为protected。因此,protected可以把访问权限控制在继承树内部,被protected修饰的字段可以被其子类或者子类的子类所访问。

class Person {
    protected String name;
    protected int age;
}

class Student extends Person {
    public String hello() {
        return "Hello, " + this.name; //OK
    }
}

5、super关键字   

1)super关键字表示父类。子类在使用父类字段时使用super.name、this.name、name 效果都是一样的。

2)某些时候必须使用super关键字。例如:

class Person {
    protected String name;
    protected int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        this.score = score;
    }
}

public class Main {
    public static void main(String[] args) {
        Student s = new Student("zhangsan", 18, 0001);
    }
}

这样写会编译报错。错误提示无法在Studet类中调用Person类的构造方法。

其实,在Java中,任何class的构造方法,第一句必须是调用父类的构造方法。如果没有明确的写出调用,编译器会自动为我们加一句super(); (其实在source里面自动生成构造方法时自带的就有super();这条语句。)所以,实际上Student类是这样的:

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        super();// 调用父类构造方法
        this.score = score;
    }
}

这样做就结束了吗?在实际的操作下我们可以看到,在加上super();语句后还是报错的。super();是不带有参数的,它调用的是父类的无参构造方法。而Person类中没有无参构造方法,所以仍会报错。这里有两个解决办法:

①在Student类的构造方法中将属性赋值写全:

class Person {
    protected String name;
    protected int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        //super();写或不写都可
        this.score = score;
        //将其他成员赋值
        this.name = name;                  
        this.age = age;
    }
}

②在Student类中加入有参super语句:

class Person {
    protected String name;
    protected int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        super(name,age);// 添加有参super语句
        this.score = score;
    }
}

3)通过上面的解读我们认识到:1、super语句可以用来调用父类的构造方法。2、子类不会继承父类的构造方法。   

6、向上转型   

Person p = new Student();// 这句代码是OK的

1)这句代码与平时所见不同,以往我们见的应该是Person p = new Person();或者Student p = new Student(); 但是这里变量类型和创建的对象的类型不同。这是因为,Student类是从Person类继承下来的,Student类拥有Person类的全部功能,Person类型的变量可以指向Student类的实例。这样把一个子类型安全的转变为父类型的做法叫做向上转型。

2)Object p = new Student();也是可以的。也就是说可以转为更高层次的类型。

3)向上转型实际上是将一个子类型安全的转变为更为抽象的父类型。 

4)编译阶段p被认为是Person类型,不可以使用p调用Student类中的方法;运行阶段p被认为是Student类型。

7、向下转型   

1)相反的,如果把一个父类型强制转换为子类型就叫做向下转型。

2)怎么实现向下转型?

Person p1 = new Student();
Student s1 = (Student) p1;

Person类型的p1实际指向Student的实例所以在强制类型转换的时候可以成功。

Person p2 = new Person();
Student s2 = (Student) p2;

Person类型的p2实际指向了Person实例,在强制转换时失败。其实例还是个Person类,父类不能变成子类,子类的功能要比父类多,多的部分父类是无法补上的。

8、instanceof操作符

1)instanceof操作符可以判断一个变量是否为指定的类型。例如:

Person p = new Person();
System.out.println(p instanceof Person);// true

我们知道现在Student类是Person类的子类,判断类型的时候会因为继承而有所特殊吗?我们动手试试。

Student s = new Student();
System.out.println(s instanceof Student);// true
System.out.println(s instanceof Person);// true

我们惊奇的发现,s是Person类型。

2)由上面的实验我们可以得知,instanceof的实际作用是:判断一个变量指向的实例是否为指定的类型,或者是否为指定类型的子类。再举个例子说明:

Person p = new Student();

System.out.println(p instanceof Student);// true
//p的实例类型为Student。指定的类型是Student,自然为true

System.out.println(p instanceof Person);// true
//p的实例类型为Student。指定的类型是Person类型,Student是Person类型的子类,故结果也是true。

3)有了instanceof,我们在进行向下转型时就可以先判断变量的实例类型,如果实例类型是子类,那么转型一定成功。

Person p = new Student();
if(p instanceof Student){ 
    Student s = (Student) p;
}

9、继承和组合       

假设我们有一个Book类:

public class Book{
    protected String name;

    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
}

1)现在我们创建一个Student类,它能否继承Book类呢?答案是可以的。虽然在语法上没有错误,但是这在逻辑上是讲不通的,因为一个学生的父类不能是一本书,而应该是一个学生有一本书。这样的关系叫做组合。

2)继承是is关系,组合是has关系。

正确的写法是:

学生有一本书,就是学生类中可以有Book类的实例。

public class Student{
    protected Book book;
    protected int age;
}

                                                                                          End...                                                                                           

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值