Trying to add a base interface with method so all derived classes have to implement the method or use default method. What's the best way to going about getting this method callable? See comment in code block below.
public interface IA{}
public interface IB{
public Integer doWork();
}
public interface IC extends IB{
}
class B implements IB{
Integer doWork(){
return 2;
}
}
class C extends B implements IC{
#Override
Integer doWork(){
return 7;
}
}
//What do I need to do to cast clazz to an object so I can call the derived class' doWork method?
private Integer newClient(Class<T> clazz){
((B) clazz).doWork();
}
Ended up finding a solution:
B.class.cast(clazz);
As for how to ensure you call the derived class' method that overrides the base, that is a native behavior of Java.
Example Program:
public class Foo {
static class A {
int get() { return 0; }
}
static class B extends A {
#Override
int get() { return 1; }
}
public static void main(final String[] args)
{
A a = new A();
B b1 = new B();
A b2 = new B();
printA(a);
printA(b1);
printA(b2);
}
public static <T extends A> void printA(T bObj) {
System.out.println(bObj.get());
}
}
Output:
0
1
1
Note that the output returned from b2::get()::int is the same as b1::get()::int, even though b2 is type A and b1 is type B. This is because even though we only have a reference to the A class in b2, the object implementation is still B.
It seems that you only want to know how to instantiate the Class. Assuming it has a default constructor you can do it this way:
private Integer newClient(Class<B> clazz){
try {
((B) (clazz.getConstructor().newInstance())).doWork();
} catch ...
}
Related
I have two Java classes, one of which inherits from other. They are somewhat like the following:
A.java:
public class A {
public String invocations[] = {"foo"};
public A() {
// do stuff
}
}
B.java:
public class B extends A {
public String invocations = {"bar", "baz"};
public B() {
super();
}
}
In this example, assuming I create an instance of B and get its invocations property, it returns {"foo"} instead of the expected {"bar", "baz"}. Why is this, and how can I get the {"bar", "baz"}?
You have one variable hiding another one. You can refer to a variable in a super class by using a cast to the type explicitly. (I am assuming you fix the syntax errors)
public class Main {
static class A {
public String[] invocations = {"foo"};
}
static class B extends A {
public String[] invocations = {"bar", "baz"};
}
public static void main(String... args) {
B b = new B();
System.out.println("((A)b).invocations=" + Arrays.toString(((A) b).invocations));
System.out.println("b.invocations=" + Arrays.toString(b.invocations));
}
}
prints
((A)b).invocations=[foo]
b.invocations=[bar, baz]
Lets say we have a baseclass called A and some subclasses (B,C,D, etc.). Most subclasses have the method do() but the baseclass does not.
Class AA provides a method called getObject(), which will create an object of type B, or C or D, etc., but returns the object as type A.
How do I cast the returned object to the concrete type and call its do() method, if this method is available?
EDIT:
I'm not allowed to change the implementation of Class A, the subclasses or AA, since im using a closed Source API.. And yeah, it does have some design issues, as you can see.
You can test with instanceof and call the do() methods:
A a = aa.getObject();
if (a instanceof B) {
B b = (B) a;
b.do();
}
// ...
I think a better idea is to actually have class A define the do() method either as an abstract method or as a concrete empty method. This way you won't have to do any cast.
If you are not allowed to change any of the classes than you could define a class MyA extends A which defines the do() method and MyB, MyC,... and a MyAA that would basically do what AA does, just that it returns objects of type MyB, MyC....
If this is not ok then I don't see another way than checking if the returned object is of type B and do a cast to B and so on.
Assuming A defines do, and it is not private, you can just call it without a cast, no matter the subclass that AA returns. That's one of the features of polymorphism. At runtime, the interpreter will use the correct (i.e. the implementation of the actual class) version of do.
First of all it would be a better approach to make Class A as an abstract Class with do() as an Abstract method in it......
Moreover if you still want the way you want to do it..then
Do an explicit cast.
B b = (B) a; // a is a casted back to its concrete type.
Moreover you should keep in mind this very important behaviour of the Compiler.
The Object Reference Variable of Super Type must have the method to be called, whether the Sub Type Object has or not.
Eg:
A a = new B();
- To call a method, do() on Object Reference Variable of Type A, class A must have the go() method.
If you are not allowed change A but you can change the subclasses then you can make an interface with the method do() and let all the subclass implement that interface.
public interface Doer {
public void do();
}
public class B extends A implements Doer {
//implement do method
}
//.. same for other subclass
Then you don't need a cast. Otherwise you will need some explicit downcasts.
What you are describing seems to me like you want to invoke Derived Class methods on Base class reference..
But for that, you need to have your methods in your base class also..
So, you need to declare your method do() in your base class A also.. If you don't want to give an implementation, let it be abstract, or let it be an empty method.. It will not matter..
Now, if you do the same thing you're explaining.. You won't need to do a typecast..
Because, appropriate Derived Class method will be invoked based upon - which derived class object does your base class reference point to
public abstract class A {
public abstract void do();
}
public class B extends A {
public void do() {
System.out.println("In B");
}
}
public class Test {
public static void main(String[] args) {
A obj = returnA();
obj.do(); // Will invoke class B's do() method
}
/** Method returning BaseClass A's reference pointing to subclass instance **/
public static A returnA() {
A obj = new B();
return obj;
}
}
Ok, just now saw your edit, that you are not allowed to change your classes..
In that case, you will actually need to do a typecast based on the instance of returned reference..
So, in main method above, after A obj = returnA(); this line add the following line: -
if (obj instanceof B) {
B obj1 = (B) obj;
}
But, in this case, you would need to check instanceof on each of your subclasses.. That can be a major problem..
Best way to do it have A class that method. But since you are not allowed to change any class. I would advice you to create a wrapper instance around all classes using reflections.
Static method in Below class is used just to show how to do it. You can have separate instance variable which can Wrap A in E.
public class E {
public static void doMethod(A a) {
Class<?> class1 = a.getClass();
Method method;
try {
method = class1.getDeclaredMethod("doMethod", null);// B, C, D has doMethod
method.invoke(a, null);
// I know to many exceptions
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
Second option is instance of for which you will have to check for the type and then cast it.
You can do this with a little work if the method invocations return instances of the class in question, which is your specific question (above).
import static java.lang.System.out;
public class AATester {
public static void main(String[] args){
for(int x: new int[]{ 0, 1, 2 } ){
A w = getA(x);
Chain.a(w.setA("a")).a(
(w instanceof C ? ((C) w).setC("c") : null );
out.println(w);
}
}
public static getA(int a){//This is whatever AA does.
A retval;//I don't like multiple returns.
switch(a){
case 0: retval = new A(); break;
case 1: retval = new B(); break;
default: retval = new C(); break;
}
return retval;
}
}
Test class A
public class A {
private String a;
protected String getA() { return a; }
protected A setA(String a) { this.a=a; return this; }//Fluent method
#Override
public String toString() {
return "A[getA()=" + getA() + "]";
}
}
Test class B
public class B {
private String b;
protected String getB() { return b; }
protected B setB(String b) { this.b=b; return this; }//Fluent method
#Override
public String toString() {
return "B[getA()=" + getA() + ", getB()=" + getB() + "]\n "
+ super.toString();
}
}
Test Class C
public class C {
private String c;
protected String getC() { return c; }
protected C setC(String c) { this.c=c; return this; }//Fluent method
#Override
public String toString() {
return "C [getA()=" + getA() + ", getB()=" + getB() + ", getC()="
+ getC() + "]\n " + super.toString();
}
}
The Chain class
/**
* Allows chaining with any class, even one you didn't write and don't have
* access to the source code for, so long as that class is fluent.
* #author Gregory G. Bishop ggb667#gmail.com (C) 11/5/2013 all rights reserved.
*/
public final class Chain {
public static <K> _<K> a(K value) {//Note that this is static
return new _<K>(value);//So the IDE names aren't nasty
}
}
Chain's helper class.
/**
* An instance method cannot override the static method from Chain,
* which is why this class exists (i.e. to suppress IDE warnings,
* and provide fluent usage).
*
* #author Gregory G. Bishop ggb667#gmail.com (C) 11/5/2013 all rights reserved.
*/
final class _<T> {
public T a;//So we can reference the last value if desired.
protected _(T t) { this.a = T; }//Required by Chain above
public <K> _<K> a(K value) {
return new _<K>(value);
}
}
Output:
A [get(A)=a]
B [get(A)=a, getB()=null]
A [getA()=a]
C [getA()=a, getB()=null, getC()=c)]
B [get(A)=a, getB()=null]
A [get(A)=a]
public class A {
protected ClassX a;
public void foo() {
operations on a;
}
}
public class B extends A {
private ClassY b; // ClassY extends ClassX
#Override
public void foo() {
//wanna the exact same operation as A.foo(), but on b;
}
}
Sorry for such a not clear title.
My question is: in class B, when I call foo(), and I want the exact same operation as class A have on a. How do I achive that and without duplicate the same code from A?
If i leave out foo() in class B, would it work?
Or whats happening when I call super.foo() in foo();
Since ClassY extends ClassX, then you can remove private ClassY b from class B. Then you can just set your instance of ClassX to the a instance variable. This allows foo() to be inherited in class B, but still use the same logic and instance variable.
public class A {
protected ClassX a
public void foo() {
// operations on a;
}
}
public class B extends A {
// do something to set an instance of ClassY to a; for example...
public void setClassY(ClassY b){
this.a = b;
}
}
It sounds like ClassX and ClassY would have a common interface (if they have the same methods you want to call on earch, at least). Have you considered making foo() take in an object of the type of the common interface?
public class A {
private ClassX a;
protected void foo(ClassXAndClassYInheritMe anObject) {
operations on anObject;
}
public void foo() {
foo(a);
}
}
public class B {
private ClassY b;
#Override
public void foo() {
foo(b);
}
}
Don't define the foo() method in B if you want the same operation as that in A. If you want a different operation as A, override the foo() method in B. If you want to extend the foo() method in B so that it first does the operation in A and then in B, then call super.foo() at the top of the method; if you want the operation in A to come after the one in B, then call super.foo() at the end of the method foo().
You can do super.foo() inside your overrided method.
class A {
public A get() { }
}
class B extends A {
}
The return types are incompatible for the inherited methods,
how to solve this problem ?
From JDK 5, Java allow you to alter the return type of an overridden method, as long as the new type is a subclass of the original one.
This is called covariant return type.
Following code will compile correctly:
class A {
A get() {
return new A();
}
void sayHello(){
System.out.println("Hello");
}
}
class B extends A {
#Override
B get() {
return new B();
}
void sayGoodbye(){
System.out.println("Goodbye");
}
}
class Test{
void check(){
B two=new B();
two.get().sayGoodbye();
}
}
Remember that the return type of the overridden method should be a subclass of the return type, to allow you to call the method on A variables and get a valid A object (which is infact a B instance):
void check(){
A two=new B();
A copy=two.get();
copy.sayHello();
}
Use generics:
class A<T extends A> {
public T get() { }
}
class B extends A<B> {
}
B b = new B();
B got = b.get();
I'm assuming you want to write something like B b = new B().get(); without explicit typecasting like Nikita Beloglazov suggests, though that's not an idiom that Java supports well. Eugene's answer works well enough, though that still involves a cast to T and generates an ugly compiler warning besides. Personally, I would write code more like the following:
class A {
private A() {}
public A get() {
return new A();
}
}
class B extends A {
private B() {}
#Override
public A get() {
return new B();
}
public B getB() {
return (B) get();
}
}
You still can't do B b = new B().get();, but you can do B b = new B().getB();, which is just as easy and a bit more self-documenting anyways, since you already know you want a B object, not just any A object. And A a = new B().get(); would create a B object, albeit one that only has access to the methods declared in A.
I wanted to create an interface for copying an object to a destination object of the same class. The simple way is to use casting:
import org.junit.Test;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.runner.RunWith;
#RunWith(JUnit4ClassRunner.class)
public class TestGenerics {
public static interface Copyable {
public void copy(Copyable c);
}
public static class A implements Copyable {
private String aField = "--A--";
protected void innerCopy(Copyable c) {
A a = (A)c;
System.out.println(a.aField);
}
public void copy(Copyable c) {
innerCopy(c);
}
}
public static class B extends A {
private String bField = "--B--";
protected void innerCopy(Copyable c) {
B b = (B)c;
super.innerCopy(b);
System.out.println(b.bField);
}
}
#Test
public void testCopy() {
Copyable b1 = new B();
Copyable b2 = new B();
b1.copy(b2);
}
}
But also i've found a way it can be done using generics:
import org.junit.Test;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.runner.RunWith;
#RunWith(JUnit4ClassRunner.class)
public class TestGenerics {
public static interface Copyable<T> {
public void copy(T t);
}
public static class A<T extends A<?>> implements Copyable<T> {
private String a = "--A--";
public void copy(T t) {
System.out.println(t.a);
}
}
public static class B<T extends B<?>> extends A<T> {
private String b = "--B--";
public void copy(T t) {
super.copy(t);
System.out.println(t.b);
}
}
#Test
#SuppressWarnings("unchecked")
public void testCopy() {
Copyable b1 = new B();
Copyable b2 = new B();
b1.copy(b2);
}
}
Though the only way i've found to get rid of warnings is the annotation. And it feels like something is wrong.
So what's wrong? I can accept that something is wrong in the root of the problem. So any sort of clarification is welcome.
Your interface definition:
public interface Copyable<T extends Copyable<T>> {
void copy(T copyFrom);
}
Your implementation:
public class Example implements Copyable<Example> {
private Object data;
void copy(Example copyFrom) {
data = copyFrom.data;
}
//nontrivial stuff
}
That should take care of your warnings.
Assuming you don't want to subclass further you just need:
public static /*final*/ class AClass implements Copyable<AClass> {
For an abstract class, you do the "enum" thing:
public static abstract class AClass<T extends AClass<T>> implements Copyable<T> {
In testCopy, one of the warnings is because you're instantiating a "raw type" of Copyable rather than some concrete Copyable<T>. Once you instantiate a Copyable, it can only be applied to Ts (which include subtypes of T). In order to instantiate with a formal type, the class definitions will need to be changed slightly:
public static class A<T extends A> implements Copyable<T>
public static class B<T extends B> extends A<T>
The next issue is that a Copyable<B> can only be passed a compile-time type of B (based on the definition of Copyable). And testCopy() above is passing it a compile-time type of Copyable. Below are some examples of what will work, with brief descriptions:
public void testExamples()
{
// implementation of A that applies to A and subtypes
Copyable<A> aCopier = new A<A>();
// implementation of B that applies to B and subtypes
Copyable<B> bCopier = new B<B>();
// implementation of A that applies to B and subtypes
Copyable<B> bCopier2 = new A<B>();
}
I keep trying to figure out a way to get rid of the warnings in your first approach and I can't come up with anything that works. Even so, I think the first approach is the lesser of two evils. An unsafe cast is better than needing to give your classes such a complicated api.
A completely separate approach would be to override Object.clone() and implement Cloneable.
This is the best possible code of second approach. It compiles without any warnings.
import static org.junit.Assert.fail;
import org.junit.Test;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.runner.RunWith;
#RunWith(JUnit4ClassRunner.class)
public class TestGenerics {
public static interface Copyable<T> {
public void copy(T t);
}
public static class A<T extends A<T>> implements Copyable<T> {
private String a = "--A--";
public void copy(T t) {
System.out.println(t.a);
}
#SuppressWarnings("unchecked")
public static Copyable<Object> getInstance() {
return new A();
}
}
public static class B<T extends B<T>> extends A<T> {
private String b = "--B--";
public void copy(T t) {
super.copy(t);
System.out.println(t.b);
}
#SuppressWarnings("unchecked")
public static Copyable<Object> getInstance() {
return new B();
}
}
#Test
public void testCopy() {
Copyable<Object> b1 = B.getInstance();
Copyable<Object> b2 = B.getInstance();
Copyable<Object> a = A.getInstance();
b1.copy(b2); // this works as intended
try {
b1.copy(a); // this throws ClassCastException
fail();
} catch (ClassCastException cce) {
}
}
}
And also i figured out all that happens in this program with help of reflection:
for (Method method : A.class.getMethods()) {
if (method.getName().equals("copy")) {
System.out.println(method.toString());
}
}
for (Method method : B.class.getMethods()) {
if (method.getName().equals("copy")) {
System.out.println(method.toString());
}
}
Here is the output:
public void com.sbp.core.TestGenerics$A.copy(com.sbp.core.TestGenerics$A)
public void com.sbp.core.TestGenerics$A.copy(java.lang.Object)
public void com.sbp.core.TestGenerics$B.copy(com.sbp.core.TestGenerics$B)
public void com.sbp.core.TestGenerics$B.copy(com.sbp.core.TestGenerics$A)
public void com.sbp.core.TestGenerics$A.copy(java.lang.Object)
It means that:
The copy(...) methods in A and B make compiler generate "bridges" -
2 different methods for each, one with reifed argument type from
ancestor (reified T from Copyable becomes Object, reified "T extends
A" from A becomes A) and that is why it's override and not overload,
and the other one with reified argument type for defining class. First
method (with autogenerated body) downcasts its argument to call the
second (they call it a bridge). Because of this downcasting we get
ClassCastException in runtime if we call b1.copy(a).
It looks like direct type casting is cleaner and better tool for my
problem and generics are better used in their direct purpose - to
enforce compile time type checking.
I've learned Scala and now i know that the thing i wanted 2 years ago could have been achieved with contravariant type parameter and Scala's type system:
trait CopyableTo[-T] {
def copyTo(t: T)
}
class A(private var a: Int) extends CopyableTo[A] {
override def copyTo(t: A) {
println("A:copy")
t.a = this.a
}
}
class B(private var a: Int, private var b: Int) extends A(a) with CopyableTo[B] {
def copyTo(t: B) {
println("B:copy")
super.copyTo(t)
t.b = this.b
}
}
#Test
def zzz {
val b1 = new B(1, 2)
val a1 = new A(3)
val b2 = new B(4, 5)
b1.copyTo(a1)
a1.copyTo(b1)
b1.copyTo(b2)
}
Java type system is too weak for this.