【问题标题】:Cast to instance's type automatically自动转换为实例的类型
【发布时间】:2014-11-28 20:43:23
【问题描述】:

我有一个函数应该采用任何扩展 Object 的实例,然后将转换后的实例传递给函数。我不想使用开关,因为该函数可以接受大量的对象类型,所以它会成为一个非常大的方法。

public void attachBufferData(ContextConstant bufferType, Object<T> data, ContextConstant usage) {
    glBufferData(bufferType.getGLType(), (T) data, usage.getGLType());
}

上面的代码不起作用(因为Object 不是泛型类型),但它应该可以理解我正在尝试做的事情。

----- 编辑-----

好的,我试过了:

public void attachBufferData(ContextConstant bufferType, Object data, Class<?> dataType, ContextConstant usage) {
    glBufferData(bufferType.getGLType(), dataType.cast(data), usage.getGLType());
}

但是我得到一个编译错误 glBufferData(int, long, int) is not applicable for arguments (int, capture#1-of ?, int)。我想这是一个巨大的 switch 语句:(

【问题讨论】:

  • 只传递对象。你不需要将它转换成任何东西。
  • glBufferData 被每个具体类型 T 重载?这是你想要达到的目标吗?否则,我不明白您为什么要尝试转换为特定类型。
  • @HotLicks 但 glBufferData 具有适用于每种类型的函数,因此您必须传递 FloatBuffer 或 IntBuffer 或其他的实例,而不仅仅是 Object 的实例。
  • (Java 中没有“动态案例”之类的东西。)
  • @IsaacWoods - 然后你必须有一个 switch 语句或其他什么。每个特定函数都必须是一个单独的调用(除非您使用反射)。

标签: java oop casting instance-variables


【解决方案1】:

恐怕你不能这样做。有三件事需要考虑。我认为 (2) 是您真正想要的,但我不确定,所以我将所有三个问题都留在那里供您考虑。

  1. glBufferData() 有什么签名(如果它没有过载)?如果它的第二个参数是Object 类型,那么你传递的任何东西最终都会被视为Object,即使它是一个子类,所以你不会通过强制转换来实现任何目标。您不妨将data 的类型与glBufferData() 的第二个参数的类型相同。
  2. 如果glBufferData()是一个重载方法,并且你想调用正确的方法,那么你不能动态地做到这一点:你需要一些代码在运行时测试类的真实类型,然后你选择要调用的正确版本。重载方法的选择会在编译时解决,而不是运行时解决,因此您不能只将编译时不知道的特定实例传递给它,然后让它选择正确的版本。
  3. 如果glBufferData() 是您编写的非重载方法,包含在您的类中,那么您确实有另一个更好的选择,那就是使您的类通用。如果你的类接受T的类型参数,那么你可以有T data作为attachBufferData()的第二个参数,你可以有T data作为glBufferData()的第二个参数,这样类型匹配.

方法重载的关键在于它并不像看起来那么聪明。就编译器而言,这两种情况确实没有区别。

案例一:

public void f(int x);
public void f(String s);

案例 2:

public void f(int x);
public void g(String s);

虽然我们认为案例 1 只有一个重载方法,而案例 2 有两个单独的方法,但就编译器而言,每种情况下都有两个不同的方法,它们是不同的,因为它们有不同的签名(忽略返回类型)。在这两种情况下,编译器都可以根据您编写的代码选择正确的方法来调用,因为它可以查看参数的类型和您请求的方法的名称,并找到匹配的方法。两个具有相同名称的事实并不比拥有两个名称不同但参数类型相同的方法更重要。

在情况 1 中没有选择在运行时调用哪个方法的机制,与在情况 2 中一样。

【讨论】:

  • 所以你的意思是SomeClass.cast(obj)实际上不会调用正确的方法或者只会导致错误?如果我们有一个带有SomeClass 的方法签名和一个带有SomeOtherClass 的方法签名?
  • @plalx 编译器只能根据obj的声明类型来做。因此,如果您使用SomeClass obj = new SomeClass() 声明它,那么它将选择SomeClass 版本。如果你用Object obj = new SomeClass() 声明了它,那么它会寻找一个带有Object 的方法签名,如果找不到它就会抱怨。它不会考虑实际类型,因为在编译时无法确定。
  • 这个怎么样? SomeClass obj = new SomeClass(); 然后你调用一个方法 someMethod(obj, obj.class) 并在该方法内 someOtherMethod(passedClass.cast(obj))?
  • @IsaacWoods 是的,这就是我的想法,尽管您可能正在调用您自己的 glBufferData 方法,这就是我将选项 3 留在那里的原因。更正你需要一个巨大的开关,更正你应该在写它之前叹气 :)
  • @IsaacWoods 重载会更快,因为它都将在编译时解决。唯一的问题是你是否会在更高层遇到本质上相同的问题,但如果你的代码构建得很好,你不应该这样做。
【解决方案2】:

您可以在类级别声明类型并在需要的地方重用它,下面是一个示例。

public class ExceptionHolder<T>
{
    private List<T> errors      = new ArrayList<T>();

    public void addError( T t )
    {
        errors.add( t );
    }

    public void addError( List<T> t )
    {
        errors.addAll( t );
    }
}

在调用代码中

ExceptionHolder<String> exHolder = new ExceptionHolder<String>();

String 可以根据需要替换为任何对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    相关资源
    最近更新 更多