ALPHA第四章 多态,接口,抽象类

server/2024/12/25 12:38:18/

在给出的选项中,错误的叙述是

子类可以继承父类的构造函数

详细分析:

1. 子类可以继承父类的构造函数

错误的
在 Java 中,子类不能继承父类的构造函数。构造函数是用来初始化对象的,因此构造函数是不能被继承的,但子类可以通过 super() 显式调用父类的构造函数。

2. 子类中调用父类构造函数不可以直接书写父类构造函数,而应该用 super();

正确的
子类的构造函数不能直接写父类的构造函数,而是应该使用 super() 来显式调用父类的构造函数。super() 必须是构造函数的第一行代码。通过 super() 可以调用父类的无参或带参构造函数。

示例:

class Parent {

Parent() {

System.out.println("Parent Constructor");

}

}

class Child extends Parent {

Child() {

super(); // 调用父类的构造函数 System.out.println("Child Constructor");

}

}

3. 用 new 创建子类的对象时,若子类没有带参构造函数,将先执行父类的无参构造函数,然后再执行自己的构造函数

正确的
如果子类没有定义带参构造函数,Java 会自动提供一个无参构造函数。在创建子类对象时,子类的构造函数会先执行,若没有显式调用父类构造函数,Java 会默认调用父类的无参构造函数。然后,子类构造函数的内容会被执行。

示例:

class Parent {Parent() {System.out.println("Parent Constructor");}
}

class Child extends Parent {
    Child() {
        super();  // 调用父类的构造函数
        System.out.println("Child Constructor");
    }
}
 

4. 子类的构造函数中可以调用其他函数

正确的
在子类的构造函数中,完全可以调用其他方法(包括父类的方法)。不过需要注意的是,方法调用应该是在构造函数的主体部分,而不能替代构造函数的调用逻辑。

示例:

class Parent {Parent() {System.out.println("Parent Constructor");}
}class Child extends Parent {Child() {System.out.println("Child Constructor");}
}public class Test {public static void main(String[] args) {new Child();  // 输出顺序是:Parent Constructor -> Child Constructor}
}

总结:

  • 错误的选项是:“子类可以继承父类的构造函数”。
  • 其他的选项都是正确的叙述。

1.extends只能接一个,继承据有传递性,但不具有多继承

2.implements可以多接口

多态

注意:

protected方法可以被子类所访问

在 Java 中,Person p = new Child(); 是一个非常常见的 向上转型(upcasting)操作。让我们详细解释这一行代码的含义和背后的概念。

1. 基本的类继承关系

首先,理解这段代码需要知道类 PersonChild 的继承关系:

public class Person {private String name = "Person";  // private:只能在当前类中访问int age = 0;  // 默认访问修饰符:包内可见
}public class Child extends Person {public String grade;
}
  • Child 是 Person 的子类。
  • Person 类有两个字段:一个 private String name 和一个 int agename 是 private,只能在 Person 类内部访问;age 是包内可见(默认修饰符),可以在同一个包内的其他类中访问。
  • Child 类继承了 Person 类,并且可以拥有自己的字段和方法。当前例子中,Child 只有一个字段 grade

2. 向上转型(Upcasting)

这行代码:

Person p = new Child();

向上转型 的一个例子。具体来说,它是将 Child 类型的对象赋值给一个 Person 类型的变量 p

向上转型 的意思是:将子类的对象赋给父类类型的变量。因为 ChildPerson 的子类,所以 Child 类型的对象可以被赋给 Person 类型的变量。Java 中允许这种赋值操作,且它是隐式的,不需要显式转换。

3. 为什么可以这么做?

在面向对象编程(OOP)中,子类对象是父类对象的一种特殊类型。也就是说,ChildPerson 的一种类型,因此可以通过父类类型(Person)来引用子类对象(Child)。这是继承的多态特性。

  • Child 是 Person 的子类,因此 Child 对象不仅拥有 Child 类的成员(字段和方法),还继承了 Person 类的成员(字段和方法)。
  • 通过 Person p = new Child();,你可以在 p 变量中引用 Child 类型的对象,但只能访问 Person 类中定义的公共方法和字段。

4. 访问权限和方法

由于 p 的类型是 Person,所以你只能通过 p 访问 Person 类中的字段和方法。例如,在上面的代码中,Person 类有一个私有字段 name,它在 Child 类的对象中是不可访问的。即使 p 引用的是一个 Child 对象,你仍然只能访问 Person 类中 p 能访问的字段(如 age)。

举个例子:

public class Person {private String name = "Person";  // 只能在Person类中访问int age = 0;  // 在同一包内的类可以访问public String getName() {return name;}
}public class Child extends Person {public String grade;public void printGrade() {System.out.println(grade);}
}public class Test {public static void main(String[] args) {Person p = new Child();  // 向上转型,Child对象赋给Person类型的变量System.out.println(p.age);  // 可以访问父类的age字段// System.out.println(p.grade);  // 错误:p是Person类型,无法访问Child类的grade字段}
}

5. 总结

Person p = new Child(); 是一个合法的语法,它表示:

  • 创建了一个 Child 类型的对象;
  • 使用 Person 类型的变量 p 引用这个 Child 对象。

通过 p 这个 Person 类型的引用,我们只能访问 Person 类中定义的成员(比如 age),而不能直接访问 Child 类中特有的成员(比如 grade)。但是,我们可以通过向下转型(downcasting)将 p 强制转换回 Child 类型,从而访问 Child 中特有的成员。

例如:

Child c = (Child) p;  // 向下转型
c.grade = "A";  // 访问Child类的grade字段

在这个问题中,我们需要分析 Parent 类中的方法及其访问修饰符的权限,并判断子类能否继承和覆盖这些方法。下面是对每个选项的逐一分析:

1. 子类中一定能够继承和覆盖 Parent 类的 m1 方法

  • m1() 方法是 private 修饰的。private 修饰符的作用是限制方法的访问范围,表示该方法只能在当前类内部访问,子类无法访问。
  • 结论:子类不能继承和覆盖 m1 方法。

因此,这个选项是错误的

2. 子类中一定能够继承和覆盖 Parent 类的 m2 方法

  • m2() 方法是包级私有的(即没有修饰符,默认是 "default"),这意味着该方法在同一包内的类中是可以访问的,但在不同包中的类中不可访问。
  • 如果子类和父类在同一个包内,子类可以继承和覆盖 m2() 方法。
  • 如果子类与父类不在同一个包内,则子类无法访问 m2() 方法,无法继承和覆盖。
  • 结论:只有在子类与父类处于同一包时,子类才能继承和覆盖 m2 方法。

因此,这个选项是部分正确的(子类能继承和覆盖,前提是它们在同一个包中)。

3. 子类中一定能够继承和覆盖 Parent 类的 m3 方法

  • m3() 方法是 protected 修饰的。protected 修饰符的作用是,允许该方法在同一包中的类以及所有子类中访问。
  • 无论子类是否与父类处于同一包中,子类都可以继承和覆盖 m3() 方法。
  • 结论:子类一定能够继承和覆盖 m3 方法。

因此,这个选项是正确的

4. 子类中一定能够继承和覆盖 Parent 类的 m4 方法

  • m4() 方法是 public static 修饰的。public 表示该方法可以被任何类访问,而 static 表示该方法是静态的。
  • 静态方法是属于类的,而不是实例的,因此子类不能像实例方法一样重写静态方法。子类可以继承静态方法,但是不能覆盖静态方法(即不允许通过子类来改变静态方法的实现)。
  • 结论:子类能够继承 m4 方法,但不能覆盖它。

因此,这个选项是错误的,因为子类不能覆盖静态方法。

总结:

  • 子类一定能够继承和覆盖 Parent 类的 m1 方法:错误
  • 子类一定能够继承和覆盖 Parent 类的 m2 方法:部分正确(仅当子类与父类在同一包时)
  • 子类一定能够继承和覆盖 Parent 类的 m3 方法:正确
  • 子类一定能够继承和覆盖 Parent 类的 m4 方法:错误

在这个问题中,我们需要分析每个 System.out.println() 输出的结果,来确定输出 true 的个数。

首先,来看一下类的继承关系:

class A{}

class B extends A{}

class C extends A{}

class D extends B{}

  • A 是基类。
  • B 和 C 都继承自 A
  • D 继承自 B

接下来,看看 A obj = new D(); 这行代码的含义。它声明了一个类型为 A 的引用 obj,并将一个 D 类的实例赋值给它。由于 D 继承自 B,而 B 又继承自 A,所以 obj 实际上是指向一个 D 类型的对象。

分析 instanceof 的每个表达式

  1. obj instanceof B

    • obj 是一个 D 类的实例,而 D 继承自 B
    • 因此,obj instanceof B 返回 true,因为 obj 是 B 类型的一个实例(通过继承关系)。
  2. obj instanceof C

    • obj 是 D 类的实例,而 C 和 B 是平行的(即 C 不是 B 的子类,也不是 B 的父类)。
    • 所以 obj instanceof C 返回 false,因为 obj 既不是 C 类型,也不属于 C 的继承体系。
  3. obj instanceof D

    • obj 是 D 类的实例,因此 obj instanceof D 返回 true
  4. obj instanceof A

    • obj 是 D 类的实例,而 D 继承自 BB 继承自 A,因此 obj 也是 A 的一个实例。
    • 所以 obj instanceof A 返回 true

总结:

  • obj instanceof B 返回 true
  • obj instanceof C 返回 false
  • obj instanceof D 返回 true
  • obj instanceof A 返回 true

因此,输出 true 的个数是 3

答案:3

静态类不能被继承

举一个实际的例子,说明 super()this() 的使用,以及为什么某些描述是错误的。

例子 1:super() 和 this() 必须放在构造方法的第一行

class Animal {public Animal() {System.out.println("我是一只动物");}
}class Dog extends Animal {public Dog() {// 错误:super() 必须是第一行System.out.println("我是一只狗");super();  // 编译错误}
}public class Test {public static void main(String[] args) {Dog dog = new Dog();  // 编译错误}
}
解释:
  • super() 必须是构造方法中的第一行。如果你在构造方法里先执行了其他语句(如 System.out.println("我是一只狗")),然后再调用 super(),就会导致编译错误。

例子 2:super() 和 this() 不能同时出现在同一个构造函数中

class Animal {public Animal() {System.out.println("我是一只动物");}
}class Dog extends Animal {public Dog() {// 错误:不能同时使用 super() 和 this()this("小狗");   // 错误super();       // 错误System.out.println("我是一只狗");}public Dog(String name) {System.out.println("狗的名字是:" + name);}
}public class Test {public static void main(String[] args) {Dog dog = new Dog();  // 编译错误}
}
解释:
  • 在一个构造方法中,不能同时使用 super() 和 this()。构造方法中只能使用其中之一,且必须是第一行语句。Java 不允许 this() 和 super() 在同一个构造方法中同时出现。

例子 3:super() 和 this() 不能在 static 方法中使用

class Animal {public Animal() {System.out.println("我是一只动物");}
}class Dog extends Animal {public Dog() {super();System.out.println("我是一只狗");}public static void staticMethod() {// 错误:不能在静态方法中使用 super() 或 this()super();  // 编译错误this();   // 编译错误}
}public class Test {public static void main(String[] args) {Dog.staticMethod();  // 编译错误}
}
解释:
  • super() 和 this() 不能在 static 方法中使用。它们都依赖于实例对象,而 static 方法属于类级别的方法,不依赖于实例。因此,尝试在 static 方法中使用 super() 或 this() 会导致编译错误。

例子 4:super() 是构造方法的第一行

class Animal {public Animal() {System.out.println("我是一只动物");}
}class Dog extends Animal {public Dog() {// 正确:super() 必须是第一行super();  // 父类构造方法必须是第一行System.out.println("我是一只狗");}
}public class Test {public static void main(String[] args) {Dog dog = new Dog();  // 输出:我是一只动物\n我是一只狗}
}
解释:
  • 这是一个正确的例子。子类 Dog 的构造方法中,super() 被放在了第一行,并且成功调用了父类 Animal 的构造方法。

结论:

  • super() 必须是构造方法的第一行。
  • super() 和 this() 不能同时出现在同一个构造函数中。
  • super() 和 this() 不能在静态方法中使用。

方法重写(Method Overriding) 是面向对象编程中的一个重要概念,主要出现在继承的情境中。它指的是在子类中重新定义父类已经定义过的方法,以改变或者扩展父类方法的行为。

关键特点:

  1. 继承关系:方法重写是发生在子类与父类之间的。子类继承了父类的属性和方法,但有时子类希望对父类的方法进行不同的实现。
  2. 方法签名相同:重写的方法必须与父类中的方法有相同的签名,即方法名、参数列表和返回类型必须一致。否则,它就不是重写,而是方法的重载(Overloading)。
  3. 实现不同:子类重写父类的方法后,可以提供不同的实现,以便满足特定的需求。这样,子类可以修改或扩展父类的行为,而不需要改变父类本身的代码。
  4. 多态性:方法重写是实现多态性的基础。当父类引用指向子类对象时,调用的将是子类中重写的方法,而不是父类的方法。

1.父类中的同名成员方法被屏蔽

填空题

Java规定,如果子类中定义的成员方法与父类中定义的成员方法同名,并且参数的个数和类型以及(返回值)的类型也相同, 则父类中的同名成员方法被屏蔽。

2.所有类的父类Object

3.不可被继承的类

填空题

定义一个Java类时,如果前面使用(final)关键字修饰,那么该类不可以被继承。

4.

继承的定义

填空题

在Java语言中,允许使用已存在的类作为基础创建新的类,这种技术称为(继承)

5.创建一个人的类Student

程序填空

创建一个人的类Student,属性包括姓名和年龄,方法包括构造方法(初始化一个人的姓名和年龄)、显示姓名和年龄的方法;创建一个学生类Prog1,是从Student类继承而来,Prog1类比Student类多一个成员变量“所在学校”,Prog1的方法包括构造方法(借助父类的方法对学生的三个属性进行初始化)和显示学生的三个属性方法;最后创建一个学生对象并显示其自然信息。

形状的多态性

程序填空

下面的程序设计一个名为的超类Shape,它定义所有形状的公共接口(或行为)。所有形状都有一个称为的方法getArea(),该方法返回该特定形状的面积。

补全下面代码,使得父类的引用分别指向三角形和矩形。

class Shape {private String color;public Shape (String color) {this.color = color;}public String toString() {return "Shape[color=" + color + "]";}public double getArea() {System.err.println("Shape unknown! Cannot compute area!");return 0;}
}
class Rectangle extends Shape {private int length, width;public Rectangle(String color, int length, int width) {super(color);this.length = length;this.width = width;}public String toString() {return "Rectangle[length=" + length + ",width=" + width + "," + super.toString() + "]";}public double getArea() {return length*width;}
}
class Triangle extends Shape {private int base, height;public Triangle(String color, int base, int height) {super(color);this.base = base;this.height = height;}public String toString() {return "Triangle[base=" + base + ",height=" + height + "," + super.toString() + "]";}public double getArea() {return 0.5*base*height;}
}
public class Program{public static void main(String[] args){Shape s1 = new Rectangle("red", 4, 5);System.out.println(s1);Shape s2 = new Triangle ("blue", 4, 5);System.out.println(s2);  }
}
 

为了完成这个程序,我们需要判断 an1 的本质类型,并根据其类型执行相应的代码。由于 DogCat 都是实现了 Animal 接口的类,我们需要通过 instanceof 运算符来判断 an1 是否是 Cat 类型的实例。

解释:public class Program {
    public static void main(String[] args) {
        Animal an1 = new Dog(); // 创建一个Dog对象,并将其赋值给Animal类型的变量an1
        
        // 判断an1是否是Cat类型的实例
        if(an1 instanceof Cat){ 
            Cat cat = (Cat) an1; // 强制转换an1为Cat类型
            cat.shout(); // 调用Cat类的shout方法
            cat.catchMouse(); // 调用Cat类的catchMouse方法
        }else{
            System.out.println("该类型的对象不是Cat类型!"); // 如果an1不是Cat类型,输出提示信息
        }
    }
}

instanceof 运算符用于判断对象是否是某个类的实例。此处,我们判断 an1 是否是 Cat 类的实例。

  1. 如果 an1Cat 类型的对象(即 an1 instanceof Cattrue),则进行强制类型转换,将 an1 转换为 Cat 类型并调用 shout()catchMouse() 方法。

  2. 如果 an1 不是 Cat 类型的对象,则输出 "该类型的对象不是Cat类型!"。

注意:

  • 在你的代码中an1 被初始化为 new Dog(),所以它实际上是 Dog 类型的对象,因此 instanceof Cat 判断会返回 false,并且程序会输出 "该类型的对象不是Cat类型!"。
  • 如果你将 an1 初始化为 new Cat(),那么 instanceof Cat 判断会为 true,然后会调用 Cat 类的方法。

乐器的多态实现

程序填空

下面的代码,实现多态,乐器(Instrument )分为:钢琴( Piano )、小提琴( Violin ) ,各种乐器的弹奏( play )方法各不相同。

填空使得,依据乐器的不同,进行相应的弹奏。

动物类实现多态

程序填空

下面的代码编写 Animal 及其实现类。

定义了测试类 Program,请补全代码,使得程序输出 抓老鼠


http://www.ppmy.cn/server/153038.html

相关文章

Linux -- 线程的优点、pthread 线程库

目录 线程的优点 pthread 线程库 前言 认识线程库 简单验证线程的独立栈空间 线程的优点 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少得多。 调度进程时,CPU 中有一个 cache(缓存,提高运行效率&#xff0…

Linux RTC 驱动框架

目录 一、实时时钟(RTC)介绍1.1 概述1.2 功能1.3 应用场景1.4 工作原理1.5 对外接口1.6 常见 RTC 芯片1.7 在 Linux 系统中的应用1.8 注意事项 二、Linux 内核 RTC 驱动框架2.1 相关源码文件介绍2.2 核心数据结构2.2.1 struct rtc_device2.2.2 rtc_class…

memcached 与 redis 的区别?

1、Redis 不仅 仅 支 持 简 单 的 k/v 类型 的 数 据 ,同时 还 提 供 list,set,zset,hash等数 据 结 构 的 存 储 。而 memcache 只支 持 简 单 数 据 类 型 ,需要 客 户 端 自 己 处 理 复杂对 象 2、 Redis 支持 数 …

对象、函数、原型之间的关系

在 JavaScript 中,对象、函数 和 原型 是三者紧密联系的核心概念。它们共同构成了 JavaScript 中面向对象编程的基石,并通过原型链实现了继承与代码复用。本文将从对象、函数、原型的基础概念到它们之间的关系进行详细的讲解,帮助你理解 Java…

Hive其三,数据库操作,小技巧设置,加载数据等操作

目录 一、操作数据库 二、关于表的操作 1)关于字符类型的 2)创建表 3) 修改表 4)删除表 5) 小案例演示 三、Hive中经常使用的小技巧的设置 四、加载数据 1)加载本地数据: 2)从HDFS加载到Hive中&a…

基于Spring Boot的校园商城系统

一、系统背景与意义 随着互联网技术的快速发展,电子商务已经渗透到生活的方方面面。校园作为一个相对封闭但活跃的社群,同样需要一个专门的线上平台来满足其特殊的需求。基于Spring Boot的校园商城系统正是为此目的而设计,它结合了微服务架构…

【开源】一款基于SpringBoot的智慧小区物业管理系统

一、下载项目文件 项目文件源码链接:https://pan.quark.cn/s/3998d958e182如出现网盘空间不够存的情况!!!解决办法是先用夸克手机app注册,然后保存上方链接,就可以得到1TB空间了!!&…

【深入理解@EnableCaching】

深入理解EnableCaching EnableCaching 是 Spring Framework 中用于启用和配置缓存机制的一个注解。它通常被应用在配置类上,用来告诉 Spring 容器需要激活缓存相关的功能。Spring 的缓存抽象提供了一种简单的机制来管理缓存,可以减少重复的计算或数据库…