类型、类、接口的含义?

发布于 10-10 19:34 字数 112 浏览 11 评论 0原文

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

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

Find many authors interchangably use the term Type and Class. Certain textbooks covering object based model covers the term Interface also.

Could someone please explain these in simple terms based on Object Oriented Programming in general and C++/Java/object-oriented-database in particular.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

披肩女神2024-10-17 19:34:07

类型是一段数据的分类,告诉您其允许的值和允许的操作是什么。 (几乎?)所有编程语言都有类型,尽管一种语言与另一种语言的类型规则差异很大。

是OOP语言中一种特殊的种类类型,它是用语言本身的特定语法定义的(与所谓的“本机类型”相反)例如 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是由classMyClass定义的类型。 MyClass 定义内存布局(在本例中由两个 32 位有符号整数组成,采用 2 补码表示法)以及单个操作 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 位整数和两个操作组成。其中一项操作是它必须实现的,因为整个实现了MyInterface部分。这样,任何需要(抽象)MyInterface 类型的东西都可以使用(具体)MyOtherClass 类型,因为操作保证在那里。另一种方法 - myNonInterfaceMethod() - 不是来自 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 类型 - 但是 DON 'T 在现实世界金融代码中使用浮点!)和交易限额(其本身是 int 类型)。您还知道您可以执行一项交易(创造性地称为交易),该交易将根据交易限额检查更改并修改余额。 (一个真正的类将包含更多内容,并且包含许多令人困惑的保护内容,我出于教学目的而删除了这些内容。)

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

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< /code> 类型可以使用您的 BankAccount 实例以及 ReceivablesAccount 实例。他们不必知道银行账户有交易限额,而应收账款账户则没有。他们不必了解有关数据内部表示的任何信息。他们不必了解任何事情的特殊情况。他们只需要知道一个函数的名称 (transaction()),仅此而已。 (如果您想更具体地使用它,请查看集合类(更不用说“for in”循环)如何使用 Java 中的 Iterable 接口。)

A type is a classification of a piece of data telling you what its permissible values and permissible operations are. (Almost?) all programming languages have types, although the typing discipline varies considerably from one language to another.

A class is a particular kind of type in OOP languages which is defined with a specific syntax in the language itself (as opposed to, say, so-called "native types" like Java's int or float or the like which are defined by the language proper). A class is typically defined in terms of a memory layout and encoding of data (so-called member variables) and the functions that work on them (so-called member functions or methods).

An interface* is a specification of what operations a type must implement to be considered part of a given set of similar types but which does not specify permissible values, memory layouts, etc.

This is a very, very, very brief overview that is kind of the simplified "average form" of several languages' approach to these. It ignores a few edge cases and things like C++'s ability to make things that are part-way between an interface and a class. It also ignores what classes are in functional languages like Haskell because damaging your brain farther is not the goal here. ;)


edited to add some examples

Here are some Java-like declarations to help cement the concepts.

int myVariable1;

This variable—myVariable1—is a native (or primitive) type consisting of a 32-bit signed integer value encoded in 2s-complement notation. It has a known range (of approximately -2 billion to +2 billion) and a known set of operations (multiplication, addition, division, modulus, subtraction, various conversions, etc.) available to it.

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

Here myVariable2 is a type defined by the class MyClass. MyClass defines the memory layout (which in this case consists of two 32-bit signed integers in 2s-complement notation) as well as the single operation myMethod() which adds its argument to myMemberVariable and sets myOtherMemberVariable to that argument.

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

Here MyInterface only declares a set of operations (consisting in this case of the single function myInterfaceMethod()) without any member variables and without any implementation. It only tells you that any class that implements this interface is guaranteed to have a method with that specific signature of name + return value + arguments. To use it you have to make a class that implements the interface.

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();

Now myVariable3 is defined as a type with a memory layout consisting of three signed 32-bit integers and two operations. One of those operations is one it must implement because of the whole implements MyInterface portion. This way anything that's expecting the (abstract) MyInterface type can use the (concrete) MyOtherClass type since the operation is guaranteed to be there. The other method—myNonInterfaceMethod()—does not come from MyInterface so something that is expecting only a MyInterface can't use it because it can't know it exists.


further edited to add some real-world stuff by request

If you've ever used an integer value, a floating point value, a string or anything like this in a program you've used types. Types are arguably the stuff of computing and everything we do is manipulation of values of given types. I'll focus, therefore, on the OOP-specific notions of classes and interfaces.

Any time you have data and operations on that data you have the potential for a class. Take, for example, a bank account. A bank account will have, among other things, an account number, a current balance, a transaction limit, etc. A class representing this (badly and shown only to explain concepts) might look like this:

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;
  }
}

Now you can make a variable of this type and know that it will carry around an account number (which is itself a String type), a balance (which is itself a float type -- but DON'T USE FLOATING POINT IN REAL WORLD FINANCIAL CODE!) and a transaction limit (which is itself an int type). You also know you can perform a transaction (creatively called transaction) which will check the change against the transaction limit and modify the balance. (A real class for this would contain lots more and would contain a lot of obfuscatory protection stuff that I've removed for pedagogical purposes.)

Now let's say you're in a more sophisticated financial environment in which there are several kinds of transactions, not just bank accounts. Let's say further you've got some code that will process transactions that doesn't care what the specifics of the underlying types are. An offline batch processor of transactions, say, that covers bank accounts, accounts receivables accounts, etc. Rather than making it know about every kind of transaction in the book, we can do this instead:

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; }
}

Now anything that knows about Transactable types can use both your BankAccount's instances as well as your ReceivablesAccount's instances. They don't have to know that bank accounts have transaction limits while receivables accounts don't. They don't have to know anything about the internal representation of the data. They don't have to know the special cases of anything. They just have to know about one function by name (transaction()) and that's it. (If you want more concrete real-world usage of this, look at how the collection classes, not to mention the "for in" loop, use the Iterable interface in Java.)

耳根太软2024-10-17 19:34:07

在 OOP 术语中,交替使用术语“类型”和“类”是很常见的,尤其是在谈论 Java 和/或 C++ 等语言时。

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

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

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

如需进一步了解,请参阅抽象数据类型背后的理论。

In O.O.P parlance is very common to use the Terms Type and Class interchangeably, especially when talking about some languages like java and/or C++.

Generally speaking, when you define a Class you're actually defining a Type template, from which objects of the Type you're defining will be created, and/or instantiated.

The concept of interface is a little bit more complicated, when you define an interface you're basically specifying a particular way to deal with any Type of object that does use of it. That is, your object must come from a class that implements that interface. An interface is a way of enhancing your Class/Type by specifying additional behavior not contained in the original Class/Type specification.

For many practical purposes you can treat an Object thorough it's interface as if it were of the interface type, that's probably why the term interface is used interchangeably with the term type.

See the theory behind Abstract Data Types for further insight.

春夜浅2024-10-17 19:34:07

我个人觉得如果具体描述一下的话会更容易理解。例如,假设我们想要构建一个程序来跟踪厨房中物品的库存。

大多数语言只知道非常简单、原始的“类型”,例如整数、字符和字节。我们完全可以使用这些原始类型来描述厨房中事物的类型。例如,您可以构造一个字符数组的数组,其中数组中的每个索引代表某物的一个属性。就像,也许索引 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 保证提供“添加”、“删除”等功能。

希望这有助于澄清概念!

Personally, I think it's easier to understand if you describe it in concrete terms. For example, let's say we want to build a program to track inventory of things in a kitchen.

Most languages only know about very simple, primitive "Types" of things like integers, characters, and bytes. We could totally use these primitive Types to describe the types of things in a kitchen. For example, you could construct an array of an array of characters where each index in the array represents an attribute of something. Like, maybe, index 0 represents the "type" of thing you're trying to describe. But, of course, this technique would get very complicated very quickly.

So, using Object Oriented techniques, we can easily define new Types by combining primitive Types. The way that you do that is by creating a Class definition. Think of a Class as a blueprint for a new Type.

In the kitchen example, we have the concept of "Food" Type, "Appliance" Type, and "Furniture" Type. In order to use these new types in the program, we'd need to create a class definition for each of these:

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

An Interface describes how we can interact with something. For example, we want to create an inventory of things in our kitchen. We will want to be able to "Add" to our inventory, "Remove" things from our inventory, and maybe "Iterate" over our inventory. The actions "Add", "Remove" and "Iterate" apply to pretty much any list of anything (not just our inventory). Java provides an interface named "List" for this purpose. By creating an inventory object with the very popular and common List "Interface", we get all the actions for free and other programmers can look at our program and know exactly how to interact with the "Inventory" object:

...
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"));
...

So, in the example above, inventory is variable that contains an instance of type ArrayList. Since the ArrayList Class definition implements the "List" interface, all instances of Type ArrayList must obey the contract defined in the the "List" interface. In other words, we could have just as easily created inventory as a LinkedList (instead of an ArrayList) like this:

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

Remember to think of an interface as a contract that exposes a specific set of actions to be preformed. Because LinkedList and ArrayList both implement the "List" interface, they are both contractually obligated to implement all the methods in the "List" interface.

The great thing about this is that any code that is interested in using our "inventory" variable doesn't give a crap about how the "add", or "remove", or "iterator" actions are implemented. All they care is that the variable "inventory" obeys the "List" interface.

In other words, LinkedList implements the "add" method slightly different than ArrayList. But that doesn't matter to any code that wants to use our "inventory" variable.

If some math whiz comes up with a revolutionary way to store lists. Maybe they figure out how to store lists on the moon rather than inside computer memory and that turns out to be 10x faster than ArrayList. Then all we'd need to do is this:

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

All the other code that uses inventory can stay exactly the same because CrazyMoonList is guaranteed to provide "add", "remove", etc.

Hope this helps clarify the concepts!

∞琼窗梦回ˉ2024-10-17 19:34:07

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

//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 类型的新对象。

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

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

我希望这有帮助。

A class is a template for an object, a user-defined datatype that contains variables, properties, and methods.

//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.... 
}

When we instantiate this class to be an object, we need to let the compiler know what type of object it is going to be. In this case our object is going to be of type Fruit.

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

The previous line of code tells the compiler to construct a new object of type Fruit.

So in simple terms "class" defines an objects characteristics (its data), where as "type" is refers to what type of object we are looking at when it has been instantiated, whether it be a Fruit, Car, or Desk!

This concept can be expanded upon by reading further into the topics of Inheritance and Polymorphism.

I hope this is of help.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文