1

I've got two class: GraphNode and BTNode extends GraphNode. I've got method:

public GraphNode.addChild(GraphNode node) 

as GraphNode may have many children and two methods:

public BTNode.addLeftChild(BTNode left) public BTNode.addRightChild(BTNode right) 

as BTNode may have only two children

How may I restrict public access to inherited addChild(GraphNode node) method from BTNode class? I wouldn't like to have that publicly accessible from that level (while remaining public access from GraphNode class)?

7
  • 1
    You can't do that, but what you can do is implement addChild and have it throw an exception with a good error message that explains why this method shouldn't be used here and what should be used instead. Now, all that said, maybe you should re-consider inheritance, because it feels that BTNode doesn't have that much in common with GraphNode after all... Commented Aug 26, 2017 at 15:16
  • 1
    You probably may have to ask yourself, is the right way to inherit from the parent class? You are trying to violate the Liskov substitution principle over there. I guess you should rethink your design. Commented Aug 26, 2017 at 15:17
  • I was thinking about design and it indeed looks like problem here. HOWEVER I cannot see why is so as the only difference between BTNode and GraphNode is that that first may have only two children. Binary Tree IS indeed a special version of graph isn't it? Commented Aug 26, 2017 at 15:25
  • I don't like the idea of letting the user use the method only to throw an exception. BUT maybe the solution would be to let him add only two children (assuming that left and right is not important for the user so assigning them just in order) and THEN throwing an exception when the user tries to add more children? Commented Aug 26, 2017 at 15:27
  • 2
    Likewise a square is a special version of a rectangle but you don't inherit a square from a rectangle, otherwise you violate Liskov's principle: stackoverflow.com/questions/1030521/… Commented Aug 26, 2017 at 15:33

3 Answers 3

4

If you extend (or implement) from a class (or interface) then the parent will specify the whole signature of a method. There is nothing you can change about it, you will always need to have the method public if your parent specifies it as public.

Otherwise you would run into problems when casting like ((Parent) child).theMethod(). The object itself is child but the view gets reduced to the Parent class. The method gets invoked from the child class, so it would be private although you casted it to Parent which specified it as public.

However you could do something like:

public class Child extends Parent { @Override public void theMethod() throws UnsupportedOperationException { throw new UnsupportedOperationException(); } private void otherMethod { // Do something } } 

But note that saying "I am extending class XY but not supporting all of its methods" is not the best design. It is a sign that the parent class (or other parts of the architecture) could have been structured more modular in the first place.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for great answer. It is clear now why such operation is impossible. And, tbh, I've neven seen that class of exception before ;) However I don't like the idea of letting the user to call a method only to throw an exception, I have an idea how to use it properly now.
You're welcome. Most of such problems come from an improper architecture/structure and can be avoided simply by using a better suited one. You are right that saying "I am extending class XY but not supporting all of its methods" is not the best design. It is a sign that the parent class could have been structured more modular in the first place. Good to here that you have found a better one :)
1

It is not possible to reduce the visibility of a method in subclass. The subclass need to be a valid instance of the base class.

Comments

0

As you can see in the previous answers, it is not possible to change visibility of public methods in the child classes. But in case of you are designer of GraphNode class, you could use a little bit another class hierarchy:

public abstract class BaseNode { protected final Map<String, GraphNode> children = new HashMap<>(); protected void addChild(String id, GraphNode node) { children.put(id, node); } } public class GraphNode extends BaseNode { public void addChild(GraphNode node) { children.put(String.valueOf(System.currentTimeMillis()), node); } } public class BTNode extends BaseNode { private static final String LEFT = "left"; private static final String RIGHT = "right"; public void addLeftChild(BTNode node) { addChild(LEFT, node); } public void addRightChild(BTNode node) { addChild(RIGHT, node); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.