Anonymous Inner Classes


Lesson 11 discussed the distinction between static nested classes and inner classes. A third type of nested class is the anonymous inner class. An anonymous inner class allows you to dynamically define unnamed class implementations within a method body.

Understanding the syntax and nuances of anonymous inner classes can be daunting. But once you understand anonymous inner classes, your use of them can make your code more concise and easy to understand.

Take the body of the MockAch class (i.e., all the method definitions) and insert it as the first line of code in testTransferFromBank. Immediately preceding all that code, add the line:

 Ach mockAch = new Ach() { 

Then terminate the mock Ach method definitions with a closing brace and semicolon. The transformed test:[3]

[3] You'll need to import com.jimbob.ach and java.util to get this to compile.

 public void testTransferFromBank() {    Ach mockAch = new Ach() {       public AchResponse issueDebit(             AchCredentials credentials, AchTransactionData data) {          Assert.assertTrue(             data.account.equals(AccountTest.ACCOUNT_NUMBER));          Assert.assertTrue(data.aba.equals(AccountTest.ABA));          AchResponse response = new AchResponse();          response.timestamp = new Date();          response.traceCode = "1";          response.status = AchStatus.SUCCESS;          return response;       }       public AchResponse markTransactionAsNSF(             AchCredentials credentials,             AchTransactionData data,             String traceCode) {          return null;       }       public AchResponse refundTransaction(AchCredentials credentials,             AchTransactionData data,     String traceCode) {            return null;       }       public AchResponse issueCredit(AchCredentials credentials,             AchTransactionData data) {          return null;       }       public AchResponse voidSameDayTransaction(             AchCredentials credentials,             AchTransactionData data,             String traceCode) {          return null;       }       public AchResponse queryTransactionStatus (             AchCredentials credentials,             AchTransactionData data, String traceCode) {          return null;       }    };    account.setAch(mockAch);    final BigDecimal amount = new BigDecimal("50.00");    account.transferFromBank(amount);    assertEquals(amount, account.getBalance()); } 

Instance Initializers

In Lesson 4 you learned about static initialization blocks. Java allows you to use instance initialization blocks, which are also known as instance initializers.

Within an anonymous inner class, you cannot create a constructor. Since the anonymous inner class has no name, you wouldn't be able to supply a name for its constructor! Instead, you can use an instance initialization block.

 Expirable t = new Expirable() {    private long then;    {       long now = System.currentTimeMillis();       then = now + 86400000;    }    public boolean isExpired(Date date) {       return date.getTime() > then;    } }; 

Instance initializers are rarely used within top-level classes. Prefer either constructor or field-level initialization. However, you might use instance initializers to eliminate duplication if you have multiple constructors that must execute common setup code.


The line of code:

 Ach mockAch = new Ach() { 

creates a reference named mockAch of the interface type Ach. The right-hand side instantiates an Ach object using new. But Ach is an interfacehow can you instantiate an interface?

Java is allowing you to dynamically provide an implementation for the Ach interface and at the same time create an instance with that implementation. You provide the implementation in a block of code immediately after the constructor call (new Ach()) but before the semicolon that terminates the statement.

The implementation supplied in the block is of Ach type, but it has no specific class name. It is anonymous. You can send messages to this object, store it, or pass it as a parameter, just as you might with an object of a named Ach implementation such as MockAch.

Make sure that your tests pass, but don't delete MockAch just yet.

As you've seen, anonymous inner classes can be useful when building mocks for testing purposes. Swing applications (see Additional Lesson I) and multithreading (see Lesson 13) often make heavy use of anonymous inner classes.

Admittedly, it's still a bit difficult to follow what's going on in testTransferFromBank. The test method is now long and cluttered. The next section on adapters shows how to improve on things.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net