【问题标题】:Is it possible to use Class<?> with the new Pattern-Matching switch?是否可以将 Class<?> 与新的模式匹配开关一起使用?
【发布时间】:2022-01-07 21:53:44
【问题描述】:

作为对方法参数的调查的一部分,我尝试了新的Pattern Matching for switch (Preview)。使用传统条件,完美运行:

Method firstMethod = BitSet.class.getDeclaredMethods()[0];
Parameter firstParameter = firstMethod.getParameters()[0];
if (firstParameter.getType() == Integer.class) {
        System.out.println("Integer");
    }

当我尝试重构它以使用 switch 语句时,它没有编译:

Method firstMethod = BitSet.class.getDeclaredMethods()[0];
Parameter firstParameter = firstMethod.getParameters()[0];
switch (firstParameter.getType()) {
    case Integer.class: System.out.println("Integer");
    case int.class: System.out.println("int");
    default: System.out.println("other");
}

错误是:

 error: incompatible types: Class<Integer> cannot be converted to Class<CAP#1>
        case Integer.class: System.out.println("Integer");
                    ^
 where CAP#1 is a fresh type-variable:
   CAP#1 extends Object from capture of ?

这是无法做到的事情,还是只是语法错误?

【问题讨论】:

  • 这看起来不像是新语法,你可能想要case Class&lt;Integer&gt; ci : System.out.println("Integer"); break;int 类似的东西/
  • 它也不起作用
  • 新的 switch 表达式按其类对对象进行分支。 firstParameter.getType() 返回一个类对象(Class 的实例),因此该类始终为 Class。所以你不能在你的例子中分支。

标签: java switch-statement java-17 preview-feature


【解决方案1】:

这不是切换类型的工作方式。您可以切换对象的实际类型,并且必须指定类型名称,而不是 Class 文字。

Object o = 42;
switch(o) {
    case Integer i: System.out.println("Integer " + i); break;
    case String s: System.out.println("String " + s); break;
    default: System.out.println("other");
}

请注意,使用模式匹配时,没有直接支持,因此必须指定 break。或者你使用一开始就没有失败的新语法

Object o = 42;
switch(o) {
    case Integer i -> System.out.println("Integer " + i);
    case String s -> System.out.println("String " + s);
    default -> System.out.println("other");
}

getType() 返回的对象始终是java.lang.Class 的实例,因此按其类型进行分支是没有意义的。这并不意味着不可能将实际值与switch 语句或表达式进行比较。可以使用受保护的模式进行比较:

Method firstMethodWithParam = Arrays.stream(BitSet.class.getDeclaredMethods())
        .filter(m -> m.getParameterCount() > 0)
        .findAny().orElseThrow();
switch(firstMethodWithParam.getParameterTypes()[0]) {
    case Class<?> cl && cl == Integer.class -> System.out.println("Integer");
    case Class<?> cl && cl == int.class -> System.out.println("int");
    case Class<?> cl && cl == String.class -> System.out.println("String");
    case Class<?> cl && cl == long.class -> System.out.println("long");
    case Class<?> cl && BitSet.class.isAssignableFrom(cl)
                                  -> System.out.println("BitSet or subtype");
    default -> System.out.println("other");
}

但这只是为了完整性。我认为很明显,这对 if 语句或从 Class 到处理程序的映射没有任何改进。

【讨论】:

  • 请注意x instanceof Cx.getClass() == C.class之间的区别;前者包括 C 及其子类型;后者只包含 C(如果 C 是抽象的,这可能永远不会成立。)类型模式就像instanceof C;对于像Integer 这样的最终类,它没有区别,但这是例外,而不是规则。
  • @BrianGoetz 好点。我扩展了示例以显示支持子类型的外观。
  • 为了完整起见,instanceof 的反射拼写为Class::isAssignableFrom
  • 嗯,是的,这就是我在示例中添加的内容。
猜你喜欢
  • 2022-01-10
  • 1970-01-01
  • 2021-03-27
  • 1970-01-01
  • 2022-06-22
  • 1970-01-01
  • 2012-09-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多