Suresh Rohan's Blog

This blog is all about Java, J2EE,Spring, Angular, React JS, NoSQL, Microservices, DevOps, BigData, Tutorials, Tips, Best practice, Interview questions, Views, News, Articles, Techniques, Code Samples, Reference Application and much more

Saturday, October 24, 2015

Flavors of Nested Classes in Java


There are four types or flavors of nested classes in Java:
  1. Static nested class
  2. Inner class
  3. Local inner class 
  4. Anonymous inner class

Static Nested Classes (or Interfaces)

You can define a class (or interface) as a static member inside another class (or interface). Since the outer type can be a class or an interface and the inner ones can also be a class or interface, there are four combinations.

class Outer { 
// an outer class has a static nested class
static class Inner {}
}

interface Outer {
// an outer interface has a static nested class
static class Inner {}
}

class Outer {
// an outer class has a static nested interface
static interface Inner {}
}

interface Outer {
// an outer interface has a static nested interface
static interface Inner {}
}

You don’t have to explicitly use the static keyword with a nested interface, since it is implicitly static.

Example 1 - In constants

public enum ErrorCode {

NONE("", null, false),
ERRORCODE1("ERRORCODE1", FS.Strategy1, false),
ERRORCODE2("ERRORCODE2", null, false);


private final String strategy;
private final String errorcode;

ErrorCode(String errorcode, String strategy) {
this.code = code;
this.strategy = strategy;
}

public final String getCode() {
return code;
}

public final FulfillmentStrategy getStrategy() {
if(strategy == null) {
return FS.NoLicenseStrategy;
}
return (FulfillmentStrategy)ContextSingleton.getFactory().getBean(strategy);
}

private static class FS {
private static final FulfillmentStrategy NoLicenseStrategy = new NoLicenseFulfillmentStrategy();
private static final String Strategy_1 = "Strategy1";
private static final String Strategy_2 = "Strategy2";
private static final String Strategy_3 = "Strategy3";
}

}

Example 2 - In DTO and Builder Pattern

public class CustomerData {

private String name;
private String adddress;
private Long customerId;

private CustomerData( Builder builder){
setName(builder.name);
setAdddress(builder.adddress);
setCustomerId(builder.customerId);
}
public String getName() {
return name;
}
public String getAdddress() {
return adddress;
}
public Long setCustomerId() {
return customerId;
}
public static class Builder {
private String name;
private String adddress;
private Long customerId;

public Builder name(String name){
this.name = name;
return this;
}
public Builder adddress(String adddress){
this.adddress = adddress;
return this;
}
public Builder customerId(Long customerId){
this.customerId = customerId;
return this;
}
public CustomerData build(){
return new CustomerData(this);
}
}
}

// using the builder
private CustomerData createCustomerData(final ResultSet rs) throws SQLException {
CustomerData.Builder builder = new CustomerData.Builder();
builder.name(rs.getString(1)).
address(rs.getString(2)).
custmerId(rs.getLong(3));

return builder.build();
}

Inner Classes



You can define a class (or an interface) as a non-static member inside another class.

 
class Outer { // an outer class has an inner class
class Inner {}
}

class Outer { // an outer class has an inner interface
interface Inner {}
}

Let’s create a Point class to implement the center of a Circle. Since you want to associate each Circle with a center Point, it is a good idea to make Point an inner class of Circle

 
public class Circle {

// define Point as an inner class within Circle class
class Point {
private int xPos;
private int yPos;
// you can provide constructor for an inner class like this
public Point(int x, int y) {
xPos = x;
yPos = y;
}
// the inner class is like any other class - you can override methods here
public String toString() {
return "(" + xPos + "," + yPos + ")";
}
}

// make use of the inner class for declaring a field
private Point center;
private int radius;
public Circle(int x, int y, int r) {
// note how to make use of the inner class to instantiate it
center = this.new Point(x, y);
radius = r;
}
public String toString() {
return "mid point = " + center + " and radius = " + radius;
}
public static void main(String []s) {
System.out.println(new Circle(10, 10, 20));
}
// other methods such as area are elided
}


you have defined Point as a private member of Circle here

center = this.new Point(x, y);

You need to prefix the object reference of the outer class to create an instance of the inner class. In this case, it is a this reference, so you are prefixing it with this before the new operator

You can access members of an outer class within an inner class without creating an instance; but this is not the case with an outer class. You need to create an instance of inner class in order to access the members.

Local Inner Classes


A local inner class is defined in a code block (say, in a method, constructor, or initialization block).
local inner classes are not members of an outer class; they are just local to the method or code in which they are defined.

Here is an example of the general syntax of a local class:

class SomeClass {
void someFunction() {
class Local { }
}
}

Local is a class defined within someFunction. It is not available outside of someFunction, not even to the members of the SomeClass. Since you cannot declare a local variable static, you also cannot declare a local class static.


class StatusReporter {

// important to note that the argument "color" is declared final
// otherwise, the local inner class DescriptiveColor will not be able to use it!!
static Shape.Color getDesciptiveColor(final Shape.Color color) {
// local class DescriptiveColor that extends Shape.Color class
class DescriptiveColor extends Shape.Color {
public String toString() {
return "You selected a color with RGB values " + color;
}
}
return new DescriptiveColor();
}

public static void main(String []args) {
Shape.Color descriptiveColor =
StatusReporter.getDesciptiveColor(new Shape.Color(0, 0, 0));
System.out.println(descriptiveColor);
}
}

You can pass only final variables to a local inner class.


Anonymous Inner Classes


anonymous inner class does not have a name. The declaration of the class automatically derives from the instance-creation expression. They are also referred to simply as anonymous classes.

Here is an example just to address the syntax of a local class:

class SomeClass {
void someFunction() {
new Object() { };
}
}

You can simplify the code by converting the local class into an anonymous class

class StatusReporter {

static Shape.Color getDesciptiveColor(final Shape.Color color) {
// note the use of anonymous inner classes here -- specifically, there is no name
// for the class and we construct and use the class "on the fly" in the return
// statement!
return new Shape.Color() {
public String toString() {
return "You selected a color with RGB values " + color;
}
};
}

public static void main(String []args) {
Shape.Color descriptiveColor =
StatusReporter.getDesciptiveColor(new Shape.Color(0, 0, 0));
System.out.println(descriptiveColor);
}
}

• Anonymous classes are defined in the new expression itself, so you cannot create multiple objects of an anonymous class. 
• You cannot explicitly extend a class or explicitly implement interfaces when defining an anonymous class.

No comments:

Post a Comment