在Java中,您可以在不使用varargs工具的情况下使用变量参数吗?

在Java中,您可以在不使用varargs工具的情况下使用变量参数吗?,java,variadic-functions,Java,Variadic Functions,在Java中,我想根据用户输入创建一些几何形状。诀窍是我不能更改现有的API,所以我不能像这样使用varargs语法 public Shape(Object... attrs) {} 用户输入: shape.1.triangle.arg1 = 3 shape.1.triangle.arg2 = 4 shape.1.triangle.arg3 = 5 shape.1.triangle.arg4 = "My first triangle" shape.2.rectangle.arg1 = 4 sh

在Java中,我想根据用户输入创建一些几何形状。诀窍是我不能更改现有的API,所以我不能像这样使用varargs语法

public Shape(Object... attrs) {}
用户输入:

shape.1.triangle.arg1 = 3
shape.1.triangle.arg2 = 4
shape.1.triangle.arg3 = 5
shape.1.triangle.arg4 = "My first triangle"
shape.2.rectangle.arg1 = 4
shape.2.rectangle.arg2 = 7
shape.2.rectangle.arg3 = "Another string label"
应导致方法调用,如:

Shape s1 = new Triangle(arg1, arg2, arg3, arg4);
或泛指:

String shapeType = "triangle";
Object[] args = {arg1, arg2, arg3, arg4};
// This won't work, because newInstance() doesn't take args
Shape s1 = Class.forName(shapeType).newInstance(args); 

String shapeType = "rectangle";
Object[] args = {arg1, arg2, arg3};
// This won't work, because newInstance() doesn't take args
Shape s2 = Class.forName(shapeType).newInstance(args);
问题是三角形的构造函数不允许varargs(…),我无法更改它。具体来说,构造函数是

public Triangle (int a, int b, int c, String label) {}

public Rectangle (int a, int b, String label) {}

那么,如何根据用户输入创建正确的形状呢?

使用factory对象包装三角形和正方形类。然后,工厂可以根据传入的内容确定要创建的内容,并且底层三角形和矩形对象的签名不必更改。

使用工厂对象包装三角形和正方形类。然后,工厂可以根据您传入的内容确定要创建的内容,并且底层三角形和矩形对象的签名不必更改。

我认为您需要使用桥接模式,或者至少是它的变体。您的网桥可以遵循您想要的签名,并决定如何调用底层类


请注意,如果您的基础库无法完成您需要它完成的任务,则没有办法解决这个问题,例如,如果它只需要4个参数就可以生成一个三角形。您的网桥可能会抛出某种不受支持的异常。

我认为您需要使用网桥模式,或者至少是它的一个变体。您的网桥可以遵循您想要的签名,并决定如何调用底层类


请注意,如果您的基础库无法完成您需要它完成的任务,则没有办法解决这个问题,例如,如果它只需要4个参数就可以生成一个三角形。您的网桥可能会抛出某种不受支持的异常。

这是一种有趣的方法。问题不是
Triangle
缺少vararg构造函数,而是事实而不是
newInstance()
只能调用默认构造函数

mschaef提出了一个合理的方法。它仍然需要静态地了解每个形状的构造形式。这些知识将隐藏在各自的工厂中。这可能是最好的解决办法。问题是你必须为每个形状写一个工厂

但是,您可以编写使用反射API动态调用正确构造函数的代码。如果你有很多形状,这将在一个地方解决所有形状的问题。您将获得
对象,然后调用
getDeclaredConstructors()
以获得构造函数数组。构造函数参数类型可以通过
getParameterTypes()
查询。您的代码必须根据您拥有的参数找到理想的构造函数。这本质上就是编译器对静态类型所做的

此解决方案并不特别优雅,但它确实有一些优点: 如果您正确地编写了一次,它将始终适用于您可能引入的任何新形状。您可以将代码放在一个整洁的实用程序类中,而不再查看它


一般来说,我仍然认为使用反射是一个不受欢迎的选择。

< P>这是一个有趣的方法。问题不是
Triangle
缺少vararg构造函数,而是事实而不是
newInstance()
只能调用默认构造函数

mschaef提出了一个合理的方法。它仍然需要静态地了解每个形状的构造形式。这些知识将隐藏在各自的工厂中。这可能是最好的解决办法。问题是你必须为每个形状写一个工厂

但是,您可以编写使用反射API动态调用正确构造函数的代码。如果你有很多形状,这将在一个地方解决所有形状的问题。您将获得
对象,然后调用
getDeclaredConstructors()
以获得构造函数数组。构造函数参数类型可以通过
getParameterTypes()
查询。您的代码必须根据您拥有的参数找到理想的构造函数。这本质上就是编译器对静态类型所做的

此解决方案并不特别优雅,但它确实有一些优点: 如果您正确地编写了一次,它将始终适用于您可能引入的任何新形状。您可以将代码放在一个整洁的实用程序类中,而不再查看它


一般来说,我仍然认为使用反射是一个不受欢迎的选择。

< P>如果你想实现你原来的解决方案(<代码> MyCase.NeWist立场(ARGs)< /代码>)-你可以这样做(一个建议,当然你可以想出你自己的):
shape.1.triangle.arg1.int=3
shape.1.triangle.arg2.int=4
shape.1.triangle.arg3.int=5
shape.1.triangle.arg4.String=“我的第一个三角形”
shape.2.rectangle.arg1.int=4
shape.2.rectangle.arg2.int=7
shape.2.rectangle.arg3.String=“另一个字符串标签”

然后,您的代码可以使用
class.getConstructor(class…parameterType)
获取正确的构造函数,并在
构造函数上调用
新实例(Object…args)
。 例如:

Class<?> shape = Class.forName("triangle");  
Constructor<?> constructor = shape.getConstructor(Integer.TYPE, Integer.TYPE, Integer.TYPE, String.class);  
constructor.newInstance(Integer.TYPE, Integer.TYPE, Integer.TYPE, String.class);
您需要:

public interface IShapeFactory
{
    public IShape buildShape(Object ... args);
}

public class TriangleFactory implements IShapeFactory
{
    public IShape buildShape(Object ... args)
    {
       return new Triangle(args[0], args[1], args[2], args[3]); // You will need some casting here :)
    }
}
您的代码需要做的就是实例化工厂,用参数调用
buildShape
方法,工厂将完成它需要做的事情

第二种解决方案对我来说似乎更好,而且我认为对您来说更容易,但是如果从外部提供形状,您的用户可能更难实现新的形状


您的呼叫。

如果您想实现您的原始解决方案(
myClass.newInstance(args)
)-您可以这样做(一个建议,当然您可以自己提出):
shape.1.triangle.arg1.int=3
形状1.3
public interface IShapeFactory
{
    public IShape buildShape(Object ... args);
}

public class TriangleFactory implements IShapeFactory
{
    public IShape buildShape(Object ... args)
    {
       return new Triangle(args[0], args[1], args[2], args[3]); // You will need some casting here :)
    }
}