问题
Is it possible to generically parameterize a method accepting EITHER ClassA OR InterfaceB ?
Does Not Compile Due to | Pseudocode
public <T extends Number | CharSequence> void orDoer(T someData){ // ... }
i.e. instead of writing multiple method signatures, I would like this one method to accept either a Number or CharSequence as an argument
Should Pass with a Number OR CharSequence argument
orDoer(new Integer(6));
int somePrimitive = 4;
orDoer(somePrimitive);
orDoer("a string of chars");
回答1:
If you really want to do that, you'll need to wrap youur accepted classes inside a custom class of your own. In your example case, probably something like:
public class OrDoerElement {
private final Number numberValue;
private final CharSequence charSequenceValue;
private OrDoerElement(Number number, CharSequence charSequence) {
this.numberValue = number;
this.charSequenceValue = charSequence;
}
public static OrDoerElement fromCharSequence(CharSequence value) {
return new OrDoerElement(null, value);
}
public static OrDoerElement fromNumber(Number value) {
return new OrDoerElement(value, null);
}
}
And your orDoer
method becomes:
public void orDoer(OrDoerElement someData) { .... }
Then you can build one of those and use in your method using either:
orDoer(OrDoerElement.fromCharSequence("a string of chars"));
orDoer(OrDoerElement.fromNumber(new Integer(6)));
But honestly, that sounds a bit too complex and too much work just to be able to call a method with different parameter types. Are you sure you can't achieve the same using two methods, and a third method for the common logic?
回答2:
Is using an anonymous abstract class an option for you? When I need type safe parameters or return types, I use some variant of the code below. That being said, I agree with the other comments here, and am curious what benefit you really derive when you're enforcing a type safety for a group of objects that don't have all that much in common.
public abstract class Doer<T> {
public void do(T obj) {
// do some stuff.
}
}
// calling method
new Doer<Number>(){}.do(new Integer(5));
回答3:
For the original question:
public void orDoer(Object someData){
assert someData instanceof Number || someData instanceof CharSequence;
// ...
}
In your more specific case, the assert
statement should just use introspection to clarify if the object has the specifics you want, i.e. check for a constructor from String, probe to create a new instance of the object from the toString()
result of the incoming object, and compare both for equality:
public void orDoer(Object someData) {
assert isUniconstructable(someData);
}
public static boolean isUniconstructable(Object object) {
try {
return object.equals(object.getClass().getConstructor(String.class)
.newInstance(object.toString()));
} catch (InstantiationException | IllegalAccessException | InvocationTargetException
| NoSuchMethodException| RuntimeException e) {
return false;
}
}
(Because of the exceptions that may be thrown, we need to wrap the assert test into its own function.)
Be aware that introspection may break due to Android’s ProGuard code compression which rewrites the class names, and instead of YourClass
just a Class, i.e. Q
, is stored in the database, and when you want to restore it with a later version of your app which has more classes, class Q
is something different then. See the ProGuard website for more information on this; I just wanted to notify that you should be aware of this when using introspection on Android.
来源:https://stackoverflow.com/questions/8330370/generic-or-instead-of-and-t-extends-number-charsequence