- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
为了提供一些背景知识,我正在创建一个小型依赖项注入(inject)器,但在将方法调用转换回它们的返回类型时遇到了问题。一个最小的例子是:
public class MinimalExample {
public static <T> void invokeMethod(Class<T> aClass) throws ReflectiveOperationException {
Optional<Method> myOptMethod = resolveMethod(aClass);
if (myOptMethod.isPresent()) {
Method myMethod = myOptMethod.get();
Object myInstance = myMethod.invoke(myMethod);
doSomething(myMethod.getReturnType(), myMethod.getReturnType().cast(myInstance));
}
}
private static <T> Optional<Method> resolveMethod(Class<T> aClass) {
return Stream.of(aClass.getMethods())
.filter(aMethod -> Modifier.isStatic(aMethod.getModifiers()))
.filter(aMethod -> aMethod.getParameterCount() == 0)
.findAny();
}
private static <U> void doSomething(Class<U> aClass, U anInstance) {
// E.g. Map aClass to anInstance.
}
}
这里的问题是doSomething
需要用 Class<U>, U
调用, 但目前正在使用 Class<capture of ?>, capture of ?
调用它由于 invoke
方法的通配符返回类型。
我可以改变 doSomething
至 doSomething(Class<?> aClass, Object anInstance)
但后来我失去了类型安全,这不一定是唯一调用该方法的地方。
我的问题是:为什么编译器不能推断它们具有相同的底层类型,U
,给定显式类型转换?
编辑(2021 年 3 月 9 日):
我通过反编译字节码的自由来了解为什么 rzwitserloot's helper method确实解决了类型问题。由于类型删除,它们似乎是相同的调用。我猜想编译器不够聪明,无法在转换后推断它们是相同的捕获类型,需要类型绑定(bind)来提供帮助。
我添加了以下功能
private static <U> void doSomethingWithTypeBinding(Class<U> aClass, Object anObject) {
doSomething(aClass, aClass.cast(anObject));
}
private static void doSomethingUnsafe(Class<?> aClass, Object anInstance) {}
我现在分别从第 15 行和第 16 行调用
doSomethingWithTypeBinding(myMethod.getReturnType(), myInstance);
doSomethingUnsafe(myMethod.getReturnType(), myMethod.getReturnType().cast(myInstance));
产生以下字节码:
L5
LINENUMBER 15 L5
ALOAD 2
INVOKEVIRTUAL java/lang/reflect/Method.getReturnType ()Ljava/lang/Class;
ALOAD 3
INVOKESTATIC depinjection/handspun/services/MinimalExample.doSomethingWithTypeBinding (Ljava/lang/Class;Ljava/lang/Object;)V
L6
LINENUMBER 16 L6
ALOAD 2
INVOKEVIRTUAL java/lang/reflect/Method.getReturnType ()Ljava/lang/Class;
ALOAD 2
INVOKEVIRTUAL java/lang/reflect/Method.getReturnType ()Ljava/lang/Class;
ALOAD 3
INVOKEVIRTUAL java/lang/Class.cast (Ljava/lang/Object;)Ljava/lang/Object;
INVOKESTATIC depinjection/handspun/services/MinimalExample.doSomethingUnsafe (Ljava/lang/Class;Ljava/lang/Object;)V
// access flags 0xA
// signature <U:Ljava/lang/Object;>(Ljava/lang/Class<TU;>;TU;)V
// declaration: void doSomething<U>(java.lang.Class<U>, U)
private static doSomething(Ljava/lang/Class;Ljava/lang/Object;)V
L0
LINENUMBER 30 L0
RETURN
L1
LOCALVARIABLE aClass Ljava/lang/Class; L0 L1 0
// signature Ljava/lang/Class<TU;>;
// declaration: aClass extends java.lang.Class<U>
LOCALVARIABLE anInstance Ljava/lang/Object; L0 L1 1
// signature TU;
// declaration: anInstance extends U
MAXSTACK = 0
MAXLOCALS = 2
// access flags 0xA
// signature <U:Ljava/lang/Object;>(Ljava/lang/Class<TU;>;Ljava/lang/Object;)V
// declaration: void doSomethingWithTypeBinding<U>(java.lang.Class<U>, java.lang.Object)
private static doSomethingWithTypeBinding(Ljava/lang/Class;Ljava/lang/Object;)V
L0
LINENUMBER 33 L0
ALOAD 0
ALOAD 0
ALOAD 1
INVOKEVIRTUAL java/lang/Class.cast (Ljava/lang/Object;)Ljava/lang/Object;
INVOKESTATIC depinjection/handspun/services/MinimalExample.doSomething (Ljava/lang/Class;Ljava/lang/Object;)V
L1
LINENUMBER 34 L1
RETURN
L2
LOCALVARIABLE aClass Ljava/lang/Class; L0 L2 0
// signature Ljava/lang/Class<TU;>;
// declaration: aClass extends java.lang.Class<U>
LOCALVARIABLE anObject Ljava/lang/Object; L0 L2 1
MAXSTACK = 3
MAXLOCALS = 2
// access flags 0xA
// signature (Ljava/lang/Class<*>;Ljava/lang/Object;)V
// declaration: void doSomethingUnsafe(java.lang.Class<?>, java.lang.Object)
private static doSomethingUnsafe(Ljava/lang/Class;Ljava/lang/Object;)V
L0
LINENUMBER 37 L0
RETURN
L1
LOCALVARIABLE aClass Ljava/lang/Class; L0 L1 0
// signature Ljava/lang/Class<*>;
// declaration: aClass extends java.lang.Class<?>
LOCALVARIABLE anInstance Ljava/lang/Object; L0 L1 1
MAXSTACK = 0
MAXLOCALS = 2
我们可以看到INVOKEVIRTUAL
直接转换到INVOKESTATIC
由于它们的运行时类型删除,看起来完全相同。
编辑(2021 年 3 月 12 日):
@霍尔格pointed out in the comments , Method#getReturnType
返回 Class<?>
.因为它是通配符,所以从编译器的角度来看,该方法无法保证后续方法调用返回具有相同捕获类型的类。
最佳答案
类型变量是编译器想象的产物:它们在编译后无法存活(删除*)。最好将它们视为链接事物。仅在一个地方使用的类型变量永远是完全无用的;一旦它们出现在两个地方,这就很有用了:它允许您将类型的多种用法链接在一起,表示出现次数相同。比如可以绑定(bind).add(Obj thingToAdd)
的参数类型, 和 .get(int idx)
的返回类型一起为java.util.List
.
在这里,您要链接 Class<X>
的 myMethod.getReturnType
连同 myInstance
多变的。正如您所意识到的,这是不可能的,因为编译器不知道它们最终将成为同一类型。但是,通过调用 cast()
Class<X>
的方法| ,我们围绕该部分进行工作。
但您仍然需要一些类型变量作为将事物联系在一起的工具,而您没有。 ?
类似于一次性使用类型变量; Class<?> cls
和 myMethod.getReturnType().cast(myInstance)` 是“不同的”?s:是的,您的眼球可以看出它是同一类型,但 java 不能。你需要一个类型变量。当然可以介绍一个:
private static <X> helper(Class<X> x, Object myInstance) {
doSomething(x, x.cast(myInstance));
}
将此方法添加到您的代码中并调用此方法,而不是调用 doSomething
. <X>
我们在这里创建的用于将结果联系在一起。
*) 当然,它们保留在公共(public)签名中,但在其他任何地方,在运行时它们都被删除了。
您可以在此处使用替代选项:doSomething
方法是私有(private)的,因此您可以完全控制它。因此,您可以只在其中移动类型转换,这可以解决所有问题,或者,您可以这样写:
/** precondition: o must be an instance of c */
private static void doSomething(Class<?> c, Object o) {
}
因为是私有(private)方法,引入前置条件就好了。您可以完全控制调用此方法的所有代码。如果你真的想要,你可以添加一个运行时检查(顶部的 if (!c.isInstanceof(o)) throw new IllegalArgumentException("o not instance of c");
),但是否值得这样做是 java 生态系统中针对私有(private)方法的公开辩论。通常判决是不这样做,或者使用 assert
它的关键字。
注意:这有一些糟糕的空/可选处理。如果找不到要解决的方法,你..只是默默地什么都不做?这就是 NPE 更好的原因:至少粗心的编码会导致异常,而不是徒劳的追逐。
关于Java 反射转换方法 ReturnType,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66552153/
一、反射 1.定义 Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法(即使是私有的);对于任意一个对象,都能够调用它的任意方法和属性,那么,我
有没有办法从 JavaScript 对象内部获取所有方法(私有(private)、特权或公共(public))?这是示例对象: var Test = function() { // private m
我有一个抽象类“A”,类“B”和“C”扩展了 A。我想在运行时根据某些变量创建这些实例。如下所示: public abstract class A { public abstract int
假设我们在内存中有很多对象。每个都有一个不同的ID。如何迭代内存以找到与某些 id 进行比较的特定对象?为了通过 getattr 获取并使用它? 最佳答案 您应该维护这些对象的集合,因为它们是在类属性
假设我有这个结构和一个方法: package main import ( "fmt" "reflect" ) type MyStruct struct { } func (a *MyS
C#反射简介 反射(Reflection)是C#语言中一种非常有用的机制,它可以在运行时动态获取对象的类型信息并且进行相应的操作。 反射是一种在.NET Framework中广
概述 反射(Reflection)机制是指在运行时动态地获取类的信息以及操作类的成员(字段、方法、构造函数等)的能力。通过反射,我们可以在编译时期未知具体类型的情况下,通过运行时的动态
先来看一段魔法吧 public class Test { private static void changeStrValue(String str, char[] value) {
结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套; go中的struct类型理解为类,可以定义方法,和函数定义有些许区别; struct类型是值类型
反射 1. 反射的定义 Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们
反射的定义 java的反射(reflection) 机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到嘛,那么,我们就可以
我有一个 Java POJO: public class Event { private String id; private String name; private Lon
我编写了以下函数来检查给定的单例类是否实现了特征。 /** Given a singleton class, returns singleton object if cls implements T.
我正在研究 Java 反射的基础知识并观察有关类方法的信息。我需要获得一个符合 getMethod() 函数描述的规范的方法。然而,当我这样做时,我得到了一个 NoSuchMethodExceptio
我正在通过以下代码检索 IEnumerable 属性列表: BindingFlags bindingFlag = BindingFlags.Instance | BindingFlags.Public
我需要检查属性是否在其伙伴类中定义了特定属性: [MetadataType(typeof(Metadata))] public sealed partial class Address { p
我正在尝试使用 Reflections(由 org.reflections 提供)来处理一些繁重的工作,因此我不需要在很长的时间内为每个类手动创建一个实例列表。但是,Reflections 并未按照我
scala 反射 API (2.10) 是否提供更简单的方法来搜索加载的类并将列表过滤到实现定义特征的特定类? IE; trait Widget { def turn(): Int } class
我想在运行时使用反射来查找具有给定注释的所有类,但是我不知道如何在 Scala 中这样做。然后我想获取注释的值并动态实例化每个映射到关联注释值的带注释类的实例。 这是我想要做的: package pr
这超出了我的头脑,有人可以更好地向我解释吗? http://mathworld.wolfram.com/Reflection.html 我正在制作一个 2d 突破格斗游戏,所以我需要球能够在它击中墙壁
我是一名优秀的程序员,十分优秀!