【问题标题】:How to get class from field?如何从现场上课?
【发布时间】:2016-06-10 20:21:48
【问题描述】:

我正在尝试通过反射接收类字段值。但是当我调用我的代码时,我收到异常:IllegalArgumentException:无法将 class 字段 field 设置为 java.lang.Class。 (我是从 javaagent 打来的)

我的代码:

 private static Class<?> GetInstance(Class<?> clz) throws NoSuchFieldException, IllegalAccessException {
    Class<?> clazz1 = null;
    Field f = clz.getDeclaredField("INSTANCE");
    f.setAccessible(true);
    clazz1 = f.get(clz).getClass();
    return clazz1;
}

private static Class GetClassLoader(Class<?> clz) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
    Field f = clz.getDeclaredField("classLoader");
    f.setAccessible(true);
    Class cls = f.get(clz).getClass();
    return cls;
}

public static void agentmain(String agentArgs, Instrumentation inst){
    try{
        inst.addTransformer(new ClientTransfomer());

        Class<?> FMLDeobfuscatingRemapper = null;
        Class<?> InstanceClass;
        Class<?>[] classes = inst.getAllLoadedClasses();
        for(int i = 0;i < classes.length;i++){
            if(classes[i].getName().contains("cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper")){
                FMLDeobfuscatingRemapper = classes[i];
            }

        }

        Class<?> instance = GetInstance(FMLDeobfuscatingRemapper);
        Class cloader = GetClassLoader(instance);

        Method m = cloader.getDeclaredMethod("findClass");
        m.setAccessible(true);
        m.invoke(null, "net.minecraft.client.entity.EntityClientPlayerMP");

    }catch (Exception e){


    }

【问题讨论】:

  • 我无法重现您的问题。请正确发布SSCCE / MCVE
  • 现在我怀疑您可能正在寻找 f.getType() 但这只会返回引用类型(classLoader 字段的类型始终为 RelaunchClassLoader),而不是实际的对象类型它成立。

标签: java class reflection field


【解决方案1】:

如何从字段中获取类?

fieldValue.getClass()。不需要反射。

你的代码没有意义。

  • 您有一个名为GetInstance() 的方法,它返回Class,而不是实例。需要将此方法的返回值改为Object,并去掉里面的getClass()调用。
  • 您有一个名为GetClassLoader() 的方法,它返回Class,而不是ClassLoader。需要将此方法的返回类型改为ClassLoader,并去掉其中的getClass()调用。

  • 然后,您会反思地将此对象视为 ClassLoader,但实际上并非如此,并尝试在其上调用 findClass()

但是一旦你有了实例,我认为在这里根本没有必要使用反射:你可以直接调用getClass().getClassLoader().findClass()

【讨论】:

  • 嗯,findClassprotected,所以这将是使用反射来调用它的一个原因,但是,对于大多数类加载器,使用 public 方法 loadClass 会产生同样的结果。但是在这里,为了完成没有意义的事情列表,null 作为接收器实例传递给m.invoke,而不是应该是ClassLoader 的对象。并且使用contains 来检查字符串是否相等看起来也很奇怪。
  • @Holger OP 不需要调用findClass().。他应该调用loadClass():使用公共API。这就是它的用途。
  • 我就是这么说的。可能存在ClassLoader 实现不遵循标准委托模型的罕见极端情况,但是,在这种情况下,此代码中的任何内容都不像是经过深思熟虑的结果。
【解决方案2】:

你的意思是这样的?

    public class One {
        public Two two = new Two();
    }

    public class Two {
    public void hello(){
        System.out.println("hello");
    }
}



    public static void main(String[] args) {
      public static void main(String[] args) {
        One one = new One();
        Class<?> clazz = one.getClass();
        try {
            Field twoField = clazz.getField("two");
            twoField.setAccessible(true);
            Class<?> twoClazz =Class.forName(twoField.getType().getName());

            Method method = twoClazz.getMethod("hello", null);

            method.invoke(twoClazz.newInstance(), null);
        } catch (NoSuchFieldException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException | InstantiationException e) {
            e.printStackTrace();
        }
    }
}

【讨论】:

  • 我在代码中犯了一个错误。字段不是静态的。如果我收到一个课程,我需要从他那里调用一个公共方法。
  • 这很奇怪,因为我在发送之前执行了代码。 ideone.com/XUqCR7我把两个类放到main里,但是你可以分成文件。
【解决方案3】:

使用 getType() 如下:

clz.getDeclaredField("fieldName").getType()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多