Chapter 6. Class Definitions

JavaFX Script is an object-oriented programming (OOP) language. Because it is built on the Java platform, JavaFX Script inherits almost all the features of Java, including those that support object orientation. We will start this chapter by examining some basic concepts of OOP, and later you will learn how to implement your own class in JavaFX Script.

Object-oriented programming languages were developed to correct some of the flaws programmers found with procedural languages; for example, typically they are not very flexible. In OOP data is treated as a critical element and not allowed to flow unrestrictedly. OOP binds data closely to the functions that operate on it and protects it from accidental modification by outside functions. OOP allows the decomposition of a problem into a number of entities called objects and then builds data and functions around these objects. Thanks to the use of objects, one of the advantages of using OOP is its reusability of code. OOP also has these basic advantages:

  • OOP provides a clear modular structure for programs, which makes it good for defining abstract data types in which implementation details are hidden and the unit has a clearly defined interface.

  • OOP makes it easy to maintain and modify existing code, as new objects can be created with small differences from existing ones.

  • Data is hidden and cannot be accessed by non-member functions.

Classes and Objects

Classes and objects are the two most important concepts of OOP, so we'll begin with a brief definition of each.

Classes

A class is a user-defined data type. It's a blueprint or prototype from which objects are created. A well-defined class demonstrates all or at least few of the features of OOP: data abstraction, encapsulation, polymorphism, and inheritance. We'll discuss these defining features shortly.

Objects

An object is an instance of a class, which replicates the real world object. For example, consider a computer. You see the computer as one unit, but it is built from many individual components —the motherboard, RAM, processor, hard disk, SMPS, and so on. Instead of looking at these individual components, you tend to look the whole. In the same a way, an object is made up of data members of the class.

Features of OOP

The object-oriented programming approach is defined by the following four features:

  • Data abstraction

  • Encapsulation

  • Polymorphism

  • Inheritance

Data Abstraction

Abstraction refers to the act of representing essential features without including the underlying details or explanations. Classes use the concept of abstraction and are defined as lists of abstract attributes.

Encapsulation

Encapsulation is the process of storing data and functions in a single unit and is achieved by declaring a class. It can also be called data hiding; since data cannot be accessible to the outside world, only those functions that reside within the class can access it. Encapsulation can be achieved by declaring packages and modules as well as classes.

Inheritance

Inheritance is the process by which an object belonging to one class can acquire the properties of another class. This is an important feature facilitating the reusability of code. It is achieved by deriving a new class from an existing class (base class). The new class (derived class) will have combined features of both the classes. In Chapter 8, "Inheritance," you will learn the types of inheritance and its implementation.

Polymorphism

Polymorphism is the ability of something to take more than one form. In OOP, the concept is exhibited in different behaviors in different instances, depending on the data types used in the operation (functions). Polymorphism is extensively used in implementing inheritance. It is also called function overloading, which you learned about in Chapter 5, "Functions."

The Class Definition

Now that you know what a class is, you can move on to learn how to define one. Figure 6-1 shows the structure of a class. As you can see, a class consists of data members and member functions. It may also contain optional init() and postinit() blocks, which we'll examine later in this chapter.

Classes contain data members and member functions

Figure 6.1. Classes contain data members and member functions

Class is a keyword, which tells the compiler that you are going to create a user-defined data type. Class-name is the name given to identify the class. The rules that applies to name a variable applies even for naming a class. The Opening and closing curly braces of the class contains the data members and the member functions

The access specifiers or modifiers that can be applied to a class declaration are package, protected, and public. You will learn all about access modifiers in Chapter 7, "Access Modifiers". Access to classes, data members, and member functions is regulated using access modifiers—a class can control what information or data can be accessible by other classes. To take advantage of encapsulation, you should minimize access whenever possible.

Data members are the attributes of the object and can have the access modifier package, protected, public public-read or public-init. If you don't specify an access modifier, then such data members of the class will have script-level access and can be accessed in other classes in the same file.

Member functions are the functions that reside within the class. Member functions have the ability to access any data members and other member functions of the class. You can specify the access modifiers package, protected, and public for member functions.

Finally, the init and postinit blocks shown in Figure 6-1 are optional. You will learn about these two optional parts of a class definition later in this chapter. Listing 6-1 demonstrates a class definition.

Example 6.1. A simple class definition

class Account {
    var accountNumber : Integer ;
    var accountHolderName : String;
    var balance : Number;

    function printAccountHolderInformation( ) {
        println("Account Number = {accountNumber}  Account Holder Name = {accountHolderName}  Balance : {balance} ");
        }
}

This example declares a class called Account, which contains three data members, accountNumber, accountHolderName, and balance, along with a single member function called printAccountHolderInformation(), which prints the data members of the class. With this we have defined the blueprint of the object or defined the user-defined data type.

Creating Object Literals

Creating an instance of our new class means allocating memory for the object in RAM (main memory). An instance of a class can be created in two ways; here's the first:

Syntax

var object_name : class_name = class_name{ };

This first syntax for creating a class instance is known as the JavaFX style. It is similar to declaring an ordinary variable. In this method, you specify that the object belongs to a particular class and then you create the instance.

The second method of creating the instance of the class is to use the Java style, creating the object using the new operator.

Syntax

var object_name : class_name = new class_name( );

Here, you are specifying that the object belongs to a particular class and then creating the object using the new operator.

Note

When creating an object of a class using JavaFX style, use curly braces after the class name (class_name{ }). By contrast, when you use Java style to create an object of a class, you'll use parentheses after the class name (class_name( )).

Now let us create the objects of the class Account in both JavaFX style and Java style:

var account1 : Account = Account{ };    // JavaFX style
var account2 : Account = new Account( ) ; // Java style

Both statements create instances of the class Account. Object account1 is created using JavaFX style and account2 is created using Java style. Note that we have not initialized the attributes explicitly, which means that all the attributes will take their default values, depending on the data type.

Initializing Class Attributes within an Object Literal

So far, you have learned how to declare a class and create objects that are instances of the class. Now let's initialize an object. Listing 6-2 shows the code.

Example 6.2. Initializing the attributes of the Account class

var account1 = Account{
    accountNumber : 121    //  initializing the data member
    accountHolderName : "Praveen"    //  initializing the data member
    balance : 56434.34    //  initializing the data member
};

In the above expression, we are creating the object account1 of class Account and initializing it. The data member of the object are initialized by the colon operator (:) followed by the value.

Calling the Members of the Class

Members of the class, which as you saw earlier may be either data members or member functions, are accessed using the dot (.) operator.

account1.name    // accessing datamember
        account1.printAccountHolderInformation( ); // accessing member function

In these statements, you are accessing the name data member of class Account through its object account1, and you are accessing member function printAccountHolderInformation() of the same Account class.

Assume you have created four objects. Memory is allocated for four objects, but the member functions are loaded only once in memory. All the objects share the member functions. Figure 6-2 illustrates this structure.

Data members of the class sharing the member function

Figure 6.2. Data members of the class sharing the member function

Now let's access the member function of the class Account using the objects account1 and account2:

account1.printAccountHolderInformation( );     //  calling the member function
account2.printAccountHolderInformation( );     //  calling the member function

Finally, let's put all the pieces together—class definition, object creation, and initialization—to form a complete JavaFX class. Listing 6-3 shows the code.

Note

In JavaFX Script, unlike Java, it is not mandatory that a public class name should be same as the filename; the class and filename can be different.

Example 6.3. The complete Account class

class Account {
    var accountNumber : Integer ;
    var accountHolderName : String;
    var balance : Number;
    function printAccountHolderInformation( ) {
        println("Account Number = {accountNumber} Account Holder Name = {accountHolderName} Balance : {balance} ");
    }
}
var account1 : Account = Account{ /*create an instance and initialize the object */
    accountNumber : 121
    accountHolderName : "Praveen"
    balance : 56434.34
};
var account2 = Account{} ; // create an instance
account1.printAccountHolderInformation( ); // calling the member function
account2.printAccountHolderInformation( ); // calling the member function

After executing Listing 6-3 you'll see the following output.

Output

------
account number = 121 Account Holder Name = Praveen  Balance : 56434.34
account number = 0 Account Holder Name =   Balance : 0.0

The output statement prints the details of the objects account1 and account2. In the output of account2, you can see that the value of account number is zero, the value of accountHolderName is null "", and balance is 0.0. This is because we have not initialized the data members of the object.

Assigning Default Values to Data Members

It is possible to set a default value for the data members of the class, if you don't initialize the object. If you initialize the object, then the default value is overridden.

var balance : Number = 500.0;     // 500.0 can be either dollars or any currency

In this assignment statement the data member balance of the Account class is initialized with 500.0. This is because the minimum balance of the newly opened account should have 500.0, whether rupees or dollars. If you modify the Account class example, Listing 6-3, by initializing the balance data member with the default value as shown in the assignment statement, executing the code will display the following output.

Output

------
Details of the account2        // just to denote that you are seeing the details of account2
account number = 0 Account Holder Name =   Balance : 500.0

The init Block

init is a keyword. It's an optional block; if present it is used to initialize the data member of the class, or you can add any initialization statements. You can consider the init block to be the constructor of the class. It is executed as the final step of instance initialization. The following init block shows how to initialize the balance data member of the class Account.

init {
    balance = 500.0;
}

Example 6.4. A class definition that includes an init block

1.    class Distance {
2.        var feet : Integer = 1;    // default value is 1
3.        var inches : Number = 0.0;
4.
5.        init {
6.            println("within init block..");
7.            println("Default value is overridden by object initialization");
8.            println("feet = {feet}  inches = {inches}");
9.            println("Overriding the default value printing the ");
10.            feet = 10;
11.            inches = 4.5;
12.            println("feet = {feet}  inches = {inches}");
13.        }
14.
15.        function showdist() : Void {
16.            println("feet = {feet } inches = {inches } ");
17.        }
18.    }
19.
20.    var dist1 : Distance = Distance {
21.        feet : 5
22.        inches : 10.5
23.    }
24.    println("calling the member function to print the value of data member");
25.    dist1.showdist() ;

Output

------
within init block..
Default value is overridden by object initialization
feet = 5  inches = 10.5
Overriding the default value printing the
feet = 10  inches = 4.5
calling the member function to print the value of data member
feet = 10 inches = 4.5

In Listing 6-4, we declare a Distance class, which has two data members, feet and inches (which have default values of 1 and 0.0, respectively), and a member function named showdist() to display the value of feet and inches. In line 20, the object dist1 is created and initialized. We assign feet a value of 5 and inches a value of 10.5. Because we have initialized the object dist1, the default values of feet and inches are overridden. Now feet holds the value of 5 and inches holds the value of 10.5. Next the JavaFX script runtime will execute the init block. The first statement of the init block is line 6, which is an output statement announcing that now you are in the init block. In line 8, the values of feet and inches are printed, 5 and 10.5. Next we modify the feet and inches values by 10 and 4.5, and then print the overridden value of the object initialization. When object dist1 calls the showDist() function, the modified value in the init block is printed.

Order of Instance Initialization

Based on the previous example, we can summarize the sequence in which instances of a class are initialized:

  1. Objects are created. If a default value is set, data member are initialized with it.

  2. If the object is initialized, then any default value is overridden.

  3. The init block is executed. If data members are set to a new value, then object initialization is overridden.

The postinit Block

As noted earlier, the postinit block is optional. It is executed after instance initialization has completed. Usually, you'll place code in postinit that has to be executed after the object is initialized. One of the best uses of a postinit block is to add event-handling code, such as keyevent() and mouseEvent() functions.

Syntax

postinit {
         //statements that is required after creation and initialization of the object.
       }

Modifying Class Objects

Now that you've seen what's included in a class definition, let's move on to working with class objects elsewhere in the code.

You can modify the objects of a class just like modifying any variable. The following two assignment statements show how to assign the value to data members of the class:

dist.feet = 6;
dist.inches =  7.11;

Let's modify the Distance class to modify the value of data member outside the class; Listing 6-5 shows the code.

Example 6.5. Modifying the value of a data member outside the class

1.    class Distance {
2.        var feet : Integer = 1;    // default value is 1
3.        var inches : Number = 0.0;
4.
5.        function showdist() : Void {
6.              println("feet = {feet } inches = {inches } ");
7.        }
8.    }
9.
10.    var dist1 : Distance = Distance {  // creating the object and initializing it
11.        feet : 5
12.        inches : 10.5
13.    }
14.    println("dist1 object value");
15.    dist1.showdist() ;
16.     dist1.feet = 8;        // modifying the feet data member
17.    dist1.inches = 11.5;    // modifying the inches data member
18.    println("dist1 object value after changing the data member");
19.    dist1.showdist() ;

Output

------
dist1 object value
feet = 5 inches = 10.5
dist1 object value after changing the data member
feet = 8 inches = 11.5

Here, the Distance class is modified from the previous example to demonstrate how to change a data member of an object. In line 10 we create the instance dist1 and it is initialized. In lines 16 and 17 the data members of the dist1 instance are modified. To verify that the data member of dist1 have been modified, we call the dist1.showdist() function, and the output shows the result.

Objects as Function Arguments

Not only is it common to have either simple variables or the data members of a class as arguments of the member function, it is also common to have the object itself as the function argument.

Let's modify the Distance class of the previous example to add a member function that takes the object as its argument. Listing 6-6 shows the code.

Example 6.6. A member function that takes an object as its argument

1.    class Distance {
2.        var feet : Integer = 0;
3.        var inches : Number = 0.0;
4.
5.        function showdist() : Void {
6.            println("feet = {feet } inches = {inches } ");
7.        }
8.
9.        public function addDistance(tempDist1:Distance,tempDist2:Distance ) : Void {
10.            inches = tempDist1.inches + tempDist2.inches;
11.             if(inches >= 12.0 ) {
12.                feet++;
13.                inches -= 12.0;
14.             }
15.             feet  = feet + tempDist1.feet + tempDist2.feet;
16.        }
17.    }
18.    var dist1 : Distance = Distance {
19.        feet : 5
20.        inches : 10.5
21.    }
22.    var dist2 : Distance = Distance {
23.        feet : 7
24.        inches : 6.65
25.    }
26.    println("The value of dist1 object ");
27.    dist1.showdist() ;
28.    println("The value of dist2 object ");
29.    dist2.showdist() ;
30.    var dist3 = Distance {};
31.    dist3.addDistance(dist1 , dist2);
32.    println("The value of dist3 object ");
33.    dist3.showdist() ;

In this example, we first create three objects, dist1, dist2 and dist3. Notice that dist1 and dist2 are initialized, so they have the default value. The dist3 object is not initialized. In line 31, dist3 calls the addDistance(dist1 , dist2) member function, which takes dist1 and dist2 as its arguments. When execution control goes to line 9, the dist1 and dist2 object values are passed to the formal parameters tempDist1 and tempDist2. We add the inches values of the formal parameters and assign the result to the variable inches, which is the data member of dist3. Since the dist3 object calls addDistance(dist1 , dist2), there is no need to specify dist3 to access the data member, as we do for tempDist1 to access its data member.

Non-Member Functions Accessing the Object

It is not mandatory that only a member function of a class can access its objects. In some situations, even functions that are not members can access the object. Listing 6-7 demonstrates how a non member function can access the objects of the class and return the object.

Example 6.7. A non-member function accessing class objects

1.    class Distance {
2.          var feet : Integer = 0;
3.          var inches : Number = 0.0;
4.          function showdist() : Void {
5.          println("feet = {feet } inches = {inches } ");
6.        }
7.    } //  end class
8.    /*  Non-member function */
9.    function addDistance(dist1: Distance , dist2 : Distance): Distance {
10.        var feet : Integer = dist1.feet + dist2.feet;
11.        var inches : Number = dist1.inches + dist2.inches;
12.        if(inches >= 12.0 ) {
13.            feet++;
14.            inches -= 12.0;
15.        }
16.        return Distance{ feet : feet  inches : inches }
17.  }
18.
19.    var dist1 : Distance = Distance {
20.        feet : 5
21.        inches : 10.5
22    }
23.    var dist2 : Distance = Distance {
24.        feet : 7
25.        inches : 6.65
26.    }
27.    println("The value of the dist1 object ");
28.    dist1.showdist() ;
29.    println("The value of the dist2 object ");
30.    dist2.showdist() ;
31.    var dist3 = addDistance(dist1 , dist2);
32.    println("The value of the dist3 object ");
33.    dist3.showdist() ;

Output

------
The value of the dist1 object
feet = 5 inches = 10.5
The value of the dist2 object
feet = 7 inches = 6.65
The value of the dist3 object
feet = 13 inches = 5.1499996

Listing 6-7 is a modified version of the previous example, Listing 6-6. Here we have pulled the addDistance function outside the class and make the member function return the object as the return value of the function.

Static Members

When you use script-level variables and script-level functions along with a class, the class can access those variables and functions as its own data members and member functions. This is because the script-level variables and functions become static within the class, and the instance of the class can also script variables and functions. Listing 6-8 shows an example; save the code as StaticMember.fx.

Example 6.8. Using script-level variables and functions as static members of a class

1.    var x : Integer = 14;
2.    function square() {
3.        x * x;
4.    }
5.
6.    class StaticMember {
7.        var dataMem : Integer = x;
8.
9.        function memberFunction(){
10.            println("square of {x} = {square()}");
11.        println(x);
12.        }
13.    }
14.
15.    var st = StaticMember{}; // instance of the class
16.    println("{st.x},  {st.dataMem }");    // 14,14
17.    StaticMember.x = 3;
18.    println("{st.x}, square: {st.square() }");    //9, square:  9
19.    st.memberFunction();
20.    st. dataMem = 99;
21.    println("{StaticMember.x}, {st.dataMem }");    //3, 99
22.    st = StaticMember {
23.        dataMem : 71717
24.    };
25.    println("{StaticMember.x},  {st.dataMem }");    //3, 71717

Output

------
14,  14
3, square: 9
square of 3 = 9
3
3, 99
3,  71717

In this example, you can see a script-level variable x and a script-level function named square() that returns the square of x. A class StaticMember has a data member dataMem, which contains the value of x (that is, the default value, which is the script-level variable's value). This indicates that that x is accessed inside the class as a static variable of the script. In the same code, the member function callingScrptLevelFunction() calls the square() function in line 10. Another interesting statement in this example is that the object or instance of the StaticMember class can access the x and dataMem variables in line 16 also in other places in the example.

Function Overloading Within a Class

Chapter 5, "Functions," introduced the concept of function overloading. This concept can also be applied to member functions. Since you already know about function overloading, let's go straight to an example of how it works with member functions. Listing 6-9 shows an example.

Example 6.9. Overloading a member function

class Circle {
    function draw(){
        println("Drawing a circle with the fixed x,y and the radius value");
    }
function draw(radius : Number){
        println("Drawing a circle with the fixed x,y value with the given radius of {radius}");
    }

    function draw(x : Number , y : Number){
        println("Drawing a circle with the given x = {x } ,y = { y} value with default value radius");
    }

    function draw(x : Number , y : Number , radius : Number){
        println("Drawing a circle with the given x = {x } ,y = { y} value with the given radius of {radius}");
    }
}
var fo : Circle = Circle{};
fo.draw();
fo.draw(10.0);
fo.draw(35.0,55.5);
fo.draw(35.0 , 55.0 , 10.25);

Output

------
Drawing a circle with the fixed x,y and the radius value
Drawing a circle with the fixed x,y value with the given radius of 10.0
Drawing a circle with the given x = 35.0 ,y = 55.5 value with default value radius
Drawing a circle with the given x = 35.0 ,y = 55.0 value with the given radius o
f 10.25

In this example, you can see that the class Circle has four member functions with the same function name, but they differ in their parameters; this is the function overloading. When you invoke each function JavaFX looks for the corresponding function name whose parameters match. If the match is found, it calls that function.

Sharing a Function Name Between Script-Level and Member Functions

It is possible for a script-level function and the member function of the class to share the same name. JavaFX Script determines which function to call by the context in which it is called.

if you want to call the member function, you need to call it through an instance or object of the class. By contrast, you call a script-level function directly by its name within the script. If you need to call a member function outside its class, you must call it using the script name or the file name Listing 6-10 shows an example.

Note

Although it's possible for a Script-level function and a member function to share a name, you should avoid this practice, as it may be confusing.

Example 6.10. A script-level function and a main function with the same name

1.    function sayHello( ){
2.        println("i am a script-level function..!");
3.    }
4.
5.    class MyClass {
6.        function sayHello( ){
7.            println("i am class member function..!");
8.        }
9.    }
10.    sayHello();
11.    var obj : MyClass = MyClass{}
12.    obj.sayHello( );
13    MyClass{}.sayHello();    // anonymous object calling the member function

Output

------
i am a script-level function..!
i am a class member function..!
i am class member function..!

In Listing 6-10, you can see that the script-level function and the member function have the same name, sayHello(). The script-level function is called directly by its name, as specified line 10. In line 12, the member function is called by an instance of the class. In line13, the member function is called using the anonymous object.

Note

An anonymous object is one that doesn't have a name. You can see the anonymous object calling the member function in line 13.

Calling a Java Method That Is a JavaFX Reserved Word

How do you call a method on a Java object whose name happens to be the same as a JavaFX Script reserved word? You learned about JavaFX Script reserved words, or keywords, in Chapter 3, "Data Types." You cannot directly use a reserved word to name a variable (as in var while;), class (such as class true {}), or other user-defined entity. You could, however, indiscriminately use reserved words to name your classes, functions, variables, and so on; but this would be unwise. Instead, the doubled angle brackets notation was introduced so that you can invoke Java object methods whose names happen to be reserved in JavaFX Script. For example, the following script uses this feature to invoke the java.lang.String class's replace() method.

var s = "abc def ghi";
s = s.<<replace>> ("def", "DEF");
println (s); // Output: abc DEF ghi

Output

abc DEF ghi

The abstract Class

An abstract class is one that is declared with the access modifier abstract. Like other classes, this type of class can have data members and member functions; but with a few functions that are not implemented (instead, you just specify the function prototype). These unimplemented functions are described as abstract functions. Because a class of this type is incomplete without implementing member functions, you cannot create an object of the class. To access the data members or the member functions of this class, you need to extend this class and implement the incomplete member function—the abstract function. You will learn more about extending classes in Chapter 8. Because this chapter is dedicated to classes, our purpose here is just to introduce you to abstract classes and functions. Listing 6-11 shows an example.

Example 6.11. Example of an abstract class

public abstract class   AbstractClassExample {
    var  x: Integer ;

        function  callMe( ) : Void  {     // implemented function
            println("Please call me also. ");
        }
        //unimplemented function
        public abstract function sayHello( ) : String;
    }

In this code, AbstractClassExample is an abstract class because it contains an abstract member function, sayHello().

Note

It is mandatory to specify the keyword abstract for both the abstract method and the class. Failing to specify either of these will result in a compilation error.

You will learn more about implementing abstract classes, interfaces, and other elements in Chapter 8.

Summary

In this chapter you learned the essentials of working with class definitions and other object-oriented features of JavaFX Script. Following are the main points to keep in mind:

  • A well defined class exhibits some or all features of OOP, including at a minimum data abstraction and encapsulation.

  • An object is an instance of the class. When a program is executed, objects interact with each other by sending messages.

  • The variables inside a class are called its data members and the functions inside the class are called member functions.

  • A member function can only access the data members of the class.

  • Objects of a class can be created using either JavaFX or Java style. The new operator is used to create an object in Java style.

  • The init block is optional and used to initialize the data member of the class. It is called after the objects are created and is the final stage of initializing the object.

  • The postinit block is optional and called after the object initialization is completed.

  • An abstract class is one that contains abstract functions. Therefore, it is not possible to create instances of an abstract class.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset