Reputation: 644
Let's say, I have two classes that look like this:
public class classA {
private Boolean is_started;
public classA(Boolean is_started) {
this.is_started = started;
}
public Boolean getIs_started(){
return this.is_started;
}
}
public class classB {
private String token;
public classA(String token) {
this.token = token;
}
public String get_token(){
return this.token;
}
}
I am calling those two classes from another class like this:
public class CallingClass {
public void function1() {
ClassA stepA = new ClassA(<some boolean>);
commonFunction(stepA);
}
public void function2() {
ClassB stepB = new ClassB(<some string>);
commonFunction(stepB);
}
public <T> void commonFunction(Class<T> dataObject) {
//An if statement that has a condition that only calls a function in classB {
String token = dataObject.get_token();
}
//An if statement that has a condition that only calls a function in classA {
Boolean is_started = dataObject.getIS_started();
}
//It returns error : The method [get_token()/getIS_started()] is undefined for the type Class<T>
I want to make sure that I can call different objects without specifying them in the function. For example, I want to supply ClassA
and ClassB
as an argument to the commonFunction
as in the example above. How do I make it happen with generics?
Upvotes: 0
Views: 74
Reputation: 31323
The direct answer to your literal question would be that the only supertype of classA
and classB
is Object
, so your parameter type must be Object
, and you can use instanceof
to test if it's an instance of a particular type, and if so, cast to that type to do stuff that can only be done with that type:
public void commonFunction(Object dataObject) {
if (dataObject instanceof classB) {
String token = ((classB)dataObject).get_token();
}
if (dataObject instanceof classA) {
Boolean is_started = ((classA)dataObject).getIS_started();
}
}
However, using instanceof
like this is evidence of bad design. If the logic for the two different types is separate, then why put them in the same function? If the "token" and "is_started" are supposed to represent the same kind of information, then refactoring them to the same method provided in an interface, like other answers suggested, makes more sense.
Upvotes: 1
Reputation: 609
It could be that there's something I'm missing about your question because it's not entirely clear what you are trying to achieve but something doesn't seem quite right about the way you're trying to do this.
You have logic in commonFunction
that behaves one way if the argument is one type and another way if the argument is the other type. It seems like what you really should do is have that logic inside ClassA and ClassB. So they should both implement some method that behaves one way inside ClassA and the other way inside ClassB. Then commonFunction
can treat all arguments the same.
In general, if you are testing the type of an argument and triggering different behaviour in different cases then it's a pretty good indication that the behaviour really belongs inside those classes themselves, provided you are the one defining the classes which you are in this case.
Upvotes: 0
Reputation: 347314
You need some way to tie the classes together which says "this instance implements a method called getToken
which returns some kind of result"
The simplest place to start would be a interface
, for example...
public interface Tokenable<T> {
public T getToken();
}
Then both ClassA
and ClassB
would need to implement this interface
as required, for example...
public class ClassA implements Tokenable<Boolean> {
private Boolean started;
public ClassA(Boolean started) {
this.started = started;
}
@Override
public Boolean getToken() {
return started;
}
}
public class ClassB implements Tokenable<String> {
private String token;
public ClassB(String token) {
this.token = token;
}
@Override
public String getToken() {
return token;
}
}
And then you can communalise the call back...
public class CallingClass {
public void function1() {
ClassA stepA = new ClassA(false);
commonFunction(stepA);
}
public void function2() {
ClassB stepB = new ClassB("hello");
commonFunction(stepB);
}
public <T> void commonFunction(Tokenable<T> dataObject) {
T token = dataObject.getToken();
}
}
Without providing some kind of common ancestor, you're not really going to be able to get it to work - Class
doesn't define a getToken
method, so you need some kind of common ancestor in order to call it (there is a "hacky" way to do it, but you really, really, really don't want to go down that rabbit hole)
Upvotes: 4