Topic 37: Additional Keywords in Java
When an instance variable is declared as transient, then its value need not persist when an object is stored. For example:
class T
{
transient int a; // will not persist
int b; // will persist
}
Here,
if an object of type T is written to a persistent storage area, the
contents of "a" would not be saved, but the contents of "b" would.
Variable
modified by volatile can be changed unexpectedly by other parts of the program. Specifying the variable as volatile tells the compiler that
it must always use the master copy of a volatile variable (or, at least,
always keep any private copies up-to-date with the master copy, and
vice versa). Used mostly in multithreaded programming.
Sometimes,
knowing the type of an object during run time is useful. For example, we might have one thread of execution that generates various types of
objects, and another thread that processes these objects. In this
situation, it might be useful for the processing thread to know the type
of each object when it receives it. The instanceof operator has this general form:
objref instanceof type
Here,
objref is a reference to an instance of a class, and type is a class
type. If objref is of the specified type or can be cast into the
specified type, then the instanceof operator evaluates to true.
Otherwise, its result is false. The
following program demonstrates instanceof:
// Demonstrate instanceof operator.
class A
{
int i, j;
}
class B
{
int i, j;
}
class C extends A
{
int k;
}
class InstanceOf
{
public static void main(String args[])
{
A a = new A();
B b = new B();
C c = new C();
if(a instanceof A)
System.out.println("a is instance of A");
if(b instanceof B)
System.out.println("b is instance of B");
if(c instanceof C)
System.out.println("c is instance of C");
if(c instanceof A)
System.out.println("c can be cast to A");
System.out.println();
// compare types of derived types
A ob = c; // A reference to c
System.out.println("ob now refers to c");
if(ob instanceof A)
System.out.println("ob can be cast to A");
System.out.println();
// all objects can be cast to Object
if(a instanceof Object)
System.out.println("a may be cast to Object");
if(b instanceof Object)
System.out.println("b may be cast to Object");
if(c instanceof Object)
System.out.println("c may be cast to Object");
}
}
By modifying a class or a method with strictfp, we ensure that floating-point calculations (and thus all truncations)
take place precisely as they did in earlier versions of Java. When
a class is modified by strictfp, all the methods in the class are also
modified by strictfp automatically. For example, the following fragment
tells Java to use the original floating-point model for calculations in all methods defined within MyClass:
strictfp class MyClass { //...
Frankly, most programmers never need to use strictfp, because it affects only a very small class of problems.
Keyword assert is used
during program development to create an assertion, which is a condition
that should be true during the execution of the program. For example,we might have a method that should always return a positive integer
value. We might test this by asserting that the return value is greater
than zero using an assert statement. At run time, if the condition
actually is true, no other action takes place. However, if the condition
is false, then an AssertionError is thrown. Assertions are often used
during testing to verify that some expected condition is actually met.
They are not usually used for released code.
The assert keyword has two forms. The first is shown here:
assert condition;
Here,
condition is an expression that must evaluate to a Boolean result. If
the result is true, then the assertion is true and no other action takes
place. If the condition is false, then the assertion fails and a
default AssertionError object is thrown.
The second form of assert is
shown here:
assert condition : expr;
In
this version, expr is a value that is passed to the AssertionError
constructor. This value is converted to its string format and displayed
if an assertion fails. Typically, we will specify a string for expr,
but any non-void expression is allowed as long as it defines a
reasonable string conversion.
Here is an example that uses assert. It
verifies that the return value of getnum( ) is positive.
// Demonstrate assert.
class AssertDemo
{
static int val = 3;
// Return an integer.
static int getnum()
{
return val--;
}
public static void main(String args[])
{
int n;
for(int i=0; i < 10; i++)
{
n = getnum();
assert n > 0; // will fail when n is 0
System.out.println("n is " + n);
}
}
}
To
enable assertion checking at run time, we must specify the -ea option.
For example, to enable assertions for AssertDemo, execute it using this
line:
java -ea AssertDemo
As
explained, we can specify the message displayed when an assertion
fails. For example, we can specify:
assert n > 0 : "n is
negative!";
One
important point to understand about assertions is that we must not
rely on them to perform any action actually required by the program. The
reason is that normally, released code will be run with assertions
disabled. For ex:
assert (n = getnum()) > 0; // This is not a good idea!
This works fine if assertions are enabled, it
will cause a malfunction when assertions are disabled, because the call
to getnum( ) will never be executed! In fact, n must now be
initialized, because the compiler will recognize that it might not be
assigned a value by the assert statement.
Assertions
are a good addition to Java because they streamline the type of error
checking that is common during development. For example, prior to
assert, if we wanted to verify that n was positive in the preceding
program, we had to use a sequence of code similar to this:
if(n < 0){System.out.println("n is negative!"); return; // or throw an exception}
With
assert, you need only one line of code. Furthermore, we don’t have to
remove the assert statements from our released code.
When
executing code, we can disable assertions by using the -da option. We can enable or disable a specific package by specifying its name after
the -ea or -da option. For example, to enable assertions in a package
called MyPack:
-ea:MyPack
To disable assertions in MyPack:
-da:MyPack
To enable or disable all subpackages of a package, follow the package name with three dots:
-ea:MyPack...
We can also specify a class with the -ea or -da option. For example, this enables AssertDemo individually:
-ea:AssertDemo
A new feature to Java called static import that expands the
capabilities of the import keyword. By following import with the keyword
static, an import statement can be used to import the static members of
a class or interface. When using static import, it is possible to
refer to static members directly by their names, without having to
qualify them with the name of their class.
To
understand the usefulness of static import, let’s begin with an example
that does not use it. The following code fragment computes the hypotenuse of a
right triangle. It uses two static methods from Java’s built-in math
class Math, which is part of java.lang. The first is Math.pow( ), which
returns a value raised to a specified power. The second is Math.sqrt( ),
which returns the square root of its argument.
// Notice how sqrt() and pow() must be qualified by their class name, which is Math.
hypot = Math.sqrt(Math.pow(side1, 2) + Math.pow(side2, 2));
Because
pow( ) and sqrt( ) are static methods, they must be called through the
use of their class’ name, Math. As
this simple example illustrates, having to specify the class name each
time pow( ) or sqrt( ) is used can grow tedious. We can use static
import in such cases:
import static java.lang.Math.sqrt;
import static java.lang.Math.pow;
class Hypot {//...
hypot = sqrt(pow(side1, 2) + pow(side2, 2));
There are two general forms of the import static statement:
The
first, brings into view a
single name. Its general form is shown here:
import static
pkg.type-name.static-member-name;
Here,
type-name is the name of a class or interface that contains the desired
static member. Its full package name is specified by pkg. The name of
the member is specified by static-member-name.
The
second form, imports all static members of a given class or interface.
Its general form is shown here:
import static pkg.type-name.*;
One
other point: in addition to importing the static members of classes and
interfaces defined by the Java API, we can also use static import to
import the static members of classes and interfaces that we create. If using a static member once or twice
in the program, it’s best not to import it. Static import is designed for those situations in which we are using a static member repeatedly, such as when performing a series
of mathematical computations.
When
working with overloaded constructors, it is sometimes useful for one
constructor to invoke another. In Java, this is accomplished by using
another form of the this keyword. The general form is shown here:
this(arg-list)
When
this( ) is executed, the overloaded constructor that matches the
parameter list specified by arg-list is executed first. The call to this( ) must be the first statement within the constructor. To
understand how this( ) can be used, let’s work through a short example.
First, consider the following class that does not use this( ):
class MyClass
{
int a, b;
// initialize a and b individually
MyClass(int i, int j) { a = i; b = j; }
// initialize a and b to the same value
MyClass(int i) { a = b = i; }
// give a and b default values of 0
MyClass( ) { a = b = 0; }
}
By using this( ), it is
possible to rewrite MyClass as shown here:
// initialize a and b individually
MyClass(int i, int j) { a = i; b = j; }
// initialize a and b to the same value
MyClass(int i)
{
this(i, i); // invokes MyClass(i, i)
}
// give a and b default values of 0
MyClass( )
{
this(0); // invokes MyClass(0)
}
In
this version of MyClass, the only constructor that actually assigns
values to the a and b fields is MyClass(int, int). The other two
constructors simply invoke that constructor (either directly or
indirectly) through this( ). For example, consider what happens when
this statement executes:
MyClass mc = new MyClass(8);
The
call to MyClass(8) causes this(8, 8) to be executed, which translates
into a call to MyClass(8, 8), because this is the version of the MyClass
constructor whose parameter list matches the arguments passed via this(
). Now, consider the following statement, which uses the default
constructor:
MyClass mc2 = new MyClass();
In
this case, this(0) is called. This causes MyClass(0) to be invoked
because it is the constructor with the matching parameter list. Of
course, MyClass(0) then calls MyClass(0, 0) as just described.
One
reason why invoking overloaded constructors through this( ) can be
useful is that it can prevent the unnecessary duplication of code.
Constructors that call this( ) will execute a bit slower
than those that contain all of their initialization code inline. This
is because the call and return mechanism used when the second
constructor is invoked adds overhead.
There are two restrictions when using this( ).
First, we cannot use any instance variable of the constructor’s class in a call to this( ).
Second, we cannot use super( ) and this( ) in the same
constructor because each must be the first statement in the constructor.
Click for NEXT article.
Please feel free to correct me by commenting your suggestions and feedback.
No comments:
Post a Comment