Just need to add my 10c worth, seeing that my name was mentioned :-)

Final fields are considered immutable by the JMM.  The fact that you
CAN change them does not matter to that definition.  Final fields are
allowed to be inlined at runtime, which means that changing them might
cause visibility issues.

Serializable also modifies final fields.  The ObjectInputStream first
constructs an object, using a special method in sun.reflect (see
http://www.javaspecialists.eu/archive/Issue175.html).  It then sets
the final fields.

Incidentally in Java 1.1 you could NOT set final fields.  Then in 1.2
you COULD.  In 1.3 and 1.4 you could NOT.  In 1.5+ you CAN.  That is
with just standard reflection.  It's actually bad, because setting a
final field could cause serious concurrency issues, but the reflection
API does not give you a warning when you try to do it.

Externalizable is quite dangerous as a general solution and does not
offer many performance benefits over Serializable with custom read/
writeObject methods.  Have a look at my talk from JavaZone:
http://www.javaspecialists.eu/talks/oslo09/ReflectionMadness.pdf and
search for Externalizable Hack.

Heinz

On Feb 17, 10:47 pm, "David Dabbs" <dmda...@gmail.com> wrote:
>  >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.

Reply via email to