Java面向对象特性

 Java继承:

继承的概念:

在Java中,继承(inheritance)是面向对象编程的一个重要概念,它允许一个类(子类)继承另一个类(父类)的属性和方法。通过继承,子类可以拥有父类的属性和方法,并且可以扩展或修改这些属性和方法,实现代码的重用和扩展。

父类怎么形成的?

当我们定义了多个类,发现每个类中的属性重复,我们就可以把这些重复属性抽取出来,形成父类,其它的类直接继承这个父类即可。

继承其实更贴合于设计这方面的感觉,因为我们写代码的时候,不可能写了好多类之后,然后发现好多类的属性重复,再去抽取,这样就很慢,而是在设计的时候就提前想好。

在Java中,使用关键字extends来实现继承,语法如下: 

class 子类名 extends 父类名 {
    // 子类的属性和方法
}

继承的基本使用:

1:首先定义一个父类(people)
package Testextends;

public class People {
    String name;
    int age;
    public void work(){
        System.out.println("工作");
    }
    private void eat(){
        System.out.println("吃饭");
    }
}
2:定义若干子类(teacher,manager)
package Testextends;

public class Manager extends People{
}
package Testextends;

public class Teacher extends People{

}

同时继承父类people,不过在子类中不写任何代码

3:在main方法中创建对象
package Testextends;

public class Test01 {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        
    }
}

如图,通过java的反射机制,我们就可以看出teacher继承了people的方法,

不过我们仔细看,私有方法eat并没有显示出来。

说明子类使用不了父类的私有方法和变量,只能使用非私有方法和变量

继承中成员变量的使用:

 1:继承中成员变量不重名:

首先我们需要明白一个规则,我创建了一个对象,如果我想调用这个对象里面的属性,我先是在这个对象的范围里面查找,找不到,再去查父类

明白了这个规则

我们看下面的代码:

在子类中创建一个变量zi = 10

package Testextends;

public class Teacher extends People{
    int zi = 10;
}

在父类中创建一个变量fu = 100 

package Testextends;

public class People {
    String name;
    int age;
    private int gender;
    int fu = 100;
    public void work(){
        System.out.println("工作");
    }
    private void eat(){
        System.out.println("吃饭");
    }
}

在主函数中创建父类对象 

 仔细看上面的代码:

父类调用子类的特有变量(zi)报错,这也印证了上面的规则。

2:继承中成员变量重名:

重名的话,很好理解,就是直接覆盖

 继承中成员方法的使用:

其实和上面的差不多,如果不重名,则这个方法就算子类的特有方法

如果重名,那这个就算子类重写了父类的方法,直接覆盖掉了

注意点:

如果这个时候来一行代码:

使用父类来创建一个子类的对象

People people1 = new Teacher();

这个时候的成员变量和成员方法的结果就需要特别注意了:

package Testextends;

public class Teacher extends People{
    int age = 18;
    public void work(){
        System.out.println("教师工作");
    }
}
package Testextends;

public class People {
    String name;
    int age = 100;
    private int gender;
    public void work(){
        System.out.println("工作");
    }
    private void eat(){
        System.out.println("吃饭");
    }
}
        People people1 = new Teacher();
        System.out.println(people1.age);
        people.work();
        teacher.work();
        people1.work();

输出结果:

100
工作
教师工作
教师工作

我们可以发现,对于成员变量来说,age的值还是父类的值,对于成员方法来说,work方法的内容却变成了子类重写过的内容

所以我们可以总结:

 继承中:

成员变量访问特点:看等号左边是谁,先调用谁中的成员变量

如上面People people1 = new Teacher();等号左边是父类(people),那成员变量的值就是左边

成员方法访问特点:看new的是谁,先调用谁中的方法

还是上面这个例子,调用的方法就是Teacher重写过的方法。

方法重写: 

方法重写(Method Overriding)是指子类重写(覆盖)其父类中具有相同名称相同参数列表返回类型的方法。

检测是否为重写方法:在该方法上写

  @Override

方法重写和方法重载的区别:

方法重载(Method Overloading)指的是在同一个类中可以有多个同名的方法,但这些方法的参数列表必须不同(包括参数的类型、顺序或个数)。在调用这些同名方法时,编译器会根据传入的参数类型来确定调用哪个重载的方法。

这是方法的重载

public class OverloadExample {
    public void printInfo(int num) {
        System.out.println("Number: " + num);
    }

    public void printInfo(String str) {
        System.out.println("String: " + str);
    }

    public void printInfo(int num1, int num2) {
        System.out.println("Numbers: " + num1 + " and " + num2);
    }

    public static void main(String[] args) {
        OverloadExample example = new OverloadExample();
        example.printInfo(10); // 调用第一个printInfo方法
        example.printInfo("Hello"); // 调用第二个printInfo方法
        example.printInfo(5, 8); // 调用第三个printInfo方法
    }
}

这是方法的重写:

class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Dog barks");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.sound(); // 输出:Animal makes a sound

        Dog dog = new Dog();
        dog.sound(); // 输出:Dog barks
    }
}

@Override判断此方法是否是重写方法,如果不是就会报错

重写的注意事项:

 1:子类重写父类方法,权限必须要保证大于等于父类权限,这里的权限指的是访问权限

(子类中重写的方法不能使用比父类中被重写的方法更严格的访问修饰符)

权限排序:public > protected > 默认(什么都不加)> private 

2:父类私有方法,构造方法,静态方法

私有方法不能继承,也不能重写

构造方法不可以继承,不能重写

静态方法可以继承,不能重写

3:子类重写父类方法之后,返回值得是父类方法返回值得子类类型

重写的使用场景:

  1. 实现多态性:方法重写是实现运行时多态性的一种重要手段。通过子类重写父类方法,可以在运行时根据对象的实际类型来调用相应的方法,实现动态绑定。

  2. 修改父类方法的行为:有时候子类可能需要修改父类方法的行为或者提供更具体的实现。通过重写父类方法,子类可以根据自己的需求来实现特定的逻辑。

  3. 扩展父类方法的功能:在某些情况下,子类可能需要在父类方法的基础上添加额外的逻辑或功能。通过重写父类方法并在其中调用父类的原方法,可以实现逻辑的扩展。

  4. 更好地适应子类的需求:通过重写父类方法,子类可以更好地适应自身的特性和需求,从而提高代码的灵活性和可维护性。

(from GPT)

super和this:

先来看一个案例:

我在这里只初始化了一个子类对象,只调用了子类的构造方法。

可是连通父类的构造方法一起调用了。

所以,我们可以得出:

1:new子类对象时,会先初始化父类(父类的无参构造方法)

2:原因:

        每个构造方法的第一行,默认会有一个super(),jvm自动提供

        super代表父类的无参构造

 了解了这个案例之后:

super的使用:

1:概述:代表的是父类的引用
2:使用:

        a.调用父类的构造方法:在子类的构造方法中使用super关键字可以调用父类的构造方法。这样可以确保在子类对象被实例化时,父类的构造方法也会被执行。如果不显式使用super关键字调用父类构造方法,Java编译器会默认插入调用父类的无参构造方法。

        super() -> 调用父类无参构造

        super(实参)->调用父类有参构造

         b.调用父类的成员变量和方法:在子类中使用super关键字可以访问调用父类的成员变量和方法

        super.成员变量名

        super.成员方法名(实参)

public class Fu {
    int num = 10;
    public Fu(){
        System.out.println("我是父类中的无参构造");
    }

    public Fu(int data){
        System.out.println("我是父类中的有参构造");
    }

    public void method(){
        System.out.println("我是父类中的method方法");
    }
}

```

```java
public class Zi extends Fu{
    int num = 100;
    public Zi(){
        super();//调用父类中的无参构造
        System.out.println("我是子类中的无参构造");
    }

    public Zi(int num){
        super(10);//调用父类的有参构造
        System.out.println("我是子类中的有参构造");
    }

    public void method(){
        super.method();//调用父类的method方法
        System.out.println("我是子类中的method方法");
        System.out.println(num);//子类自己的
        System.out.println(super.num);//调用父类的num
    }
}

```

```java
public class Test01 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        System.out.println("============");
        Zi zi1 = new Zi(10);
        System.out.println("============");
        Zi zi2 = new Zi();
        zi2.method();

    }
}

this的使用:

1.this概述:代表的是当前对象(哪个对象调用的this所在的方法,this就代表哪个对象)

当前对象:指的是指定上下文中的实例化对象

public class MyClass {
    private int num;

    public void setNum(int num) {
        this.num = num; // 在这里,this表示当前对象的引用,指正在调用setNum方法的对象
    }
}

MyClass obj = new MyClass();
obj.setNum(10);
// 当调用setNum方法时,this表示obj这个实例化的对象

这里面的obj就是当前对象

2.作用:

  a.区分重名的成员变量和局部变量

  b.调用当前对象中的成员

3.使用:
  a.调用当前对象的构造:在构造中写

    this():调用当前对象的无参构造

    this(实参):调用当前对象的有参构造

public class MyClass {
    private int num;

    public MyClass() {
        this(0); // 在这里,this表示当前对象的引用,指构造当前对象的实例
    }

    public MyClass(int num) {
        this.num = num;
    }
}

MyClass obj = new MyClass();
// 当创建MyClass对象时,this表示的是正在实例化的MyClass对象

当在主函数中实例化一个对象后,就算你调用的是一个无参构造方法, 在无参构造中调用了this(0)

还是会用那个有参的构造方法实例化。

  b.调用当前对象的成员变量:

    this.成员变量名

public class MyClass {
   
    int m;
    public void setNum(int num){
        this.num = num;
        System.out.println(this.num);
    }
    private int num;
    public void method(){
        int num = 100;
        System.out.println(num);
        System.out.println(this.num);
    }
}

 当全局变量有一个和方法中的变量重名的时候(这段代码中的num),我们就可以用this来区分全局变量和局部变量

  c.将当前对象作为参数传递给其他方法:
public class MyClass {
    private int num;

    public void method() {
        newMethod(this); // 在这里,this表示当前对象的引用,指调用method方法的对象
    }

    public void newMethod(MyClass obj) {
        // 在这里,obj参数接收到的是this所指向的对象
    }
}

MyClass obj = new MyClass();
obj.method();
// 当调用method方法时,this表示的是obj这个实例化的对象
4:注意点:

不管是super还是this,只要在构造中使用,都必须在第一行,所以二者不能同时手写出来

继承的特点:

1.继承只支持单继承,不能多继承

  public class A extends B,C{}  -> 错误

2.继承支持多层继承

  public class A extends B{}

  public class B extends C{}

3.一个父类可以有多个子类

  public class A extends C{}

  public class B extends C{}

 继承(为父类私有属性赋值)

首先我们知道,父类的私有属性,子类是没有办法访问的,那这个时候如果我们还是要去修改值怎么办呢?

两种方法:

1:利用set赋值

其实这个就是去构造一个javabean对象,然后通过get和set方法对这个变量进行赋值

public class Employee {
    private String name;
    private int age;

    public Employee() {
    }

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void work(){
        System.out.println("工作");
    }
}
Teacher teacher = new Teacher();
        teacher.setName("张三");
        teacher.setAge(18);
        System.out.println(teacher.getName()+"..."+teacher.getAge());
2:利用构造方法赋值

在子类的构造方法中利用super(参数)来构造

其实利用构造方法赋值本质上也是利用了set方法。

public class Manager extends Employee{
    public Manager() {
    }

    public Manager(String name, int age) {
        super(name, age);
    }
}
Manager manager = new Manager("金莲", 24);
        System.out.println(manager.getName()+"..."+manager.getAge());

继承中的抽象类: 

首先我们设想一个场景:三角形类,正方形类,圆形类,他们中都有一个方法是求面积

根据我们之前学习的继承,我们很容易想到将这个求面积的方法抽象出来成一个形状类

不过我们再看,三个形状求面积的公式不同,我们不能想之前那样抽象成一个方法。

所以就需要我们的抽象类。

抽象类的定义:

Java中的抽象类是指不能被实例化的类,通常用于定义一些共同的方法和属性,让子类来实现具体的逻辑。抽象类通常包含抽象方法(没有具体实现的方法)和非抽象方法(有具体实现的方法)。

 抽象类案例:

public abstract class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    // 抽象方法
    public abstract void sound();

    // 非抽象方法
    public void sleep() {
        System.out.println(name + " is sleeping");
    }
}

在上面的例子中,Animal类是一个抽象类,包含一个抽象方法sound()和一个非抽象方法sleep()。任何继承Animal类的子类都必须实现sound()方法,否则会被标记为抽象类。

要实现一个继承自抽象类的子类,需要在子类中实现所有的抽象方法,如下所示:

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void sound() {
        System.out.println(name + " is barking");
    }
}

在这个例子中,Dog类继承自Animal类,并且实现了抽象方法sound()。这样,Dog类就可以被实例化并调用其方法了。

特点:
  1. 继承了抽象类,就必须重写所有的抽象方法,由此我们也可以得出,抽象方法不能用private,final 或者static关键字来修饰,这是因为定义抽象方法的目的就是想将方法的具体实现延迟到子类,最终是要被子类重写的,而private,final,static这几个关键字都和“方法重写”的目的背道而驰。
  2. 拥有抽象方法的类一定是抽象类;但是抽象类不一定有抽象方法。这个如何理解,如果一个类你一开始定义为普通类,后面想用抽象方法,就会报错,必须加上abstract,但是一开始,如果你定义了一个抽象类,你可以不写抽象方法,后面再补也许
  3. 抽象类不能被实例化,只能创建其非抽象子类对象 。既然抽象类不能实例化,那抽象类的构造方法用处是什么呢?我们之前讲过继承可以为父类私有属性赋值,同时我们也可以利用这一点

package Testextends;

public class Manager extends Person{
    public Manager(String name, int age) {
        super(name, age);
    }
}


package Testextends;

public abstract class Person {
    String name;
    int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}




package Testextends;

public class Test01 {
    public static void main(String[] args) {
        Manager manager = new Manager("张三",18);
        System.out.println(manager.getName()+manager.getAge());
    }
}

在这个案例中,Manager继承了抽象类Person,并且super(name, age);

就和上面那张图一样,将抽象类中的name和age属性赋上了值。

Java接口:

接口的定义:

在Java中,接口(Interface)是一种抽象数据类型,它定义了一组方法的签名,但并没有提供方法的具体实现。接口可以看作是一种约定或契约,让类来实现这些方法以确保特定的行为或功能。

来举一个生活中例子把:

当我们订购外卖时,我们可以将食品平台比作接口,而餐厅则是实现了这个接口的具体类。在这个例子中,食品平台定义了一组规范,比如订单方法、支付方法等,餐厅则按照这些规范实现了具体的行为。

接口代表食品平台提供的服务,而餐厅作为实现类,提供了具体的食品和服务。我们可以通过食品平台下单、支付等方法与不同的餐厅交互,而不需要关心具体餐厅是如何处理订单和支付的。

这样的设计使得我们可以更加灵活地选择不同的餐厅进行订餐,并且不需要知晓每个餐厅的具体细节,只需按照规范进行操作就可以了。

接口的理解(特点):

  1. 接口可以理解为一个抽象类,实现这个接口的类必须重写这个接口里面的所有方法,但是接口和抽象类不同的是:接口可以实现多实现,这就和之前的继承不同了,也算弥补了java不能多继承的缺点,子类可以继承一个父类的同时实现一个或者多个接口
  2. 接口里面的方法默认都是abstract的,在JDK8中添加了default和static,在JDK9中添加了private,如果在接口中不去特意定义default,private和static这三个关键字的话,那是不是接口中的方法默认都是abstract
  3. 接口中的变量默认都是静态常量,即使用 public static final 修饰的常量。
  4. 同时接口也不能被实例化,都只能通过子类来new

接口的使用:

关键字:
   a.interface 接口
      public interface 接口名{}
   
  b.implements 实现
      实现类 implements 接口名{}

第一个案例:最简单的一个接口的使用
public interface USB {
    public abstract void open();
    public abstract void close();
}


public class Mouse implements USB{
    @Override
    public void open() {
        System.out.println("鼠标打开");
    }

    @Override
    public void close() {
        System.out.println("鼠标关闭");
    }
}


public class Test01 {
    public static void main(String[] args) {
        Mouse mouse = new Mouse();
        mouse.open();
        mouse.close();
    }
}
第二个案例:定义了默认方法:
public interface Greetable {
    // 默认方法
    default void greet() {
        System.out.println("Hello, nice to meet you!");
    }
}

public class Person implements Greetable {
    public static void main(String[] args) {
        Person p = new Person();
        p.greet(); // 调用接口中的默认方法
    }
}

对于默认方法,需要通过接口的实例来调用

第三个案例:定义了静态方法:
public interface Calculator {
    // 静态方法
    static int add(int a, int b) {
        return a + b;
    }
}

public class TestCalculator {
    public static void main(String[] args) {
        int sum = Calculator.add(10, 20); // 调用接口中的静态方法
        System.out.println("Sum: " + sum);
    }
}

静态方法直接用接口名就可以调用

第四个案例:定义了私有方法
public interface Calculation {
    default int add(int a, int b) {
        return performAddition(a, b); // 调用私有方法
    }

    private int performAddition(int a, int b) {
        return a + b;
    }
}

public class TestCalculation implements Calculation {
    public static void main(String[] args) {
        TestCalculation calc = new TestCalculation();
        int sum = calc.add(10, 20); // 调用接口中的默认方法
        System.out.println("Sum: " + sum);
    }
}

在这个例子中,接口 Calculation 中定义了一个默认方法 add,并在该默认方法中调用了一个私有方法 performAddition。私有方法被用来实现具体的逻辑,但只能在接口内部使用,外部无法访问。

Java多态:

多态是指同一个方法调用,在不同对象上有不同的表现形式。

这样讲其实蛮难理解:

举一个例子:

class Animal {
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    void makeSound() {
        System.out.println("Dog barks");
    }
    void lookDoor(){
        System.out.println("Dog lookDoor");
    }
}

class Cat extends Animal {
    void makeSound() {
        System.out.println("Cat meows");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog(); // 编译时类型为Animal,运行时类型为Dog
        animal.makeSound(); // 运行时调用Dog类的makeSound方法
        Animal animal = new Cat(); // 运行时类型为Cat
        animal.makeSound(); // 运行时调用Cat类的makeSound方法
    }
}




首先创建一个动物类Animal类,狗dog类,猫cat类

dog和cat同时继承Animal,并且重写了父类的makeSound,父类引用指向子类对象

这是我们就会发现控制台输出了:

Dog barks

Cat meows

这就是多态,相同的引用到不同的对象上,有不同的表现形式。

注意点:由父类引用指向子类对象创建出来的对象不能调用自己的特有方法

比如用Animal animal = new Dog();创建了一个对象animal,这个animal就不能调用Dog类中特有的方法lookDoor

 多态的前提:

  1.   必须有子父类继承或者接口实现关系
  2.   必须有方法的重写(没有重写,多态没有意义),多态主要玩儿的是重写方法
  3.   new对象:父类引用指向子类对象,Fu fu = new Zi() -> 理解为大类型接收了一个小类型的数据 ->比如  double b = 10
  4.   多态下不能直接调用子类特有功能(这一点和继承一样)

多态的条件下成员的访问特点

 看new的是谁,先调用谁中的成员方法,子类没有,找父类

这一句话和继承的时候学的是一样的

比如:

成员变量的使用:
public class Fu {
    int num = 1000;
}
public class Zi extends Fu{
    int num = 100;
}
public class Test01 {
    public static void main(String[] args) {
        Fu fu = new Zi();
        System.out.println(fu.num);
    }
}

new的是子类,所以输出的就是子类的成员变量

成员方法的使用:
public class Fu {
    int num = 1000;
    public void method(){
        System.out.println("我是父类中的method方法");
    }
}

public class Zi extends Fu{
    int num = 100;

    public void method(){
        System.out.println("我是子类中的method方法");
    }
}

public class Test01 {
    public static void main(String[] args) {
        Fu fu = new Zi();
        System.out.println(fu.num);//父类中的num
        fu.method();//子类中重写的method方法
    }
}

这里也是同理。

多态的优点:

要讲多态的优点,我们先来举个例子吧,这个例子的目的其实也不是说能说明多态的优点,就是做一个对比,已多态的方式创建对象和普通的方式创建对象

问题描述:


  如果使用原始方式new对象(等号左右两边一样),既能调用重写的,还能调用继承的,还能调用自己特有的成员
  但是多态方式new对象,只能调用重写的,不能直接调用子类特有的成员,那为啥还要用多态呢?

既然我们学了,那肯定就有学的用处:

先来看一下优缺点吧:

多态方式和原始方式new对象的优缺点:


  原始方式:
    a.优点:既能调用重写的,还能调用父类非私有的,还能调用自己特有的
    b.缺点:扩展性差
        
  多态方式:
    a.优点:扩展性强
    b.缺点:不能直接调用子类特有功能       

这样讲肯定太宽泛了:

具体的代码案例:

package Testduotai;

class Animal {
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    void makeSound() {
        System.out.println("Dog barks");
    }
}

class Cat extends Animal {
    void makeSound() {
        System.out.println("Cat meows");
    }
}
public class Test01 {
    public static void main(String[] args) {
        //不用多态,用普通的方法
        Dog dog = new Dog();
        method01(dog);
        Cat cat = new Cat();
        method02(cat);
    }
    public static void method01(Dog dog){
        dog.makeSound();
    }
    public static void method02(Cat cat){
        cat.makeSound();
    }
}

这段代码是用普通的创建对象的方式:

这段代码中:method01 和method02这两个方法的参数分别是dog和cat,

因为Dog和Cat两个对象之间没有什么关系,所以,我们需要建两个方法,方法的参数分别是dog和cat

但是如果我们用了多态的创建对象的方式:

public static void main(String[] args) {
        //不用多态,用普通的方法
        Dog dog = new Dog();
        method01(dog);
        Cat cat = new Cat();
        method02(cat);
        //用多态的方式
        Animal animal = new Dog();
        method(animal);
        Animal animal1 = new Cat();
        method(animal1);
    }
    public static void method(Animal animal){
        animal.makeSound();
    }

我们用一个方法就可以实现上面的功能,并且如果动物的种类多了,用这种方式可以更好的实现代码的复用性

总结起来就是:

形参传递父类类型,调用此方法父类类型可以接收任意它的子类对象
传递哪个子类对象,就指向哪个子类对象,就调用哪个子类对象重写的方法

 

多态中的转型

一:向上转型:

        1.父类引用指向子类对象
          好比是: double b = 1;

二:向下转型:

        1.向下转型:好比强转,将大类型强制转成小类型
        2.表现方式:
          父类类型 对象名1 = new 子类对象() -> 向上转型 -> double b = 1
          子类类型 对象名2 = (子类类型)对象名1 -> 向下转型 -> int i = (int)b
        3.想要调用子类特有功能,我们就需要向下转型 

具体讲一下第三点调用子类特有功能:

看代码:

public abstract class Animal {
    public abstract void eat();
}
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    //特有方法
    public void catchMouse(){
        System.out.println("猫会捉老鼠");
    }
}
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗啃骨头");
    }

    //特有方法
    public void lookDoor(){
        System.out.println("狗会看门");
    }
}
public class Test01 {
    public static void main(String[] args) {
        //多态new对象  向上转型
        Animal animal = new Dog();
        animal.eat();//dog重写的
        //animal.lookDoor();//多态不能调用子类特有功能

        //向下转型
        Dog dog = (Dog) animal;
        dog.eat();
        dog.lookDoor();
    }
}

这段代码中,猫和狗都有一个自己特定的方法捉老鼠和看门,

父类对象animal如果想要调用这两个方法,就需要向下转型

转型时会遇到的问题:

如果等号左右两边类型不一致,会出现类型转换异常(ClassCastException)

在我们进行类型转换的时候难免会发生这个异常

比如我们去调用一个别人写好的方法,我们不知道类型,我们直接进行强转,就很容易错

解决办法:


  在向下转型之前,先判断类型 关键字:instanceof
  判断结果是boolean型
  对象名 instanceof 类型 -> 判断的是关键字前面的对象是否符合关键字后面的类型

具体看代码:

public static void method(Animal animal){
        if(animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.lookDoor();
        }
        if(animal instanceof Cat){
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }
    }

判断传进来的类型再进行输出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/753369.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL高级-SQL优化- order by 优化(尽量使用覆盖索引、注意联合索引创建的规则、增大排序缓冲区大小)

文章目录 0、order by优化原则1、Using filesort2、Using index3、连接数据库4、查看索引5、删除索引6、按照年龄进行排序7、执行计划 order by age8、执行计划 order by age,phone9、创建联合索引 (age,phone)10、再次执行计划 order by age11、再次执行计划 order by age,pho…

SpringMVC处理器映射器HandlerMapping详解

目录 一、前言 二、initHandlerMappings 三、处理器映射器架构 策略接口 请求链 模版类 四、RequestMappingHandlerMapping的初始化 HandlerMethod映射器模版类的初始化 AbstractHandlerMethodMapping.MappingRegistry:内部类注册中心 五、Reques…

从菌群代谢到健康影响——认识肠道丙酸和丁酸

谷禾健康 短链脂肪酸这一词经常出现在谷禾的文章和报告中,那你真的了解短链脂肪酸吗?短链脂肪酸(SCFA)主要是肠道微生物群在结肠内通过发酵碳水化合物(包括膳食和内源性碳水化合物,主要是抗性淀粉和膳食纤维)和一些微生物可利用的蛋白质而产生…

一个人 三个月 干了二十万

相信很多人是被这个标题吸引进来的,但我并不是标题党,我也很讨厌标题党,这篇文章也不在乎流量,更多的是想记录下。 出来创业三个多月了,给大家汇报一下这段时间的业绩吧。一个人,三个多月,干了…

线性图标绘制指南:从基础到精通

图标在生活中随处可见。相比文字来说,图标可以让人在更短的时间内认知并了解信息,并且大大提升信息的视觉美观性,增加设计的艺术感染力。在用户界面中使用图标,是一种用户熟知的设计模式。而线性图标是通过提炼图形轮廓&#xff0…

TIOBE 6月榜单出炉!编程语言地位大洗牌,谁才是王?

C历史上首次超越C!!! TIOBE 公布了 2024 年 6 月编程语言的排行榜:https://www.tiobe.com/tiobe-index/ 排行榜 以下列出的语言代表了第51至第100名。由于它们之间的差异相对较小,编程语言仅以字母顺序列出。 ABC, A…

ubuntu16.04上搭建qt开发环境

安装qt 下载qt在linux下的安装包qt-opensource-linux-x64-5.8.0.run;将安装包拷贝到ubuntu16.04上;执行如下命令进行安装,注意:安装前先断开虚拟机的网络,这样就避免了注册账户的操作 基本上一路按“next”键&#xf…

使用青否数字人直播软件有哪些优势?

使用青否数字人主播主要具有以下优势: 1、降低直播门槛 在垂直程度较高、专业度更强的行业,面对相关品牌们“专业主播难培养”的问题。数字人主播的学习技能和灵活优势尽显。通过数字人直播可以借助知识库配置与AI能力,快速获得技术性知识&am…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 螺旋矩阵填数(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 &#x1f…

c语言--指针

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理c语言中指针的相关知识点。 指针概念 指针存储的就是数据的地址。 直观理解: 李华家是北洋路130号1单元101 用变量处理数据: 我们去李华家拿数据。 用指针处理数据: 我们去北洋路130号1单元101拿数据…

石墨舟氮气柜的特点和使用要求介绍

石墨舟是一种在半导体、太阳能光伏等高科技产业中广泛使用的专用工具,主要由高纯度石墨材料制成。它的形状通常像一只船,因此得名“石墨舟”。石墨舟主要用于承载硅片或其他基板材料通过各种高温处理过程,是制造半导体器件和太阳能电池片的关…

二叉树的方法

目录 一、二叉树的定义 ​编辑 二、二叉树的创建 三、二叉树的遍历 1、前序遍历 2、中序遍历 3、后序遍历 4、层序遍历 四、二叉树遍历方法的使用 五、二叉树的操作 1、节点的个数 2、叶子节点的个数 3、第k层节点的个数 4、二叉树的高度 5、检查值为value的元素…

「2024抢先看」6款免费的ai变声器,助你开麦就变声

你是否也曾想模仿电视剧中的明星说话,或者想像泰勒一样有着独特的嗓音呢?通过免费版ai变声器,你可以轻松实现实时变声,将你的声音转换为专业且动听的声音,让身边的朋友对你刮目相看。在本文中,小编将分享20…

服务器日志事件ID4107:从自动更新 cab 中提取第三方的根目录列表失败,错误为: 已处理证书链,但是在不受信任提供程序信任的根证书中终止。

在查看Windows系统日志时,你是否有遇到过事件ID4107错误,来源CAPI2,详细信息在 http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/authrootstl.cab 从自动更新 cab 中提取第三方的根目录列表失败,…

简单的本地局域网的前后端接口联调

由于项目被赶进度了,急于前后端联调接口,但是我又没钱买服务器(主要我也不会部署),所以我这里就紧急找一个后端的大神朋友请教了一下:苏泽SuZe-CSDN博客 提示:这里不讲后端怎么写接口、前端怎么…

C#——里氏转换详情

里氏转换 里氏转换就是派生类的对象赋值给父类对象,反之则不行 实例 : 先创键一个类然后继承 调用

双路视频同屏显示(拼接)-基于野火Zynq7020开发板

前情提要 米联客FDMA驱动OV5640摄像头—基于野火Zynq7020开发板 本文在此基础上,实现了双路视频拼接。将ov5640输出的1024600的图像数据缩放为512600,分两路写入ddr3,并且显示在1024*600的RGB屏幕中。 纯FPGA也可以按此方法实现。 总体BLOC…

【C++ 初阶路】--- 类和对象(末)

目录 一、const成员1.1 取地址及const取地址操作符重载 二、再谈构造函数2.1 构造函数体赋值2.2 初始化列表2.3 explicit关键字 三、static成员3.1 概念3.2 特性 四、友元4.1 友元函数4.2 友元类 五、内部类六、匿名对象 一、const成员 将const修饰的“成员函数”称之为const成…

Qt creator实现一个简单计算器

目录 1 界面设计 2 思路简介 3 代码 目录 1 界面设计 ​2 思路简介 3 代码 3.1 widget.h 3.2 widget.c 4 完整代码 在这里主要记载了如何使用Qt creator完成一个计算器的功能。该计算器可以实现正常的加减乘除以及括号操作,能实现简单的计算器功能。 1 界…

北京站圆满结束!MongoDB Developer Day上海站,周六见!

上周六 MongoDB Developer Day首站北京站 80位开发者与MongoDB一起度过了充实的一天 专题讲座➕动手实操➕专家面对面交流 从数据建模、进阶查询技巧 到Atlas搜索与向量搜索 让参会伙伴们直呼“满满的技术干货!” 全体参会者与工作人员合影 MongoDB Developer …