Lets look at the following example:
public class BothPaintAndPrintable implements Paintable,Printable{
public void print() {}
public void paint() {}
}
public interface Paintable {
public void paint();
}
public interface Printable {
public void print();
}
public class ITest {
ArrayList<Printable> printables = new ArrayList<Printable>();
ArrayList<Paintable> paintables = new ArrayList<Paintable>();
public void add(Paintable p) {
paintables.add(p);
}
public void add(Printable p) {
printables.add(p);
}
public static void main(String[] args) {
BothPaintAndPrintable a= new BothPaintAndPrintable();
ITest t=new ITest();
t.add(a);//compiliation error here
}
}
What if I want BothPaintAndPrintable instances to be added to each of the ArrayLists?
One way would be overloading the method with a BothPaintAndPrintable parameter, but I'm trying to see alternatives since doing that might reduce code reuseability. Does anyone have another idea?
You need a third overload:
public <T extends Object&Paintable&Printable> void add(T t) {
paintables.add(t);
printables.add(t);
}
This makes the erasure add(Object), so it doesn't conflict with the other methods, but it does restrict the input to implementors of both Paintable and Printable.
(Guava had to use this trick for Joiner with Iterator and Iterable, because some evil classes out there implemented both, even though it's a terrible idea.)
I would go with a general add(Object o) method, then checking for instanceof, and putting the Object into the according lists.
If the passed Object implements neither interface, throwing an InvalidArgumentException might be a good idea.
Not sure about the best answer as I can't find a way I actually like!
You could use generics, but I don't like either the "instanceof" tests, nor the casts required:
import java.util.ArrayList;
class BothPaintAndPrintable implements Paintable, Printable {
public void print() {
}
public void paint() {
}
}
interface Paintable {
public void paint();
}
interface Printable {
public void print();
}
public class ITest<T> {
ArrayList<Printable> printables = new ArrayList<Printable>();
ArrayList<Paintable> paintables = new ArrayList<Paintable>();
public void add(T p) {
if (p instanceof Paintable) {
paintables.add((Paintable) p);
}
if (p instanceof Printable) {
printables.add((Printable) p);
}
}
public static void main(String[] args) {
BothPaintAndPrintable a = new BothPaintAndPrintable();
ITest<BothPaintAndPrintable> t = new ITest<BothPaintAndPrintable>();
t.add(a);
}
}
Okay I do like the correct answer; however, there is another solution I should point out to the OP.
public static void main(String[] args) {
BothPaintAndPrintable a= new BothPaintAndPrintable();
ITest t=new ITest();
t.add((Paintable)a);
t.add((Printable)a);
}
This works without adding the third member, and even works if you decide to add more interfaces down the road.
Related
I want to have a class to run other classes in java, like constructor parameterized with a class to run that class later on, similar to this
class MyClass{
Class classToRun;
public MyClass(Class c) {
super();
this.classToRun = c;
}
public void runClass(){
classToRun.someStaticMethod();
}
}
where classToRun possible classes doesn't have a common ancestor, but all have method someStaticMethod, and have no idea about MyClass, which runs them.
But there are problems, like inner classes cannot have static methods, classes cannot be cast Class, etc.
There are solutions for parameterized with class methods, like
How do I pass a class as a parameter in Java?
Passing a class as an argument to a method in java
but not for constructors.
What is the proper solution to do this?
Use lambdas and pass the method reference: they match on the method signature. For void someStaticMethod() you can use Runnable.
class MyClass{
private final Runnable methodToRun;
public MyClass(Runnable someStaticMethod) {
methodToRun = someStaticMethod;
}
public void runClass(){
methodToRun.run();
}
}
new MyClass(SomeClass::someStaticMethod).runClass();
You cannot enforce that the method passed has the right name, but looks even neater IMHO.
You need to understand what generics are.
interface
public interface SomeInterface {
void someStaticMethod();
}
use
class MyClass<T extends SomeInterface>{
T classToRun;
public MyClass(T c) {
super();
this.classToRun = c;
}
public void runClass(){
classToRun.someStaticMethod();
}
}
As 2 of 3 answers were not to the point, I decided to publish fixed versions of both answers as far as they can be fixed.
The f1sh version from the above should like follows:
public class ClassToRunOthers {
Class classToRun;
public ClassToRunOthers(Class c) {
this.classToRun = c;
}
public void runClass() throws Exception {
Optional<Method> method = Arrays.stream(classToRun.getDeclaredMethods()).filter(m -> m.getName().equals("someStaticMethod")).findFirst();
if(!method.isPresent()) {
throw new RuntimeException();
}
method.get().invoke(null);
}
public static void main(String[] args) throws Exception {
ClassToRunOthers mc = new ClassToRunOthers(SomeClass.class);
mc.runClass();
}
}
class SomeClass {
static void someStaticMethod() {
System.out.println("test");
}
}
The zwei solution above can not be fixed without reflection, as generics is not to the point. Evan if you try to parametrize not with SomeInerface (because SomeClass does not extend a common SomeInterface), but with Object, it is still won't solve the problem:
public class MyClass<T extends Object> {
T classToRun;
public MyClass(T c) {
super();
this.classToRun = c;
}
public void runClass() {
// classToRun.someStaticMethod(); // Cannot resolve method 'someStaticMethod' in 'T'
}
public static void main(String[] args) {
MyClass mc = new MyClass(SomeClass.class);
}
}
class SomeClass {
static void someStaticMethod() {
System.out.println("test");
}
}
This can be fixed like the above, via reflection.
I believe, it can be done with annotations in some elegant way, and may be someone will share us with such a solution or I will do it by myself as time permits.
By now for myself, a solution with saving class name in the String in constructor next day after the question been asked did the trick.
You will have to use reflection if you want to execute a method when you only have the Class instance.
In the code below, runClass finds the method of the class using it's name as a String, then executes it. This code assumes that the method is static, also ignoring any Exception handling.
The following code prints "test":
class MyClass {
Class classToRun;
public MyClass(Class c) {
this.classToRun = c;
}
public void runClass() throws Exception {
Optional<Method> method = Arrays.stream(classToRun.getDeclaredMethods()).filter(m -> m.getName().equals("someStaticMethod")).findFirst();
if(!method.isPresent()) {
throw new RuntimeException();
}
method.get().invoke(null);
}
}
class Main {
public static void main(String[] args) throws Exception {
MyClass mc = new MyClass(Main.class);
mc.runClass();
}
static void someStaticMethod() {
System.out.println("test");
}
}
In java, I'd like to do something like this
public class Tata{
public static void f(){
//something
}
public static void g(){
//something
}
}
public class Titi{
public static void f(){
//something
}
public static void g(){
//something
}
}
public class Toto{
private Class c = Tata.class; //or Titi.class
public static void main(String[] args) {
c.f();
c.g();
}
}
To be precise, I'd like to be able to freely switch between classes Tata and Titi, to use their respective methods f or g.
This doesn't work as intended, as I get the cannot resolve method 'f()' error. Simply replacing c.f(); and c.g(); with Tata.f(); and Tata.g(); works fine, but defeats the purpose of using a parameter. How to solve this?
Will turn the comment into answer after all.. The correct (Java) way to deal with what you want is the use of interface. So in your demo code the implementation would be the following:
public interface TheFGFunctions {
void f();
void g();
}
public class Tata implements TheFGFunctions {
#Override
public void f() {
//something
}
#Override
public void g() {
//something
}
}
public class Titi implements TheFGFunctions {
#Override
public void f() {
//something
}
#Override
public void g() {
//something
}
}
public class Toto {
private TheFGFunctions c;
public Toto(TheFGFunctions c) {
this.c = c;
}
public void notStaticFunction() {
c.f();
c.g();
}
}
This way is totally typesafe with zero exceptions to deal with!
You cannot access a static method polymorphically. The Java language doesn't support it.
The reason your current approach fails is that c is an instance of the class Class, and the class Class doesn't define methods f() or g().
(The methods that it does define are listed in the javadoc for Class. Note that Class is final so you can't create a custom subclass with extra methods.)
The simple alternative is to use reflection; e.g.
Class c =
Method f = c.getMethod("f");
f.invoke(null); // because it is static
But note:
This is not statically type-safe. The compiler cannot tell when you make the mistake of trying to use a static f() on a class that doesn't have such a method.
There are a few exceptions that you need to deal with; e.g. missing methods, incorrect signatures, methods that are not static, methods that don't have the correct access.
Other answers have proposed creating an interface and wrapper classes to make certain static methods dispatchable. It will work and it will be compile-time type-safe (!) but there is a lot of boiler plate code to write.
#Michael Michailidis commented:
Thus interfaces!
Yea ... kind of. You can only dispatch polymorphically on instance methods declared on an interface. That implies that you must have an instance of Tata or Titi, and call the methods on it. My reading of the Question is that the author wants to avoid that.
(IMO, the avoidance is the real problem. You are better of not trying to avoid instance methods.)
FWIW, you can declare static methods in an interface (since Java 8), but they would behave the same as if you declared them in a class. You wouldn't be able to dispatch ...
You could use reflections:
private Class c = Tata.class;
public Toto() throws Exception {
c.getMethod("f").invoke(null);
c.getMethod("g").invoke(null);
}
Here my Tata class
public class Tata {
public static void f() {
System.out.println("ffff");
}
public static void g() {
System.out.println("gggg");
}
}
Output on new Toto() call:
ffff
gggg
Update (call with parameters):
public Toto() throws Exception {
c.getMethod("f", String.class).invoke(null, "paramValue1");
c.getMethod("g", String.class).invoke(null, "paramValue2");
}
public class Tata {
public static void f(String param1) {
System.out.println("ffff " + param1);
}
public static void g(String param2) {
System.out.println("gggg " + param2);
}
}
Output:
ffff paramValue1
gggg paramValue2
Write a wrapper interface
interface CWrapper {
void f();
void g();
}
and wrapper class factory method for each Class containing the methods
class CWrappers {
CWrapper forTiti(Class<Titi> titiClass) {
return new CWrapper() {
void f() { Titi.f(); }
void g() { Titi.g(); }
}
}
// another factory method for Tata
}
Then you can use that:
public class Toto {
private CWrapper c = CWrappers.forTata(Tata.class); //or forTiti(Titi.class)
public static void main(String[] args) {
c.f();
c.g();
}
}
interface Y {
void search(String name);
}
class A implements Y {
void search(String name) {
//Is it possible to say: "If I was called from class B then do a search("B");
}
}
class B extends A {
}
public class Main {
public static void main(String[] args) {
B b = new B();
b.search();
}
}
Given the above code is it possible to reason in superclass which subclass was used for calling a method?
The reason I want to do this is because the code in Search is very similar for all Subclasses, the only thing that changes is the Classname, so I thought there is no need to Override in each subclass. I have updated the code to reflect this. Please let me know if there is a better way of doing it/
Calling this.getClass() inside your search method will give you the concrete class of the current instance.
For example:
class Example
{
static class A {
public void search() {
System.out.println(getClass());
}
}
static class B extends A {}
public static void main (String[] args) throws java.lang.Exception
{
new A().search();
new B().search();
}
}
outputs
class Example$A
class Example$B
The cleanest way to do it is to override the method in each subclass.
interface Y {
void search();
}
class A implements Y {
public void search(){
search("A");
}
protected void search(String name) {
// implement your searching algoithm here
}
}
class B extends A {
public void search(){
search("B");
}
}
public class Main {
public static void main(String[] args) {
B b = new B();
b.search();
}
}
That's the way inheritance is suppose to works. A super class should not know its subclasses.
And, in case you extends your class B, you can easily either:
-Keep the same behaviour as B:
class C extends B {
// do nothing, when calling search, it calls the method implemented in B
}
-Change the behaviour to search for "C"
class C extends B {
public void search(){
search("C"); // or search("whateveryouwant")
}
}
You can simply override the method in class B.
The other way could be to write the search() method as
void search() {
if (this.getClass().equals(B.class)) {
//The logic for B
} else if (this.getClass().equals(A.class)) {
//The logic for A
}
}
You have to provide the fully qualified name for the class.
Better follow template pattern.
interface Y {
void search(String name);
}
abstract class AbstractionTemplate implements Y{
#Override
public void search(String name) {
//a lot of code.
System.out.println("common stuff start");
doImplspecificStuffOnly();
System.out.println("common stuff end");
//a lot of code.
}
abstract void doImplspecificStuffOnly();
}
class A extends AbstractionTemplate{
#Override
void doImplspecificStuffOnly() {
System.out.println("a's stuff");
}
}
class B extends A {
#Override
void doImplspecificStuffOnly() {
System.out.println("B's stuff");
}
}
public class Main {
public static void main(String[] args) {
B b = new B();
b.search("hey");
}
}
Assuming the following situation:
public interface A {
void a1();
void a2();
}
public interface B {
void b1(A a);
}
public class ImplA implements A {
// interface methods
void a1() {};
void a2() {};
// ImplA specific methods
void a3() {};
}
public class ImplB implements B {
void b1(A a) {
if(a instaceof ImplA) { // avoid instanceof test and cast
((ImplA)a).a3();
}
}
}
Would it be possible by some architectural voodoo to avoid an instanceof check in ImplB.b1()? ImplA and ImplB are in the same package and closely related to each other. I read somewhere, that the use of instanceof is a hint for a "no-so-good" interface design. Any recommendations? Thanks alot!
You could use a Visitor pattern to avoid the instanceof cast
public interface Visitor {
void visitImplA(ImplA toVisit);
}
public class VisitorImpl implements Visitor {
#Override
public void visitImplA(ImplA toVisit) {
toVisit.a3();
}
}
public interface A {
void a1();
void a2();
void accept(Visitor visitor);
}
public interface B {
void b1(A a);
}
public class ImplA implements A {
// interface methods
void a1() {};
void a2() {};
// ImplA specific methods
void a3() {};
void accept(Visitor visitor) {
visitor.visitImplA(this);
}
}
public class ImplB implements B {
void b1(A a) {
a.accept(new VisitorImpl());
}
}
This would eliminate all you instanceof checks and divide them into the visitor and the implementing classes, this pattern would suffice in the case where you'd be doing the same stuff after most of the instanceof checks, otherwise you'd need a lot of implementations of the Visitor interface
The VooDoo you want is composition. You can solve that using Visitor dessign pattern. But ther is some penalty when you are using it. Or you can create onther interface that will be used to invoke that a3 method.
The case varry. The reason of question might be that your architecture is not consist and you trying to do something strange or your class perform to many things.
I'm using some Java code which produces the following interfaces. This code is non-modifiable.
interface A1 {
public void run();
}
interface A2 {
public void run();
}
...
interface A24 {
public void run();
}
I'm having a class cast error with the following code. How would I dynamically build an adapter to my interface?
interface ARunnable {
public void run();
}
public void someMethod() {
// getARunnables() returns a list of A1, A2, ... A24
List<ARunnable> runnables = (List<ARunnable>)getARunnables();
for (ARunnable a : runnables) {
a.run();
}
}
Since the interfaces can't be modified to extend java.lang.Runnable, an option would be to use java.lang.reflect.Proxy to build up instances of Runnable that delegate to your A1, A2... interfaces.
It's not trivial, but take a look at this example using java.lang.reflect.Proxy. The sample simply delegates to a delegate object based on method name.
public class ProxyTest
{
public static void main(String... args)
{
List<?> instances = Arrays.asList(new A1());
List<ARunnable> runnableInstances = new ArrayList<ARunnable>(instances.size());
for (Object instance : instances)
{
ARunnable runnableInstance = (ARunnable)Proxy.newProxyInstance(
ARunnable.class.getClassLoader(),
new Class<?>[] {ARunnable.class},
new RunnableWrapper(instance));
runnableInstances.add(runnableInstance);
}
//Now we have a list of ARunnables!
//Use them for something
for (ARunnable runnableInstance : runnableInstances)
{
runnableInstance.run();
}
}
private static class RunnableWrapper implements InvocationHandler
{
private final Object instance;
public RunnableWrapper(Object instance)
{
this.instance = instance;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
//Ensure that your methods match exactly or you'll get NoSuchMethodExceptions here
Method delegateMethod = instance.getClass().getMethod(method.getName(), method.getParameterTypes());
return(delegateMethod.invoke(instance, args));
}
}
public static class A1
{
public void run()
{
System.out.println("Something");
}
}
public static interface ARunnable
{
public void run();
}
}
Also I would recommend you fix the line
List<ARunnable> runnables = (List<ARunnable>)getARunnables();
That type safety warning you should not ignore. That list of objects does not actually contain ARunnables, hence the ClassCastException.
Consider this sample code (doesn't have the loop for simplicity):
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
interface Interface {
public void run();
}
static class Hello /* does't implement Interface */{
public void run() {
System.out.println("Hello, world!!");
}
}
static <T> T dirtyCast(Class<T> intrface, final Object target) {
return intrface.cast(Proxy.newProxyInstance(
intrface.getClassLoader(),
new Class<?>[] { intrface }, new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
Method targetMethod = target.getClass().getMethod(
method.getName(), method.getParameterTypes());
return targetMethod.invoke(target, args);
}
}));
}
public static void main(String[] args) {
Interface proxy = dirtyCast(Interface.class, new Hello());
proxy.run();
}
}
Please don't consider this solution as feasible if you want to pass arguments or return values or throw exceptions. The problem is that the shared objects (as arguments and return values and exceptions) need to live in the same (common) classloader. This also means that usual java lang types and exceptions will be okay.
Also you have to bear in mind security considerations. Classloaders may have different (incompatible) security constraints.
If you run quickly into trouble, I would try a project designed for this like transloader.
Have fun.
In your case you can use simply
public void someMethod() throws ReflectiveOperationException {
// getARunnables() returns a list of A1, A2, ... A24
List runnables = (List)getARunnables();
for (Object r : runnables) {
r.getClass().getMethod("run").invoke(r);
}
}