【Java学习日记】#14 接口、继承与多态 类的继承 Object类 类的上下转型 方法的重载 多态 抽象类与接口

进入第二篇,接触核心技术。


类的继承

继承在面向对象开发思想中是一个非常重要的概念,它使整个程序框架具有一定的弹性。在程序中复用一些已经定义完善的类不仅可以减少软件的开发周期,也可以提高软件的可维护性和可拓展性。

继承的基本思想是基于某个父类进行拓展,得到一个新的子类。子类可以继承父类原有的属性和方法,也可以增加原来父类所不具有的属性和方法,或者重写父类中的一些方法。

extends关键字

语法

Child extends Parents

示例

public class Child extends Parents{
    
}

举例
父类电脑Computer,子类平板电脑Pad

如图新建父类子类和另外一个类
在这里插入图片描述

父类:

public class Computer {
    String screen = "液晶显示屏";
    void StartUp(){
        System.out.println("电脑正在开机。");
    }
}

子类:

public class Pad extends Computer {

}

另一个类:

public class Demo {
    public static void main(String[] args) {
        Computer com = new Computer();
        Pad iPad = new Pad();
        System.out.println(com.screen);
        com.StartUp();
        System.out.println(iPad.screen);
        iPad.StartUp();
    }
}

子类继承了父类的成员变量和成员方法。

液晶显示屏
电脑正在开机。
液晶显示屏
电脑正在开机。

子类可以有独有的变量和方法:
子类改为:

public class Pad extends Computer {
    String battery = "5000mAh";
    void TurnOnNet(){
        System.out.println("打开5G网络。");
    }
}

运行:

public class Demo {
    public static void main(String[] args) {
        Computer com = new Computer();
        Pad iPad = new Pad();
        //继承父类
        System.out.println(com.screen);
        com.StartUp();
        System.out.println(iPad.screen);
        iPad.StartUp();
        //子类独有
        iPad.TurnOnNet();
        System.out.println(iPad.battery);
    }
}

液晶显示屏
电脑正在开机。
液晶显示屏
电脑正在开机。
打开5G网络。
5000mAh

方法的重写

父类中新建方法:

void openPicture(){
        System.out.println("鼠标打开 图片.jpg");
    }

子类中进行重写:

public class Pad extends Computer {
    String battery = "5000mAh";
    void TurnOnNet(){
        System.out.println("打开5G网络。");
    }
    void openPicture(){
        System.out.println("触屏打开 图片.jpg");
    }
}

输出:

com.openPicture();
iPad.openPicture();

鼠标打开 图片.jpg
触屏打开 图片.jpg

super关键字

子类没有权限调用父类中被修饰为private的方法,只可以调用父类中修饰为public或者protected的成员方法。

语法
super.property;
super.method();

super关键字代表父类的对象。
super.property 父类的属性
super.method() 父类的方法

示例
public class Pad extends Computer {
    public void action(){
        super.action();
    }
}

父类中加入方法:

    String sayHello(){
        return "欢迎使用!";
    }

子类中重写:

String sayHello(){
        return super.sayHello()+"iPad!";
    }

输出:

//super关键字
        System.out.println(com.sayHello());
        System.out.println(iPad.sayHello());

欢迎使用!
欢迎使用!iPad!

将父类中的“欢迎使用!”改为“Welcome!”后的输出:

Welcome!
Welcome!iPad!

调用父类的属性:this关键字
public Pad(){
        this.screen = super.screen;
    }
调用父类的构造方法
    public Pad(){
        super();
    }

两点注意

Java语言中,一个类只可以有一个父类

如果需要同时继承两个类,需要使用多重继承


多重继承

简单来说,就是套娃。

class parent1{

}
class parent2 extends parent1{

}
class child extends parent2{

}

子类不仅会覆盖父类的方法,还会覆盖父类的属性

子类覆盖父类的属性

创建类:

class parent2{
    String name;
    public parent2(String name){
        this.name = name;
    }
}
class Child extends parent2{
    String name = "Tom";
    public Child(String name) {
        super(name);
    }
}

main方法中:

        Child child = new Child("Jack");
        System.out.println(child.name);

输出:

Tom

可见子类覆盖了父类的属性。

虽然name与父类的属性同名,仍然属于子类独有的属性。

Object类

Java中所有的类都直接或者间接继承了java.lang.Object类。
Object类是比较特殊的类,它是所有类的父类,是Java类层中的最高层的类。

在创建一个类时,例如:

public class Person{
}

实际上完整的是:

public class Person extends Object{
}

只是由于所有的类都是Object类的子类,所以后面的extends Object可以省略。

getClass()

返回对象执行时的Class实例。

创建一个Object数组,因为Object类是所有类的父类,所以Object数组可以存放任何一个类:

先创建一个Object数组,然后存放不同类型的元素,遍历数组:

public class Demo {
    public static void main(String[] args) {
        Object[] arr = new Object[4];
        arr[0] = new Object();//实例化了一个Object对象给arr[0]
        arr[1] = new String("我是字符串。");
        arr[2] = new Integer("123456");
        arr[3] = new Demo();

        for (Object obj:arr){
            System.out.println(obj.getClass());
        }
    }
}

输出:

class java.lang.Object
class java.lang.String
class java.lang.Integer
class Demo

输出的是类的全名,class表示这是一个类,后面是类名

toString()

将对象返回为字符串形式,如果子类不重写方法,将返回类名+@+十六进制的哈希值

public class Demo {
    public static void main(String[] args) {
        Object[] arr = new Object[4];
        arr[0] = new Object();//实例化了一个Object对象给arr[0]
        arr[1] = new String("我是字符串。");
        arr[2] = new Integer("123456");
        arr[3] = new Demo();

        for (Object obj:arr){
            System.out.println(obj.toString());
        }
    }
}

输出:

java.lang.Object@10f87f48
我是字符串。
123456
Demo@b4c966a

第一四行按格式输出,第二三行返回了StringInteger的字面值,因为StringInteger类重写了该方法。

重写toString

public class Demo {
    public static void main(String[] args) {
        Object[] arr = new Object[4];
        arr[0] = new Object();//实例化了一个Object对象给arr[0]
        arr[1] = new String("我是字符串。");
        arr[2] = new Integer("123456");
        arr[3] = new Demo();

        for (Object obj:arr){
            System.out.println(obj.toString());
        }
    }

    @Override
    public String toString() {
        return "Demo类";
    }
}

输出

java.lang.Object@10f87f48
我是字符串。
123456
Demo类

这里的System.out.println(obj.toString());中的.toString()是可以删掉的。

public class Demo {
    public static void main(String[] args) {
        Object[] arr = new Object[4];
        arr[0] = new Object();//实例化了一个Object对象给arr[0]
        arr[1] = new String("我是字符串。");
        arr[2] = new Integer("123456");
        arr[3] = new Demo();

        for (Object obj:arr){
            System.out.println(obj);
        }
    }

    @Override
    public String toString() {
        return "Demo类";
    }
}

输出结果相同:

java.lang.Object@10f87f48
我是字符串。
123456
Demo类

equals()

比较两个对象是否相等

默认比较地址是否相等

public class Demo {
    public static void main(String[] args) {
        Object[] arr = new Object[4];
        arr[0] = new Object();//实例化了一个Object对象给arr[0]
        arr[1] = new String("我是字符串。");
        arr[2] = new Integer("123456");
        arr[3] = new Demo();

        System.out.println(arr[0].equals(arr[3]));
    }
}

false

public class Demo {
    public static void main(String[] args) {
        Object[] arr = new Object[4];
        arr[0] = new Object();//实例化了一个Object对象给arr[0]
        arr[1] = new String("我是字符串。");
        arr[2] = new Integer("123456");
        arr[3] = arr[0];

        System.out.println(arr[0].equals(arr[3]));
    }
}

true

public class Demo {
    public static void main(String[] args) {
        Object[] arr = new Object[4];
        arr[0] = new Object();//实例化了一个Object对象给arr[0]
        arr[1] = new String("我是字符串。");
        arr[2] = new Integer("123456");
        arr[3] = new Object();

        System.out.println(arr[0].equals(arr[3]));
    }
}

false

重写:

import java.util.Objects;

public class Person {
    String name;
    String ID;

    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person();
        Person p3 = new Person();

        p1.name = "XiaoMing";
        p1.ID = "123";
        p2.name = "XiaoHong";
        p2.ID = "456";
        p3.name = "XiaoMing";
        p3.ID = "123";

        System.out.println(p1.equals(p2));
        System.out.println(p1.equals(p3));
        System.out.println(p2.equals(p3));
    }
    @Override
    public boolean equals(Object o) {
        Person p = (Person)o;
        boolean b1 = this.name.equals(p.name);//字符串的equals方法,判断字面值是否一样
        boolean b2 = this.ID.equals(p.ID);
        return b1&&b2;

    }

    @Override
    public int hashCode() {
        return Objects.hash(name, ID);
    }
}

输出:

false
true
false

类的上下转型

向上转型

子类的对象转为父类的对象

语法

用父类声明对象,用子类实例化对象

Parents Object = new Child();
实例
Person tom = new Student();

一个人叫tom,是一个学生。

举例

创建父类Person,在其中创建一个构造方法:

public class Person {
    public Person(String name){
        System.out.println(name);
    }
}

创建子类Students

public class Students extends Person {

    public Students(String name) {
        super(name);
    }
}

主方法:

public class Up {
    public static void main(String[] args) {
        Person TOM = new Person("TOM");
    }
}

输出:

TOM

实例化时把Person改成Students

public class Up {
    public static void main(String[] args) {
        Person TOM = new Students("TOM");
    }
}

输出相同,还是:

TOM

向下转型

将父类的对象强制转换为子类的对象

语法

必须使用强制转换

Parents p = new Parents();
Child c = (Child)p;
示例
Person tom = new Person();
Doctor dr_tom = (Doctor)tom;
public class Down {
    public static void main(String[] args) {
        Person tom = new Students("tom");
        Person jack = new Person("jack");
        Doctor dr = (Doctor)tom;
    }
}

报错,Error:(5, 29) java: 不兼容的类型: Person无法转换为Doctor

public class Down {
    public static void main(String[] args) {
        Person tom = new Students("tom");
        Person jack = new Person("jack");
        Doctor dr = (Doctor)jack;
    }
}

报错,Error:(5, 29) java: 不兼容的类型: Person无法转换为Doctor

public class Down {
    public static void main(String[] args) {
        Person tom = new Students("tom");
        Person jack = new Doctor("jack");
        Doctor dr = (Doctor)jack;
    }
}

正常输出:

tom
jack

instanceof关键字

语法
boolean result = child instanceof parents;

判断对象是否继承自类

如果前是后的子类,返回true,如果不是,返回false

public class Computer {//电脑
    public static void main(String[] args) {
        Pad iPad = new Pad();
        HuaweiPad MatePad = new HuaweiPad();
        System.out.println("Pad是否继承自Computer:"+(iPad instanceof Computer));
        System.out.println("HuaweiPad是否继承自Pad:"+(MatePad instanceof Pad));
        System.out.println("HuaweiPad是否继承自Computer:"+(MatePad instanceof Computer));
        System.out.println("HuaweiPad是否继承自Object:"+(MatePad instanceof Object));
    }
}
class Pad extends Computer{//平板电脑

}
class HuaweiPad extends Pad{//华为平板电脑

}

父类的父类返回的也是true,甚至可以是Object

两个没有任何继承关系的类不能用instanceof

方法的重载

方法名相同,参数个数不相同

public class Demo {
    public static void main(String[] args) {
        System.out.println("调用add(int a):"+add(1));
        System.out.println("调用add(int a,int b):"+add(1,2));
    }
    static int add(int a){//最普通的方法
        return a;
    }
    static int add(int a,int b){//定义了与第一个方法参数个数不同的方法
        return a+b;
    }
}

调用add(int a):1
调用add(int a,int b):3

方法名相同,参数顺序不相同

public class Demo {
    public static void main(String[] args) {
        System.out.println("调用add(int a):"+add(1));
        System.out.println("调用add(int a,int b):"+add(1,2));
    }
    static int add(int a){//最普通的方法
        return a;
    }
    static int add(double b,int a){//参数顺序不同
        return (int)(a+b);
    }
}

方法名相同,参数类型不相同

public class Demo {
    public static void main(String[] args) {
        System.out.println("调用add(int a):"+add(1));
        System.out.println("调用add(int a,int b):"+add(1,2));
    }
    static int add(int a){//最普通的方法
        return a;
    }
    static int add(int a,double b){//参数类型不同
        return (int)(a+b);
    }
}

加入出现两个参数顺序不同的同名函数,调用时会报错:

public class Demo {
    public static void main(String[] args) {
        System.out.println("调用add(int a):"+add(1));
        System.out.println("调用add(int a,int b):"+add(1,2));
    }
    static int add(int a){//最普通的方法
        return a;
    }
    static int add(double b,int a){//参数顺序不同
        return 100;
    }
    static int add(int a,double b){//参数顺序不同
        return 100;
    }
}
Error:(4, 50) java: 对add的引用不明确
  Demo 中的方法 add(double,int) 和 Demo 中的方法 add(int,double) 都匹配

解决(两种):

System.out.println("调用add(int a,int b):"+add(1,2.0));
System.out.println("调用add(int a,int b):"+add(1.0,2));

多态

同一个变量,不同的方法,执行出不同的结果

class Animal {
    void move(){
        System.out.println("移动");
        }
}
class Fish extends Animal{
    void move(){
        System.out.println("游动");
    }
}
class Eagle extends Animal{
    void move(){
        System.out.println("飞翔");
    }
}
public class Demo {
    public static void main(String[] args) {
        Animal jack = new Animal();
        jack.move();
        jack = new Fish();
        jack.move();
        jack = new Eagle();
        jack.move();

    }
}

抽象类与接口

抽象类

抽象类

在解决实际问题时,一般将父类定义为抽象类,需要使用这个父类进行继承和多态处理。在继承和多态的原理中,继承树中越是在上方的类越抽象,例如鸽子继承鸟类,鸟类继承动物类等。

创建一个Color类,它有RedBlue两个子类:

public abstract class Color {
    public void show(){

    }
}
class Red extends Color{
    public void show(){
        System.out.println("我是红色");
    }
}
class Blue extends Color{
    public void show(){
        System.out.println("我是蓝色");
    }
}

创建Demo2:

public class Demo2 {
    public static void main(String[] args) {
        Color c1 = new Red();
        Color c2 = new Blue();
        c1.show();
        c2.show();
    }
}

输出:

我是红色
我是蓝色

如果实例化一个c3:

public class Demo2 {
    public static void main(String[] args) {
        Color c1 = new Red();
        Color c2 = new Blue();
        c1.show();
        c2.show();
        Color c3 = new Color();
    }
}

会报错:

错误:(8, 20) java: Color是抽象的; 无法实例化

抽象类是不能实例化的

抽象方法

含有抽象方法的类必须是抽象类。

含有抽象方法的类必须被继承,而抽象方法必须被抽象类的子类所重写。

如果继承于一个含有抽象方法的类,则必须实现抽象类中的抽象方法。

public abstract class Teacher {
    abstract void teaching();//抽象方法不能有实体,所以直接括号结束,不能有花括号
}
class MathTeacher extends Teacher{
    @Override
    void teaching() {
        System.out.println("Delta等于死亡。");
    }
}
class EnglishTeacher extends Teacher{
    @Override
    void teaching() {
        System.out.println("How are you? I'm fine, thank you! And you?");
    }
}
public class Demo3 {
    public static void main(String[] args) {
        Teacher Lee = new MathTeacher();
        Teacher Jon = new EnglishTeacher();
        Lee.teaching();
        Jon.teaching();
    }
}

输出:

Delta等于死亡。
How are you? I’m fine, thank you! And you?

抽象类继承抽象类

创建顶层父类Animal类,两种行为,吃、繁殖:

public abstract class Animal {
    public Animal(){
        System.out.println("创建了一个动物");
    }
    public abstract void eat();
    abstract public void reproduce();//两种顺序都可以
}

创建父类Bird类,具有属性羽毛,具有行为长羽毛、通过下蛋繁殖

public abstract class Bird extends Animal{
    String feather;//羽毛
    public Bird(String feather){
        System.out.println("创建了一个鸟类");
        this.feather=feather;
    }
    public void growFeather(){
        System.out.println("长满了"+feather+"羽毛");
    }
    public abstract void move();
    public void reproduce(){
        System.out.println("下蛋");
    }
}

创建子类海鸥,创建时提示自动添加方法,添加完后:

public class Seagull extends Bird{

    public Seagull(String feather) {
        super(feather);
    }

    @Override
    public void move() {

    }

    @Override
    public void eat() {

    }
}

可见,第一个重写的方法来自鸟类中的抽象方法,第二个来自最顶层的动物类,说明,一个子类继承一个抽象类之后,需要实现这个抽象类以及他的父类的所有抽象方法。

完整子类的创建:

public class Seagull extends Bird{

    public Seagull(String feather) {
        super(feather);
        System.out.println("创建了一只海鸥");
    }

    @Override
    public void move() {
        System.out.println("飞翔");
    }

    @Override
    public void eat() {
        System.out.println("吃鱼");
    }
}

主方法:

public class Demo {
    public static void main(String[] args) {
        Seagull tom = new Seagull("白色的");
        tom.eat();
        tom.growFeather();
        tom.move();
        tom.reproduce();
    }
}

输出:

创建了一个动物
创建了一个鸟类
创建了一只海鸥
吃鱼
长满了白色的羽毛
飞翔
下蛋

首先运行最顶层动物类的构造方法,然后运行鸟类的构造方法,其次运行海鸥的构造方法,再运行成员方法。

创建Chicken类:

public class Chicken extends Bird {

    public Chicken(String feather) {
        super(feather);
        System.out.println("创建了一只鸡");
    }

    @Override
    public void move() {
        System.out.println("跑");
    }

    @Override
    public void eat() {
        System.out.println("吃米");
    }
}

主方法:

public class Demo {
    public static void main(String[] args) {
        Chicken kaji = new Chicken("黄色");
        kaji.eat();
        kaji.move();
        kaji.growFeather();
        kaji.reproduce();
    }
}

输出:

创建了一个动物
创建了一个鸟类
创建了一只鸡
吃米

长满了黄色羽毛
下蛋

接口

从抽象类中可以看出,继承抽象类的所有子类都需要将抽象类中的所有抽象方法进行覆盖。对于一些复杂的继承关系,这会造成代码的冗余,有些不需要使用父类中的某些方法的子类也需要重写这些不需要使用的方法。接口为这个情况给出了解决方案。

接口的声明及实现

创建Draw接口:

public interface Draw {
    public void draw();
}

创建四边形类:

public class Qua implements Draw {//四边形
    @Override
    public void draw() {
        System.out.println("绘制一个四边形");
    }
}

创建正方形类:

public class Square implements Draw{
    @Override
    public void draw() {
        System.out.println("绘制一个正方形");
    }
}

主方法:

public class Demo {
    public static void main(String[] args) {
        Draw d1 = new Qua();
        d1.draw();
        Draw d2 = new Square();
        d2.draw();
    }
}

输出:

绘制一个四边形
绘制一个正方形

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值