Hi! We continue to explore the topic of nested classes in Java. Static nested classes - 1In the last exercise, we spoke about non-static nested classes, which are also known as inner classes. Static nested classes - 2Today we move on to another group of classes. We'll consider static nested classes. Static nested classes - 3How are they different from other classes? When declaring this sort of class, we use the static keyword, which you are already familiar with:
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Static nested classes - 4In this example, we have the Boeing737 outer class, which represents an airplane of this type. It has a constructor with one parameter: the year of manufacture (int manufactureYear). There is also one static variable: the maximum number of passengers (int maxPassengersCount). It will have the same value for all planes of the same model, so we only need one instance. Additionally, it has a static nested class: Drawing (representing the plane's engineering blueprints). We use this class to encapsulate all the official information about the aircraft. In our example, for simplicity, we've limited this class to the year of manufacture, but it could contain a lot of other information. Static nested classes - 5As we said in the last lesson, creating such a nested class improves encapsulation and contributes to a more realistic abstraction. What's the difference between static and non-static nested classes? 1. An object of the static Drawing class does not store a reference to a specific instance of the outer class. Remember the bicycle example from the last lesson:
public class Bicycle {

   private String model;
   private int maxWeight;

   public Bicycle(String model, int maxWeight) {
       this.model = model;
       this.maxWeight = maxWeight;
   }

   public void start() {
       System.out.println("Let's go!");
   }

   public class Handlebar {

       public void right() {
           System.out.println("Steer right!");
       }

       public void left() {

           System.out.println("Steer left!");
       }
   }

}
In that lesson, we talked about the fact that each instance of the Handlebar inner class, imperceptibly to us, passes a reference to the instance of the Bicycle outer class. Without an instance of the outer class, an object of the inner class simply could not exist. For static nested classes, this is not the case. An object of a static nested class is entirely capable of existing on its own. In this regard, static classes are more "independent" than non-static. The only thing you need to know is that when creating such an object, you must specify the name of the outer class:
public class Main {

   public static void main(String[] args) {

       Boeing737.Drawing drawing1 = new Boeing737.Drawing();
       Boeing737.Drawing drawing2 = new Boeing737.Drawing();
   }
}
Why did we make the Drawing class static when in the last lesson we made the Seat class (representing the bicycle seat) non-static? Like last time, let's add a little "philosophy" in order to understand the example :) Unlike a bicycle seat, the concept of an engineering drawing is not rigidly tied to the concept of an aircraft. Without a bicycle, a separate bicycle seat object would most often be meaningless (though not always, we talked about this in the last lesson). The concept of an engineering drawing makes sense on its own. For example, it could be useful to engineers planning airplane maintenance. The airplane isn't needed to make the plan and can be located anywhere. Only the engineering drawing is needed. In addition, all aircraft of the same model will have the same engineer drawing, so there is no such tight relationship as exists with a bicycle seat. Therefore, a Drawing object does not need a reference to a specific airplane object. 2. Different access to the variables and methods of the outer class. A static nested class can only access the static fields of an outer class. In our example, the Drawing class has a getMaxPassengersCount() method that returns the value of the static maxPassengersCount variable of the outer class. However, we can't create a getManufactureYear() method in the Drawing class to return the value of manufactureYear. After all, the manufactureYear variable is non-static, which means it must belong to a specific instance of Boeing737. And as we have already discovered, in the case of static nested classes, the object of the outer class may easily be absent. Hence, the limitation :) It doesn't matter which access modifier a static variable has in the outer class. Even if it is private, a static nested class will still have access. All of the above applies not only to access to static variables, but also to static methods. IMPORTANT! In the declaration of an inner class, the static keyword does not mean that you can create only one object. Don't confuse objects with variables. If we're talking about static variables, then, yes, there exists a single instance of a static class variable, for example, maxPassangersCount. But when static is applied to a nested class, it means only that its objects do not contain references to objects of the outer class. And we can create as many of the objects themselves as we want:
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

       private int id;

       public Drawing(int id) {
           this.id = id;
       }

       public static int getPassengersCount() {

           return maxPassengersCount;
       }

       @Override
       public String toString() {
           return "Drawing{" +
                   "id=" + id +
                   '}';
       }

       public static void main(String[] args) {

           for (int i = 1; i < 6; i++) {

               Boeing737.Drawing drawing = new Boeing737.Drawing(i);
               System.out.println(drawing);
           }
       }
   }
}
We declared the main() method directly in the nested class (there's no special reason for this — only to let you know that this is possible), and created 5 Drawing objects. Despite the fact that we don't have a single object of the outer class. As you can see, this didn't create any problems :) Console output:
Drawing{id=1}
Drawing{id=2}
Drawing{id=3}
Drawing{id=4}
Drawing{id=5}
And that concludes our lesson! Just in case, I'll leave you a link to the section about them in the Oracle documentation. If something still remains unclear, read it. Now it's time for me to solve a couple of tasks! :)