为什么我们使用内部类?

发布于 2024-08-30 08:08:02 字数 60 浏览 1 评论 0原文

我想问你为什么我们需要内部类以及为什么我们使用它们?
我知道如何使用内部类,但我不知道为什么..

I want to ask you why we need inner classes and why we use them ?
I know how to use inner classes but I don't know why..

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

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

发布评论

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

评论(7

伏妖词 2024-09-06 08:08:02

一些内部类是公开公开的(例如Java中的Map.Entry),但这只是例外而不是常态。

内部类基本上是一个实现细节。

例如,Swing 广泛使用内部类作为事件侦听器。如果没有它们,您最终会用一堆您不需要看到的类来污染全局名称空间(这可能会使它们的目的更难确定)。

本质上,内部类是范围的一种形式。包访问从包外部隐藏了类。私有内部类向该类外部隐藏该类。

Java 中的内部类还可以替代函数指针或方法委托(C# 中的)或闭包的缺失。它们是将一个函数传递给另一个函数的方法。例如,在 Executor 类中,您有:

void execute(Runnable r);

因此您可以传入一个方法。在 C/C++ 中,可以通过以下方式实现:

void execute(void (*run)());

作为指向函数的指针。

Some inner classes are exposed publicly (eg Map.Entry in Java) but that is by far the exception rather than the norm.

Inner classes are, basically, an implementation detail.

For example, Swing makes extensive use of inner classes for event listeners. Without them you would end up polluting the global namespace with a bunch of classes you otherwise don't need to see (which may make their purpose harder to determine).

Essentially inner classes are a form of scope. Package access hides classes from outside the package. Private inner classes hide that class from outside that class.

Inner classes in Java are also a substitute for a lack of function pointers or method delegates (which are in C#) or closures. They are the means of passing a function to another function. For example, in the Executor class you have:

void execute(Runnable r);

so you can pass a method in. In C/C++ that could be achieved with:

void execute(void (*run)());

being a pointer to a function.

月牙弯弯 2024-09-06 08:08:02

这篇来自 wikipedia 的文章可能会帮助您理解为什么我们需要一个内部类:

普通类或顶级类的实例可以自己存在。相比之下,内部类的实例如果不绑定到顶级类就无法实例化。

让我们采用四轮汽车的抽象概念。我们的车轮有一个特定的功能,它是我们汽车的一部分。该概念并不将车轮表示为可以作为车辆的一部分的更一般形式的车轮。相反,它代表了特定于此的它们。我们可以使用内部类来模拟这个概念,如下所示:

我们有顶级的汽车。 Car 类的实例由 Wheel 类的四个实例组成。 Wheel 的这种特定实现是特定于汽车的,因此代码不会对 Wheel 的一般概念进行建模,最好将其表示为顶级类。因此,它在语义上与 Car 类相关,并且 Wheel 的代码以某种方式与其外部类耦合。

内部类为我们提供了一种准确建模此连接的机制。我们说我们的车轮类是Car.Wheel,Car是顶级类,Wheel是内部类。

内部类因此允许程序的某些部分面向对象,否则这些部分不会封装到类中。

This piece from wikipedia might help you understand why we need an inner class:

An instance of a normal or top-level class can exist on its own. By contrast, an instance of an inner class cannot be instantiated without being bound to a top-level class.

Let us take the abstract notion of a Car with four wheels. Our wheels have a specific feature that relies on being part of our Car. This notion does not represent the wheels as wheels in a more general form that could be part of vehicle. Instead it represents them as specific to this one. We can model this notion using inner classes as follows:

We have the top-level class Car. Instances of Class Car are composed of four instances of the class Wheel. This particular implementation of Wheel is specific to the car, so the code does not model the general notion of a Wheel which would be better represented as a top-level class. Therefore, it is semantically connected to the class Car and the code of Wheel is in some way coupled to its outer class.

Inner classes provide us with a mechanism to accurately model this connection. We say that our wheel class is Car.Wheel, Car being the top-level class and Wheel being the inner class.

Inner classes therefore allow for the object orientation of certain parts of the program that would otherwise not be encapsulated into a class.

も星光 2024-09-06 08:08:02

Java 中的匿名内部类是使用适配器模式的一种方式。

interface Bar
{
  public void bar();
}

class Foo
{
  public void foo()
  {
    // do something relevant
  }

  // it happens that foo() defines the same contract (or a compatible one) as
  // Bar.bar(); with an anonymous inner class we can adapt Foo to the Bar
  // interface
  public Bar asBar()
  {
    // return an instance of an anonymous inner class that implements
    // the Bar inteface
    return new Bar()
    {
      public void bar()
      {
        // from an inner class, we can access the enclosing class methods
        // as the "this pointers" are "linked"
        foo();
      }
    };
  }
}

在 Java 中,请确保您了解内部类和嵌套类之间的区别类

内部类与
其封闭类的实例和
可以直接访问该对象的
方法和字段

C# 没有 Java 意义上的内部类,只有嵌套类。

另请参阅此内部类示例

Anonymous inner classes in Java are a way to use the adapter pattern.

interface Bar
{
  public void bar();
}

class Foo
{
  public void foo()
  {
    // do something relevant
  }

  // it happens that foo() defines the same contract (or a compatible one) as
  // Bar.bar(); with an anonymous inner class we can adapt Foo to the Bar
  // interface
  public Bar asBar()
  {
    // return an instance of an anonymous inner class that implements
    // the Bar inteface
    return new Bar()
    {
      public void bar()
      {
        // from an inner class, we can access the enclosing class methods
        // as the "this pointers" are "linked"
        foo();
      }
    };
  }
}

In Java, make sure you understand the difference between inner classs and nested class:

an inner class is associated with an
instance of its enclosing class and
has direct access to that object's
methods and fields

C# doesn't have inner classes in sense of Java, only nested classes.

See also this Inner Class Example.

薄情伤 2024-09-06 08:08:02

大多数时候我使用内部类是因为内部类是最接近闭包概念的东西。 有其他语言版本。这使得能够创建和使用内部嵌套作用域的对象,该对象可以访问其外部作用域的变量。这在创建回调(例如,在 Swing 中定义各种Listener)等方面通常很有用。

Most of the time I use inner classes is because inner classes are the closest thing to the concept of closure available in other languages. This enables creating and working with an object of inner nested scope which has access to variables of its outer scope. This is often useful in creating callbacks (e.g. defining various Listeners in Swing) among other things.

不羁少年 2024-09-06 08:08:02

我使用它们来确定范围,例如,如果我有 ebook 类并且有 ebookPrice,我会将 ebookPrice 包含在 ebook 类之间,因为它与其相关并且只能在其中使用(至少在概念上)。

ebookPrice 可以继承自 Price,Price 处于更高的范围,并且与所有其他类相关。

(只是我的两分钱)。

I use them to scope, for example, if I have the class ebook and I have ebookPrice, I enclose ebookPrice between the ebook class, as it is related to it and only usable (at least conceptually) inside it.

ebookPrice may inherit from Price which is in a more higher scope, and related to every other class.

(Just my two cents).

何以心动 2024-09-06 08:08:02

有些语言将内部类提升到相当不同的水平,例如 Beta 和 Newpeak。在这些语言中,类的嵌套充当包装(即没有包)。

要详细了解这一愿景,请参阅 “我们需要多少个模块概念?”。另请参阅 Gilad Bracha 在他的博客上的作品...

There are languages that take inner classes to quite some different level, like Beta and Newspeak. In these languages the nesting of classes serves as packaging (ie there are no packages).

For a good coverage of this vision, please refer to "How many concepts for modules do we need?" on the object teams blog. See also the work by Gilad Bracha on his blog...

瑾兮 2024-09-06 08:08:02

面向对象的优势

在我看来,内部类最重要的特性是它允许你将通常不会变成对象的东西变成对象。这使得您的代码比没有内部类时更加面向对象。

我们来看看会员等级。由于它的实例是其父实例的成员,因此它可以访问父实例中的每个成员和方法。乍一看,这似乎并不算多;但实际上,这并不算什么。我们已经可以从父类的方法中进行这种访问。然而,成员类允许我们从父类中取出逻辑并将其对象化。例如,树类可能具有一个方法和许多执行树搜索或遍历的辅助方法。从面向对象的角度来看,树就是一棵树,而不是一种搜索算法。但是,您需要深入了解树的数据结构才能完成搜索。

内部类允许我们删除该逻辑并将其放入自己的类中。因此,从面向对象的角度来看,我们将不属于它的功能取出来,并将其放入自己的类中。通过使用内部类,我们成功地将搜索算法与树解耦。现在,要更改搜索算法,我们只需换入一个新类即可。我可以继续说下去,但这使我们的代码能够享受到面向对象技术提供的许多优点。

组织优势

面向对象设计并不是每个人都喜欢的,但幸运的是,内部类提供了更多。从组织的角度来看,内部类允许我们通过使用命名空间来进一步组织包结构。类可以进一步嵌套在类中,而不是将所有内容都转储到平面包中。明确地,如果没有内部类,我们将受到以下层次结构的限制:

package1
   class 1
      class 2
      ...
      class n
...
package n

使用内部类,我们可以执行以下操作:

package 1
   class 1
   class 2
      class 1
      class 2
      ...
      class n

仔细使用,内部类可以提供更自然地适合您的类的结构层次结构。

回调优势

内部成员类和匿名类都提供了定义回调的便捷方法。最明显的例子与 GUI 代码有关。然而,回调的应用可以扩展到许多领域。

大多数 Java GUI 都有某种组件来发起 actionPerformed() 方法调用。不幸的是,大多数开发人员只是让他们的主窗口实现 ActionListener。因此,所有组件共享相同的 actionPerformed() 方法。为了确定哪个组件执行了该操作,actionPerformed() 方法中通常有一个巨大且丑陋的开关。

这是一个整体实现的示例:

public class SomeGUI extends JFrame implements ActionListener {

    protected JButton button1;
    protected JButton button2;
    //...
    protected JButton buttonN;

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == button1) {
        // do something
        } else if (e.getSource() == button2) {
            //... you get the picture
        }
    }
}

每当您看到开关或大型 if/if else 块时,您的脑海中应该开始响起响亮的警钟。一般来说,这样的构造是不好的面向对象设计,因为代码的一个部分的更改可能需要 switch 语句中的相应更改。内部成员类和匿名类允许我们摆脱切换的actionPerformed()方法。

相反,我们可以定义一个内部类,为我们想要监听的每个组件实现 ActionListener。这可能会导致许多内部类。但是,我们可以避免使用大型 switch 语句,并获得封装操作逻辑的额外好处。此外,该方法可以提高性能。在有 n 次比较的 switch 中,我们可以预期在平均情况下会有 n/2 次比较。内部类允许我们在动作执行者和动作监听者之间建立 1:1 的对应关系。在大型 GUI 中,此类优化会对性能产生重大影响。匿名方法可能如下所示:

public class SomeGUI extends JFrame {
    //  ... button member declarations ...

    protected void buildGUI() {
        button1 = new JButton();
        button2 = new JButton();
        //...
        button1.addActionListener(
                new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent e) {
                // do something
            }
        });
// .. repeat for each button
    }
}

使用内部成员类,相同的程序将如下所示:

public class SomeGUI extends JFrame
{
   ... button member declarations ...
   protected void buildGUI()
   {
      button1 = new JButton();
      button2 = new JButton();
      ...
      button1.addActionListener(
         new java.awt.event.ActionListener()
         {
            public void actionPerformed(java.awt.event.ActionEvent e)
            {
               // do something
            }
         }
      );
      .. repeat for each button

由于内部类可以访问父级中的所有内容,因此我们可以将出现在整体 actionPerformed() 实现中的任何逻辑移动到内部类。

我更喜欢使用成员类作为回调。然而,这是个人喜好的问题。我只是觉得太多的匿名类会使代码变得混乱。我还认为,如果匿名类超过一两行,它们可能会变得笨重。

缺点?

与其他任何事情一样,你必须兼顾好与坏。内部类有其缺点。从维护的角度来看,没有经验的Java开发人员可能会觉得内部类很难理解。使用内部类也会增加代码中类的总数。此外,从开发的角度来看,大多数 Java 工具对内部类的支持都有些不足。例如,我使用 IBM 的 VisualAge for Java 进行日常编码。虽然内部类将在 VisualAge 中编译,但没有内部类浏览器或模板。相反,您必须简单地将内部类直接键入到类定义中。不幸的是,这使得浏览内部类变得困难。键入也很困难,因为当您键入类定义或使用内部类时,您会丢失 VisualAge 的许多代码完成辅助功能

The object-oriented advantage

In my humble opinion, the most important feature of the inner class is that it allows you to turn things into objects that you normally wouldn't turn into objects. That allows your code to be even more object-oriented than it would be without inner classes.

Let's look at the member class. Since its instance is a member of its parent instance, it has access to every member and method in the parent. At first glance, this might not seem like much; we already have that sort of access from within a method in the parent class. However, the member class allows us to take logic out of the parent and objectify it. For example, a tree class may have a method and many helper methods that perform a search or walk of the tree. From an object-oriented point of view, the tree is a tree, not a search algorithm. However, you need intimate knowledge of the tree's data structures to accomplish a search.

An inner class allows us to remove that logic and place it into its own class. So from an object-oriented point of view, we've taken functionality out of where it doesn't belong and have put it into its own class. Through the use of an inner class, we have successfully decoupled the search algorithm from the tree. Now, to change the search algorithm, we can simply swap in a new class. I could go on, but that opens up our code to many of the advantages provided by object-oriented techniques.

The organizational advantage

Object-oriented design isn't everyone's thing, but luckily, inner classes provide more. From an organizational point of view, inner classes allow us to further organize our package structure through the use of namespaces. Instead of dumping everything in a flat package, classes can be further nested within classes. Explicitly, without inner classes, we were limited to the following hierarchy structure:

package1
   class 1
      class 2
      ...
      class n
...
package n

With inner classes we can do the following:

package 1
   class 1
   class 2
      class 1
      class 2
      ...
      class n

Used carefully, inner classes can provide a structural hierarchy that more naturally fits your classes.

The callback advantage

Inner member classes and anonymous classes both provide a convenient method for defining callbacks. The most obvious example relates to GUI code. However, the application of the callback can extend to many domains.

Most Java GUIs have some kind of component that instigates an actionPerformed() method call. Unfortunately, most developers simply have their main window implement ActionListener. As a result, all components share the same actionPerformed() method. To figure out which component performed the action, there is normally a giant, ugly switch in the actionPerformed() method.

Here's an example of a monolithic implementation:

public class SomeGUI extends JFrame implements ActionListener {

    protected JButton button1;
    protected JButton button2;
    //...
    protected JButton buttonN;

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == button1) {
        // do something
        } else if (e.getSource() == button2) {
            //... you get the picture
        }
    }
}

Whenever you see switches or large if/if else blocks, loud alarm bells should begin to ring in your mind. In general, such constructs are bad object-oriented design since a change in one section of the code may require a corresponding change in the switch statement. Inner member classes and anonymous classes allow us to get away from the switched actionPerformed() method.

Instead, we can define an inner class that implements ActionListener for each component to which we want to listen. That may result in many inner classes. However, we can avoid large switch statements and have the added bonus of encapsulating our action logic. Moreover, that approach may improve performance. In a switch where there are n comparisons, we can expect n/2 comparisons in the average case. Inner classes allow us to set up a 1:1 correspondence between the action performer and the action listener. In a large GUI, such optimizations can make a substantial impact on performance. An anonymous approach may look like this:

public class SomeGUI extends JFrame {
    //  ... button member declarations ...

    protected void buildGUI() {
        button1 = new JButton();
        button2 = new JButton();
        //...
        button1.addActionListener(
                new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent e) {
                // do something
            }
        });
// .. repeat for each button
    }
}

Using inner member classes, the same program would look like this:

public class SomeGUI extends JFrame
{
   ... button member declarations ...
   protected void buildGUI()
   {
      button1 = new JButton();
      button2 = new JButton();
      ...
      button1.addActionListener(
         new java.awt.event.ActionListener()
         {
            public void actionPerformed(java.awt.event.ActionEvent e)
            {
               // do something
            }
         }
      );
      .. repeat for each button

Since inner classes have access to everything in the parent, we can move any logic that would have appeared in a monolithic actionPerformed() implementation to an inner class.

I prefer to use member classes as callbacks. However, that is a matter of personal preference. I just feel that too many anonymous classes clutter code. I also feel that anonymous classes can become unwieldy if they are larger than one or two lines.

Disadvantages?

As with anything else, you have to take the good with the bad. Inner classes have their disadvantages. From a maintenance point of view, inexperienced Java developers may find the inner class difficult to understand. The use of inner classes will also increase the total number of classes in your code. Moreover, from a development point of view, most Java tools come up a bit short on their support of inner classes. For example, I use IBM's VisualAge for Java for my day-to-day coding. While inner classes will compile within VisualAge, there is no inner class browser or template. Instead, you must simply type the inner class directly into the class definition. That unfortunately makes browsing the inner class difficult. It is also difficult to type since you lose many of VisualAge's code completion aids when you type into the class definition or use an inner class

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