9.面向对象(2)继承和多态

继承

Java使用extends关键字来实现继承

  • 子类自动获得了父类的所有属性,严禁定义与父类重名的属性。
  • Object,每个类都会有父类,一个类有且仅有一个父类。
  • 子类无法访问父类的private字段或者private方法,但可以继承protected字段和方法。
  • 父类没有默认的构造方法,子类就必须显式调用super()并给出参数以便让编译器定位到父类的一个合适的构造方法。
public class SuperClass {
    protected String name;
    protected int age;

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

public class Child extends SuperClass {

    public Child(int age, String name) {
        super(name,age);// 调用父类的构造方法
        System.out.println("Child");
    }

    public String hello() {
        return "Hello, " + name; // OK!
    }

    public void updateAge(int age)
    {
        super.setAge(age);
    }
}

继承树: Child >SuperClass > Object

  • super关键字表示父类(超类)
public void updateAge(int age)
{
    super.setAge(age);
}

阻止继承

正常情况下,只要某个class没有final修饰符,那么任何类都可以从该class继承。
从Java 15开始,允许使用sealed修饰class,并通过permits明确写出能够从该class继承的子类名称。

public sealed class Shape permits Rect, Circle, Triangle {
    ...
}

上述Shape类就是一个sealed类,它只允许指定的3个类(Rect, Circle, Triangle)继承它。

向上转型

当我们定一个变量指向子类时,我们可以将定义类型指定为父类,这种方式在我们使用设计模式会很常用。
这种把一个子类类型安全地变为父类类型的赋值,被称为向上转型(upcasting)。

SuperClass sc = new SuperClass("张三",14);
System.out.println(sc.getName());
Object o1 = sc;

向下转型

和向上转型相反,如果把一个父类类型强制转型为子类类型,就是向下转型(downcasting)。
向下转型很容易出现ClassCastException,所以最好使用instanceof判定下类型

SuperClass c = new Child(14,"张三");
Child c2 = (Child) c;
System.out.println(c2.getName());
SuperClass sc = new SuperClass(14,"李四");
if (sc instanceof Child){
    //不包含Child
    Child sc2 = (Child) sc;
}
Child sc1 = (Child) sc;//ClassCastException

区分继承和组合

区域继承就是通过属性来进行赋值

class Book {
    protected String name;
    public String getName() {...}
    public void setName(String name) {...}
}
public class Child extends SuperClass {
    protected Book book;
}

final

如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。用final修饰的方法不能被Override

public final String hello() {
    return "Hello, " + name;
}

如果一个类不希望任何其他类继承自它,那么可以把这个类本身标记为final

final class Person {}

对于一个类的实例字段,同样可以用final修饰。用final修饰的字段在初始化后不能被修改。

class Person {
    public final String name = "Unamed";
}
Person p = new Person();
p.name = "New Name"; // compile error!

可以在构造方法中初始化final字段

多态

方法重写

在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为覆写(Override)。
如果方法签名相同,并且返回值也相同,就是Override,如果方法签名不同,就是Overload。

public class Child extends SuperClass {
...
  @Override
  public String getName() {
    return name+"——"+ age;
  }
}

多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法

public static void getName(SuperClass c){
    System.out.println(c.getName());
}
SuperClass c = new Child(14,"张三");
getName(c);

多态的特性就是,运行期才能动态决定调用的子类方法。对某个类型调用某个方法,执行的实际方法可能是某个子类的覆写方法。

覆写Object方法

因为所有的class最终都继承自Object,而Object定义了几个重要的方法:

  • toString():把instance输出为String;
  • equals():判断两个instance是否逻辑相等;
  • hashCode():计算一个instance的哈希值。
class SuperClass {
    ...
    // 显示更有意义的字符串:
    @Override
    public String toString() {
        return "SuperClass:name=" + name;
    }
    // 比较是否相等:
    @Override
    public boolean equals(Object o) {
        // 当且仅当o为SuperClass类型:
        if (o instanceof SuperClass) {
            SuperClass sc = (SuperClass) o;
            // 并且name字段相同时,返回true:
            return this.name.equals(sc.name);
        }
        return false;
    }
    // 计算hash:
    @Override
    public int hashCode() {
        return this.name.hashCode();
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容