0

Without using getter and setter method how to prevent modification access from child class if super class has protected Hashmap variable?

This Map is mutable (So i should be able to add the values from super class)So can't use UnmodifiableMap(its only applicable immutable collection object)

    Class A
    {
      protected Map<Integer,Integer> m = new HashMap<Integer,Integer>();
      A()
       {
         m.put(10,11)
         m.put(11.12)
       }

      }

    Class B extends A
    {
      B()
      {
        super.m.put(34,90)    —— I don’t want to give access to child       class to add 

the value and child class and its only should able to get the values. } }

Jena
  • 59
  • 1
  • 4
  • Is your goal to create an Immutable map that can be accessed by B to read values? Or is this map going to be modified later? – jbarrueta Apr 24 '15 at 06:59
  • 1
    if you don't want to modify then make it private final in Super and make use of getter method in Super class so that you can get unmodifiable hashmap. – Shriram Apr 24 '15 at 07:01
  • B should have only read access for the Map. – Jena Apr 24 '15 at 07:02
  • HI Shriram,I know we can use getter and setter but i don't want to use those ,without using how we can prevent. – Jena Apr 24 '15 at 07:03

3 Answers3

2

Make the map unmodifiable, and populate it in the construction of A.

class A {
    protected final Map<Integer,Integer> m;

    A() {
        Map<Integer, Integer> tempMap =  = new HashMap<>();
        tempMap.put(10,11);
        tempMap.put(11.12);
        this.m = java.util.Collections.unmodifiableMap(tempMap);
    }
}

If and when B attempts to modify the map, a ´UnsupportedOperationException´ will be thrown.

If you want A to be able to modify the map, then you'll need a different approach in which the map is private, and a protected getter returns an unmodifiable map.

class A {
    private final Map<Integer,Integer> m = new HashMap<>();

    A() {
        m.put(10,11);
        m.put(11.12);
        // m remains modifiable within the context of A
    }

    protected Map<Integer, Integer> getMap() {
        return java.util.Collections.unmodifiableMap(m);
    }
}

EDIT

If you really don't want to use a getter but still have read-only access, you can use this approach.

class A {
    private final Map<Integer,Integer> writableMap = new HashMap<>();
    protected final Map<Integer,Integer> m = Collections.unmodifiableMap(writableMap);

    A() {
        writableMap.put(10,11);
        writableMap.put(11.12);
    }
}

Using this approach, only m is visible outside A, and is read-only. Within A, you can update writableMap and these changes will be visible in m

Steve Chaloner
  • 8,162
  • 1
  • 22
  • 38
  • HI Steve,if i use unmodifiable map then if i want to add the values in future from super class then i can't do that so unmodifiableMap will not work in this .So i would like my Map to modifiable from Superclass not from Sub class. – Jena Apr 24 '15 at 07:11
  • But a childclass would still be able to edit the writable map wouldn't it? Never mind he has no getter – Lama Apr 24 '15 at 07:34
  • 1
    No, because writableMap is private. Child classes can't see it; that's the entire point of `protected`. – Steve Chaloner Apr 24 '15 at 07:39
0

Here is a variant of what Steve Chaloner presented in his answer:

public class A {

    private final Map<Integer, Integer> map = new HashMap<>();
    protected final Map<Integer,Integer> m = Collections.unmodifiableMap(map);

    public A() {
        map.put(10, 11);
        map.put(11, 12);
    }
}

The private map is modifiable in the A class and changes will be reflected in the protected m whenever changes are made in map.


It is being used this way in Concurrency In Practice for example.

maba
  • 47,113
  • 10
  • 108
  • 118
  • Is there any other way for this problem? – Jena Apr 24 '15 at 07:40
  • @Jena What other way would you need? It solves the problem you have presented to us. Subclasses can **only** access `m` and can **not** do any modifications. Superclass `A` can **still** do modifications. – maba Apr 24 '15 at 07:42
  • HI Maba,Here we end up creating two collection variable so thats why i am asking for the other way ,its confuse that super class can't use "m Map" to put the values . – Jena Apr 24 '15 at 07:46
  • 1
    @Jena Well rename `m` to `readOnlyMap` instead then. I don't really see the problem. – maba Apr 24 '15 at 07:47
  • Thanks Every one for Answering . – Jena Apr 24 '15 at 17:00
0

This should be the best solution Composition:

Implement a new Map and keep an internal private modifiable map like this:

class A {

    private Map<Integer,Integer> m = new HashMap<>();

    protected Map<Integer, Integer> map = new Map<>() {
        //implement interface
        public Integer put(Integer key, Integer value) {
            throw new UnsupportedOperationException();
        }

        public Integer get(Object key) {
            return m.get(key);
        }

        public void clear() {
            throw new UnsupportedOperationException();
        }

        public boolean containsKey(Object key) {
            return m.containsKey(key);
        }

        public boolean containsValue(Object value) {
            return m.containsValue(value);
        }

        //
        // ... And so on
        //
        // ... with all other methods
    }

    A() {
        m.put(10,11)
        m.put(11.12)
    }


}

class B extends A {
    B() {
       super.map.put(34,90) // thorws exception
       super.m.put(34,90) // inaccesible
    }
}

All modifications are allowed in A via m but subclasses may only acces them by map that was succesfully blocked modifications.

Mordechai
  • 15,437
  • 2
  • 41
  • 82