class One {
public One foo() { return this; }
}
class Two extends One {
public One foo() { return this; }
}
class Three extends Two {
public Object foo() { return this; }
}
public Object foo() { return this; } throws a compilation error. Why is that? Can someone explain why "Object" type is not possible? Is Object the base class of Class One, Two? If So why does it throws an error?
Please change the title of the question as I couldnt find a suitable title.
Three.foo is trying to override Two.foo(), but it doesn't do it properly. Suppose I were to write:
One f = new Three();
One other = f.foo();
Ignoring the fact that actually Three.foo() does return a One, the signature of Three.foo() doesn't guarantee it. Therefore it's not an appropriate override for a method which does have to return a One.
Note that you can change the return type and still override, but it has to be more specific rather than less. In other words, this would be okay:
class Three extends Two {
public Three foo() { return this; }
}
because Three is more specific than One.
You are changing the signature of the foo method in a way not supported. Polymorphism only works for different argument list, not for identical methods only different by the return type.
And if you think about it, it is quite natural... If it worked and someone who only knows about one of the two super classes would call Three.foo() he would expect it to return a One (because that is how it works in One and Two) but in Three you could actually return a HashMap and still behave correctly.
Jon (in the comment below) is correct, you can narrow the scope but then you would still follow the protocol that you will return a "One" (should you return a Three from Three.foo()) because subclasses will all implement the superclass interface.
However, return type is still not part of the polymorphism, hence you cannot have three different methods that only differs by return type.
It would enable:
class Four extends Three {
public Object foo() { return "This String is not an instance of One"; }
}
Overriding a method and trying to return a less specific type is a violation of the Liskov substitution principle, which says that subclasses must fulfill all contracts of their superclass. Your class Three violates the superclass contract "foo() returns an instance of One".
Related
I realize the title is kind of messy, but that's the best I could come up with.
Below is a minimal example of what I wish, but am currently failing to do.
public class ObjectA {}
public class ObjectB extends ObjectA {}
public interface HandlerInterface<T extends ObjectA> {
public T easyToOverride();
public List<T> hardToOverride();
}
public class HandlerA implements HandlerInterface<ObjectA> {
public ObjectA easyToOverride() {
return new ObjectA();
}
public List<ObjectA> hardToOverride() {
return new ArrayList<ObjectA>();
}
}
public class HandlerB extends HandlerA implements HandlerInterface<ObjectB> {
/*
This method ovverides its super method with ease since its return
type directly inherits from the super class's return type
*/
public ObjectB easyToOverride() {
return new ObjectB();
}
/*
This method is NOT accepted by the Java syntax since List<ObjectB>
does NOT directly inherit from List<ObjectA>
The method signature for hardToOverride() clashes with the signature
in the super class and is not overridden because the return types
don't obviously inherit each other
*/
public List<ObjectB> hardToOverride() {
return new ArrayList<ObjectB>();
}
}
Ignore that these classes should be in their own files and that I have not included their imports. I just put it like this to make it easier to read.
As you may have understood by the comments in the class HandlerB, the method hardToOverride() is not accepted (throw this code into your IDE and watch it scream).
I realise I could just return a List<Object> and type cast the contents of the returned List object to the type that I personally know the specific handler instance returns (ObjectA or ObjectB), but that would mean that anyone using these methods has to understand the inner workings of them, and I do not like that.
What I want is to be able to override the List<ObjectA> hardToOverride() method with a method List<ObjectB> hardToOverride() without losing the hard typing that these methods provide.
So my final question is:
Is there any way to keep all of these interfaces, inheritances and overrides without loosing the strong typing they provide in my example code?
If not, what is a better way to achieve a similar set of classes and interfaces that actually works?
Your code is accepted if you declare HandlerA with a new generic even if this is never used really:
public class HandlerA<T> implements HandlerInterface<ObjectA> {
//....
}
NOTE: This is to be considered just a workaround but as result your example code will work as you asked. Moreover, even if HandlerA declares a generic, you can anycase instantiate it also without brackets:
ObjectA objectA = new HandlerA();
I am working on creating a java utils library and have come across a problem with generics. I have found a solution that lets the library work, but it seems like bad code practice and prone to undetected program failures. For question's sake, I've simplified the program into a minimum verifiable example.
Let's say I have an interface Invokable<E>, which is called upon to effect an E.
public interface Invokable<E> {
void invoke(E e);
}
Let's say I have another interface, InvokableFactory<E>, which creates Invokable<E>s
public interface InvokableFactory<E> {
Invokable<E> create();
}
Now let's say I have a class InvokableUser<E>, that is designed to be extended. It holds an InvokableFactory<E>, and uses it to create an Invokable<E>, which it then invokes with itself.
public class InvokableUser<E> {
private InvokableFactory<E> factory;
public InvokableUser(InvokableFactory<E> factory) {
this.factory = factory;
}
public void start() {
factory.create().invoke((E) this);
}
}
You might see that my conundrum is that I'm trying to ensure that a subclass InvokableUser, extends InvokableUser of the generic type of itself. I'm trying to ensure that an InvokableUser contains a factory that produces Invokables that can be invoked with the InvokableUser object, but still be passed an object of the type of the subclass of InvokableUser so that the Invokable can utilize methods added only by the subclass of InvokableUser.
I feel like I might not be explaining this very well, so for example, let's say there's a subclass of Invokable that needs to print out the getString method added by a subclass of InvokableUser, like this:
public class PrintingInvokable implements Invokable<PrintingInvokableUser> {
#Override
public void invoke(PrintingInvokableUser e) {
System.out.println(e.getString());
}
}
public class PrintingInvokableUser extends InvokableUser<PrintingInvokableUser> {
public PrintingInvokableUser() {
super(PrintingInvokable::new);
}
public String getString() {
return "( ͡° ͜ʖ ͡°)";
}
}
If you create a new PrintingInvokableUser() and call start() on it, it will create a new PrintingInvokable() and call invoke(this) on it, when will then print out the getString() method of the PrintingInvokableUser.
While my code does work for this, it depends on the unwritten expectation that a subclass Foo of InvokableUser will extend InvokableUser<Foo>, involves an unchecked cast which is bad (and raises a compiler warning), seems to not even make use of the generic type as I could achieve the same effect with unparametrized types, and generally seems like there has to be a better way to do this.
If someone could point me in the right direction for how to do this, I'd be appreciative. Thanks!
I haven't quite found an elegant way to solve this issue. I have an abstract class that several other classes are inheriting with an abstract method that can contain anywhere from zero to 4-5 arguments of varying types.
public abstract class Item {
public abstract void use();
}
For instance, I have a Book class that inherits this and takes no arguments when overriding use(), I have a Key class that inherits and takes a String and a Queue as arguments when overriding, etc...
I've tried using generics but I have to input the number used, such as Item, when it actually depends on the class.
public abstract class Item<T,U> {
public abstract void use(T arg1, U arg2); //Number of arguments/types could be more or less
}
I've tried sending a variable list of Objects but the object types are always variable and I've unsure as to the syntax to receive in the inheriting classes.
public abstract class Item<T> {
public abstract void use(T... arguments);
}
public class Book extends Item<?> {
public void use(?);
}
public class Book extends Item<String, Queue> { //Wrong number of arguments since I can't use Item<T...>
public void use(String str, Queue q); //fails
}
I may just be doing something wrong - can anyone offer any assistance or insight?
I've struggled with the same question, and there's not a perfect answer, but I can give you a few things to consider. First, you're basically trying to do something that is inherently against Object Oriented Programming, which is that you're trying to create a variable interface. The point of an interface is that code that gets an abstract version of the object (the Item rather than the Book, for example), knows how to invoke the use() method. This means that they must know what can be passed to the use() method. If the answer depends on the implementation of the abstract class or interface, then you need to ensure that the code using it actually knows what kind of implementation (Book, etc.) that it's using, otherwise it's not going to know how to invoke use() with the appropriate parameters anyway. It sounds like you need to refactor your code, in all honesty.
However, there is a way to answer your question as stated without refactoring the architecture. You could create a class that's data is all of the different types of parameters that could possibly be passed to the use() method, have the calling code set the fields of that class, and then pass that to the use() method. For example:
public class UseParameters {
private String string;
private Queue queue;
// Any other potential parameters to use(...)
public void setString(String string) {
this.string = string;
}
public String getString() {
return string;
}
// All of the other accessor methods, etc.
}
Then, you could define the use method in Item like this:
public abstract void use(UseParameters params);
And any code using an Item would have to set the parameters of the object appropriately:
Item item = // However you're going to get the item
UseParameters params = new UseParameters();
params.setString("good string");
params.setQueue(new Queue());
item.use(params);
I just want to point out that if the code above knows the Item is a Book (which is how it knows to set the String and Queue, then why not just get a Book and skip needing an abstract class with a variable use() method altogether? But I digress. Anyway, the Book would then implement the use() method like so:
#Override
public void use(UseParameters params) {
if(params.getString == null || params.getQueue() == null)
// throw exception
// Do what books do with strings and queues
}
I think that gets you what you want, but you should consider refactoring, I think.
What you want is the Value Object Pattern.
Define a class that encapsulates the various parameter types into one value object, and have the abstract method accept a parameter of this type. Each variation of parameters you were considering would have its own value class.
Then simply add a generic type to the class and have the abstract method accept a parameter of that type:
public abstract class Item<V> {
public abstract void use(V v);
}
To use it, suppose MyItem needs a value object of type MyValueClass:
public class MyItem extends Item<MyValueClass> {
public void use(MyValueClass v) {
}
}
If the types to be used as argument are always variable I don't see a reason to use generics. Just use plain Object type:
public abstract class Item {
public abstract void use(Object ... arguments);
}
public class Book extends Item {
public void use(Object ... arguments) { ... }
}
The best approach I can think of is to group the items according to the behavior of their use() method.
Example
public abstract class QueueableItem {
public abstract void use(String, Queue);
}
public abstract class OrdinaryItem{
public abstract void use(String);
}
If the grouped items share a common behavior (common as in same method signature & return value), you can define and extend a parent class that will contain the definition of this common behavior.
Yes, we can provide parameters to abstract method but it is must to provide same type of parameters to the implemented methods we wrote in the derived classes.
Suppose I have an abstract class like:
public abstract class Pet {
private final String name;
public Pet(String name) {
this.name = name
};
public abstract boolean getsSpecialTreatment();
}
public final class Dog extends Pet {
#Override public boolean getsSpecialTreatment() { return true; }
}
public final class Cat extends Pet {
#Override public boolean getsSpecialTreatment() { return false; }
}
My program will treat Pets differently depending on whether the special treatment flag is set. My question is whether this counts as violating the Liskov substitution principle, which states that:
[...] in a computer program if S is a subtype of T, then objects of type T may be replaced with objects of type S [...] without altering any of the desirable properties of that program (correctness, task performed, etc.).
In this case, users of those classes will probably write:
...
if (pet.getsSpecialTreatment()) {
// special treatment
...
} else {
// normal treatment
...
}
...
This code will work on both cases, so you would not be violating LSP. However, if you had
public class UnknownAnimal extends Pet {
#Override public boolean getsSpecialTreatment() {
throw new UnsupportedOperationException("Unknown species");
}
}
then you would be violating LSP, because existing code will break when using UnknownAnimal instances.
No. Any usage of the method in the program would base subsequent decisions on the return value, just like any other method. By the very nature of the existence of the method, no program should make assumptions as to its outcome. Therefore the change in the value returned by this method should not change the properties of the program.
First, strong objection to your discrimination against cats!
Now, when programmers invoke the so called "Liskov substitution principle", they are not really talking about it in its academic sense. We must be using it in some informal, vulgar, bastardized sense.
What sense is that? I find it nothing more than requiring that subclass must conform to the contract set by the super class. So it's really uninteresting. People invoke this phrase just to be fansy.
It depends on the contract. That is, the code using your classes must get consistent behavior, regardless what derivation of your type is it using.
If the contract stated "getSpecialTreatment" always returns true, you would be violating that in your derived class.
If the contract states "getSpecialTreatment" returns a boolean value determining blabla., then you are not violating LSP.
You could violate LSP if you introduced additional constraint that is not present in the base class.
I Have something similar to this setup:
public class Base {
public String getApple() {return "base apple"};
}
public class Extended extends Base{
public String getApple() {return "extended apple"};
}
Somewhere else in the code I have this:
{
Base b = info.getForm();
if (b instanceof Extended){
b = (Extended) b;
}
System.out.println(b.getApple()); // returns "base apple" even when if clause is true why??
}
How do I accomplish that?
First:
if (b instanceof Extended){
b = (Extended) b;
}
does absolutely nothing. You are basically saying b = b, which says nothing. You are not even changing the reference.
Second, getApple() will always be dynamically bound, and the "extended apple" should always be called - given that the subclass is truly extending the base class, and the method is truly overridden.
Basically what you need to do, in order to accomplish correct getApple() behavior:
remove the if clause. it does nothing.
make sure your class is indeed extending the base class
make sure the getApple() method is overriding the base class method. (use the #override annotation if you are not sure)
As written, your code will not compile, which makes me think that your problem is elsewhere. Your return statements don't have semicolons at the end of them. Rather, they appear after the }. It's possible you had some other problem (maybe your subclass misspelled getApple()), but you're still using your old class files because your new stuff isn't compiling.
This code works:
class Base {
public String getApple() { return "base apple"; }
}
class Extended extends Base {
public String getApple() { return "extended apple"; }
}
public class Test {
public static void main(String[] args) {
Base b = new Extended();
System.out.println(b.getApple());
}
}
Console:
#javac Test.java
#java Test
extended apple
First of all, that if block should never be necessary. It's basically a no-op.
Second, this isn't your real code, because it doesn't even compile. You're missing semicolons after the return statements.
I suspect that your problem is that your real code has a typo that's making the signatures of the two getApple methods different. This means that Extended has two methods: the one inherited from Base and the one with a different signature in itself. Since you're calling with the signature of the Base.getApple method, you're always getting that behavior. This is only a guess though, as your posted code does not exhibit the problem you describe.
Yuval is right that your cast in the if block has no effect. You might try combining your last statement with the if:
if (b instanceof Extended)
{
// Prints "extended apple" if reached.
System.out.println(((Extended)b).getApple());
}
Add #Override to the method in your subclass and recompile. This will help you find out if you're not actually overriding the method you think you are.
i.e.
public class Base {
public String getApple() {return "base apple";}
}
public class Extended extends Base{
#Override
public String getApple() {return "extended apple";}
}
The only way to get that behavior is to return super.getApple() in your extended class, which is effectively the same as not overriding it in the first place. The only way this could help is if you pass in an argument to decide which to return. Not saying thats good design...
Forgot to mention that, as Yuval said, the cast does nothing to the object.
You should investigate what is constructing your instance that is returned from info.getForm(). You may want to make the Base abstract to prevent it from being instantiated and you'll quickly see where construction is happening.
Are you sure your code example provided in your question EXACTLY matches the code your are using? The reason I ask is that the behavior you are describing happens when you access a public FIELD instead of a public METHOD with an object pointer.
For example:
public class BaseClass {
public String baseField;
public BaseClass() {
baseField = "base";
}
public String getBaseField() {
return baseField;
}
}
public class SubClass extends BaseClass {
public String baseField;
public SubClass () {
baseField = "sub";
}
public String getBaseField() {
return baseField;
}
}
public class MainClass {
public static void main(String[] args) {
BaseClass baseObject = new BaseClass();
SubClass subObject = new SubClass();
System.out.println(baseObject.getBaseField());
System.out.println(subObject.getBaseField());
System.out.println(baseObject.baseField);
System.out.println(subObject.baseField);
System.out.println(((BaseClass)subObect).getBaseField());
System.out.println(((BaseClass)subObect).baseField);
}
}
Will print out:
base
sub
base
sub
sub
base
When you call a method, the JVM will start at the bottom of the inheritance hierarchy and call the appropriate method. When you reference a field instead, it uses the class of the pointer instead of walking up the class hierarchy to resolve the value. The behavior of the field reference matches what you're seeing, which is why I ask for clarification/verification.