composition java_灵魂拷问之阿里面试官:Java的继承与构造,如何选择?

继承和构造是开发人员用来在类和对象之间建立关系的两种编程技术。继承是从另一类继承一个类,而组合将一个类定义为其部分的总和。

通过继承创建的类和对象紧密耦合,因为在继承关系中更改父类或超类可能会破坏您的代码。通过合成创建的类和对象是松散耦合的,这意味着您可以更轻松地更改组件,而不会破坏代码。

b6917b8e450722c044783a45dd18308d.png

因为松散耦合的代码提供了更大的灵活性,所以许多开发人员已经了解到,构造是比继承更好的技术,但事实更复杂。选择编程工具类似于选择正确的厨房工具:您不会使用黄油刀切菜,并且同样的,您不应为每种编程场景都选择成分。

何时在Java中使用继承

在面向对象的编程中,当我们知道孩子与其父类之间存在“是”关系时,就可以使用继承。一些示例是:

· 一个人就是一个人。

· 猫是动物。

· 汽车就是 车辆。

在每种情况下,子类或子类都是父类或超类的专门版本。从超类继承是代码重用的一个示例。为了更好地理解这种关系,请花点时间学习Car该类,该类继承自Vehicle:

class Vehicle {

String brand;

String color;

double weight;

double speed;

void move() {

System.out.println("The vehicle is moving");

}

}

public class Car extends Vehicle {

String licensePlateNumber;

String owner;

String bodyStyle;

public static void main(String... inheritanceExample) {

System.out.println(new Vehicle().brand);

System.out.println(new Car().brand);

new Car().move();

}

}

在考虑使用继承时,请问问自己,子类是否真的是超类的更专门的版本。在这种情况下,汽车是车辆的一种,因此继承关系很有意义。

何时在Java中使用合成

在面向对象的编程中,我们可以在一个对象“具有”(或属于)另一个对象的情况下使用组合。一些示例是:

· 汽车有电池(电池是汽车的一部分)。

· 一个人有心脏(心脏是人的一部分)。

· 房子有一个客厅(客厅是房子的一部分)。

为了更好地理解这种类型的关系,请考虑a的组成House:

public class CompositionExample {

public static void main(String... houseComposition) {

new House(new Bedroom(), new LivingRoom());

// The house now is composed with a Bedroom and a LivingRoom

}

static class House {

Bedroom bedroom;

LivingRoom livingRoom;

House(Bedroom bedroom, LivingRoom livingRoom) {

this.bedroom = bedroom;

this.livingRoom = livingRoom;

}

}

static class Bedroom { }

static class LivingRoom { }

}

在这种情况下,我们知道一所房子有一个客厅和一间卧室,因此我们可以使用Bedroom和 LivingRoom对象构成一个House。

获取代码

获取此Java Challenger中示例的源代码。您可以在遵循示例的同时运行自己的测试。

继承与组成:两个例子

考虑以下代码。这是继承的好例子吗?

import java.util.HashSet;

public class CharacterBadExampleInheritance extends HashSet<Object> {

public static void main(String... badExampleOfInheritance) {

BadExampleInheritance badExampleInheritance = new BadExampleInheritance();

badExampleInheritance.add("Homer");

badExampleInheritance.forEach(System.out::println);

}

在这种情况下,答案是否定的。子类继承了许多永远不会使用的方法,从而导致紧密耦合的代码既混乱又难以维护。如果仔细观察,很显然此代码未通过“是”测试。

现在,让我们尝试使用组合的相同示例:

import java.util.HashSet;import java.util.Set;

public class CharacterCompositionExample {

static Set<String> set = new HashSet<>();

public static void main(String... goodExampleOfComposition) {

set.add("Homer");

set.forEach(System.out::println);

}

在这种情况下使用composition允许 CharacterCompositionExample类仅使用的两个HashSet方法,而无需继承所有方法。这样可以简化代码,减少耦合,使代码更易于理解和维护。

JDK中的继承示例

Java Development Kit充满了很好的继承示例:

class IndexOutOfBoundsException extends RuntimeException {...}

class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {...}

class FileWriter extends OutputStreamWriter {...}

class OutputStreamWriter extends Writer {...}

interface Streamextends BaseStreamStream> {...}

注意,在每个示例中,子类都是其父类的专门版本;例如,IndexOutOfBoundsException是的一种RuntimeException。

用Java继承重写方法

继承使我们可以在新类中重用一个类的方法和其他属性,这非常方便。但是,要使继承真正起作用,我们还需要能够在新的子类中更改某些继承的行为。例如,我们可能想专门制造一种声音Cat:

class Animal {

void emitSound() {

System.out.println("The animal emitted a sound");

}

}

class Cat extends Animal {

@Override

void emitSound() {

System.out.println("Meow");

}}

class Dog extends Animal {}

public class Main {

public static void main(String... doYourBest) {

Animal cat = new Cat(); // Meow

Animal dog = new Dog(); // The animal emitted a sound

Animal animal = new Animal(); // The animal emitted a sound

cat.emitSound();

dog.emitSound();

animal.emitSound();

}

}

这是带有方法覆盖的Java继承的示例。首先,我们扩展的Animal类来创建一个新的Cat类。接下来,我们覆盖的Animal类的emitSound()方法来获取特定声音的Cat品牌。即使我们将类类型声明为Animal,当我们实例化它时Cat也会得到猫的叫声。

方法重载是多态

您可能还记得我上一篇文章中的方法重写是多态或虚拟方法调用的示例。

Java是否具有多重继承?

与某些语言(例如C ++)不同,Java不允许对类进行多重继承。但是,您可以对接口使用多重继承。在这种情况下,类和接口之间的区别在于接口不保持状态。

如果您尝试像我在下面这样进行多重继承,则代码将无法编译:

class Animal {}class Mammal {}class Dog extends Animal, Mammal {}

使用类的解决方案将是逐一继承:

class Animal {}class Mammal extends Animal {}class Dog extends Mammal {}

另一个解决方案是用接口替换类:

interface Animal {}interface Mammal {}class Dog implements Animal, Mammal {}

使用“超级”访问父类方法

当两个类通过继承相关联时,子类必须能够访问其父类的每个可访问字段,方法或构造函数。在Java中,我们使用保留字super来确保子类仍然可以访问其父类的重写方法:

public class SuperWordExample {

class Character {

Character() {

System.out.println("A Character has been created");

}

void move() {

System.out.println("Character walking...");

}

}

class Moe extends Character {

Moe() {

super();

}

void giveBeer() {

super.move();

System.out.println("Give beer");

}

}

}

在此示例中,Character是Moe的父类。使用super,我们可以访问Character的 move()方法来给Moe喝啤酒。

将构造函数与继承一起使用

当一个类继承自另一个类时,在加载其子类之前,始终会先加载超类的构造函数。在大多数情况下,保留字super将自动添加到构造函数中。但是,如果超类在其构造函数中有一个参数,我们将不得不故意调用该super构造函数,如下所示:

public class ConstructorSuper {

class Character {

Character() {

System.out.println("The super constructor was invoked");

}

}

class Barney extends Character {

// No need to declare the constructor or to invoke the super constructor

// The JVM will to that

}

}

如果父类的构造函数带有至少一个参数,则必须在子类中声明该构造函数,并使用super它显式调用父构造函数。该super保留字不会被自动添加,没有它的代码将无法编译。例如:

public class CustomizedConstructorSuper {

class Character {

Character(String name) {

System.out.println(name + "was invoked");

}

}

class Barney extends Character {

// We will have compilation error if we don't invoke the constructor explicitly

// We need to add it

Barney() {

super("Barney Gumble");

}

}

}

类型转换和ClassCastException

强制转换是一种向编译器显式传达您确实打算转换给定类型的方法。就像说,“嘿,JVM,我知道我在做什么,所以请使用这种类型转换此类。” 如果您强制转换的类与声明的类类型不兼容,则将获得ClassCastException。

在继承中,我们可以在不强制转换的情况下将子类分配给父类,但是在不使用强制转换的情况下不能将父类分配给子类。

考虑以下示例:

public class CastingExample {

public static void main(String... castingExample) {

Animal animal = new Animal();

Dog dogAnimal = (Dog) animal; // We will get ClassCastException

Dog dog = new Dog();

Animal dogWithAnimalType = new Dog();

Dog specificDog = (Dog) dogWithAnimalType;

specificDog.bark();

Animal anotherDog = dog; // It's fine here, no need for casting

System.out.println(((Dog)anotherDog)); // This is another way to cast the object

}

}

class Animal { }class Dog extends Animal { void bark() { System.out.println("Au au"); } }

当我们尝试将Animal实例转换为时,Dog我们会得到一个异常。这是因为Animal对其子项一无所知。它可能是猫,鸟,蜥蜴等。没有关于特定动物的信息。

在这种情况下的问题是我们已经Animal像这样实例化了:

Animal animal = new Animal();

然后尝试将其投射如下:

Dog dogAnimal = (Dog) animal;

由于我们没有Dog实例,因此无法将分配Animal给Dog。如果尝试,将得到一个ClassCastException。

为了避免异常,我们应该Dog像这样实例化:

Dog dog = new Dog();

然后将其分配给Animal:

Animal anotherDog = dog;

在这种情况下,因为我们扩展了Animal类,所以Dog甚至不需要强制转换该实例。在Animal父类的类型只是接受任务。

用超类型进行转换

可以Dog使用超类型声明a Animal,但是如果我们要从中调用特定方法Dog,则需要对其进行强制转换。例如,如果我们想调用该bark()方法怎么办?该Animal超有没有办法知道到底是什么动物的情况下,我们是在调用,所以我们要投Dog之前手动我们可以调用bark()方法:

Animal dogWithAnimalType = new Dog();Dog specificDog = (Dog) dogWithAnimalType;

specificDog.bark();

您也可以在不将对象分配给类类型的情况下使用强制转换。当您不想声明另一个变量时,此方法很方便:

System.out.println(((Dog)anotherDog)); // This is another way to cast the object

最后,开发这么多年我也总结了一套学习Java的资料与面试题,如果你在技术上面想提升自己的话,可以关注我,私信发送领取资料或者在评论区留下自己的联系方式,有时间记得帮我点下转发让跟多的人看到哦。

09fb09832b67e554f1485b918dbf88d3.png
b824ce5a403637043086776a78647666.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值