Overriding a chained method - java

Let's have class A with a method useful for chaining:
class A {
A foo() {
// do stuff
return this;
}
}
You could now do a.foo().foo().foo() (think: builder pattern). Let class B extend it:
class B extends A {
}
B b;
Now invoking b.foo() returns actual type B, but declared A. Therefore I cannot write:
B other = b.foo();
I would have to write either:
B other = (B) b.foo();
Or override foo() in B:
class B extends A {
#Override
B foo() {
super.foo();
return this;
}
}
Is there a nice way to do this?

Did this by implementing an additional generic method as(type) to the superclass. This helps to have a nicer cast for fluent interfaces.
class A {
public A foo() {
return this;
}
#SuppressWarnings("unchecked")
public <T extends A> T as(Class<T> clazz) {
return (T) this;
}
}
class B extends A {}
So you can write a.foo().as(B.class).methodOfB(..). And you do not need to reimplement foo() in all subclasses.

Sorry, but no you already listed the nicest way:
B other = (B) b.foo();
That would be the solution for any developer, who uses classes A and B.
Overwriting is for you, so that other developers could simply write B other = b.foo();
But there is actually no other way for the compiler to know, that
B is sort of an A
B is compatible, so that you won't use any information when instantiating an A but putting it in a B
The last one is the reason why you have to cast explicitly. Example:
int myInt = 2;
short myShort = (short) myInt; // correct
although this works, the compiler needs you to be explicit, because in many cases (when myInt is big) you will loose precision / information when casting to short.
If this one would work:
short myShort = myInt; // wrong
Then the compiler would make an assumption on its own. But only the developer can know, if myInt will ever have a value that is bigger than a short can hold.

You can declare class A to have a generic type parameter of its implementing class and foo() could return this dynamic type:
class A<T extends A<T>> {
#SuppressWarnings("unchecked")
T foo() {
// do stuff
return (T) this;
}
}
class B extends A<B> {
B bar() {
// do other stuff
return this;
}
}
After this, the following is valid:
B b = new B();
b.foo().bar();

I think the nice way to do this is to keep the reference as type A, since this is the least specific class that has the functionality that you require:
A other = b.foo();
You should only cast to type B if B contains some required functionality:
B another = (B)A;
another.somethingElse();
This is the same logic that makes:
List<String> myList = new ArrayList<>();
more desirable than:
ArrayList<String> myList = new ArrayList<>();

Related

Polymorphic method return type down-casting in java

So I don't know if this is possible I've tried searching it but maybe my search terms are off. Basically I'm wondering, is there a way to create a generic function/method in a super class that returns the downcast object.
class A {
public <downcasted type (in this example B if called from a B instance)> test() {
return this;
}
}
class B extends A { }
B b = new B().test()
basically having "test()" return the B instance as type B even know the function/method is declared purely in the parent class?
I know I can cast the variable, tho having many functions some of which may return Lists of the class type, etc become troublesome. I also realize I could #override the function in B and do a "return (B)this.super()" thing, but again wrapping many functions is tedious and makes makes updating the base classes code more painful.
I also know you can do
"class A<T extends A>"
and then define B as
"class B extends A<B>"
but then if you want to make a "C" that extends "B" it breaks.
So is this type of behavior possible? If so, what is it called and how do I implement it?
An example as to where this behavior could be useful would be any base data structures you want to make extendable like an N-Ary Tree that you extend into oct/quad tree structure and/or an extended class that adds a "Name" and "Attributes" or something for a xml-like node.
Edit:
This seems to work(as far as the linter is concerned), it's a bit more work to implement the base methods but it's got the desired end result as far as I can tell. That said when I attempt to run it, it gives me a "cannot find symbol: class type" error. :S
static class D extends auto {
final Class type = getClass();
#SuppressWarnings("unchecked")
public <T extends type> T test() {
return (T)type.cast(this);
}
}
static class E extends D { }
static class F extends E { }
static {
D d = new D().test();
E e = new E().test();
F f = new F().test();
}
Update
There is a simpler way, which seems to work:
class Alpha {
#SuppressWarnings("unchecked")
<T extends Alpha> T test() {
return (T) this;
}
}
class B extends A { }
However, that does not support method chaining.
Original post
You need test() to return a subtype of A, rather than A itself. In order to do this, the signature of the A class could be this:
class A<T extends A<?>> {
#SuppressWarnings("unchecked")
public T test() {
return (T) this;
}
}
If you create a class B extending A, you will need B.test() to return an instance of B, without needing to override test() returning a specific type. You could then do something like this:
class B<T extends B<?>> extends A<T> { }
Now T is a subclass of B, and because test()'s return type is T, it will return a B instance. Further subclassing can be done in the same way:
class C<T extends C<?>> extends B<T> { }
And statements like this will work:
C<?> c = new C<>().test();

Return data type the same as class name via superclass?

I have an abstract class which has one abstract method. I want this method to return the same data type as the class which is overriding the method without having to cast the result of create or having to make a new method declaration on each subclass. I want it to all be declared seemlessly from the parent class.
I want the method to return a object whose data type is the same as the class it was called on.
EDIT: I removed print as people are getting confused with what I am asking
abstract class A
{
public abstract ... create();
}
class B extends A
{
#override
public ... create()
{
return new B...;
}
}
class C extends A
{
#override
public ... create()
{
return new C...;
}
}
Such that
B x1 = new B();
B x2 = x1.create();
// Since create was called on a B object
// a B object is returned, NOT AN "A" object
C y1 = new C();
C y2 = y1.create();
// create makes a C object this time,
// because it's called on a C object
// Problem: create() returns A object, even when
// called from class B or C.
// I want create() to return a B object if called from a B object.
What would be a good way of going about this? Thanks.
I no longer think this is the right answer. It's an answer, but is over-complicated. See my other answer.
There is no notion of a "self" type in Java's generics. The best you can do is to use self-bounded generics:
abstract class A<T extends A<T>>
{
public abstract T create();
}
Then, in your subclasses:
class B extends A<B>
{
#override
public B create()
{
return new B...;
}
}
Actually, there is an easier way to do it than with my other answer: just use a covariant return type in the subclass:
abstract class A {
public abstract A create();
}
class B extends A {
#Override public B create() {
return new B...
}
}
This is more pleasant if you are dealing with instances of A, since you don't have to make it generic (or, shudder, raw).
It also gives just as much of a guarantee that it returns a "self" type, i.e. no guarantee at all.
this.getClass() to get the class object, or, this.getClass().getSimpleName() to get a string of class name.
I have to question the design approach.
I'd be going for
abstract class A {
abstract Supplier<? extends A> create();
}
with
class B extends A {
public Supplier<B> create() {
return B::new;
}
}
(and C accordingly).
Then, there is
A b = new B();
A anotherB = b.create().get(); // will create a B
A c = new C();
A anotherC = c.create().get(); // will create a C
You don't need to make your create method abstract. If all the subclasses have a no-argument constructor, then you can just write this (in class A)
public A create() {
try {
return getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
return null;
}
}
This checks the class of the object that you called the method on; and creates a new object of the same class, using its no-argument constructor.
Update
OP's comment suggests that they don't want to have to cast the returned value. If this is a requirement, then the casting can be avoided by changing the method signature as follows.
public <T extends A> T create() {
try {
return getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
return null;
}
}

Java generic types inheritance error

In Android Studio I have the following error:
java: incompatible types: java.lang.Object cannot be converted to
java.lang.String
I think b1 and b2 should be behaving the same, but they are not.
Is there a way to make them behave the same (without changing their type of course)?
Here is the code typed:
public class Test
{
class A<T>
{
T t;
T getT()
{
return t;
}
}
class AS extends A<String>
{
}
class B<T> extends AS
{
}
B<Object> b1;
B b2;
public void test()
{
String t3 = b1.getT();
String t4 = b2.getT();
}
}
The problem is that B is a parameterized type, but b2 is declared to have raw B as its type.
You demonstrate with b1 that B's type parameter is distinct from A's, even though they have the same name, so that B's type parameter has nothing to do with the return type of the getT() method inherited from A<String>. When you use a raw type, however, you get the full erasure of that type, including of its supertypes.
Since's A's type parameter is unbounded, its erasure produces type Object, and therefore this is the type of b2.getT(). Of course, Object is not assignable to String.
You can resolve this in at least two ways:
Don't use a raw type for b2. If you don't care about its type parameter then use B<?>. Or,
Remove class B's type parameter. It's not used for anything in your example, so that would be the cleanest thing to do. Just because its superclass is generic does not mean that B has to be.
I think that B without the template object is an incomplete class as opposed to B<Object>. This is why when you are calling it getT() you are actually calling A.getT().
This why in the code below, only String t3 = b2.getT(); fails to compile.
static class A<T>
{
T t;
T getT()
{
return t;
}
}
static class AS extends A<String> {}
static class B<T> extends AS {}
static class C extends B<Object> {}
static A a;
static B<Object> b1 = null;
static B b2 = new B();
static C c = new C();
static void test()
{
Object tt = a.getT();
String t2 = b1.getT();
String t3 = b2.getT();
String t4 = c.getT();
}
The issue here is that getT() returns the object. What you need to do is implement a method toString() that gives the value of the T Object in terms of a String (or just change the types for t3 and t4 to T so the declaration comes out to T t3 = b1.getT(); and T t4 = b2.getT();).
In addition, you should do the following instead of the code you have for B.
B<T> b1;
B<T> b2;
Note that you need to initialize B to something before you can call b1.anyMethod() or else you'll get a NullPointer Exception.

How to make this interface as this parameter's type not throw "incompatible types" when it's assigned to an object that implements the interface?

Without irrelevant pieces, I have:
public interface A {
// contents
}
public class B implements A {
// contents
}
I'd like to follow the dependency interjection pattern by instantiating the object of class B in my main method then passing it into class C's constructor, instead of instantiating it in C's constructor.
public class C {
private final B object;
private int D;
}
public C(A object) {
B = object;
D = object.method();
}
public static void main(String[] args){
C finalobject = new C(new B);
}
Essentially, I want to do something similar to what this question is based on.
I get the error:
C.java:137: error: incompatible types: B cannot be converted to A
C finalobject = new C(new B());
How do I pass B into C's constructor with the interface as the parameter?
I've tried casting it, and I can't instantiate it as the interface in the first place for obvious reasons. I can't pass it in as the object's class type not only because it doesn't fit the specifications I have for how this program has to behave, but I'd like to learn how to do what I've been trying to do.
You're forgetting that there could also be a D, E, F, and G classes that implement A interface. Meaning what you're doing is wrong conceptually. Of course you know what you're passing inside and you know it is an instance of class B, however Liskov's Substitution Principle would suggest that you either deal entirely with B or deal entirely with A depending on what fits the role better. You shouldn't ever need to cast to a derived class.
So that said, your solution is simply the following:
public class C {
private final A object;
private int D;
}
Any methods you need to call in B should be added accordingly to A, and if you don't think that A is suited to have certain methods, then you should ask yourself if you should be passing an A instance to C to begin with.
Hope that helps!
The definition of class C should be:
public class C {
private final A object;
private int D;
}
If you really need a B in C class, you have to change the C constructor to:
public C(B object) {
B = object;
D = object.method();
}

How to find out the subclass from the base class instance?

Is there a way to find out the name of derived class from a base class instance?
e.g.:
class A{
....
}
class B extends A{
...
}
class c extends A{
...
}
now if a method returns an object of A, can I find out if it is of type B or C?
using either instanceof or Class#getClass()
A returned = getA();
if (returned instanceof B) { .. }
else if (returned instanceof C) { .. }
getClass() would return either of: A.class, B.class, C.class
Inside the if-clause you'd need to downcast - i.e.
((B) returned).doSomethingSpecificToB();
That said, sometimes it is considered that using instanceof or getClass() is a bad practice. You should use polymorphism to try to avoid the need to check for the concrete subclass, but I can't tell you more with the information given.
Have you tried using instanceof
e.g.
Class A aDerived= something.getSomethingDerivedFromClassA();
if (aDerived instanceof B) {
} else if (aDerived instanceof C) {
}
//Use type-casting where necessary in the if-then statement.
Short answer to your question
Is there a way to find out the derived class's name from a base class object?
no, the super-class has no way of telling the name/type of a sub-class.
You have to interrogate the object (which is an instance of a sub-class) and ask if it is an: instanceof a particular sub-class, or call it's getClass() method.
You can do it in the subclass' constructor
class A {
protected String classname;
public A() { this.classname = "A"; }
public String getClassname() { return this.classname; }
}
class B extends A {
public B() {
super();
this.classname = "B";
}
}
So
A a = new A();
a.getClassname(); // returns "A"
B b = new B();
b.getClassname(); // returns "B"
((A)b).getClassname(); // Also returns "B"
Because it is casted into an "A" object, it will call the "A" getClassname() function but will return a value set by the constructor that was the "B" constructor.
Note: Call super(); before setting it
There are 2 ways I can think of
1) One with Using the Java reflection API
2) Other one would be with the instanceOf
Other method can be a Comparing objects to objects, I dont know how it might be, you can try this
Is there a way to find out the name of derived class from a base class instance?
As answered here, you can use this extremely simple approach.
abstract class A {
public final String getName() {
return this.getClass().getName();
}
}
class B extends A { }
class C extends A { }
then simply print the current class name:
B b = new B();
C c = new C();
System.out.println(b.getName());
System.out.println(c.getName());
Output:
com.test.B
com.test.C
There is no need to store additional Strings, check instanceof or override the method in any subclass.
A more modern approach (Java 16+) would be using pattern matching for the instanceof operator. The syntax is pretty simple:
if(x instanceof X xChild){
// use xChild
}
It is both shorter and less error-prone as it combines all the steps of testing the runtime type of the variable(x in the example above), casting it down, and assigning it to a new variable(`xChild in the example above). Read more.
Another example:
public void addUIControl(UIControl control) {
if(control instanceof SelectList sl){
selectList = sl;
}
else if(control instanceof TextBox tb){
textBox = tb;
}
else if(control instanceof Button btn){
button = btn;
}
else {
throw new IllegalArgumentException("Uknown UIControl object has been passed to the SendFormMediator");
}
}

Categories