Can someone tell me what the purpose of having inner classes? I can think of a few but may be they are not good reasons for using inner classes. My reasoning is that inner class is helpful when you want to use a class that no other classes can use. What else?
A list implementation that internally uses a linked list to store the elements could make good use of an inner class to represent the nodes within the list. I think you've hit the nail on the head by saying that you'd use such a class where you want to use it internally to a class but don't want it exposed - a 'one off' class that is only really useful 'here'.
When I was learning Java we used inner classes for GUI event handling classes. It is sort of a "one time use" class that need not be available to other classes, and only is relevant to the class in which it resides.
I use inner classes (in C++) in situations where multiple classes, unrelated through inheritance, have conceptually similar implementation details, which form an implicit part of the public interface and ought to be named similarly.
class lib::Identifier { ... };
class lib::Person {
public:
class Identifier : public lib::Identifier { ... };
};
class lib::File {
public:
class Identifier : public lib::Identifier { ... };
};
This makes it convenient to refer to Identifier
, Person::Identifier
, and File::Identifier
as simply Identifier
, in the appropriate scopes.
I use inner classes to define a structure that is best represented by the containing class, but doesn't necessarily make sense to use a separate external class to represent the structure.
To give an example I have a class that represents a particular type of network device, and the class has certain types of tests that can be run on that device. For each test there is also a potential set of errors that can be found. Each type of device may have a different structure for the errors.
With this you could do things like
List<Error> errors = RemoteDeviceA.getErrors();
With methods being available from the inner class, like
for ( Error error : errors ) {
System.out.println("MOnitor Type: " + error.getMonType());
...
}
Of course there are other ways to do this, this is just an inner class approach.
Simplified (aka incomplete) code for above:
public class RemoteDeviceA {
private String host;
private String user;
private String password;
private static List<Error> errors;
public RemoteDeviceA(String user, String host, String password) {
this.host = host;
this.user = user;
this.password = password;
login();
}
private void login() {
// Logs in
}
public void runTestA() {
List<Error> errorList = new ArrayList<Error>();
//loop through test results
if (!value.equals("0")) {
Error error = new Error(node, rackNum, shelfNum, slotNum, monType, value);
if (error.isError()) {
errorList.add(error);
}
}
setErrors(errorList);
}
private static void setErrors(List<Error> errors) {
RemoteDeviceA.errors = errors;
}
public List<Error> getErrors() {
return errors;
}
public class Error {
private String monType;
private String node;
private String rack;
private String shelf;
private String slot;
private String value;
private boolean error = false;
private boolean historyError = false;
private boolean critical = false;
private boolean criticalHistory = false;
Error(String node, String rack, String shelf, String slot,
String monType, String value) {
parseAlarm(node, rack, shelf, slot, monType, value);
}
private void parseAlarm(String node, String rack, String shelf,
String slot, String monType, String value) {
String modType = "";
if (monType.startsWith("ES_15") && !value.equals("0")) {
setMonType("ES_15");
setError(true);
} else if (monType.startsWith("SES_15") && !value.equals("0")) {
setMonType("SES_15");
setError(true);
} else if (monType.startsWith("BBE_15") && !value.equals("0")) {
setMonType("BBE_15");
setError(true);
} else if (monType.startsWith("UT_15") && !value.equals("0")) {
setMonType("UT_15");
setError(true);
setCritial(critical);
} else if (monType.startsWith("ES_24") && !value.equals("0")) {
setMonType("ES_24");
setHistoryError(true);
setError(true);
} else if (monType.startsWith("SES_24") && !value.equals("0")) {
setMonType("SES_24");
setHistoryError(true);
setError(true);
} else if (monType.startsWith("BBE_24") && !value.equals("0")) {
setMonType("BBE_24");
setHistoryError(true);
setError(true);
} else if (monType.startsWith("UT_24") && !value.equals("0")) {
setMonType("UT_24");
setHistoryError(true);
setError(true);
setCriticalHistory(true);
} else if (monType.startsWith("UT_15") && !value.equals("0")) {
setMonType("UT_15");
setError(true);
setCritial(true);
} else if (monType.startsWith("LASPWR")) {
float laserPwr = Float.valueOf(value);
if (node.startsWith("LEM_EM")) {
if ((laserPwr < 8.0) || (laserPwr > 12.0)) {
setMonType("LASERPWR");
setError(true);
}
} else if (node.startsWith("LEM10")) {
if ((laserPwr < 18.0) || (laserPwr > 22.0)) {
setMonType("LASERPWR");
setError(true);
}
}
}
if (isError()) {
setNode(node);
setRack(rack);
setShelf(shelf);
setSlot(slot);
setValue(value);
setError(true);
}
}
private void setMonType(String monType) {
this.monType = monType;
}
public String getMonType() {
return monType;
}
private void setNode(String node) {
this.node = node;
}
public String getNode() {
return node;
}
public void setRack(String rack) {
this.rack = rack;
}
public String getRack() {
return rack;
}
public void setShelf(String shelf) {
this.shelf = shelf;
}
public String getShelf() {
return shelf;
}
public void setSlot(String slot) {
this.slot = slot;
}
public String getSlot() {
return slot;
}
private void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
private void setError(boolean error) {
this.error = error;
}
public boolean isError() {
return error;
}
public void setCritial(boolean critical) {
this.critical = critical;
}
public boolean isCritical() {
return critical;
}
public void setCriticalHistory(boolean criticalHistory) {
this.criticalHistory = criticalHistory;
}
public boolean isCriticalHistory() {
return criticalHistory;
}
public void setHistoryError(boolean historyError) {
this.historyError = historyError;
}
public boolean isHistoryError() {
return historyError;
}
}
}
Inner classes can be used to simulate closures: http://en.wikipedia.org/wiki/Closure_(computer_science)#Java