【问题标题】:Meaning of Types, Class, Interface?类型、类、接口的含义?
【发布时间】:2011-01-06 13:34:25
【问题描述】:

发现许多作者交替使用术语类型和类。某些涵盖基于对象的模型的教科书也涵盖了术语接口。

有人可以根据一般的面向对象编程,特别是 C++/Java/面向对象的数据库,用简单的术语来解释这些。

【问题讨论】:

    标签: java c++ object oop object-oriented-database


    【解决方案1】:

    type 是一段数据的分类,告诉你它的允许值和允许的操作是什么。 (几乎?)所有编程语言都有类型,尽管打字规则因一种语言而异。

    class 是 OOP 语言中一种特殊的 kind 类型,它是用语言本身的特定语法定义的(与所谓的“本机类型”,如 Java 的 intfloat 等,由语言本身定义)。一个类通常根据内存布局和数据编码(所谓的成员变量)和作用于它们的函数(所谓的成员函数方法)。

    接口* 是对类型必须实现哪些操作才能被视为给定相似类型集的一部分的规范,但它没有指定允许的值、内存布局等。

    这是一个非常、非常、非常简短的概述,是几种语言处理这些方法的简化“平均形式”。它忽略了一些边缘情况以及诸如 C++ 在接口和类之间制作部分内容的能力。它还忽略了 Haskell 等函数式语言中的类,因为进一步损害你的大脑并不是这里的目标。 ;)


    编辑添加了一些例子

    这里有一些类似于 Java 的 声明,有助于巩固这些概念。

    int myVariable1;
    

    这个变量——myVariable1——是一个原生(或原始)类型,由一个以 2 补码表示法编码的 32 位有符号整数值组成。它有一个已知的范围(大约 -20 亿到 +20 亿)和一组已知的可用运算(乘法、加法、除法、模数、减法、各种转换等)。

    class MyClass
    {
      int myMemberVariable;
      int myOtherMemberVariable;
      int myMethod(int p) { myMemberVariable += p; myOtherMemberVariable = p; }
    }
    MyClass myVariable2 = new MyClass();
    

    这里的myVariable2 是由 MyClass 定义的类型。 MyClass 定义了内存布局(在这种情况下,它由两个 32 位有符号整数组成,采用 2s 补码表示法)以及单个操作 myMethod() 将其参数添加到 myMemberVariable 并将 myOtherMemberVariable 设置为论据。

    interface MyInterface
    {
      int myInterfaceMethod(int p, int q);
    }
    

    这里MyInterface 只声明了一组操作(在这种情况下由单个函数myInterfaceMethod() 组成),没有任何成员变量,也没有任何实现。它只告诉您,任何实现此接口的类都保证有一个方法,该方法具有名称 + 返回值 + 参数的特定签名。要使用它,您必须创建一个实现接口的类。

    class MyOtherClass implements MyInterface
    {
      int myMember1;
      int myMember2;
      int myMember3;
      int myInterfaceMethod(int p, int q) { myMember1 = p; myMember2 = q; myMember3 = p - q; }
      int myNonInterfaceMethod() { return myMember1; }
    }
    MyOtherClass myVariable3 = new MyOtherClass();
    

    现在myVariable3 被定义为具有由三个带符号的 32 位整数和两个操作组成的内存布局的类型。由于整个implements MyInterface 部分,其中一项操作是必须实施的。这样,任何期望(抽象)MyInterface 类型的东西都可以使用(具体)MyOtherClass 类型,因为操作保证在那里。另一种方法——myNonInterfaceMethod()——确实not来自 MyInterface,所以只需要 MyInterface 的东西不能使用它,因为它不知道它的存在。


    进一步 根据要求进行了编辑以添加一些真实世界的东西

    如果您曾经在程序中使用过整数值、浮点值、字符串或类似的东西,那么您就使用过类型。类型可以说是计算的东西,我们所做的一切都是对给定类型的值的操作。因此,我将重点关注 OOP 特定的类和接口概念。

    只要你有数据和对这些数据的操作,你就有可能成为一个类。以银行账户为例。除其他外,银行帐户将具有帐号、当前余额、交易限额等。表示此的类(很糟糕,仅用于解释概念)可能如下所示:

    class BankAccount
    {
      String accountNumber;
      float balance;  /* DO NOT USE FLOATING POINT IN REAL FINANCIAL CODE! */
      int transaction_limit;
      float transaction(float change) {
        balance += change > transaction_limit ? transaction_limit : change;
        return balance;
      }
    }
    

    现在你可以创建一个这种类型的变量,并且知道它将携带一个帐号(它本身是一个String 类型)、一个余额(它本身是一个float 类型——但是不要在真实世界的金融代码中使用浮点数!)和交易限制(它本身就是一个int 类型)。您还知道您可以执行交易(创造性地称为transaction),它将根据交易限制检查更改并修改余额。 (一个真正的类会包含更多内容,并且会包含很多我出于教学目的而删除的模糊保护内容。)

    现在假设您处于一个更复杂的金融环境中,其中有多种交易,而不仅仅是银行账户。进一步假设您有一些代码将处理不关心底层类型的细节是什么的事务。一个离线的交易批处理器,例如,涵盖银行账户、应收账款账户等。与其让它知道书中的每一种交易,我们可以这样做:

    interface Transactable
    {
      float transaction(float change);
    }
    
    class BankAccount implements Transactable
    {
      /* interior is identical */
    }
    
    class ReceivablesAccount implements Transactable
    {
      float balance;
      float transaction(float change) { balance += change; }
    }
    

    现在任何知道Transactable 类型的东西都可以使用BankAccount 的实例以及ReceivablesAccount 的实例。他们不必知道银行账户有交易限额,而应收账款账户没有。他们不必了解数据的内部表示。他们不必知道任何事情的特殊情况。他们只需要按名称了解一个函数 (transaction()) 就可以了。 (如果您想更具体地实际使用它,请查看集合类如何使用 Java 中的 Iterable 接口,更不用说“for in”循环了。)

    【讨论】:

    • 概念解释清楚。你能告诉一个现实生活中使用它的例子吗?
    • 天哪。你清楚地解释了这一点。你是一位非常好的老师。谢谢。
    【解决方案2】:

    在 O.O.P 的说法中,可以互换使用术语类型和类是很常见的,尤其是在谈论某些语言时,例如 java 和/或 C++。

    一般来说,当您定义一个类时,您实际上是在定义一个 Type 模板,将从中创建您定义的 Type 的对象,并且/或实例化。

    接口的概念有点复杂,当你定义一个接口时你基本上是在指定一种特殊的方式来处理使用它的任何类型的对象。也就是说,您的对象必须来自实现该接口的类。接口是一种通过指定原始类/类型规范中未包含的附加行为来增强类/类型的方法。

    出于许多实际目的,您可以将对象的接口视为接口类型,这可能就是术语接口与术语类型互换使用的原因。

    请参阅 Abstract Data Types 背后的理论以获取更多信息。

    【讨论】:

      【解决方案3】:

      就个人而言,我认为如果你用具体的术语来描述它会更容易理解。例如,假设我们要构建一个程序来跟踪厨房中的物品库存。

      大多数语言只知道整数、字符和字节等非常简单、原始的“类型”。我们完全可以使用这些原始类型来描述厨房中事物的类型。例如,您可以构造一个由字符数组组成的数组,其中数组中的每个索引代表某物的一个属性。就像,也许索引 0 代表您要描述的事物的“类型”。但是,当然,这种技术很快就会变得非常复杂。

      因此,使用面向对象技术,我们可以通过组合原始类型轻松定义新类型。你这样做的方法是创建一个类定义。将类视为新类型的蓝图。

      在厨房示例中,我们有“食物”类型、“电器”类型和“家具”类型的概念。为了在程序中使用这些新类型,我们需要为每个类型创建一个类定义:

      public class Food {...}
      public class Appliance {...}
      public class Furniture {...}
      

      接口描述了我们如何与某物进行交互。例如,我们想在厨房里创建一个物品清单。我们希望能够“添加”到我们的库存中,从我们的库存中“删除”东西,并可能“迭代”我们的库存。 “添加”、“删除”和“迭代”操作几乎适用于任何列表(不仅仅是我们的库存)。 Java 为此提供了一个名为"List" 的接口。通过使用非常流行和常见的列表“接口”创建一个清单对象,我们可以免费获得所有操作,其他程序员可以查看我们的程序并确切知道如何与“清单”对象交互:

      ...
      java.util.List inventory = new ArrayList(); 
      ...
      //later in our program, we can interact with inventory
      //  with any of methods on the list interface (because ArrayList "implements" List)
      inventory.add(new Furniture("chair"));
      inventory.add(new Appliance("refrigerator"));
      inventory.add(new Food("ice cream"));
      ...
      

      因此,在上面的示例中,inventory 是包含 ArrayList 类型实例的变量。由于 ArrayList 类定义实现了“List”接口,因此 ArrayList 类型的所有实例都必须遵守“List”接口中定义的约定。换句话说,我们可以像这样轻松地创建 inventory 作为 LinkedList(而不是 ArrayList):

      java.util.List inventory = new LinkedList();
      

      请记住将接口视为公开要执行的特定操作集的合同。因为 LinkedList 和 ArrayList 都实现了“List”接口,所以它们都有合同义务实现“List”接口中的所有方法。

      这样做的好处是,任何对使用我们的“库存”变量感兴趣的代码都不会对如何“添加”、“删除”或“迭代器”一无所知" 行动得到执行。他们所关心的是变量“inventory”服从“List”接口。

      换句话说,LinkedList 实现的“add”方法与 ArrayList 略有不同。但这对于任何想要使用我们的“库存”变量的代码都无关紧要。

      如果某个数学高手想出一种革命性的方式来存储列表。也许他们想出了如何在月球上而不是在计算机内存中存储列表,结果证明这比 ArrayList 快 10 倍。那么我们需要做的就是:

      java.util.List inventory = new CrazyMoonList();
      

      所有其他使用库存的代码可以保持完全相同,因为 CrazyMoonList 保证提供“添加”、“删除”等。

      希望这有助于澄清概念!

      【讨论】:

      • 这个真实的例子清楚地给了我正确的概念。我在这里有一个问题。 java.util.List inventory; 这到底是什么意思?那么接口generally指的是一些预定义的东西?
      • 酷,很高兴它有帮助。我稍微阐述了interface的概念。我花了很长时间才完全掌握接口的概念,所以如果你不 100% 理解它就不要出汗事实上,你可能不会“得到它”,直到你使用它几个(数百个)次;-)
      【解决方案4】:

      类是对象的模板,是用户定义的包含变量、属性和方法的数据类型。

      //defines a simple class describing all types of fruit
      public class Fruit {
          //insert fields here...
      
          Fruit(){//constructor method
              //insert constructor code here... 
          }
      
          //insert class methods here.... 
      }
      

      当我们将这个类实例化为一个对象时,我们需要让编译器知道它将是什么类型的对象。在这种情况下,我们的对象将是 Fruit 类型。

      //The initialisation might look something like this. 
      Fruit myFruit = new Fruit(); 
      

      上一行代码告诉编译器构造一个 Fruit 类型的新对象。

      所以简单来说,“类”定义了一个对象的特征(它的数据),其中“类型”是指当它被实例化时我们正在查看的对象类型,无论是水果、汽车还是桌子!

      可以通过进一步阅读继承和多态的主题来扩展这个概念。

      我希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-26
        • 1970-01-01
        • 2019-07-14
        • 1970-01-01
        • 2020-03-01
        • 1970-01-01
        相关资源
        最近更新 更多