7

我是 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以及为什么即使没有, likelogger.setLevel()等我们也能使用它。

4

8 回答 8

8

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

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

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

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

于 2012-09-03T22:14:41.770 回答
3

在这种情况下,我们正在处理工厂方法,正如我在评论中所说的那样。

请参阅相关的 API 规范Logger

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

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

工厂方法模式是一种创建型设计模式,根据维基百科,在以下情况下通常很有用:

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

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

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

Creative Commons Wiki 也有一篇相关文章

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

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

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

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

于 2012-09-03T22:19:19.487 回答
2

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

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

return uniqueInstance;

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

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

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

于 2012-09-03T22:17:02.793 回答
1

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

public class Logger {
     public static Logger getLogger() {
        return new Logger("foo", "bar");
    }
}
于 2012-09-03T22:14:36.260 回答
1

那么你所问的与设计模式更相关。Logger 类遵循单例模式。

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

public class SingletonPattern{

    private static SingletonPattern instance;

    private SingletonPattern(){} 

    public static synchronized SingletonPattern getInstance(){
        if (instance == null){
            instance = new SingletonPattern();
        }
        return instance;
    }
}

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

于 2012-09-03T22:41:42.923 回答
0

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

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

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

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

于 2012-09-03T22:14:21.047 回答
0

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

于 2012-09-03T22:14:36.593 回答
0

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

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

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

于 2012-09-03T22:17:27.930 回答