个人主页:鲤鱼王打挺-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修饰。
注意:启动电脑 和 关闭电脑是小编后面加的调用。
?小结:
接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法。今天我们浅浅了解下抽象类和接口,我们下期再见!希望给小编点赞关注支持下!