Java 如何通过静态工厂方法返回对象?

Java 如何通过静态工厂方法返回对象?,java,groovy,constructor,Java,Groovy,Constructor,我知道Java的基础知识,现在我正在阅读有效的Java。这本书建议使用静态工厂方法而不是构造函数。我有如下Groovy代码: public class Anto { public static void main(String[] args) { println Java.javaInstance() } } class Java { public static Java javaInstance() { return t

我知道Java的基础知识,现在我正在阅读有效的Java。这本书建议使用静态工厂方法而不是构造函数。我有如下Groovy代码:

public class Anto {
    public static void main(String[] args) {
            println Java.javaInstance()
        }
}

class Java {
    public static Java javaInstance() {
        return this
    }
}
当我编译此文件时,会出现如下错误:

Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'class Java' with class 'java.lang.Class' to class 'Java'
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'class Java' with class 'java.lang.Class' to class 'Java'
    at Java.javaInstance(Anto.groovy:9)
    at Java$javaInstance.call(Unknown Source)
    at Anto.main(Anto.groovy:3)

我哪里出错了?

您可以使用
return new Java()实现这一点。静态方法无权访问此

编辑:

这些静态工厂通常是单例的,这意味着只应该使用类的一个实例(通常是到db的连接)。如果要将此维度添加到
Java
类中,请使用私有静态属性,如下所示:

class Java {

    private static Java instance;

    public static Java javaInstance() {
        if(instance == null) {
            instance = new Java();
        }
        return instance;
    }

}

您不能使用
,因为
静态
方法不是实例方法

每次创建一个特定类的新实例时,该新对象/实例将作为它自己的状态<代码>此指向特定实例

你想成为单身汉吗?意思是你只需要一个类的实例

class Singleton {
     //static reference to a particular instance
     private static Singleton instance;

     //private constructor so that it cant be called outside this class scope
     private Singleton();

     //synchronized in case your working in threaded enviroment
     public synchronized static Singleton getInstance()
     {
       if(NULL == instance)
       {
         instance = new Singleton();
       }
       return instance;
     }
}

正确创建单例很容易出错(特别是在多线程环境中),因此您最好使用Groovy附带的,而不是自己使用:

public class Anto {
  public static void main(String[] args) {
    println Java.instance
  }
}

@Singleton
class Java {
}
这将
Java
类转换为:

class Java {
  private static volatile Java instance
  private Java() {}
  static Java getInstance () {
    if( instance ) {
      instance
    } else {
      synchronized( Java ) {
        if( instance ) {
          instance
        } else {
          instance = new Java()
        }
      }
    }
  }
}
下面是一个使用静态工厂方法的库的好例子(尽管不是Groovy特有的)。番石榴在很多地方都使用这个成语。例如,它们的类支持九种类型的范围,如果它们使用普通构造函数,它们的签名在几种情况下会发生冲突,因为唯一可以用来区分它们的是它们的参数

另一方面,静态方法也可以通过名称来区分,因此Guava为每种类型的范围定义了不同的方法。在内部,这些方法仍然调用一个普通的构造函数,但它不是一个可以公开访问的构造函数

import com.google.common.collect.Ranges
import com.google.common.collect.DiscreteDomains

final dom = DiscreteDomains.integers()

assert [1,2,3,4,5] as Set == Ranges.closed(1, 5).asSet(dom)
assert [2,3,4] as Set     == Ranges.open(1, 5).asSet(dom)

这是一个有用的习惯用法,但不是一个应该自动优先于普通构造函数的习惯用法。在普通构造函数已经足够的情况下,您最多只能编写比所需更多的代码,最糟糕的情况是无法扩展该类,因为任何子类仍然需要可以调用的公共或受保护的构造函数。

,这不会每次调用时都创建一个新的
Java
实例吗?@Ant是的,会的,如果您需要这个约束,我只是编辑了我的答案。@sp00m我想这本书不是在谈论单例(我可能错了,我没有读过)。它可能建议使用静态工厂方法来实例化对象,而不是直接使用构造函数,因为当您需要使用多种方法来实例化具有重载构造函数的对象时,这种方法不是非常清晰/直观,而以直观的方式命名不同的(静态)方法则更为可取。我知道这个习语是“”但是我不知道它是否有C++以外的其他名字。有趣的是,我不知道这些C++命名的构造函数。关于@sp00m,您一定是对的。该模式在Java世界中似乎被称为“静态工厂方法”这篇文章描述了为什么它们比使用重载构造函数更方便。还有几个关于它们在Java语言中的用法的问题。我真的不明白为什么每个人都用单例实现来回答,因为它是最丑陋的反模式之一:S。我现在对sp00m的答案投赞成票,因为我认为“编辑”之前的部分是最合适的。但我建议阅读其他SO问题,了解静态工厂方法有效使用的其他示例,以及概述该模式相对于使用重载构造函数的优缺点的文章。因此我在这里有一个疑问,
Singleton
不同于
Static factory methods
的概念,或者我遗漏了什么?是的,我想我的答案更多的是纠正所有不正确/错误的Singleton实现如果使用@Singleton(lazy=true),你实际上只会得到这样的延迟初始化(你可能不应该这样做,因为有些情况下会出现这种情况)。@JustinPiper双重检查锁定现在只是旧JVM(1.5之前)上的一个问题,如果你像上面那样使用
volatile
编写代码,这些(加上有缺陷的JVM和其他语言)就是我提到的情况。是的,你可能没有使用旧JVM(如果您使用的是Groovy,您肯定不会这样做),但推荐使用它似乎是个坏主意。