Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use member variables with Interfaces and anonymous implementations

Please check the Java code below:

public class Test
{
  public static void main(String arg[]) throws Throwable
  {
      Test t = new Test();
      System.out.println(t.meth().s);           //OP: Old value
      System.out.println(t.meth().getVal());    //OP: String Implementation
  }
  private TestInter meth()
  {
    return new TestInter()
    {
      public String s = "String Implementation";
      public String getVal()
      {
        return this.s;
      }
    };
  }
}
interface TestInter
{
  String s = "Old value";
  String getVal();
}

As you see I have created an interface anonymously. When I access the interface variable directly, it will show "Old value".

t.meth().s => "Old value"

Accessing it through the getVal() method returns proper values,

t.meth().getVal() => "String Implementation"

I don't understand how this code works, can somebody explain it to me?

like image 587
sprabhakaran Avatar asked Jun 06 '13 06:06

sprabhakaran


People also ask

CAN interfaces have member variables?

Yes, Interfaces CAN contain member variables. But these variables have to be implicitly (without any keyword definition) final, public and static. This means that within interfaces, one can only declare constants. You cannot declare instance variables using interfaces.

Can Anonymous classes be implemented an interface?

A normal class can implement any number of interfaces but the anonymous inner class can implement only one interface at a time. A regular class can extend a class and implement any number of interfaces simultaneously. But anonymous Inner class can extend a class or can implement an interface but not both at a time.

Can we use private or protected member variables in an interface?

Protected members of an interface In general, the protected members can be accessed in the same class or, the class inheriting it. But, we do not inherit an interface we will implement it. Therefore, the members of an interface cannot be protected.

Can anonymous class have multiple methods?

Because the EventHandler<ActionEvent> interface contains only one method, you can use a lambda expression instead of an anonymous class expression. See the section Lambda Expressions for more information. Anonymous classes are ideal for implementing an interface that contains two or more methods.


2 Answers

The s variable declared in the interface is entirely separate from the s variable you've declared in your anonymous inner class.

Interface variables are really just designed to be constants - they aren't part of the API each implementation needs to provide. In particular, they're implicitly static and final.

From the JLS section 9.3:

Every field declaration in the body of an interface is implicitly public, static, and final. It is permitted to redundantly specify any or all of these modifiers for such fields.

The fact that you've accessed the field via an implementation instance is irrelevant - this code:

System.out.println(t.meth().s);

is effectively:

t.meth();
System.out.println(TestInter.s);

I would strongly encourage you to avoid using variables in interfaces except for genuine constants... and even then, only where it really makes sense. It's not clear what you're trying to achieve, but declaring a field in an interface isn't a good way forward IMO.

like image 116
Jon Skeet Avatar answered Oct 05 '22 23:10

Jon Skeet


There is nothing like variable-overriding like method overriding in java. Name a new type for subclass, then you will get the "String Implementation", when you access through the subclass reference type.

Access privilege protected only means we can access the variable in a subclass but not that it can be override.

Even if you are using normal class instead of interface this won't work. When you refer using super class type, you only get the instance variables from super type and so on.... This example illustrates the first case: Example:

public class Tester
{
  public static void main(String arg[]) throws Throwable
  {
      Tester t = new Tester();
      System.out.println(t.meth().s); // it prints "Old value" because your type is TestInter           
  }
  private TestInter meth()
  {
    return new TestInter()
    {
       protected String s = "String Implementation";

    };
  }
}
class TestInter
{
  protected String s = "Old value";

}

This example illustrates the second case: It prints "String Implementation"

 public class Tester
{
  public static void main(String arg[]) throws Throwable
  {
      Tester t = new Tester();
      System.out.println(t.meth().s);           
  }
  private SubTestInter meth()
  {
    return new SubTestInter();
  }
}
class SubTestInter extends TestInter{
       protected String s = "String Implementation";
}
class TestInter
{
  protected String s = "Old value";

}
like image 28
pinkpanther Avatar answered Oct 05 '22 23:10

pinkpanther