Suppose that I have interface MyInterface and 2 classes A, B which implement MyInterface.
I declared 2 objects: MyInterface a = new A() , and MyInterface b = new B().
When I try to pass to a function - function doSomething(A a){} I am getting an error.
This is my code:
public interface MyInterface {}
public class A implements MyInterface{}
public class B implements MyInterface{}
public class Tester {
public static void main(String[] args){
MyInterface a = new A();
MyInterface b = new B();
test(b);
}
public static void test(A a){
System.out.println("A");
}
public static void test(B b){
System.out.println("B");
}
}
My problem is that I am getting from some component interface which can be all sorts of classes and I need to write function for each class.
So one way is to get interface and to check which type is it. (instance of A)
I would like to know how others deal with this problem??
Thx
Can you not just have a method on the interface which each class implements? Or do you not have control of the interface?
This would provide both polymorphism and avoid the need to define any external methods. I believe this is the intention of an interface, it allows a client to treat all classes implementing it in a non type specific manner.
If you cannot add to the interface then you would be best introducing a second interface with the appropriate method. If you cannot edit either the interface or the classes then you need a method which has the interface as a parameter and then check for the concrete class. However this should be a last resort and rather subverts the use of the interface and ties the method to all the implementations.
It sounds like you are after something like this:
public static void test(MyInterface obj){
if(obj instanceof A) {
A tmp = (A)obj;
} else if(obj instanceof B) {
B tmp = (B)obj;
} else {
//handle error condition
}
}
But please note this is very bad form and indicates something has gone seriously wrong in your design. If you don't have control of the interface then, as suggested by marcj, adding a second interface might be the way to go. Note you can do this whilst preserving binary compatibility.
I'm unclear on what you're actually asking, but the problem is that you don't have a method that takes a parameter of type MyInterface. I don't know what the exact syntax is in Java, but you could do something like if (b is B) { test(b as B) } but I wouldn't. If you need it to be generic, then use the MyInterface type as the variable type, otherwise use B as the variable type. You're defeating the purpose of using the interface.
I'm not sure if I fully understand the issue, but it seems like one way might be to move the test() methods into the child classes:
public interface MyInterface {
public void test();
}
public class A implements MyInterface{
public void test() {
System.out.println("A");
}
}
public class B implements MyInterface{
public void test() {
System.out.println("B");
}
}
public class Tester {
public static void main(String[] args){
MyInterface a = new A();
MyInterface b = new B();
b.test();
}
}
You could similarly use a toString() method and print the result of that. I can't quite tell from the question, though, if your requirements make this impossible.
I think visitor design pattern will help you out here. The basic idea is to have your classes (A and B) call the appropriate method themselves instead of you trying to decide which method to call. Being a C# guy I hope my Java works:
public interface Visitable {
void accept(Tester tester)
}
public interface MyInterface implements Visitable {
}
public class A implements MyInterface{
public void accept(Tester tester){
tester.test(this);
}
}
public class B implements MyInterface{
public void accept(Tester tester){
tester.test(this);
}
}
public class Tester {
public static void main(String[] args){
MyInterface a = new A();
MyInterface b = new B();
a.accept(this);
b.accept(this);
}
public void test(A a){
System.out.println("A");
}
public void test(B b){
System.out.println("B");
}
}
Use only one public class/interface in one .java file, otherwise it'll throw error. And call the object with the object name.. You declared two methos in Teater class only, then what the purpose of declaring class A,B.
I usually use an abstract class to get around this problem, like so:
public abstract class Parent {}
public class A extends Parent {...}
public class B extends Parent {...}
That allows you to pass Parent objects to functions that take A or B.
You have 3 options:
Visitor pattern; you'll need to be able to change the MyInterface type to include a method visit(Visitor) where the Visitor class contains lots of methods for visiting each subclass.
Use if-else inside your method test(MyInterface) to check between them
Use chaining. That is, declare handlers ATester, BTester etc, all of which implement the interface ITester which has the method test(MyInterface). Then in the ATester, check that the type is equal to A before doing stuff. Then your main Tester class can have a chain of these testers and pass each MyInterface instance down the chain, until it reaches an ITester which can handle it. This is basically turning the if-else block from 2 into separate classes.
Personally I would go for 2 in most situations. Java lacks true object-orientation. Deal with it! Coming up with various ways around it usually just makes for difficult-to-follow code.
Sounds like you need either a) to leverage polymorphism by putting method on MyInterface and implementing in A and B or b) some combination of Composite and Visitor design pattern. I'd start with a) and head towards b) when things get unwieldy.
My extensive thoughts on Visitor:
http://tech.puredanger.com/2007/07/16/visitor/
public interface MyInterface {}
public class A implements MyInterface{}
public class B implements MyInterface{}
public class Tester {
public static void main(String[] args){
MyInterface a = new A();
MyInterface b = new B();
test(b); // this is wrong
}
public static void test(A a){
System.out.println("A");
}
public static void test(B b){
System.out.println("B");
}
}
You are trying to pass an object referenced by MyInterface reference variable to a method defined with an argument with its sub type like test(B b). Compiler complains here because the MyInterface reference variable can reference any object which is a sub type of MyInterface, but not necessarily an object of B.There can be runtime errors if this is allowed in Java. Take an example which will make the concept clearer for you. I have modified your code for class B and added a method.
public class B implements MyInterface {
public void onlyBCanInvokeThis() {}
}
Now just alter the test(B b) method like below :
public static void test(B b){
b.onlyBCanInvokeThis();
System.out.println("B");
}
This code will blow up at runtime if allowed by compiler:
MyInterface a = new A();
// since a is of type A. invoking onlyBCanInvokeThis()
// inside test() method on a will throw exception.
test(a);
To prevent this, compiler disallows such method invocation techniques with super class reference.
I'm not sure what are you trying to achieve but it seems like you want to achieve runtime polymorphism. To achieve that you need to declare a method in your MyInterface and implement it in each of the subclass. This way the call to the method will be resolved at run time based on the object type and not on the reference type.
public interface MyInterface {
public void test();
}
public class A implements MyInterface{
public void test() {
System.out.println("A");
}
}
public class B implements MyInterface{
public void test() {
System.out.println("B");
}
}
public class Tester {
public static void main(String[] args){
MyInterface a = new A();
MyInterface b = new B();
b.test(); // calls B's implementation of test()
}
}
Related
I try myself with design-patterns & -principles and have a question.
Before, sorry for the bad coding-style habit !!
I have an interface like ITest in this case:
public interface ITest
{
public void method1();
}
and then implement the methods and fields, if any, into a concrete class B like this:
public class B implements ITest
{
//This is the method from the interface
#Override
public void method1()
{
System.out.println("method1");
}
//This is another method in class B
public void method2()
{
System.out.println("method2");
}
}
Now in the application code I put it in like this:
public class Main
{
public static void main(final String args[]) throws Exception
{
//One principle says:
//programm to an interface instead to an implementation
ITest test = new B();
//method from interface
test.method1();
//this method is not accessible because not part of ITest
test.method2(); //compile-time error
}
}
You see that method2() from class B is not available because to the interface of ITest.
Now, what if I need this 'important' method?
There are several possibilities. I could abstract it in the interface or make class B abstract and extend into another class and so on, or make the reference in the main() method like:
B test = new B();
But this would violate the principle.
So, I modified the interface to:
public interface ITest
{
//A method to return the class-type B
public B hook();
public void method1();
}
And put in class B the implementation:
public class B implements ITest
{
//this returns the object reference of itself
#Override
public B hook()
{
return this;
}
//This is the method from the interface
#Override
public void method1()
{
System.out.println("method1");
}
//This is the 'important' method in class B
public void method2()
{
System.out.println("method2");
}
}
Now in my main()-method I can call both methods with a little hook or chaining mechanism without referencing a new object nor does it violate the design-principle and I don't need an extra class for extension or abstraction.
public class Main
{
public static void main(final String args[])
{
//programm to an interface instead into an implemintation
ITest test = new B();
//method from interface
test.method1();
//method2 will not be accessible from ITest so we referencing B through a method hook()
//benefits: we don't need to create extra objects nor additional classes but only referencing
test.hook().method2();
System.out.println("Are they both equal: "+test.equals(test.hook()));
}
}
Also, I can encapsulate, inherit and abstract other methods, fields etc.
This means, that I can create more complex and flexible hierarchies.
My question now:
Is this a kind of anti-pattern, bad design-principle or could we benefit from this?
Thank you for watching. :-)
Is this a kind of anti-pattern, bad design-principle or could we
benefit from this?
Yes, it is a bad pattern.
The problem stems from the fact that you have tightly coupled ITest to B. Say I want to create a new implementation of ITest - let's call it C.
public class C implements ITest
{
#Override
public B hook()
{
// How do I implement this?
}
#Override
public void method1()
{
System.out.println("method1");
}
}
There's no sane way we can implement this method. The only reasonable thing to do is to return null. Doing so would force any users of our interface to constantly perform defensive null checks.
If they're going to have to check every time before using the result of the method, they might as well just do an instanceof and cast to B. So what value are you adding? You're just making the interface less coherent and more confusing.
Adding a method returning B to interface ITest implemented by B is definitely an awful design choice, because it forces other classes implementing ITest return B, for example
public class C implements ITest {
#Override
public B hook()
{
return // What do I return here? C is not a B
}
...
}
Your first choice is better:
B test1 = new B();
C test2 = new C();
The following context is needed: The purpose of this way of coding is to avoid if-else statements and instanceof; which is always a bad idea.
I have 3 classes with the following signatures:
abstract class A {}
class B extends A {}
class C extends A {}
Then I have another class with the following structure:
class MyClass {
private final A model;
public MyClass(A m) {
this.model = m;
}
public void doSomething() {
System.out.println(this.model instanceof C); //TRUE!!
execute(this.model);
}
private void execute(A m) {
System.out.println("noo");
}
private void execute(C m) {
System.out.println("yay");
}
}
And finally the contents of my main:
public static void main(String... args) {
C mod = new C();
MyClass myClass = new MyClass(mod);
myClass.doSomething();
}
Now the problem; the execute(C) method never gets executed, it's always the execute(A) method. How can I solve this? I cannot change the signature of the execute(A) method to execute(B) since that would give an error saying java "cannot resolve method execute(A)" at MyClass#doSomething.
Method overloads are resolved at compile time. At compile time, the type of m is A, so execute(A m) gets executed.
In addition, private methods are not overridable.
The solution is to use the Visitor pattern as suggested by #OliverCharlesworth.
Your code illustrates the difference between a static and a dynamic type of an object. Static type is what's known to the compiler; dynamic type is what's actually there at runtime.
The static type of your model field is A:
private final A model;
That is, the compiler knows that A itself or some of its implementations is going to be assigned to model. The compiler does not know anything else, so when it comes to choosing between execute(A m) and execute(C m) its only choice is execute(A m). The method is resolved on the static type of the object.
instanceof, on the other hand, understands the dynamic type. It can tell that the model is set to C, hence reporting the true in your printout.
You can solve it by adding a method to A and overriding it in B and C to route to the proper execute:
abstract class A {
public abstract void callExecute(MyClass back);
}
class B extends A {
public void callExecute(MyClass back) {
back.execute(this);
}
}
class C extends A {
public void callExecute(MyClass back) {
back.execute(this);
}
}
class MyClass {
private final A model;
public MyClass(A m) {
this.model = m;
}
public void doSomething() {
System.out.println(this.model instanceof C); //TRUE!!
model.callExecute(this.model);
}
public void execute(B m) {
System.out.println("noo");
}
public void execute(C m) {
System.out.println("yay");
}
}
Note that both implementations call
back.execute(this);
However, the implementation inside B has this of type B, and the implementation inside C has this of type C, so the calls are routed to different overloads of the execute method of MyClass.
I cannot change the signature of the execute(A) method to execute(B)
Also note that now you can (and should) do that, too, because callbacks are performed to the correct overload based on type of this.
Method overloading is a compile time polymorphism. Thus, for calling method execute(C) you need to define your model as class C.
It's better to define method execute() in class A and override it in subclasses.
abstract class A {
abstract void execute();
}
class B extends A {
public void execute(){};
}
class C extends A {
public void execute(){};
}
And then:
class MyClass {
private final A model;
public void doSomething() {
model.execute();
}
This much better way to use polymorphism to avoid if-else statements and instanceof checking
You are sending object of type C as an object of type A in constructor( you've done upcasting) and assigning it to a reference to type A(which will result in calling only execute(A) method).You could check if the object is a instance of C and depending on the outcome, call the desired method. You could do it like this
public void doSomething(){
System.out.println(model instanceof C);
if (model instanceof C) execute((C)model);
else
execute(model);
}
So, I want to be able to get an instance of a subclass that is being run when it calls a method from the super class. For example, if I had this class:
public class A {
public void aMethod() {
//Here is where I want to see if class B is calling the code
}
}
public class B extends A {
}
public class C {
B b = new B();
b.aMethod();
}
And, like the comment says, I want to check, in aMethod, if class B, the subclass of class A, is calling the code.
As has been pointed out to you, there is almost never a good reason to do this and I agree that you should be using polymorphism instead. However, if you "need" to do this or just want to know how to go about doing something like this, you can use instanceof on this inside of the method:
class A {
public void aMethod() {
if (this instanceof B) {
System.out.println("I'm a B!");
}
}
}
public class B extends A {
public static void main(String[] args) {
B b = new B();
b.aMethod();
}
}
public class A {
public void aMethod() {
if(this.getClass() == B.class){
System.out.println("huhuhuuuuuuuuuuuuuuuuu");
}
}
}
public class B extends A {
}
public class C {
public static void main(String[] args) {
B b = new B();
b.aMethod();
}
}
Check here: How to get the caller class in Java
The 2nd part of the answer from #dystroy is probably a start.
Note that this finds a call at any depth:
for(final StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getClassName().equals(B.class.getName())) {
System.out.println("BINGO");
}
}
If you want to check only a limited depth, don't iterate through all of the array.
This can be useful e.g. if some framework forces you to have a special method or a no-arg constructor to be present, but you don't want any developer to call this method directly. (Yes, it is a hack, but sometimes odd frameworks force you to do odd things). Then you can have an assertion in the unwanted method that just throws an exception if it is called by the wrong corner of your code.
Anyway you should try do avoid things like this if possible.
I have the following scenario in Java. Let's say I have an interface, and two classes that implement this interface. As follows:
public interface myInterface {
public String printStuff();
}
public class A implements myInterface {
#Override
public String printStuff(){
return "Stuff";
}
}
public class B implements myInterface {
#Override
public String printStuff(){
return "Stuff";
}
public String printOtherStuff(){
return "Other Stuff";
}
}
How do I call the printOtherStuff method above if I define it as follows:
public static void main(String... args) {
myInterface myinterface = new B();
String str = myinterface.printOtherStuff(); // ? This does not work
}
The above calling code does not seem work. Any ideas?
myInterface myinterface = new B();
The reference type of myinterface is myInterface. That means you can only access the methods defined in the interface. You can cast it to type B in order to make the method call.
NOTE: From here on out I'll be using the proper naming conventions.
Example
MyInterface myInterface = new B();
String str = ((B)myInterface).printOtherStuff();
Just a note on this
If you need to do this, then you need to have a look at your class design. The idea of using an interface in this way is to abstract away from the details of the object's concrete implementation. If you're having to perform an explicit cast like this, then you might want to look into either changing your interface to accommodate the necessary methods, or change your class so that the method is moved into a global location (like a util file or something).
Extra Reading
You should read about reference types here, and you should have a look at casting here. My answer is a combination of the understanding of both of these things.
As an added note, take a look at the Java Naming Conventions. This is a vital piece of information for any Java developer to make understandable code.
Surely this wouldn't work because you have reference type of Interface MyInterface. At the time of method binding compiler would try to find this method in your Interface MyInterface which is not available. So you need to cast it to your class like this.
MyInterface myInterface = new B();
B newB=(B) myInterface ;//casting to class
newB.printOtherStuff();// would work fine
change myInterface
public interface myInterface {
public String printStuff();
public String printOtherStuff();
}
If you cant change myInterface, then extends myInterface
public interface myOtherInterface extends myInterface {
public String printOtherStuff();
}
Then Implements myOtherInterface
public class B implements myOtherInterface {
#Override
public String printStuff(){
return "Stuff";
}
#Override
public String printOtherStuff(){
return "Other Stuff";
}
}
public static void main(String... args) {
myOtherInterface myotherinterface = new B();
String str = myotherinterface.printOtherStuff();
}
In Python, class methods can be inherited. e.g.
>>> class A:
... #classmethod
... def main(cls):
... return cls()
...
>>> class B(A): pass
...
>>> b=B.main()
>>> b
<__main__.B instance at 0x00A6FA58>
How would you do the equivalent in Java? I currently have:
public class A{
public void show(){
System.out.println("A");
}
public void run(){
show();
}
public static void main( String[] arg ) {
new A().run();
}
}
public class B extends A{
#Override
public void show(){
System.out.println("B");
}
}
I'd like to call B.main() and have it print "B", but clearly it will print "A" instead, since "new A()" is hardcoded.
How would you change "new A()" so that it's parameterized to use the class it's in when called, and not the hard-coded class A?
Static methods in java are not classmethods they are staticmethods. In general it is not possible to know which class reference the static method was called from.
Your class B does not have a main method and static methods are not inherited.
The only way I can see this happening is to find whatever is calling A.main( String[] arg ) and change it to call B.main instead.
B.main:
public static void main( String[] arg ) {
new B().run();
}
How is your program started? Is there a batch file, shortcut, etc? Something you can change? Where does A.main get called?
I think this isn't possible. Here's why:
In Java, the implementation of a method is determined by the instance's run-time type. So, to execute B.show(), you need to have an instance of B. The only way I could see to do this, if the method that constructs the instance is supposed to be inherited, is to use Class.newInstance() to construct an instance of a type that's not known at runtime.
The problem with that is that within a static method, you have no reference to the containing class, so you don't know whose newInstance method to call.
Why do you want to do this, though? There may be some better way to achieve whatever it is you want to achieve.
In your example I wouldn't put your main method inside of A. This is setup as the entry point into the system (you can't be in B if you are specifically entering into A).
In the example below I created class A, B, and C. Class C instantiates A and B and runs them. Notice that in C I created an A, a B, and another A that I instantiate as a B. My output is:
A
B
B
Hopefully this makes sense.
public class A {
public void show(){
System.out.println("A");
}
public void run(){
show();
}
}
public class B extends A {
#Override
public void show(){
System.out.println("B");
}
}
public class C {
public static void main(String[] args) {
A a = new A();
B b = new B();
A anothera = new B();
a.show();
b.show();
anothera.show();
}
}