29
Fri, Nov
0 New Articles

Object-oriented Design for AS/400 Java Applications: Inheritance

Java
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Code reuse for AS/400 programmers has been limited to the techniques of cut and paste and COPY. But now, with Java, AS/400 development can obtain huge payoffs from the advanced code-reuse facilities of object-oriented inheritance.

The most-often-heralded benefit of Java and object-oriented programming is code reuse. But we legacy programmers already have two varieties of code reuse: cut and paste and copy code. Cut and paste (a technique used all too often) is where we take good code examples, copy that code into a new program, and then tweak it to perform the desired behavior. Copy code is where the code is copied into a source member at compile time (rather than the design time of cut and paste) using COPY statements. The use of copy code with COBOL and RPG programs is far superior to cut and paste, but it has limitations. Typically, copy code has been restricted to the definition of complex data structures; it has not been widely used for calculations.

Object-oriented programming gives us a method of code reuse far superior to cut and paste or copying code—object-oriented encapsulation. Encapsulation, as I covered in “Object-oriented Design for AS/400 Java Applications: Standard Encapsulation Strategies” (MC, July 1998), is the process of placing all the properties and behaviors of an entity into one place—a Java class definition—and exposing to the users of that class only the information the designer feels the users need to know about the class. As a Java programmer, when you use that class as the abstract data type in the declaration of a variable, you are, in effect, reusing the implementation of that class without touching its code. In truth, you can achieve similar results with ILE modularization techniques. But what are you supposed to do when you find a Java class (or an ILE module, for that matter) that is almost, yet not quite, what you need? Your first impulse might be to fall back into the bad habit of cutting and pasting code in the design of a completely new Java class. Don’t. There is a better way: the object-oriented mechanism known as inheritance. Sorry, there is no such alternative for ILE languages.

The Roles of Inheritance

Inheritance plays an even stronger role than just code reuse. That role is abstraction. Object-oriented designers use the abstraction capabilities of inheritance to organize business entities into hierarchies of specialization.

When designers classify business entities, they seek to group them by their common characteristics or by their common behaviors. Classification is nothing new to us; it’s how we order knowledge. To understand the complexities and variations of things, we categorize them into clusters of generalized groups. Object-oriented programming directly supports our human nature to categorize by allowing us to build a hierarchy of classes in which specialized classes inherit the structure and behavior defined by more generalized classes.

Biology’s classification of species is often used as an excellent example of classification. Carolus Linnaeus came up the hierarchical categorization of genus and species in the 1700s, to which modern biology has expanded to kingdom, phylum, class, order, family, genus, and species. Don Denoncourt is from the kingdom animalia, phylum chordata, class mammalia, order primates, family hominidae, genus Homo, species sapiens.

At the start of application design, object-oriented designers seek to discover objects that model the problem domain. Often, they discover a variety of objects that share common characteristics. Rather than redundantly implementing those common characteristics as fields and functions in each of the various classes, they are factored out as generalizations into a base class.

The object model of Figure 1 shows a Company and a Consumer class. These objects have dissimilar characteristics, but so do they have common characteristics. Those common characteristics were factored out into the Customer class. Both the Consumer and Company classes inherit the common characteristics and behaviors from the Customer class. The Unified Modeling Language (UML) notation graphically portrays inheritance with the line that descends to those two classes from the Customer class (the triangle symbol represents inheritance). The operative word here is descends. Both the Consumer and the Company classes are descendants of the Customer class. Just as with humans, the Consumer and Company classes inherit the characteristics of their parent. The difference is that a Java class can inherit from only one parent.

The Customer class is an example of the abstraction capabilities of object-oriented design. More often, however, we are not involved in the complete design of an application. What inheritance gives us at the workaday level is a code-reuse mechanism. We build on top of existing classes by developing new ones that inherit the fields and functions of a base class and adding the capabilities required by the new class.

The payoffs from object-oriented inheritance are numerous. First, we don’t need to know the implementation details of a class’s parent class. Second, we don’t have to duplicate the efforts of writing and testing code, which provides a service similar to what is already provided for in another class. Third, inheritance allows incremental development by allowing us to introduce new code without causing bugs in existing code, such as what you might have done with the cut-and-paste techniques of RPG programming. We get a fourth payoff from inheritance when the implementation of a base class is modified (as is always done in business programming), because those changes are immediately available to derived classes without recompilation. In an RPG application, for instance, if the original section of code that has been copied numerous times requires modification, so too must all the copied versions of that code be changed. Use of RPG’s COPY is less of a problem, but all of the affected programs still require recompilation. The payoffs from Java’s code reuse alone should be enough reason to consider moving from RPG to Java development.

The Basics of Inheritance

All Java classes have some form of inheritance, even those classes that do not explicitly extend another class. That’s because all Java classes inherit from Java’s great

grandparent of base classes—Object. Figure 2 shows a UML of the BigDecimal class. BigDecimal inherits from the Number class, and the Number class inherits from Object. The Number class is a generalization of the behaviors of numbers, any numbers, be they integers, long, float, double, or even our familiar zoned and packed numbers. In fact, you will use the BigDecimal class to store those fixed decimal values that we have traditionally kept on the AS/400 as zoned or packed. The BigDecimal class extends the Number class with the following:

class BigDecimal extends Number {...}
But if a Java class does not extend another class, the Java compiler implicitly
assigns the Object class to be its parent. The following
declarations for the Number class are identical:
class Number {
// fields and functions:
}

class Number extends Object {
// fields and function:
}

The Java compiler automatically inserts extends Object to the first implementation of the Number class. The Number class is—as all classes ultimately are—an extension of the Object class.

A base class is also known as the parent class or superclass, and the derived class is also known as the subclass. The Number class, as a subclass, picks up all the characteristics and behaviors of its parent—Java’s Object class. The Number class then adds new behaviors to those derived from its Object superclass. An instance of a BigDecimal object can directly invoke functions that are a part of any of its ancestors, which includes Java’s Order class:

BigDecimal money = new BigDecimal ();
Class moneyClass = money.getClass();
String str = money.toString();

When we derive a class, only those fields and functions that are qualified in the parent class with either the public or protected access specifiers are available for the implementation of a derived class.

(Remember that the UML notation for the public, protected, and private access specifiers are the +, #, and - characters, respectively.) Private fields and functions are not inherited by derived classes; they are solely for the internal implementation of their classes. When a function has an access specifier of protected, as I covered in “Object-oriented Design for AS/400 Java Applications:

Standard Encapsulation Strategies” (MC, July 1998), it is accessible only from within other functions of that same class or from within functions of its subclasses. The protected functions, for instance, of the Object class—clone() and finalize()—are inherited by the PurchaseOrder class and are available for its implementation, but they are not available to instance variables of the PurchaseOrder class. For example:

class PurchaseOrder extends Object {

PurchaseOrder () {

// internal use of a protected Object function

clone();

}

}

PurchaseOrder po = new PurchaseOrder();
// external use of Object’s protected function
po.clone ();

// compile error, function inaccessible
po.finalize ();

// compile error, function inaccessible

It would be easy if this were it for inheritance. That is, you design a new class by extending an existing class, thereby inheriting all of its public and protected fields and functions. Then, you add additional fields and functions as required by the new class. Using only what I have described so far, you can define some fairly sophisticated object models. But, as always, you have to be concerned with a few other areas; namely, overriding, overloading, and constructor invocation in an inheritance tree.

Overriding

In object-oriented language, you would say that the Consumer object of Figure 1 IS-A Customer. The Consumer inherited all of the fields and functions of its parent class, so it is a Customer. But the Consumer class is also more than the Customer class because it was extended to include some additional consumer-specific functions. There are occasions, however, in which you might want to change behaviors inherited from a base class. When the inherited behaviors and characteristics of a base class are changed in a derived class, we say that the subclass IS-A-KIND-OF its base class. It is an IS-A-KIND-OF base class because you have changed it to have some but not all of the characteristics and behaviors of its base. Why would you want to do this?

You might want to change the imple-mentation of a function inherited from a base class to adapt it to the needs of a new class. For instance, the finalize() function implemented in Java’s ubiquitous Object class is often reimplemented in derived classes to perform class-specific cleanup, such as closing files when an object is garbage collected (destroyed) by the Java Virtual Machine (JVM). That new, improved finalize() function is automatically invoked when an object is destroyed by the garbage collection facilities of the JVM.

Hide-and-seek

You can change the inherited behaviors of a superclass by defining a function in the subclass that has the same name, return type, order, and type of arguments as a function of its superclass. Characteristics are changed simply by defining a field that has the same name as a field of the base class. The process of replacing characteristics and behaviors of a base class in a derived class is known as overriding.

When fields or functions of a base class are overridden in a derived class (subclass), the base versions of those fields and functions are still available to the derived class; they are simply hidden by the new versions in the derived class. You can still access the base class’s (parent class’s) overridden fields or functions by qualifying the reference with the Java Super keyword (the reserved word Super can be thought of as a synonym for the base class name). By specifying the overridden base class’s function or field name qualified by Super, you force the Java compiler to reference the parent’s version. The following DOS executions of the superClass and subClass classes of Figure 3 shows how a parent class’s overridden fields and functions—theInt and theFunc—may be accessed.

C:>java superClass
theInt:1 theFunc():1

C:>java subClass
theInt:2 theFunc():2
super.theInt:1 super.theFunc():1

Functions are overridden far more often than attributes. The object designer may wish to extend the functionality of a given method without complicating the API by adding another public function. Frequently, the overridden method even calls the very function that it hid. A simple example is a technique often used to test the functions of a class. This process is simple: You derive a class that overrides each of the functions in the superclass, add test code such as profiling information, and then invoke the parent’s implementation of the function so the parent class still works as designed.

class TestProfile extends VeryComplicatedClass {

void veryComplicatedFunction() {

System.out.print(“got to

veryComplicatedFunction()”);

super.veryComplicatedFunction();

}

...

}

Overloaded Functions

Java programmers are able to easily understand the functional interface of a well- designed class because it has descriptive function names, return types, and parameter lists. It is normal to have requirements for interfaces that are similar in function but have a variety of argument options. For this reason, Java allows you to overload a function name by defining several functions with the same name but different signatures (a signature being the combination of function name, return type, number, and type of arguments).

In RPG (or even in a poorly designed Java class), we often create a parameter list by cramming in all the potential options, but that would make it unclear which parameters were required. A well-designed Java class lets you create multiple functions that have the same name and accept the correct combinations of parameters needed.

The BigDecimal class of Figure 1 uses function overloading because it has not one but four constructor functions. (You might recall that a constructor function has the same name as its class and no return type; it is used in conjunction with Java’s New operator to instantiate an object of the constructor’s class.) You can build an instance of a BigDecimal object with a numerical string, a double value, another BigInteger object, or a BigInteger with specification for decimal precision:

BigDecimal money1 = new BigDecimal(“128.95”);
BigDecimal money2 = new BigDecimal(128.95);
BigInteger aBigInt = new BigInteger(“325”);
BigDecimal threeHundred25Bucks =

new BigDecimal(aBigInt);
BigDecimal threeBucksAndaQuarter =

new BigDecimal(aBigInt, 2);

If you define a function in a derived class with the same function name as one in the base class (but with a different signature), it’s considered an overloaded function. The base class’s function of the same name is not overridden and is still directly available to the derived class. To override a function of the base class, you must specify the same signature in the function of the derived class.

You override a base class’s function by defining a function of the same name and signature in the derived class. You overload a function by defining a function of the same name but with a different signature. You override a base class’s function to extend or modify the behavior of the derived class and to hide the base class’s version. You overload functions to allow multiple methods to have the same descriptive name, but with different parameter requirements to provide an intuitive API.

If You Do Not Have a Constructor, One Will Be Appointed for You

The initial state of an object is set by its constructor function. Every object in Java has a constructor function, whether you coded one or not. If you do not code a constructor, Java creates one for you. So what’s the big deal, since Java seems to handle everything for you?

Understanding class construction becomes more important when you start using inheritance. When you create an object by invoking the New operator on a class’s constructor, that constructor’s code must call the constructor of its parent class. Why? Remember that you should not be concerned with the implementation details of parent objects. Also remember that private attributes and functions are not inherited. With that in mind, realize that a subclass’s constructor should not be required to set the initial state for fields found in all levels of its inheritance tree. That’s why the constructor of the parent

class must be called. Again, Java helps out because, if you don’t explicitly code a call to the parent’s constructor in your subclass’s constructor, Java will attempt to do it for you.

Implicit Class Construction

Earlier, I showed how Java’s Super keyword can be used to qualify fields and functions to be from a subclass’s parent: super.parentField. So it should make sense to you when I say that the qualification of a subclass’s parent’s constructor is super(). Now the tricky part: If the first statement in a subclass’s constructor is neither a call to super() nor a call to another overloaded constructor of the same class, then Java implicitly inserts a function call to super() as the first statement. For example, say you defined the following derived class:

class MyDerivedClass extends MyParentClass {
int I; MyDerivedClass() {

I = getIValue();

}

}

The Java compiler would create the Java byte code of the class with the
inclusion of a call to MyDerivedClass’s parent’s constructor:

MyDerivedClass() {

super();

I = getIValue();
}

Further, if you do not code a constructor, Java creates a default constructor for you that calls the class’s immediate ancestor’s constructor. If you let Java create constructors for you, don’t go looking around for the default constructor code. Just trust me that it will be in the *.CLASS byte code file. It will not be inserted into your *.JAVA source file. Nevertheless, the constructor code would look like this:

MyDerivedClass() {

Super();
}

As you can see, the Java-appointed default constructor of the derived class does nothing but invoke the constructor of the base class. The Java-created constructor always has an empty parameter list. A constructor function that has no arguments is known as a default constructor. Note that once you code your own constructor function (regardless of whether or not it takes any arguments), Java will no longer generate a default constructor for you.

Explicit Class Construction

So far, Java does it all for you. Again, you ask, “What’s the big deal? Whether I define a constructor or not, Java always seems to step in and call the parent’s constructor for me.” But Java can help only if you derive your class from a base class that has a default constructor. If you derive your class from a class that has an explicit constructor (which takes arguments) and that class does not also have a default constructor (one that takes no arguments), then Java can’t help. You must explicitly code your subclass to call that parameterized constructor.

Think of it this way: The designers of the superclass are forcing you to provide the parameters that the superclass requires to properly initialize itself. No matter; this is easily done with an explicit call using the super() function passing the appropriate parameter list:

super(argument1, argument2, ...);

The Shoulders of Giants

Your initial Java development efforts may not require the sophisticated design of hierarchical classes. What those initial efforts will require is the reuse of existing classes within standard packages such as Java’s Abstract Window Toolkit (AWT) and third-party classes like IBM’s Java Toolbox for the AS/400. When you first start to look at the classes that make up a package, you should also look at its accompanying online hypertext

documentation. Each class within the package has its own hypertext document that lists its public fields and functions.

For you to fully understand the use of a class, you should also look at the hypertext documentation of its superclass.

For instance, AWT has a GUI class called TextField that allows the entry of characters into a Windows component. You would expect the TextField class to define a method of retrieving its text with something like a getText function. But if you pull up the Java Development Kit’s (JDK) hypertext documentation for AWT’s TextField, you won’t find a function that retrieves TextField’s text. At the top of TextField’s hypertext document, however, you’ll see the inheritance tree for TextField. If you click on its parent TextComponent class to browse that class’s documentation, you’ll find the getText function. So TextField, by order of inheritance, also contains the getText function.

Inheritance allows us to create a new class based on an existing class without reimplementing the functionality of the existing class. We don’t even need to know the implementation details of the base class. Inheritance allows us to incrementally develop Java applications by introducing new classes without causing bugs in an application’s base classes. Further, Java’s innovative method of handling inheritance at runtime allows modified base classes to be moved into production without the recompilation of derived classes. As you develop Java classes by using inheritance, you are able to stand on the shoulders of the talented object designers who came before us.

References

Java Design. Coad, Peter and Mark Mayfield. Upper Saddle River: Yourdon Press,


1996.

Professional Java Fundamentals. Cohen, et al. Birmingham: WROX Press, 1996. Java in a Nutshell, 2nd Edition. Flanagan, David. Sebastopol: O’Reilly & Associates Inc., 1997.

The Java Language Specification. James Gosling, Bill Joy, and Guy Steele. Mountain View: Addison-Wesley. 1996




Figure 1: The PurchaseOrder system’s object model in UML notation



Object-_oriented_Design_for_AS-_400_Java_...208-00.png 900x724




Figure 2: The inheritance tree for Java’s BigDecimal class in UML notation


class superClass {

int theInt = 1;

int theFunc() { return 1;}

void print() {

System.out.print(“theInt: “+theInt+

“theFunc():”+theFunc());

}

public static void main(String[] argv) {

new superClass().print();

}

}

class subClass extends superClass {

int theInt = 2;



Object-_oriented_Design_for_AS-_400_Java_...209-00.png 899x960

int theFunc() { return 2; }

void print() {

System.out.print(“theInt:”+

theInt+” theFunc():”+theFunc());

System.out.print(“ super.theInt:”+

super.theInt+

“ super.theFunc():”

+super.theFunc());

}

public static void main(String[] argv) {

new subClass().print();

}

}

Figure 3: An example of the use of Java’s Super keyword to qualify a base class’s fields and functions

Don Denoncourt

Don Denoncourt is a freelance consultant. He can be reached at This email address is being protected from spambots. You need JavaScript enabled to view it..


MC Press books written by Don Denoncourt available now on the MC Press Bookstore.

Java Application Strategies for iSeries and AS/400 Java Application Strategies for iSeries and AS/400
Explore the realities of using Java to develop real-world OS/400 applications.
List Price $89.00

Now On Sale

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: