多态
基本信息:


应用场景:

可以把子类对象赋值给父类对象,实现多态从而使用同一种方法;
多态中调用成员的特点
1.调用成员变量都看左边
调用成员变量:编译看左边,运行也看左边 
 编译看左边: javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败报错。
 运行也看左边: java运 行代码的时候,实际获取的就是左边父类中成员变量的值

2.调用成员方法一左一右
调用成员方法:编译看左边,运行看右边
编译看左边: javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有报错。
运行看右边: java运 行代码的时候,实际上运行的是子类中的方法。
3.成员变量和成员方法
成员变量:在子类的对象中,会把父类的成员变量也继承下的,所以使用的是弗雷德变量。
成员方法:如果子类对方法进行了重写,那么在虚方法表中是会把父类的方法进行覆盖的,所以调用成员方法输出就是成员重写的方法。

多态的优势



多态的弊端
不能调用子类的特有共能;

解决方案:强转回子类即可;

判断+转换+调用
小总结:


继承多态小案例:
package 多态的实例;
public abstract class Animal {
    private String colour;
    private int age;
    public Animal() {
    }
    public Animal(String colour, int age) {
        this.colour = colour;
        this.age = age;
    }
    public void eat(String something){
        System.out.println("吃"+something);
    }
    /**
     * 获取
     * @return name
     */
    public String getColour() {
        return colour;
    }
    /**
     * 设置
     */
    public void setColour(String colour) {
        this.colour = colour;
    }
    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    public String toString() {
        return "Animal{colour = " + colour+ ", age = " + age + "}";
    }
    public abstract void eat();
} 
package 多态的实例;
public class Dog extends Animal{
    @Override
    public void eat(){
        System.out.println(getAge()+"岁"+getColour()+"颜色"+"的狗两只前腿死死的抱住骨头猛吃");
    }
    public void lookHome(){
        System.out.println("lookHome");
    }
} 
package 多态的实例;
public class Cat extends Animal{
    @Override
    public void eat() {
    }
    public void catchMouse(){
        System.out.println("catchMouse");
    }
    public Cat() {
    }
    public Cat(String colour, int age) {
        super(colour, age);
    }
} 
package 多态的实例;
public class Polymorphic_demo {
    public static void main(String[] args) {
        Person p =new Person();
        p.setName("老王");
        p.setAgeMan(33);
        Dog d =new Dog();
        d.setAge(3);
        d.setColour("黑色");
        Cat c =new Cat();
        c.setAge(2);
        c.setColour("黑白");
        p.grrenxinxi(d,"骨头");
        p.grrenxinxi(c,"粑粑");
    }
}
 
抽象类
抽象类(Abstract Class)是一种在编程语言中用于表示不能被实例化的类的概念。它的主要目的是提供一个或多个抽象方法(即没有实现体的方法,只有方法声明),这些方法必须由继承自抽象类的子类来实现。抽象类还可以包含已实现的方法(即具有方法体的方法)以及字段、属性、构造函数等。
抽象类的主要特点包括:
-  
不能被实例化:抽象类不能直接创建对象,即不能使用
new关键字来实例化抽象类。它的主要目的是被其他类继承,并由这些子类提供具体的实现。 -  
包含抽象方法:抽象类可以包含一个或多个抽象方法。抽象方法是没有方法体的方法,只有方法的声明(即方法签名),并且必须以
abstract关键字进行修饰。 -  
允许包含非抽象方法和字段:除了抽象方法外,抽象类还可以包含已经实现的方法(即非抽象方法)以及字段、属性等。
 -  
子类必须实现父类的所有抽象方法:如果子类继承了一个抽象类,并且这个子类不是抽象类(即这个子类需要被实例化),那么子类必须实现父类中所有的抽象方法。否则,子类也必须被声明为抽象类。
 -  
作为类型引用:虽然不能直接实例化抽象类,但可以使用抽象类作为类型引用,指向其子类的实例。
 
抽象类在软件设计中非常有用,尤其是在实现多态和框架设计时。通过使用抽象类,可以定义一套接口规范,让不同的子类按照这套规范来实现具体功能,同时保证了代码的灵活性和可扩展性。
示例(以Java为例):
abstract class Animal {  | |
// 抽象方法  | |
abstract void eat();  | |
// 已实现的方法  | |
void sleep() {  | |
System.out.println("This animal sleeps.");  | |
}  | |
}  | |
class Dog extends Animal {  | |
// 必须实现父类的抽象方法  | |
@Override  | |
void eat() {  | |
System.out.println("Dog eats meat.");  | |
}  | |
}  | |
public class Test {  | |
public static void main(String[] args) {  | |
Animal myDog = new Dog(); // 使用抽象类作为类型引用  | |
myDog.eat(); // 调用Dog类实现的eat方法  | |
myDog.sleep(); // 调用Animal类中已实现的sleep方法  | |
}  | |
} | 
抽象类的构造方法、成员方法和成员变量的几问
在Java中,抽象类(Abstract Class)与它的构造方法(Constructor)、成员变量(Member Variables)、以及成员方法(Member Methods,包括抽象方法和非抽象方法)之间有着特定的关系。下面分别解释这些关系:
构造方法(Constructor)
- 构造方法的存在:抽象类可以有构造方法。这些构造方法主要用于在创建子类对象时初始化父类(即抽象类)的成员变量。
 - 构造方法的调用:当子类被实例化时,会首先调用父类(如果父类是抽象类)的构造方法(除非子类也是抽象类且仅被用作其他类的基类)。这是Java中对象初始化的一个基本步骤,确保父类被正确初始化。
 - 限制:构造方法本身不能被声明为抽象(
abstract)。 
成员变量(Member Variables)
- 定义:抽象类可以定义成员变量,这些成员变量可以是任何类型(基本数据类型、对象引用等)。
 - 访问:成员变量可以在抽象类的构造方法、成员方法(包括抽象方法和非抽象方法)中被访问和修改。同时,它们也可以被子类继承,并在子类中通过继承的
super关键字或直接访问(如果它们不是私有的)来访问和修改。 
成员方法(Member Methods)
- 抽象方法:抽象类中可以定义抽象方法,这些方法只有声明没有实现体(即方法体为空,并且使用
abstract关键字修饰)。子类必须实现这些抽象方法,除非子类也是抽象类。 - 非抽象方法:抽象类中也可以定义非抽象方法,这些方法有具体的实现体,可以直接被调用。这些非抽象方法可以被继承到子类,并在子类中被直接使用或重写。
 - 访问:成员方法(无论是抽象的还是非抽象的)都可以在抽象类的构造方法、其他成员方法中被调用(抽象方法除外,因为抽象方法没有实现体)。同时,这些方法也可以被子类继承,并在子类中通过继承或重写来使用。
 
小总结
- 抽象类可以有构造方法,但构造方法本身不能是抽象的。
 - 抽象类可以定义成员变量,这些变量可以在构造方法、成员方法中被访问和修改。
 - 抽象类可以定义抽象方法和非抽象方法。抽象方法必须由子类实现(除非子类也是抽象类),而非抽象方法可以直接在子类中使用或重写。
 - 成员变量和成员方法(非抽象的)都可以被子类继承,并根据需要在子类中进行访问、修改或重写。
 
接口
在Java中,接口(Interface)是一种引用类型,是一种抽象的类型,用于指定一组方法规范,但不提供这些方法的具体实现。接口是一种形式上的契约,它要求实现了该接口的类(称为接口的实现类或实现接口的类)必须遵循接口中定义的规范。
接口的主要特点:
-  
抽象性:接口中的所有方法默认都是抽象的(在Java 8之前),即它们只有声明没有实现体。从Java 8开始,接口中可以包含带有实现体的默认方法和静态方法。
 -  
继承性:接口可以继承另一个或多个接口,使用
extends关键字。接口之间的继承是多继承的,即一个接口可以继承多个其他接口。 -  
多态性:接口是支持多态性的重要手段。通过接口,我们可以指向实现了该接口的任何对象的引用。
 -  
实现接口的类必须实现接口中的所有方法(在Java 8之前),除非该类是抽象类。从Java 8开始,如果一个类实现了接口,但它不想实现接口中的某个默认方法,它可以选择不覆盖该方法,而是直接使用接口中提供的默认实现。
 -  
接口中不能包含实例变量,但可以包含常量(即使用
public static final修饰的变量,但通常省略这些修饰符)。 -  
接口中的方法默认是
public的,且不允许使用其他访问修饰符(如private、protected或包级私有)。 -  
接口可以包含嵌套接口、枚举和静态类(在Java 9之前,接口中只能包含静态内部类;从Java 9开始,接口中可以包含非静态内部类,但内部类不能是抽象的)。
 
接口的使用场景包括定义一组方法的规范,使不相关的类可以实现这个接口,从而实现多态性。例如,List、Set和Map等Java集合框架中的接口定义了集合操作的标准方法,不同的类如ArrayList、LinkedList和HashMap等实现了这些接口,提供了不同的实现方式。
接口在Java编程中非常重要,它促进了代码的模块化、可重用性和可扩展性。通过定义接口,我们可以让不同的类按照相同的约定进行工作,而不需要知道这些类的具体实现细节。
Java如何表示接口:
public interface Animal {  
     // 这是一个抽象方法,默认是public abstract的  
     void eat();  
   
     // 接口中的常量,默认是public static final的  
     int AGE = 10;  
   
     // Java 8 引入的默认方法  
     default void sleep() {  
         System.out.println("This animal sleeps.");  
     }  
   
     // Java 8 引入的静态方法  
     static void info() {  
         System.out.println("This is an interface for animals.");  
     }  
 }
public class Dog implements Animal {  
     // 必须实现接口中的抽象方法  
     @Override  
     public void eat() {  
         System.out.println("Dog is eating.");  
     }  
   
     // 可以选择性地覆盖接口中的默认方法  
     @Override  
     public void sleep() {  
         System.out.println("Dog is sleeping in a doghouse.");  
     }  
   
     // 静态方法和常量可以直接通过接口名访问,无需实现  
     public static void main(String[] args) {  
         Animal.info(); // 直接访问接口的静态方法  
         System.out.println(Animal.AGE); // 直接访问接口的常量  
   
         Dog dog = new Dog();  
         dog.eat();  
         dog.sleep(); // 调用的是Dog类中覆盖的sleep方法  
     }  
 }
接口实例化(虽然不能直接实例化抽象类,但可以使用抽象类作为类型引用,指向其子类的实例。)
// 定义接口  
 public interface Animal {  
     void eat();  
     void sleep();  
 }  
   
 // 实现接口  
 public class Dog implements Animal {  
     @Override  
     public void eat() {  
         System.out.println("Dog is eating.");  
     }  
   
     @Override  
     public void sleep() {  
         System.out.println("Dog is sleeping.");  
     }  
 }  
   
 // 在另一个类中实例化Dog类  
 public class Main {  
     public static void main(String[] args) {  
         // 实例化Dog类,但可以将实例引用视为Animal类型  
         Animal myDog = new Dog();  
   
         // 调用接口中定义的方法,但实际上是调用Dog类中的实现  
         myDog.eat();  
         myDog.sleep();  
   
         // 注意:你不能直接实例化接口,下面的代码会编译错误  
         // Animal anotherAnimal = new Animal(); // 错误:接口不能被实例化  
     }  
 }
 在这个例子中,Dog类实现了Animal接口,所以我们可以通过new Dog()来创建一个Dog对象。但是,由于Dog实现了Animal接口,我们可以将这个Dog对象的引用视为Animal类型(即Animal myDog = new Dog();)。这允许我们在不直接依赖于具体类(Dog)的情况下编写更灵活和可重用的代码。我们可以将myDog引用传递给期望Animal类型参数的任何方法或函数,只要这些方法或函数不依赖于Animal接口中未由Dog类实现的任何额外方法。
接口的成员方法和成员变量
成员方法
接口中的成员方法默认是public abstract的,这意味着它们必须被实现接口的类所实现(除非该类也是抽象的)。然而,从Java 8开始,接口还可以包含默认方法(使用default关键字)和静态方法(使用static关键字)。
- 抽象方法:没有方法体的方法,必须由实现接口的类提供具体实现。
 - 默认方法:提供了一种方式,允许接口在不破坏向后兼容性的情况下添加新的方法实现。
 - 静态方法:可以直接通过接口名来调用,不需要实现接口的类实例。
 
成员变量
接口中的成员变量实际上是常量,因为它们在接口中默认是public static final的。这意味着你可以直接通过接口名来访问这些常量,而不需要创建接口的实例。
使用示例
// 定义一个接口  | |
public interface Animal {  | |
// 成员变量(实际上是常量)  | |
int MAX_AGE = 100;  | |
// 抽象方法  | |
void eat();  | |
// 默认方法  | |
default void sleep() {  | |
System.out.println("This animal sleeps.");  | |
}  | |
// 静态方法  | |
static void info() {  | |
System.out.println("This is an interface for animals.");  | |
}  | |
}  | |
// 实现接口的类  | |
public class Dog implements Animal {  | |
@Override  | |
public void eat() {  | |
System.out.println("Dog is eating.");  | |
}  | |
// 可以选择性地覆盖默认方法  | |
@Override  | |
public void sleep() {  | |
System.out.println("Dog is sleeping in a doghouse.");  | |
}  | |
// 使用接口中的常量  | |
public void printMaxAge() {  | |
System.out.println("The maximum age of an animal is " + Animal.MAX_AGE);  | |
}  | |
}  | |
// 在另一个类中测试  | |
public class Main {  | |
public static void main(String[] args) {  | |
// 访问静态方法  | |
Animal.info();  | |
// 实例化Dog类  | |
Dog myDog = new Dog();  | |
// 调用抽象方法的实现  | |
myDog.eat();  | |
// 调用默认方法(可能被覆盖)  | |
myDog.sleep();  | |
// 调用打印常量的方法  | |
myDog.printMaxAge();  | |
}  | |
} | 
在这个例子中,Animal接口定义了一个常量MAX_AGE、一个抽象方法eat()、一个默认方法sleep()和一个静态方法info()。Dog类实现了Animal接口,并提供了eat()方法的具体实现,同时覆盖了sleep()默认方法。在Main类中,我们展示了如何通过接口名直接访问静态方法和常量,以及如何通过实现接口的类实例来调用抽象方法和默认方法。

新增接口三兄弟











