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

时间:2012-09-03 22:09:50

标签: java class instance

我是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()等。

8 个答案:

答案 0 :(得分:7)

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

答案 1 :(得分:3)

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

请参阅Logger

上的相关API规范
  

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

     

默认情况下,记录器没有设置级别,但是从具有设置级别的neareast祖先继承它。这是log4j的核心功能之一。

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

  

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

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

这三个都适用于此......谁知道找到正确的记录器需要做哪些工作?每次你想要使用一个全新的记录器时,你真的不感兴趣...相反,你的重点主要在于 - 使用一个。

Creative Commons Wiki还有relevant article

  

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

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

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

总而言之,工厂方法的使用通常是为了实现更清晰,更直接的代码,而不会暴露您不一定关心的工作。

答案 2 :(得分:1)

因为Logger.getLogger()返回Logger个对象。 new Logger()调用构造函数,该构造函数也返回Logger。这也使用new,因为在Logger类中可能类似于:

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

答案 3 :(得分:1)

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

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

return uniqueInstance;

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

无法实例化类的其他方法是将类定义为static。

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

答案 4 :(得分:1)

你问的问题与设计模式有关。 Logger类遵循单例模式。

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

public class SingletonPattern{

    private static SingletonPattern instance;

    private SingletonPattern(){} 

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

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

答案 5 :(得分:0)

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

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

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

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

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

此处,createAnA()是工厂方法。