Java学习Day18:基础篇8

多态

基本信息:

应用场景:

可以把子类对象赋值给父类对象,实现多态从而使用同一种方法;

多态中调用成员的特点

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)是一种在编程语言中用于表示不能被实例化的类的概念。它的主要目的是提供一个或多个抽象方法(即没有实现体的方法,只有方法声明),这些方法必须由继承自抽象类的子类来实现。抽象类还可以包含已实现的方法(即具有方法体的方法)以及字段、属性、构造函数等。

抽象类的主要特点包括:

  1. 不能被实例化:抽象类不能直接创建对象,即不能使用new关键字来实例化抽象类。它的主要目的是被其他类继承,并由这些子类提供具体的实现。

  2. 包含抽象方法:抽象类可以包含一个或多个抽象方法。抽象方法是没有方法体的方法,只有方法的声明(即方法签名),并且必须以abstract关键字进行修饰。

  3. 允许包含非抽象方法和字段:除了抽象方法外,抽象类还可以包含已经实现的方法(即非抽象方法)以及字段、属性等。

  4. 子类必须实现父类的所有抽象方法:如果子类继承了一个抽象类,并且这个子类不是抽象类(即这个子类需要被实例化),那么子类必须实现父类中所有的抽象方法。否则,子类也必须被声明为抽象类。

  5. 作为类型引用:虽然不能直接实例化抽象类,但可以使用抽象类作为类型引用,指向其子类的实例。

抽象类在软件设计中非常有用,尤其是在实现多态和框架设计时。通过使用抽象类,可以定义一套接口规范,让不同的子类按照这套规范来实现具体功能,同时保证了代码的灵活性和可扩展性。

示例(以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)是一种引用类型,是一种抽象的类型,用于指定一组方法规范,但不提供这些方法的具体实现。接口是一种形式上的契约它要求实现了该接口的类(称为接口的实现类或实现接口的类)必须遵循接口中定义的规范

接口的主要特点:

  1. 抽象性接口中的所有方法默认都是抽象的(在Java 8之前),即它们只有声明没有实现体。从Java 8开始,接口中可以包含带有实现体的默认方法和静态方法

  2. 继承性:接口可以继承另一个或多个接口,使用extends关键字。接口之间的继承是多继承的,即一个接口可以继承多个其他接口

  3. 多态性:接口是支持多态性的重要手段。通过接口,我们可以指向实现了该接口的任何对象的引用。

  4. 实现接口的类必须实现接口中的所有方法(在Java 8之前),除非该类是抽象类。从Java 8开始,如果一个类实现了接口,但它不想实现接口中的某个默认方法,它可以选择不覆盖该方法,而是直接使用接口中提供的默认实现

  5. 接口中不能包含实例变量,但可以包含常量(即使用public static final修饰的变量,但通常省略这些修饰符)。

  6. 接口中的方法默认是public,且不允许使用其他访问修饰符(如privateprotected或包级私有)。

  7. 接口可以包含嵌套接口、枚举和静态类(在Java 9之前,接口中只能包含静态内部类;从Java 9开始,接口中可以包含非静态内部类,但内部类不能是抽象的)。

接口的使用场景包括定义一组方法的规范,使不相关的类可以实现这个接口,从而实现多态性。例如,ListSetMap等Java集合框架中的接口定义了集合操作的标准方法,不同的类如ArrayListLinkedListHashMap等实现了这些接口,提供了不同的实现方式。

接口在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类中,我们展示了如何通过接口名直接访问静态方法和常量,以及如何通过实现接口的类实例来调用抽象方法和默认方法。

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值