There are five key pillars of object-oriented design. In this lesson, we will cover the five core concepts of objects/classes, inheritance, encapsulation, methods, and polymorphism.
A World of Objects
The concept of object-oriented design (OOD) may seem hard to grasp at first. But consider that everything in the world is an object. Within a forest, there are trees, shrubs, leaves, and animals. All of these objects are instances of their respective species. That is, each budding maple tree belongs to the class of the Maple tree.
Some of these objects are related and some of them inherit traits from other objects. A spruce tree inherits all the traits of a tree and all the traits of an evergreen tree. When completing an object-oriented design, there are five basic concepts to understand: classes/objects, encapsulation/data hiding, inheritance, polymorphism, and interfaces/methods.
Classes and Objects
A Maple (capital M) is a class. We capitalize it because it's the blueprint. When seeds drop and sprout, the growing maple tree is really an instance, or a type, of the Maple class. The growing maple tree is considered an object, that is, an instance of a class. To reiterate: a newly-growing maple tree is an instance of the Maple class
This is the only time we'll show code in this lesson, but here it reinforces the fundamentals of object-oriented design (objects are instances of classes).
- Maple maple = new Maple();
Inheritance
Recall that a spruce tree will have features of all trees, plus features from evergreen trees. A Spruce class will inherit all of the features of the Tree class. Just like we inherit genes and traits from our parents, so too do classes in object-oriented design. In this case, the variables and methods in the Tree class are available to the Spruce class.
The graphic below is a good depiction both of class hierarchy and inheritance, although it is not comprehensive. In this case, the parent of everybody is the Tree class. As you move down the chart, each of the classes is a child class, or subclass, of the parent above it.
Class Hierarchy and Inheritance
Not only does Red Pine inherit from Pine, but from Evergreen, and the top parent Tree class.
Encapsulation, Interfaces, Methods
Encapsulation is a fancy word to describe the protection, or hiding, of data. The power of objected-oriented design is that you can protect certain data in certain classes from being used. Remember that the Spruce class inherited everything from the Evergreen class. But what if you don't want everything to be passed down to children? Although we're focusing on trees here, think about things like age and pay rate. These are items we would definitely want to keep close to the vest in a system. We would not want to allow other classes to get at these items.
Let's say the Deciduous class has a method, or process, for growth changes in the fall. We'll call it fallChanges(). Within it are all sorts of variables for modifications as the season approaches winter (rate of leaf fall, color change rate). We don't need to expose any of that to the Evergreen class. In fact, as you design an object-oriented program or system, it's best to start out by encapsulating data. That is, don't make everything public. It's best to start off with more restrictions since this prevents inappropriate access of items in classes.
An instance of a Maple class (a maple) will change colors in the fall. To do so it needs a method, or a function that performs an action. Part of the color change could be in the fallChanges() method mentioned earlier.
An interface tells the object what it can do. For example, it tells a tree that it can grow. So all Tree classes will implement the grow interface. The reason for the interface is to fully lock down the objects. All instances of a Tree will have a grow method.
Polymorphism
It may sound like science fiction, but polymorphism really means that the same thing can have different features. Think of two classes (instances of objects), Squirrel and Coyote. Both are children (sub-classes) of the Animal class (they've inherited the traits from the parent class). The Animal class has a Communicate() method. When asked to communicate, they each have different ways of implementing that method. The graphic appearing here depicts this type of polymorphism.
Recall the fallChanges() method in the Deciduous class. Although we wanted to encapsulate most of the functions within Deciduous, polymorphism can be harnessed to provide different changes among the Maples, Elm, and Ash classes. An interface is like a method, but it actually defines what a class can do. All trees will have a grow() function. So you could have a Trees interface with the grow() function in it. Then all other subclasses would implement this interface.
Lesson Summary
Let's take a moment to review what we've learned about the five basic concepts of object-oriented design. An object is an instance of a class, with the class being the blueprint and an instance being a type of the class. That is, a Maple is an instance of the Tree class. In object-oriented design (OOD), objects and classes are the key concepts. Inheritance is also an important facet. It means that a class can gain all features and traits (such as methods and variables) from a parent class. The class doing the inheriting is a child, or subclass.
In order to protect data and methods from other classes, OOD allows for encapsulation, which is a fancy word to describe the protection, or hiding, of data. For example, other classes can run a calculatePay() method, but not have access to the details. Finally, in order for classes to actually do something, we need methods, or code that performs an action (such as calculate pay rate). Interfaces are like methods but define what a class can do. For example, all Tree classes (and subclasses) have a grow() method. How they grow is up to the individual class, but they all grow. Using the method in a different way is called polymorphism, which is the same thing can have different features.
Object-oriented programming has become the most widely used approach to software development. Learn about the core concepts of object-oriented programming and how they are implemented using objects, classes and methods in this video lesson.
What Is an Object in Programming?
Object-oriented programming, or OOP, is an approach to problem solving where all computations are carried out using objects. An object is a component of a program that knows how to perform certain actions and how to interact with other elements of the program. Objects are the basic units of object-oriented programming. A simple example of an object would be a person. Logically, you would expect a person to have a name. This would be considered a property of the person. You could also expect a person to be able to do something, such as walking or driving. This would be considered a method of the person.
Code in object-oriented programming is organized around objects. Once you have your objects, they can interact with each other to make something happen. Let's say you want to have a program where a person gets into a car and drives it from A to B. You would start by describing the objects, such as a person and car. That includes methods: a person knows how to drive a car, and a car knows what it is like to be driven. Once you have your objects, you bring them together so the person can get into the car and drive.
Classes and Objects
A class is a blueprint of an object. You can think of a class as a concept, and the object is the embodiment of that concept. You need to have a class before you can create an object. So, let's say you want to use a person in your program. You want to be able to describe the person and have the person do something. A class called 'person' would provide a blueprint for what a person looks like and what a person can do. To actually use a person in your program, you need to create an object. You use the person class to create an object of the type 'person.' Now you can describe this person and have it do something.
Classes are very useful in programming. Consider the example of where you don't want to use just one person but 100 people. Rather than describing each one in detail from scratch, you can use the same person class to create 100 objects of the type 'person.' You still have to give each one a name and other properties, but the basic structure of what a person looks like is the same.
Methods and Functions
Once you have created objects, you want them to be able to do something. This is where methods come in. A method in object-oriented programming is a procedure associated with a class. A method defines the behavior of the objects that are created from the class. Another way to say this is that a method is an action that an object is able to perform. The association between method and class is called binding. Consider the example of an object of the type 'person,' created using the person class. Methods associated with this class could consist of things like walking and driving. Methods are sometimes confused with functions, but they are distinct.
A function is a combination of instructions that are combined to achieve some result. A function typically requires some input (called arguments) and returns some results. For example, consider the example of driving a car. To determine the mileage, you need to perform a calculation using the distance driven and the amount of fuel used. You could write a function to do this calculation. The arguments going into the function would be distance and fuel consumption, and the result would be mileage. Anytime you want to determine the mileage, you simply call the function to perform the calculation.
How does this differ from a method? A function is independent and not associated with a class. You can use this function anywhere in your code, and you don't need to have an object to use it.
Now, what if you were to associate the function with an object of the type 'car?' For example, you want to be able display the mileage of the car on the dashboard. In this case, the mileage calculation has become a method because it is a procedure associated with the car's class. Every time you create a new object of the type 'car' using the car class, this method will be part of the object. The action the car is now able to perform is to calculate mileage. It is the same calculation as performed by the stand-alone function but is now bound to the car.
OOP Concepts
Object-oriented programming is built around a number of concepts. These concepts are implemented using classes, objects and methods, but it is useful to review those concepts more generally. Four core concepts of object-oriented programming are abstraction, encapsulation, inheritance and polymorphism.
Using abstraction, a programmer hides many of the details about an object and shows only the most relevant information. This reduces complexity and increases efficiency. For example, in the case of a person, there could be any number of detailed descriptions. However, if only the name and age are really relevant in a particular context, only those descriptions will be used.
Encapsulation is the hiding of internal mechanisms and data structures behind a defined interface. This keeps data safe from interference and misuse. Encapsulation is like a protective wrapper around code and data that prevents it from being accessed arbitrarily by code outside the wrapper. Consider the example of where each is the owner of a car. The properties of the car are encapsulated from the owners; an owner can drive a car but is not able to change the color or the engine.
Inheritance is the process by which new classes are created from existing classes and inherit the general characteristic of those classes. Consider the person class that is used to create two new classes called woman and man. The new classes inherit the properties of the person class, which saves a lot of coding. Each of the new classes does have some unique properties, but it is much easier to add these to an existing class than to start from scratch. Inheritance is one example of code reusability, which makes OOP very efficient for certain tasks.
Polymorphism means to have one name but multiple forms. This means that the properties of an object can change with the context. For example, an object called person could be considered an owner when inside a car but an employee when at the office. These concepts have made object-oriented programming the most widely used approach in today's software development.
Lesson Summary
Object-oriented programming is an approach to problem solving where all computations are carried out using objects. An object is a component of a program that knows how to perform certain actions and how to interact with other elements of the program. A class is a blueprint of an object. You need to have a class before you can create an object. Objects have properties and methods.
A method is a procedure associated with a class and defines the behavior of the objects that are created from the class. A function is a combination of instructions that are combined to achieve some result. A function is independent and not associated with a class. Object-oriented programming uses a number of core concepts: abstraction, encapsulation, inheritance and polymorphism. These concepts are implemented using classes, objects and methods.
Learning Outcomes
After this video lesson, you should be able to:
- Summarize how object-oriented programming works
- Define object, class and method
- Differentiate between method and function
- Explain the four core concepts of object-oriented programming
Inheritance in Java is not an estate or a classic car from a long-lost relative. It means certain classes can share attributes from other classes. Here, we'll learn the concept and the syntax for this powerful feature of Java.
A Great Inheritance
Inheritance is a wonderful thing in Java. It's a term used often in object-oriented programming. But what does it really mean? And how do you harness this powerful concept?
To inherit in Java means allowing all methods and variables from one class to be accessible by another class. That is, the new class inherits these items. The parent class, also called superclass, is the class whose methods and variables can be used in the child class (also called subclass).
Another way to think of the inheritance concept is the phrase: A union employee is an employee; a paperback book is a book. It's more than a child inheriting 50% of their parent's DNA - they get all of it. The subclass gets all the goodies from the parent class, but it can also create its own variables and methods.
Inheritance is a key part of object-oriented programming. It allows for use and re-use of objects, methods, and variables, without having to add extra/redundant code.
Syntax
The syntax for creating a subclass, and thus harnessing inheritance is:
- public class Class extends ParentClass {
- //new variable or methods here
- }
Inheritance in Java: Example
Let's look at some code. The following example creates an Employee class and another class for a union employee. All of the features of the employee class come over to the Union class, such as pay, FTE (full-time equivalent; how many hours you work in a pay period). However, this class can be used for its own methods.
- public class Employee {
- private double payRate;
- private String fullName;
- private double FTE;
- public void calculatePay() {
- //calculate the pay here
- }
- }
- public class UnionEmployee extends Employee {
- // everything from Employee will come over
- // new fields for UnionEmployee:
- private String barganingUnit;
- private String unionCode;
- private double unionDues;
- public void calculateUnionDues() {
- // can use the Employee calc pay
- // also special calc for dues
- }
- }
The subclass can use the variables and methods from the parent class, but not vice versa. You are not able to bring in the union information to the parent Employee class as they are private to the UnionEmployee class.
Overriding
The child class inherits variables and methods from the parent. Not only can you use the methods from the parent class, you can override, or change, them. In the above example, we could use the method to calculate pay as-is. Or, we could override it for a union employee.
In the following code, we've revamped the pay calculation method to return some values; we've also added methods to calculate pay, hours, and FTE. We'll need those later when we override them!
- public class Employee {
- private double payRate;
- private String fullName;
- private double FTE;
- float hoursWorked;
- public double calculatePay() {
- return getPayRate() * getFTE() * getHoursWorked();
- }
- public double getPayRate() {
- return payRate;
- }
- public double getFTE() {
- return FTE;
- }
- public float getHoursWorked() {
- return hoursWorked;
- }
- }
In the UnionEmployee subclass, we want to calculate pay but also subtract the union dues. We can override the original method and add in our own. To do this, use the same data type as the parent and add your stuff.
There is a requirement here: Use the super keyword in front of any methods or variables you're using from the parent class. This tells Java that you are overriding the original method.
For our union employee example, we would subtract the union dues as follows:
- public class UnionEmployee extends Employee {
- private String barganingUnit;
- private String unionCode;
- private double unionDues;
- private double getUnionDues() {
- return unionDues;
- }
- public double calculatePay() {
- return (super.calculatePay() - getUnionDues());
- }
- }
Lesson Summary
As a child might inherit an estate from a parent, Java classes can inherit data and methods from other classes. To inherit in Java means allowing all methods and variables from one class to be accessible by another class. These classes are child classes, or subclasses. They inherit the variables and methods from the parent class, though you can use your own within the subclass. You can even override, or change, a method from the parent class, adding your own arguments. Inheritance is a huge component of object-oriented programming and allows objects to be used and re-used without adding extra and unnecessary code.
Object-oriented programming is all about reducing unnecessary code. In Java, interfaces and abstract classes are powerful tools for writing well-organized programs. This lesson will cover each and provide code examples.
Interfaces and Abstract Classes
Interfaces and abstract classes are great tools for reducing repetitive code and keeping all the nitty-gritty details of code away from the end user or programmers. We'll cover each type and provide working code examples. Let's start with interfaces.
Interfaces
In reality, an interface is already abstract because they don't hold all the details of what is being done. Think of a card game app on your phone; there's a little icon on your screen that you click. That is all you need to do. The interface is a gateway to the actual code that runs the card game.
What does this look like in code? Let's take a look at the following interface for a card game. We don't necessarily have to know the details behind the shuffling of the cards, or how the cards are dealt. There are two empty methods listed, shuffle and deal.
- interface CardGame {
- public void shuffle();
- public void deal();
- }
Multiple Inheritance
Interfaces are great tools that help us get around Java's restriction on multiple inheritance. That is, a single class cannot inherit from more than one main class. The game of Golf cannot inherit from both CardGame and SolitaireCardGame classes. Instead, interfaces would allow you to access methods from both classes.
Remember that interfaces let us avoid the restriction of multiple inheritance (also called polymorphism). An interface CAN inherit (extend) from multiple classes. When we create an interface, we can tell it to draw from multiple classes. We do this by using the extends keyword.
Take a look at the following code. Here we create a new interface that extends both the CardGame and Solitaire interfaces:
- public interface SolitareDoubleDeck extends CardGame, Solitaire {
- public CardGame doubleShuffle();
- }
Classes Using Interfaces
We used the extends keyword on an interface to get around multiple inheritance restrictions. That is specific to interfaces. So how do we use an interface in a class? In Java, the keyword is implements to specify an interface to use.
If we create a new class for a card game, say Double Diamond, we can use that interface by using the implements keyword:
- public class DoubleDiamond implements CardGame() {
- }
An interface is useful for our card game example - you shouldn't have to reinvent the wheel each time a new game is added. There are hundreds of solitaire games. Our code should be flexible and transparent in order to add a new game. The shuffle and deal methods should still work regardless of the new type of game.
Extend vs. Implement
It may be tricky to remember these important concepts for classes/interfaces. Here's a quick method for using each:
- If you add more buttons to your interface, you EXTEND it
- If your code uses an interface, it is IMPLEMENTED
Now that we've covered some basics of interfaces, let's look at another important concept in object-oriented programming, the abstract class.
Abstract Classes
Where an interface declares methods and can let us get around the multiple inheritance restriction, an abstract class is a class that cannot be instantiated. You cannot create an instance of an abstract class.
What's the use? you might ask.
Let's continue with the theme of a card game. Recall that we briefly discussed inheritance - a class inheriting methods and variables from another class. We might create a hierarchy of Card Game -> Solitaire -> Double Diamond. The top-level class of Game shouldn't need to be instantiated. Game is too generic a concept.
Instead, we can make Game. It can't be instantiated, that is you can't create an instance of an abstract class. However, an abstract class can have methods; you just have to use these methods in the child class(es).
The following code example provides a straightforward example of the concept (for sake of simplicity we'll simplify the hierarchy and use CardGame -> Double Diamond.
- public abstract class CardGame {
- //this method has to be overridden in the subclass
- public abstract long getCards();
- }
- //DoubleDiamond inherits from CardGame
- public class DoubleDiamond extends CardGame {
- public long getCards() {
- return 104;
- }
- }
Lesson Summary
Think of an interface as a gateway that signals which methods to run. It lets us get around the multiple inheritance restriction; Java doesn't let you have one class inherit from multiple classes. However, an interface can use the extends keyword to inherit methods from more than one class. When you want to use an interface in a class, use the implements keyword. An abstract class cannot be instantiated but is good for a class hierarchy; e.g., a Game class can be built to define all games, whereas a card game class can inherit the Game class's methods and variables.
Do you want to define your own data types? Learn about why abstract data types are useful in programming, and how to create very basic ones in Java using a Java interface in this lesson.
Creating a Data Type
Consider the types of data you use in your code. Whether it's a complicated class-based type or a simple primitive type (such as int), they are defined by the characteristics they can have and how they can be used. For example, you can add an int to another int by using the '+' function. So, when you think about making your own type, you might consider creating a class and defining the type's characteristics and behaviors using class members (for example, methods or variables).
Let's say you're creating an application that monitors the usage of a server. You'd probably want to keep track of the precise times users logged in and out. So, it would be useful to have a data type representing time. In Java, you should see this as a prime candidate for a class, maybe called Time. Time would have variables to store the day, hour, minute, and second. For behaviors, you'd make methods that allow you to access those variables, methods to get the time from somewhere, and maybe a method to convert the time from one format to another. The code to create such a class would look something like this:
- import java.time.*;
- public class Time {
- private int hour;
- private int minute;
- private int second;
- private LocalDateTime time;
- public Time(LocalDateTime time) {
- this.time = time;
- }
- public int getHour() {
- return time.getHour();
- }
- public int getMinute() {
- return time.getMinute();
- }
- public int getSecond() {
- return time.getSecond();
- }
- public static void main(String[] args) {
- Time time_logged = new Time(LocalDateTime.now());
- int this_hour = time_logged.getHour();
- System.out.println(this_hour);
- }
- }
For this example we're using the java.time library, which makes the LocalDateTime.now() method available. If you compile and execute this code, you should see the hour printed out.
Abstraction
But what if you're going to be using this application in different contexts where there are different ways of getting the time? For example, in one department it's been mandated that all times must be synchronized to a company time server. In another department, there's no such requirement and, in fact, your application doesn't even have access to that time server. In the latter case, you'd likely have to get the time from a public server, perhaps by using the java.time library. This would probably have a very different API and require a different kind of error handling.
You still want your data type to behave the same, however. Calls to getHour() should behave the same regardless of what's being done behind the scenes to accomplish the method's task. Here's where you'd want to seriously consider making your data type abstract. An abstract data type defines only the variables and methods, including the parameters and return types of those methods, without determining how they are implemented. That's why it's abstract, you're determining what the data type can do, but not how it does it.
In Java, this is usually accomplished using interfaces. The dashboard of a car is an interface. You know you can see the current speed and do things like turn on the windshield wipers, but you don't know how these things are done behind the panel. And, in fact, two cars might use the same model speedometer but have different mechanisms for actually causing the speed to be displayed. Java interfaces are created similarly to classes, but with the keyword interface. Here's how the code would look for the Time interface:
- interface Time {
- public int getHour();
- public int getMinute();
- public int getSecond();
- }
You'll notice that the methods have no bodies. They are not implemented, merely described. But you have to create a class that does the implementation. To make that happen, after the class name use the keyword 'implements' followed by the interface name. So in the previous example, you'd make two different classes that implement the Time interface, one to be used with the company time server, and the other to be used with the public time server. Putting it all together would look like this:
- import java.time.*;
- interface Time {
- public int getHour();
- public int getMinute();
- public int getSecond();
- }
- public class PublicTime implements Time {
- private int hour;
- private int minute;
- private int second;
- private LocalDateTime time;
- public Time(LocalDateTime time) {
- this.time = time;
- }
- public int getHour() {
- return time.getHour();
- }
- public int getMinute() {
- return time.getMinute();
- }
- public int getSecond() {
- return time.getSecond();
- }
- public static void main(String[] args) {
- PublicTime time_logged = new PublicTime(LocalDateTime.now());
- int this_hour = time_logged.getHour();
- System.out.println(this_hour);
- }
- }
Here we've created the class PublicTime, which implements the Time interface and uses the java.time library to store and report on times. Of course, you could add more interesting methods to the interface, such as ones that compare two different times, or add, subtract, or convert times. Once you've added these to the interface, any class that implements the interface will have to implement those methods too.
Interfaces are like blueprints that describe the data type in abstract terms, leaving the actual implementation to the classes that implement them. This is a useful way to organize your code because, for instance, whenever you have a class that implements the Time interface, you know exactly what you can expect to be able to do with it. That's the essence of abstraction: you design only the outward-facing aspect of the data type, the interface.
Lesson Summary
Let's review. If you want to define the way a certain type of data behaves and is structured, but not how those behaviors and structures are implemented, you should use an abstract data type. Abstraction means that you're determining what the data does, but not how it does it. In Java, this is usually accomplished using interfaces. You create an interface by using the keyword 'interface,' after which comes a block of code with methods defined, but without bodies. Interfaces cannot be used directly in Java code, but must be implemented by a class, using the keyword 'implements' after the class name. A class that implements an interface must define all of the methods specified in the interface definition. This is so that when you're using a class that is an example of the abstract data type, you can expect to be able to use any or all of its behaviors.
File not found! We see exceptions every day as they are a feature of any program or programming language. In this lesson, we'll cover Java exceptions/errors, and provide some examples and methods for handling them.
Error! Error!
What is an exception in Java? The short answer: An exception is an error. The long answer: An exception is an unscheduled, unplanned event that interferes with a program's processing.
When Java encounters an exception, it throws it. Unfortunately it doesn't throw it away. Instead, it throws it to the internal system of the computer (called the runtime system). Basically, Java gives up, and tosses the exception to the system in hopes that there's something there that can handle the error.
Exception Types
When an exception is thrown, Java most likely knows what type of exception it is: Java is a pretty smart programming language, because it has many exceptions already built in. The following exceptions are already known by Java:
Java ExceptionDescription
ArithmeticException | Dividing by zero |
ArrayIndexOutOfBoundsException | Trying to reference an item in an array but the index doesn't exist |
ClassCastException | Try to change a String object to a Double |
NullPointerException | Try to call an object that isn't there |
Errors:
- Divide by Zero
- File Not Found
- Array Index Out of Bounds
But this doesn't mean you are safe! This only means that Java knows what to display when your program crashes. If you do nothing to handle (catch) these exceptions, Java will nicely tell you that you've hit a File Not Found exception. But your program will still terminate!
If there is nothing to 'catch' this error, the program crashes. This type of exception is an unhandled exception. The code that handles the error is called the 'exception handler', and is the code that catches the exception. As we'll see in our code, the actual Java keywords are 'try' and 'catch'.
Java Classes
When we say that Java includes the exceptions in its code, it means that there is actually a Java class (think blueprint) for these known exceptions. There is a Throwable class (which lets Java throw the exception), from which comes the all-important Exception class.
In turn there is a whole slate of sub-classes that all inherit from Exception. These include the arithmetic (divide by zero), file, and array exceptions shown earlier.
A few examples of the different classes and subclasses
Exceptions: Examples
Let's look at a couple of examples of exceptions. We'll start with the divide by zero error, since it can happen very easily in code that crunches numbers.
Divide By Zero
The following code will most likely result in a divide-by-zero error. Whenever the date is Thursday, the modifier is set to 0; but the total value is calculated by dividing the fees by the modifier. Although it may seem apparent after looking at it, divide-by-zero errors can lurk in your code. The best bet is to create an exception handler to catch the errors.
- double fees = 50;
- double modifier = .05;
- double total;
- String todaysDate = new String();
- while(fees < 50) {
- if(todaysDate == "Thursday") {
- modifer = 0;
- }
- total = fees / modifier;
- }
Array Out Of Bounds
The following code will compile without issue. But when we run it, an exception will be thrown and the program terminates. In this example, we create an array of size five, but write a loop to cycle through the array 15 times.
- //Array size = 5
- int[] numbers = new int[5];
- //loop past the last array item
- for(int i = 0; i < 15; i++) {
- System.out.println(numbers[i]);
- }
When we run the code, the following error is displayed:
Handling Exceptions
For this lesson, we'll cover the basics of the 'try' and 'catch' keywords. We place the code we want to run in the try block, and any exception handling in the catch block.
- //Array size = 5
- int[] numbers = new int[5];
- try {
- //loop past the last array item
- for(int i = 0; i < 15; i++) {
- System.out.println(numbers[i]);
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- System.out.println("Oops!");
- }
Instead of crashing, Java throws our exception to our handler, which displays a message. The program finishes successfully.
In order to catch the exception, we've written a simple but effective exception handler. The code within the catch block is able to handle the exception thrown. You'll notice in that the catch statement includes the ArrayIndexOutOfBoundsException name: This is one of those known exceptions that Java can handle. You just have to add it to the catch statement so Java knows to process YOUR code versus terminating the program.
Lesson Summary
An exception in Java (or any programming language) is an error. It is an unexpected break in the program's flow that can cause the program to crash. If the program or runtime engine has no means of dealing with the error, it is considered unhandled and the program will crash. That is, unless you catch these errors. Writing effective exception handlers can help reduce the risk of exceptions. Java provides the try and catch functions. The desired code is placed in the try block, with any exception handling code in the catch block.
A static nested class in Java is a class that is defined within another class but retains most of the characteristics of an independent class. Learn why this can be useful in the following lesson.
A nested class in Java is basically a class that is defined within another class, so it's a member, just like variables and methods. To see what makes a static nested class different from a non-static one, let's review what makes a static member different from a non-static member.
Defining Static
When you define a member of a class as static you are saying that it should not be associated with any particular object that will be instantiated from that class. For this reason, they are sometimes referred to as class members, that is, members of the class as a whole, rather than attributes or behaviors of individual objects. You can think of them as resources that are available wherever the class is available.
In the case of static nested classes, this essentially means that you get an extra class in the same package. This extra class interacts with the containing class in the same way any other class would, it just happens to be neatly packaged up with that containing class, so it comes along with it. Let's look at a simple example:
If you compile and run this code, it should output the string 'from the nested class'.
All you need to do to create a static nested class is to create a class within another class and add the word 'static' at the beginning of the definition.
As you can see, you don't need to instantiate the containing class in order to create an object from the static nested class. You access it by name using a dot (.) the same as you would any other member. It's like you have another class available that just happens to have a dot in its name (which is usually illegal). In this case, we've created an object called 'object' of type OuterClass.Nested.
Uses for Static Nested Classes
A common use case for static inner classes is the situation where we only need a certain class (call it 'class B') when we're using a certain other class (call it 'class A'). If we make class B a static nested class of class A, we can be sure to only load class B when we load class A. This is efficient. They act independently but always show up together.
Ok, so let's look at a more useful example:
Here we have a class that represents an employee. One of the things we want to be able to do is calculate the amount paid to a given employee for a pay period. We'd also like to be able to calculate overtime pay. It might be nice to have this capability even when we're not dealing with a particular employee. So our application can report general information about overtime pay. We'll make an 'OvertimeCalculator' class for this. Two reasons this is a good candidate for a static nested class are:
- We probably won't need it in any other context.
- We'll likely need it frequently when we're dealing with employee data.
You can see in the following code that we can set and retrieve the overtime rate without creating an employee object, but that the OvertimeCalculator class is available wherever the Employee class is.
If you run this with the Employee class available it should output:
The current overtime rate is 0.5
Salary for Kelly Kelly is 225.0
Summary
Static nested classes are classes that you define within other classes, but that behave mostly independently of their containing class. Like other static members, they may be accessed without instantiating (creating an object from) the containing class, as long as the class has been loaded. Like any other separate class, they do not have access to any non-static members of the containing class. You create a static nested class by including a full class definition within the containing class, using the keyword 'static' before 'class.' Static nested classes are often used as a way to package classes that are used together. In this way, you only have to load one class and you can use that class and all its static nested classes. If you're only going to need a class when you are using another class, it may be neater choice to make it a static nested class.