我正在向change提交一个JNA,而在先前的发行版中,它已将一组常量定义为int
类型,具体是:
int VER_EQUAL = 1;
int VER_GREATER = 2;
int VER_GREATER_EQUAL = 3;
... etc...
(由于它们是在interface
中定义的,因此它们分别自动为static
和final
。)
这些常量在VerSetConditionMask函数中用作Condition
参数,该函数需要一个BYTE
参数,在JNA中映射为Java的byte
。
要在该函数中使用现有的int
常量,将需要我(和其他用户)显式地对它们进行类型转换,因此我想将库中的这些常量值更改为byte
,例如,
byte VER_EQUAL = 1;
byte VER_GREATER = 2;
byte VER_GREATER_EQUAL = 3;
... etc...
我不认为此更改会破坏向后兼容性,因为使用这些常量的任何代码当前都必须至少期望int
,并且会愉快地扩展byte
,而不会有所抱怨。我已经写了很多测试代码来说服自己。我知道将Object
类型(例如从Integer
更改为Byte
)是行不通的,但是我相信这对于基元是很好的。但是,尽管在网上搜索了一个小时进行确认,但我仍然不敢置信。
此更改是否向后兼容?还是我做错了,有没有可能依靠int
原语破坏现有代码?
答案 0 :(得分:4)
也许很明显。但也许不是。如果某些第三方用户获取了int
值并将其本地存储在Integer
对象中,则将int
更改为byte
会在此处导致编译时错误:
interface IntToByteWithInt
{
int VER_EQUAL = 1;
int VER_GREATER = 2;
int VER_GREATER_EQUAL = 3;
}
interface IntToByteWithByte
{
byte VER_EQUAL = 1;
byte VER_GREATER = 2;
byte VER_GREATER_EQUAL = 3;
}
public class IntToByte
{
public static void main(String[] args)
{
Integer a = IntToByteWithInt.VER_EQUAL;
// Type mismatch: cannot convert from byte to Integer
Integer b = IntToByteWithByte.VER_EQUAL;
}
}
除此之外,我认为至少应该提及 reflection 以确保完整性。
我也认为三元运算符(https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.25.2)是最热门的候选者,但是并没有导致那个错误。
答案 1 :(得分:3)
此更改是否向后兼容?
否。
即使通常内联常量,该字段仍然是类文件的一部分,因此某些动态查找可能会使用其旧类型int
来引用该字段。例如:
// defined in `MyClass`
static final byte x = 10;
public static void main(String[] args) throws Throwable {
lookup().findStaticGetter(MyClass.class, "x", int.class); // old code
}
由于查询正在寻找旧的字段类型,因此抛出NoSuchFieldException
。
这也适用于访问该字段的字节码编写API,例如与ASM:
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cw.visit(55, ACC_PUBLIC, "Test", null, "java/lang/Object", null);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m", "()V", null, null);
mv.visitCode();
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitFieldInsn(GETSTATIC, "MyClass", "x", "I"); // looking for int field
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(-1, -1);
mv.visitEnd();
Class<?> cls = lookup().defineClass(cw.toByteArray());
cls.getMethod("m").invoke(null); // NoSuchFieldError
如果该字段的类型为10
,则上面的代码可以工作并打印int
,但是一旦更改为byte
,则失败。