个人主页:鲤鱼王打挺-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修饰,子类不能重写方法。
java">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.直接赋值法
java">//直接赋值法Animal animal = new Cat("taotao");
2.利用参数传递
java">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.返回值传递
java">public Animal test(){return new Cat("taotao");}
3.动态绑定
动态绑定也称为 后期绑定,即在编译时,不能确定方法的行为,需等待程序运行,才能够确定具体调用那个类的方法。
java">class Parent {public void show() {System.out.println("Parent's show()");}
}class Child extends Parent {@Overridepublic 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()。
有动态那也就有静态绑定: 也称为早期绑定,是指在编译时就确定的方法调用。静态绑定通常应用于静态方法、私有方法、以及那些没有被子类重写的方法。
java">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就会报错。
java">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中就定义了抽象类,父类的方法不需要具体实现。 一个类不能描述一个具体对象时,就称为抽象类。
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)。接口是实现抽象化的一种方式,它允许不同的类以统一的方式被处理。接口允许不同的类以统一的方式被处理,从而实现多态性。
java">// 定义一个接口
public interface Movable {void move();
}// 实现接口的类
public class Car implements Movable {@Overridepublic void move() {System.out.println("Car is moving.");}
}// 另一个实现接口的类
public class Bicycle implements Movable {@Overridepublic void move() {System.out.println("Bicycle is moving.");}
}
接口也不能被实例化。
2.成员变量,成员方法
在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。
在接口中:成员变量默认是public static final类型,即使不写,或者写成public时也默认成public static final。
成员方法:成员方法的默认类型是:public,所以使用private时会报错,它只能被static或default修饰。
注意:启动电脑 和 关闭电脑是小编后面加的调用。
💖小结:
接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法。今天我们浅浅了解下抽象类和接口,我们下期再见!希望给小编点赞关注支持下!