inner

Nested/innere Klassen


Motivation

public class LinkedList {
    private Node first;
    
    public Object getFirst() {
        if (first == null)
            throw new NoSuchElementException();
        return first.getItem();
    }
    ...
public class Node {
    private Object item;
    private Node next;
    ... 
  • Klassen stark aneinander gekoppelt
  • Node wird nur in LinkedList verwendet

Nested/static inner


public class Outer {
    private static int staticVar;
    private int instanceVar;
    private static void staticMethod() {}
    private void instanceMethod() {}
    
    private static class Nested {
        private static int nestedStaticVar;
        private int nestedVar;
        private void foo() {
            staticVar++;        βœ”οΈ
            staticMethod();     βœ”οΈ
            instanceVar++;      🚫
            instanceMethod();   🚫
        }
    }
    public static void main(String[] args) {
        Nested.nestedStaticVar++;
        new Nested().nestedVar++;
        new Outer.Nested().foo();       
    }
}


public class LinkedList {
    Node first;

    public Object getFirst() {
        Node f = first;
        if (f == null)
            throw new NoSuchElementException();
        return f.item;
    }

    private static class Node {
        Object item;
        Node next;

        Node(Object item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
}
  • Einfacher Zugriff Outer -> Inner
  • Outer mΓΆchte verstecken, dass Inner existiert

inner


public class Outer {
    ...
    private class Inner {
        private static int nestedStaticVar; 🚫
        private int innerVar;
    
        private void foo() {
            staticVar++;        βœ”οΈ
            staticMethod();     βœ”οΈ
            instanceVar++;      βœ”οΈ
            instanceMethod();   βœ”οΈ
        }
    }
    
    public static void main(String[] args) {
        new Outer.Inner();      🚫
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
    }
}

Einfacher Zugriff Outer <-> Inner


Local

button.setOnAction(EventHandler handler);
@FunctionalInterface
public interface EventHandler extends EventListener {
    void handle(Event event);
}
public void initialize(URL location, ResourceBundle resources) {
    class CustomEventHandler implements EventHandler {

        @Override
        public void handle(Event event) {
            foo();
        }
    }
    Button button = new Button();
    button.setOnAction(new CustomEventHandler());
}

Closure


public static void main(String[] args) {
    String s = "Closure?";
    class Local {
        void foo() {
            System.out.println(s); 🚫
        }
    }
    s += "Object, welche den aktuellen Zustand kapselt";
}

Error: local variables referenced from an inner class must be final or effectively final


😱

Object foo() {
    String s = "wtf";
    class Local {
        void foo() {
            System.out.println(s);
        }
    }
    return new Local();
}
  • Referenz s wird am Stack angelegt
  • Objekt "wtf" muss erhalten bleiben
  • ⟹ Local muss eine Referenz darauf haben

😱 final 😱


Object foo() {
    String s = "wtf";
    class Local {
        void foo() {
            System.out.println(s);
        }
    }
    Object result = new Local();
    Runnable mayHaveRun = () -> s = null; 🚫
    mayHaveRun.start();
    return result;
}

Anonym

public void initialize(URL location, ResourceBundle resources) {
    Button button = new Button();
    button.setOnAction(new EventHandler() {
    
        @Override
        public void handle(Event event) {
            foo();
        }
    });
}
public void initialize(URL location, ResourceBundle resources) {
    Button button = new Button();
    button.setOnAction(ev -> foo());
}

Best-practice

Brauch ich nur eine Referenz?
Anonyme innere Klasse
Outer -> Inner
nested
Outer <-> Inner
ganz sicher?
inner