【问题标题】:Specify a Java class literal programmatically (without hard coding it)? reflection?以编程方式指定 Java 类文字(无需硬编码)?反射?
【发布时间】:2013-03-12 01:55:28
【问题描述】:

问题:

  1. 排队

    Object o = myC.getConstructor(short.class).newInstance(myC.cast(pPrim));

    有没有办法避免硬编码“short.class”,而是从pPrim获取文字?

    我从Create new object using reflection?的答案中得到了使用“short.class”的想法

  2. 难道我不能使用“T o = ...(例如,用于字节或短)而不是Object o = ...吗?

    我认为我的方法与Class Literals as Runtime-Type Tokens 末尾的方法几乎相同。

  3. 我想做的事是反思吗?

背景:

我正在学习 Finegan 和 Liguori 编写的 OCA Java SE 7:程序员 1 学习指南一书,为 1Z0-803 做准备。 所以我经常练习代码。在练习的时候,我写了一堂课希望看看发生了什么 从 char 转换时在基元内部。我列出了下面的代码...如果您看一下,请关注方法 byteToBinaryString、shortToBinaryString 和primitiveToBinaryString ...这就是我的问题所在。

让我回答问题的步骤:

  1. 写了 byteToBinaryString
  2. 将 byteToBinaryString 克隆为 shortToBinaryString
  3. 想,“我应该能够避免这种方法重复,也许使用泛型”
  4. 将shortToBinaryString 克隆为primitiveToBinaryString 并尝试转换为泛型
  5. 开始认为这也是一种反思
  6. 被类文字硬编码卡住了

这是我的代码

    import java.util.TreeMap;
import java.util.Set;

public class StackoverflowQuestion {

  // I wrote this 1st
  public static String byteToBinaryString(byte pByte) {
    int primLength = 8;
    int count = 0;
    String s = "";
    while ( count++ < primLength ) {
      byte sm = (byte) (pByte & 0x01);
      pByte >>= 1;
      s = sm + s;
      if ( count % 4 == 0 && count != primLength ) {
        s = " " + s;
      }
    }
    return s;
  }

  // Then I cloned byteToBinaryString to this and had the thought, 
  // I shouldn' have to repeat this
  public static String shortToBinaryString(short pShort) {
    int primLength = 16;
    int count = 0;
    String s = "";
    while ( count++ < primLength ) {
      short sm = (short) (pShort & 0x0001);
      pShort >>= 1;
      s = sm + s;
      if ( count % 4 == 0 && count != primLength ) {
        s = " " + s;
      }
    }
    return s;
  }

  // So I cloned shortToBinaryString, modifidied to this and ...
  public static <T extends Number> String primitiveToBinaryString(T pPrim) {
    int primLength = 16;
    int count = 0;
    String className = pPrim.getClass().getName();
    try {
      Class<?> myC = Class.forName(className);
      // ... got stuck here
      Object o = myC.getConstructor(short.class).newInstance(myC.cast(pPrim));
      System.out.println(pPrim + "<--pPrim.equals(o)-->" + pPrim.equals(o) + "<--" + o);
    } catch ( Exception e ) {
      System.out.println("Caught exception: " + e);
    }
    String s = "";
    while ( count++ < primLength ) {
      //T sm = new Class<T>(pPrim.intValue() & 0x0001);
      //pPrim >>= 1;
      //s = sm + s;
      if ( count % 4 != 0 && count != primLength ) {
        s = "-" + s;
      }
    }
    return s;
  }

  public static void main ( String[] args ) {

    // exercise byteToBinaryString
    for ( int i = 0; i < 256; i++ ) {
      char cByte = (char) i; 
      byte b1 = (byte) cByte;
      System.out.printf( "char(%c): charValue(%05d): bin(%s): dec(%+6d)\n", cByte, (int) cByte, byteToBinaryString(b1), b1 );
    }

    // exercise shortToBinaryString
    // please ignore my use of TreeMap, just figuring out how it works
    TreeMap<Integer, String> charsTM = new TreeMap<Integer, String>();
    charsTM.put(00000, "00000");
    charsTM.put(00001, "00001");
    charsTM.put(32766, "32766");
    charsTM.put(32767, "32767");
    charsTM.put(32768, "32768");
    charsTM.put(32769, "32769");
    charsTM.put(65535, "65535");

    short s1  = 32767;
    char  ch1 = 32768;

    Set<Integer> charKeys = charsTM.keySet();
    // loop through the boundary values I selected to show what's going on in memory
    for ( Integer i : charKeys ) {
      ch1 = (char) i.intValue();
      s1 = (short) ch1;
      System.out.printf( "char(%c): charValue(%05d): bin(%s): dec(%+6d)\n", ch1, (int) ch1, shortToBinaryString(s1), s1 );
    }

    // exercise primitiveToBinaryString
    primitiveToBinaryString( (byte)  127 );
    primitiveToBinaryString( (short) 32767 );
    primitiveToBinaryString( (int)   2147483647);
    primitiveToBinaryString(         2147483648L);
    primitiveToBinaryString(         2147483648F);
    primitiveToBinaryString(         2147483648D);
  }
}

【问题讨论】:

    标签: java generics reflection literals


    【解决方案1】:

    有几点:

    这可以稍微清理一下:

    String className = pPrim.getClass().getName();
    Class<?> myC = Class.forName(className);
    //Can just do
    Class<?> myC = pPrim.getClass();
    

    此外,如果您正在寻找采用原始值的单参数构造函数,您可以这样做:

    public Constructor<?> getPrimitiveSingleArgConstructor(Class<?> myC) {
    
      for( Constructor<?> constructor : myC.getConstructors() ) {
        if( constructor.getParameterTypes().length == 1 ) {
          Class<?> paramType = constructor.getParameterTypes()[0];
          if (paramType.isPrimitive()) {
            return constructor;
          }
        }
      }
    }
    

    最后,如果您尝试将数字转换为二进制字符串并且您只使用整数(我假设您是),您始终可以将数字向上转换为 long 并将其转换为二进制字符串.

    long integralValue = pPrim.longValue();
    

    【讨论】:

    • 1) 感谢您的清理指针。我总是欢迎他们。 2)我在我的代码中尝试了你的方法getPrimitiveSingleArgConstructor,它有效。但是,对于 float,它会循环通过 3 个构造函数:Stringdoublefloat。我的代码使用float 签名,但我还没有完全弄清楚原因。 3) 你知道我只能将实例分配给Object o 而不是T o 类型的变量吗? 4)在发这个问题之前,我首先使用的是Long.toBinaryString,但是我想练习其他的编码技巧……这就是为什么我的toBinary方法进来了。
    • 2) 是的,如果有多个单参数原始构造函数可能会导致问题。您始终可以使用@Javier 的方法来获取原始类并使用该类查找构造函数。 3) getConstructor() 方法返回一个 Constructor 对象数组。 getConstructors() 方法返回一个 Constructor> 对象数组。有关说明,请参阅 javadocs。由于您有一个 Constructor> 您只能实例化 Object。您可以将其转换为 Constructor 然后实例化 T.
    • 5) docs.oracle.com/javase/7/docs/api/java/lang/… 显示单个 Constructor 的返回,并且(在同一网页上)getConstructors 返回 Constructor>[] ...只是想确保我正在寻找正确的东西 6) 我唯一可以工作的演员是Constructor&lt;?&gt; myConstructorQ = getPrimitiveSingleArgConstructor(myC); Constructor&lt;T&gt; myConstructorT = (Constructor&lt;T&gt;) myConstructorQ;,但它会产生未经检查的警告。但是,我现在可以实例化 T t。非常感谢@Pace
    【解决方案2】:

    事实上,您可以通过强制boxing conversion,然后反射静态字段TYPE(为任何原始包装器声明)从原始值获取类文字。

     short s = 0;
     Object obj = s;
     System.out.println(obj.getClass().getDeclaredField("TYPE").get(null));
    

    这里是obj.getClass()==Short.classShort.TYPE==short.class。赋值obj=s 是一个装箱转换(从shortShort),然后是一个引用扩大转换(从ShortObject)。如果您通过调用 Object box(Object obj){return obj;} 等方法来替换赋值,它也可以工作,因为赋值转换和方法调用转换都允许进行装箱转换。

    然而,所有这些反射对于硬编码short.class 没有任何优势,因为您不能在原始类型上使用泛型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-28
      • 1970-01-01
      相关资源
      最近更新 更多