2016-02-27 43 views
0

我想通过反射接收类字段值。但是当我打电话给我的代码时,我收到异常:IllegalArgumentException:无法将字段字段设置为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){ 


    } 
+0

我无法重现您的问题。请发布正确的[SSCCE](http://sscce.org)/ [MCVE](http://stackoverflow.com/help/mcve) – Pshemo

+0

现在我怀疑你可能正在寻找'f.getType()'但是这只会返回引用的类型(classLoader'字段的类型总是'RelaunchClassLoader'),而不是它所保存的实际类型的对象。 – Pshemo

回答

-1

你的意思是这样呢?

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(); 
     } 
    } 
} 
+0

我在代码中犯了一个错误。字段不是静态的。如果我收到一堂课,我需要从他那里调用公开的方法。 – NanoN

+0

以上检查代码 – BabyGluk

+0

不起作用... – NanoN

1

如何从现场得到的类?

With fieldValue.getClass()。不需要反思。

你的代码没有意义。

  • 你有一个方法叫做GetInstance(),它返回一个Class,而不是一个实例。您需要将此方法的返回值更改为Object并删除其中的getClass()调用。
  • 您有一种称为GetClassLoader()的方法,它返回Class而不是ClassLoader。您需要将此方法的返回类型更改为ClassLoader,并在其中删除getClass()调用。

  • 你,然后若有所思地治疗这一目的,就好像它是一个ClassLoader,它不是,试图调用findClass()就可以了。

,但我看不出有什么必要对使用反射的一切都在这里,一旦你有实例:你可以直接调用getClass().getClassLoader().findClass()

+0

好吧,'findClass'是'protected',所以这将是一个使用Reflection来调用它的原因,然而,对于大多数类加载器,使用'public'方法'loadClass'代替产生相同的结果。但是在这里,为了完成没有意义的事情列表,'null'作为接收者实例传递给'm.invoke',而不是被认为是'ClassLoader'的对象。并且使用'contains'来检查字符串相等也看起来很奇怪。 – Holger

+0

@Holger OP不需要调用'findClass()。'。他应该调用'loadClass()':使用公共API。这就是它的目的。 – EJP

+0

这就是我所说的。可能有一些罕见的角落案例,其中ClassLoader实现不遵循标准委托模型,但是在这种情况下,此代码中没有任何内容看起来像是这种深刻思想的结果。 – Holger