数据结构和类/对象之间的区别在 Java 中比在 C++ 中更难解释。在 C 中,没有类,只有数据结构,它们只不过是类型化和命名字段的“容器”。 C++ 继承了这些“结构”,因此您可以同时拥有“经典”数据结构和“真实对象”。
在 Java 中,您可以使用没有方法且只有公共字段的类“模拟”C 风格的数据结构:
public class VehicleStruct
{
public Engine engine;
public Wheel[] wheels;
}
VehicleStruct 的用户知道车辆的部件,并且可以直接与这些部件进行交互。行为,即函数,必须在类之外定义。这就是改变行为很容易的原因:添加新功能不需要更改现有代码。另一方面,更改数据需要更改与VehicleStruct 交互的几乎每个函数。它违反了封装!
OOP 背后的想法是隐藏数据并公开行为。它着重于您可以对车辆做什么,而无需知道它是否有发动机或安装了多少个轮子:
public class Vehicle
{
private Details hidden;
public void startEngine() { ... }
public void shiftInto(int gear) { ... }
public void accelerate(double amount) { ... }
public void brake(double amount) { ... }
}
请注意Vehicle 可能是摩托车、汽车、卡车或坦克——您无需了解详细信息。更改数据很容易——班外没有人知道数据,因此不需要更改班级的用户。改变行为是困难的:当一个新的(抽象)函数被添加到类中时,所有的子类都必须调整。
现在,遵循“封装规则”,您可以将隐藏数据理解为简单地将字段设为私有并将访问器方法添加到VehicleStruct:
public class VehicleStruct
{
private Engine engine;
private Wheel[] wheels;
public Engine getEngine() { return engine; }
public Wheel[] getWheels() { return wheels; }
}
在他的书中,鲍勃叔叔认为,通过这样做,您仍然拥有数据结构而不是对象。您仍然只是将车辆建模为其各部分的总和,并使用方法公开这些部分。它本质上与具有公共字段和普通旧 C struct 的版本相同——因此是数据结构。隐藏数据和公开方法不足以创建对象,您必须考虑这些方法实际上是公开行为还是仅公开数据!
当您混合使用这两种方法时,例如暴露getEngine() 和startEngine(),你最终会得到一个“混合”。我手头没有 Martin 的书,但我记得他根本不推荐混合,因为你最终会得到两全其美的结果:数据和行为都很难改变的对象。
您关于 HashMaps 和 Strings 的问题有点棘手,因为它们的级别非常低,不太适合您将为应用程序编写的类。不过,使用上面给出的定义,您应该能够回答它们。
HashMap 是一个对象。它向您展示其行为并隐藏所有令人讨厌的散列细节。你把它告诉put 和get 数据,而不关心使用哪个散列函数,有多少“桶”,以及如何处理冲突。实际上,您仅通过其Map 接口使用HashMap,这很好地表明了抽象和“真实”对象。
您可以使用 Map 的 instances 作为数据结构的替代品,不要感到困惑!
// A data structure
public class Point {
public int x;
public int y;
}
// A Map _instance_ used instead of a data structure!
Map<String, Integer> data = new HashMap<>();
data.put("x", 1);
data.put("y", 2);
另一方面,String 几乎是一个字符数组,不会试图隐藏太多。我想可以将其称为数据结构,但老实说,我不确定是否会以一种或另一种方式获得很多。