Question

I am trying to wrap my mind around something in java. When I pass an object to another class' method, can I not just call any methods inherent to that object class?

What is the reason code such as the example below does not compile?

Thank you,

class a {
  public static void myMethod(Object myObj) {
    myObj.testing();
  }
}


class b {
  public void testing() {
    System.out.println ("TESTING!!!");
  }
}


class c {  
  public static void main (String[] args) {
    b myB = new b();    
    a.myMethod(myB);  
  }
}

Edit: The reason I have left the parameter in myMethod as type Object, is because I would like to be able to pass in a variety of object types, each having a testing() method.

Was it helpful?

Solution

If you would like to pass in a variety of objects with testing() methods, have each object implement a Testable interface:

public interface Testable
{
   public void testing()
}

Then have myMethod() take a Testable.

public static void myMethod(Testable testable)
{
  testable.testing();
}

Edit: To clarify, implementing an interface means that the class is guaranteed to have the method, but the method can do whatever it wants. So I could have two classes whose testing() methods do different things.

public class AClass implements Testable
{
   public void testing()
   {
      System.out.println("Hello world");
   }
}

public class BClass implements Testable
{
   public void testing()
   {
      System.out.println("Hello underworld");
   }
}

OTHER TIPS

The problem is that myMethod can't know it's getting a b object until it actually runs. You could pass a String in, for all it knows.

Change it to

public static void myMethod(b myObj) {
  myObj.testing();
}

and it should work.


Update of the question:

Edit: The reason I have left the parameter in myMethod as type Object, is because I would like to be able to pass in a variety of object types, each having a testing() method.

As Amanda S and several others have said, this is a perfect case for an interface. The way to do this is to create an interface which defines the testing() method and change myMethod to take objects implementing that interface.

An alternative solution (without interfaces) would be to reflectively discover if the object has a testing() method and call it, but this is not recommended and not needed for a such a simple case.

What you are talking about is duck typing. Java doesn't have duck typing.

Therefore you need to define an interface that all the classes with a testing() method implement.

e.g:

public interface Testable
{
   public void testing()
}

class B implements Testable 
{
  public void testing() {
    System.out.println ("TESTING!!!");
  }
}

class A {
  public static void myMethod(Testable myObj) {
    myObj.testing();
  }
}

Your issue is a classic argument in favor of an interface. You want as generic as possible, yet you want every object you pass to have a testing() method. I suggest something along the lines of the following:

public interface Testable
{
  public void testing();
}

public class A
{
  public static void myMethod(Testable myObj)
  {    
    myObj.testing();
  }
}

public class B implements Testable
{
  public void testing()
  {
    System.out.println("This is class B");
  }
}

public class C implements Testable
{
  public void testing()
  {
    System.out.println("This is class C");
  }
}

public class Test
{  
  public static void main (String[] args) 
  {
    B myB = new B();
    C myC = new C();
    A.myMethod(myB); // "This is class B"
    A.myMethod(myC); // "This is class C" 
  }
}

Because you're passing in an Object (b inherit from Object). Object doesn't have testing, b does.

You can either pass in b or cast the object to b before calling the method.

EDIT To pass in a generic class that implements that method: you'll want to make an interface that has the method signature and pass in the interface type instead of Object. All objects that you pass in must implement the interface.

You can only access the members that are visible for the type of reference you have to the object.

In the case of myMethod(Object myObj) that means only the members defined in Object, so in class a the members of class b will not be visible.

If you changed the definition of a.myMethod to be public static void myMethod(b myObj) you would then be able to see the testing method on the instance of b while in myMethod.

update based on clarification:

In that case defining an interface for all of them to implement is likely what you want.

public interface Testable {
    public void testing();
}

public class a {
    public static void myMethod(Testable myObj) {
        myObj.testing();
    }
}

public class b implements Testable {
    public void testing () {
        System.out.println("TESTING!!!");
    }
}

Why can’t java find my method?

Because of the way Java was designed.

Java is "statically typed" that means objects types are checked during compilation.

In Java you can invoke a method only if that method belongs to that type.

Since this verification is made during compilation and the Object type does not have the "testing()" method, the compilation fails ( even though if at runtime the objects do have that method". This is primarily for safety.

The workaround as described by others will require you to create a new type, where you can tell the compiler

"Hey, the instances of this type will respond the the testing method"

If you want to pass a variety of objects and keep it very generic, one way is having those objects to implement and interface.

public interface Testable { 
    public void testing();
}

class A implements Testable { // here this class commits to respond to "testing" message 
    public void testing() {
    }
}

class B implements Testable { // B "is" testable 
    public void testing() { 
        System.out.println("Testing from b");
    } 
}


class C implements Testable { // C is... etc. 
    public void testing() { 
        //.... 
    }
}

Later somewhere else

public void doTest( Testable object ) { 
    object.testing();
}

doTest( new A() );
doTest( new B() );
doTest( new C() );

The "OTHER" way to do this, in java is invoking the methods reflectively, but I'm not sure if that's what you need, for the code is much more abstract when you do it that way, but that's how automated testing frameworks (and a lot of other frameworks such as Hibernate) do actually work.

I hope this help you to clarify the reason.

If you REALLY, REALLY want to keep the parameter as abstract as possible, you should consider reflection API. That way, you can pass whatever object you want and dynamically execute the method you want. You can take a look at some examples.

It's not the only way, but it might be a valid alternative depending on your problem.

Keep in mind that reflection is way slower than calling your methods directly. You might consider using an interface as well, such as the one on Amanda's post.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top