How do I identify immutable objects in Java

后端 未结 15 1400
小蘑菇
小蘑菇 2020-11-30 22:40

In my code, I am creating a collection of objects which will be accessed by various threads in a fashion that is only safe if the objects are immutable. When an attempt is m

15条回答
  •  无人及你
    2020-11-30 23:05

    There is no reliable way to detect if a class is immutable. This is because there are so many ways a property of a class might be altered and you can't detect all of them via reflection.

    The only way to get close to this is:

    • Only allow final properties of types that are immutable (primitive types and classes you know are immutable),
    • Require the class to be final itself
    • Require that they inherit from a base class you provide (which is guaranteed to be immutable)

    Then you can check with the following code if the object you have is immutable:

    static boolean isImmutable(Object obj) {
        Class objClass = obj.getClass();
    
        // Class of the object must be a direct child class of the required class
        Class superClass = objClass.getSuperclass();
        if (!Immutable.class.equals(superClass)) {
            return false;
        }
    
        // Class must be final
        if (!Modifier.isFinal(objClass.getModifiers())) {
            return false;
        }
    
        // Check all fields defined in the class for type and if they are final
        Field[] objFields = objClass.getDeclaredFields();
        for (int i = 0; i < objFields.length; i++) {
            if (!Modifier.isFinal(objFields[i].getModifiers())
                    || !isValidFieldType(objFields[i].getType())) {
                return false;
            }
        }
    
        // Lets hope we didn't forget something
        return true;
    }
    
    static boolean isValidFieldType(Class type) {
        // Check for all allowed property types...
        return type.isPrimitive() || String.class.equals(type);
    }
    

    Update: As suggested in the comments, it could be extended to recurse on the superclass instead of checking for a certain class. It was also suggested to recursively use isImmutable in the isValidFieldType Method. This could probably work and I have also done some testing. But this is not trivial. You can't just check all field types with a call to isImmutable, because String already fails this test (its field hash is not final!). Also you are easily running into endless recursions, causing StackOverflowErrors ;) Other problems might be caused by generics, where you also have to check their types for immutablity.

    I think with some work, these potential problems might be solved somehow. But then, you have to ask yourself first if it really is worth it (also performance wise).

提交回复
热议问题