多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。
在java中要实现多态,必须要满足如下几个条件,缺一不可:
多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法
我们已经了解过继承 那么什么是重写呢?
重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, **返回值和形参都不能改变。即外壳不变,核心重写!**重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
即方法重载是一个类的多态性的表现,而方法重写是子类与父类的一种多态性表现
对于已经投入使用的类,尽量不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中共性的内容,并且添加或者改动新的内容。
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()
Animal animal = new Cat("元宝",2);
animal是父类类型,但可以引用一个子类对象,因为是从小范围向大范围的转换。
向上转型的使用场景有哪些呢?
Animal cat = new Cat("元宝",2); // 1. 直接赋值:子类对象赋值给父类对象
public static void eatFood(Animal a){
a.eat();
}
//调用时/
eatFood(cat);
eatFood(dog);
//用父类对象接受 传入一个子类对象
//作为返回值直接返回子类对象 类似于直接赋值
public static Animal buyAnimal(String var){
if("狗".equals(var) ){
return new Dog("狗狗",1);
}else if("猫" .equals(var)){
return new Cat("猫猫", 1);
}else{
return null;
}
}
//使用/
Animal animal = buyAnimal("狗");
向上转型的优点:让代码实现更简单灵活。
向上转型的缺陷:不能调用到子类特有的方法。
向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换。
public class TestAnimal {
public static void main(String[] args) {
Cat cat = new Cat("元宝",2);
Dog dog = new Dog("小七", 1);
// 向上转型
Animal animal = cat;
animal.eat();
animal = dog;
animal.eat();
if(animal instanceof Cat){
cat = (Cat)animal;
cat.mew();
}
if(animal instanceof Dog){
dog = (Dog)animal;
dog.bark();
}
}
}
静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。
我们前面了解过的重载就是一种静态绑定
public class test {
public static int add(int a, int b) {
return a + b;
}
public static double add(double a, double b) {
return a + b;
}
//两个add方法构成了重载
public static void main(String[] args) {
int a = 1;
int b = 2;
System.out.println(add(a, b));
double c = 6.5;
double d = 8.4;
System.out.println(add(c, d));
}
}
运行结果
也就是说在编译器编译时就可以根据你调用的参数分辨出你调用的是哪个方法,这就叫做静态绑定
也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体
调用那个类的方法。
package testDemo;
class Animal {
String name;
int age;
float weight;
public void eat() {
System.out.println(this.name + "正在吃饭!!!");
}
public void sleep() {
System.out.println(this.name + "正在睡觉!!!");
}
}
class Dog extends Animal {
public void bark() {
System.out.println(this.name + "汪汪汪~~~");
}
public void eat(){
System.out.println(this.name + "吃狗粮~~~");
}
}
class Cat extends Animal {
public void bark() {
System.out.println(this.name + "喵喵喵~~~");
}
}
public class test1 {
public static void main(String[] args) {
Animal animals = new Dog();
animals.eat();
}
}
这里我们向上转型创建了一个Dog对象 但是当父类Animals使用
运行结果
这里我们虽然编译的时候是父类的eat方法 但结果却调用了子类的eat方法 这个过程就叫做运行时绑定!!
在java中要实现多态,必须要满足如下几个条件,缺一不可:
多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。
public class Animals {//父类Animals
String name;
int age;
public Animals(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name + "吃饭");
}
}
public class Cat extends Animals {//子类
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat() {//方法的重写
System.out.println(this.name + "吃鱼");
}
}
public class Dog extends Animals {//子类
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {//方法的重写
System.out.println(this.name + "吃狗粮");
}
}
以上是方法实现者的写的代码///
以下是方法调用者写的代码/
public class TestAnimals {
public static void testFunc(Animals animals) {
animals.eat();
}
public static void main(String[] args) {
Cat cat = new Cat("miaomiao", 3);
Dog dog = new Dog("wangcai", 9);
testFunc(cat);
testFunc(dog);
//向上转型:出现在testFunc 方法中通过参数的传递体现的向上转型 方法需要Animals但我们实际上传入了Cat 和Dog类
//方法的重写:在Dog类和Cat类中的eat方法被重写
//动态绑定:编译的时候调用的是Animals的eat方法 但是实际上调用的是子类的方法 体现了动态绑定
}
}
当类的调用者在编写 eat 这个方法的时候, 参数类型为 Animal (父类), 此时在该方法内部并不知道, 也不关注当前的a 引用指向的是哪个类型(哪个子类)的实例. 此时 a这个引用调用 eat方法可能会有多种不同的表现(和 a 引用的实例相关), 这种行为就称为 多态.
什么叫 “圈复杂度” ?
圈复杂度是一种描述一段代码复杂程度的方式. 一段代码如果平铺直叙, 那么就比较简单容易理解. 而如
果有很多的条件分支或者循环语句, 就认为理解起来更复杂.
因此我们可以简单粗暴的计算一段代码中条件语句和循环语句出现的个数, 这个个数就称为 “圈复杂度”.
如果一个方法的圈复杂度太高, 就需要考虑重构.
不同公司对于代码的圈复杂度的规范不一样. 一般不会超过 10
例如我们现在需要打印的不是一个形状了, 而是多个形状. 如果不基于多态, 实现代码如下:
public class Shape {
public void draw() {
System.out.println("画图形!");
}
}
class Cycle extends Shape {
@Override
public void draw() {
System.out.println("画一个圆");
}
}
class Rect extends Shape {
@Override
public void draw() {
System.out.println("画一个矩形");
}
}
class Flower extends Shape {
@Override
public void draw() {
System.out.println("花一朵花");
}
}
class drawShape {
public static void drawshape() {
Rect rect = new Rect();
Cycle cycle = new Cycle();
Flower flower = new Flower();
String[] shapes = {"cycle", "rect", "cycle", "rect", "flower"};
for (String shape : shapes) {
if (shape.equals("cycle")) {
cycle.draw();
} else if (shape.equals("rect")) {
rect.draw();
} else if (shape.equals("flower")) {
flower.draw();
}
}
}
public static void main(String[] args) {
drawshape();
}
}
如果使用使用多态, 则不必写这么多的 if - else 分支语句, 代码更简单
public class drawShape2 {
public static void drawshape() {
Shape[] shapes = {new Cycle(), new Rect(), new Cycle(),
new Rect(), new Flower()};
for (Shape shape : shapes) {
shape.draw();
}
}
public static void main(String[] args) {
drawshape();
}
}
- 属性没有多态性 当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性
- 构造方法没有多态性