In Java 8, can an interface default method access instance variables?
Asked Answered
F

4

9

TL;TD In Java 8, is there a way for an interface default method to access instance variables?

For instance:

public interface Foo{
    default getBazModified(){
       return baz * 2; 
    }
}

public class Bar implements Foo {
   int baz;
   ...
}

I know that sounds like travisty but is there a way to do anything like that in Java 8?

Or is the only way is to have an abstract class that implements Foo, which would have both the instance variable baz declared and have a default implementation of getBazModified()?

Female answered 7/2, 2019 at 16:37 Comment(4)
sounds like a use case for method arguments to be implementedNagey
nullpointer, could you please elaborate?Female
i mean a method argument like in default int getBazModified(int baz){ return baz * 2; }, what's the challenge there? since anyway you call an instance method which would have its own baz value that it can pass on the invocation of this method.Nagey
Possibly related #29667176Nagey
C
17

An interface doesn't "see" its implementation's instance fields. This is not specific to interfaces, any super-type wouldn't know about its sub-types' specific fields (or any member type for that matter).

Your solution in this case is to declare an abstract getter method in the interface and use it to read the property of the subclass:

public interface Foo{
    default int getBazModified(){
       return this.getBaz() * 2; 
    }

    int getBaz();
}

And let the concrete class implement the getter:

public class Bar implements Foo {
   int baz;
   public int getBaz() {return this.baz;}
}
Conifer answered 7/2, 2019 at 16:40 Comment(2)
and all that said, there has to be some return type (int here) specified for the methodsNagey
I've been trying to get a model right and this concrete implementation for the getter whilst declaring it in the interface is perfect. 10000%Toliver
K
3

No. Because variables used inside a default method of an interface have access only to the variables defined inside the interface.

public interface Foo {
int BAZ=1;

default int getBazModified(){
    return BAZ * 2;
  }
}

Remember variables defined inside an interface are public,static and final and they must be initialized.

Now,

public class Bar implements Foo {
  int BAZ = 10;
}

within calling class..

 Foo foo = new Bar();
 System.out.print(foo.getBazModified()); // output: 2

You can only access instance variable inside "Bar" class by overriding default method. Like so,

public class Bar implements Foo {

  int BAZ = 10;

  @Override
  public int getBazModified() {
    return BAZ * 2;
  }
}

And know if,

Foo foo = new Bar();
System.out.print(foo.getBazModified()); // output: 20 (access instance variable)
Kaete answered 7/2, 2019 at 17:17 Comment(1)
the variable defined in interface is NOT even an instance variable.Photochemistry
E
1

Did you try to compile it? The answer is no because the interface doesn't know whether there will even be a field named 'baz' or not.

I know that sounds like travisty but is there a way to do anything like that in Java 8?

Yes. An abstract class. That's literally exactly what abstract classes were designed for.

Essentiality answered 7/2, 2019 at 16:39 Comment(2)
I know it wouldn't compile, but I'm asking whether using a class providing the default implementation is the only wayFemale
Basically, yes it is the only way.Pitterpatter
C
-1

In essence your default method when running is running inside the instance of the class you are implementing. Therefore, instead of defining a getter method inside the class, you can always try to access the class parameters inside your default method using getDeclaredField. Keep in mind that you probably need to provide try..catch around it since if there is no parameter defined inside your class you get an exception.

public interface Foo {
    default getBazModified() {
        //since you have only one declared field in your class,
        //you can access it via index number 0
        // you can also use getDeclaredField("baz") if you 
        // prefer but then you are might get issues if you 
        //rename it. try.. catch would be needed here
        int baz = (int) this.getClass().getDeclaredFields()[0].get(this);

        return baz * 2; 
    }
}

public class Bar implements Foo {
    int baz;
   ...
}
Coldhearted answered 1/9, 2024 at 15:39 Comment(6)
This is (IMO) a really bad idea. The problem is that there is no guarantee that there is a field called "baz", let alone that it is the first one returned. So this code is liable to throw runtime exceptions ... or worse ... if a second class is added. If you want to reliably call getBazModified() it needs to be declared as a regular interface method and provided by every class that implements the method.Pitterpatter
Note if the interface Foo is only ever going to be implemented by one class (Bar), then it is redundant. It is safe to assume that the OP knows this ... and that there may be other classes that implement Foo, either now or in the future. Hence your assumption that there will be only one is unsound.Pitterpatter
This question has one variable, you can also call by name, it's easier than having to write ~100 getters for each class implementing this interface...Coldhearted
So? The question is not about supporting multiple variables. It is about using interface default methods to access the instance state of a class that implements an interface. These are different problems. (Besides, if you have 100's of state variables there is probably something wrong with your design. And there are other ways to avoid writing 100's of getters, such as record classes.)Pitterpatter
Exactly, it's about accessing the implementing class variables in the default method, not about writing extra getter code as a workaround. The exact question " is there a way for an interface default method to access instance variables?"Coldhearted
And the way you are proposing to do it is a really bad idea. Fragile. Error prone. And shouldn't be done. The OP is better off using an abstract class. Writing getters for the common instance variables in an abstract class is not a workaround. It is the correct way to write Java code. (This ain't Python.)Pitterpatter

© 2022 - 2025 — McMap. All rights reserved.