从零开始学java--封装、继承和多态

面向对象基础篇

封装、继承和多态

......接上篇

类的继承

面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。

在定义不同类的时候存在一些相同属性,可将这些共同属性抽象成一个父类,在定义其他子类时可以继承自该父类,减少代码的重复定义,子类可以使用父类中非私有的成员。

首先定义一个父类,

接着可以创建各种子类,继承一个类使用extends关键字

public class Student extends Person{
}

类的继承可以不断向下,但是同时只能继承一个类。

标记为final的类不允许被继承:

public final class Person {  //class前面添加final关键字表示这个类已经是最终形态,不能继承
}

当一个类继承另一个类时,属性会被继承,可以直接访问父类中定义的属性,除非父类中将属性的访问权限修改为private,那么子类将无法访问(但依然是继承了这个属性的):

public class Student extends Person{
    public void study(){
        System.out.println("我是学生,我叫"+name); //可直接访问父类中name属性
    }
}

父类中定义的方法也会被子类继承,我们创建一个子类对象时可以直接使用这个方法:

public class Main {
    public static void main(String[] args) {
        Student student=new Student();
        student.study();  //子类自己的独特技能
        student.hello();  //继承了父类的全部技能
    }
}

子类构造方法:

如果父类存在一个有参构造方法,子类必须在构造方法中调用。

子类在构造时,不仅要初始化子类的属性,还需要初始化父类的属性(无参的情况下省略了):

父类:

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

则子类:

public class Student extends Person{
    protected Student(String name, int age, String sex) {
        super(name, age, sex);
    }
}

super()调用必须是构造函数主体中的第一条语句,在调用父类构造方法之前,不允许执行任何代码,只能在之后执行。

向上转型和向下转型:

我们在使用子类时,可以将其当作父类来使用:

    public static void main(String[] args) {
        Person person=new Student("小明",18,"男");//使用父类类型的变量,去引用一个子类对象(向上转型
        person.hello();  //父类对象的引用相当于当做父类来使用,只能访问父类对象的内容
    }

我们可以使用强制类型转换,将一个被当做父类使用的对象,转换回子类:

    public static void main(String[] args) {
        Person person=new Student("小明",18,"男");
        Student student=(Student) person;//使用强制类型转换(向下转型)
        student.study();
    }
  • 这种方法只适用于本身就是对应的子类

判断某个变量所引用的对象是什么类:

    public static void main(String[] args) {
        Person person=new Student("小明",18,"男");
        if(person instanceof Student){
            System.out.println("对象是Student类型的");
        }
        if(person instanceof Person){
            System.out.println("对象是Person类型的");
        }
    }

如果变量所引用的对象是对应类型或对应类型的子类,那么instanceof都会返回true,否则false。

子类和父类成员变量同名:

子类可以定义和父类同名的属性,当我们在子类中直接使用时 作用于子类中定义的属性,

在子类存在同名变量的情况下,用super关键字来表示父类

    public void work(){
        System.out.println("我是"+super.name);
    }

顶层Object类

实际上所有类都默认继承自Object类,除非手动指定继承的类型,但是依然改变不了最顶层的父类是Object类。所有类都包含Object类中的方法

标记为native的方法是本地方法。

对象比较equals方法:

//判断当前对象和给定对象是否相等,默认实现是直接用等号判断,也就是直接判断是否为同一个对象
public boolean equals (Object obj){
    return (this ==obj);
}
    public static void main(String[] args) {
        Worker w1=new Worker("小明",18,"男");
        Worker w2=w1;
        
        System.out.println(w1.equals(w2));
    }

获取对象信息:

//将当前对象转换为String的形式,默认情况下格式为 完整类名@十六进制哈希值
public String toString(){
    return getClass().getName()+"@"+Integer.toHexString(hashCode());
}
    public static void main(String[] args) {
        Worker w1=new Worker("小明",18,"男");
        System.out.println(w1.toString());
    }

方法的重写

重写:也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写。重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

重写和重载的区别:

区别重写重载
参数列表一定不能修改必须修改
返回类型一定不能修改(除非可以构成父子类关系)可以修改
访问限定符一定不能做更严格的限制(可以降低限制)可以修改

重写Object类中提供的equals方法:

public  class Person {
    String name;
    int age;
    String sex;

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


    @Override  //重写方法可添加注解,默认情况下可以省略
    public boolean equals(Object obj){  //重写方法要求与父类的定义完全一致
        if(obj == null) return false;  //如果传入的对象为null,肯定不相等
        if(obj instanceof Person){     //只有是当前类型的对象,才能进行比较
            Person person=(Person) obj;    //先转换为当前类型
            return this.name.equals(person.name)&&   //字符串内容的比较必须使用equals方法
                    this.age==person.age &&        //基本类型直接==
                    this.sex.equals(person.sex);
        }
        return false;
    }
}
public class Main {
    public static void main(String[] args) {
        Person p1=new Person("小明",18,"男");
        Person p2=new Person("小明",18,"男");

        System.out.println(p1.equals(p2));
    }
}

//
结果为true

其他父类方法的重写:

基于这种方法可以重写的特性,对于一个类行为的定义,不同的子类可以出现不同的行为:

//父类Person中:

    public void test(){
        System.out.println("我是原本的实现");
    }
//子类Student中:

    public void test(){
        System.out.println("我是学生");
    }
//Main:

public class Main {
    public static void main(String[] args) {
        Person p1=new Student("小明",18,"男");
        p1.test();  //依照实际对象Student,而不是引用对象Person
    }
}

//输出结果:
我是学生

final最终形态:

如果我们不希望子类重写某个方法,我们可以在方法前添加final关键字,表示这个方法已经是最终形态:

    public final void test(){
        
    }

super:

重写父类方法时,若要调用父类原本的实现,同样可以使用super关键字:

//父类中

    public void test(){
        System.out.println("我是原本的实现");
    }
    public void test(){
        super.test();
        System.out.println("我是学生");
    }

结果:

子类在重写父类时,不能降低父类方法中的可见性。可以在子类中提升权限。

若父类中方法test()是private,子类中可以存在public void test(){ },但并不是父类方法的重写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值