0

Is there a good reason why you can or cannot have an inner interface within a Java class? (like you would an inner class). I couldn't find a definitive answer with Google, but it appears as though you can't embed an interface the same way you would with an inner class. My guess is that the Java creators didn't see a great reason to make it possible, and so it isn't but maybe there are really good reasons?

for example I can't get this to compile (it's all one big class)

package buttonGetSourceObject;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ClassWithButton implements ActionListener, ButtonOwner{

    private String objectName = "";

    public ClassWithButton(String string) {
        objectName = string;
        JFrame f = new JFrame();
        JPanel p = new JPanel();
        MyJButton b = new MyJButton(this,"Press This Button for Name of Owner of Button");
        b.addActionListener(this);
        f.add(p);
        p.add(b);
            f.pack();
        f.setVisible(true);


    }

    public static void main(String[] args){
        ClassWithButton c = new ClassWithButton("object1name");
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        ((ButtonOwner)((MyJButton)arg0.getSource()).getOwner()).printInstanceName();

    }


    public interface ButtonOwner {
        public void printInstanceName();
    }


    private class MyJButton extends JButton {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        Object owner = null;

        public Object getOwner() {
            return owner;
        }

        public void setOwner(Object owner) {
            this.owner = owner;
        }

        public MyJButton(Object o, String string){
            owner = o;
            this.setText(string);
        }
    }


   @Override
    public void printInstanceName() {

        System.out.println(this);

    }

    public String getObjectName() {
        return objectName;
    }

    public void setObjectName(String objectName) {
        this.objectName = objectName;
    }

    public String toString(){
        return this.getObjectName();
    }

} //end

the compiler doesn't seem to recognize the inner Interface "ButtonOwner" as existing at all

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
  • What aspect of nesting interfaces did you find was impossible (that happened to be _possible_ with nested classes)? – Ray Toal Jun 08 '13 at 04:29
  • You can have inner interfaces (interfaces inside of classes). Do you mean interfaces inside of interfaces? – zastrowm Jun 08 '13 at 04:32
  • I am pretty sure my IDE (Eclipse Juno) barfed when I tried to do it. Also, I couldn't find any evidence on google that supported the belief that you could nest interfaces (or not, either, no evidence either way). – Alexander Mills Jun 08 '13 at 04:32
  • I mean an interface inside of a class. – Alexander Mills Jun 08 '13 at 04:33
  • You can: http://ideone.com/bPeHd0 – zastrowm Jun 08 '13 at 04:34
  • 1
    Your question 'why you can or cannot' is completely meaningless. – user207421 Jun 08 '13 at 10:26
  • EJP, actually, it's not a meaningless question at all. In fact, if you look below, there are meaningful answers to my question :) – Alexander Mills Jun 08 '13 at 18:02
  • it is my humble opinion that this is a very good question and that it should not be downvoted... – Alexander Mills Jun 08 '13 at 18:06
  • It's meaningless because it contains an internal contradiction, and also because the designers' intentions are not available here. All you will get here is either guesswork or references to the JLS which you could have found for yourself. You could at least have discovered whether you can or can't do this before posting the question, instead of clearly conducting zero prior research, which is another reason for downvoting and close-voting. – user207421 Jun 09 '13 at 01:25
  • EJP you didn't even read the original post. I said I googled before I posted. It is not a contradiction. Good luck in life. It is people like you that make asking serious, nuanced questions difficult on this website. – Alexander Mills Jun 09 '13 at 04:22
  • @EJP can and cannot is a contradiction, can or cannot is not a contradiction, and you are an idiot. There are two great answers to this question because these people are decent. – Alexander Mills Sep 25 '15 at 00:34

2 Answers2

6

Because it's an inner class, you must use the full name of the class that you're extending (e.g. use ClassWithButton.ButtonOwner instead of just ButtonOwner):

public class ClassWithButton implements ActionListener, ClassWithButton.ButtonOwner

This won't work however, as you're extending an inner interface:

Cycle detected: the type ClassWithButton cannot extend/implement itself or one of its own member types

As to why a class cannot implement an inner interface, a comment on the above question indicates that it could be because:

how class loading works. Normal references to other classes are loaded lazily, but outer classes, superclasses and implemented interfaces are loaded automatically before the class itself is loaded. When your outer class implements an inner interface and that construct would have been valid, you'd get a StackOverflowError in the class loader when loading the class at runtime...

Community
  • 1
  • 1
zastrowm
  • 8,017
  • 3
  • 43
  • 63
  • 2
    +1 this is the only answer that actually answers the OP's question of "why?" Other answers simply say "the compiler says no" – Brandon Jun 08 '13 at 05:30
  • 1
    This reasoning (support the purported "why") is incorrect. They could have made it work if they wanted to. In fact, the order in which classes are *loaded* ... or whether loading is eager or lazy ... are *not specified* in the JLS. (The order of class initialization is specified, but that is different process.) (And resolution of supertype references, etc, is part of the linking process that happens after class loading ... according to the JLS.) – Stephen C Jun 08 '13 at 09:44
  • 2
    (Another nitpick - the nested interface is not "inner". According to the JLS, nested interfaces are implicitly `static`.) – Stephen C Jun 08 '13 at 23:09
3

Here is a definitive answer: JLS Chapter 9:

"A nested interface is any interface whose declaration occurs within the body of another class or interface."

"A top level interface is an interface that is not a nested interface."

And the syntax is in Chapter 18:

ClassBody: 
    { { ClassBodyDeclaration } }

ClassBodyDeclaration:
    ; 
    {Modifier} MemberDecl
    [static] Block

MemberDecl:
    ...
    InterfaceDeclaration

The reason that your code won't compile is that you are trying to make the outer class a subtype of an nested interface of itself. (I cannot find the JLS section that forbids this, but the compiler error message makes it clear that this is forbidden.)


I'm not sure about "why" they decided to forbid a class extending an inner class or interface of itself. It could simply be that they thought that the specification and implementation effort involved out-weighed the utility of allowing it.

(The explanation that it is to prevent a StackOverflowError during class loading doesn't hold water:

  • Nested classes are actually compiled to free-standing ".class" files.
  • The JLS does not specify the order in which classes are loaded. (Initialization is another matter.
  • Resolution of the linkages between classes (including links to superclasses) actually happens after the classes have been loaded ... according to the JLS.
  • In fact, you can "achieve" this kind of problem anyway (e.g. by messing around with the ".class" files to create loop in the inheritance graph) ... and the verifier will detect it before it does any harm.)
Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216