A Simple Introduction To Java - Object Oriented Programming - Part 5 (Anonymous and Inner Classes, Enum)
Michael Otu
Posted on June 18, 2022
In this session, we will discuss:
Anonymous Class
Inheritance is a concept of subclass-ing another class, thereby having access to the opened attribute (or via setters and getters if closed) and methods. Polymorphism is the concept of having many forms. It is either we can overload or override the said method. So we have to inherit a class we can overload or override. With an Anonymous class, we can extend the class on the fly. However, this extension only exits for the said object. So another object of the same class will not have that extension.
Say we have an Employee class. Every employee gets a monthly and due to some circumstances, an employee's salary will be increased by some fraction. In such a case an employee is said to be rated.
// Employee.java
public class Employee {
private String name;
private double salary = 200;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public void calculateRate() {
this.salary += this.salary * 0.5;
}
public void print() {
System.out.println("Name: " + name);
System.out.println("Salary: " + salary);
System.out.println();
}
}
We will create two instances of the Employee class and later make one of the objects rated.
// Main.java
public class Main {
public static void main(String[] args) {
// this is peter parker and he is not a rated employee
Employee peter = new Employee("Peter Parker");
peter.print();
// this is harry potter and he is also not a rated employee
Employee harry = new Employee("Harry Potter");
harry.print();
// the employer smiles on harry potter and harry becomes rated
// management now processes harry's salary
harry.calculateRate();
System.out.println();
// this is rated harry potter
harry.print();
}
}
Consider reading through the comment on each line
Now I want to draw our attention to where harry's rate was calculated. Assuming we want to either reduce or increase the rate at which the salary is increased, what would we do? Think about this for a while.
I believe we would all agree that:
- we could pass the rate to the
calculateRate
method as a parameter - we could overload the
calculateRate
in the Employee class - we could subclass the Employee class then we'd override and or overload
calculateRate
method is the said subclass
Assuming we run into an issue like this but we don't have or want to do any of the above, we could extend the calculateRate
method on the run. For this, let's create another Employee object and set the rate to 0.15
. This is sone at where the class is instantiated.
// Main.java
public class Main {
public static void main(String[] args) {
// this is peter parker and he is not a rated employee
Employee peter = new Employee("Peter Parker");
peter.print();
// this is harry potter and he is also not a rated employee
Employee harry = new Employee("Harry Potter");
harry.print();
// the employer smiles on harry potter and harry becomes rated
// management now processes harry's salary
harry.calculateRate();
System.out.println();
// this is rated harry potter
harry.print();
// this is john doe and is not a rated employee
Employee john = new Employee("John Doe") {
@Override
public void calculateRate() {
double johnSalary = this.getSalary();
johnSalary += johnSalary * 0.15;
this.setSalary(johnSalary);
}
};
// the employer smiles on john so john becomes rated
// management now processes john's salary
john.calculateRate();
System.out.println();
// this is rated john doe
john.print();
}
}
When we created the john
Employee, we opened the constructor body, which we normally don't. We then used the @Override
annotation and reimplemented (overrode) the calculateRate
method.
Employee john = new Employee("John Doe") {
@Override
public void calculateRate() {
double johnSalary = this.getSalary();
johnSalary += johnSalary * 0.15;
this.setSalary(johnSalary);
}
};
The this
keyword is used to access the getters and setters of the Employee class. The this
keyword is in the scope of the constructor body.
Overriding the Employee class on the fly makes it an Anonymous class for just that moment and this overridden method works for just the object that implemented it.
Inner Class
When we talk about the members of a class, then we are referring to the properties and methods. In java, we can have a class as a member of a class. This is known as a nested class. The snippet below is how I used Inner classes. It is a User class which has Inner classes. One for property validation, Validation and the other, Response. Response returns the response after a sign-up.
// User.java
public class User {
private static int id = 0;
private String fullName;
private String email;
private String password;
public User(String fullName, String email, String password) {
this.fullName = fullName;
this.email = email;
this.password = password;
}
public String getEmail() {
return email;
}
public String getFullName() {
return fullName;
}
public static int getId() {
return id;
}
public User.Response signup() {
User.Validation validation = new User.Validation();
boolean isValidEmail = validation.email(this.email);
boolean isValidFullName = validation.name(this.fullName);
boolean isValidPassword = validation.password(this.password);
User.Response response = new User.Response();
if (isValidEmail && isValidFullName && isValidPassword) {
User.id += 1;
response = new User.Response(true, "Signup successful", this);
}
return response.getResponse();
}
// this is a nested class used for validating the user properties
private class Validation {
private boolean name(String name) {
return !name.isEmpty() && name.trim().length() > 3;
}
private boolean email(String email) {
return !email.isEmpty() && email.trim().contains("@");
}
private boolean password(String password) {
return !password.isEmpty() && password.trim().length() > 2;
}
}
// this is a nested class used for returning response after signup
class Response {
private boolean success = false;
private String message = "Signup unsuccessful";
private User user = null;
// for the default values above so that when the process fails
// I won't have to pass the success status and message
private Response() {
}
private Response(boolean success, String message, User user) {
this.success = success;
this.message = message;
this.user = user;
}
public boolean getSuccess() {
return success;
}
public String getMessage() {
return message;
}
public User getUser() {
return user;
}
public Response getResponse() {
return this;
}
}
}
We will create a User object and call the signup
method which then would return a Response object. We take the Response object and pass it to a method to print it out.
// App.java
public class App {
private static void printResponse(User.Response response) {
System.out.println("Registration status: " + response.getSuccess());
System.out.println("Message: " + response.getMessage());
if (response.getSuccess()) {
System.out.println("User");
System.out.println("Id: " + User.getId());
System.out.println("Full name: " + response.getUser().getFullName());
System.out.println("Email: " + response.getUser().getEmail());
}
}
public static void main(String[] args) {
User john = new User("John Doe", "johndoe@email.com", "password");
User.Response response = john.signup();
printResponse(response);
}
}
Enum
An Enum is a type used for the enumeration of constants. It is used to define a collection of constants.
If you want the days of the week, we could do:
/// Day.java
public class Day {
private int monday = 0;
private int tuesday = 1;
private int wednesday = 2;
private int thursday = 3;
private int friday = 4;
private int saturday = 5;
private int sunday = 6;
public int getMonday() {
return monday;
}
public int getTuesday() {
return tuesday;
}
public int getWednesday() {
return wednesday;
}
public int getThursday() {
return thursday;
}
public int getFriday() {
return friday;
}
public int getSaturday() {
return saturday;
}
public int getSunday() {
return sunday;
}
}
where we would create an object of the Day class and call a getter to return the day we want.
Ok. What do you think is wrong with this snippet? What are we not doing well? I think we are going to be having a lot of code (getters) even though it is doing what we want it. What if we have about twenty (20) properties? What if we made the properties public
and got rid of the getters, what do you think? Let's do it.
// Day.java
public class Day {
public int monday = 0;
public int tuesday = 1;
public int wednesday = 2;
public int thursday = 3;
public int friday = 4;
public int saturday = 5;
public int sunday = 6;
}
Waw! Now all that we want can access directly. Problem solved? Not quite. What would happen when monday is altered? what will happen when any of the properties are altered? Well, we could go back and use the private
and getter approach. That will work however, we could make all the properties final
. This way even though the properties are opened, they can't be modified. Also, we can make them static
so that we won't have to create an object before accessing any of the days. Let's try that.
// Day.java
public class Day {
public static final int monday = 0;
public static final int tuesday = 1;
public static final int wednesday = 2;
public static final int thursday = 3;
public static final int friday = 4;
public static final int saturday = 5;
public static final int sunday = 6;
}
This way we would just do, Day.monday
to get the numerical value (ordinal) of monday. The snippet about is similar to an enum
.
// Day.java
public enum Day {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
All caps are for enum
constants is a java convention. We can have an enum
in a file on its own and we can have it as part of a class.
// DayEnum.java
public class DayEnum {
public enum Day {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
}
We can not have an enum
inside a constructor or the body of a method. (It is a sealed class). So it can exist as a member. We can not have duplicates in an enum
as well. This is just like having duplicate attributes. We don't have to declare every property (constant) of the enum
is public
, static
and final
. So we can not alter the value of an enum
at run time.
An enum
can be used as a type (it is a type) just as an int
or String
could be used. We can pass it as a type to a parameter.
public static void printDay(Day day) {
System.out.println("Today is, " + day.name().toLowerCase());
}
enum
has a name()
method which returns the name of the enum
value. This will be in uppercase since we used uppercase to define the enum
constants. The toString()
method does the same.
public static void printDayToString(Day day) {
System.out.println("Today is, " + day.toString());
}
We can the integer constant (ordinal) of an enum
constant using the ordinal()
method.
public static void printOrdinal(Day day) {
System.out.println("The ordinal for " + day.name() + " is " + day.ordinal());
}
We can get an enum
constant when we pass its String
name to the valueOf
method, valueOf(String name)
. We'd get an error if the name passed doesn't exist.
System.out.println(Day.valueOf("MONDAY"));
We can compare one enum
constant to another using the compareTo
method, compareTo(Enum o)
. This returns the difference between the two constants.
We can also check for equality between enum constants using the equal
method, equal(Enum o)
. It returns a boolean
.
System.out.println(day.equals(Day.FRIDAY));
We can loop through the enum
constants. The static method values()
returns an array of the enum
constants.
for (Day d : Day.values()) {
System.out.println(d);
}
An enum
can have methods.
All the Snippet for the enum
:
// DayEnum.java
public class DayEnum {
public enum Day {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY;
public void salutation() {
System.out.println("Hey, today is " + this.name().toLowerCase());
}
}
public static void printDay(Day day) {
System.out.println("Today is, " + day.name().toLowerCase());
}
public static void printDayToString(Day day) {
System.out.println("Today is, " + day.toString());
}
public static void printOrdinal(Day day) {
System.out.println("The ordinal for " + day.name() + " is " + day.ordinal());
}
public static void main(String[] args) {
Day day = Day.THURSDAY;
printDay(day);
printDayToString(day);
printOrdinal(day);
System.out.println(Day.valueOf("MONDAY"));
System.out.println(day.compareTo(Day.MONDAY));
System.out.println(day.equals(Day.FRIDAY));
for (Day d : Day.values()) {
System.out.println(d);
}
day.salutation();
}
}
Conclusion
Anonymous classes provide a means to override a method on the fly. This is done by opening the constructor using the @Override
annotation to overrode the said method. The method overridden is only available to the object the overrode it.
An Inner class is a class nested in a class as a member of the class.
Problem
- Read more on
enum
Source
- Sololearn
- DS Malik
Posted on June 18, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.