Hello! Today we will look at the operation of an important mechanism - inheritance in nested classes. I don't know if you've ever thought about what you'll do when you need to inherit a nested class from some other. If not, believe me: such a situation can be confusing, because there are a lot of nuances here:
- Do we inherit a nested class from some class or do we inherit another class from a nested one?
- Is the inheritor/inheritor of an ordinary public class, or is it also a nested class?
- Finally, what kind of nested classes are we using in all these situations?
Static nested classes
Their inheritance rules are the simplest. Here you can do almost anything you want. A static nested class can be inherited from:- regular class
- a static nested class that is declared in the outer class or its ancestors
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;
}
}
}
Let's try to change the code and create a static nested class Drawing
and its descendant - Boeing737Drawing
.
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 class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
As you can see, no problem. We can take out the class altogether Drawing
and make it an ordinary public class instead of a static nested one - nothing will change.
public class Drawing {
}
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 Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
Got it sorted out. And what classes can be inherited from a static nested one? Practical any! Nested/regular, static/non-static, it doesn't matter. Here we inherit the inner class Boeing737Drawing
from the static nested one Drawing
:
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 class Boeing737Drawing extends Drawing {
public int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
You can create an instance Boeing737Drawing
like this:
public class Main {
public static void main(String[] args) {
Boeing737 boeing737 = new Boeing737(1990);
Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
System.out.println(drawing.getMaxPassengersCount());
}
}
Although our class Boeing737Drawing
inherits from a static class, it is not static itself! So it will always need an instance of the outer class. We can take a class Boeing737Drawing
out of a class Boeing737
and make it just a public class. Nothing will change - it can also be inherited from a static nested Drawing
.
public class Boeing737 {
private int manufactureYear;
public static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
}
public class Boeing737Drawing extends Boeing737.Drawing {
public int getMaxPassengersCount() {
return Boeing737.maxPassengersCount;
}
The only important point: in this case, we need to make the static variable maxPassengersCount
public. If it remains private, the normal public class will not have access to it. We figured out the static classes! :) Now let's move on to inner classes. As you remember, there are 3 types of them: simple inner classes (inner classes), local classes and anonymous inner classes. Again, let's move from simple to complex :)
Anonymous Inner Classes
An anonymous inner class cannot inherit from another class. No other class can inherit from an anonymous class. Easier nowhere! :)Local classes
Local classes (in case you forgot) are declared inside the code block of another class. Most often - inside some method of this external class. Logically, only other local classes within the same method (or block) can inherit from a local class. Here is an example:public class PhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber() {
this.phoneNumber = number;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
class CellPhoneNumber extends PhoneNumber {
}
class LandlinePhoneNumber extends PhoneNumber {
}
//...code валидации номера
}
}
This is the code from our lecture on local classes. Inside the number validator class, we have a local class PhoneNumber
- a phone number. If for our purposes we need to separate two separate entities from it, for example, a mobile phone number and a landline phone number, we can do this only inside the same method. The reason is simple: the scope of a local class is within the method (block) where it is declared. Therefore, we cannot somehow use it from the outside (including for inheritance). However, the possibilities for inheritance from the local class itself are wider! A local class can inherit from:
- Regular class.
- An inner class that is declared in the same class as the local class or in its ancestors.
- From another local class declared in the same method (block).
public class PhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
//...code валидации номера
}
}
Here we have taken the class PhoneNumber
out of the method validatePhoneNumber()
and made it internal instead of local. This does not prevent us from inheriting 2 of our local classes from it. Example 2 - "...or in the ancestors of this class." Here it is more interesting. We can take it PhoneNumber
even further up the inheritance chain. Let's declare an abstract class AbstractPhoneNumberValidator
that will become an ancestor of our PhoneNumberValidator
:
public abstract class AbstractPhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
}
As you can see, we not only declared it, but also moved the inner class into it PhoneNumber
. However, in its descendant class - PhoneNumberValidator
- local classes in methods can easily inherit from PhoneNumber
!
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
//...code валидации номера
}
}
Due to the relationship through inheritance, local classes inside a descendant class "see" inner classes inside an ancestor. And finally, let's move on to the last group :)
Inner classes
An inner class can inherit from another inner class declared in the same outer class (or its descendant). Let's take a look at our bicycle example from the lecture on inner classes.public class Bicycle {
private String model;
private int mawWeight;
public Bicycle(String model, int mawWeight) {
this.model = model;
this.mawWeight = mawWeight;
}
public void start() {
System.out.println("Go!");
}
class Seat {
public void up() {
System.out.println("Сидение поднято выше!");
}
public void down() {
System.out.println("Сидение опущено ниже!");
}
}
class SportSeat extends Seat {
//...methods
}
}
Here, inside the class, we Bicycle
declared an inner class Seat
- the seat. A special subspecies of racing seats was inherited from him - SportSeat
. However, we could create a separate type of "racing bikes" and put it in a separate class:
public class SportBicycle extends Bicycle {
public SportBicycle(String model, int mawWeight) {
super(model, mawWeight);
}
class SportSeat extends Seat {
public void up() {
System.out.println("Сидение поднято выше!");
}
public void down() {
System.out.println("Сидение опущено ниже!");
}
}
}
That's also possible. The inner child class ( SportBicycle.SportSeat
) "sees" the inner classes of the ancestor and can inherit from them. Inheritance from inner classes has one very important feature! In the previous two examples, we SportSeat
had an internal. But what if we decide to make it SportSeat
a regular public class that inherits from the inner class Seat
?
//ошибка! No inclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {
public SportSeat() {
}
public void up() {
System.out.println("Сидение поднято выше!");
}
public void down() {
System.out.println("Сидение опущено ниже!");
}
}
We got an error! Can you guess what it has to do with it? :) Everything is simple. When we talked about the inner class Bicycle.Seat
, we mentioned that a reference to an object of the outer class is implicitly passed to the constructor of the inner class. Therefore, without creating an object, Bicycle
you cannot create an object Seat
. What about creation SportSeat
? It does not have the built-in mechanism for implicitly passing a reference to an outer class object in the constructor as in Seat
. However, without an object Bicycle
, we, just as in the case of Seat
, cannot create an object SportSeat
. Therefore, we have only one thing left - to pass SportSeat
a reference to the object Bicycle
explicitly to the constructor. Here's how it's done:
class SportSeat extends Bicycle.Seat {
public SportSeat(Bicycle bicycle) {
bicycle.super();
}
public void up() {
System.out.println("Сидение поднято выше!");
}
public void down() {
System.out.println("Сидение опущено ниже!");
}
}
To do this, we use a special word super();
Now, if we want to create an object SportSeat
, nothing will prevent us from doing this:
public class Main {
public static void main(String[] args) {
Bicycle bicycle = new Bicycle("Peugeot", 120);
SportSeat peugeotSportSeat = new SportSeat(bicycle);
}
}
Phew, the lecture turned out to be rather big :) But you learned a lot of new things! And now it's time to solve some problems! :)
GO TO FULL VERSION