类的继承与接口

目录

一、接口

1.接口的使用

2.接口的作用

二、类的继承

1.类的继承

2.方法重写

3. 自动转型(以及强制转型)

三、接口与继承


一、接口

1.接口的使用

接口是指将建立的该类与想要连接的类联通起来,相当于接了一个通道一样。而被连接到的类中,一般含有的都是抽象方法。接口是一种抽象类型,它定义了一组方法的签名和常量,但是没有实现方法的代码。先让我们简单定义一个按钮出来,探究按钮监听器这一接口。

package 接口;

import javax.swing.*;
import java.awt.*;

public class DrawUI {

    //使用方法构建一个含有按钮的窗体出来
    public void ShowUI(){
        JFrame jf = new JFrame();
        jf.setTitle("接口");  //设置标题
        jf.setSize(400,400);  //设置大小
        jf.setLocationRelativeTo(null);  //居中出现
        jf.setDefaultCloseOperation(3);  //可以关闭

        //流式布局管理器,用来控制组件在窗口上的位置
        FlowLayout flow = new FlowLayout(); //类名创建
        jf.setLayout(flow); //使得jf对象可以使用FlowLayout所创建的类(flow这个对象被包含进去)

        JButton jbu = new JButton("point it");
        Dimension dm = new Dimension(100,100);
        jbu.setPreferredSize(dm);   //设置大小
        jf.add(jbu);   //在jf对象(窗体)上添加jbu对象(组件)

        jf.setVisible(true);   //窗体可以显现
    }



    public static void main(String[] args){
        DrawUI ui = new DrawUI();
        ui.ShowUI();
    }

}

那么接下来,我们想让按钮能够接收到我们点击它的这一行为。这里要用到监听器,并且是行为监听器,采用的方法是用接口接到ActionListener。由于接口不能直接创建对象(里面定义的是抽象的方法),我们需要重新新建一个类来和它对接。

package 接口;

import java.awt.event.ActionListener;

public class ButtonListener implements ActionListener {
    
}

implement的意思是使生效,执行,意思就是用我们的这个类去执行这个接口类。我们用command点击进去(Mac),可以得到这么一页代码:

/*
 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 */

package java.awt.event;

import java.util.EventListener;

/**
 * The listener interface for receiving action events.
 * The class that is interested in processing an action event
 * implements this interface, and the object created with that
 * class is registered with a component, using the component's
 * {@code addActionListener} method. When the action event
 * occurs, that object's {@code actionPerformed} method is
 * invoked.
 *
 * @see ActionEvent
 * @see <a href="https://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html">How to Write an Action Listener</a>
 *
 * @author Carl Quinn
 * @since 1.1
 */
public interface ActionListener extends EventListener {

    /**
     * Invoked when an action occurs.
     * @param e the event to be processed
     */
    public void actionPerformed(ActionEvent e);

}

注释那部分不懂也没关系,涉及到更深的设置了,我们只看我们的ActionListener。可以看出它的类型名为interface,就是接口这一字面意思。后面的extend也是属于我们本文的内容,放到后面讲解。其实点开EventListener会发现它也是一个接口并且里面没有任何抽象方法。所以我们可以推测接口本身就连接到某个库函数,所以在这里不显示;我们这里主要看这个接口,它的方法只有一条。

同时我们发现,我们所写出来的新类是会报错的,这与接口是抽象方法有关。为了解决这一问题,我们需要将接口中所有的抽象方法都写入到我们的新类中,这样使得新类对接上监听器有了可以使用监听器里面的功能。为了防止过于繁琐,我们直接在监听器中写入我们需要的方法(记得将;改为{},将抽象方法改为函数方法)。

package 接口;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ButtonListener implements ActionListener {

    public void actionPerformed(ActionEvent e){
        System.out.println("点击!");
    }

}

同时在主函数中加入类调用:

ButtonListener buttonListener = new ButtonListener();
        jbu.addActionListener(buttonListener);

然后我们再次点击按钮,就会发现我们的输出上有“点击!”出现了。

上面便是简单的接口使用方法.同时,接口支持一个类接多个类,如我们常用的String中。点入进去会发现它内容:

public final class String   implements   java.io.Serializable, Comparable<String>, CharSequence, Constable, ConstantDesc {

………………

}

不同类之间用,隔开,表示可以使用这些类里面的方法。只要注意将其中所有的方法全部复制到新类中即可,并且将末尾的封号改为大括号。

2.接口的作用

在Java中,接口是一种定义行为的抽象类型,它可以用来描述一组相关的方法,但不提供这些方法的具体实现。它的作用具体可以分为以下几点:

  1. 定义规范:接口定义了一组行为规范,它规定了一个类应该提供哪些方法,但并不规定这些方法应该如何实现。这使得不同的类可以实现同一个接口,并提供不同的实现。

  2. 多态性:由于接口只定义了方法规范,不提供具体实现,因此它可以被多个类实现。这种特性使得接口可以实现多态性,即不同的类可以根据需要使用同一个接口。

  3. 代码重用:接口可以被多个类实现,这样可以避免代码的重复编写,提高代码的可重用性和可维护性。

  4. 解耦合:通过接口,可以将程序的不同部分分离开来,使得它们之间的耦合度降低,提高了程序的可扩展性和灵活性。

  5. 版本管理:接口可以用来定义API,它规定了与外部世界交互的一组方法,而不用考虑这些方法的具体实现。这种特性使得接口可以用来进行版本管理,即通过改变接口定义来控制API的演进。

总之,接口是Java编程中一个非常重要的概念,它使得程序的不同部分之间可以进行松耦合的交互,提高了程序的可维护性、可扩展性和灵活性。

二、类的继承

Java中的类继承是一种重要的面向对象编程概念,它允许一个类(称为子类或派生类)从另一个类(称为父类或基类)继承其属性和行为。类继承是Java中一个非常重要的概念,它使得代码的复用和扩展变得更加容易和灵活。

1.类的继承

先来讲述类的继承的写法。先建立一个简单的类:

package 继承;

public class Animal {

    //属性
    private String animal_name;
    public int animal_age;

    //方法

    public void setAnimal_name(String animal_name) {
        this.animal_name = animal_name;
    }
    public String getAnimal_name() {
        return animal_name;
    }
    //set... get... 函数负责给private里的属性赋值

    public void Function(){
        System.out.println("The "+animal_name+"'s age is "+animal_age);
    }
}

在该类中,我们定义了动物的名字和年龄,其中第一个是private限制,后者是public。下面的函数方法是给private中的属性赋值。由于private的限制性,我们可以知道animal_name只能在Animal里面被命名和使用。下面我们建立一个新类来继承这个类。

package 继承;

import 继承.Animal;

public class Individuality extends Animal {
    //继承用extends来继承,其中extends前面是子类,又称派生类;后者为父类,称基类或超类
    public void Hello(){
        System.out.println("Hello, world!");
    }
}

经过测试,在父类中定义的private类型即使在子类继承之后也无法使用,子类也只能调用父类中公开的内容。

我们知道,Java是纯粹的面向对象程序设计,在我们设计程序的时候需要用对象来使用类中的属性和方法。因为我们的I类是A类的继承,同样的,我们在主函数中创建I的对象,I的对象就能够使用A类中的方法。下面写一个主函数:

public static void main(String[] args) {

        Individuality dog = new Individuality();
        dog.setAnimal_name("doggo");
        dog.getAnimal_name();
        dog.animal_age = 10;

        dog.Function();
        dog.Hello();
    }

可以看到的是,我们是在I类里创建的对象,可它却可以使用A类里的方法。这就是类的继承。不同于接口,一个子类只能够继承一个父类,一个父类可以被多个子类继承。所以命名还是很准确的。输出结果如下:

The doggo's age is 10
Hello, world!

Process finished with exit code 0

我们也可以在子类中对于父类中不是private修饰的属性进行修改,修改的方式就相当于构造函数,这里简单提一下:

//在I类中插入这么一段

public Individuality(int animal_age){
        this.animal_age = 10;
    }

//在主函数中修改创建对象的方式
Individuality dog = new Individuality(10);
        dog.setAnimal_name("doggo");
        dog.getAnimal_name();

 因为 age 属性是从父类继承而来的,所以需要使用 this 关键字来引用子类中的属性。而我们下面创建对象可以直接在这里赋值,所以此处的this可以省略掉。

2.方法重写

在上述的例子中,我们用I类继承了A类中的方法和属性,并且还建立了一个只属于I类的方法——“Hello()”方法。从这里我们就可以看得出继承的部分作用,可以使我们对于一些基础属性相同的类不需要一直被重写,直接继承从而省去代码,并且还可以以此为基础继续编写子类中独有的方法。那如果我们想在子类中对父类的一些内容作出修改,让父类的方法变成子类特有的方法。好比我们上述的Function函数,我们想让它在子类中被修改从而实现另外的功能,相同名称从而被主函数所调用。实现这一过程的方法叫做方法重写。下面进行一步简单介绍:

package 继承;

import 继承.Animal;

public class Individuality extends Animal {
    //继承用extends来继承,其中extends前面是子类,又称派生类;后者为父类,称基类或超类

    public void Function(){
        System.out.println("The cat's age is "+animal_age+".");
    }

    public void Hello(){
        System.out.println("Hello, world!");
    }
}

输出结果如下:

The cat's age is 10.
Hello, world!

Process finished with exit code 0

在我们的编译器上,其实就可以实实在在的看到A类中的Function变为灰色显示没有被调用,而是子类中的Function在此处被使用。这就称之为方法重写,并且只有创建的对象属于这个子类时会出现这种情况。它的作用就是在函数名表示的内容一致时,给予不同对象不同的方法。

但是,如果我们既需要父类中的函数方法被使用也需要子类中新的函数方法,这个时候该如何修改我们的代码呢?这时我们就需要用到super。在 Java 中,super 是一个关键字,可以用于访问父类的属性、方法和构造函数。当在子类中重写父类的方法时,使用 super 关键字可以调用父类中被重写的方法。

package 继承;

import 继承.Animal;

public class Individuality extends Animal {
    //继承用extends来继承,其中extends前面是子类,又称派生类;后者为父类,称基类或超类

    public void Function(){
        System.out.println("The cat's age is "+animal_age+".");
        super.Function();
    }

    public void Hello(){
        System.out.println("Hello, world!");
    }
}

super无论放在新代码的上面还是下面都会被执行,执行的同样也是父类的内容。执行结果如下:

The cat's age is 10.
The doggo's age is 10
Hello, world!

Process finished with exit code 0

方法重写有使用条件,它必须在有继承关系的两个类之间,摒弃(访问修饰符大于等于父类)返回值类型,方法名,参数类型(个数,顺序)完全一样 。

3. 自动转型(以及强制转型)

所谓自动转型,也叫向上转型,其实就是是指将一个子类类型的对象赋给父类类型的变量的过程。这个过程会自动发生,而无需显式地进行类型转换。具体的表现就是我们可以对主函数中对象的创立做点手脚。

public static void main(String[] args) {

        Animal dog = new Individuality(10);
        dog.setAnimal_name("doggo");
        dog.getAnimal_name();

        dog.Function();
        dog.Hello();//该条报错
    }

在上面的示例中,I 类继承了 A 类。在 main() 方法中,创建了一个 dog 对象,并将其赋值给 A类型的变量 dog。这里发生了自动转型。因为 I类是 A 类的子类,所以可以将 I 类型的对象赋给 A类型的变量。自动转型属于向上转型。

在调用 dog.Function 方法时,调用的是 I 类中重写的 Function() 方法。这是因为在 Java 中,方法的调用是根据实际对象的类型来确定的,而不是根据变量的类型来确定的。因此,即使变量类型是 A类,但是由于实际对象是 I类,所以调用的是 I 类中的方法。

需要注意的是,虽然 dog 变量的类型是 Animal,但是无法调用 I 类中定义的 Hello() 方法,因为这个方法是 I 类独有的,而不是 Animal 类的方法。当我们看上述修改后的代码时,dog.Hello()这一方法会报错。如果需要调用这个方法,必须将 dog 变量强制转换为 I类 类型。

为了解决自动转型中不能使用子类方法,我们可以用强制转换使得dog变量强制转换为I类类型。

public static void main(String[] args) {

        Animal dog = new Individuality(10);
        dog.setAnimal_name("Doggo");
        dog.getAnimal_name();

        dog.Function();
        Individuality doggo = (Individuality)dog;
        doggo.Hello();
    }

这样我们就可以使用子类中的方法。强制转型也叫向下转型,前提条件是对象一开始是被向上转型过的。

自动转型通常有两种应用场景,一种是直接从子类中调用父类方法,这样就不需要在子类同名方法中使用super。第二种则是Java重要的多态。下例:

Animal animal1 = new Cat();
Animal animal2 = new Dog();
animal1.makeSound();  // 调用的是 Cat 类的 makeSound() 方法
animal2.makeSound();  // 调用的是 Dog 类的 makeSound() 方法

在上面的示例中,CatDog 类都是 Animal 类的子类,因此可以将它们的对象赋值给 Animal 类型的变量。通过这种方式,可以使用通用的 Animal 类型来实现不同子类对象的特定行为,这就是多态性。

三、接口与继承

Java中类的继承和接口是两种不同的机制,它们之间存在区别和联系。

类的继承是一种机制,它允许一个类继承另一个类的属性和方法。继承的类被称为子类或派生类,被继承的类被称为父类或基类。子类可以访问父类中的非私有成员(方法和属性),并且还可以添加自己的成员。子类可以覆盖父类的方法,以实现自己的功能。继承是一种is-a(是一个)的关系,即子类是一种特殊类型的父类。

接口是另一种机制,它定义了一个抽象的规范,而不是实现。接口可以包含方法,但是这些方法没有实现,只有方法的声明。类可以实现接口,这意味着它必须实现接口中的所有方法。实现接口是一种has-a(有一个)的关系,即类有一个接口,它定义了类应该具有的行为。

类可以同时继承一个类并实现多个接口。继承可以重用代码并建立is-a的关系,而接口可以实现多态和定义规范。在设计时,应该优先考虑使用接口,以提高代码的灵活性和可维护性。

而继承和接口这样联通类与类,并且可以使每个类产生新的功能的能力,实现了java的多态性。在Java中,多态是指一个对象可以根据其所属的类的不同表现出不同的行为。具体来说,多态包括两种形式:静态多态和动态多态。

静态多态也称为方法重载(Overloading),是指在同一个类中,方法名称相同但参数类型或数量不同的情况下,可以定义多个方法。在调用这些方法时,Java会根据传入的参数类型或数量自动选择调用相应的方法,这种机制称为静态多态。

动态多态也称为方法覆盖(Overriding)(方法重写),是指一个子类可以覆盖其父类中的方法,以实现自己的功能。在调用覆盖的方法时,实际调用的是子类中的方法,而不是父类中的方法。这种机制称为动态多态,也称为运行时多态。

多态的优点是增加代码的灵活性和可扩展性。通过多态机制,程序员可以编写通用的代码,而不必考虑具体的实现。多态也是面向对象编程的重要特性之一。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值