TSM - Clasele Inner în Java

Ovidiu Mățan - Fondator @ Today Software Magazine

Continuăm seria de articole Java cu clasele Inner. Acestea sunt puțin folosite față de reprezentarea lambda a acestora. Avantajul principal constă în separarea contextelor și în accesul claselor Inner la variabilele private din clasa de bază.

public class Outside {
  private int count;
  public Outside(int nr){
    this.count=nr;
  }
 class Inner {
   public void showCount(){
   System.out.println(“count is:”
    +count);
    }
  }

 public static void main(
  String[] args) {
   Outside out=new Outside(10);
   Inner inner=out.new Inner();
   inner.showCount();

    new Outside(20)
     .new Inner().showCount();
    }

}

În acest exemplu putem vedea cum metoda privată count din clasa Outside este accesibilă clasei Inner. Pentru crearea clasei Inner folosim constructorul implicit și de asemenea avem nevoie de o instanță a clasei de bază.

Ce facem în schimb dacă avem mai multe clase Inner înlănțuite? Vedem în următorul exemplu:

public class MoreInner {
  private int count=0;
  class Inner1{
    private int count=10;
    class Inner2{
      private int count=20;

      public void showAll(){
      System.out.println(this.count);
      System.out.println(
       Inner1.this.count);
    System.out.println(
     MoreInner.this.count);
            }
        }
    }

  public static void main(
    String[] args) {

  new MoreInner().new Inner1()
    .new Inner2().showAll();
  }
}

Deși este un pic împinsă spre limită, suprascrierea variabilei count ne ajută să înțelegem mai bine modul de a fi referită o variabilă dintr-o clasă de bază. Modalitatea este:

.this.

Ex: Inner1.this.count sau MoreInner.this.count

A se observa că doar în acest context de clasă Inner putem referi this către o referință statică a clasei. Încercarea de a face acest lucru în metoda main(), de exemplu, va genera bineînțeles o eroare de compilare.

Alte tipuri de clase Inner

Clase inner statice

public class Park {
 static class Ride {
   private int price;
   public Ride(int price){
     this.price=price;
   }
}
 public static void main(
    String[] args) {
    var ride = new Ride(2);
        System.out.println(ride.price);
        System.out.println(new Ride(3).price);
    }
}

Avantajul principal al claselor Inner statice este că nu mai avem nevoie de o instanță a clasei de bază pentru instanțiere. Chiar dacă clasele sunt declarate static, instanțele lor sunt diferite. În exemplul de mai sus vor fi afișate rezultatele 2 și 3.

Clase Inner declarate în metode

public class PrintNumbers {
    private int length = 5;

    public void calculate() {
        final int width = 20;
        class Calculator {
            public void multiply() {
                System.out.print(length * width);
            }
        }
        var calculator = new Calculator();
        calculator.multiply();
    }

    public static void main(String[] args) {
        new PrintNumbers().calculate();
    }
}

Avantajul în cazul claselor Inner din metode este că putem separa logica internă și că avem acces la membrii clasei în care aceasta este declarată.

Clasele Inner anonime

redButton.setOnAction(new EventHandler() {
   public void handle(ActionEvent e) {
      System.out.println(“Red button pressed!”);
   }
 });

Este o implementare clasică a unei interfețe printr-o clasă anonimă. Exemplul n-ar fi complet dacă nu am aminti și de prescurtările din metodele lambda:

public interface ActionInterface {
    String justDoIt(String s);
}
public class AnonymousInner {

    String makeNoise(ActionInterface action){
        return action.justDoIt(“Hello”);
    }

public static void main(String[] args) {
  AnonymousInner inner=new AnonymousInner();
  System.out.println(
    inner.makeNoise((e)->{return “action:”+e;}));

  System.out.println(
    inner.makeNoise((e)->(“action:”+e)));

    }
}

Ultimele două linii sunt echivalente.

Concluzie

Clasele Inner reprezintă în Java o modalitate rapidă de a încapsula logica aplicației noastre prin clase declarate în interiorul altor clase sau metode.