当前位置:首页 » 《关于电脑》 » 正文

Java 抽象类与接口(上)

5 人参与  2024年10月31日 17:21  分类 : 《关于电脑》  评论

点击全文阅读


个人主页:鲤鱼王打挺-CSDN博客 

目录

?前言: 

?一.多态:

1.重写与重载

1.1 override 

1.2 overlord

2.向上转型 

3.动态绑定 

4.向下转型

?二.抽象类

1.abstract 

 2.抽象方法

?三.接口

1.interface 与 implements

2.成员变量,成员方法 

?小结: 


 

?前言: 

我们已经学习了类与对象(Java 类和对象详解(下)-CSDN博客),我们知道Java面向对象具有多态性,今天我们正好借此来了解一下抽象类与接口,这对多态的学习尤为重要。

?一.多态:

学习了继承后,当我们创建父类对象使用它时,它只能实现父类方法,那么怎么实现一个方法,可以自由调用所有子类呢?作为面试中经常提及的问题,什么是多态呢?我们接着往下看。

1.重写与重载

注意该部分属于前情提要

1.1 override 

在面向对象编程中,重写(Override)是指子类提供了一个与父类同名的方法实现,并且可以有相同的方法签名(即相同的方法名、参数列表和返回类型)。重写是实现多态性的一种方式,它允许子类改变继承自父类的行为。

重写必须满足以下条件:

子类方法必须具有与父类方法相同的方法名和参数列表。子类方法的返回类型必须与父类方法的返回类型相同,或者是其子类型(对于协变返回类型)。子类方法不能有比父类方法更严格的访问权限,如public大于protect。子类方法不能重写父类的private方法,因为private方法在子类中不可见。子类方法通常需要使用@Override注解来明确表示该方法是重写了父类的方法,这有助于编译器检查重写的正确性。

总结:

方法名必须相同;

参数列表必须相同;

返回值必须相同(注意:如果返回类型构成父子类关系,也算重写【协变返回类型) ;

父类方法如果被static,final,private修饰,子类不能重写方法。

public class Animal {    public void eat(){        System.out.println("吃吃吃");    }} class Cat extends Animal{    public void eat(){        System.out.println("猫吃吃吃");    }}

1.2 overlord

在面向对象编程中,重载(Overloading)是指在一个类中可以有多个同名的方法,只要它们的参数列表不同。这包括参数的数量、类型或者顺序不同。重载方法可以有不同的返回类型,也可以没有返回类型(例如,如果它们是void类型的)。重载的主要目的是提供相同操作的多个版本,这些版本适用于不同的参数。

重载必须满足以下条件:

方法名必须相同。参数列表必须不同,即参数的数量、类型或顺序至少有一个不同。返回类型可以不同,但仅返回类型不同不足以构成重载。访问修饰符可以不同。

2.向上转型 

在java中要实现多态,必须要满足如下几个条件,缺一不可:

1. 必须在继承体系下

2. 子类必须要对父类中方法进行重写

3. 通过父类的引用调用重写的方法

多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法,向上传递是通过父类引用的一种形式。

向上转型(Upcasting)是面向对象编程中的一种类型转换,指的是将子类对象的引用赋给父类类型的引用。这种转换通常是隐式的,不需要显式地进行类型转换(也就是强制类型转换),因为子类对象可以被看作是父类对象的一个特化版本。

有如下三种方法:

1.直接赋值法 

//直接赋值法        Animal animal = new Cat("taotao");

2.利用参数传递 

public class Main {    public static void test(Animal aminal){        aminal.eat(aminal.name);    }    public static void main(String[] args) {        //利用参数传递        Cat cat = new Cat("xiaobai");        test(cat);    }}

 3.返回值传递

public Animal test(){        return new Cat("taotao");    }

3.动态绑定 

动态绑定也称为 后期绑定,即在编译时,不能确定方法的行为,需等待程序运行,才能够确定具体调用那个类的方法。

class Parent {    public void show() {        System.out.println("Parent's show()");    }}class Child extends Parent {    @Override    public void show() {        System.out.println("Child's show()");    }}public class Test {    public static void main(String[] args) {        Parent obj = new Child(); // 向上转型        obj.show(); // 动态绑定,调用的是Child类的show()方法    }}

 在这个例子中,尽管 obj 被声明为 Parent 类型,调用的 show() 方法是 Child 类中重写的方法,因为这是在运行时根据对象的实际类型决定的。通过底层可以观察到,编译好的字节码中仍调用Animal.eat(),但是运行时,调用的却是子类中的eat()。

有动态那也就有静态绑定: 也称为早期绑定,是指在编译时就确定的方法调用。静态绑定通常应用于静态方法、私有方法、以及那些没有被子类重写的方法。

class Parent {    public void show() {        System.out.println("Parent's show()");    }}class Child extends Parent {    // Child类没有重写show()方法}public class Test {    public static void main(String[] args) {        Parent obj = new Child(); // 向上转型        obj.show(); // 静态绑定,调用的是Parent类的show()方法    }}

在这个例子中,即使 obj 实际指向的是 Child 类型的对象,调用的 show() 方法是 Parent 类中的版本,因为 Child 类没有重写这个方法,所以这是在编译时就确定了的。

4.向下转型

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。

向下转型用的比较少,而且不安全,万一转换失败,运行时就会报错。

Java中为了提高向下转型的安全性,引入了 instanceof,如果该表达式为true,则可以安全转换。 为什么被认为不安全?因为如果Cat引用成 Dog就会报错。

public class TestAnimal {    public static void main(String[] args) {        Cat cat = new Cat("xaiobai");         // 向上转型        Animal animal = cat;        animal.eat();         // 编译时编译器将animal当成Animal对象处理        // 而Animal类中没有bark方法,因此报错        // animal.meow();        //向下转型        //由于向下转型通常被认为不安全        //所以要使用instanceof判断是否调用该类        if(animal instanceof Cat){            cat = (Cat)animal;            cat.meow();        }            } }

 大家可以将向下转型理解为一个强制类型转换的过程。

?二.抽象类

我们在写继承时,经常遇到父类方法对整体代码可有可无,或者说并不是我们需要的效果,通常在子类实现它。Java中就定义了抽象类,父类的方法不需要具体实现。 一个类不能描述一个具体对象时,就称为抽象类。

abstract class shape {// 抽象类    /* 抽象方法 求面积 */    public abstract double getArea( );    /* 抽象方法 求周长 */    public abstract double getPerimeter( );}//主类输入圆形的半径值,创建一个圆形对象,然后输出圆形的面积和周长。。class Circle extends shape{    private double radius;    public Circle(double r){        this.radius = r;    }    public  double getArea( ){        return Math.pow(radius,2)*Math.PI;    }    public double getPerimeter( ){        return 2.0*radius*Math.PI;    }}public class Main {    public static void main(String[] args) {        Scanner input = new Scanner(System.in);        DecimalFormat d = new DecimalFormat("#.####");// 保留4位小数        double r = input.nextDouble( );        shape c = new  Circle(r);        System.out.println(d.format(c.getArea()));        System.out.println(d.format(c.getPerimeter()));        input.close();    }}

1.abstract 

 抽象类一般使用关键字abstract来修饰,这时不能通过 new 关键字 来实例化对象。

上文代码中可以看到当类内一个方法没有具体实现时,就将这个方法用abstract修饰,留到子类中实现。

 2.抽象方法

如果一个类中有抽象方法,那么该类必须是抽象类。但如果它本身就是一个抽象类,并不强制要求含有抽象方法!当然,如果一个类继承了抽象类后却不重写抽象类中的方法,可以也加上abstract,但是总要有一个子类来实现抽象方法。

抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量 

?三.接口

1.interface 与 implements

 在面向对象编程(OOP)中,接口(Interface)是一个抽象类型,它定义了一组方法规范,这些方法规范可以由任何类实现(implement)。接口是实现抽象化的一种方式,它允许不同的类以统一的方式被处理。接口允许不同的类以统一的方式被处理,从而实现多态性。

// 定义一个接口public interface Movable {    void move();}// 实现接口的类public class Car implements Movable {    @Override    public void move() {        System.out.println("Car is moving.");    }}// 另一个实现接口的类public class Bicycle implements Movable {    @Override    public void move() {        System.out.println("Bicycle is moving.");    }}

接口也不能被实例化。 

2.成员变量,成员方法 

 在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。

在接口中:成员变量默认是public static final类型,即使不写,或者写成public时也默认成public static final。

成员方法:成员方法的默认类型是:public,所以使用private时会报错,它只能被static或default修饰。

注意:启动电脑 和 关闭电脑是小编后面加的调用。

?小结: 

接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法。今天我们浅浅了解下抽象类和接口,我们下期再见!希望给小编点赞关注支持下!


点击全文阅读


本文链接:http://zhangshiyu.com/post/180614.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1