关于java:为什么有些类在创建实例时不需要“New”这个词?

Why some classes don't need the word “New” when creating its instance?

我是爪哇人。有一件事让我感到困惑,那就是为什么有些类需要new来实例化,而另一些类不需要new来实例化。

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

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

为什么其他的课程需要新的?例如,员工类:

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

为什么我们不说,以东十一〔三〕号?为什么即使没有new,我们也能使用它,比如logger.setLevel(),等等。


在Java中创建新对象的唯一方法是使用EDCOX1〔4〕〔1〕。但是,在某些类中,不允许您自己说new,您必须调用一个工厂方法,该方法可能是静态的(与日志程序示例一样)。类的作者通过使构造函数具有除public之外的访问权限来设置此设置。

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

奥格登·纳什的以下诗句似乎有些关联:

1
2
3
4
5
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()


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

Logger相关API规范

Retrieve a logger named according to the value of the name parameter. If the named logger already exists, then the existing instance will be returned. Otherwise, a new instance is created.

By default, loggers do not have a set level but inherit it from their neareast ancestor with a set level. This is one of the central features of log4j.

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

The factory pattern can be used when:

  • The creation of an object precludes its reuse without significant duplication of code.
  • The creation of an object requires access to information or resources that should not be contained within the composing class.
  • The lifetime management of the generated objects must be centralized to ensure a consistent behavior within the application.

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

Creative Commons wiki也有一篇相关文章,

Factory methods are sometimes used in place of constructors for any of several reasons:

  • Some languages (such as Java) do not allow constructors to have useful names
  • Some languages (such as Java) do not allow constructors to have different names (which may be necessary if you want to use the same method signature for two constructors)
  • To allow the same instance to be reused instead of recreated each time it is needed (see FlyweightPattern)

我认为第三种选择可能最适用于这里。使用手动创建新的Logger,您无法充分共享它们。使用getLogger立面可以透明地实现这一点。

总而言之,使用工厂方法通常是为了在不公开您不必关心的工作的情况下实现更清晰、更直接的代码。


你所要求的与设计模式更相关。logger类遵循singleton模式。

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

<代码>公共类单件模式{

1
2
3
4
5
6
7
8
9
10
11
    private static SingletonPattern instance;

    private SingletonPattern(){}

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

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


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

1
2
3
4
5
if(uniqueInstance == null) {
    uniqueInstance = new Logger();
}

return uniqueInstance;

其中uniqueinstance是logger的实例。这是一个名为singleton的设计模式。在这种模式中,不能实例化类,因为它的构造函数是私有的。

另一种无法实例化类的方法是将类定义为静态类。

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


因为Logger.getLogger()返回Logger对象。new Logger()调用构造函数,该构造函数还返回Logger。这种方法也使用new,因为在Logger类中可能有如下情况:

1
2
3
4
5
public class Logger {
     public static Logger getLogger() {
        return new Logger("foo","bar");
    }
}

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

1
2
3
4
public class A {
   private A() {}
   public A createAnA() { return new A(); }
}

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


您没有在技术上使用logger类,而是在使用方法。您没有在技术上实例化logger类,也没有像使用Logger logger = new Logger()那样直接保留对它的引用。相反,您要做的是访问一个方法以返回返回的实例。很高兴看到类定义。但是,您所拥有的很可能是类内的静态方法。类很可能是用私有构造函数定义的。这允许在不实例化类的情况下访问方法。您可以在这里看到一个很好的解释,以及Java中的静态:HTTPS://StaskOfFult.COM/A/1844


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

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

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

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