Is it possible to make an object “Read Only” to a method

后端 未结 11 1852
攒了一身酷
攒了一身酷 2020-12-29 06:33

If an object reference is passed to a method, is it possible to make the object \"Read Only\" to the method?

相关标签:
11条回答
  • 2020-12-29 06:39

    There's no general mechanism for that. You'll need to write special-case code to achieve it, like writing an immutable wrapper (see Collections.unmodifiableList).

    0 讨论(0)
  • 2020-12-29 06:39

    You could achieve a similar thing in most cases by cloning the Object as the first statement of the method, such as this...

    public void readOnlyMethod(Object test){
        test = test.clone();
        // other code here
    }
    

    So if you called readOnlyMethod() and pass in any Object, a clone of the Object will be taken. The clone uses the same name as the parameter of the method, so there's no risk of accidentally changing the original Object.

    0 讨论(0)
  • 2020-12-29 06:39

    Depending on where you want the rule enforced. If you are working collaboratively on a project, use final with a comment telling the next person they are not meant to modify this value. Otherwise wouldn't you simply write the method to not touch the object?

    public static void main(String[] args) {
        cantTouchThis("Cant touch this");
    }
    
    /**
     * 
     * @param value - break it down
     */
    public static void cantTouchThis(final String value) {
        System.out.println("Value: " + value);
        value = "Nah nah nah nah"; //Compile time error
    } 
    

    So specifically to this method, the value will never be written to, and it is enforced at compile time making the solution extremely robust. Outside the scope of this method, the object remains unaltered without having to create any sort of wrapper.

    0 讨论(0)
  • 2020-12-29 06:40

    Not strictly speaking. That is, a reference that can mutate an object can not be turned into a reference that can not mutate an object. Also, there is not way to express that a type is immutable or mutable, other than using conventions.

    The only feature that ensure some form of immutability would be final fields - once written they can not be modified.

    That said, there are ways to design classes so that unwanted mutation are prevented. Here are some techniques:

    • Defensive Copying. Pass a copy of the object, so that if it is mutated it doesn't break your internal invariants.

    • Use access modifiers and/or interface to expose only read-only methods. You can use access modifieres (public/private/protected), possibly combined with interface, so that only certain methods are visible to the other object. If the methods that are exposed are read-only by nature, you are safe.

    • Make your object immutable by default. Any operation on the object returns actually a copy of the object.

    Also, note that the API in the SDK have sometimes methods that return an immutable version of an object, e.g. Collections.unmodifiableList. An attempt to mutate an immutable list will throw an exception. This does not enforce immutability statically (at compile-time with the static type system), but is is a cheap and effective way to enforce it dynamically (at run-time).

    There has been many research proposals of Java extension to better control of aliasing, and accessibility. For instance, addition of a readonly keyword. None of them is as far as I know planned for inclusion in future version of Java. You can have a look at these pointers if you're interested:

    • Why We Should Not Add ''Read-Only'' to Java (yet) -- it lists and compare most of the proposals
    • The Checker Framework: Custom pluggable types for Java -- a non intrusive way to extend the type system, notably with immutable types.

    The Checker Framework is very interesting. In the Checker Framework, look at Generic Universe Types checker, IGJ immutability checker, and Javari immutability checker. The framework works using annotations, so it is not intrusive.

    0 讨论(0)
  • 2020-12-29 06:42

    Expanding on ewernli's answer...

    If you own the classes, you can use read-only interfaces so that methods using a read-only reference of the object can only get read-only copies of the children; while the main class returns the writable versions.

    example

    public interface ReadOnlyA {
        public ReadOnlyA getA();
    }
    
    public class A implements ReadOnlyA {
        @Override
        public A getA() {
            return this;
        }
    
        public static void main(String[] cheese) {
            ReadOnlyA test= new A();
            ReadOnlyA b1 = test.getA();
            A b2 = test.getA(); //compile error
        }
    }
    

    If you don't own the classes, you could extend the class, overriding the setters to throw an error or no-op, and use separate setters. This would effectively make the base class reference the read-only one, however this can easily lead to confusion and hard to understand bugs, so make sure it is well documented.

    0 讨论(0)
  • 2020-12-29 06:43

    No, not without decorating, compositing, cloning, etc.

    0 讨论(0)
提交回复
热议问题