Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 带有泛型的静态工厂方法_Java_Generics - Fatal编程技术网

Java 带有泛型的静态工厂方法

Java 带有泛型的静态工厂方法,java,generics,Java,Generics,我在Java中遇到了一些泛型问题。我有一个通用的基类a,它定义了一个静态工厂方法,用初始值创建a的实例。我这样做是为了在创建A的实例时设置一些初始值,而不是指定一个设置初始值的构造函数,因为这将涉及调用构造函数中的可重写方法(这是非常不鼓励的) 我希望能够使用B中的create静态方法来创建带有初始项的B实例。尝试调用B.create(…)时,我收到一个错误,内容如下: 错误:(5,23)java:不兼容的类型:不存在类型变量T,E的实例,因此A符合B 因此,我决定尝试为B类定义create的实

我在Java中遇到了一些泛型问题。我有一个通用的基类
a
,它定义了一个静态工厂方法,用初始值创建
a
的实例。我这样做是为了在创建
A
的实例时设置一些初始值,而不是指定一个设置初始值的构造函数,因为这将涉及调用构造函数中的可重写方法(这是非常不鼓励的)

我希望能够使用
B
中的
create
静态方法来创建带有初始项的
B
实例。尝试调用
B.create(…)
时,我收到一个错误,内容如下:

错误:(5,23)java:不兼容的类型:不存在类型变量T,E的实例,因此A符合B

因此,我决定尝试为
B
类定义
create
的实现:

public static B create(List<String> values) {
    B b = new B();
    b.setValues(values);
    return b;
}
publicstaticb创建(列表值){
B=新的B();
b、 设置值(值);
返回b;
}
但这次我得到了一个不同的错误:

错误:(8,21)B中的java:name clash:create(java.util.List)和A中的create(java.util.List)具有相同的擦除,但两者都不隐藏另一个


虽然我理解每个错误的有效含义,但我不知道如何避开它们。我如何在
a
上定义一个与任何子类一起工作的静态工厂方法,或者如何在
a
上定义一个静态工厂方法,以及在覆盖/隐藏
a
实现的
a
的每个适用子类上定义一个静态工厂方法。也就是说,您将静态工厂方法放在非final类中

我想提出一种不同的方法:创建一个“ 使用复数名称(例如,
SomeType
->
SomeTypes
)的“companion”实用程序类,并将静态工厂放在那里。然后对你的其他类型做同样的事情


由于这种方法,您无法(甚至意外地)获得与预期不同的类型(现在,调用
B.create
生成
a
的实例)。

这里可能没有完美的答案。有几个选项可能是有意义的,但细节可能取决于应用案例。我将列出一些关于以下问题的选项:静态工厂方法应该在哪里,它们的名称应该是什么?


  • 把他们放到课堂上
  • 这就是您现在所做的,但可能有一些警告:
    A
    中的方法创建了
    A
    的一个实例,您无法通过调用它“through”
    B
    将其神奇地更改为
    B
    B.create()
    仍将创建一个
    A
    ,无论您做什么

    正如您所观察到的,在
    B
    中创建
    create()
    方法将导致名称冲突


  • 将它们放入与其操作的类相对应的类中
  • 他在回答中提到的方法并不少见:对于名为
    ClassName
    的类,有一个名为
    ClassNames
    的类包含创建实例的方法

    当类名没有合理的复数形式时,我感到很烦,尽管

    例如:

    class Customer { /* With package-private constructor, usually ... */ }
    public final class Customers {
        public static Customer create() { ... }
    }
    
    class PremiumCustomer { /* With package-private constructor, usually ... */ }
    public final class PremiumCustomers {
        public static PremiumCustomer create() { ... }
    }
    
    这样做的好处是,您可以轻松添加扩展
    Customer
    的类,而不会影响现有的代码库

    这里的一个小缺点是,您不能使用方法的静态导入,因为它们都有相同的名称,但在实际代码中这很少是一个问题


  • 将它们放在一个类中,聚合不同的类型
  • 您的类被称为
    A
    B
    ,这并不表示实际的结构。但根据这种结构,一个类使用不同的工厂方法(使用不同的名称)来表示专门化可能更有意义:

    public final class Customers {
        public static Customer createStandard() { ... }
        public static PremiumCustomer createPremium() { ... }
    }
    
    后一种选择哪一种“更好”很难说。这还取决于包结构:当类位于不同的包中时,不能将其构造函数包私有,这可能是不可取的


    一个可能很重要的注意事项:您专门询问了工厂方法。但是您描述的场景提出了另一个问题:谁应该调用这些方法,以及如何调用?

    每个人都必须知道他想要创建的实例的确切类型

    一般来说,当涉及多态性和继承时,
    静态
    方法总是会出现问题,可能会引起麻烦。您应该考虑使用(“简单”的、非静态的)工厂。p> 当你有这个:

    void example() {
        Customer customer = Customer.create();
        doSomeComplexStuffWith(customer);
    }
    
    然后,实现者必须显式调用
    Customer.create()
    (或
    Customers.create()
    Customers.createDefault()
    ——这在这里并不重要)

    无法更改在此处创建的图元的类型

    在此,您可以考虑将静态工厂方法的使用更改为<代码>供应商 >:

    void example(Supplier<? extends Customer> supplier) {
        Customer customer = supplier.get();
        doSomeComplexStuffWith(customer);
    }
    
    但同样,这取决于您首先打算如何创建和使用实例


    一句小评论:

    正在构造函数中调用可重写的方法。。。他非常气馁

    这是真的。但是当你有一个静态的工厂方法时,你可以把它看作是一个拐角的例子,并使类的构造函数<代码>私下<代码>或<代码>保护< /代码>。然后,您可以建立一个契约,对创建过程有更多的控制,并确保重写的方法不会产生不良影响

    但一般来说,工厂可能确实不需要在构造函数中调用可重写的方法

    我如何定义一个与 任何子类void example() { Customer customer = Customer.create(); doSomeComplexStuffWith(customer); }
    void example(Supplier<? extends Customer> supplier) {
        Customer customer = supplier.get();
        doSomeComplexStuffWith(customer);
    }
    
    example(Customers::createStandard); // Run example with standard customers
    example(Customers::createPremium); // Run example with premium customers
    
    public class A<T> {
        private List<T> values;
    
        public A() {
            this.values = new ArrayList<>();
        }
    
        public static <T> A<T> createA(List<T> values) {
            A<T> a = new A<>();
            a.setValues(values);
            return a;
        }
    
    }
    
    public class B extends A<Integer> {
        public B() {
            super();
        }
    
        public static  B createB(List<Integer> values) {
            B b = new B();
            b.setValues(values);
            return b;
        }           
    }
    
    A<String> a = A.createA(Arrays.asList("hello" ,"you"));
    B b = B.createB(Arrays.asList(1 ,2));
    
    public final class MyFactory{
    
        public static <T, U extends A<T>> U create(Supplier<U> supplierA, List<T> values) {     
            U a = supplierA.get();
            a.setValues(values);
            return a;
        }
    }
    
    
    public class A<T> {
        public void setValues(List<T> values) {
            this.values.clear();
            for (T value : values) {
                this.values.add(this.modify(value));
            }
        }
     }
    
    public class B extends A<Integer> {
    }
    
    A<String> list = MyFactory.create(A::new, Arrays.asList("hello", "you"));
    B b = MyFactory.create(B::new, Arrays.asList(1, 2));