• Features of the Java Language, Object-oriented Programming
• Creating an Application in Java, Compiling and executing Applications in Java
• Program comments
• Primitive data types, Integer Data Types, Floating Point Data Types
• Reference Data types
• Arrays, single and multi-dimensional arrays
• Other reference types, classes, interfaces, enums and annotations
• Unicode escapes in Java source code
• Understanding super types and subtypes.
• Operators - Arithmetic, String concatenation, Relational, Logical, Bitwise, increment-decrement,
conditional, assignment, cast and instance of operators.
• Understanding the narrowing and widening conversions of numeric data types.
• Statements - if, if-else, switch-case, for, while, do-while, break, continue and return statements.
• Various members within a class
• instance variables
• methods and their overloading
• constructors and their overloading
• Garbage collector and finalize method
• static variables and methods
• initializer blocks and the class initializer blocks
1) Features of the Java Language, Object-oriented Programming.
Platform Independent
The concept of Write-once-run-anywhere (known as the Platform independent) is one of the important key feature of java language that makes java as the most powerful language. Not even a single language is idle to this feature but java is more closer to this feature. The programs written on one platform can run on any platform provided the platform must have the JVM.
Object Oriented
To be an Object Oriented language, any language must follow at least the four characteristics.
Robust
Java has the strong memory allocation and automatic garbage collection mechanism. It provides the powerful exception handling and type checking mechanism as compare to other programming languages. Compiler checks the program whether there any error and interpreter checks any run time error and makes the system secure from crash. All of the above features makes the java language robust.
Distributed
The widely used protocols like HTTP and FTP are developed in java. Internet programmers can call functions on these protocols and can get access the files from any remote machine on the internet rather than writing codes on their local system.
Portable
The feature Write-once-run-anywhere makes the java language portable provided that the system must have interpreter for the JVM. Java also have the standard data size irrespective of operating system or the processor. These features makes the java as a portable language.
Dynamic
While executing the java program the user can get the required files dynamically from a local drive or from a computer thousands of miles away from the user just by connecting with the Internet.
Secure
Java does not use memory pointers explicitly. All the programs in java are run under an area known as the sand box. Security manager determines the accessibility options of a class like reading and writing a file to the local disk. Java uses the public key encryption system to allow the java applications to transmit over the internet in the secure encrypted form. The bytecode Verifier checks the classes after loading.
Performance
Java uses native code usage, and lightweight process called threads. In the beginning interpretation of bytecode resulted the performance slow but the advance version of JVM uses the adaptive and just in time compilation technique that improves the performance.
Multithreaded
As we all know several features of Java like Secure, Robust, Portable, dynamic etc; you will be more delighted to know another feature of Java which is Multithreaded.
Java is also a Multithreaded programming language. Multithreading means a single program having different threads executing independently at the same time. Multiple threads execute instructions according to the program code in a process or a program. Multithreading works the similar way as multiple processes run on one computer.
Multithreading programming is a very interesting concept in Java. In multithreaded programs not even a single thread disturbs the execution of other thread. Threads are obtained from the pool of available ready to run threads and they run on the system CPUs. This is how Multithreading works in Java which you will soon come to know in details in later chapters.
Interpreted
We all know that Java is an interpreted language as well. With an interpreted language such as Java, programs run directly from the source code.
The interpreter program reads the source code and translates it on the fly into computations. Thus, Java as an interpreted language depends on an interpreter program.
The versatility of being platform independent makes Java to outshine from other languages. The source code to be written and distributed is platform independent.
Another advantage of Java as an interpreted language is its error debugging quality. Due to this any error occurring in the program gets traced. This is how it is different to work with Java.
Architecture Neutral
The term architectural neutral seems to be weird, but yes Java is an architectural neutral language as well. The growing popularity of networks makes developers think distributed. In the world of network it is essential that the applications must be able to migrate easily to different computer systems. Not only to computer systems but to a wide variety of hardware architecture and Operating system architectures as well. The Java compiler does this by generating byte code instructions, to be easily interpreted on any machine and to be easily translated into native machine code on the fly. The compiler generates an architecture-neutral object file format to enable a Java application to execute anywhere on the network and then the compiled code is executed on many processors, given the presence of the Java runtime system. Hence Java was designed to support applications on network. This feature of Java has thrived the programming language.
2) Creating an Application in Java, Compiling and executing Applications in Java.
a)Writing a Program
b) Compiling the Program
• Creating an Application in Java, Compiling and executing Applications in Java
• Program comments
• Primitive data types, Integer Data Types, Floating Point Data Types
• Reference Data types
• Arrays, single and multi-dimensional arrays
• Other reference types, classes, interfaces, enums and annotations
• Unicode escapes in Java source code
• Understanding super types and subtypes.
• Operators - Arithmetic, String concatenation, Relational, Logical, Bitwise, increment-decrement,
conditional, assignment, cast and instance of operators.
• Understanding the narrowing and widening conversions of numeric data types.
• Statements - if, if-else, switch-case, for, while, do-while, break, continue and return statements.
• Various members within a class
• instance variables
• methods and their overloading
• constructors and their overloading
• Garbage collector and finalize method
• static variables and methods
• initializer blocks and the class initializer blocks
1) Features of the Java Language, Object-oriented Programming.
Platform Independent
The concept of Write-once-run-anywhere (known as the Platform independent) is one of the important key feature of java language that makes java as the most powerful language. Not even a single language is idle to this feature but java is more closer to this feature. The programs written on one platform can run on any platform provided the platform must have the JVM.
Object Oriented
To be an Object Oriented language, any language must follow at least the four characteristics.
- Inheritance : It is the process of creating the new classes and using the behavior of the existing classes by extending them just to reuse the existing code and adding the additional features as needed.
- Encapsulation:
: It is the mechanism of combining the
information and providing the abstraction.
- Polymorphism:
: As the name suggest one name multiple
form, Polymorphism is the way of providing the different functionality by
the
functions having the same name based on the signatures of the methods. - Dynamic binding : Sometimes we don't have the knowledge of objects about their specific types while writing our code. It is the way of providing the maximum functionality to a program about the specific type at runtime.
Robust
Java has the strong memory allocation and automatic garbage collection mechanism. It provides the powerful exception handling and type checking mechanism as compare to other programming languages. Compiler checks the program whether there any error and interpreter checks any run time error and makes the system secure from crash. All of the above features makes the java language robust.
Distributed
The widely used protocols like HTTP and FTP are developed in java. Internet programmers can call functions on these protocols and can get access the files from any remote machine on the internet rather than writing codes on their local system.
Portable
The feature Write-once-run-anywhere makes the java language portable provided that the system must have interpreter for the JVM. Java also have the standard data size irrespective of operating system or the processor. These features makes the java as a portable language.
Dynamic
While executing the java program the user can get the required files dynamically from a local drive or from a computer thousands of miles away from the user just by connecting with the Internet.
Secure
Java does not use memory pointers explicitly. All the programs in java are run under an area known as the sand box. Security manager determines the accessibility options of a class like reading and writing a file to the local disk. Java uses the public key encryption system to allow the java applications to transmit over the internet in the secure encrypted form. The bytecode Verifier checks the classes after loading.
Performance
Java uses native code usage, and lightweight process called threads. In the beginning interpretation of bytecode resulted the performance slow but the advance version of JVM uses the adaptive and just in time compilation technique that improves the performance.
Multithreaded
As we all know several features of Java like Secure, Robust, Portable, dynamic etc; you will be more delighted to know another feature of Java which is Multithreaded.
Java is also a Multithreaded programming language. Multithreading means a single program having different threads executing independently at the same time. Multiple threads execute instructions according to the program code in a process or a program. Multithreading works the similar way as multiple processes run on one computer.
Multithreading programming is a very interesting concept in Java. In multithreaded programs not even a single thread disturbs the execution of other thread. Threads are obtained from the pool of available ready to run threads and they run on the system CPUs. This is how Multithreading works in Java which you will soon come to know in details in later chapters.
Interpreted
We all know that Java is an interpreted language as well. With an interpreted language such as Java, programs run directly from the source code.
The interpreter program reads the source code and translates it on the fly into computations. Thus, Java as an interpreted language depends on an interpreter program.
The versatility of being platform independent makes Java to outshine from other languages. The source code to be written and distributed is platform independent.
Another advantage of Java as an interpreted language is its error debugging quality. Due to this any error occurring in the program gets traced. This is how it is different to work with Java.
Architecture Neutral
The term architectural neutral seems to be weird, but yes Java is an architectural neutral language as well. The growing popularity of networks makes developers think distributed. In the world of network it is essential that the applications must be able to migrate easily to different computer systems. Not only to computer systems but to a wide variety of hardware architecture and Operating system architectures as well. The Java compiler does this by generating byte code instructions, to be easily interpreted on any machine and to be easily translated into native machine code on the fly. The compiler generates an architecture-neutral object file format to enable a Java application to execute anywhere on the network and then the compiled code is executed on many processors, given the presence of the Java runtime system. Hence Java was designed to support applications on network. This feature of Java has thrived the programming language.
2) Creating an Application in Java, Compiling and executing Applications in Java.
a)Writing a Program
//A Very Simple Example class Demo { public static void main(String[] args){ System.out.println("it's Demo"); } }
b) Compiling the Program
javac ExampleProgram.java
c) Running the programm
java demo (Note:- use here class name which have main method)
3) Program comments
* Single-Line Comments
/* Handle the condition. */
* Trailing Comments if (a == 2) { return TRUE; /* special case */ } else { return isPrime(a); /* works only for odd a */ * End-Of-Line Comments if (foo > 1) { // Do a double-flip. ... } else { return false; // Explain why here. } //if (bar > 1) { // // // Do a triple-flip. // ... //} //else { // return false; //} * Documentation Comments /** * The Example class provides ... */
4) Primitive data types, Integer Data Types, Floating Point Data Types
Primitive Data Types
int gear = 1;
int
, the Java programming language supports seven other primitive data types.
A primitive type is predefined by the language and is named by a
reserved keyword. Primitive values do not share state with other
primitive values. The eight primitive data types supported by the Java
programming language are:-
byte: The
byte
data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive). Thebyte
data type can be useful for saving memory in large arrays, where the memory savings actually matters. They can also be used in place ofint
where their limits help to clarify your code; the fact that a variable's range is limited can serve as a form of documentation.
-
short: The
short
data type is a 16-bit signed two's complement integer. It has a minimum value of -32,768 and a maximum value of 32,767 (inclusive). As withbyte
, the same guidelines apply: you can use ashort
to save memory in large arrays, in situations where the memory savings actually matters.
-
int: The
int
data type is a 32-bit signed two's complement integer. It has a minimum value of -2,147,483,648 and a maximum value of 2,147,483,647 (inclusive). For integral values, this data type is generally the default choice unless there is a reason (like the above) to choose something else. This data type will most likely be large enough for the numbers your program will use, but if you need a wider range of values, uselong
instead.
-
long: The
long
data type is a 64-bit signed two's complement integer. It has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807 (inclusive). Use this data type when you need a range of values wider than those provided byint
.
-
float: The
float
data type is a single-precision 32-bit IEEE 754 floating point. Its range of values is beyond the scope of this discussion, but is specified in the Floating-Point Types, Formats, and Values section of the Java Language Specification. As with the recommendations forbyte
andshort
, use afloat
(instead ofdouble
) if you need to save memory in large arrays of floating point numbers. This data type should never be used for precise values, such as currency. For that, you will need to use the java.math.BigDecimal class instead. Numbers and Strings coversBigDecimal
and other useful classes provided by the Java platform.
-
double: The
double
data type is a double-precision 64-bit IEEE 754 floating point. Its range of values is beyond the scope of this discussion, but is specified in the Floating-Point Types, Formats, and Values section of the Java Language Specification. For decimal values, this data type is generally the default choice. As mentioned above, this data type should never be used for precise values, such as currency.
-
boolean: The
boolean
data type has only two possible values:true
andfalse
. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its "size" isn't something that's precisely defined.
-
char: The
char
data type is a single 16-bit Unicode character. It has a minimum value of'\u0000'
(or 0) and a maximum value of'\uffff'
(or 65,535 inclusive).
String
object; for example, String s = "this is a string";
. String
objects are immutable, which means that once created, their values cannot be changed. The String
class is not technically a primitive data type, but considering the
special support given to it by the language, you'll probably tend to
think of it as such. You'll learn more about the String
class in
Simple Data Objects.byte | 0 | |
short | 0 | |
int | 0 | |
long | 0L | |
float | 0.0f | |
double | 0.0d | |
char | '\u0000' | |
String (or any object) | null | |
boolean | false |
Literals
You may have noticed that thenew
keyword isn't used
when initializing a variable of a primitive type. Primitive types are
special data types built into the language; they are not objects created
from a class. A literal is the source code representation of a
fixed value; literals are represented directly in your code without
requiring computation. As shown below, it's possible to assign a literal
to a variable of a primitive type:boolean result = true; char capitalC = 'C'; byte b = 100; short s = 10000; int i = 100000;
Integer Literals
An integer literal is of typelong
if it ends with the letter L
or l
; otherwise it is of type int
. It is recommended that you use the upper case letter L
because the lower case letter l
is hard to distinguish from the digit 1
.Values of the integral types
byte
, short
, int
, and long
can be created from int
literals. Values of type long
that exceed the range of int
can be created from long
literals. Integer literals can be expressed by these number systems:- Decimal: Base 10, whose digits consists of the numbers 0 through 9; this is the number system you use every day
- Hexadecimal: Base 16, whose digits consist of the numbers 0 through 9 and the letters A through F
- Binary: Base 2, whose digits consists of the numbers 0 and 1 (you can create binary literals in Java SE 7 and later)
0x
indicates hexadecimal and 0b
indicates binary:// The number 26, in decimal int decVal = 26; // The number 26, in hexadecimal int hexVal = 0x1a; // The number 26, in binary int binVal = 0b11010;
Floating-Point Literals
A floating-point literal is of typefloat
if it ends with the letter F
or f
; otherwise its type is double
and it can optionally end with the letter D
or d
.The floating point types (
float
and double
)
can also be expressed using E or e (for scientific notation), F or f
(32-bit float literal) and D or d (64-bit double literal; this is the
default and by convention is omitted).double d1 = 123.4; // same value as d1, but in scientific notation double d2 = 1.234e2; float f1 = 123.4f;
Character and String Literals
Literals of typeschar
and String
may
contain any Unicode (UTF-16) characters. If your editor and file system
allow it, you can use such characters directly in your code. If not, you
can use a "Unicode escape" such as '\u0108'
(capital C with circumflex), or "S\u00ED Se\u00F1or"
(Sí Señor in Spanish). Always use 'single quotes' for char
literals and "double quotes" for String
literals. Unicode escape sequences may be used elsewhere in a program (such as in field names, for example), not just in char
or String
literals.The Java programming language also supports a few special escape sequences for
char
and String
literals: \b
(backspace), \t
(tab), \n
(line feed), \f
(form feed), \r
(carriage return), \"
(double quote), \'
(single quote), and \\
(backslash).There's also a special
null
literal that can be used as a value for any reference type. null
may be assigned to any variable, except variables of primitive types. There's little you can do with a null
value beyond testing for its presence. Therefore, null
is often used in programs as a marker to indicate that some object is unavailable.Finally, there's also a special kind of literal called a class literal, formed by taking a type name and appending "
.class"
; for example, String.class
. This refers to the object (of type Class
) that represents the type itself.
Type
|
Representation
|
Range
|
---|---|---|
byte
|
8-bit, signed, two's complement
|
-128 to 127
|
short
|
16-bit, signed, two's complement
|
-32768 to 32767
|
int
|
32-bit, signed, two's complement
|
-2147483648 to 2147483647
|
long
|
64-bit, signed, two's complement
|
-9223372036854775808 to 9223372036854775807
|
char
|
16-bit, unsigned, Unicode
|
'\u0000' to '\uffff'
|
To/From
|
byte
|
char
|
short
|
int
|
long
|
---|---|---|---|---|---|
byte
|
Assignable
|
Cast needed
|
Cast needed
|
Cast needed
|
Cast needed
|
char
|
Cast needed
|
Assignable
|
Cast needed
|
Cast needed
|
Cast needed
|
short
|
Assignable
|
Cast needed
|
Assignable
|
Cast needed
|
Cast needed
|
int
|
Assignable
|
Assignable
|
Assignable
|
Assignable
|
Cast needed
|
long
|
Assignable
|
Assignable
|
Assignable
|
Assignable
|
Assignable
|
5) Reference Data types
The non-primitive data types in Java are objects and arrays. These non-primitive types are often called "reference types" because they are handled "by reference"--in other words, the address of the object or array is stored in a variable, passed to methods, and so on. By comparison, primitive types are handled "by value"--the actual primitive values are stored in variables and passed to methods.
In C, you can manipulate a value by reference by taking its
address with the & operator, and you can "dereference"
an address with the * and -> operators.
These operators do not exist in Java: primitive types are
always passed by value; arrays and objects are always
passed by reference.
Because objects are passed by reference, two different
variables may refer to the same object:
Button p, q; p = new Button(); // p refers to a Button object. q = p; // q refers to the same Button. p.setLabel("Ok"); // A change to the object through p... String s = q.getLabel(); // ...is also visible through q. // s now contains "Ok."
This is not true of primitive types, however:
int i = 3; // i contains the value 3. int j = i; // j contains a copy of the value in i. i = 2; // Changing i doesn't change j. // Now, i == 2 and j == 3.
Terminology: Pass by Reference
The statement that Java manipulates objects "by reference"
causes confusion for some programmers, because there are
several different meanings of "by reference" in common use.
Regardless of what we call it, it is important to understand
what Java does. Java works with references to objects. A
Java variable holds only a reference to an object, not the
object itself. When an object is passed to a method,
only a reference to the object is actually passed, not the
entire object. It is in this sense that Java manipulates
objects "by reference."
Some people use the term "pass by reference" to mean that a
reference to a variable is passed to a method. Java
does not do this. For example, it is not possible to
write a working swap() function like the following
in Java:
public void swap(Object a, Object b) { Object temp = a; a = b; b = temp; }
The method parameters a and b contain
references to objects, not addresses of variables. Thus,
while this swap() function does compile and run, it
has no effect except on its own local variables and
arguments.
To solve this terminology problem, perhaps we should say
that Java manipulates objects "by reference," but it passes
object references to methods "by value."
Copying Objects
Because reference types are not passed by value, assigning
one object to another in Java does not copy the value of the
object. It merely assigns a reference to the object.
Consider the following code:
Button a = new Button("Okay"); Button b = new Button("Cancel"); a = b;
After these lines are executed, the variable a
contains a reference to the object that b refers
to. The object that a used to refer to is lost.
To copy the data of one object into another object, use the
clone() method:
Vector b = new Vector; c = b.clone();
After these lines run, the variable c refers to an
object that is a duplicate of the object referred to by b.
Note that not all types support the clone() method.
Only classes that implement the Cloneable interface
may be cloned.
For more information on cloning objects,
look up java.lang.Cloneable and
java.lang.Object.clone
Arrays are also reference types, and assigning an array simply
copies a reference to the array. To actually copy the
values stored in an array, you must assign each of the
values individually or use the System.arraycopy()
method.
Checking Objects for Equality
Another implication of passing objects by reference is that
the == operator tests whether two variables refer to
the same object, not whether two objects contain the same
values. To actually test whether two separate objects are
the same, you must use a specially written method for that
object type (just as you might use strcmp() to
compare C strings
for equality). In Java, a number of
classes define an equals() method that you can use
to perform this test.
Java Has No Pointers
The referencing and dereferencing of objects is handled
for you automatically by Java. Java does not allow you to
manipulate pointers or memory addresses of any kind:
- It does not allow you to cast object or array references into integers or vice-versa.
- It does not allow you to do pointer arithmetic.
- It does not allow you to compute the size in bytes of any primitive type or object.
There are two reasons for these restrictions:
- Pointers are a notorious source of bugs. Eliminating them simplifies the language and eliminates many potential bugs.
- Pointers and pointer arithmetic could be used to sidestep Java's run-time checks and security mechanisms. Removing pointers allows Java to provide the security guarantees that it does.
To a C programmer, the lack of pointers and pointer
arithmetic may seem an odious restriction in Java. But once
you get used to the Java object-oriented programming model,
it no longer seems like a serious restriction at all. The
lack of pointers does mean that you probably can't do things
like write UNIX device drivers in Java (at least not without
using native methods written in C). But big deal--most of
us never have to do this kind of low-level programming
anyway.
null
The default value for variables of all reference types is
null. null is a reserved value that
indicates "an absence of reference"--i.e., that a variable
does not refer to any object or array.
In Java, null is a reserved keyword, unlike
NULL in C, where it is just a constant defined to be 0.
null is an exception to the strong typing rules of
Java--it may be assigned to any variable of reference type
(i.e., any variable which has a class, interface, or array as
its type).
null can't be cast to any primitive type, including
integral types and boolean. It shouldn't be
considered equal to zero (although it may be
implemented this way).
Reference Type Summary
The distinction between primitive types passed by value, and
objects and arrays passed by reference is a crucial one in
Java. Be sure you understand the following:
- All objects and arrays are handled by reference in Java. (Those object references are passed-by-value to methods, however.)
- The = and == operators assign and test references to objects. Use clone() and equals() to actually copy or test the objects themselves.
- The necessary referencing and dereferencing of objects and arrays is handled automatically by Java.
- A reference type can never be cast to a primitive type.
- A primitive type can never be cast to a reference type.
- There is no pointer arithmetic in Java.
- There is no sizeof operator in Java.
- null is a special value that means "no object" or indicates an absence of reference.
Primitives vs. References
- primitive types are the basic types of data
byte, short, int, long, float, double, boolean, char
- primitive variables store primitive values
- reference types are any instantiable class as well as arrays
String, Scanner, Random, Die, int[], String[]
, etc.- reference variables store addresses
Assignment
- copies the contents of RHS variable into LHS variable
- primitives: the primitive value is copied
- references: the address is copied
- implications: for references the object is not copied, it is shared (reference variables are aliases)
Comparisons (e.g. ==)
- compares the contents of the variables
- primitives: the primitive values are compared
- references: the addresses are compared
- implications: for references the contents of the objects are not compared
Passing Parameters
- terminology:
- formal parameter: the parameter variable that is listed (along with its type) in the method declaration
- actual parameter: the parameter that is given when the method is called
- copies the contents of actual parameter into the formal parameter (i.e.,
pass-by-value)
- primitives: the primitive value is copied
- references: the address is copied
- implications: for references the object is not copied, it is shared (i.e., actual parameter and formal parameter are aliases)
- primitives: changing the formal parameter's value doesn't affect the actual parameter's value
- references: changing the formal parameter's address doesn't affect the actual parameter's address but changing the formal parameter's object does change the actual parameter's object since they refer to the same object
Returning Values
- returns a result to where the method was called
- primitives: the primitive value is returned
- references: the address is returned
- recall: local variables and parameters are destroyed when the method finishes execution
- implications: a locally created object can survive if it is returned or if it is stored in a data member
6) Arrays, single and multi-dimensional arrays
Array Types
Array types are the second kind of reference types in Java. An array is an ordered collection, or numbered list, of values. The values can be primitive values, objects, or even other arrays, but all of the values in an array must be of the same type. The type of the array is the type of the values it holds, followed by the characters []. For example:For compatibility with C and C++, Java also supports another syntax for declaring variables of array type. In this syntax, one or more pairs of square brackets follow the name of the variable, rather than the name of the type:byte b; // byte is a primitive type byte[] arrayOfBytes; // byte[] is an array type: array of byte byte[][] arrayOfArrayOfBytes; // byte[][] is another type: array of byte[] Point[] points; // Point[] is an array of Point objects
This is almost always a confusing syntax, however, and it is not recommended.byte arrayOfBytes[]; // Same as byte[] arrayOfBytes byte arrayOfArrayOfBytes[][]; // Same as byte[][] arrayOfArrayOfBytes byte[] arrayOfArrayOfBytes[]; // Ugh! Same as byte[][] arrayOfArrayOfBytes
With classes and objects, we have separate terms for the type and the values of that type. With arrays, the single word array does double duty as the name of both the type and the value. Thus, we can speak of the array type int[] (a type) and an array of int (a particular array value). In practice, it is usually clear from context whether a type or a value is being discussed.
* Creating Arrays
To create an array value in Java, you use the new keyword, just as you do to create an object. Arrays don't need to be initialized like objects do, however, so you don't pass a list of arguments between parentheses. What you must specify, though, is how big you want the array to be. If you are creating a byte[], for example, you must specify how many byte values you want it to hold. Array values have a fixed size in Java. Once an array is created, it can never grow or shrink. Specify the desired size of your array as a non-negative integer between square brackets:When you create an array with this syntax, each of the values held in the array is automatically initialized to its default value. This is false for boolean values, '\u0000' for char values, 0 for integer values, 0.0 for floating-point values, and null for objects or array values.byte[] buffer = new byte[1024]; String[] lines = new String[50];
* Using Arrays
Once you've created an array with the new operator and the square-bracket syntax, you also use square brackets to access the individual values contained in the array. Remember that an array is an ordered collection of values. The elements of an array are numbered sequentially, starting with 0. The number of an array element refers to the element. This number is often called the index, and the process of looking up a numbered value in an array is sometimes called indexing the array.To refer to a particular element of an array, simply place the index of the desired element in square brackets after the name of the array. For example:
In some programming languages, such as C and C++, it is a common bug to write code that tries to read or write array elements that are past the end of the array. Java does not allow this. Every time you access an array element, the Java interpreter automatically checks that the index you have specified is valid. If you specify a negative index or an index that is greater than the last index of the array, the interpreter throws an exception of type ArrayIndexOutOfBoundsException. This prevents you from reading or writing nonexistent array elements.String[] responses = new String[2]; // Create an array of two strings responses[0] = "Yes"; // Set the first element of the array responses[1] = "No"; // Set the second element of the array // Now read these array elements System.out.println(question + " (" + responses[0] + "/" + responses[1] + " ): ");
Array index values are integers; you cannot index an array with a floating-point value, a boolean, an object, or another array. char values can be converted to int values, so you can use characters as array indexes. Although long is an integer data type, long values cannot be used as array indexes. This may seem surprising at first, but consider that an int index supports arrays with over two billion elements. An int[] with this many elements would require eight gigabytes of memory. When you think of it this way, it is not surprising that long values are not allowed as array indexes.
Besides setting and reading the value of array elements, there is one other thing you can do with an array value. Recall that whenever we create an array, we must specify the number of elements the array holds. This value is referred to as the length of the array; it is an intrinsic property of the array. If you need to know the length of the array, append .length to the array name:
.length is special Java syntax for arrays. An expression like a.length looks as though it refers to a field of an object a, but this is not actually the case. The .length syntax can be used only to read the length of an array. It cannot be used to set the length of an array (because, in Java, an array has a fixed length that can never change).if (errorCode < errorMessages.length) System.out.println(errorMessages[errorCode]);
In the previous example, the array index within square brackets is a variable, not an integer literal. In fact, arrays are most often used with loops, particularly for loops, where they are indexed using a variable that is incremented or decremented each time through the loop:
In Java, the first element of an array is always element number 0. If you are accustomed to a programming language that numbers array elements beginning with 1, this will take some getting used to. For an array a, the first element is a[0], the second element is a[1], and the last element is:int[] values; // Array elements initialized elsewhere int total = 0; // Store sum of elements here for(int i = 0; i < values.length; i++) // Loop through array elements total += values[i]; // Add them up
a[a.length - 1] // The last element of any array named a
* Array Literals
The null literal used to represent the absence of an object can also be used to represent the absence of an array. For example:In addition to the null literal, Java also defines special syntax that allows you to specify array values literally in your programs. There are actually two different syntaxes for array literals. The first, and more commonly used, syntax can be used only when declaring a variable of array type. It combines the creation of the array object with the initialization of the array elements:char[] password = null;
This creates an array that contains the eight int elements listed within the curly braces. Note that we don't use the new keyword or specify the type of the array in this array literal syntax. The type is implicit in the variable declaration of which the initializer is a part. Also, the array length is not specified explicitly with this syntax; it is determined implicitly by counting the number of elements listed between the curly braces. There is a semicolon following the close curly brace in this array literal. This is one of the fine points of Java syntax. When curly braces delimit classes, methods, and compound statements, they are not followed by semicolons. However, for this array literal syntax, the semicolon is required to terminate the variable declaration statement.int[] powersOfTwo = {1, 2, 4, 8, 16, 32, 64, 128};
The problem with this array literal syntax is that it works only when you are declaring a variable of array type. Sometimes you need to do something with an array value (such as pass it to a method) but are going to use the array only once, so you don't want to bother assigning it to a variable. In Java 1.1 and later, there is an array literal syntax that supports this kind of anonymous arrays (so called because they are not assigned to variables, so they don't have names). This kind of array literal looks as follows:
With this syntax, you use the new keyword and specify the type of the array, but the length of the array is not explicitly specified.// Call a method, passing an anonymous array literal that contains two strings String response = askQuestion("Do you want to quit?", new String[] {"Yes", "No"}); // Call another method with an anonymous array (of anonymous objects) double d = computeAreaOfTriangle(new Point[] { new Point(1,2), new Point(3,4), new Point(3,2) });
It is important to understand that the Java Virtual Machine architecture does not support any kind of efficient array initialization. In other words, array literals are created and initialized when the program is run, not when the program is compiled. Consider the following array literal:
This is compiled into Java byte codes that are equivalent to:int[] perfectNumbers = {6, 28};
Thus, if you want to include a large amount of data in a Java program, it may not be a good idea to include that data literally in an array, since the Java compiler has to create lots of Java byte codes to initialize the array, and then the Java interpreter has to laboriously execute all that initialization code. In cases like this, it is better to store your data in an external file and read it into the program at runtime.int[] perfectNumbers = new int[2]; perfectNumbers[0] = 6; perfectNumbers[1] = 28;
The fact that Java does all array initialization explicitly at runtime has an important corollary, however. It means that the elements of an array literal can be arbitrary expressions that are computed at runtime, rather than constant expressions that are resolved by the compiler. For example:
Point[] points = { circle1.getCenterPoint(), circle2.getCenterPoint() };
* Multidimensional Arrays
As we've seen, an array type is simply the element type followed by a pair of square brackets. An array of char is char[], and an array of arrays of char is char[][]. When the elements of an array are themselves arrays, we say that the array is multidimensional. In order to work with multidimensional arrays, there are a few additional details you must understand.Imagine that you want to use a multidimensional array to represent a multiplication table:
Each of the pairs of square brackets represents one dimension, so this is a two-dimensional array. To access a single int element of this two-dimensional array, you must specify two index values, one for each dimension. Assuming that this array was actually initialized as a multiplication table, the int value stored at any given element would be the product of the two indexes. That is, products[2][4] would be 8, and products[3][7] would be 21.int[][] products; // A multiplication table
To create a new multidimensional array, use the new keyword and specify the size of both dimensions of the array. For example:
In some languages, an array like this would be created as a single block of 100 int values. Java does not work this way. This line of code does three things:int[][] products = new int[10][10];
-
Declares a variable named products
to hold an array of arrays of int.
-
Creates a 10-element array to hold 10 arrays of
int.
-
Creates 10 more arrays, each of which is a 10-element
array of int. It assigns each of these
10 new arrays to the elements of the initial array. The
default value of every int element
of each of these 10 new arrays is 0.
The new keyword performs this additional initialization automatically for you. It works with arrays with more than two dimensions as well:int[][] products = new int[10][]; // An array to hold ten int[] values. for(int i = 0; i < 10; i++) // Loop ten times... products[i] = new int[10]; // ...and create ten arrays.
When using new with multidimensional arrays, you do not have to specify a size for all dimensions of the array, only the leftmost dimension or dimensions. For example, the following two lines are legal:float[][][] globalTemperatureData = new float[360][180][100];
The first line creates a single-dimensional array, where each element of the array can hold a float[][]. The second line creates a two-dimensional array, where each element of the array is a float[]. If you specify a size for only some of the dimensions of an array, however, those dimensions must be the leftmost ones. The following lines are not legal:float[][][] globalTemperatureData = new float[360][][]; float[][][] globalTemperatureData = new float[360][180][];
Like a one-dimensional array, a multidimensional array can be initialized using an array literal. Simply use nested sets of curly braces to nest arrays within arrays. For example, we can declare, create, and initialize a 5×5 multiplication table like this:float[][][] globalTemperatureData = new float[360][][100]; // Error! float[][][] globalTemperatureData = new float[][180][100]; // Error!
Or, if you want to use a multidimensional array without declaring a variable, you can use the anonymous initializer syntax:int[][] products = { {0, 0, 0, 0, 0}, {0, 1, 2, 3, 4}, {0, 2, 4, 6, 8}, {0, 3, 6, 9, 12}, {0, 4, 8, 12, 16} };
When you create a multidimensional array using the new keyword, you always get a rectangular array: one in which all the array values for a given dimension have the same size. This is perfect for rectangular data structures, such as matrixes. However, because multidimensional arrays are implemented as arrays of arrays in Java, instead of as a single rectangular block of elements, you are in no way constrained to use rectangular arrays. For example, since our multiplication table is symmetrical about the diagonal from top left to bottom right, we can represent the same information in a nonrectangular array with fewer elements:boolean response = bilingualQuestion(question, new String[][] { { "Yes", "No" }, { "Oui", "Non" }});
When working with multidimensional arrays, you'll often find yourself using nested loops to create or initialize them. For example, you can create and initialize a large triangular multiplication table as follows:int[][] products = { {0}, {0, 1}, {0, 2, 4}, {0, 3, 6, 9}, {0, 4, 8, 12, 16} };
int[][] products = new int[12][]; // An array of 12 arrays of int. for(int row = 0; row < 12; row++) { // For each element of that array, products[row] = new int[row+1]; // allocate an array of int. for(int col = 0; col < row+1; col++) // For each element of the int[], products[row][col] = row * col; // initialize it to the product. }
7) Other reference types, classes, interfaces, enums and annotations
Reference Types
Java is an object-oriented language. An object is a collection
of variables and associated methods that is described by a class.
The concepts in this section that relate to objects
are discussed in detail in Object-Orientation Java Style.
The name of a class can be used as a type, so you can declare
an object-type variable or specify that a method returns an object.
If you declare a variable using the name of a class for its type,
that variable can contain a reference
to an object of that class. Such a variable does not contain
an actual object, but rather a reference to the class instance,
or object, the variable refers to. Because using a class name as
a type declares a reference to an object, such types are called
reference types. Java also allows the use of
an interface name to specify a reference type. In addition, array
types in Java are reference types because Java treats arrays as
objects.
The two main characteristics of objects in Java are that:
- Objects are always dynamically allocated. The lifetime of the storage occupied by an object is determined by the program's logic, not by the lifetime of a procedure call or the boundaries of a block. The lifetime of the storage occupied by an object refers to the span of time that begins when the object is created and ends at the earliest time it can be freed by the garbage collector.
- Objects are not contained by variables. Instead, a variable contains a reference to an object. A reference is similar to what is called a pointer in other languages. If there are two variables of the same reference type and one variable is assigned to the other, both variables refer to the same object. If the information in that object is changed, the change is visible through both variables.
Java references are very similar to pointers in C/C++, but
they are not at all related to the C++ notion
of a reference. The main difference between Java references and
C++ pointers is that Java does not allow any arithmetic to be done
with references. This, coupled with Java's lack of any way to explicitly
deallocate the storage used by reference type values, guarantees
that a reference can never point to an illegal address.
Class Types
The name of a class can be used to specify the type of a
reference. If a variable is declared as a class type, the variable either
contains null or a reference to an object of
that class or a subclass of that class. It is not allowed to contain
any other kinds of values. For example:
class Shape { ... } class Triangle extends Shape { ... } ... Shape s; Triangle t; ... s = t;
This example declares a class called Shape
and a subclass of Shape called Triangle.
The code later declares a reference variable called s
that can contain a reference to a Shape object
and another variable
called t that can contain a reference to a Triangle
object. The value of s can be assigned to the
value of t because an object is not only an instance
of its declared class, but also an instance of every superclass
of its declared class. Since instances of the Triangle
class are also instances of its superclass Shape,
the Java compiler has no problem with s = t.
However, saying t = s generates an error
message from the compiler. Java does not allow a reference variable
declared as a class type to contain a reference to a superclass
of the declared class. The assignment t = s is
illegal because Shape is a superclass of Triangle. The assignment can be accomplished if s
is first cast to a reference to Triangle:
t = (Triangle)s;
The cast operation ensures that the object referenced
by s is a class type that is either
Triangle
or a descendant of Triangle. When you cast an
object reference to a subclass of the reference type, you are saying
that you want to treat the object being referenced as an instance
of the specified subclass. If the compiler cannot determine whether
the argument of a cast will be of the required type, the compiler
generates runtime code that ensures that the argument really is
an instance of the specified subclass. At runtime, if the class
of the object being referenced is not an instance of the specified
subclass, a ClassCastException is thrown.
Examining Enums
-
Class.isEnum()
- Indicates whether this class represents an enum type
-
Class.getEnumConstants()
- Retrieves the list of enum constants defined by the enum in the order they're declared
-
java.lang.reflect.Field.isEnumConstant()
- Indicates whether this field represents an element of an enumerated type
values()
on the enum. If an instance of an enum type is not available the only way to get a list of the possible values is to invoke
Class.getEnumConstants()
since it is impossible to instantiate an enum type.Given a fully qualified name, the
EnumConstants
example shows how to retrieve an ordered list of constants in an enum using
Class.getEnumConstants()
.import java.util.Arrays; import static java.lang.System.out; enum Eon { HADEAN, ARCHAEAN, PROTEROZOIC, PHANEROZOIC } public class EnumConstants { public static void main(String... args) { try { Class<?> c = (args.length == 0 ? Eon.class : Class.forName(args[0])); out.format("Enum name: %s%nEnum constants: %s%n", c.getName(), Arrays.asList(c.getEnumConstants())); if (c == Eon.class) out.format(" Eon.values(): %s%n", Arrays.asList(Eon.values())); // production code should handle this exception more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } }
$ java EnumConstants java.lang.annotation.RetentionPolicy Enum name: java.lang.annotation.RetentionPolicy Enum constants: [SOURCE, CLASS, RUNTIME]
$ java EnumConstants java.util.concurrent.TimeUnit Enum name: java.util.concurrent.TimeUnit Enum constants: [NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS]
Class.getEnumConstants()
is identical to the value returned by invoking values()
on an enum type.$ java EnumConstants Enum name: Eon Enum constants: [HADEAN, ARCHAEAN, PROTEROZOIC, PHANEROZOIC] Eon.values(): [HADEAN, ARCHAEAN, PROTEROZOIC, PHANEROZOIC]
For Interface Please Go to unit 2;
7) Unicode escapes in Java source code
java.util.regex
Class Pattern
java.lang.Object java.util.regex.Pattern
- All Implemented Interfaces:
- Serializable
public final class Pattern
- extends Object
- implements Serializable
A regular expression, specified as a string, must first be compiled into an instance of this class. The resulting pattern can then be used to create a
Matcher
object that can match arbitrary
character sequences
against the regular
expression. All of the state involved in performing a match resides in the
matcher, so many matchers can share the same pattern.
A typical invocation sequence is thus
APattern p = Pattern.compile
("a*b"); Matcher m = p.matcher
("aaaaab"); boolean b = m.matches
();
matches
method is defined by this class as a
convenience for when a regular expression is used just once. This method
compiles an expression and matches an input sequence against it in a single
invocation. The statement
is equivalent to the three statements above, though for repeated matches it is less efficient since it does not allow the compiled pattern to be reused. Instances of this class are immutable and are safe for use by multiple concurrent threads. Instances of theboolean b = Pattern.matches("a*b", "aaaaab");
Matcher
class are not safe for
such use.
Summary of regular-expression constructs
Construct | Matches |
---|---|
Characters | |
x | The character x |
\\ | The backslash character |
\0n | The character with octal value 0n (0 <= n <= 7) |
\0nn | The character with octal value 0nn (0 <= n <= 7) |
\0mnn | The character with octal value 0mnn (0 <= m <= 3, 0 <= n <= 7) |
\xhh | The character with hexadecimal value 0xhh |
\uhhhh | The character with hexadecimal value 0xhhhh |
\t | The tab character ('\u0009') |
\n | The newline (line feed) character ('\u000A') |
\r | The carriage-return character ('\u000D') |
\f | The form-feed character ('\u000C') |
\a | The alert (bell) character ('\u0007') |
\e | The escape character ('\u001B') |
\cx | The control character corresponding to x |
Character classes | |
[abc] | a, b, or c (simple class) |
[^abc] | Any character except a, b, or c (negation) |
[a-zA-Z] | a through z or A through Z, inclusive (range) |
[a-d[m-p]] | a through d, or m through p: [a-dm-p] (union) |
[a-z&&[def]] | d, e, or f (intersection) |
[a-z&&[^bc]] | a through z, except for b and c: [ad-z] (subtraction) |
[a-z&&[^m-p]] | a through z, and not m through p: [a-lq-z](subtraction) |
Predefined character classes | |
. | Any character (may or may not match line terminators) |
\d | A digit: [0-9] |
\D | A non-digit: [^0-9] |
\s | A whitespace character: [ \t\n\x0B\f\r] |
\S | A non-whitespace character: [^\s] |
\w | A word character: [a-zA-Z_0-9] |
\W | A non-word character: [^\w] |
POSIX character classes (US-ASCII only) | |
\p{Lower} | A lower-case alphabetic character: [a-z] |
\p{Upper} | An upper-case alphabetic character:[A-Z] |
\p{ASCII} | All ASCII:[\x00-\x7F] |
\p{Alpha} | An alphabetic character:[\p{Lower}\p{Upper}] |
\p{Digit} | A decimal digit: [0-9] |
\p{Alnum} | An alphanumeric character:[\p{Alpha}\p{Digit}] |
\p{Punct} | Punctuation: One of !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ |
\p{Graph} | A visible character: [\p{Alnum}\p{Punct}] |
\p{Print} | A printable character: [\p{Graph}\x20] |
\p{Blank} | A space or a tab: [ \t] |
\p{Cntrl} | A control character: [\x00-\x1F\x7F] |
\p{XDigit} | A hexadecimal digit: [0-9a-fA-F] |
\p{Space} | A whitespace character: [ \t\n\x0B\f\r] |
java.lang.Character classes (simple java character type) | |
\p{javaLowerCase} | Equivalent to java.lang.Character.isLowerCase() |
\p{javaUpperCase} | Equivalent to java.lang.Character.isUpperCase() |
\p{javaWhitespace} | Equivalent to java.lang.Character.isWhitespace() |
\p{javaMirrored} | Equivalent to java.lang.Character.isMirrored() |
Classes for Unicode blocks and categories | |
\p{InGreek} | A character in the Greek block (simple block) |
\p{Lu} | An uppercase letter (simple category) |
\p{Sc} | A currency symbol |
\P{InGreek} | Any character except one in the Greek block (negation) |
[\p{L}&&[^\p{Lu}]] | Any letter except an uppercase letter (subtraction) |
Boundary matchers | |
^ | The beginning of a line |
$ | The end of a line |
\b | A word boundary |
\B | A non-word boundary |
\A | The beginning of the input |
\G | The end of the previous match |
\Z | The end of the input but for the final terminator, if any |
\z | The end of the input |
Greedy quantifiers | |
X? | X, once or not at all |
X* | X, zero or more times |
X+ | X, one or more times |
X{n} | X, exactly n times |
X{n,} | X, at least n times |
X{n,m} | X, at least n but not more than m times |
Reluctant quantifiers | |
X?? | X, once or not at all |
X*? | X, zero or more times |
X+? | X, one or more times |
X{n}? | X, exactly n times |
X{n,}? | X, at least n times |
X{n,m}? | X, at least n but not more than m times |
Possessive quantifiers | |
X?+ | X, once or not at all |
X*+ | X, zero or more times |
X++ | X, one or more times |
X{n}+ | X, exactly n times |
X{n,}+ | X, at least n times |
X{n,m}+ | X, at least n but not more than m times |
Logical operators | |
XY | X followed by Y |
X|Y | Either X or Y |
(X) | X, as a capturing group |
Back references | |
\n | Whatever the nth capturing group matched |
Quotation | |
\ | Nothing, but quotes the following character |
\Q | Nothing, but quotes all characters until \E |
\E | Nothing, but ends quoting started by \Q |
Special constructs (non-capturing) | |
(?:X) | X, as a non-capturing group |
(?idmsux-idmsux) | Nothing, but turns match flags on - off |
(?idmsux-idmsux:X) | X, as a non-capturing group with the given flags on - off |
(?=X) | X, via zero-width positive lookahead |
(?!X) | X, via zero-width negative lookahead |
(?<=X) | X, via zero-width positive lookbehind |
(?<!X) | X, via zero-width negative lookbehind |
(?>X) | X, as an independent, non-capturing group |
Backslashes, escapes, and quoting
The backslash character ('\') serves to introduce escaped constructs, as defined in the table above, as well as to quote characters that otherwise would be interpreted as unescaped constructs. Thus the expression \\ matches a single backslash and \{ matches a left brace.It is an error to use a backslash prior to any alphabetic character that does not denote an escaped construct; these are reserved for future extensions to the regular-expression language. A backslash may be used prior to a non-alphabetic character regardless of whether that character is part of an unescaped construct.
Backslashes within string literals in Java source code are interpreted as required by the Java Language Specification as either Unicode escapes or other character escapes. It is therefore necessary to double backslashes in string literals that represent regular expressions to protect them from interpretation by the Java bytecode compiler. The string literal "\b", for example, matches a single backspace character when interpreted as a regular expression, while "\\b" matches a word boundary. The string literal "\(hello\)" is illegal and leads to a compile-time error; in order to match the string (hello) the string literal "\\(hello\\)" must be used.
Character Classes
Character classes may appear within other character classes, and may be composed by the union operator (implicit) and the intersection operator (&&). The union operator denotes a class that contains every character that is in at least one of its operand classes. The intersection operator denotes a class that contains every character that is in both of its operand classes.The precedence of character-class operators is as follows, from highest to lowest:
Note that a different set of metacharacters are in effect inside a character class than outside a character class. For instance, the regular expression . loses its special meaning inside a character class, while the expression - becomes a range forming metacharacter.
1 Literal escape \x 2 Grouping [...] 3 Range a-z 4 Union [a-e][i-u] 5 Intersection [a-z&&[aeiou]]
Line terminators
A line terminator is a one- or two-character sequence that marks the end of a line of the input character sequence. The following are recognized as line terminators:- A newline (line feed) character ('\n'),
- A carriage-return character followed immediately by a newline character ("\r\n"),
- A standalone carriage-return character ('\r'),
- A next-line character ('\u0085'),
- A line-separator character ('\u2028'), or
- A paragraph-separator character ('\u2029).
UNIX_LINES
mode is activated, then the only line terminators
recognized are newline characters.
The regular expression . matches any character except a line terminator unless the
DOTALL
flag is specified.
By default, the regular expressions ^ and $ ignore line terminators and only match at the beginning and the end, respectively, of the entire input sequence. If
MULTILINE
mode is activated then
^ matches at the beginning of input and after any line terminator
except at the end of input. When in MULTILINE
mode $
matches just before a line terminator or the end of the input sequence.
Groups and capturing
Capturing groups are numbered by counting their opening parentheses from left to right. In the expression ((A)(B(C))), for example, there are four such groups:Group zero always stands for the entire expression.
1 ((A)(B(C))) 2 (A) 3 (B(C)) 4 (C)
Capturing groups are so named because, during a match, each subsequence of the input sequence that matches such a group is saved. The captured subsequence may be used later in the expression, via a back reference, and may also be retrieved from the matcher once the match operation is complete.
The captured input associated with a group is always the subsequence that the group most recently matched. If a group is evaluated a second time because of quantification then its previously-captured value, if any, will be retained if the second evaluation fails. Matching the string "aba" against the expression (a(b)?)+, for example, leaves group two set to "b". All captured input is discarded at the beginning of each match.
Groups beginning with (? are pure, non-capturing groups that do not capture text and do not count towards the group total.
Unicode support
This class is in conformance with Level 1 of Unicode Technical Standard #18: Unicode Regular Expression Guidelines, plus RL2.1 Canonical Equivalents.Unicode escape sequences such as \u2014 in Java source code are processed as described in §3.3 of the Java Language Specification. Such escape sequences are also implemented directly by the regular-expression parser so that Unicode escapes can be used in expressions that are read from files or from the keyboard. Thus the strings "\u2014" and "\\u2014", while not equal, compile into the same pattern, which matches the character with hexadecimal value 0x2014.
Unicode blocks and categories are written with the \p and \P constructs as in Perl. \p{prop} matches if the input has the property prop, while \P{prop} does not match if the input has that property. Blocks are specified with the prefix In, as in InMongolian. Categories may be specified with the optional prefix Is: Both \p{L} and \p{IsL} denote the category of Unicode letters. Blocks and categories can be used both inside and outside of a character class.
The supported categories are those of The Unicode Standard in the version specified by the
Character
class. The category names are those
defined in the Standard, both normative and informative.
The block names supported by Pattern
are the valid block names
accepted and defined by
UnicodeBlock.forName
.
Categories that behave like the java.lang.Character boolean ismethodname methods (except for the deprecated ones) are available through the same \p{prop} syntax where the specified property has the name javamethodname.
Converting Non-Unicode Text
char
values represent
Unicode characters. Unicode is a 16-bit character encoding that supports
the world's major languages. You can learn more about the Unicode
standard at the
Unicode Consortium Web site .Few text editors currently support Unicode text entry. The text editor we used to write this section's code examples supports only ASCII characters, which are limited to 7 bits. To indicate Unicode characters that cannot be represented in ASCII, such as ö, we used the
\uXXXX
escape sequence. Each X
in the escape sequence is a hexadecimal digit. The following example
shows how to indicate the ö character with an escape sequence:String str = "\u00F6"; char c = '\u00F6'; Character letter = new Character('\u00F6');
OutputStreamWriter
using it and asking for its canonical name:OutputStreamWriter out = new OutputStreamWriter(new ByteArrayOutputStream()); System.out.println(out.getEncoding());
This section discusses the APIs you use to translate non-Unicode text into Unicode. Before using these APIs, you should verify that the character encoding you wish to convert into Unicode is supported. The list of supported character encodings is not part of the Java programming language specification. Therefore the character encodings supported by the APIs may vary with platform. To see which encodings the Java Development Kit supports, see the Supported Encodings document.
The material that follows describes two techniques for converting non-Unicode text to Unicode. You can convert non-Unicode byte arrays into
String
objects, and vice versa. Or you can translate between streams of Unicode characters and byte streams of non-Unicode text.Unicode Escapes
A compiler
for the Java programming language ("Java compiler") first recognizes Unicode escapes
in its input, translating the ASCII characters
\u
followed by four hexadecimal digits to the UTF-16 code unit of
the indicated hexadecimal value, and passing all other
characters unchanged. Representing supplementary characters requires
two consecutive Unicode escapes. This translation step results in a
sequence of Unicode input characters.
UnicodeInputCharacter:
UnicodeEscape
RawInputCharacter
UnicodeEscape:
\
UnicodeMarker HexDigit HexDigit HexDigit HexDigitUnicodeMarker:
u
UnicodeMarker
u
RawInputCharacter:
any Unicode character
HexDigit: one of
0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
The
\
, u
, and
hexadecimal digits here are all ASCII characters.
In addition
to the processing implied by the grammar, for each raw input character
that is a backslash
\
, input processing must
consider how many other \
characters contiguously
precede it, separating it from a non-\
character or
the start of the input stream. If this number is even, then
the \
is eligible to begin a Unicode escape; if the
number is odd, then the \
is not eligible to begin
a Unicode escape.
For example, the raw input
"
\\u2297=\u2297
" results in the eleven
characters " \ \ u 2 2 9 7 =
⊗ "
(\u2297
is the
Unicode encoding of the character ⊗).
If an
eligible
\
is not followed by u
,
then it is treated as a RawInputCharacter and
remains part of the escaped Unicode stream.
If an
eligible
\
is followed by u
, or
more than one u
, and the last u
is not followed by four hexadecimal digits, then a compile-time error
occurs.
For example, the raw
input
\u005cu005a
results in the six
characters \ u 0 0 5 a
,
because 005c
is the Unicode value
for \
. It does not result in the character
Z, which is Unicode character 005a
, because
the \
that resulted from
the \u005c
is not interpreted as the start of a
further Unicode escape.
The
Java programming language specifies a standard way of transforming a program written
in Unicode into ASCII that changes a program into a form that can be
processed by ASCII-based tools. The transformation involves converting
any Unicode escapes in the source text of the program to ASCII by
adding an extra
u
- for
example, \uxxxx
becomes \uuxxxx
- while
simultaneously converting non-ASCII characters in the source text to
Unicode escapes containing a single u
each.
This
transformed version is equally acceptable to a Java compiler and
represents the exact same program. The exact Unicode source can later
be restored from this ASCII form by converting each escape sequence
where multiple
u
's are present to a sequence of
Unicode characters with one fewer u
, while
simultaneously converting each escape sequence with a
single u
to the corresponding single Unicode
character.
A Java compiler should use
the
\uxxxx
notation as an
output format to display Unicode characters when a suitable font is
not available. Subtypes and Subclasses
Subtypes
We have used closed arrows in module dependence diagrams and object models. In MDDs, a closed arrow from an implementation ArrayList to a specification List means that ArrayList “meets” the specification of List. In an object model, a closed arrow denotes a subset relationship between the two sets.
We can also draw a closed arrow from A to B in an MDD, where A and B are implementation parts.
Here, the specifications of A and B are not drawn, but are implied in the MDD. A and B are modules with objects and associated methods. We say that that A is a B if every A object is also a B object. For instance, every automobile is a vehicle, and every bicycle is a vehicle, and every pogo stick is a vehicle; every vehicle is a mode of transport, as is every pack animal.
This subset relationship is a necessary but not sufficient condition for a subtyping relationship. Type A is a subtype of type B when A’s specification implies B’s specification. That is, any object (or class) that satisfies A’s specification also satisfies B’s specification, because B’s specification is weaker.
The definition of subtyping depends on the definition of strong versus weak specifications. In 6.170, we will define true subtyping to mean that anywhere in the code, if you expect a B object, an A object is acceptable.1 Code written to work with B objects (and to depend on their properties) is guaranteed to continue to work if it is supplied A objects instead; furthermore, the behavior will be the same, if we only consider the aspects of A’s behavior that is also included in B’s behavior. (A may introduce new behaviors that B does not have, but it may only change existing B behaviors in certain ways; see below.)
With no hubris whatsoever, we call the 6.170 notion of subtyping, true subtyping to distinguish it from Java subtypes, which correspond to a weaker notion.
Example: Bicycles
Suppose we have a class for representing bicycles. Here is a partial implementation:
class Bicycle {
private int framesize;
private int chainringGears;
private int freewheelGears;
...
// returns the number of gears on this bicycle
public int gears() { return chainringGears * freewheelGears; }
// returns the cost of this bicycle
public float cost() { ... }
// returns the sales tax owed on this bicycle
public float salesTax() { return cost() * .0825; }
// effects: transports the rider from work to home
public void goHome() { ... }
...
}
A new class representing bicycles with headlamps can accommodate late nights (or early mornings).
class LightedBicycle {
private int framesize;
private int chainringGears;
private int freewheelGears;
private BatteryType battery;
...
// returns the number of gears on this bicycle
public int gears() { return chainringGears * freewheelGears; }
// returns the cost of this bicycle
float cost() { ... }
// returns the sales tax owed on this bicycle
public float salesTax() { return cost() * .0825; }
// effects: transports the rider from work to home
public void goHome() { ... }
// effects: replaces the existing battery with the argument b
public void changeBattery(BatteryType b);
...
}
Copying all the code is tiresome and error-prone. (The error might be failure to copy correctly or failure to make a required change.) Additionally, if a bug is found in one version, it is easy to forget to propagate the fix to all versions of the code. Finally, it is very hard to comprehend the distinction the two classes by looking for differences themselves in a mass of similarities. 2
Java and other programming languages use subclassing to overcome these difficulties. Subclassing
permits reuse of implementations and overriding of methods. A better implementation of LightedBicycle is
class LightedBicycle extends Bicycle {
private BatteryType battery;
...
// returns the cost of this bicycle
float cost() { return super.cost() + battery.cost(); }
// effects: transports the rider from work to home
public void goHome() { ... }
// effects: replaces the existing battery with the argument b
public void changeBattery(BatteryType b);
...
}
LightedBicycle need not implement methods and fields that appear in its superclass Bicycle; the Bicycle versions are automatically used by Java when they are not overridden in the subclass.
Consider the following implementations of the goHome method (along with more complete specifications).
If these are the only changes, are LightedBicycle and RacingBicycle subtypes of Bicycle? (For the time being we will talk about subtyping; we’ll return to the differences between Java subclassing, Java subtyping, and true subtyping later.)
class Bicycle {
...
// requires: windspeed < 20mph && daylight
// effects: transports the rider from work to home
void goHome() { ... }
}
class LightedBicycle {
...
// requires: windspeed < 20mph
// effects: transports the rider from work to home
void goHome() { ... }
}
class RacingBicycle {
...
// requires: windspeed < 20mph && daylight
// effects: transports the rider from work to home
// in an elapsed time of < 10 minutes
// && gets the rider sweaty
void goHome() { ... }
}
To answer that question, recall the definition of subtyping: can an object of the subtype be substituted anywhere that code expects an object of the supertype? If so, the subtyping relationship is valid. 3
In this case, both LightedBicycle and RacingBicycle are subtypes of Bicycle. In the first case, the requirement is relaxed; in the second case, the effects are strengthened in a way that still satisfies the superclass’s effects.
The cost method of LightedBicycle shows another capability of subclassing in Java. Methods
can be overridden to provide a new implementation in a subclass. This enables more code reuse; in particular, LightedBicycle can reuse Bicycle’s salesTax method. When salesTax is invoked on a LightedBicycle, the Bicycle version is used instead. Then, the call to cost inside salesTax invokes the version based on the runtime type of the object (LightedBicycle), so the LightedBicycle version is used. Regardless of the declared type of an object, an implementation of a method with multiple implementations (of the same signature) is always selected based on the run-time type.
In fact, there is no way for an external client to invoke the version of a method specified by the declared type or any other type that is not the run-time type. This is an important and very desirable
property of Java (and other object-oriented languages). Suppose that the subclass maintains some extra fields which are kept in sync with fields of the superclass. If superclass methods could be invoked directly, possibly modifying superclass fields without also updating subclass fields, then the representation invariant of the subclass would be broken.
A subclass may invoke methods of its parent via use of super, however. Sometimes this is useful when the subclass method needs to do just a little bit more work; recall the LightedBicycle implementation of cost:
class LightedBicycle extends Bicycle {
//
returns
the
cost
of this bicycle
float cost(
){
return
super.cost()
+ battery.cost(); }
}
Suppose the Rider class models people who ride bicycles. In the absence of subclassing and subtypes, the module dependence diagram would look something like this:
Rider Bicycle LightedBicycle RacingBicycle PennyFarthing
The code for Rider would also need to test which type of object it had been passed, which would be ugly, verbose, and error-prone.
With subtyping, the MDD dependences look like this:
Rider Bicycle LightedBicycle RacingBicycle PennyFarthing3
The many dependences have been reduced to a single one.
When subtype arrows are added, the diagram is only a bit more complicated:
Rider Bicycle LightedBicycle RacingBicycle PennyFarthing
Even though there are just as many arrows, this diagram is much simpler than the original one: dependence edges complicate designs and implementations more than other types of edge.
Substitution principle
The substitution principle is the theoretical underpinning of subtypes; it provides a precise definition of when two types are subtypes. Informally, it states that subtypes must be substitutable for supertypes. This guarantees that if code depends on (any aspect of) a supertype, but an object of a subtype is substituted, system behavior will not be affected. (The Java compiler also requires that the extends or implements clause names the parent in order for subtypes to be used in place of supertypes.)
The methods of a subtype must hold certain relationships to the methods of the supertype, and the subtype must guarantee that any properties of the supertype (such as representation invariants or specification constraints) are not violated by the subtype.
methods There are two necessary properties:
1.For each method in the supertype, the subtype must have a corresponding method. (The subtype is allowed to introduce additional, new methods that do not appear in the supertype.)
2.Each method in subtype that corresponds to one in the supertype:
•requires less (has a weaker precondition)
–there are no more “requires” clauses, and each one is no more strict than the one in the supertype method.
–the argument types may be supertypes of the ones in the supertype. This is called contravariance, and it feels somewhat backward, because the arguments to the subtype method are supertypes of the arguments to the supertype method. However, it makes sense, because any arguments passed to the supertype method are sure to be legal arguments to the subtype method.
•guarantees more (has a stronger postcondition)
–there are no more exceptions
–there are no more modified variables
–in the description of the result and/or result state, there are more clauses, and they describe stronger properties
–the result type may be a subtype of that of the supertype. This is called covariance:
the return type of the subtype method is a subtype of the return type of the supertype method.
5 (The above descriptions should all permit equality; for instance, “requires less” should be “requires no more”, and “less strict” should be “no more strict”. They are stated in this form for ease of reading.) The subtype method should not promise to have more or different results; it merely promises to do what the supertype method did, but possibly to ensure additional properties
as well. For instance, if a supertype method returns a number larger than its argument, a subtype method could return a prime number larger than its argument. As an example of the type constraints, if A is a subtype of B, then the following would be a legal overriding:
Bicycle B.f(Bicycle arg);
RacingBicycle A.f(Vehicle arg); Method B.f takes a Bicycle as its argument, but A.f can accept any Vehicle (which includes all Bicycles). Method B.f returns a Bicycle as its result, but A.f returns a RacingBicycle (which is itself a Bicycle).
properties Any properties guaranteed by a supertype, such as constraints over the values that may appear in specification fields, must be guaranteed by the subtype as well. (The subtype is permitted to strengthen these constraints.)
As a simple example from the book, consider FatSet, which is always nonempty.
class FatSet { // Specification constraints: this always contains at least one element
...
// effects: if this contains x and this.size > 1, removes x from this void remove(int x); }
Type NotSoFatSet with additional method
// effects: removes x from this
void reallyRemove(int x)
is not a subtype of FatSet. Even though there is no problem with any method of FatSet — reallyRemove is a new method, so the rules about corresponding methods do not apply — this method violates the constraint.
If the subtype object is considered purely as a supertype object (that is, only the supertype methods and fields are queried), then the result should be the same as if an object of the supertype had been manipulated all along instead.
signatures: this is essentially the contravariant and covariant rules above. (A procedure’s signature is its name, argument types, return types, and exceptions.)
methods: this is constraints on the behavior, or all aspects of a specification that cannot be expressed in a signature
Java types are classes, interfaces, or primitives. Java has its own notion of subtype (which involves only classes and interfaces). This is a weaker notion than the true subtyping described above; Java subtypes do not necessarily satisfy the substitution principle. Further, a subtype definition that satisfies the substitution principle may not be allowed in Java, and will not compile.
In order for a type to be a Java subtype of another type, the relationship must be declared (via Java’s extends or implements syntax), and the methods must satisfy two properties similar to, but weaker than, those for true subtyping:
1.for each method in the supertype, the subtype must have a corresponding method. (The subtype is allowed to introduce additional, new methods that do not appear in the supertype.)
2.each method in subtype that corresponds to one in the supertype
•the arguments must have the same types
•the result must have the same type
•there are no more declared exceptions
Java has no notion of a behavioral specification, so it performs no such checks and can make no guarantees about behavior. The requirement of type equality for arguments and result is stronger than strictly necessary to guarantee type-safety. This prohibits some code we might like to write. However, it simplifies the Java language syntax and semantics.
4.1 Example: Square and rectangle
We know from elementary school that every square is a rectangle. Suppose we wanted to make Square a subtype of Rectangle, which included a setSize method:
class Rectangle {
...
// effects: sets width and height to the specified values
// (that is, this.width’ = w && this.height’ = h)
void setSize(int w, int h);
}
class Square extends Rectangle {
...
}
Which of the following methods is right for Square?
// requires: w = h
void setSize(int w, int h);
void setSize(int edgeLength);
// throws BadSizeException if w != h
void setSize(int w, int h) throws BadSizeException;
7
5
The first one isn’t right because the subclass method requires more than the superclass method. Thus, subclass objects can’t be substituted for superclass objects, as there might be code that called setSize with non-equal arguments.
The second one isn’t right (all by itself) because the subclass still must specify a behavior for setSize(int, int); that definition is of a different method (whose name is the same but whose signature differs).
The third one isn’t right because it throws an exception that the superclass doesn’t mention. Thus, it again has different behavior and so Squares can’t be substituted for Rectangles. If BadSizeException is an unchecked exception, then Java will permit the third method to compile; but then again, it will also permit the first method to compile. Therefore, Java’s notion of subtype is weaker than the 6.170 notion of subtype.
There isn’t a way out of this quandary without modifying the supertype. Sometimes subtypes do not accord with our intuition! Or, our intuition about what is a good supertype is wrong.
One plausible solution would be to change Rectangle.setSize to specify that it throws the exception; of course, in practice only Square.setSize would do so. Another solution would be to eliminate setSize and instead have a
void scale(double scaleFactor);
method that shrinks or grows a shape. Other solutions are also possible.
Java subclassing
Subclassing has a number of advantages, all of which stem from reuse:
•Implementations of subclasses need not repeat unchanged fields and methods, but can reuse those of the superclass
•Clients (callers) need not change code when new subtypes are added, but can reuse the existing code (which doesn’t mention the subtypes at all, just the supertype
•The resulting design has better modularity and reduced complexity, because designers, implementers,
and users only have to understand the supertype, not every subtype; this is specification reuse.
A key mechanism that enables these benefits is overriding, which specializes behavior for some methods. In the absence of overriding, any change to behavior (even a compatible one) could force a complete reimplementation. Overriding permits part of an implementation to be changed without changing other parts that depend on it. This permits more code and specification reuse, both by the implementation and the client.
A potential disadvantage of subclassing is the opportunities it presents for inappropriate reuse. Subclasses and superclasses may depend on one another (explicitly by type name or implicitly by knowledge of the implementation), particularly since subclasses have access to the protected parts of the superclass implementation. These extra dependences complicate the MDD, the design, and the implementation, making it harder to code, understand, and modify.
10) Operators - Arithmetic, String concatenation, Relational, Logical, Bitwise, increment-decrement
Expressions and Operators
So far in this chapter, we've learned about the primitive types that Java programs can manipulate and seen how to include primitive values as literals in a Java program. We've also used variables as symbolic names that represent, or hold, values. These literals and variables are the tokens out of which Java programs are built.An expression is the next higher level of structure in a Java program. The Java interpreter evaluates an expression to compute its value. The very simplest expressions are called primary expressions and consist of literals and variables. So, for example, the following are all expressions:
When the Java interpreter evaluates a literal expression, the resulting value is the literal itself. When the interpreter evaluates a variable expression, the resulting value is the value stored in the variable.1.7 // An integer literal true // A boolean literal sum // A variable
Primary expressions are not very interesting. More complex expressions are made by using operators to combine primary expressions. For example, the following expression uses the assignment operator to combine two primary expressions--a variable and a floating-point literal--into an assignment expression:
But operators are used not only with primary expressions; they can also be used with expressions at any level of complexity. Thus, the following are all legal expressions:sum = 1.7
sum = 1 + 2 + 3*1.2 + (4 + 8)/3.0 sum/Math.sqrt(3.0 * 1.234) (int)(sum + 33)
* Operator Summary
The kinds of expressions you can write in a programming language depend entirely on the set of operators available to you. Table 2-5 summarizes the operators available in Java. The P and A columns of the table specify the precedence and associativity of each group of related operators, respectively.Table 2-5. Java Operators
P | A | Operator | Operand Type(s) | Operation Performed |
---|---|---|---|---|
15 | L | . | object, member | object member access |
[] | array, int | array element access | ||
( args ) | method, arglist | method invocation | ||
++, − − | variable | post-increment, decrement | ||
14 | R | ++, − − | variable | pre-increment, decrement |
+, − | number | unary plus, unary minus | ||
~ | integer | bitwise complement | ||
! | boolean | boolean NOT | ||
13 | R | new | class, arglist | object creation |
( type ) | type, any | cast (type conversion) | ||
12 | L | *, /, % | number, number | multiplication, division, remainder |
11 | L | +, − | number, number | addition, subtraction |
+ | string, any | string concatenation | ||
10 | L | << | integer, integer | left shift |
>> | integer, integer | right shift with sign extension | ||
>>> | integer, integer | right shift with zero extension | ||
9 | L | <, <= | number, number | less than, less than or equal |
>, >= | number, number | greater than, greater than or equal | ||
instanceof | reference, type | type comparison | ||
8 | L | = = | primitive, primitive | equal (have identical values) |
!= | primitive, primitive | not equal (have different values) | ||
= = | reference, reference | equal (refer to same object) | ||
!= | reference, reference | not equal (refer to different objects) | ||
7 | L | & | integer, integer | bitwise AND |
& | boolean, boolean | boolean AND | ||
6 | L | ^ | integer, integer | bitwise XOR |
^ | boolean, boolean | boolean XOR | ||
5 | L | | | integer, integer | bitwise OR |
| | boolean, boolean | boolean OR | ||
4 | L | && | boolean, boolean | conditional AND |
3 | L | || | boolean, boolean | conditional OR |
2 | R | ?: | boolean, any, any | conditional (ternary) operator |
1 | R | = | variable, any | assignment |
*=, /=, %=, | variable, any | assignment with operation | ||
+=, −=, <<=, | ||||
>>=, >>>=, | ||||
&=, ^=, |= |
* Precedence
The P column of Table 2-5 specifies the precedence of each operator. Precedence specifies the order in which operations are performed. Consider this expression:The multiplication operator has higher precedence than the addition operator, so a is added to the product of b and c. Operator precedence can be thought of as a measure of how tightly operators bind to their operands. The higher the number, the more tightly they bind.a + b * c
Default operator precedence can be overridden through the use of parentheses, to explicitly specify the order of operations. The previous expression can be rewritten as follows to specify that the addition should be performed before the multiplication:
The default operator precedence in Java was chosen for compatibility with C; the designers of C chose this precedence so that most expressions can be written naturally without parentheses. There are only a few common Java idioms for which parentheses are required. Examples include:(a + b) * c
// Class cast combined with member access ((Integer) o).intValue(); // Assignment combined with comparison while((line = in.readLine()) != null) { ... } // Bitwise operators combined with comparison if ((flags & (PUBLIC | PROTECTED)) != 0) { ... }
* Associativity
When an expression involves several operators that have the same precedence, the operator associativity governs the order in which the operations are performed. Most operators are left-to-right associative, which means that the operations are performed from left to right. The assignment and unary operators, however, have right-to-left associativity. The A column of Table 2-5 specifies the associativity of each operator or group of operators. The value L means left to right, and R means right to left.The additive operators are all left-to-right associative, so the expression a+b-c is evaluated from left to right: (a+b)-c. Unary operators and assignment operators are evaluated from right to left. Consider this complex expression:
This is evaluated as follows:a = b += c = -~d
As with operator precedence, operator associativity establishes a default order of evaluation for an expression. This default order can be overridden through the use of parentheses. However, the default operator associativity in Java has been chosen to yield a natural expression syntax, and you rarely need to alter it.a = (b += (c = -(~d)))
* Operand number and type
The fourth column of Table 2-5 specifies the number and type of the operands expected by each operator. Some operators operate on only one operand; these are called unary operators. For example, the unary minus operator changes the sign of a single number:Most operators, however, are binary operators that operate on two operand values. The − operator actually comes in both forms:-n // The unary minus operator
Java also defines one ternary operator, often called the conditional operator. It is like an if statement inside an expression. Its three operands are separated by a question mark and a colon; the second and third operators must both be of the same type:a - b // The subtraction operator is a binary operator
In addition to expecting a certain number of operands, each operator also expects particular types of operands. Column four of the table lists the operand types. Some of the codes used in that column require further explanation:x > y ? x : y // Ternary expression; evaluates to the larger of x and y
- number
- An integer, floating-point value, or character (i.e., any primitive type except boolean)
- integer
- A byte, short, int, long, or char value (long values are not allowed for the array access operator [])
- reference
- An object or array
- variable
- A variable or anything else, such as an array element, to which a value can be assigned
* Return type
Just as every operator expects its operands to be of specific types, each operator produces a value of a specific type. The arithmetic, increment and decrement, bitwise, and shift operators return a double if at least one of the operands is a double. Otherwise, they return a float if at least one of the operands is a float. Otherwise, they return a long if at least one of the operands is a long. Otherwise, they return an int, even if both operands are byte, short, or char types that are narrower than int.The comparison, equality, and boolean operators always return boolean values. Each assignment operator returns whatever value it assigned, which is of a type compatible with the variable on the left side of the expression. The conditional operator returns the value of its second or third argument (which must both be of the same type).
* Side effects
Every operator computes a value based on one or more operand values. Some operators, however, have side effects in addition to their basic evaluation. If an expression contains side effects, evaluating it changes the state of a Java program in such a way that evaluating the expression again may yield a different result. For example, the ++ increment operator has the side effect of incrementing a variable. The expression ++a increments the variable a and returns the newly incremented value. If this expression is evaluated again, the value will be different. The various assignment operators also have side effects. For example, the expression a*=2 can also be written as a=a*2. The value of the expression is the value of a multiplied by 2, but the expression also has the side effect of storing that value back into a. The method invocation operator () has side effects if the invoked method has side effects. Some methods, such as Math.sqrt(), simply compute and return a value without side effects of any kind. Typically, however, methods do have side effects. Finally, the new operator has the profound side effect of creating a new object.* Order of evaluation
When the Java interpreter evaluates an expression, it performs the various operations in an order specified by the parentheses in the expression, the precedence of the operators, and the associativity of the operators. Before any operation is performed, however, the interpreter first evaluates the operands of the operator. (The exceptions are the &&, ||, and ?: operators, which do not always evaluate all their operands.) The interpreter always evaluates operands in order from left to right. This matters if any of the operands are expressions that contain side effects. Consider this code, for example:Although the multiplication is performed before the addition, the operands of the + operator are evaluated first. Thus, the expression evaluates to 3+4*5, or 23.int a = 2; int v = ++a + ++a * ++a;
* Arithmetic Operators
Since most programs operate primarily on numbers, the most commonly used operators are often those that perform arithmetic operations. The arithmetic operators can be used with integers, floating-point numbers, and even characters (i.e., they can be used with any primitive type other than boolean). If either of the operands is a floating-point number, floating-point arithmetic is used; otherwise, integer arithmetic is used. This matters because integer arithmetic and floating-point arithmetic differ in the way division is performed and in the way underflows and overflows are handled, for example. The arithmetic operators are:- Addition (+)
-
The + operator adds two numbers. As
we'll see shortly, the + operator can
also be used to concatenate strings. If either operand of
+ is a string, the other one is
converted to a string as well. Be sure to use parentheses
when you want to combine addition with concatenation. For
example:
System.out.println("Total: " + 3 + 4); // Prints "Total: 34", not 7!
- Subtraction (−)
- When − is used as a binary operator, it subtracts its second operand from its first. For example, 7-3 evaluates to 4. The − operator can perform unary negation.
- Multiplication (*)
- The * operator multiplies its two operands. For example, 7*3 evaluates to 21.
- Division (/)
-
The / operator divides its first
operand by its second. If both operands are integers,
the result is an integer, and any remainder is
lost. If either operand is a floating-point value,
however, the result is a floating-point value. When
dividing two integers, division by zero throws an
ArithmeticException. For
floating-point calculations, however, division by zero
simply yields an infinite result or NaN:
7/3 // Evaluates to 2 7/3.0f // Evaluates to 2.333333f 7/0 // Throws an ArithmeticException 7/0.0 // Evaluates to positive infinity 0.0/0.0 // Evaluates to NaN
- Modulo (%)
- The % operator computes the first operand modulo the second operand (i.e., it returns the remainder when the first operand is divided by the second operand an integral number of times). For example, 7%3 is 1. The sign of the result is the same as the sign of the first operand. While the modulo operator is typically used with integer operands, it also works for floating-point values. For example, 4.3%2.1 evaluates to 0.1. When operating with integers, trying to compute a value modulo zero causes an ArithmeticException. When working with floating-point values, anything modulo 0.0 evaluates to NaN, as does infinity modulo anything.
- Unary Minus (−)
- When − is used as a unary operator, before a single operand, it performs unary negation. In other words, it converts a positive value to an equivalently negative value, and vice versa.
* String Concatenation Operator
In addition to adding numbers, the + operator (and the related += operator) also concatenates, or joins, strings. If either of the operands to + is a string, the operator converts the other operand to a string. For example:As a result, you must be careful to put any addition expressions in parentheses when combining them with string concatenation. If you do not, the addition operator is interpreted as a concatenation operator.System.out.println("Quotient: " + 7/3.0f); // Prints "Quotient: 2.3333333"
The Java interpreter has built-in string conversions for all primitive types. An object is converted to a string by invoking its toString() method. Some classes define custom toString() methods, so that objects of that class can easily be converted to strings in this way. An array is converted to a string by invoking the built-in toString() method, which, unfortunately, does not return a useful string representation of the array contents.
* Increment and Decrement Operators
The ++ operator increments its single operand, which must be a variable, an element of an array, or a field of an object, by one. The behavior of this operator depends on its position relative to the operand. When used before the operand, where it is known as the pre-increment operator, it increments the operand and evaluates to the incremented value of that operand. When used after the operand, where it is known as the post-increment operator, it increments its operand, but evaluates to the value of that operand before it was incremented.For example, the following code sets both i and j to 2:
But these lines set i to 2 and j to 1:i = 1; j = ++i;
Similarly, the − − operator decrements its single numeric operand, which must be a variable, an element of an array, or a field of an object, by one. Like the ++ operator, the behavior of − − depends on its position relative to the operand. When used before the operand, it decrements the operand and returns the decremented value. When used after the operand, it decrements the operand, but returns the un-decremented value.i = 1; j = i++;
The expressions x++ and x− − are equivalent to x=x+1 and x=x−1, respectively, except that when using the increment and decrement operators, x is only evaluated once. If x is itself an expression with side effects, this makes a big difference. For example, these two expressions are not equivalent:
These operators, in both prefix and postfix forms, are most commonly used to increment or decrement the counter that controls a loop.a[i++]++; // Increments an element of an array a[i++] = a[i++] + 1; // Adds one to an array element and stores it in another
* Comparison Operators
The comparison operators consist of the equality operators that test values for equality or inequality and the relational operators used with ordered types (numbers and characters) to test for greater than and less than relationships. Both types of operators yield a boolean result, so they are typically used with if statements and while and for loops to make branching and looping decisions. For example:Java provides the following equality operators:if (o != null) ...; // The not equals operator while(i < a.length) ...; // The less than operator
- Equals (= =)
-
The = = operator evaluates to
true if its two operands are equal
and false otherwise. With primitive operands, it tests whether the operand
values themselves are identical. For operands of
reference types, however,
it tests whether the operands refer to
the same object or array. In other words,
it does not test the equality
of two distinct objects or arrays. In particular, note
that you cannot test two distinct strings for equality
with this operator.
If = = is used to compare two numeric or character operands that are not of the same type, the narrower operand is converted to the type of the wider operand before the comparison is done. For example, when comparing a short to a float, the short is first converted to a float before the comparison is performed. For floating-point numbers, the special negative zero value tests equal to the regular, positive zero value. Also, the special NaN (not-a-number) value is not equal to any other number, including itself. To test whether a floating-point value is NaN, use the Float.isNan() or Double.isNan() method. - Not Equals (!=)
- The != operator is exactly the opposite of the = = operator. It evaluates to true if its two primitive operands have different values or if its two reference operands refer to different objects or arrays. Otherwise, it evaluates to false.
- Less Than (<)
- Evaluates to true if the first operand is less than the second.
- Less Than or Equal (<=)
- Evaluates to true if the first operand is less than or equal to the second.
- Greater Than (>)
- Evaluates to true if the first operand is greater than the second.
- Greater Than or Equal (>=)
- Evaluates to true if the first operand is greater than or equal to the second.
2.5.6. Boolean Operators
As we've just seen, the comparison operators compare their operands and yield a boolean result, which is often used in branching and looping statements. In order to make branching and looping decisions based on conditions more interesting than a single comparison, you can use the Boolean (or logical) operators to combine multiple comparison expressions into a single, more complex, expression. The Boolean operators require their operands to be boolean values and they evaluate to boolean values. The operators are:- Conditional AND (&&)
-
This operator performs a Boolean AND operation on its
operands. It evaluates to true if and
only if both its operands are
true. If either or both
operands are false, it evaluates to
false. For example:
if (x < 10 && y > 3) ... // If both comparisons are true
if ((x < 10) && (y > 3)) ...
This operator is called a conditional AND because it conditionally evaluates its second operand. If the first operand evaluates to false, the value of the expression is false, regardless of the value of the second operand. Therefore, to increase efficiency, the Java interpreter takes a shortcut and skips the second operand. Since the second operand is not guaranteed to be evaluated, you must use caution when using this operator with expressions that have side effects. On the other hand, the conditional nature of this operator allows us to write Java expressions such as the following:
if (data != null && i < data.length && data[i] != -1) ...
- Conditional OR (||)
- This operator performs a Boolean OR operation on its two boolean operands. It evaluates to true if either or both of its operands are true. If both operands are false, it evaluates to false. Like the && operator, || does not always evaluate its second operand. If the first operand evaluates to true, the value of the expression is true, regardless of the value of the second operand. Thus, the operator simply skips that second operand in that case.
- Boolean NOT (!)
-
This unary operator changes the boolean
value of its
operand. If applied to a true value,
it evaluates to false, and if applied
to a false value, it evaluates to
true. It is useful in expressions like
these:
if (!found) ... // found is a boolean variable declared somewhere while (!c.isEmpty()) ... // The isEmpty() method returns a boolean value
if (!(x > y && y > z))
- Boolean AND (&)
- When used with boolean operands, the & operator behaves like the && operator, except that it always evaluates both operands, regardless of the value of the first operand. This operator is almost always used as a bitwise operator with integer operands, however, and many Java programmers would not even recognize its use with boolean operands as legal Java code.
- Boolean OR (|)
- This operator performs a Boolean OR operation on its two boolean operands. It is like the || operator, except that it always evaluates both operands, even if the first one is true. The | operator is almost always used as a bitwise operator on integer operands; its use with boolean operands is very rare.
- Boolean XOR (^)
- When used with boolean operands, this operator computes the Exclusive OR (XOR) of its operands. It evaluates to true if exactly one of the two operands is true. In other words, it evaluates to false if both operands are false or if both operands are true. Unlike the && and || operators, this one must always evaluate both operands. The ^ operator is much more commonly used as a bitwise operator on integer operands. With boolean operands, this operator is equivalent to the != operator.
* Bitwise and Shift Operators
The bitwise and shift operators are low-level operators that manipulate the individual bits that make up an integer value. The bitwise operators are most commonly used for testing and setting individual flag bits in a value. In order to understand their behavior, you must understand binary (base-2) numbers and the twos-complement format used to represent negative integers. You cannot use these operators with floating-point, boolean, array, or object operands. When used with boolean operands, the &, |, and ^ operators perform a different operation, as described in the previous section.If either of the arguments to a bitwise operator is a long, the result is a long. Otherwise, the result is an int. If the left operand of a shift operator is a long, the result is a long; otherwise, the result is an int. The operators are:
- Bitwise Complement (~)
-
The unary ~ operator is known as the
bitwise complement, or bitwise NOT, operator. It inverts
each bit of its single operand, converting ones to zeros
and zeros to ones. For example:
byte b = ~12; // ~00000110 ==> 11111001 or -13 decimal flags = flags & ~f; // Clear flag f in a set of flags
- Bitwise AND (&)
-
This operator combines its two integer operands by
performing a Boolean AND operation on their individual
bits. The result has a bit set only if the
corresponding bit is set in both operands. For example:
10 & 7 // 00001010 & 00000111 ==> 00000010 or 2 if ((flags & f) != 0) // Test whether flag f is set
- Bitwise OR (|)
-
This operator combines its two integer operands by
performing a Boolean OR operation on their individual
bits. The result has a bit set if the
corresponding bit is set in either or both of the
operands. It has a zero bit only where both
corresponding operand bits are zero. For example:
10 | 7 // 00001010 | 00000111 ==> 00001111 or 15 flags = flags | f; // Set flag f
- Bitwise XOR (^)
-
This operator combines its two integer operands by
performing a Boolean XOR (Exclusive OR) operation on their
individual bits. The result has a bit set if
the corresponding bits in the two operands are
different. If the corresponding operand bits are both ones or
both zeros, the result bit is a zero. For example:
10 & 7 // 00001010 ^ 00000111 ==> 00001101 or 13
- Left Shift (<<)
-
The << operator shifts the bits
of the left operand left by the number of places specified
by the right operand. High-order bits of the left operand
are lost, and zero bits are shifted in from the right. Shifting an integer left by n
places is equivalent to multiplying that number by
2n. For example:
10 << 1 // 00001010 << 1 = 00010100 = 20 = 10*2 7 << 3 // 00000111 << 3 = 00111000 = 56 = 7*8 -1 << 2 // 0xFFFFFFFF << 2 = 0xFFFFFFFC = -4 = -1*4
- Signed Right Shift (>>)
-
The >> operator shifts the bits
of the left operand to the right by the number of places
specified by the right operand. The low-order bits
of the left operand are shifted away and are lost. The
high-order bits shifted in are the same as the original
high-order bit of the left operand. In other words, if the
left operand is positive, zeros are shifted into the
high-order bits. If the left operand is
negative, ones are shifted in instead. This technique is
known as sign extension; it is
used to preserve the sign of the left operand. For
example:
10 >> 1 // 00001010 >> 1 = 00000101 = 5 = 10/2 27 >> 3 // 00011011 >> 3 = 00000011 = 3 = 27/8 -50 >> 2 // 11001110 >> 2 = 11110011 = -13 != -50/4
- Unsigned Right Shift (>>>)
-
This operator is like the >>
operator, except that it always shifts zeros into the
high-order bits of the result, regardless of the sign of
the left-hand operand. This technique is called
zero extension ; it is appropriate
when the left operand is being treated as an unsigned
value (despite the fact that Java integer types are
all signed). Examples:
-50 >>> 2 // 11001110 >>> 2 = 00110011 = 51 0xff >>> 4 // 11111111 >>> 4 = 00001111 = 15 = 255/16
* Assignment Operators
The assignment operators store, or assign, a value into some kind of variable. The left operand must evaluate to an appropriate local variable, array element, or object field. The right side can be any value of a type compatible with the variable. An assignment expression evaluates to the value that is assigned to the variable. More importantly, however, the expression has the side effect of actually performing the assignment. Unlike all other binary operators, the assignment operators are right-associative, which means that the assignments in a=b=c are performed right-to-left, as follows: a=(b=c).The basic assignment operator is =. Do not confuse it with the equality operator, = =. In order to keep these two operators distinct, I recommend that you read = as "is assigned the value."
In addition to this simple assignment operator, Java also defines 11 other operators that combine assignment with the 5 arithmetic operators and the 6 bitwise and shift operators. For example, the += operator reads the value of the left variable, adds the value of the right operand to it, stores the sum back into the left variable as a side effect, and returns the sum as the value of the expression. Thus, the expression x+=2 is almost the same x=x+2. The difference between these two expressions is that when you use the += operator, the left operand is evaluated only once. This makes a difference when that operand has a side effect. Consider the following two expressions, which are not equivalent:
The general form of these combination assignment operators is:a[i++] += 2; a[i++] = a[i++] + 2;
This is equivalent (unless there are side effects in var) to:var op= value
The available operators are:var = var op value
The most commonly used operators are += and − =, although &= and |= can also be useful when working with boolean flags. For example:+= −= *= /= %= // Arithmetic operators plus assignment &= |= ^= // Bitwise operators plus assignment <<= >>= >>>= // Shift operators plus assignment
i += 2; // Increment a loop counter by 2 c −= 5; // Decrement a counter by 5 flags |= f; // Set a flag f in an integer set of flags flags &= ~f; // Clear a flag f in an integer set of flags
* The Conditional Operator
The conditional operator ?: is a somewhat obscure ternary (three-operand) operator inherited from C. It allows you to embed a conditional within an expression. You can think of it as the operator version of the if/else statement. The first and second operands of the conditional operator are separated by a question mark (?), while the second and third operands are separated by a colon (:). The first operand must evaluate to a boolean value. The second and third operands can be of any type, but they must both be of the same type.The conditional operator starts by evaluating its first operand. If it is true, the operator evaluates its second operand and uses that as the value of the expression. On the other hand, if the first operand is false, the conditional operator evaluates and returns its third operand. The conditional operator never evaluates both its second and third operand, so be careful when using expressions with side effects with this operator. Examples of this operator are:
Note that the ?: operator has lower precedence than all other operators except the assignment operators, so parentheses are not usually necessary around the operands of this operator. Many programmers find conditional expressions easier to read if the first operand is placed within parentheses, however. This is especially true because the conditional if statement always has its conditional expression written within parentheses.int max = (x > y) ? x : y; String name = (name != null) ? name : "unknown";
* The instanceof Operator
The instanceof operator requires an object or array value as its left operand and the name of a reference type as its right operand. It evaluates to true if the object or array is an instance of the specified type; it returns false otherwise. If the left operand is null, instanceof always evaluates to false. If an instanceof expression evaluates to true, it means that you can safely cast and assign the left operand to a variable of the type of the right operand.The instanceof operator can be used only with array and object types and values, not primitive types and values. Object and array types are discussed in detail later in this chapter. Examples of instanceof are:
"string" instanceof String // True: all strings are instances of String "" instanceof Object // True: strings are also instances of Object new int[] {1} instanceof int[] // True: the array value is an int array new int[] {1} instanceof byte[] // False: the array value is not a byte array new int[] {1} instanceof Object // True: all arrays are instances of Object null instanceof String // False: null is never instanceof anything // Use instanceof to make sure that it is safe to cast an object if (object instanceof Point) { Point p = (Point) object; }
* Special Operators
There are five language constructs in Java that are sometimes considered operators and sometimes considered simply part of the basic language syntax. These "operators" are listed in Table 2-5 in order to show their precedence relative to the other true operators. The use of these language constructs is detailed elsewhere in this chapter, but is described briefly here, so that you can recognize these constructs when you encounter them in code examples:- Object member access (.)
- An object is a collection of data and methods that operate on that data; the data fields and methods of an object are called its members. The dot (.) operator accesses these members. If o is an expression that evaluates to an object reference, and f is the name of a field of the object, o.f evaluates to the value contained in that field. If m is the name of a method, o.m refers to that method and allows it to be invoked using the () operator shown later.
- Array element access ([])
- An array is a numbered list of values. Each element of an array can be referred to by its number, or index. The [] operator allows you to refer to the individual elements of an array. If a is an array, and i is an expression that evaluates to an int, a[i] refers to one of the elements of a. Unlike other operators that work with integer values, this operator restricts array index values to be of type int or narrower.
- Method invocation (())
- A method is a named collection of Java code that can be run, or invoked, by following the name of the method with zero or more comma-separated expressions contained within parentheses. The values of these expressions are the arguments to the method. The method processes the arguments and optionally returns a value that becomes the value of the method invocation expression. If o.m is a method that expects no arguments, the method can be invoked with o.m(). If the method expects three arguments, for example, it can be invoked with an expression such as o.m(x,y,z). Before the Java interpreter invokes a method, it evaluates each of the arguments to be passed to the method. These expressions are guaranteed to be evaluated in order from left to right (which matters if any of the arguments have side effects).
- Object creation (new)
-
In Java, objects are created with the
new operator, which is followed by the
type of the object to be created and a parenthesized
list of arguments to be passed to the object
constructor. A constructor is a
special method that initializes a newly created object, so
the object creation syntax is similar to the Java method
invocation syntax. For example:
new ArrayList(); new Point(1,2)
- Type conversion or casting (())
-
As we've already seen, parentheses
can also be used as an operator to perform narrowing type
conversions, or casts. The first operand of this operator
is the type to be converted to; it is placed between the
parentheses. The second operand is the value to be
converted; it follows the parentheses. For example:
(byte) 28 // An integer literal cast to a byte type (int) (x + 3.14f) // A floating-point sum value cast to an integer value (String)h.get(k) // A generic object cast to a more specific string type
* The Narrowing Conversion | |
The narrowing conversion occurs from a type to a different type that has a smaller size, such as from a long (64 bits) to an int (32 bits). | |
In general, the narrowing primitive conversion can occur in these cases: | |
| |
| |
|
The widening conversion is permitted in the following cases:
- byte to short, int, long, float, or double
- Short to int, long, float, or double
- char to int, long, float, or double
- int to long, float, or double
- long to float or double
- float to double
Narrowing conversion with information loss | ||||||
Narrowing conversion may incur information loss, if the converted value is larger than the capacity of the target type. | ||||||
In the following conversion, there is some information loss because 9876543210L is too big for an int. | ||||||
| ||||||
1286608618
|
* Convert byte array to Integer and Long | ||||||||||||||||||||||||||||||||||||||||||
15) Methods and their overloading
Overloading MethodsThe Java programming language supports overloading methods, and Java can distinguish between methods with different method signatures. This means that methods within a class can have the same name if they have different parameter lists (there are some qualifications to this that will be discussed in the lesson titled "Interfaces and Inheritance").Suppose that you have a class that can use calligraphy to draw various types of data (strings, integers, and so on) and that contains a method for drawing each data type. It is cumbersome to use a new name for each method—for example, drawString , drawInteger , drawFloat ,
and so on. In the Java programming language, you can use the same name
for all the drawing methods but pass a different argument list to each
method. Thus, the data drawing class might declare four methods named draw , each of which has a different parameter list.public class DataArtist { ... public void draw(String s) { ... } public void draw(int i) { ... } public void draw(double f) { ... } public void draw(int i, double f) { ... } } draw(String s) and draw(int i) are distinct and unique methods because they require different argument types.You cannot declare more than one method with the same name and the same number and type of arguments, because the compiler cannot tell them apart. The compiler does not consider return type when differentiating methods, so you cannot declare two methods with the same signature even if they have a different return type. Note: Overloaded methods should be used sparingly, as they can make code much less readable.
16)constructors and their overloading
Here, you will learn more about Constructor and
how constructors are overloaded in Java. This section provides you a brief
introduction about the Constructor that are overloaded in the given
program with complete code absolutely in running state i.e. provided for best
illustration about the constructor overloading in Java.
Constructors are used to assign initial values to instance variables of the class. A default constructor with no arguments will be called automatically by the Java Virtual Machine (JVM). Constructor is always called by new operator. Constructor are declared just like as we declare methods, except that the constructor don't have any return type. Constructor can be overloaded provided they should have different arguments because JVM differentiates constructors on the basis of arguments passed in the constructor. Whenever we assign the name of the method same as class name. Remember this method should not have any return type. This is called as constructor overloading. We have made one program on a constructor overloading, after going through it the concept of constructor overloading will get more clear. In the example below we have made three overloaded constructors each having different arguments types so that the JVM can differentiates between the various constructors. The code of the program is given below:
public class ConstructorOverloading{ 17) Garbage collector and finalize method
Garbage collection
Since
objects are dynamically allocated by using the new operator, you might be
wondering how such objects are destroyed and their memory released for later
reallocation. In some languages, such as C++, dynamically allocated objects must
be manually released by use of a delete
operator.
Java takes a different approach; it
handles deallocation for you automatically. The
technique that accomplishes this is called garbage collection. It works like
this: when no references to an object to an object exist, that object is
assumed to be no longer needed, and the memory occupied by the object can be
reclaimed. There is no explicit need to destroy objects as in C++. Garbage
collection only occurs sporadically (if at all) during the execution of your
program. It will not occur simply because one or more objects exist that are no
longer used. Furthermore, different java run-time implementations will take
varying approaches to garbage collection, but for the most part, you should not
have to think about it while writing your programs
The finalize () Method
Sometimes
an object will need to perform some action when it is destroyed. For example,
if an object is holding some non-java resource such as a file handle or window
character font, then you might want to make sure these resources are freed
before an object is destroyed. To handle such situations, java provides a
mechanism called finalization. By using finalization, you can define specific
actions that will occur when an object is just about to be reclaimed by the
garbage collector.
To
add a finalizer to a class, you simply define the finalize() method. The java run time calls that method whenever it is about
to recycle an object of that class. Inside the finalize() method you will specify those actions that must be performed
before an object is destroyed. The garbage collector runs periodically,
checking for objects that are no longer referenced by any running state or
indirectly through other referenced objects. Right before an asset is freed,
the java run time calls the finalize() method
on the object.
The
finalize() method has this general form:
protected void finalize()
{
//
finalization code here
}
Here,
the keyword protected is a specifier that prevents
access to finalize() by code defined outside its class.
It
is important to understand that finalize() is only
called just prior to garbage collection. It is not called when an object goes
out-of-scope, for example. This means program should provide other means of
releasing system resources, etc., used by the object. It must not rely on finalize() for normal program operation.
18) static variables and methods
The static keyword can be used in 3 scenarios
static variable
static method
Assignment: To Learn working of static variables & methods Step 1) Copy the following code into a editor
Step 3) Expected output show below Following diagram shows , how reference variables & objects are created and static variables are accessed by the different instances. Step 4) It is possible to access a static variable from outside the class using the syntax ClassName.Variable_Name. Uncomment line # 27 & 28 . Save , Compile & Run . Observe the output. Step 5) Uncomment line 15,16 & 17 . Save , Compile & Run. Step 5) Error = ? This is because it is not possible to access instance variable “a” from static method “increment“. static blockThe static block, is a block of statement inside a Java class that will be executed when a class is first loaded in to the JVM
19)initializer blocks and the class initializer blocks
Initializing Fields
As you have seen, you can often provide an initial value for a field in its declaration:
public class BedAndBreakfast { // initialize to 10 public static int capacity = 10; // initialize to false private boolean full = false; } for
loop to fill a complex array), simple assignment is inadequate.
Instance variables can be initialized in constructors, where error
handling or other logic can be used. To provide the same capability for
class variables, the Java programming language includes static initialization blocks.Note: It is not necessary to declare fields at the beginning of the class definition, although this is the most common practice. It is only necessary that they be declared and initialized before they are used. Static Initialization BlocksA static initialization block is a normal block of code enclosed in braces,{ } , and preceded by the static keyword. Here is an example:static { // whatever code is needed for initialization goes here } There is an alternative to static blocks — you can write a private static method: class Whatever { public static varType myVar = initializeClassVariable(); private static varType initializeClassVariable() { // initialization code goes here } } Initializing Instance MembersNormally, you would put code to initialize an instance variable in a constructor. There are two alternatives to using a constructor to initialize instance variables: initializer blocks and final methods.Initializer blocks for instance variables look just like static initializer blocks, but without the static keyword:{ // whatever code is needed for initialization goes here } A final method cannot be overridden in a subclass. This is discussed in the lesson on interfaces and inheritance. Here is an example of using a final method for initializing an instance variable: class Whatever { private varType myVar = initializeInstanceVariable(); protected final varType initializeInstanceVariable() { // initialization code goes here } } |
No comments:
Post a Comment