我是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()
等。
答案 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
检索根据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()
是工厂方法。