36

Is there any way to, in a Java derived class, "disable" a method and/or field that is otherwise inherited from a base class?

For example, say you have a Shape base class that has a rotate() method. You also have various types derived from the Shape class: Square, Circle, UpwardArrow, etc.

Shape has a rotate() method. But I don't want rotate() to be available to the users of Circle, because it's pointless, or users of UpwardArrow, because I don't want UpwardArrow to be able to rotate.

Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188

11 Answers11

45

I don't think it is possible. However you can further refine the Shape class by removing the rotate() method from its specification and instead define another subclass of Shape called RotatableShape and let Circle derive from Shape and all other Rotatable classes from RotatableShape.

e.g:

public class Shape{
 //all the generic methods except rotate()
}

public class RotatableShape extends Shape{

 public void rotate(){
    //Some Code here...
 }
}

public class Circle extends Shape{
 //Your implementation specific to Circle
}

public class Rectangle extends RotatableShape{
 //Your implementation specific to Rectangle
}
Chandu
  • 81,493
  • 19
  • 133
  • 134
  • What about implementing a `Rotatable` interface or something, like `public class Circle extends Shape implements Rotatable {`? Is that possible? Not? Preferred? (I'm not an expert) – Joshua Pinter Mar 08 '17 at 15:25
  • Check out the [Liskov Substitution Principle](https://en.wikipedia.org/wiki/Liskov_substitution_principle), which is the reason for your confusion, and the reason for this answer. Basically, it says any subclass had better be able to act just like its super class. – Nick Crews May 20 '17 at 17:28
23

You can override the specific method "rotate()" in the class you want to disable this operation, like this

public void rotate() {
    throw new UnsupportedOperationException();
}
Wavyx
  • 1,715
  • 2
  • 14
  • 23
  • 2
    This answers the more general question where maybe the developer is not also creating the superclass. – Brian Risk Apr 21 '17 at 14:51
  • Exactly. All the answers posted here at the moment don't consider that case if the base class might be a standard class which you are not able to reimplement. Maybe it is not a really good practical example, but let imagine you want to implement a FastHashMap derived from HashMap, but you want to allow only putIfAbsent() method and disallow put() method (putIfAbsent() exists since Java 8). – Alexander Samoylov Oct 03 '18 at 10:32
8

You have a bad class heirarchy if you need to disable methods in child classes. Any subclass should be able to smoothly use the methods of its superclasses. This is called the "Liskov Substitution Principle" (https://en.wikipedia.org/wiki/Liskov_substitution_principle). You can read more about this in this thread: https://softwareengineering.stackexchange.com/questions/219543/should-a-class-know-about-its-subclasses.

Do what Chandu suggests. Don't put rotate() in Shape. Instead, make a subclass of Shape called RotatableShape, and put rotate() in there. Then Circle can inherit from Shape, and Rectangle can inherit from RotatableShape.

Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
Nick Crews
  • 837
  • 10
  • 13
5

No.

  • you can pull the method down in only the Circle class (or an interface that is implemented only by that class)
  • you can provide an empty implementations or ones that throw UnsupportedOperationException in the classes that do not support it.
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • @Jean-François Corbett that's the eclipse terminology. This means you move it from the superclass to the subclass. – Bozho Mar 30 '11 at 14:17
3

Declaring the same function in the 'child'-class will overwrite the default function declared in the base class. So in your child-class, make a function called rotate() which does nothing, that will overwrite the default behaviour

3

Can you use an empy (does nothing) method for the circle? For the arrow I would reconsider object hierarchy

Riccardo Cossu
  • 2,699
  • 1
  • 28
  • 47
2

One way to deal with this is to define a second method called (say) boolean isRotatable(), and use this to determine whether the rotation controls are made available to the user.

Another option would be to introduce a Rotatable interface and use shape instanceof Rotatable to make the determination. (However, I think the isRotatable() approach is more flexible.)

In either case, you can implement the rotate() method on a class that should never be rotated as:

public void rotate() {
    throw new UnsupportedOperationException("rotate");
}

The Java language doesn't provide a way to "remove" or "disable" a method in a subclass. That would violate the substitutability principle and would break polymorphism. A subclass cannot remove visible members from the parent classes API.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

So there are two possibilities here. One is that you have an object that can rotate, but shows no change in the process. The other is that you have an object that is defined by it's direction. Each ought to be handled separately and in their own way.

So for circle, we have a stub for a rotate function since there is no change in the system. Don't like it, too bad. I'm putting off my quiz on point groups to write this.
For upward arrow, we throw an exception since we don't want to drive the wrong way on a one-way street and this ought to be constant anyway.

In my case, I'm defining a point in 3 dimensional space by inheriting operations from a class defining a quaternion. The 3 dimensional point only uses the 3 imaginary coordinates of the quaternion and if the quaternion has a non-zero value for the real component, it will ruin the vital operations of the rendering algorithm inherited from the quaternion via the 3 dimensional coordinate.

Excuse me for being overly philosophical, however, this question raises a valid point in CS about how this should be handled. As Stephen notes, being able to hide, disable or remove the inherited function in the child class "...would violate the substitutability principle and would break polymorphism."

My case falls under the upward arrow, except I'm pointing into imagination. I am attempting to truncate a derived class, which means any 'grandchild' class (possibly inheriting spin operators) would no longer necessarily be quaternions. It would be more elegant to avoid resorting to throwing exceptions, by trimming the base class at the typecast for a truncating derived class. The alternative would be defining the 3 dimensional coordinate as a separate class with a quaternion member variable; the drawback is that the implementation has too much glue.

Then I can put the new spin operations into the derived class for the 3 dimensional coordinates for the three planes (ij, jk, ik) and then the objects with 3d vertices can be rotated via a loop and an identical member function call for each vertex. You might could keep track of the symmetry on your own, before you start rotating the points defining the surface of sphere, which is why you need to use the stub function and possibly implement your own 'constant' flag.

JustKevin
  • 378
  • 3
  • 13
1

I don't think you can disable a method in the way you suggest.

In your example, lets say you have a method that takes a Shape

public void handleShape(Shape s){
  s.rotate();
}

Then you pass a Circle to this method

handleShape(new Circle());

What should happen? Essentially you are asking for a fundamental change to Java's type system.

If Circle is a Shape and shouldn't be rotated then it probably means that Shape was designed poorly and shouldn't have a rotate method. You can add rotate to a different class int the hierarchy like, RotatableShape or possibly use an interface Rotatable.

richs
  • 4,699
  • 10
  • 43
  • 56
0

I needed the same thing for a custom alertdialog. I needed to pass an argument that became available only at the show moment, so I implemented my show(argument) method, but show() worked too because of the superclass. There was a risk of that I could invoke myDlg.show() by accident, without an argument, and that would cause a crash. To make sure the superclass method is never called outside my CustomAlertDialog class, I added the method private static void show(){} to it. That's it.

So, to disable a supermethod, make it private and static in the subclass. In your case, it would be:

 private void rotate(){}
Eugene Kartoyev
  • 501
  • 4
  • 11
0

There is a possibility and it's quite simple. Instead of inheritance use composition:

public class Shape{
   public method1();
   public method2();
   public rotate();
   public method3();
}

public class Circle{
  private Shape shape;

  public Circle(){
    this.shape = new Shape();
  }

  public method1(){
    shape.method1()
  }

  public method2(){
    shape.method2()
  }

  public method3(){
    shape.method3()
  }
}