© Adam L. Davis 2020
A. L. DavisModern Programming Made Easyhttps://doi.org/10.1007/978-1-4842-5569-8_8

8. Inheritance

Adam L. Davis1 
(1)
Oviedo, FL, USA
 

Inheritance is a good way to share functionality between objects. When a class has a parent class, we say it inherits the fields and methods of its parent.

In Java, you use the extends keyword to define the parent of a class. For example:
1   public class Griffon extends FlyingCreature {
2   }
Another way to share functionality is called composition . This means that an object holds a reference to another object and uses it to do things. For example, see the following Griffon and Wing classes:
1   class Griffon {
2       Wing leftWing = new Wing()
3       Wing rightWing = new Wing()
4       def fly() {
5           leftWing.flap()
6           rightWing.flap()
7       }
8   }
9   class Wing {
10      def flap() { println 'flap'}
11  }
12  new Griffon().fly()

Running the preceding code in the groovyConsole would print out “flap flap”. This way you can have a Bird class that also uses the Wing class for example.

Objectify

What is an object anyway? An object is an instance of a class (in Java, Groovy, and Scala). It can have state (fields, also known as instance variables) stored in memory.

In Java, classes have constructors, which can have multiple parameters for initializing the object. For example, see the following:
1   class  FlyingCreature  {
2           String name;
3           // constructor
4           public  FlyingCreature(String name) {
5               this.name = name;
6           }
7   }
The constructor of FlyingCreature has one parameter, name, which is stored in the name field. A constructor must be called using the new keyword, to create an object, for example:
1   String name = "Bob";
2   FlyingCreature fc = new  FlyingCreature(name);

Once an object is created, it can be passed around (this is called a pass by reference). Although String is a special class, it is a class, so you can pass around an instance of it, as shown in the preceding code.

JavaScript

In JavaScript, a constructor is a function used to define a prototype (a prototype in JavaScript is somewhat like a class definition in Java). Inside the constructor, the prototype is referred to using the this keyword. For example, you could define a Creature in JavaScript, as follows:
1   function Creature(n) {
2       this.name = n;
3   }
4   var  bob = new  Creature('Bob');
This constructor adds a name variable to the Creature prototype . The object defined earlier (bob) has the name value of ‘Bob’.
Note

All functions and objects in JavaScript have a prototype.

Parenting 101

A parent class defines shared functionality (methods) and state (fields) that are common to multiple classes. You can specify the visibility of fields and methods using access modifiers like public and protected (we will cover these more in depth later).

For example, let’s create a FlyingCreature class that defines a fly() method and has a name.
 1   class FlyingCreature {
 2           String name;
 3           public FlyingCreature(String name) {
 4                   this.name = name;
 5           }
 6           public void fly() {
 7                   System.out.println(name + " is flying");
 8           }
 9   }
10   class Griffon extends FlyingCreature {
11           public  Griffon(String n) { super(n); }
12   }
13   class Dragon extends FlyingCreature {
14           public  Dragon(String n) { super(n); }
15   }
16   public  class  Parenting  {
17           public static void main(String ... args) {
18                   Dragon d = new  Dragon("Smaug");
19                   Griffon g = new   Griffon("Gilda");
20                   d.fly(); // Smaug is flying
21                   g.fly(); // Gilda is flying
22           }
23   }

There are two classes in the preceding code, Griffon and Dragon, that extend FlyingCreature. FlyingCreature is sometimes referred to as the base class. Griffon and Dragon are referred to as subclasses.

Within each constructor of Griffon and Dragon, the keyword super refers to the parent class’s (FlyingCreature) constructor.

Keep in mind that you can use the parent class’s type to refer to any subclass. For example, you can make any flying creature fly, as follows:
1   FlyingCreature creature = new Dragon("Smaug");
2   creature.fly(); // Smaug is flying
3   FlyingCreature gilda = new Griffon("Gilda");
4   gilda.fly(); //Gilda is flying

This concept is called extension, inheritance, or polymorphism. You extend the parent class (FlyingCreature, in this case).

JavaScript

In JavaScript, we can use prototypes to extend functionality.

For example, let’s say we have a prototype called Undead.
1   function Undead() {
2       this.dead = false;
3   }
Now let’s create two other constructors, Zombie and Vampire. JavaScript also has a built-in object named Object which has a create method that creates a new object based on the given prototype. For example:
 1   function Zombie() {
 2       Undead.call(this); // calls the Undead constructor
 3       this.diseased = true;
 4       this.talk = function() { alert("BRAINS!") }
 5   }
 6   Zombie.prototype = Object.create(Undead.prototype);
 7
 8   function Vampire() {
 9       Undead.call(this); // calls the Undead constructor
10       this.pale = true;
11       this.talk = function() { alert("BLOOD!") }
12   }
13   Vampire.prototype = Object.create(Undead.prototype);
Note how we set Zombie’s and Vampire’s prototype to an instance of the Undead prototype. This allows zombies and vampires to inherit the properties of Undead while having different talk functions, as follows:
1   var zombie = new Zombie();
2   var vamp = new Vampire();
3   zombie.talk();   //BRAINS
4   zombie.diseased;  // true
5   vamp.talk();     //BLOOD
6   vamp.pale; //true
7   vamp.dead; //false

Packages

In Java (and related languages, Groovy, and Scala), a package is a namespace for classes. Namespace is just shorthand for a bin of names (names can be reused if they are in different bins). Every modern programming language has some type of namespace feature. This is necessary, owing to the nature of having lots of classes in typical projects.

As you learned in Chapter 3, the first line of a Java file defines the package of the class, for example:
1   package com.github.modernprog;

The Java file also needs to reside in the directory corresponding to the package, so in this case com/github/modernprog. Also, there is a common understanding that a package name typically corresponds to a URL (github.com/modernprog, in this case). However, this is not necessary.

Public Parts

You might be wondering why the word public shows up everywhere in the examples so far. The reason has to do with encapsulation. Encapsulation is a big word that just means “a class should expose as little as possible to get the job done” (some things are meant to be private). This helps reduce complexity of code and therefore makes it easier to understand and think about.

There are three different keywords in Java for varying levels of “exposure.”
  • private: Only this class can see it.

  • protected: Only this class and its descendants can see it.

  • public: Everyone can see it.

../images/435475_2_En_8_Chapter/435475_2_En_8_Figa_HTML.jpg There’s also “default” protection (absence of a keyword), which limits use to any class in the same package (package protected).

This is why classes tend to be declared public, because, otherwise, their usage would be very limited. However, a class can be private when declaring a class within another class, as follows:
1   public class Griffon extends FlyingCreature {
2           private class GriffonWing {}
3   }

JavaScript

JavaScript does not have the concept of packages, but, instead, you must rely on scope. Variables are only visible inside the function they were created in, except for global variables. There are frameworks in JavaScript for providing something like packages, but they are outside the scope of this book. One is RequireJS1 which allows you to define modules and dependencies between modules.

Interfaces

An interface declares method signatures that will be implemented by classes that implement the interface. This allows Java code to work with several different classes without necessarily knowing what specific class is “underneath” the interface. An interface is something like a contract that says what an implementing class must implement.

For example, you could have an interface with one method, as follows:
1   public interface  Beast  {
2           int getNumberOfLegs();
3   }
Then you could have several different classes that implement that interface. Interface methods are public by default. For example:
1   public class Griffon extends FlyingCreature implements  Beast {
2            public int getNumberOfLegs() { return 2; }
3   }
4   public class Unicorn implements Beast {
5            public int getNumberOfLegs() { return 4; }
6   }
In Java 8, the ability to add static methods and the “default method” feature was added which allows you to implement a method within an interface. For example, you can use the default keyword and provide an implementation (which can still be overridden—implemented a different way—by implementing classes):
1   public interface  Beast  {
2           default int getNumberOfLegs() { return 2; }
3   }
Note

JavaScript does not have an equivalent concept to interface; however, interfaces are not useful since JavaScript is not strongly typed. You can call any method you want.

Abstract Class

An abstract class is a class that can have abstract methods but cannot have instances. It is something like an interface with functionality. However, a class can only extend one superclass, while it can implement multiple interfaces.

For example, to write the preceding Beast interface as an abstract class, you can do the following:
1   public abstract class Beast {
2           public abstract int getNumberOfLegs();
3   }
Then you could add non-abstract methods and/or fields. For example:
1   public abstract class Beast {
2           protected String name;
3           public String getName() { return name; }
4           public abstract int getNumberOfLegs();

Enums

In Java, the enum keyword creates a type-safe, ordered list of constant values. For example:
1   public enum BloodType {
2           A, B, AB, O, VAMPIRE, UNICORN;
3   }
An enum variable can only point to one of the values in the enum. For example:
1   BloodType type = BloodType.A;
The enum is automatically given a bunch of methods, such as
  • values(): Gives you an array of all possible values in the enum (static)

  • valueOf(String): Converts the given string into the enum value with the given name (static)

  • name(): An instance method on the enum that gives its name

Also, enums have special treatment in switch statements. For example, in Java, you can use an abbreviated syntax (assuming type is a BloodType).
1   switch (type) {
2           case VAMPIRE: return vampire();
3           case UNICORN: return unicorn();
4           default: return human();
5   }

Annotations

Java annotations allow you to add meta-information to Java code that can be used by the compiler, various APIs, or even your own code at runtime. They can be put before definitions of methods, classes, fields, parameters, and some other places.

The most common annotation you will see is the @Override annotation , which declares to the compiler that you are overriding a method from either a superclass or interface. For example:
1   @Override
2   public String toString() {
3           return "my own string";
4   }

This is useful because it will cause a compile-time error if you mistype the method name or a parameter’s type for example. It’s not required to override a method, but it’s good practice to use it.

Other useful annotations are those in javax.annotation, such as @Nonnull and @Nonnegative , which can be added to parameters to declare your intentions and be used by an IDE to help catch bugs in code.

There are many other annotations used by frameworks like Hibernate, Spring Boot, and others that can be very useful. Annotations such as @Autowired and @Inject are used by direct-injection frameworks such as Spring and Google Guice2 to reduce “wiring” code.

Autoboxing

Although Java is an object-oriented language, this sometimes conflicts with its primitive types (int, long, float, double, etc.). For this reason, Java added autoboxing and unboxing to the language.

Autoboxing

The Java compiler will automatically wrap a primitive type in the corresponding object when it’s necessary, like int to Integer, boolean to Boolean, double to Double, and float to Float. For example, when passing in parameters to a function or assigning a variable, as in the following: Integer number = 1.

Unboxing

Unboxing is the reverse of autoboxing. The Java compiler will unwrap an object to the corresponding primitive type when possible. For example, the following code is acceptable: double d = new Double(1.1) + new Double(2.2).

Summary

After reading this chapter, you should understand OOP, polymorphism, and the definitions of the following:
  • Extension and composition

  • Public vs. private vs. protected vs. package protected

  • Class, abstract class, interface, and enum

  • Annotations

  • Autoboxing and unboxing

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset