代表不同类型的Java方法参数

问题描述

有没有办法让java方法接受不同类型的参数?

public class Test {
  public boolean isTest(Type1 type1) {
    do_something_with_type1
    return bool;
  }

  public boolean isTest(DifferentType2 type2) {
    do_something_with_type2
    return bool;
  }
}

在这种情况下,do_something_with_X 部分在两种方法之间是通用的。为了避免重复部分,我们应该有类似的东西:

public class Test {
  public boolean isTest(Object obj) {
    do_something_with_obj
    return bool;
  }
}

我们可以在 Java 中做到这一点吗?

解决方法

您可以通过多种方式实现这一目标。从您提到的示例开始,像 Object 类一样使用 List<?> 进行泛型管理。

Java 泛型可以以多种方式工作,在类级别、方法甚至方法参数上定义自己。

类级别的通用定义

class Example<T> {
   public void foo(T type) {}
}

void usage() {
    Example<String> example = new Example<>();
    example.foo("Accepts strings");
}

方法类级别的泛型定义

class Example {
   public <T> void foo(T type) {}
}

void usage() {
    Example example = new Example();
    example.foo("Accepts anything");
}

更复杂的泛型

您还可以指定规则使您的泛型更加严格。例如,作为某物的子类或父类。

public <T extends List> void foo(T type) {}

public <T extends Class<? super List>> void foo(T type) {}

甚至更远的地方,您可以指定泛型来扩展多个类类型:

public <T extends List & AutoCloseable> void foo(T type) {}

甚至更远的地方,您可以根据方法参数的泛型指定方法的返回类型。

public <R,T extends AutoCloseable & List<R>> R foo(T type) {
    return null;
}
void usage() {
    // Non existing class that implements AutoCloseable,List<T>
    AutoCloseableArrayList<String> list;

    // foo(T) will return String cause it's the generic of the parameter list
    String s = foo(list);
}
,

您可以使用“do_something_with_obj”所需的方法创建一个接口,并在 type1 和 type2 中实现该接口。然后你可以将对象作为接口传递。

,

如果不了解 do_something_with_x,真的很难说。我建议提取 do_something_with_x 以便您可以保留 isTest 方法的原始类型:

public class Test {
  public boolean isTest(Type1 type1) {
    doSomethingWithObject(type1);
    return bool;
  }

  public boolean isTest(DifferentType2 type2) {
    doSomethingWithObject(type2);
    return bool;
  }

  private doSomethingWithObj(Object object) {
      //do_something_with_object
  }
}
,

好吧,你可能可以使用泛型

public class Test {
  public <T> boolean isTest(T obj) {
    do_something_with_obj
    return bool;
  }
}

接受一个 Object 作为参数是非常不寻常的,并不总是最好的选择......如果你可以编辑你关心的那两种类型(定义一个带有方法的接口),你可能想看看多态性你关心,让这两个类实现那个接口)

或者如果你不能,你可能想看看适配器设计模式,但如果你只需要一次就有点矫枉过正了

,

不直接。

您可以创建一个 isTest(Object) 方法,但它会接受所有对象,从 IntegerStringType1Type2。所以这是一个废话,不要选择那个。

但是有很多替代选择:

接口

如果 isTest 操作对 Type1Type2 有意义,并且两者在 isTest 上有共享代码,但没有关系Type1Type2 之间(没有共享超类型),感觉就像你搞砸了你的 API 设计。为什么 Type1 和 Type2 不共享一个接口或(抽象)类?

请注意,从 JDK16 开始,您可以“密封”接口,这意味着,在您枚举该接口的哪些实现存在的接口中,不允许其他代码实现它。意思是,你当然知道,在编译时。

因此,您可以制作一个接口并对其进行密封,以便只有 Type1Type2 可以实现它,现在您可以确定并制作 isTest(ThatSharedInterface)

辅助方法

只需制作单独的 2 个 isTest 方法,并将共享代码放入帮助程序中。这可以很简单:

public boolean isTest(Type1 type1) {
    return isTest0(type1);
}
public boolean isTest(Type2 type2) {
    return isTest0(type2);
}
private boolean isTest0(Object o) {
    ...
}

这使用两个方面:

  • 一般来说,挂钩到私有的实际实现的公共包装器的概念,以及辅助方法的概念,倾向于(按照惯例)使用 0 作为标记,此处使用.
  • 因为 isTest(Object) 方法是 private,所以从 API 角度看,它是一种允许任何类型的灾难,这一事实不是问题。它是私密的:你知道用什么来称呼它。