>Obviously, if you want you can use it to mutate the object, but if you like you can mutate even >perfectly final and immutable objects in Java (using some trickery).
>I'm pretty sure that's not true. Effective Java, for example, suggests using immutable classes as a >security measure, which would be a terrible suggestion if they were not really immutable. Actually, unless there's a SecurityManager in place any member (even final) is accessible. For instance, I've used code similar to the following (valid on Sun JVM only, I think) to directly read a String's char[] to avoid data copying. I *could* have modified the value. Cheers, david /////////////////////////////////////// import java.lang.reflect.*; public final class ReflectionUtils { public static final Field STRING_VALUE_FIELD = getFieldAccessible(String.class, "value"); public static final Field STRING_OFFSET_FIELD = getFieldAccessible(String.class, "offset"); public static final Constructor<?> STRING_PP_CTOR = getConstructor(String.class, 0, int.class, int.class, char[].class); public static char[] getChars(final String s) { // // use reflection to read the char[] value from the string. . . // try { return (char[]) STRING_VALUE_FIELD.get(s); } catch (Throwable e) { // } return null; } public static String sharedString(final char[] chars, final int offset, final int length) { try { return (String) STRING_PP_CTOR.newInstance(offset, length, chars); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } public static Field getFieldAccessible(final Class<?> clazz, final String fieldName) { Field fld = null; try { fld = clazz.getDeclaredField(fieldName); fld.setAccessible(true); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } return fld; } public static Constructor<?> getConstructor(final Class<?> clazz, final int searchModifier, Class<?>... paramTypes) { // // N.B. there is no explicit value for "package-private," so pass 0. // try { Constructor<?>[] allConstructors = clazz.getDeclaredConstructors(); for (Constructor<?> ctor : allConstructors) { if (searchModifier == (ctor.getModifiers() & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED))) { // // access modifier match. . . // final Class<?>[] parameterTypes = ctor.getParameterTypes(); if (parameterTypes.length == paramTypes.length) { // // same number of parameters. . . // for (int i = 0; i < parameterTypes.length; i++) { if (!parameterTypes[i].equals(paramTypes[i])) { ctor = null; break; } else { // Type[] gpType = ctor.getGenericParameterTypes(); // for (int j = 0; j < gpType.length; j++) { // char ch = (gpType[j].equals(paramTypes[i]) ? '*' : ' '); // System.out.format("%7c%s[%d]: %s%n", ch, "GenericParameterType", j, gpType[j]); // } } } if (ctor != null) { // System.out.format("%s%n", ctor.toGenericString()); // System.out.format(" [ synthetic=%-5b var_args=%-5b ]%n", ctor.isSynthetic(), ctor.isVarArgs()); ctor.setAccessible(true); return ctor; } } } } // production code should handle this exception more gracefully } catch (Exception x) { x.printStackTrace(); } return null; } public static void main(String[] args) { getConstructor(String.class, 0, int.class, int.class, char[].class); } public static boolean setAccessible(AccessibleObject o) { try { o.setAccessible(true); return true; } catch (SecurityException e) { e.printStackTrace(); } return false; } } -- You received this message because you are subscribed to the Google Groups "Protocol Buffers" group. To post to this group, send email to proto...@googlegroups.com. To unsubscribe from this group, send email to protobuf+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/protobuf?hl=en.