【问题标题】:Why some classes don't need the word "New" when creating its instance?为什么有些类在创建实例时不需要“New”这个词?
【发布时间】:2012-08-28 14:03:48
【问题描述】:

我是 Java 新手。让我困惑的一件事是为什么有些类需要new 来实例化,而为什么有些类不需要new 来实例化。

比如我在看log4j,它不需要new

// get a logger instance named "com.foo"
Logger  logger = Logger.getLogger("com.foo");
logger.setLevel(Level.INFO);

为什么其他一些类需要新的?例如,一个 Employee 类:

Employee X = new Employee (John);
X.getwork();

等等等等

为什么我们没有说,Logger logger = new Logger(...);?以及为什么即使没有new 也能使用它,比如logger.setLevel() 等。

【问题讨论】:

  • Logger.getLogger 在内部调用new Logger。总有一个构造函数调用在某处——只是并不总是在你的代码中。
  • 哇这在短时间内有很多答案......
  • @PicklishDoorknob 流行语言的简单问题 = 简单代表竞赛 :)
  • @Blorgbeard 这就是我回答这个问题时的想法! XD

标签: java class instance


【解决方案1】:

在 Java 中创建新对象的唯一方法是使用 new [1]。但是,在某些类中,您不允许为自己说new,您必须调用工厂方法,该方法可能是静态的(如您的记录器示例)或不是。类的作者通过使构造函数具有public 以外的访问权限来设置它。

另请注意,您的示例可能根本不涉及新对象。 Logger 函数可能返回的是旧对象,而不是新对象。

奥格登·纳什的以下诗似乎有点相关:

This morning I went to the zoo 
In order to look at the gnu. 
But the old gnu was dead,
and the new gnu, they said, 
Was too new a new gnu to view.

[1] 除非你涉及低级反射,否则使用Object.clone()

【讨论】:

【解决方案2】:

在这种情况下,我们正在处理 工厂方法,正如我在 my comment 中所述。

请参阅Logger 上的相关 API 规范

检索根据name参数的值命名的记录器。如果命名记录器已经存在,那么将返回现有实例。否则,将创建一个新实例。

默认情况下,记录器没有设置级别,而是从具有设置级别的最近祖先那里继承它。这是 log4j 的核心特性之一。

factory method pattern 是一种创建设计模式,根据维基百科,它通常在以下情况下很有用:

工厂模式可以在以下情况下使用:

  • 对象的创建会阻止其重用,而无需大量重复代码。
  • 创建对象需要访问不应包含在组合类中的信息或资源。
  • 生成对象的生命周期管理必须集中进行,以确保应用程序内的行为一致。

所有这三个都适用于此...谁知道找到正确的记录器需要做什么样的工作?每次想要使用一个新的记录器时,您并不是真的对创建一个全新的记录器感兴趣......相反,您的重点主要是——使用一个。

知识共享 Wiki 也有一个 relevant article

出于以下几个原因,有时使用工厂方法代替构造函数:

  • 某些语言(如 Java)不允许构造函数具有有用的名称
  • 某些语言(例如 Java)不允许构造函数具有不同的名称(如果您想为两个构造函数使用相同的方法签名,这可能是必要的)
  • 允许重复使用同一实例,而不是在每次需要时重新创建它(请参阅FlyweightPattern

我认为第三个选项可能在这里最适用。使用手动创建新的Logger,您无法充分共享它们。使用 getLogger 外观可以透明地发生这种情况。

总而言之,使用工厂方法通常是为了使代码更简洁、更直接,而不会暴露你不一定关心的工作。

【讨论】:

    【解决方案3】:

    例如,某些类可能会阻止您在应用程序中创建多个对象。在这种情况下,您需要调用一些方法来实例化该类,例如 Logger.getLogger()。 getLogger() 可能有这样的代码:

    if(uniqueInstance == null) {
        uniqueInstance = new Logger();
    }
    
    return uniqueInstance;
    

    其中 uniqueInstance 是 Logger 的一个实例。这是一种称为 Singleton 的设计模式。在这种模式下,您无法实例化该类,因为它的构造函数是私有的。

    不能实例化类的其他一些方法是当类被定义为静态时。

    具有公共构造函数且不是静态的类需要使用 new 关键字进行实例化。

    【讨论】:

      【解决方案4】:

      因为Logger.getLogger() 返回一个Logger 对象。 new Logger() 调用构造函数,该构造函数也返回 Logger。这也使用了new,因为Logger 类内部可能是这样的:

      public class Logger {
           public static Logger getLogger() {
              return new Logger("foo", "bar");
          }
      }
      

      【讨论】:

        【解决方案5】:

        您所问的更多与设计模式有关。 Logger 类遵循单例模式。

        假设您希望在整个应用程序中只创建您的类的一个实例,那么您可以将您的构造函数设为私有并提供一个静态方法,该方法在第一次调用时创建并存储您的类的对象。

        public class SingletonPattern{

         私有静态 SingletonPattern 实例;
        
            私有 SingletonPattern(){}
        
            公共静态同步 SingletonPattern getInstance(){
                如果(实例==空){
                    实例 = 新的 SingletonPattern();
                }
                返回实例;
            }
        }
        

        通过这种方式,您可以限制您的类只被实例化一次。

        【讨论】:

          【解决方案6】:

          在您的示例中,您必须使用不同的用例:返回对象的静态方法和实际的构造函数调用。

          静态方法是不需要在对象上调用的方法,这里它的内部机制可以实例化一个对象并将其返回以供将来使用,在此方法中,调用“new”但对象可能会被配置,或者在返回之前从缓存中检索。就是这样的电话

          Logger  logger = Logger.getLogger("com.foo");
          

          实际的构造函数调用(使用new)是创建新对象的正常方式。

          【讨论】:

            【解决方案7】:

            从技术上讲,您并没有使用 Logger 类,而是在使用一种方法。 从技术上讲,您没有实例化 Logger 类,也没有像使用 Logger logger = new Logger() 那样直接保留对它的引用。相反,您正在做的是访问一个方法来取回返回的实例。很高兴看到类定义。但是,您所拥有的很可能是类内部的静态方法。并且该类很可能是使用私有构造函数定义的。这允许在不实例化类的情况下访问方法。你可以在这里看到一个很好的解释,以及 java 中的静态:https://stackoverflow.com/a/1844388/1026459

            【讨论】:

            • 他使用的是 Logger 类,只是没有(直接)调用构造函数。
            • @Blorgbeard - 我应该改写一下。
            【解决方案8】:

            某些类不能在自身之外实例化(例如Math 类,这些类具有非公共构造函数)。在这些类中,有些提供了返回类实例的方法(例如 InetAddress 类)。这些被称为工厂方法。它们是返回它们所在类的实例的static 方法,因此不需要使用new 关键字(而是在工厂方法内部使用)。例如:

            public class A {
               private A() {}
               public A createAnA() { return new A(); }
            }
            

            这里,createAnA() 是工厂方法。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-08-10
              • 2014-04-08
              • 2021-03-23
              • 2022-10-17
              • 2021-05-16
              相关资源
              最近更新 更多