Java >> Java tutorial >  >> Tag >> break

Kan jeg ændre konstant fra int til byte i Java uden at bryde bagudkompatibiliteten?

Måske er det indlysende. Men måske ikke. Hvis en tredjepartsbruger hentede int værdier og gemte dem lokalt i Integer objekter, ændre int til byte vil forårsage en kompileringstidsfejl der:

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;
    }
}

Ud over det, synes jeg, at man i det mindste bør nævne refleksion for fuldstændigheden.

Jeg betragtede også den ternære operatør (https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.25.2 ) som en varm kandidat, men formåede ikke at forårsage en fejl med den.


Er denne ændring bagudkompatibel?

Nej.

Selvom konstanter normalt er inlinet, er feltet stadig en del af klassefilen, så det er muligt, at nogle dynamiske opslag refererer til feltet ved hjælp af dets gamle type, som er int . For eksempel:

// 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
}

Dette kaster en NoSuchFieldException da opslaget leder efter den gamle type af feltet.

Dette gælder også for byte-kodeskrivning API'er, der tilgår feltet, f.eks. med 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

Ovenstående kode virker og udskriver 10 hvis feltet er af typen int , men mislykkes, når den er ændret til byte .


Java tag