Karnataka State Open University Sharada Vikas Trust Jayanagar, Bangalore Subject Name: Java Programming Semester: IMCA IV Syllabus Introduction Introduction to Programming Languages, The Evolution of Java, Object-Oriented Programming Concepts and Java, Differences between C++ and Java, The Primary Characteristics of Java, The Architecture, Programming with Java, Summary Exercises JAVA Fundamentals Tokens, Expressions, Using Data Types, Declarations, Control Flow, Summary Exercises JAVA Classes, Packages and Interfaces Introduction, Classes, Working with Objects, Packages, Inheritance, Interfaces, Summary JAVA Streams Data Flow with Java Streams, Input Streams, Output Streams, Summary Exception Handling in JAVA Introduction, Exception Methods, java.lang Exceptions, Summary JAVA Threads Introduction, Creating Threads, The Life Cycle of a Thread, Thread Methods, Using Threads, Synchronization of Threads, Summary JAVA Applets Introduction, Applet Examples, The java.applet.Applet Class, The Five Stages of an Applet's Life Cycle, Methods for Adding UI Components, Methods for Drawing and Event Handling, Summary JAVA AWT Introduction, Control Classes, Summary * Variable Assignment * Operators * Objects * Arrays * Loops and Conditionals * Class Definitions * Method and Constructor Definitions * Importing * Guarding Appendix B The Java Class Library * java.lang * java.util * java.io * java.net * java.awt * java.applet Appendix C Differences Between Java and C/C++ * The Preprocessor * Pointers * Structures and Unions * Functions * Multiple Inheritance * Strings * The goto Statement * Operator Overloading * Automatic Coercions * Variable Arguments * Command-Line Arguments UNIT 1 Introduction Programming languages evolve over time. They are constantly refined and focused to meet the ever-changing needs of their users. Like other modern programming languages such as C++, Java is an amalgamation of all the techniques developed over the years. Now thousands of programmers, Internet developers, Web publishers, and software houses are making use of Java. This chapter introduces the primary characteristics of Java, how Java differs from C++, structure of Java program and most important concept Java Virtual Machine 1.1 Introduction to Programming Languages The Java programming language has many features that make it unique, powerful, and versatile. Most programming languages are either compiled or interpreted, but Java is both. To understand how Java can be both compiled and interpreted, let us look at the basics of compiled and interpreted programming languages. Interpreted Programming Languages Interpreted Programming Languages are easier to learn and use. An interpreted programming language that most of people, even nonprogrammers, are familiar is BASIC. The BASIC programming language is rudimentary and easy to use. BASIC program uses a simple, high-level language structure. The BASIC interpreter reads the instructions in code line by line. The BASIC interpreter translates these individual lines into sets of instructions than can be understood by computer. Because of this, interpreted programs generally run more slowly than other programs and require more processor time. Compiled Programming Languages Compiled programming languages are generally more difficult to learn and use than interpreted programming languages. However, most programming languages are compiled. For example, COBOL, FORTRAN, C, C++, and Pascal. These programs are created using a high-level language structure. Then these programs are compiled to a machine-readable and machineexecutable form with a compiler. When the program is executed, the computer can directly interpret the instructions. Because the lines of codes do not have to be translated into a form the computer understands as the program is executing, compiled programs run very quickly compared to interpreted programs. However, there is a trade-off to be made between speed and portability. Code is compiled to such a low-level form that it can only be run on the platform for which it was compiled. For example, code written for Windows platform will not work in Linux Platform. Java: An Interpreted and Compiled Programming Language As stated before, Java is both interpreted and compiled. Java program is created using a simple, high-level language structure. This Java program is compiled to an intermediate level called “Bytecode” as shown in figure 1.1. Run the compiled bytecode, which is interpreted by the Java runtime environment. Bytecode is very different from machine code. Machine code is represented as a series of 0s and 1s. Bytecodes are sets of instructions that look a lot like assembler code. Although computer can directly execute machine code, bytecodes must be interpreted before they can be executed. Machine code is usable only on the specific platform for which it was compiled. Bytecode can run on any platform capable of using the Java runtime environment. This capability makes Java as architecture neutral and machine independent. The Java runtime interpreter translates the bytecode into sets of instructions the computer can understand. Because the bytecode is in an intermediate form, there is only a slight delay in translating it to a form the computer understands. Figure 1.1. Java Bytecode As you know most of the compilers compile source code for a specific machine, even Java compiler compile the source code for a machine that does not exist which is called as Java Virtual Machine. This machine it exists only in nanospace, or within the confines of computer system's memory. Hello.java Java API Java Virtual Machine (JVM) Java Platform Hardware and Platform Figure 1.2: Illustrates how Java works on a typical computer. In the figure 1.2, the Virtual Machine is layered between operating system and the Java objects framework or API. Above the object framework are the user applications written in Java. 1.2 The Evolution of Java Java has been around since 1991, developed by a small team of Sun Microsystems developers in a project originally called the Green project. The intent of the project was to develop a platform-independent software technology that would be used in the consumer electronics industry. The language that the team created was originally called Oak. The first implementation of Oak was in a PDA-type device called Star Seven (*7) that consisted of the Oak language, an operating system called GreenOS, a user interface, and hardware. The name *7 was derived from the telephone sequence that was used in the team's office and that was dialed in order to answer any ringing telephone from any other phone in the office. This PDAtype device was intended to be sold to consumer electronics manufacturers who would distribute the boxes under their company name. In 1993, the team then incorporated as FirstPerson, Inc., decided to gear their technology toward a new implementation for which demand was building in the entertainment industry-interactive television. They proposed their technology to Time Warner as an operating system for set-top boxes and video-on-demand technology that would decode the data stream that Time Warner would be sending to television sets around the country. In June of 1993, Time Warner selected Silicon Graphics' technology over Sun's. A later deal fell apart and FirstPerson decided to disband. Half of the members of the original FirstPerson team continued to work with the Oak technology, however, applying it to multimedia and network computing. Around the time the FirstPerson project was floundering in consumer electronics, a new craze was gaining momentum in America; the craze was called "Web surfing." The World Wide Web, a name applied to the Internet's millions of linked HTML documents was suddenly becoming popular for use by the masses. The reason for this was the introduction of a graphical Web browser called Mosaic, developed by ncSA. The browser simplified Web browsing by combining text and graphics into a single interface to eliminate the need for users to learn many confusing UNIX and DOS commands. Navigating around the Web was much easier using Mosaic. It has only been since 1994 that Oak technology has been applied to the Web. In 1994, two Sun developers created the first version of HotJava, then called WebRunner, which is a graphical browser for the Web that exists today. The browser was coded entirely in the Oak language, by this time called Java. Soon after, the Java compiler was rewritten in the Java language from its original C code, thus proving that Java could be used effectively as an application language. Sun introduced Java in May 1995 at the SunWorld 95 convention. Web surfing has become an enormously popular practice among millions of computer users. Until Java, however, the content of information on the Internet has been a bland series of HTML documents. Web users are hungry for applications that are interactive, that users can execute no matter what hardware or software platform they are using, and those travel across heterogeneous networks and do not spread viruses to their computers. Java can create such applications. 1.3 Object-Oriented Programming Concepts and Java OOP concepts are abstract and designed under a different philosophy than traditional procedural programming languages. Concepts related to objectoriented programming are as followsObjects Object is a basic unit of object-oriented programming. It has state and a behavior. The state of an object pertains to data elements and their associated values. Data elements associated with objects are called instance variables. The behavior of an object depends on the actions that object can perform on the instance variables which are defined within the object. This is called as method (same as “functions” in procedural programming). Thus, the state of an object depends on data and the behavior depends on the actions they can perform. Consider an example, a car is an object that manipulates its speed and direction to transport people to a different location. This car object encapsulates all the functions and data that it needs to get its job done. It has a switch to turn it on, a wheel to control its direction, and brakes to slow it down. These functions directly manipulate the car's data, including direction, position, and speed. All these functions and data work together to define the object called a car. Encapsulation and message passing Objects encapsulate instance variables and related methods into a single, identifiable unit. Therefore, objects are easy to reuse, update, and maintain. The benefit of encapsulation is that one can send messages to any object without having to know how the object works. Only needed is what values a method will accept. For example, When travelling in a car, it is not necessary to know the details of how these operations work. To stop a car, simply step on the brake pedal. It is not necessary to know how the pedal stops the car. Classes Classes encapsulate objects. A single class can be used to instantiate multiple objects. This means a class can have many active objects or instances. Classes are user-defined data types. For example, object car belongs to a class vehicle. Libraries In C++ and other programming languages, a collection of related classes or functions is called a library. Java uses a term “package” to describe a collection of related classes. Just as classes encapsulate objects, packages encapsulate classes in Java. Inheritance Inheritance enables to create a class that is similar to a previously defined class, but one that still has some of its own properties. Consider a car example, Suppose that there is a class for a regular car, but now one has to create a car that has a high-speed passing gear. In a traditional program, existing code has to be modified and this might introduce bugs into code that worked fine before the changes. To avoid this, use inheritance and create a new class. This new class inherits all the data and methods from the tested base class. Add new method to increase the speed. Access modifiers In object-oriented programming, access to methods and variables are controlled through access modifiers. The Java programming language defines four levels of access controls as follows: 1. Private Methods and Variables - Methods and variables that are controlled by an associated object and are not accessible to objects of different classes are generally considered to be private. The advantage is only objects in a particular class can access the methods or variables without limitation. Java's private methods and variables are likewise accessible only by objects within the same class. 2. Public Methods and Variables - Public methods and variables are accessible to all objects, even those outside the current class and package. Java's public methods and variables are accessible by any object or class. Therefore, public methods and variables can be accessed without limitation. 3. Protected Methods and Variables - An associated object controls protected methods and variables. They are accessible to objects in the current class or a subclass of the current class. The advantage is that only objects in specific classes can access the variables without limitation. Java's protected methods and variables are accessible only by methods in the same class or subclass. 4. Friendly Methods and Variables - In most of the circumstances, friendly methods and variables are accessible to other objects. By default, in Java methods and variables are assumed to be friendly and are accessible by any class and objects in the same package. The advantage of this is that objects in a particular package (a set of related classes) can access each other without limitation. 1.4 Difference between C++ and Java No operator overloading in Java No multiple inheritance in Java. No templates in Java. No friends. All assignments are through reference for objects. ie. if one says a = b (a and b are the variables of the same class ) then 'a' also referes to the same object refered by 'b'. No new object is created. No stack allocation for objects (all are on heap) in Java. Java supports Multithreading, Networking , GUI , primitive graphics and Data structures like Vector etc. 1.5 The Primary Characteristics of Java Java is architecture-neutral, distributed, dynamic, interpreted, compiled, multithreaded, network-ready and compatible, object-oriented, Portable, Robust and Secure. The following additional characteristics make Java as strong programming languageDistributed Networked Environments Java is capable to run on heterogeneous and distributed platforms. Hence, it is used is Internet programming. Distributed means objects located on local and remote machines can be used. Java is architecture neutral and highly portable, hence it can be used in distributed networked environments. For example, in network, computers will have different platforms like windows and linux, they also differs in the hardware. But Java works across these heterogeneous platforms. High Performance Performance is the key factor in complex network environments. Java has many features that make it a high-performance language, including its compiler and runtime system. its interpreter is able to execute bytecode which increases execution speed. It has built-in multithreading capabilities, which runs more than one process thread at a time. Multithreading allows Java's interpreter to run processes such as garbage collection and memory management in the background. Processes that run in the background take advantage of idle time for your computer's CPU. Consider an example, in the real world, many things occur simultaneously: The doorbell rings, the phone rings and something is burning on the stove in kitchen. You cannot answer the phone and the door and switch off the stove all at the same time. So what you do is switch off the stove with one hand, hold the phone with the other, and tell the person at the door to wait a moment. To accomplish all three tasks in successive order, you prioritized. Switching off the stove was priority one. The phone call you have been waiting for all afternoon was priority two. The milkman at the door was priority three. Similarly, When the computer is waiting for input from the user, background processes can be busily cleaning up memory, Being able to run background processes while a foreground process waits for input from a user is essential for optimal performance. Easy Reuse of Code A complex network environment changes rapidly. Java code could easily reused even if the environment changed, This is achieved through binding of objects and dynamic linking of classes at runtime, which avoids errors if the environment has changed since the program was compiled. Another way Java avoids errors is that it checks data structures at compile time and runtime. It uses dynamic boundary checking, which ensures that memory boundaries cannot be violated; and by providing for automatic memory management, which guards against memory leaks and memory violations. Security Security features in distributed networked environments are essential, especially in an automated world where computer viruses, Trojan horses, and worms abound. Many of Java's characteristics ensure that it is extremely secure. For example, malicious programmers cannot access system heaps, stacks, or protected sections of memory because Java does not use pointers to memory and only allocates memory at runtime. This prevents malicious programmers from reaching restricted sections of the system. Java also ensures system security at runtime by using bytecode verifier. Before the Java interpreter executes a program, it checks for valid Java code. 1.6 The Architecture Java architecture has four distinct and interrelated technologies: Java programming language Java class file format Java Application Programming Interface Java virtual machine The program is written in source files written in the Java programming language, compile the source to Java class files, and run the class files on a Java virtual machine. This program will access system resources (such as I/O, for example) by calling methods in the classes that implement the Java Application Programming Interface, or Java API. As program runs, it fulfills program's Java API calls by invoking methods in class files that implement the Java API. The relationship between these four parts in Figure 1.3. Run-time environment Compile-time environment Source File Class File A.java A.class Locally through network Java Compiler A.class Class file Java Virtual Machine Object.class. String.class. ss ss Java API Class Files Figure 1.3. The Java programming environment. As shown in figure 1.3, the Java virtual machine and Java API form a "platform" for which all Java programs are compiled. In addition to being called the Java runtime system, the combination of the Java virtual machine and Java API is called the Java Platform. 1.7 Programming with Java Java is a programming language used to create a stand-alone program and also to deliver executable content over networks. It opened a new degree of interactivity and customizability of interaction for the Web. The Structure of the Java Program There are two types of programs that can be built using Java. 1. Java applet refers to a small application that is designed for use on the World Wide Web. Java applets require an external viewer program, so to use an applet, a Web browser or an applet viewer is needed. 2. Java application refers to stand-alone applications. These do not require an external viewer program and are directly executed using Java interpreter. The details about how a Java program should look likeProgram-Naming Structures The Java program or source code is file with .java extension. These files should be plain text files. When the source code is compiled using Java compiler, javac, bytecodes are generated. The executable code or bytecode is stored according to the class or library structure. After compilation, one files for each class declared in the source is generated. Each of these files will be named with the .class extension. These individual files are called compilation units. Java compilation units contain package, import statements, declarations for classes and interfaces. These four components form the basic structure of Java programs. Package Statements Java provides several libraries of classes, which are called packages. The classes in these packages can be by importing them into the application or program. They are compiled in their own name space. To tell Java where to look for packages, use package statements: package PackageName Import Statements Java includes a core functionality that is globally accessible. In Java, the core functions are in the java.lang package. To access packages, classes, and objects that are not declared in this package library, use import statements. Import statements should appear before other declarations in the source code and generally follow package statements if they are used. The idea behind import statements is to help Java find the appropriate methods and to avoid namespace conflicts. To make use of classes in other packages, use this import statement in source code: import java.packagename.*; For example, to use AWT package, use import java.awt.*. Class Declarations In Java, all classes are derived from the system class named Object. This makes Object the root of the class hierarchy and means that all methods and variables in the Object class are available to all other classes. It is this class structure that makes code reuse in Java possible. All classes are by default private unless declared to be public. Class declarations without modifiers follow this general format: class name { //methods and variables associated with the class } Java supports single inheritance of classes. Therefore, each class except Object has only one superclass. This means that any class you create can extend or inherit the functions of only a single class. Although this may seem like a limitation if you have programmed in a language that allows for multiple inheritance of classes, Java supports multiple inheritance of class methods, which is accomplished through the class interface (discussed as next topic). Interface Declarations Interfaces are abstract classes. Through an interface, you can define the protocols for methods and final variables without having to worry about the specific implementation. This allows you to create what could be called outlines for programming structures that you will later define. Interfaces can also be extensions of one or more interfaces. While interfaces are by default private unless declared to be public, an interface's methods and constants are public. Because you do not have to work out the full inner workings of methods associated with an interface, interfaces allow for rapid development. You can later implement the interface in a class declaration. Because a single class can implement more than one interface, it is possible to share the same interface with several classes or any instance of a class. This not only provides considerable flexibility, but it allows a class to inherit the properties of all method calls associated with multiple interfaces, and in turn with multiple classes. A major difference between a class and an interface is that an interface cannot store data. Further, an interface does not provide an implementation for the methods; it only provides the declaration. Interface declarations without modifiers follow this general format: interface name { //methods and static variables associated with the interface } Class declarations that use interfaces follow this general format: class classname implements interfacename { //class body } Or they can take this format: class classname implements interfacename1, … interfacenameN { //class body } An interface requires dynamic method binding, which reduces runtime performance. However, you should note that using interfaces to accomplish multiple inheritance actually reduces runtime overhead compared to the method of multiple inheritance used in C++. First Java Program Java expects its code to be inside a named class. Class Hello { Public static void main(String args[]) { System.out.println(“Hello”); } } In the example, Class Hello { Class is a Keyword and Hello is an identifier. The class definition, code, data will be within the two braces. Public static void main(String args[]) { This statement specifies main method. Here, public is a keyword used as access specifier which indicates that any class can use this method. The keyword static allows the method to be called without having to instantiate a particular instance of the class, as the interpreter calls main method before instances are created. Static methods will not directly refer to anything other than static and local variables. The keyword void specifies that method does not return any value. Java interpreters look for a main method to interpret a class. The statement String args[] declares a parameter named args, which is an array of instances of class String. The statement System.out.println(“Hello”); uses println method of out object of class OutputStream that was statically initialized in the System class. To execute the above code, store it in a file named Hello.java and use the following commands at the command prompt specifying the directory /java/bin (this path is different for different version of Java software). If java is installed in C:\ drive. 1. javac hello.java 2. java hello Output of the code is Hello. The Java API The Application Programming Interface (API) packages contain classes and interfaces for building applets and applications. Java libraries are groups of prewritten classes available for programming. In other languages these procedures are called system service calls, system calls, or library calls. Java library function is a rich resource of functionality for the programmer. These libraries are gathered in packages, which are made up of class libraries. For example packages like-java.applet, java.lang, java.io, java.net, java.awt, java.awt.image, java.awt.peer, java.util. The Java Virtual Machine The Java Virtual Machine (JVM) is the heart of the Java programming language. It helps Java to be architecture neutral, dynamic, interpreted and compiled, network ready and compatible, portable, robust, and secure. JVM provides an abstract specification for which developers can design interpreters and programmers can design applications. This abstract specification is a virtual machine that exists only in nanospace. Because the Java Virtual Machine exists only in memory, the Java developers were able to use objectoriented methodology to pass information-parameters, method calls. It has seven basic parts: A set of registers A stack An execution environment A garbage-collected heap A constant pool A method storage area An instruction set 1.8 Summary This chapter describes that Java is powerful object-oriented programming language. It also discussed about characteristics of Java, basic structure of Java program. Java developed from ideas about platform-independent executable code using JVM. Sun Microsystems researchers have developed Java to be a powerful programming and information delivery system for use with the Web. Exercises 1. Differentiate between C++ and JAVA. 2. Explain how JVM helps Java to be platform-independent. 3. Differentiate between a Java applet and a Java stand-alone application. What are the Primary characteristics of Java? 4.What are the advantages of Object-oriented programming? 5. What is interpreted and compiled programming languages. Give examples. 6. How is OOP better than procedural programming? 7. What are the main elements of a class? 8. Explain the basic structure of Java program. 9. Explain the following terms: a. Packages b. Interfaces c. Import statements 10. Consider a real-world object such as a Washing machine. List the object's data fields and functions. Then, create a class. UNIT2 JAVA Fundamentals This chapter covers the essentials of the Java language. Java programming will be easy for with the experience of C++ because both depend on object-oriented concepts. 2.1 Tokens Tokens are building blocks of Java. When a Java program is submitted to the Java compiler, the compiler parses the text and extracts individual tokens. A token is the smallest element of a program that is meaningful to the compiler. These tokens define the structure of the Java language. Java tokens can be broken into five categories: identifiers, keywords, literals, operators, and separators. The Java compiler removes all comments and whitespaces while tokenizing the source file. The resulting tokens are then compiled into machine-independent Java bytecode capable of being run from within an interpreted Java environment. Identifiers Identifiers are tokens that represent names. These names can be assigned to variables, methods, and classes to uniquely identify them to the compiler and give them meaningful names for the programmer. For example, helloWorld is an identifier that assigns the name helloWorld to the class residing in the helloWorld.java source file. Java has some naming conventions for identifiers. All Java identifiers are case sensitive and must begin with a letter, an underscore (_), or a dollar sign ($). Letters include both uppercase and lowercase letters. Subsequent identifier characters can include the numbers 0 to 9. Java Keywords cannot be used as identifiers. Table 2.1 contains a list of valid and invalid identifier names. Valid Invalid HelloWorld Hello World Hello_Dad Hello Dad! HeyFriend3 3heyFriend (uses a space) (uses a space and punctuation mark) (begins with a numeral) Sink float (this is a Java keyword) baggage #age (does not begin with letter) Table 2.1. Valid and invalid Java identifiers. In addition, it is standard Java practice to name multiple-word identifiers in lowercase except for the beginning letter of words in the middle of the name. For example, the variable toughGuy is in correct Java style; the variables like toughguy, ToughGuy, and TOUGHGUY are all in violation of this style rule. Another important issue is using underscore and dollar sign characters at the beginning of identifier names. Using either of these characters at the beginning of identifier names is a little risky because many C libraries use the same naming convention for libraries, which can be imported into Java code. To avoid name-clashes, one should avoid underscore and dollar sign characters at the beginning of identifier names. A good use of the underscore character is to use it to separate words where you normally would use a space (Hello_World). Keywords Keywords are predefined reserved words, which means that they cannot be changed, their meaning is fixed. They are special tokens. They are always lowercase. Java keywords are used as application flow controls, declarations, class identifiers, and expressions. Table 2.2 lists all the reserved keywords in Java. Data Loop Conditional Exception Structure Modifier Declaration Miscellaneous and Access boolean break case byte continu else char e if double do switch float for int while long short catch abstract final false final class native import ly default new null throw extends private package try implement protected return s public super instance static this of synchroniz true interface ed threadsafe transient void Table 2.2 Reserved keywords in Java. Literals In Java, data is represented by literals. These are based on character and number representations. The types of literals are integer, floating-point, boolean, character, and string. Every variable consists of a literal and a data type. The difference between the two is that literals are entered explicitly into the code. Data types are information about the literals, such as how much memory will be reserved for that variable and possible value ranges for the variable. Integer Literals Integers are whole numbers, such as 1 and 2468. They can be decimal (base 10), octal (base 8), or hexadecimal (base 16). Decimals can be positive, zero, or negative. Decimal literals cannot start with 0, as in 01234. After the beginning number, a decimal literal can consist of the numbers 0-9. Numbers beginning with 0 are reserved for octal and hexadecimal literals. The positive decimal integer ranges between -2,147,483,648 or –2 31 31 and 2 -1, or 2,147,483,647. Octal literals start with 0 and can be followed by any number 0-7. They can be positive, zero, or negative. The maximum value of an octal literal is 31 017777777777, which is equivalent to 2 -1. Hexadecimal integer literal start with 0x or 0X followed by one or more hexadecimal digits. Letters A-F used in a hexadecimal integer can be uppercase or lowercase. Hexadecimal integers can be positive, zero, or 31 negative. The upper limit of a positive hexadecimal literal is 0x7fffffff (2 -1). The values available are 1-9, A-F, and a-f. A compile-time error will occur if any of these values is exceeded. Floating-Point Literals A floating-point literal represents a number that has a decimal point in it, such as 3.7. Java standards specify that floating-point numbers must follow IEEE754 specification. Single-precision floating-point numbers consist of a 32-bit space and are designated by uppercase or lowercase ‘f’. Double-precision numbers are allotted a 64-bit space and are designated by uppercase or lowercase ‘d’. Double-precision floating-point numbers are the default. Therefore, 3.7 is a double-precision floating-point number, and 3.7f is a single-precision floating-point number. Compile-time errors will occur if a nonzero floating-point literal is too large or small. The largest magnitude single-precision floating-point literal is ±3.40282347e+38f, and the smallest is ±1.40239846e-45f. The largest double- precision floating-point number is 1.79769313486231570e+308, and 4.94065645841246544e-324 is the smallest floating-point number. Boolean Literals A boolean literal is either of the words true or false but no numeric value such as 0 or 1 is assigned. Therefore, the value of a boolean literal is ‘true’ or ‘false’. Character Literals A single character as a value is represented by character literals. The value of a character literal is enclosed by single quotes. An example is 'a'. A value of character literal can be a single quote, a backslash, or other nonprintable characters. A backslash (\) is used to designate certain nonprintable characters or characters that are part of the command. (Same as escape sequences in C/C++). Table 2.3 shows some examples of character literals. Description Sequence Output 'y' y Backspace (BS) '\b' Backspace Horizontal tab (HT) '\t' Tab Linefeed (LF) '\n' Linefeed Formfeed (FF) '\f' Form feed Carriage return (CR) '\r' Carriage return Double quote '\"' " Single quote '\'' ' Backslash '\\' \ Octal bit pattern '\ddd' Octal value of ddd Hex bit pattern '\xdd' Hex value of dd '\udddd' Actual Unicode character of dddd Any character Unicode character Table 2.3.Character literals. Compile-time errors occur if anything other than a single quote follows the value. String Literals String literals are a sequence of characters enclosed in double quotes, such as "Java Programming Language". This could be "" for a null character string. The javac compiler does not strip out whitespace from within string literals. String literals can be concatenated. A string literal cannot be more than one line, if it is more than one line then it is be broken up at declaration time and then concatenated during its usage. Consider an example, if one string contained "India is" and another string contained "beautiful country", they could be concatenated together. The representation would be " India is " + " beautiful country ". (No spaces on either side of the plus sign.) . Separators Java uses the following separators: (), {}, [] , ; , , , and .. The compiler uses these separators to divide the code into segments. Separators are also useful as visual and logical locators for programmers. For example, consider the code fragment: while ( loc < 20) { Here, the parentheses indicate Boolean expression to be evaluated, which is whether the value of variable loc is less than 20. The trailing {indicates the start of a block of code that will be executed if the Boolean expression is true. Comments and Whitespaces Whitespace consists of spaces, tabs, and linefeeds. The Java compiler removes all occurrences of spaces, tabs, or linefeeds. Comments are used to give explanation for each statements or group of statements for better understanding of user. It can also be used to block out certain code sections for testing purposes and to separate logic, in which case there may be no text. . They have an initial indicator and an end indicator. Comments are of three different ways, as shown in Table 2.4. Type /* comment */ // comment Description All characters between /* and */ are ignored. All characters after the // up to the end of the line are ignored. /** comment */ Machine-generated comments Table 2.4. Comments in Java. Consider the following examples of using the various types of comments: /* This is an example of a comment */ /** this is another example of a comment. This is to represent multi-line comments, until the proper end of comment */ // Single-line comment // Start each line with this comment marker for multiline comment Operators Operators specify an evaluation or computation to be performed on a data object or objects. These data objects or objects are called as Operands, which can be literals, variables, or function return types. The operators supported by Java are as shown in the Table 2.5. Operator Operation Example Meaning Arithmetic Operators + Addition A + B - - Subtraction A–B - * Multiplication A*B - / Division A/B - % Modulus A%B - Increment and Decrement operators ++ Increment by 1 A++ or ++A A = A + 1 -- Decrement by 1 A-- or --A A = A -1 Assignment operators A = 7 A=7 Add to current variable A += B A=A+B -= Subtract from current A -= B A=A-B *= Multiply current A *= B A=A*B /= Divide current A /= B A=A/B %= Modulus current A %= B A=A%B = Assign value += Comparison Operators (return true or false) == Equal A== B Is A equal to B? != Not equal A!= B Is A not equal to B? < Less than A < B > Greater than A> B Is A less than B? Is A greater than B? <= Less than or equal A <= B Is A less than or equal to B? >= Greater than or equal A >= B Is A greater than or equal to B? Table 2.5. Java Operators (Contd…) Operator Operation Example Meaning Bitwise operators & Bitwise AND - - | Bitwise OR - - ^ Bitwise XOR - - << Left shift - - >> Right shift - - Zero fill right shift - - ~ Bitwise complement - - <<= Left shift assignment - - >>= Right shift - - - - - - - - - - >>> assignment >>>= Zero fill right shift assignment x&=y AND x|=y OR x^=y NOT assignment assignment assignment Table 2.5. Java Operators 2.2 Expressions The main purpose of writing a program is to manipulate, display, and store data. Expression is a way of performing a computation. Operators are used in expressions to do specific task and to operate on declared variables. Hence, expression is a meaningful combination of operators and operands (declared variable or literal) to perform specific task. For example, expression a + b perform addition of a and b (variable a and b must be declared). Operator Precedence Operator precedence determines the order in which operators are evaluated. Java expressions are typically evaluated from left to right. The following expression illustrates the problem: b = 2 *2 + 16 / 4 Here, the multiplication operation 2 * 2 is carried out first, which leaves a result of 4. The addition operation 4 + 16 is then performed, which gives a result of 20. The division operation 20 / 4 is then performed, which gives a result of 5. Finally, the assignment operation b = 5 is performed, in which the number 5 is assigned to the variable b. List of all the Java operators from highest to lowest precedence is as shown in Table 2.6. Same Precedence Highest . [] () ++ -- ! * / % + - << >> >>> < > <= == & ^ && != || ?: = Lowest Table 2.6. Operator Precedence ~ >= In the Table 2.6, all the operators in a particular row have equal precedence. The precedence level of each row decreases from top to bottom. This means that the ( ) operator has a higher precedence than the * operator, but the same precedence as the [ ] operator. Consider the below expression as an example, b = 2 *2 + 16 / 4 Check the precedence of operators in the above expression. The multiplication (*) and division (/) operators both have the highest precedence, followed by the addition operator (+), and then the assignment operator (=). Because the multiplication and division operators share the same precedence, evaluate them from left to right. So, first perform the multiplication operation 2 * 2 with the result of 4. Then perform the division operation 16 / 4, which results in 4. After performing these two operations, the expression looks like this: b = 4 + 4; Because the addition operator has a higher precedence than the assignment operator, addition operation 4 + 4 is then performed resulting in 8. Finally, the assignment operation b = 8 is processed. As observed, expression evaluation with precedence gives different result. Consider another example, expression with parenthesis for grouping purposes, a = 2 * (14 - 7); Without parentheses, multiplication operation is performed first and then the subtraction operation. But, according to the precedence list, the ( ) operator has highest precedence. So the subtraction operation 14 - 7 is performed first, which gives the result 7 and the multiplication 2 * 7, which gives result 14 is performed and finally value 14 is assigned to variable a. 2.3 Using Data Types Data types define the storage methods available for representing information, along with how the information is interpreted. It determines how the compiler interprets the contents of the memory. To create a variable in memory, declaration is needed which provides the type of the variable as well as an identifier that uniquely identifies the variable. Data types can be stored in variables, passed as arguments, returned as values, and operated on. There are two major data types in Java: Reference types and Primitive types. The syntax of the Java declaration statement for variables follows: Type Identifier [, Identifier]; The declaration statement tells the compiler to reserve a memory for variable of type specified in ‘Type’ keyword. Finally, as in all Java statements, the declaration statement ends with a semicolon. Consider an example, char my_pen; Here, the type is char and the identifier is my_pen. The variable name my_pen has the value of null, which is the default value of type char. Finally, the semicolon tells the compiler that the defining of the variable is finished. Consider another example, int no_of_var, x, RedRose, table; This has four variables: no_of_var, x, RedRose, and table. Each of them is of type int. This shows multiple variables are declared in single statement. The default value for integers is 0. Primitive Data Types Primitive data types can have only one value at a time. They are not derived from any other types. Integer, floating-point, boolean, and character types are all primitive types. Integer Data Types Integer data types are used to represent signed integer numbers. There are four integer types: byte, short, int, and long. Each of these types takes up a different amount of space in memory, as shown in Table 2.7. Type Size byte shor t 8 bits 16 bits int 32 bits long 64 bits Table 2.7. Java Integer Types Following are some examples of declaring integer variables: int k; short VehicleFuel; long rectangle, area; byte yellow, purple, white; Floating-Point Data Types Floating-point data types are used to represent numbers with fractional parts. There are two floating-point types: float and double. The float type reserves 32-bit storage for single-precision number and reserves 64-bit for double-precision number. Following are some examples of floating-point variable declarations: float temp; double Speed, Pressure; Boolean Data Type The boolean data type is used to store values either true or false. Consider the example, boolean timeOver; Character Data Type The character data type is used to store single Unicode characters. It is stored as a 16-bit unsigned integer. Consider an example, char initialState, finalState; Reference Data Types Reference data type variables are logically grouped together for manipulation. Here identifier points to dynamically allocated objects. This contains the address of a value rather than the value itself. There are three types of reference variables: array (discussed in this section), classes, and interface (discussed in Unit-3). Arrays An array is a collection of variables of similar data type. Array items can have either a simple or composite data type. Arrays also can be multidimensional. Java arrays are declared with square brackets [ ]. Consider the following example of array declarations in Java: int num[]; char[] letters; long matrix[][]; Java does not allow specifying the size of an empty array when declaring the array. The size of the array is assigned with the new operator or by assigning a list of items to the array at time of creation. Consider an example of arrays declared, set a specific size by using the new operator and by assigning a list of items in the array declaration: char alpha[] = new char[26]; int even = {4, 6, 8}; Strings In Java, a special class called String handles strings. Even literal strings are managed internally by an object of a String class. Like C and C++, strings are represented as an array of characters. Consider an example of strings declared using the Java String class: String info; String name = "SunMicro"; 2.4 Declarations The declaration statement defines the type of variable. Declarations can happen anywhere in sections of code, but for best readability group them together in the beginning of a code section. Blocks are sections of code beginning and ending with curly braces ({}). Blocks are logical unit of code that can call methods, perform expressions, display output and so on. A variable declared in a block is valid for that block and all its sub-blocks; this is the scope of the identifier. However, the scope of a variable does not move outside the enclosing block. A variable declared in a block has no meaning in the area outside its curly braces. Consider the following example, class Hiding { public static void main (String args[]) { int Top; Top = 2; ... switch (ACommand) { case '1': int Top = 4; // Top has just been declared again // and assigned a value of 4 break; ... } .... /*return to the main loop System.out.println(Top); /*Top still has a value of 2*/ } Here, the variable Top that is declared in case command is valid for that blocks only. Any values assigned to it are within scope of that block. When program execution returns to the main block, any values assigned to the new variable are lost. Declaring integer Types Variables of type integer are declared by the amount of memory space they will be allotted. Following are examples of integer declarations: byte Var1; //8 bits short Var2; //16 bits int Var3; //32 bits long Var4; //64 bits Declaring Floating-Point Types Floating-point variables are 32 or 64 bits in length. Following are examples of floating-point declarations: float a; //32 bits double b; //64 bits Declaring character Types A character type variable holds only one character. This is different from the Strings class, which contains groups of characters. Remember that the char type holds an integer that references the Unicode character. The following sample code declares two character types: Char alpha; // holds one character char alpha = 'k'; // declares variable alpha and assigns k to it Declaring Arrays Arrays are one-dimensional lists of objects that are referenced by subscripts. They can consist of other arrays, resulting in multidimensional arrays. Arrays are declared as follows: char Array1[]; //one-dimensional array char Array2[][]; //two-dimensional array int Array3[]; //one-dimensional array of integers int []Array4; //equivalent to Array3[] 2.5 Control Flow The ability to make decisions in the program is most essential. These decisions instruct the program which expression to solve or what data to assign to a variable. Control flow instructs the program how to make a decision and how further processing should proceed on the basis of that decision. The building blocks of control flow are the { and } block delimiter characters , if, while, do, for, and switch keywords. Decision is taken based on a condition is true and then executing a different section of code, based on the result. This is called a conditional expression. Blocks and Statements A statement is any line of code ending in a semicolon. A statement can be an expression, a method call, or a declaration. A block is a group of statements that form a single compound statement. Think of blocks as statements logically grouped together for program flow and readability. Blocks starts with character ‘{‘ and ends with character ‘}’. For example, the following is considered a block of code: { Store = "Grocery"; a=b+c; System.out.println( a); } When the program runs and gets to this block of code, it will begin execution at the beginning { and will not continue execution elsewhere until leaving the final }. The opening {, the closing }, and all code in between is considered a block. The curly braces must be paired one with one another. Conditional Statements Conditional expressions will execute based on a conditional test. This code can be a single statement or blocks. Conditional expressions are used to make decisions in a program. They are used to evaluate whether a condition is true or false and will branch to different sections of code based on the result. if The simplest conditional expression. An if statement makes up a conditional expression of the form if (expression) statement; or if (expression) { statement(s); } If the expression in the parentheses evaluated and result is boolean true, statement is executed. If the expression evaluated and result is false, statement is skipped and execution continues at the statement following the if statement. Consider the following example, int Num ; // declare variable Num = System.io.read(); // get character from keyboard if ( (Num % 2) != 0 ) System.out.println("odd"); // test if number is odd and // print "odd" if it is Single-digit number is read using System.io.read (retrieve only one character at a time). In this example, the program reads a number from the keyboard. It is then tested to determine if it is odd. If it is, the System.out.println statement is executed and the program terminates or continues to the next statement block. else The statement following the if expression is executed only when the condition is true. The statement following the else is executed only when the if condition is false int Num ; Num // declare variable = System.io.read(); keyboard // get character from if ( (Num % 2) == 0 ) // test if number is even { // begin if block System.out.println("even"); // print message to screen } // end if block else // else if number not even { // begin else block System.out.println("odd"); // print message to screen } // end else block Consider an example for Nested if (if statement within if), If(a>b) { If(a>c) { System.out.println(“a is greater”); } } Switch Switch statement performs a multiway branch. Switch statements are of the form switch (expression) { case value: statement(s); break; case value: statement(s); break; . . . default: statement(s); break; } Switch statement begins with the keyword switch, the parenthesis contains value that evaluates to a byte, char, a short or int. Then the case keywords, each followed by a value. This must also be of type byte, char, short, or int. It evaluates the expression in switch statement and then scans case statements until there is a exact match. If there is match, then corresponding group of statements between the case and break will be executed. If no matches are found and a default case is executed. If no default is present, execution will scan through the entire switch construct and will not do anything. When the break is encountered, execution will resume at the first statement following the switch construct. If break is not present, program execution falls through to the next case statement. It keeps executing that group of statements until a break is encountered, so be sure to place appropriate breaks. Consider an example, here expression is a char type, and each case contains a corresponding char value. static void Arithmetic(char opera) { switch (opera) { case '+': System.out.println(a+b); break; case '-': System.out.println(a-b); break; case '*': System.out.println(a*b); break; case '/': System.out.println(a/b); break; default System.out.println("Invalid choice"); break; } } Looping Statements Looping expressions are executed till certain condition is true. Some looping expressions check the condition before executing the code (Pre-conditional statements). Some other looping expressions check the condition after executing the code (Post-conditional statements). while The while loop repeatedly executes a block of code as long as a boolean condition is true (Pre-conditional statement). General syntax of while loops is as follows, while ( expression ) statement; or while ( expression ) { statement(s); } As shown in the syntax, while construct begins with keyword “while”. The parentheses contain an expression, which must evaluate to check the condition. A statement or a block follows this. First, the expression in while statement is evaluated. The evaluated value is checked against a condition in the while statement. The block (known as body of while loop) in the while construct are executed only if the result is true. The body of while is executed until the evaluated result of expression is false. If it is false, execution will continue with the next statement following the while loop. Consider an example, int a=1,sum=0; while (a<5) { sum=sum+a; a++; } This example adds numbers from 1 to 5. Initially value of a=1 and the expression “a<5” is evaluated which returns the result as ‘true’, hence, it executes the statement sum=sum+a and increments the value of a. The value of a is incremented to update the value for the condition otherwise loop is executed for infinite times. In the second iteration, value of a=2, again evaluates the expression, in this case also it returns true, block in the while loop is executed. This continues till a=6, where expression returns false and while loop ends. do-while The do loop repeatedly executes a block of code until a boolean expression evaluates to false. Here, a block in the do-while loop is executed first and then the condition is checked (post-conditional statement). This means that the block in the loop will always be executed at least once. General syntax is as follows, do statement; while ( expression ); or do { statement(s); } while ( expression ); The do construct begins with keyword “do”, followed by the parentheses containing an expression that must evaluate to a boolean. Loop contains a statement or a block. When a do loop is encountered, the statement or block is executed. When the do loop body completes, expression is evaluated. If it is false, execution will continue with the next statement following the do loop. If it is true, the body of the do loop will be executed again. The body will continue to be executed until the expression evaluates to false. Consider an example, int a=1,sum=0; do { a++; sum=sum+a; } while (a<5); In this example, the body of the while loop is executed, which adds valus of a to sum and increments the value of a. The expression is then evaluated to determine if a is less than 5. If it is true, the do loop body will be executed again. Otherwise, execution will continue with the first statement after the do loop. This will continue until a is less than 5. for The for loop enables code to execute repeatedly until a boolean expression evaluates to false. Initializing a loop variable, modifying it and expression are in the same statement with in for statement. General syntax is as follows, for (initialization; expression; modification) statement; or for (initialization; expression; modification) { statement(s); } For loop begins with keyword “for”. The parentheses contain an initialization, an expression, and a modification statement. The initialization can be a statement is to initialize part of the expression. A semicolon (;) follows initialization, followed by an expression, which is evaluated to a boolean, this is followed by another semicolon and then modification statement which modify part of the expression. Finally, a statement or a block follows this. When a for loop is encountered, initialization is first executed, and then the expression. If it evaluates to true, the statement or block following for statement is executed. This statement or block is known as the body of for loop. When the end of the body is reached, modification is executed. The expression is then evaluated again. If it is false, execution continues with the next statement following for loop. The body continues to be executed until the expression evaluates to false. Consider an example, int sum=0,a; for (a=1; a<5; a++) { sum=sum+a; } In this example, value of a is initialized to 1, expression is then evaluated to determine if a is less than 5. If true, the body of for loop will be executed, which will add value of a to sum. Otherwise, execution will continue with the first statement after for loop. This continues until the value of a is 6. For loops are also used to evaluate a range of numbers which is used with arrays or other indexes. Consider an example in which for loop will initialize I to a value of zero and displays the elements of array alpha starting from position I=0. int alpha[] = new int[ArrSize]; for (I=0; I < ArrSize; I++) { System.out.println(alpha[I]); } break The break construct can be used to come out of the middle of for, do, or while loop. (as discussed about break in switch statement). When a break statement is encountered, execution of the current loop immediately stops and resumes at the first statement following the current loop. Consider an example, int i; for (i=0; i < ArrSize; i++) { if (i < 0) { System.out.println("Invalid Position"); break; } System.out.println(alpha[i]); } Again, this code will check the array index for negative. If the index is negative, if executes body of if which contains break statement. By including the break statement, execution of this for loop will stop at the first negative index. In this example, a negative index of array is considered so severe that no other processing should be done. Also notice that no else statement is needed because if an error occurs, execution will jump to the end of the loop, skipping the processing code. continue The continue construct can be used to short-circuit parts of a for, do, or while loop. When a continue statement is encountered, execution of the current loop immediately resumes at the top, skipping all other code between it and the end of the loop. Consider an example, int i; for (i=0; i < ArrSize; i++) { if (i < 0) { System.out.println("Invalid Position"); continue; } System.out.println(alpha[i]); } Again, this code will loop through looking for negative array index. However, the inclusions of continue statement means that execution of this for loop will not continue in the body of the loop if a negative index is encountered. In this example, a negative index is considered illegal and should not be processed. However, it is not so severe that it stops processing other entries. Labeled Loops If break and continue only jump to the end or beginning of the current loop. If this jumping is required beyond the current loop, then use labeled loops. Add a label to a loop and reference it in a break or continue statement. Consider the following example in which, if a negative index is encountered, execution will branch to the end of for loop labeled error, rather than the normal inner one. Without this construct, additional flag variable is used test in the outer loop. error: for (i=0; i < ArrSize; i++) { for (i=0; i < ArrSize; i++) { if (i < 0 && j<0) { System.out.println("Invalid Position"); break error; } System.out.println(alpha[i]); } } 2.6 Summary This chapter covers the most basic parts of the Java programming language. It gives many examples of ways to use tokens, literals, data types, expressions, declarations, and control flow. Together these form the fundamentals of any program developed in Java. This chapter is also a good reference for correct syntax. Exercises 1. What is Token? 2. What is a constant? 3. What is a variable? 4. Name the eight data types used in Java. 5. Why separators are needed in a program? 6. What is variable scope? 7. Suppose you need to write a program to find employee salary. Write declarations for the needed variables. 8. Using the variables in exercise 7, write the program statements needed to perform the salary calculations. 9. What is an expression? 10. What is the result of the logical expression (3 < 5)? 11. What is the result of the logical expression (3 < 5) && (5 == 4 + 1)? 12. What are the six comparison operators? 13. What is the result of the logical expression (3 < 5) || (6 == 5) || (3 != 3)? 14. Write the result of the logical expression (5 != 10) && ((3 == 2 + 1) ||(4 < 2 + 5))? 15. What's the result of the logical expression (5 == 2 + 3) && !(5 + 2 !=7 - 5)? 16. Write an expression that compares three numbers for equality. 17. Write an expression that determines whether one number is less than or equal to another. 18. Write an expression that uses three different types of comparison operators. The expression must be false. 19. If the variable num1 is equal to 5 and the variable num2 is equal to 10, how to evaluate the logical expression ((num1 != 5) || (num2 == 10)) && !(num1 == 5)? Show each step of the evaluation. 20. What is program flow? 21. Define conditional and Looping. 22. What are two ways to control program flow? 23. In the following Java example, if num2 equals 5, will the second line execute? if (choice == 3) num2 = choice; 24. Are braces must in an if statement? Explain. 25. What is the difference between a logical expression and a Boolean expression? 26. In the code sample P.1, what happens when choice equals 5? Program: P.1 if (choice == 1) { num = 1; num2 = 10; } else if (choice == 2) { num = 2; num2 = 20; } 27. Compare if and switch statements. 28. What value is assigned to num in the code sample P.2, when choice equals 2? Program: P.2 switch(choice) { case 1: num = 1; break; case 2: num = 2; case 3: num = 3; break; default: num = 0; } 29. Write an if statement that sets the variable num to 1 when choice equals 10. 30. Write an if statement that sets the variable num to twice the value of the control variable choice. Valid values for choice are 3, 4, 5, and 6. 31. Convert the if statement in exercise 29 to a switch statement. 32. What is the body of a loop? 33. How does Java determine when to stop looping? 34. How many times is a while loop guaranteed to execute? 35. What's an infinite loop? How to avoid this? 36. Compare and contrast while and do-while loops? 37. How many times will the loop shown in Program P.3 execute? int count = 10; do { ++count; } while (count <= 15); 38. Write a while loop that executes 20 times. 39. Convert the while loop in exercise 38 to a do-while loop. 40. Write a while loop that will result in an infinite loop. 41. Write a do-while loop that can never execute more than once. 42. Write a while loop that counts backwards from 20 to 10. 43. How do you know when to use for loop? 44. What are the three parts of for loop? 45. When does for loop stop looping? 46. How can a for loop count backward? 47. How can a for loop count by tens? 48. Is it possible to create an infinite loop with for loop? 49. How many times will the loop shown below execute? What will x equal when the loop finishes? for (int x=3; x<12; x+=2) { ++count; } 50. Write for loop that executes 15 times. 51. Write a for loop that counts backwards from 20 to 10. 52. What is an array? 53. What is a two-dimensional array? 54. If you had an array of 50 integers, what is the largest valid index? 55. What happens if you try to access a nonexistent array element? 56. How would you use for loops to initialize a two-dimensional array? 57. Declare an array that can hold 50 integers. 58. Write the code that creates the array declared in exercise 56. 59. Write for loop that initializes the array to the values 50 through 99. 60. Why for loop is appropriate for accessing an array? UNIT 3 JAVA Classes, Packages and Interfaces 3.1 Introduction The starting of object-oriented programming in Java is classes, which provide templates for specifying the state and behavior of an object at runtime. An object is said to be an instance of a class. For a given class and runtime session, there can be multiple object instances. Everything in the language is designed to use small, somewhat self-contained pieces of code, or objects. Objects use the fundamentals such as declarations and expressions to do the real work of the language. The idea is to use these pieces of code in appropriate ways without writing again and again. This chapter describes how to create and use objects. In the Unit-2, "Fundamentals of the Java," covers the smallest parts of objects, such as primitive data types and control flow keywords, this chapter describes about how to put the small pieces to work in a structural framework. To create applications with Java, it is essential to understand how the parts fit together. Hence group objects into classes. Classes are given characteristics through inheritance. Class libraries are groups of classes. Packages are groups of class libraries. Methods are functions that perform activities within classes. Methods can have templates managed by interfaces. These are abstract concepts. This chapter is full of examples to make the concepts concrete and easy to understand. 3.2 Classes A class is a template or prototype that defines a type of object. It encapsulates both data (called fields in Java) and the functions (called methods) that operate on that data. Defining a Simple Class A class is equivalent to a data type such as int, but the difference is class is user-defined data type or derived data type. A class is defined using keyword “class” followed by class name as shown below, class ExampleClass { } This class definition is stored in a file ExampleClass.java. This is compiled into a .CLASS file. The body of the class is written between the curly braces. In the class ExampleClass, the body is empty and doesn't do anything. To create an object from a class, follow the below syntax, Classname objectname = new classname ( ); For example, ExampleClass ExamObject = new ExampleClass ( ); A class generally consists of variables and methods. Variables fall into two categories: those that are particular to an instance called as instance variables and those that are global to all instances of a particular class, known as class variables. Consider the following example, class FirstPerson { int age = 0; public void setData(int newAge) { age=newAge; } public int getData( ) { return age; } } This class FirstPerson consists of a single variable, called age, which is initially set to 0. It has two methods. The setData( ) method is used to set age to the specified value. The getData( ) method returns the current value of age. The variable age is called as instance variable. This type of variable is defined for an instance of an object. It differs from a local variable, which is defined inside a block of code or a method. Consider an example, public int getHalfage() { int half; // A local variable half = age / 2; return half; } The variable half is a local variable; it will not exist after the getHalfage( ) method is executed. However, instance variable age exists until the object instance is destroyed. The name of a class follows same naming conventions same for identifier. By convention, a class name should begin with a capital letter. This makes the class easily distinguishable from methods, variables, and so on. Hence, it is highly recommended. Class Variables Class variables are declared in the same way any variable is declared in a program. The general syntax is data type of the field followed by the name of the field. For example, int myAge. This declares a data field of type integer. But with this, one cannot say myAge is actually part of an object or just a normal variable. To clear up this ambiguity, add int myAge into the FirstPerson class definition as shown in example, class FirstPerson { int myAge; } The data field myAge is by default accessible only by methods in the same file. The accessibility is controlled using the public, protected, and private keywords (as discussed in Unit1). Instance Variables Instance variables exist only for a particular instance of an object. Each different instances of a given class can have a variable of the same name, but Java stores different values for that variable in different places in memory. Each of these instance variables is manipulated individually. Instance variables can be accessed from other instances, but the variable exists only in a particular instance. They are declared after a class declaration but before method declarations. Every instance of that class has a copy of this variable and can modify it as needed without affecting any other instance copies of the variable. Consider an example of instance variable declaration, class Flower { String[] name; String[] color; } Here every instance of class Flower has a name and color variables used to store information about a particular flower. Suppose, there are two objects of class Flower, each of these can access both the variables without any overwriting. Static Variables Static variables exist in only one location and are globally accessible by all instances of a class. A variable cannot be changed by a subclass if it has been declared static and final. Further, static variables have the same information in all instances of the class. This is a powerful when a variable is shared by several instances of a class and/or subclasses. All instances will have the same value for the variable. All classes accessing that variable point to the same place in memory. This variable will remain there until the last instance accessing the variable is flushed from memory. A static variable is declared in the same way as an instance variable but has the keyword static in front of it. In the below example, the variable Type is declared static and is thus the same for all instances of class. All the instances can check this variable for the value of Type. class Flower { static String Type[] = "rose"; } Predefined Instances Java has three predefined object values: null, this, and super. null A variable can be created that is simply a placeholder for subclasses to fill with values. In this situation, a variable can be declared null, meaning that no value is assigned to a variable, as in the example, int FlowerType = null; //FlowerType is an empty object Following is a code fragment using null: class Flower{ static String name = null; public void main (String args[]) { Flower rose = new Flower(); if (Flower.name == null) { promptForName("Enter name> "); } } In this example the variable name is initialized to null. It is then tested in main to see if the variable is null. If so, the user is prompted to enter the flower's name. null cannot be used with primitive data types. this This is used to refer the current object, which allows the current instance of a variable to be referenced explicitly. This is useful when the current instance of a variable is to be passed to another class that will also use the variable: void promptForName (String prompt){ StringBuffer name; char ch = '\0'; name = new StringBuffer(); System.out.print(prompt); System.out.flush(); While (ch != '\n') { try {ch = (char)System.in.read(); } catch (IOException e) {}; name.append(ch); } this.name = name.toString(); } The compiler understands implicitly that the current instance of a class variable is this. Do not explicitly reference it unless necessary. super super is a reference to the superclass. It is often used as a shortcut or explicit way to reference a member in the superclass of the current class. Consider an example in which, a subclass named LilyFlower uses the super keyword to reference the method promptForName in its superclass, Flower. LilyFlower would look for a method called promptForName in the current class if super were not used and generates a compile error. class LilyFlower extends Flower { void getLilyInfo { super.promptForName() : } } Class Methods Methods in Java are functionally similar to functions in C and C++. They provide a way to group a block of code together and then refer to it by name. You can use the block of code again simply by referring to the name of the method. Also, the code does not have to intrude into the middle of other code. Methods do not have an explicit declaration keyword as classes do. They do have names, arguments and return types. Arguments are parameters that are passed to the method when it is called so that a method can be made to do different tasks. The code internal to the method knows how to manipulate the input parameters. Methods also have a return type. This is a value that can be returned to the code that called the method. Return values can be of any valid Java type, including strings and numeric values. Methods can be called from current class, subclasses, superclasses and even entirely unrelated classes. Consider an example, public static void main (String args[]) { ...body of method.... } It is the method main, which is the first method called when a stand-alone Java application is started. In this example, public and static are method modifiers, void is the return type, main is the name of the method, and (String args[]) is the list of method arguments. This is followed by an opening { that marks the beginning of the body of the method. The method body can consist of any valid block of Java code. It can also include calls to other methods, even itself. Finally, the method body is followed by a closing }. Return Types Methods can return any valid Java type. This could be a simple boolean, an array, an object. The return type immediately precedes the variable name of a method. Consider the following example in which a method named isEqual to return a variable with type boolean: boolean isEqual (Number num) { if (num ==1) return (true); else return (false); } The method body tests whether the num passed is 1. If it is correct, the method returns value true using keyword “return”. Otherwise, it will return false. void is a special return type in Java that indicates that there is no return type of any kind. This is used for methods that return nothing to the calling program. For example, method to print the output. Method Modifiers Method modifiers control access to a method. They are also used to declare a method's type. Declaring Method Security and Accessibility Method-declaration statements provide information to the compiler about allowable access. In Java terms, accessibility is security. The five levels of access are as shown in table 3.1. Level Allowable Access public All other classes private No other classes protected Subclasses or same package private protected <default> Subclasses only Same package Table 3.1. Five levels of access private The private modifier specifies those classes and subclasses cannot call this method. This can be used to completely hide a method from all other classes. If no other classes can access the method, it can be changed as needed without causing problems. Here is an example of a method declared private: private void isNum (Number num) { .... } protected The protected modifier specifies that only the class in which the method is defined or subclasses of that class can call the method. This allows access for objects that are part of the same application, but not other applications. Here is an example: protected void isNum (Number num) { .... } private protected The private protected modifier is a special combination of private and protected access modifiers. This modifier specifies that only the class in which the method is defined or subclasses of the class can call the method. It does not allow package access as protected does but also allows subclasses, as private does not. Here is an example: private protected void isNum (Number num) { ..... } default This provides an access control in which the class itself, subclasses and classes in the same package can call the method. In this case, no access type is explicit in the method-declaration statement. Here is an example: void isNum (Number num) { .... } static The static modifier is associated only with methods and variables, not classes. The static modifier is used to specify a method that can only be declared once. No subclasses are allowed to implement a method of the same name. This is used for methods, such as main, that are entry points into a program. The operating system would not know which method to call first if there were two main methods. Static methods are used to specify methods that should not be overridden in subclasses. Here's an example: static void isBlack (Color color) { .... } final The final modifier indicates that an object is fixed and cannot be changed. If this modifier is used with a class-level, then it means that the class can never have subclasses. When modifier is applied to a method, the method can never be overridden. When applied to a variable, the value of the variable remains constant. Compile-time error occurs if final method or class is overridden and if the value of final variable is changed. Consider an example, class ExampleFinal { final int ValueFinal = 10; // a final variable final int MethodFinal(int x, int y) { } } // a final method abstract The abstract modifier is used to create template methods, which are very similar to function prototypes in C and C++. Abstract methods define return type, name, and arguments but do not include any method body. Subclasses are then required to implement the abstract method and supply a body. Here is an example of an abstract class: abstract void isBlack (Color color) { } This defines a template for a method named isBlack. Notice that no body of isBlack is specified; that is left to subclasses of the class in which the abstract method is declared. The subclasses must implement a body for method isBlack, or they will cause a compile-time error. Overloading Methods The concept of overloading methods seems nonsensical at first. But when the idea seeps in, you will see that overloading adds to the power of Java. Why would anyone want to define methods with the same name but very different functionality? This is precisely what overloading does. You can define a method with the same name multiple times. Java selects which method of the same name to call on the basis of the calling parameters. Every overloaded method must have a different and unique parameter list. With Java you can overload any method in the current class or any superclass unless the method is declared static. For example, in the following code, method isBlack has been overloaded three times: class CheckForBlack { public boolean isBlack (Color color) { if (color == black) return(true); else return(false); } public boolean isBlack (String desc) { return(desc.compareTo("black"); } public boolean isBlack (Paint paint) { if (paint.reflectedLight < .05) return(true); else return(false); } } Each method has the same name and return type, but each has a different argument list. The first checks to see if the color passed to the method is equal to the color black. The second method compares a string passed to the argument to see if it is equal to the string "black". The last method determines if the paint object passed in to the method has a reflected light percentage of less than 5%. If it does, it is considered black. In all these cases, the method name and return type are the same, but the arguments are different. The Java compiler automatically uses the method that matches the arguments passed in the call to determine the correct method. The Java compiler issues an error if no method call has arguments to match any of the methods. Method overloading allows for flexible use of method calls. In the isBlack example, if you need another type of test, simply add it to the existing CheckForBlack class. A Java program can make isBlack calls using the new object. In this way, you can cover multiple types of tests with only one method name. Overriding means that the programmer does not need to come up with different names for a method that accomplishes the same thing, but perhaps in a different way. The programmer can concentrate on readability and consistency without having to worry about method names. This also means that in a large project, a programmer does not need to worry about using a name that some other programmer has already used (as long as the arguments are different). 3.3 Working with Objects Objects are software bundles of data and methods act on that data. The merger of data and methods provides a means of more accurately representing real-world objects in software. They enable programmers to solve real-world problems in the software domain much easier and more logically. Let us consider an example of real-world objects like Dogs, scooters, and calculators having common characteristics.. All share two common characteristics: state and behavior. For example, the state of a lion includes its color, weight, and whether the dog is tired or hungry. Lions also have certain behaviors, such as barking, sleeping, and watching. The state of a scooter includes the current speed, the type of transmission, whether it is two-wheel or four-wheel drive, whether the lights are on, and the current gear, among other things. The behaviors for a scooter include turning, braking, and accelerating. As with real-world objects, software objects also have these two common characteristics (state and behavior). The state of an object is determined by its data and the behavior is defined by its methods. Creating an Object Java uses new keyword to allocate memory space, which creates an object of virtually any type. Consider an example, String name; name = new String(20); This allocates space of 10-character string and associates it with the variable name, which is considered as an object of type String and has all the methods associated with class String. In Java, methods of a class became a part of object name when it was created with new and methods are accessed using objects as shown in example, len = name.length //gets the size of name if (name.getname( ) //reads the name and associates it to variable sub = name.getsub(4); // returns the substring Destroying an Object The destroy method destroys the object (normally used with applets). Final cleanup takes place here. The destroy method has keyword destroy, have a return type of void, declared as public and no arguments. Consider an example, public void destroy( ) { counter = 0; } In the example, destroy method only sets the variable counter to zero. Destroy can accomplish many things, such as cleanly terminating network connections, logging information to files, and other final actions. A destroy method overridden from an existing destroy method in class java.applet.Applet. Constructors Constructors are a special type of method called when an object is initialized; their syntax is similar to that of methods but without return values. The name of a constructor is the same as its class. A constructor is automatically called when an object is instantiated. Consider an example, class ConClass { int p; int q; // Main constructor... public ConClass( ) { p = 1; q =4; } // ... OTHER METHODS… } Rather than setting the values of the instance variables in their declaration, set them in the constructor. This constructor is called when instance of ConClass is created. Consider an example, ConClass conObject = new ConClass( ); Constructors can also be overloaded. Consider an example, here another constructor with argument a is defined. // Another constructor... public ConClass(int a) { this.a = a; b = 8; } To instantiate an object with this constructor, this call creates an object with a set to 100; b is set to 8. Use the following, ConClass ConObject = new ConClass(100); The statement, this.a = a refers to the current instance of the object. This helps to differentiate variable a of the object from that of the parameter. Because local variables and parameter variables are first in scope, they will be used unless “this“ keyword is used. Likewise any number of arguments can be used in constructor. 3.4 Packages Packages are groups of related classes and interfaces. It provides a convenient mechanism for managing a large group of classes and interfaces, without naming conflicts. The Java API itself is implemented as a group of packages. Every class or Interface has a package. Name the package using package statement as shown below, package myPack; If no package is specified, a default package is used (usually represented by the current directory). Java has a hierarchical naming convention for naming packages, known as a dot notation. The top level of the notation represents the producer of the source file, such as "java." For example, the JDK has a package called "lang" which contains classes related to the basic mechanics of programming in Java. The String class is one of the classes in "lang" package. Hence, to access String class use, java.lang.String. The String.java file will be located in a java/lang subdirectory. Finally, the package declaration for the String class would be package java.lang; The package declaration must be the first non-comment, non-white space line in the file. The import statement is used to address a class defined in another package or source file. For example, use import java.lang.String to access String class. To access al of the classes in lang package use, import java.lang.*; Then lang package will become part of the current package for the purposes of compilation. Reference to a class can be given in the code by using the statement, java.lang.String s = "A string"; Declaring a Package Packages are declared using the package keyword followed by a package name. The following statement describes the syntax for the package, package PackageName; This statement must be placed at the beginning of a program, before any class declarations. Every class located in a program with a package statement is considered part of that package. Consider an example, in which package name is reptiles. package reptiles; class Reptile { ...body of class } The class Reptile is now considered a part of this package. Including other classes in package reptiles is easy: Simply place an identical package line at the top of those source files. There can be only one package statement in any source file. Java also supports the concept of package hierarchy. Packages can be nested within other packages. This is similar to the directory hierarchy found in many operating systems. Multiple names in a package statement are separated by a period. Consider the following example, class Reptile belongs to the package reptiles that is in the animal package hierarchy: package animal.reptiles; class Reptile{ ...body of class } To call a method promptForName in class Crocodile in subpackage reptile in package animal consider the following statement, animal.reptile.Crocodile.promptForName( ); The Java interpreter requires that the .class files be physically located in a subdirectory with a name that matches the subpackage name, when accessing a member of a subpackage. All classes belong to a package even if not explicitly declared. If the previous example were located on a UNIX system, the class promptForName would be located as follows: animal/reptile/Crocodile.class Accessing Other Packages The import statement enables to import classes from other packages into a program. An individual classes or entire packages of classes can be imported at the same time. The syntax for the import statement follows: import packagename; The “import” is a keyword and “packagename” is the name of the package to be imported. The statement must end with semicolon. The import statement should appear before any class declarations in a source file. Multiple import statements can also be made. The following is an example of an import statement: import animal.reptile.Crocodile; Here, variables and methods of class Crocodile can be directly accessed by simply specifying their name without prepending the entire package name. This has both an advantage and a disadvantage. The advantage is that the code is no longer cluttered with long names and is easier to type. The disadvantage is that it is more difficult to determine from which package a particular member came. This is especially true when a large number of packages are imported. Consider the statement, import animal.reptile.*; the asterisk specifies that all classes located in a hierarchy be imported, rather than just a single class. Package-Naming Conventions Packages can be named using standard Java naming scheme. By convention, packages begin with lowercase letters, which helps to distinguish package names from class names. For example, according to the convention, reptile and animal are package names and Crocodile is a class name. Anything following the class name is a member of that class. Every package name must be unique otherwise naming conflicts will occur at runtime. The CLASSPATH Environment Variable When running a Java program, interpreter must find all the referenced class libraries. By default, it looks in the Java install tree for the libraries. An environment variable named CLASSPATH can be used to tell Java where these libraries are located. CLASSPATH contains a list of directories to search for Java class library trees. The syntax of the list will vary according to the operating system being used. On UNIX systems, CLASSPATH contains a colon-separated list of directory names. Under Windows, the list is separated by semicolon. The following is a CLASSPATH statement for a UNIX system, CLASSPATH=/grps/IT/Java/classes:/opt/app s/Java This tells the Java interpreter to look in the /grps/IT/Java/classes and /opt/apps/Java directories for class libraries. Overview of the Standard Packages Reusability in the very important characteristics of Java for which is creating reusable, inheritable classes in necessary. The standard Java objects are collectively known as the Java standard packages help in code reuse. These contain groups of related classes. Along with classes, the standard Java packages also include interfaces, exception definitions, and error definitions. Java is composed of six standard packages: the language package, the utilities package, the I/O package, the networking package, the windowing package, and the applet package. The Language Package The Java language package, also known as java.lang, provides classes that make up the core of the Java language. The language package contains classes at the lowest level of the Java standard packages. For example, the Object class, from which all classes are derived, is located in the language package. The most important classes contained in the language package as follows, The Object class Data type wrapper classes The Math class String classes System and Runtime classes Thread classes Class classes Exception-handling classes The Process class The Utilities Package The Java utilities package, also known as java.util, provides various classes that perform different utility functions. The utilities package includes a class for working with dates, a set of data structure classes, a class for generating random numbers, and a string tokenizer class, among others. The most important classes contained in the utilities package as follows, The Date class Data structure classes The Random class The StringTokenizer class The Properties class The Observer classes The I/O Package The Java I/O package, also known as java.io, provides classes with support for reading and writing data to and from different input and output devicesincluding files. The I/O package includes classes for inputting streams of data, outputting streams of data, working with files, and tokenizing streams of data. The most important classes contained in the I/O package as follows, Input stream classes Output stream classes File classes The StreamTokenizer class The Networking Package The Java networking package, also known as java.net, contains classes that allow you to perform a wide range of network communications. The networking package includes specific support for URLs, TCP sockets, IP addresses, and UDP sockets. The Java networking classes make it easy and straightforward to implement client/server Internet solutions in Java. The classes included in the networking package as follows, The InetAddress class URL classes Socket classes The ContentHandler class The Windowing Package The Java windowing package, also known as java.awt, consists of classes that provide a wide range of graphics and user interface features. This package includes classes representing graphical interface elements such as windows, dialog boxes, menus, buttons, checkboxes, scroll bars, and text fields, as well as general graphics elements such as fonts. The most important classes included in the windowing package as follows, Graphical classes Layout manager classes Font classes Dimension classes The MediaTracker class The Applet Package The Java applet package, also known as java.applet, contains only one class: Applet. The Applet class includes methods for accessing applet parameters, loading images, and playing sounds, along with plenty of general behind-the-scenes applet support. Another interesting component of the applet package is the AudioClip interface, which defines the basic functionality required of a Java audio clip. 3.5 Inheritance Inheritance is a mechanism used to create a new class by extending the definition of another class. It gives a powerful way to increase the reusability of code. The old extended class is the superclass, the new extended class is the subclass. In Java, the process of extending one class to create a new class is called subclassing. Subclassing Java uses the “extends” keyword to indicate the creation of a new class as a subclass of an existing class. Consider the follwing class as example, which creates a simple class that keeps a record of student’s first and last names. It has a default constructor that simply initializes the two names, a constructor for storing String parameters, and a list() method that dumps the current values to standard output. class StudentRecord { String Fname; String Lname; // Default constructor public StudentRecord() { Fname = ""; Lname = ""; } // Constructor... public StudentRecord(String firstName, String lastName) { this. Fname = firstName; this.Lname = lastName; } // To list the elements of the record... public void RecordList( ) { System.out.println("First Name: " + Fname); System.out.println("Last Name: " + Lname); } } To instantiate the class with a name, use the following: StudentRecord student = new StudentRecord("Vikram","Srivatsav"); student.RecordList( ); Derive a sub-calss from class StudentRecord using “extends” keyword with additional address information, class Address extends StudentRecord { String Addr; // Default constructor public Address( ) { Fname = ""; Lname = ""; Addr = ""; } // Constructor... public Address(String firstName, String lastName, String address) { this.Fname = firstName; this.Lname = lastName; this.Addr = address; } } This new Address class inherits the Fname and Lname variables from the StudentRecord class. It also inherits the RecordList( ) method as shown below, record = new Address("Vikram","Srivatsav", "Bangalore"); record.RecordList( ); Create an object of class Address. However, the Recordlist( ) method prints only the name variables because this will call the StudentRecord Recordlist( ) method. This is because RecordList( ) method is not explicitly defined in the Address class. This limitation can be solved using method overriding. Method Overriding Method overriding is used when there is a need for subclass to replace a method of its superclass. Method overriding involves defining a new method that replaces the method in the superclass that has the same signature. Whenever method is called, Java looks for a method of that signature in the class definition of the object. If not found, it looks for a matching signature in the definition of the superclass. Java continues to look for the matching method until it reaches the topmost superclass. To add a RecordList( ) method to the Address class that displays the address, consider the following code, // List the elements of the record... public void RecordList( ) { System.out.println("First Name: " + firstName); System.out.println("Last Name: " + lastName); System.out.println("Address: " + address); } The RecordList( ) method call from the previous example will now print the following results, First Name: Vikram Last Name: Srivatsav Address: Bangalore Calling Superclass Methods As seen in the previous example, Address RecordList( ) method duplicates some code of the StudentRecord Recordlist( ) method. Namely, it duplicates the following, System.out.println("Last Name: " + Lname); System.out.println("Address: " + Addr); The RecordList( ) method of StudentRecord already has some of the behavior of the Address class.The StudentRecord RecordList( ) method is used as part of the base behavior of the Address class. Keyword “super” is used to refer a superclass. As per example, super keyword is needed because calling the superclass of Address has some of the behavior the RecordList( ) method needs. Consequently, the RecordList( ) method of Address is modified to call the StudentRecord RecordList( ) method before specifying additional behavior, public void RecordList( ) { super.RecordList( ); System.out.println("Address: " + Addr); } Calling Superclass Constructors Use super keyword to call the constructor of the superclass. The only difference from the previous use is that calls it without any method definition. For example, the two constructors of Address are modified to call the StudentRecord constructor before performing its own initialization: // Default constructor public Address( ) { super( ); addr = ""; } // Constructor... public Address (String firstName, String lastName, String address) { super(firstName,lastName); this.Addr = address; } One can call the default constructor (no parameters) or another constructor with super as long as the constructor with the matching signature exists. Suppose that a constructor wants to add an address to the Address class, with the other fields set to empty strings. Use the following code, public Address(String address) { this( ); this.Addr = address; } This code calls the default constructor of the Address class, which in turn calls the StudentRecord default constructor. At this point, all the fields are set to empty strings. The code then assigns the specified String to the address field. 3.6 Interfaces An interface is a prototype for a class and is useful from a logical design perspective. These are abstract classes that are left completely unimplemented. It provides a means to define the protocols for a class without worrying about the implementation details. Another important use of interfaces is the capacity for a class to implement multiple interfaces. This is a twist on the concept of multiple inheritance, which is supported in C++ but not in Java. Multiple inheritance enables to derive a class from multiple parent classes. The major difference between inheriting multiple interfaces and true multiple inheritance is that the interface approach enables to inherit only method descriptions, not implementations. If a class implements multiple interfaces, that class must provide all the functionality for the methods defined in the interfaces. An interface only defines a method's name, return type, and arguments. It does not include executable code or point to a particular method. It’s like a template of structure. Declaring an Interface The syntax for creating interfaces as follows, interface Identifier { InterfaceBody } The name of the interface includes identifier and InterfaceBody refers to the abstract methods and static final variables that make up the interface. Since, all the methods in an interface are abstract, it is not necessary to use the abstract keyword. Implementing Interfaces Implementing an interface is similar to deriving from a class, except that methods defined in an interface has to be implemented. To implement an interface, use “implements“ keyword. The syntax for implementing a class from an interface is as follows, class Identifier implements Interface { ClassBody } Identifier refers to the name of the new class, Interface is the name of the interface and ClassBody is the new class body. Modifiers The modifiers like public and default (used for classes) can be applied to an interface declaration. The default is nonpublic, which means accessible by any member of a given package. Most interfaces are public because interfaces are the only means to share variable and method definitions between different packages. Consider an example, public interface ExampleInterface { ... //body of interface } Variables and methods declared inside an interface also have modifiers associated with them. Modifiers for variables are limited to one specific set that is public static final. In other words, variables declared in interfaces can only function as constants. public static final are the default modifiers.Other modifiers such as protected results in a compiletime error. Consider an examples of variable declarations, public static final int X = 50; public static final float Paise = 2.5; public static final Str = "Java Basics"; Also, modifiers for methods are limited to one specific set such as public abstract, meaning that methods declared inside an interface can only be abstract. These are the default modifiers for methods. It is not necessary to declare them explicitly.Assigning other modifiers such as protected, results in a compile-time error. Consider an example of method declarations: public abstract boolean isDate(Date); public abstract boolean isTime(Time); public abstract StringBuffer isName(String); The example below shows overloaded methods declared in an interface as in a class. public interface ExampleInterface { public static final int X = 50; public static final float Paise = 2.5; public static final String = "Java Basics"; public abstract boolean isDate(Date); public abstract boolean isDate(String); public abstract StringBuffer isName(String); } Interfaces can extend other interfaces, just like classes using “extends” keyword. Consider the following example in which, the interface ExampleInterface declares a variable named theAns: public interface ExampleInterface { public static final int theAns = 42; } public interface MyInterface extends ExampleInterface { public static final int X = 50; public static final float Paise = 2.5; public static final String = "Java Basics"; public abstract boolean isDate(Date); public abstract boolean isDate(String); public abstract StringBuffer isName(String); } The interface MyInterface specifies that it extends ExampleInterface. This means that any classes that use MyInterface will have access to not only the variables and methods declared in MyInterface, but also those in ExampleInterface. Consider another example in which a single interface inherits multiple interfaces. public interface ThirdInterface extends FirstInterface, SecondInterface { body of interface } Using an Interface Consider an example in which interface Details is defined, public interface Details{ public abstract void printAddress (anAddress); public abstract void setStreet (anAddress); public abstract String getState (anAddress); } The methods print the entire address, change the street name, and return only the state. Each of these methods is specific to manipulating addresses. A class with the “implements” keyword can use this interface. The syntax is as follows, class name [extends classname ] implements interfacename [, interfacename] { ... body of class } The implements keyword follows the name of the class (or extends declaration) and in turn is followed by one or more commaseparated interface names. Consider the following example, public class StudentRecord implements Details { ... body of class } 3.7 Summary This chapter covers the concepts of classes, packages, inheritance, and interfaces. A solid knowledge of the relationships among these parts of Java is essential to creating applets and applications. Classes in Java are used to define an object. Objects can consist of information and methods for manipulating that information. An instance is a specific implementation of an object. Packages are groups of class libraries, which are made up of related classes. Inheritance allows for the reuse of existing code while providing a means for customization of new code. Interfaces are templates of methods used to standardize method definitions. These are necessary because Java does not support multiple inheritance. Interfaces allow unrelated classes to share related methods. To summarize this chapter, consider a glossary of terms and concepts that were covered, Terms Meaning A template for an object that contains variables to describe the class object, and methods to describe how the object behaves. Classes can inherit variables and methods from other classes. A concrete instance of a class-in other words, a real instance that Object has been created using a class as its template. Multiple instances of the same class have access to the same methods, but they often have different values for their instance variables. Instance An object made real through the use of a class. A class further up the class hierarchy than another class (its Superclass subclass). The subclass inherits variables and methods from all superclasses above it in the hierarchy. A class further down the class hierarchy than another class (its Subclass superclass). When you create a new class to inherit the behavior of another class, the process is called subclassing. Instance method class method Instance variable class variable A method defined in a class that operates on an instance of that class. Instance methods usually are just called methods. A method defined in a class that operates on the class itself and can be called through the class or any of its instances. A variable owned by an individual instance of a class, and whose value is stored in that instance. A variable owned by the class and all its instances as a whole, and whose value is stored in the class. A collection of abstract behavior specifications that can be Interface implemented by individual classes. A collection of related classes and interfaces. Classes from Package packages other than java.lang must be imported explicitly or referred to by their full package names. 3.8 Exercises 1. What is a class? 2. How do classes helps to organize the programs? 3. What are the three parts of a simple, empty class? 4. What two elements need to be added to complete the class? 5. How does a class relate to an object? 6. How do you create an object from a class? 7. How do you use a class that is defined in a different file than the file that accesses the class? 8. What is inheritance and how does it helps to create new classes quickly? 9. What are subclass and a superclass? 10. How do you create a subclass? 11. How do you override a method inherited from a superclass? 12. What is a package? 13. How do you tell Java that a source-code file uses a particular package? 14. How do you add a class or interface to a package? 15. How do you tell Java that the class you are creating implements a particular interface? 16. What is the difference between an interface and a class? 17. How are interfaces similar to classes? 18. How does the complete name of a package relate to the package's storage on your disk? 19. What are the six main packages of the Java classes? Which package contains classes for operating in a windowed environment? 20. Write a basic, empty class called ExamClass. 21. Add to ExamClass a string data field called name. This data field should be private to the class. 22. Add to ExamClass in exercise 21, a constructor that accepts a starting value for name as its single argument, and public methods for setting and retrieving the value of name. Call these methods SetName( ) and GetName( ). Write the commands used to compile this class. 23. Write a subclass called ExamSubClass that is derived from ExamClass in exercise 22 and that adds an integer data field called marks (declared as private) and a public method called CreateDataString() that creates a string object from subject and code. That is, if subject is equal to Java and code is equal to 01, the CreateDataString() method should return Java 01 as a single string object. Also, create public methods called SetCode( ) and GetCode( ) for setting and retrieving the value of code, as well as a constructor that accepts arguments for the starting values of subject and code. 24. Consider the following class: public class IdentifyMyParts { public static int x = 7; public int y = 3; } a. What are the class variables? b. What are the instance variables? 25. What is the output from the following code: IdentifyMyParts a = new IdentifyMyParts(); IdentifyMyParts b = new IdentifyMyParts(); a.y = 5; b.y = 6; a.x = 1; b.x = 2; System.out.println("a.y = " + a.y); System.out.println("b.y = " + b.y); System.out.println("a.x = " + a.x); System.out.println("b.x = " + b.x); System.out.println("IdentifyMyParts.x = " + IdentifyMyParts.x); 27. What's wrong with the following program? public class SomethingIsWrong { public static void main(String[] args) { Rectangle myRect; myRect.width = 40; myRect.height = 50; System.out.println("myRect's area is " + myRect.area()); } } 28. Given the following class, called NumberHolder, write some code that creates an instance of the class, initializes its two member variables, and then displays the value of each member variable. public class NumberHolder { public int anInt; public float aFloat; } 29. Write a package used to add two numbers. 30. Change the class you wrote in exercise 24 to an interface. Write a program that implements this new interface. 31. Assume you have written some classes. Belatedly, you decide they should be split into three packages, as listed in the following table. Furthermore, assume the classes are currently in the default package (they have no package statements). Destination Packages Package Name Class Name mygame.server Server mygame.shared Utilities mygame.client Client 1. Which line of code will you need to add to each source file to put each class in the right package? 2. To adhere to the directory structure, you will need to create some subdirectories in the development directory and put source files in the correct subdirectories. What subdirectories must you create? Which subdirectory does each source file go in? 3. Do you think you'll need to make any other changes to the source files to make them compile correctly? If so, what? UNIT 4 JAVA Streams Streams in Java provide a way for two or more processes to send information to each other without having any knowledge about each other. This means that with streams an application or applet can pass data to almost any other stream-based application or applet. Programs need to bring in information from an external source or send out information to an external destination. The information can be anywhere in a file, on disk, on the network, in memory, or in another program and also it can be of any type like objects, characters, images, or sounds. There are a few stream methods found in some Java package extensions, but the standard ones are found in the java.io package. This package must be imported in all applications or applets that make use of threads. 4.1 Data Flow with Streams To bring in information, a program opens a stream on an information source (a file, memory, a socket) and reads the information serially, this is called as input stream as shown in figure 4.1, WRITES PROGRAM S A STREAM DESTINATION Figure 4.1. A Input Stream Similarly, a program can send information to an external destination by opening a stream to a destination and writing the information out serially, this is called as output stream as shown in figure 4.2, READS SOURC E A STREAM PROGRAM Figure 4.2. Output Stream The algorithms to perform I/O Stream operations are as shown in Table 4.1, Reading (Input Stream) open a stream Writing (Output Stream) open a stream while more information while more information read information write information close the stream close the stream Table 4.1. Algorithm for I/O stream operations The Java I/O package provides an extensive set of classes that handle input and output to and from many different devices. In the following sections, the primary classes contained in the I/O package, along with some examples that shows the capabilities of these classes are discussed. 4.2 Input Stream An input stream is like a physical stream of water flowing from a water plant into the pipes of a water system. The obvious difference is that an input stream deals with binary computer data rather than physical water. Data pumped into an input stream can be directed in many different ways, much like water is directed through the complex system of pipes that make up a water system. The data in an input stream is transmitted a byte at a time, which is roughly similar to individual drops of water flowing into a pipe. Java uses input streams as the means of reading data from an input source, such as the keyboard. The basic input stream classes supported by Java, which are discussed in detail in the preceding topics are as follows, InputStream BufferedInputStream DataInputStream FileInputStream StringBufferInputStream The InputStream Class The InputStream class is an abstract class that serves as the base class for all other input stream classes. InputStream defines a basic interface for reading streamed bytes of information. The typical scenario when using an input stream is to create an InputStream-derived object and then tell it that information has to be input (by calling an appropriate method). If no input information is currently available, the InputStream uses a technique known as blocking to wait until input data becomes available. An example of when blocking takes place consider using input stream to read information from the keyboard. Until the user types information and presses <Return> or <Enter> key, there is no input available to the InputStream object. The InputStream object then waits (blocks) until the user presses <Return> or <Enter>, at which time the input data becomes available and the InputStream object can process it as input. The InputStream class defines the following methods, abstract int read() int read(byte b[]) int read(byte b[], int off, int len) long skip(long n) int available() synchronized void mark(int readlimit) synchronized void reset() boolean markSupported() void close() InputStream defines three different read methods for reading input data in various ways. The first read( ) method takes no parameters and simply reads a byte of data from the input stream and returns it as an integer. This version of read( ) returns -1 if the end of the input stream is reached. The second version of read( ) takes an array of bytes as its only parameter, which enables to read multiple bytes of data at once. The data that is read is stored in this array. This returns the actual number of bytes read or -1 if the end of the stream is reached. The last version of read( ) takes a byte array, an integer offset, and an integer length as parameters. The off parameter specifies the offset into the byte array to start placing read data, and the len parameter specifies the maximum number of bytes to read. The skip( ) method is used to skip over bytes of data in the input stream. It takes a long value as its only parameter, which specifies how many bytes of input to skip. It returns the actual number of bytes skipped or -1 if the end of the input stream is reached. The available( ) method is used to determine the number of bytes of input data that can be read without blocking. It does not have parameters and returns the number of available bytes. This method is useful to ensure that there is input data available. The mark( ) method marks the current position in the stream. The reset( ) method is used to return to this position. It takes an integer parameter, readlimit, which specifies how many bytes can be read before the mark becomes invalidated.. Finally, the close( ) method closes an input stream and releases any resources associated with the stream. It causes the stream buffer to be flushed, which helps to avoid file corruption. The System.in Object The keyboard is the most standard device for retrieving user input. The System class contained in the language package contains a member variable that represents the keyboard, or standard input stream. This member variable is called in and is an instance of the InputStream class. This variable is useful for reading user input from the keyboard. Following program example contains the ReadKeys1 program, which shows how the System.in object can be used with the first version of the read() method. class ReadKeys1 { public static void main (String args[]) { StringBuffer s = new StringBuffer(); char c; try { while ((c = (char)System.in.read()) != '\n') { s.append(c); } } catch (Exception e) { System.out.println("Error: " + e.toString()); } System.out.println(s); } } The ReadKeys1 class first creates a StringBuffer object called s. It then enters a while loop that repeatedly calls the read method until a newline character is detected (the user presses Return). Notice that the input data returned by read() is cast to a char type before being stored in the character variable c. Each time a character is read, it is appended to the string buffer using the append() method of StringBuffer. It is important to see how any errors caused by the read( ) method are handled by the try/catch exception-handling blocks (Exception handling is discussed in detail in unit5). The catch block simply prints an error message to the standard output stream based on the error that occurred. Finally, when a newline character is read from the input stream, the println( ) method of the standard output stream is called to output the string to the screen. You learn more about the standard output stream a little later in this unit. The BufferedInputStream Class The BufferedInputStream class provides a buffered stream of input. This means that more data is read into the buffered stream than requested, so that subsequent reads comes from the buffer rather than from the input device. This is much faster read access because reading from a buffer is reading from memory. It implements all the same methods defined by InputStream. However, the BufferedInputStream class does have two different constructors, which as follows, BufferedInputStream(InputStream in) BufferedInputStream(InputStream in, int size) Notice that both constructors take an InputStream object as the first parameter. The only difference between the two is the size of the internal buffer. In the first constructor, a default buffer size is used; in the second constructor, buffer size is specified with the size integer parameter. To support buffered input, the BufferedInputStream class also defines a handful of member variables, such as, byte buf[] int count int pos int markpos int marklimit The buf byte array member is the buffer in which input data is actually stored. The count member variable keeps up with how many bytes are stored in the buffer. The pos member variable keeps up with the current read position in the buffer. The markpos member variable specifies the current mark position in the buffer as set using the mark() method. markpos is equal to -1 if no mark has been set. Finally, the marklimit member variable specifies the maximum number of bytes that can be read before the mark position is no longer valid. marklimit is set by the readlimit parameter passed into the mark() method. These are all protected member variables. The DataInputStream Class The DataInputStream class is useful for reading primitive Java data types from an input stream in a portable fashion. There is only one constructor for DataInputStream, which simply takes an InputStream object as its only parameter. This constructor is defined as follows: DataInputStream(InputStream in) DataInputStream implements the following useful methods beyond those defined by InputStream, final int skipBytes(int n) final void readFully(byte b[]) final void readFully(byte b[], int off, int len) final String readLine( ) final boolean readBoolean( ) final byte readByte( ) final int readUnsignedByte( ) final short readShort( ) final int readUnsignedShort( ) final char readChar( ) final int readInt( ) final long readLong( ) final float readFloat( ) final double readDouble( ) Here are the descriptions of few of these methods, The skipBytes( ) method works in a manner very similar to skip(); the exception is that skipBytes( ) blocks until all bytes are skipped. The number of bytes to skip is determined by the integer parameter n. There are two readFully( ) methods implemented by DataInputStream. These methods are similar to the read( ) methods except that they block until all data has been read. The normal read( ) methods block only until some data is available, not all. The readFully( ) skip( ). methods are to the read( ) methods what skipBytes( ) is to The readLine( ) method is used to read a line of text that has been terminated with a newline (\n), carriage return (\r), carriage return/newline (\r\n), or end-of-file (EOF) character sequence. readLine() returns the line of text in a String object. The FileInputStream Class The FileInputStream class is useful for performing simple file input. The FileInputStream class functions exactly like the InputStream class except that it deals with files. The FileInputStream class can be instantiated using one of the in three following constructors, FileInputStream(String name) FileInputStream(File file) FileInputStream(FileDescriptor fdObj) The first constructor takes a String object parameter called name, which specifies the name of the file to use for input. The second constructor takes a File object parameter that specifies the file to use for input. The third constructor for FileInputStream takes a FileDescriptor object as its only parameter. The StringBufferInputStream Class StringBufferInputStream enables to use a string as a buffered source of input. It implements all the same methods defined by InputStream. The StringBufferInputStream class has a single constructor, which as follows, StringBufferInputStream(String s) The constructor takes a String object, from which it constructs the string buffer input stream. Although StringBufferInputStream doesn't define any additional methods, it does provide a few of its own member variables, which as follow, String buffer int count int pos The buffer string member is the buffer where the string data is actually stored. The count member variable specifies the number of characters to use in the buffer. Finally, the pos member variable keeps up with the current position in the buffer. 4.3 Output Stream In Java, output streams are the logical counterparts to input streams; they handle writing data to output sources. Using the water analogy from the discussion of input streams earlier in this unit, an output stream is equivalent to the water spout on your bathtub. Just as water travels from a water plant through the pipes and out the spout into your bathtub, so must data flow from an input device through the operating system and out an output device. A leaky water spout is an even better way to visualize the transfer of data out of an output stream: Each drop of water falling out of the spout represents a byte of data. Each byte of data flows to the output device just like the drops of water falling one after the other out of the bathtub spout. Output streams are used to output data to various output devices, such as the screen. The primary output stream classes used in Java programming are as follows, OutputStream PrintStream BufferedOutputStream DataOutputStream FileOutputStream The OutputStream Class The OutputStream class is the output counterpart to InputStream; it serves as an abstract base class for all the other output stream classes. OutputStream defines the basic protocol for writing streamed data to an output device. Create an OutputStream-derived object and call an appropriate method to output information. The OutputStream class uses a technique similar to the one used by InputStream. It will block until data has been written to an output device. While blocking (waiting for the current output to be processed), the OutputStream OutputStream class does not allow any further data to be output. The class implements the following methods, abstract void write(int b) void write(byte b[]) void write(byte b[], int off, int len) void flush( ) void close( ) OutputStream defines three different write( ) methods for writing data in a few different ways. The first write( ) method writes a single byte to the output stream, as specified by the integer parameter b. The second version of write( ) takes an array of bytes as a parameter and writes it to the output stream. The last version of write( ) takes a byte array, an integer offset, and a length as parameters. The flush( ) method is used to flush the output stream. Calling flush( ) forces the OutputStream object to output any pending data. Finally, the close( ) method closes an output stream and releases any resources associated with the stream. The PrintStream Class The PrintStream class is derived from OutputStream and is designed primarily for printing output data as text. PrintStream has two different constructors as follows, PrintStream(OutputStream out) PrintStream(OutputStream out, boolean autoflush) Both PrintStream constructors take an OutputStream object as their first parameter. The only difference between the two methods is how the newline character is handled. In the first constructor, the stream is flushed based on an internal decision by the object. In the second constructor, it specifies that the stream be flushed every time it encounters a newline character. The PrintStream class also implements a rich set of methods, which as follows, boolean checkError( ) void print(Object obj) synchronized void print(String s) synchronized void print(char s[]) void print(char c) void print(int i) void print(long l) void print(float f) void print(double d) void print(boolean b) void println( ) synchronized void println(Object obj) synchronized void println(String s) synchronized void println(char s[]) synchronized void println(char c) synchronized void println(int I) synchronized void println(long l) synchronized void println(float f) synchronized void println(double d) synchronized void println(boolean b) The checkError( ) method flushes the stream and returns whether or not an error has occurred. The return value of checkError( ) is based on an error ever having occurred on the stream, meaning that once an error occurs, checkError( ) always returns true for that stream. PrintStream provides a variety of print() methods to handle all your printing needs. The version of print() that takes an Object parameter simply outputs the results of calling the toString() method on the object. The other print() methods each take a different type parameter that specifies which data type is printed. The println( ) methods implemented by PrintStream are very similar to the print( ) methods. The only difference is that the println( ) methods print a newline character following the data that is printed. The println( ) method that takes no parameters simply prints a newline character by itself. The System.out Object The monitor is the primary output device on modern computer systems. The System class has a member variable that represents the standard output stream, which is typically the monitor. The member variable is called out and is an instance of the PrintStream class. The out member variable is very useful for outputting text to the screen. The BufferedOutputStream Class The BufferedOutputStream class is very similar to the OutputStream class except that it provides a buffered stream of output. This class enables to write to a stream without causing a bunch of writes to an output device. It maintains a buffer that is written to when data is written to the stream. When the buffer gets full or when it is explicitly flushed, it is written to the output device. It implements the same methods defined in OutputStream; there are no additional methods except for constructors. The two constructors for BufferedOutputStream are as follows , BufferedOutputStream(OutputStream out) BufferedOutputStream(OutputStream out, int size) Both constructors for BufferedOutputStream take an OutputStream object as their first parameter. The only difference between the two is the size of the internal buffer used to store the output data. In the first constructor, a default buffer size of 512 bytes is used; in the second constructor, buffer size is specified with the size integer parameter. The buffer is managed by two member variables, which as follows, byte buf[] int count The buf byte array member variable is the actual data buffer in which output data is stored. The count member keeps up with how many bytes are in the buffer. These two member variables are sufficient to represent the state of the output stream buffer. The DataOutputStream Class The DataOutputStream class is useful for writing primitive Java data types to an output stream in a portable way. It has only one constructor, which simply takes an OutputStream object as its parameter. This constructor is defined as follows: DataOutputStream(OutputStream out) It implements the following useful methods beyond those inherited from OutputStream: final int size( ) final void writeBoolean(boolean v) final void writeByte(int v) final void writeShort(int v) final void writeChar(int v) final void writeInt(int v) final void writeLong(long v) final void writeFloat(float v) final void writeDouble(double v) final void writeBytes(String s) final void writeChars(String s) The size( ) method is used to determine how many bytes have been written to the stream thus far. The integer value returned by size( ) specifies the number of bytes written. The rest of the methods implemented in DataOutputStream are all variations on the write( ) method. Each version of writeType( ) takes a different data type that is in turn written as output. The FileOutputStream Class The FileOutputStream class provides a means to perform simple file output. A FileOutputStream object can be created using one of the following constructors: FileOutputStream(String name) FileOutputStream(File file) FileOutputStream(FileDescriptor fdObj) The first constructor takes a String parameter, which specifies the name of the file to use for input. The second constructor takes a File object parameter that specifies the input file. The third constructor takes a FileDescriptor object as its only parameter. 4.3 Summary Streams are Java's way of reading and writing data to entities outside an application, such as files, networks, devices, or other processes. All streams in Java consist of a flow of 8-bit bytes. Some stream classes allow the writing of other object types, but internally they simply convert these objects to bytes. Streams can be broken into two main types: input streams and output streams. Input streams accept data from an external source. Processes that accept input streams are known as consumers. The methods used with input streams are, read, skip, close, available, mark, reset and so on. Output streams produce data for an external destination. Processes that produce output streams are known as producers. The methods used with output streams are write, flush, and close. By using input and output streams, Java applications and applets can communicate with the rest of the world. Exercises 1. What is input/output package in Java called as? 2. Can data flow through a given stream in both directions? 3. What is the name of a stream that connects two running programs? 4. Can a stream act as a data source for another stream? 5. What is a buffer? 6. What is a stream that transforms data in some way called? 7. What is the name of the abstract base class for streams dealing with character input? 8. Is the character data used inside a Java program exactly the same format as the character data in a text file written by Java? 9. What is the name of the abstract base class for streams dealing with general purpose (non-character) input? 10. What is the ancestor class of streams that do character-oriented output? 11. How many bits per character does a Java program use? 12. What is the class that translates characters from the internal form (used by a Java program) to the external form (used by a disk file). 13. What is the disk file format for characters that is intended to work for all human languages? 14. What does the flush( ) method of a stream do? 15. What is an advantage in using the PrintWriter class? 16. Does the println( ) method of PrintWriter throw exceptions? 17. Which operation is usually more reliable: input or output? 18. What class would you use to read a few pieces of data that are at known positions near the end of a large file? UNIT 5 Exception Handling in JAVA Errors are a normal part of programming. Some of these errors are flaws in basic design or implementation of program. These are called bugs. Other types of errors are the result of situations like low memory or invalid filenames. Java's exception handling mechanism helps to handle errors. As the name implies, an exception is an exceptional condition. Exceptions are used as a way to report error conditions. It can be used as a means of indicating other situations as well. This unit concentrates primarily on exceptions as an error handling mechanism. Exceptions provide notification of errors and a way to handle them. This new control structure allows specifying exactly where to handle specific types of errors. Consider the problem of calculating the retail cost of an item and displaying it. For this example, the retail cost is twice the wholesale cost: int retailCost( int wholesale ) { if ( wholesale <= 0 ) { return 0 ; } return (wholesale * 2 ) ; } The retailCost( ) method takes the wholesale price of an item and doubles it. If the wholesale price is negative or zero, the function returns zero to indicate that an error has occurred. This method can be used in an application as follows, int wholesalePrice = 30 ; int retailPrice = 0 ; retailPrice = retailCost( wholesalePrice ) ; System.out.println( "Wholesale price = " + wholesalePrice ) ; System.out.println( "Retail price = " + retailPrice ) ; In this example, the retailCost( ) method calculates the correct retail cost and prints it. The problem is that the code segment never checks whether the wholesalePrice variable is negative. Even though the method checks the value of wholesalePrice and reports an error-there is nothing that forces the calling method to deal with the error. If this method is called with a negative wholesalePrice, the function blindly prints invalid data. Putting the whole operation in a method can prevent the printing of bad values. The showRetail( ) method takes the wholesale price, doubles it, and prints it. If the wholesale price is negative or zero, the method does not print anything and returns the boolean value false: boolean showRetail( int wholesale ) { if ( wholesale <= 0 ) { return false ; } int retailPrice ; retailPrice = wholesalePrice * 2 ; System.out.println( "Wholesale price = " + wholesale ) ; System.out.println( "Retail price = " + retailPrice ) ; return true ; } Using this new and improved method guarantees that bad values are never printed. But what happens if this method returns a boolean and both true and false are valid return values? How does this method report an error? Consider another example in which a method to determine whether a student passes a test. The pass( ) method takes the number of correct answers and the number of questions. The method calculates the percentage; if it is greater than 70 percent, the student passes. Consider the passingGrade( ) method: boolean passingGrade( int correct, int total ) { boolean returnCode = false ; if ( (float)correct / (float)total > 0.70 ) { returnCode = true ; } return returnCode ; } In this example, what happens if the number correct is greater than the total or if the total is zero (because this causes a division by zero in the method)? There is no way to report an error in this function. Exception solves this problem. 5.2 Exception Methods Most Java exception handling is performed using the try, catch, throw, and finally methods. try With this method, program will try to execute a block of code that might generate (throw) an exception. This is a way of telling the compiler that some attempt will be made to deal with at least some of the exceptions generated by the block of code. It is used to inform Java that a block of code may generate an exception and that some processing of that exception will be done immediately following the try. The syntax is as follows, try statement; or try { statement(s) } The keyword “try” begins the try construct and is followed by a statement or block containing the code that might generate an exception. If any one statement generates an exception, the remaining statements in the block are skipped and execution continues with the first statement following the try construct, which must be a catch or finally statement. This is an important point to remember. It is an easy way to determine which block of code should be skipped if an error occurs. Consider an example: public class Example { public static void main (String args[]) { int[] myArr = new int[10]; try { System.out.println("Before valid array invalid array assignment"); myArr[0] = 1; System.out.println("Before assignment"); myArr[100] = 1; System.out.println("After array exception"); } } } In this example, the array myArr is created with a length of 10. A try statement that contains several statements follows this. The first, third, and fifth statements simply write trace messages to the screen. The second statement contains a standard assignment statement that assigns the value 1 to array element 0. The third statement also assigns an array, but attempts to assign a value of 1 to element 100 of the array. Because the array is only 10 in size, this generates an ArrayIndexOutOfBounds exception. In tracing the execution of the block of code following the try statement, the first three statements are executed normally. The fourth statement, the invalid assignment, will start to execute and then generate an exception, which causes execution to continue at the end of the block, skipping the fifth statement. But this code will result in compilation error, because any try statement must be followed immediately by one or more catch or finally statements. No other type of statement is allowed after the end of the try statement and before the first catch or finally statement. (usage of catch statements are explained in the next topic.) Catch Catch is used to specify the action that should be taken for a particular type of exception. It is similar to the case part of a switch statement. There can be several catch statements to deal with each of the exceptions that may be generated in the block specified by the try statement. In Java terms, you say a thrown exception gets caught. It is used to handle a specific exception that has been generated in a try statement. The syntax is as follows, catch (ExceptionType ExceptionObj) statement; or catch (ExceptionType exceptionObj) { statement(s) } The keyword “catch” begins the catch construct, followed by a parameter list that contains an exception type and an exception object. A statement or block containing the code used to process the exception follows this in turn. The object specified in the parameter list, exceptionObj, is a variable that contains the exception object generated and is local to the catch block. Consider an example, public class Example{ public static void main (String args[]) { int[] myArr= new int[10]; try { System.out.println("Before valid array assignment"); myArr[0] = 1; System.out.println("Before invalid array assignment"); myArr[100] = 1; System.out.println("After array exception"); } catch(ArrayIndexOutOfBoundsException e) { System.out.println("An array index error has occured"); }}} In the example, the required catch statement has been added after the try statement. This catch statement will catch the ArrayIndexOutOfBoundsException specifically. If any other exception occurs, this catch statement is ignored. In this case, an ArrayIndexOutOfBoundsException is generated, so the body of this catch statement will be executed. This body simply generates an error message to the screen. Additional catch statements can follow the first catch statement. They must immediately follow the try/catch statement; otherwise a compilation error will occur. When an exception in a try statement is generated, the Java interpreter will treat all the catch statements following the try statement as cases in a switch statement. The first statement that is matched will be executed, and the remainder will be skipped. Note that Java does not require any processing of the exception at all. Simply having a catch statement for an exception with an empty block is sufficient to avoid program abortion. Consider the following example, try { Thread.sleep(timePeriod); } catch(InterruptedException e); As you can see, the catch statement simply ends in a semicolon (;), which does nothing. The result is an InterruptedException error that is caught and then totally ignored. Throw This involves in causing an exception to be generated. For example, say a method was written to read a file. If the method could not read the file because the file did not exist, this would generate an IOException. In Java terminology, it is said that the method threw an IOException. throw is used to cause the code itself to generate an exception. It is then up to calling routines to handle the exception. This is the preferred way of passing error information to calling routines in Java. The syntax is as follows, throw(ExceptionObj); Consider an example, public class MyMain { public static void main (String args[]) { int[] myArray = new int[10]; try { myArray[100] = 1; } catch(ArrayIndexOutOfBoundsException e) { e = new ArrayIndexOutOfBoundsException("Array index should be within bounds."); throw(e); } } } In this example, a customized error message is generated regarding the array index problem by reassigning e to a new exception object that includes the customized message and then using throw to throw another exception that must be caught at a higher level. If a catch or finally statement followed this catch statement, it would be ignored. However, if this try statement were itself enclosed in a different try statement, the execution would catch the exception. Finally The finally statement is used to specify the action to take if none of the previous catch statements specifically deals with the situation. It is similar to the default part of a switch statement. It catches everything that falls out of the exception-handling statement. It is used to handle any exception generated within a try statement. The catch statement discussed previously can handle only one type of exception; the finally statement can handle any type of exception. The syntax is as follows, finally statement; or finally { statement(s) } The keyword finally begins the finally construct, followed by a statement or block containing the code used to process the exception. As with the catch statement, a finally block must follow immediately after a try or other catch statement or a compilation error results. A finally statement acts like a default case in a switch statement if it follows a series of catch statements. Anything that was not explicitly matched by an earlier catch statement is caught by the finally statement. A finally statement cannot be followed by another catch or finally statement or a compilation error will result. Because finally catches everything, additional statements would never be executed in any case. Consider an example, import java.io.* ; import java.lang.Exception ; public class MultiThrow { public static void main( String[] args ) { try { alpha() ; } catch( Exception e } { System.out.println( "Caught exception " ) ; } finally( ) { System.out.println( "Finally. " ) ; } } } Here, if alpha( ) throws an exception, it is caught in the catch block and then the finally block is executed. If alpha( ) does not throw an exception, the finally block is executed after the try block. If any code in a try block is executed, the finally block is executed as well. 5.3 java.lang Exceptions The java.lang package contains much of the core Java language. The exceptions subclassed from RuntimeException do not have to be declared in a method's throws clause. These exceptions are considered normal and nearly any method can throw them. Table 5.1 shows the recoverable exceptions from the java.lang package. Table 5.2 shows the nonrecoverable errors in the java.lang package. Exception Cause Arithmetic error condition (for example, divide by zero). ArithmeticException ArrayIndexOutOfBoundsException Array index is less than zero or greater than the actual size of the array. Object type mismatch between the array and the object ArrayStoreException to be stored in the array. ClassCastException Cast of object to inappropriate type. ClassNotFoundException Unable to load the requested class. CloneNotSupportedException Object does not implement the cloneable interface. Exception Root class of the exception hierarchy. IllegalAccessException Class is not accessible. IllegalArgumentException Method receives an illegal argument. IllegalMonitorStateException Improper monitor state (thread synchronization). The thread is in an improper state for the requested IllegalThreadStateException operation. IndexOutOfBoundsException Index is out of bounds. InstantiationException Attempt to create an instance of the abstract class. InterruptedException Thread interrupted. NegativeArraySizeException Array size is less than zero. NoSuchMethodException Unable to resolve method. NullPointerException Attempt to access a null object member. NumberFormatException Unable to convert the string to a number. RuntimeException Base class for many java.lang exceptions. SecurityException Security settings do not allow the operation. StringIndexOutOfBoundsException Index is negative or greater than the size of the string. Table 5.1. The java.lang exceptions. Non-Recoverable Errors in java.lang package is as follows, Error Cause AbstractMethodError Attempt to call an abstract method. ClassCircularityError This error is no longer used. ClassFormatError Invalid binary class format. Error Root class of the error hierarchy. IllegalAccessError Attempt to access an inaccessible object. IncompatibleClassChangeError Improper use of a class. InstantiationError Attempt to instantiate an abstract class. InternalError Error in the interpreter. LinkageError Error in class dependencies. NoClassDefFoundError Unable to find the class definition. NoSuchFieldError Unable to find the requested field. NoSuchMethodError Unable to find the requested method. OutOfMemoryError Out of memory. StackOverflowError Stack overflow. ThreadDeath Indicates that the thread will terminate. May be caught to perform cleanup. (If caught, must be rethrown.) UnknownError Unknown virtual machine error. UnsatisfiedLinkError Unresolved links in the loaded class. VerifyError Unable to verify bytecode. VirtualMachineError Root class for virtual machine errors. Table 5.2. The java.lang errors. 5.6 Summary Exceptions are way of performing error handling in Java. Exceptions are used for error conditions, and any programs should be ready to handle them. Exceptions are handled using a combination of three statement types: try, catch, and finally. The try is used to inform the compiler that exception handling will be performed on an associated block of code. The catch is used for processing a specific exception generated in the try block of code. Several catch statements can be specified sequentially to handle specific exceptions in a specific order. The finally statement can be used to catch all exceptions not specifically caught by a catch statement. A program can generate its own exceptions using the throw statement. The exception itself can be either preexisting or newly created. Specifying a different message when creating the exception object can customize even a preexisting exception. Simply extending an existing exception class such as java.lang.Exception can create a new exception. Exercises 1. How do you use a try program block? 2. How do you use a catch program block? 3. What is the difference between exception and error? 4. Do you have to catch all types of exceptions that might be thrown by Java? 5. When a method you call is defined as potentially throwing an exception, do you have to handle that exception in your program? 6. How many exceptions can you associate with a single try block? 7. How do you pass an exception up from a called method to the calling method? 8. What are the two main types of exceptions that Java may throw? 9. Write program that catches divide-by-zero error, which will cause Java to throw an ArithmeticException exception. 10. Write a program that uses the following subroutine to solve equations specified by the user. static double root(double A, double B, double C) throws IllegalArgumentException { // Returns the larger of the two roots of // the quadratic equation A*x*x + B*x + C = 0. // (Throws an exception if A == 0 or B*B-4*A*C < 0.) if (A == 0) { throw new IllegalArgumentException("A can't be zero."); } else { double disc = B*B - 4*A*C; if (disc < 0) throw new IllegalArgumentException("Discriminant < zero."); return (-B + Math.sqrt(disc)) / (2*A); } } Your program should allow the user to specify values for A, B, and C. It should call the subroutine to compute a solution of the equation. If no error occurs, it should print the root. However, if an error occurs, your program should catch that error and print an error message. After processing one equation, the program should ask whether the user wants to enter another equation. The program should continue until the user answers no. 11. Write a testing class TestTrace that contains the static main() method, and another class CallEg that contains three methods. The main() method will create a CallEg object and call its methodA( ). class CallEg { public void methodA() throws ArithmeticException { } public void methodB() throws ArithmeticException { } public void methodC() throws ArithmeticException { } } 12. Write a class to represent Roman numerals. The class should have two constructors. One constructs a Roman numeral from a string such as "XVII" or "MCMXCV". It should throw a NumberFormatException if the string is not a legal Roman numeral. The other constructor constructs a Roman numeral from an int. It should throw a NumberFormatException if the int is outside the range 1 to 3999. In addition, the class should have two instance methods. The method toString() returns the string that represents the Roman numeral. The method toInt() returns the value of the Roman numeral as an int. 13. Write a program that lets the user enter an expression. If the expression contains an error, print an error message. Otherwise, let the user enter some numerical values for the variable x. Print the value of the expression for each number that the user enters. However, if the expression is undefined for the specified value of x, print a message to that effect. 14. Is the following code legal? try { } finally { } 15. What exception types can be caught by the following handler? catch (Exception e) { } What is wrong with using this type of exception handler? 16. Is there anything wrong with the following exception handler as written? Will this code compile? try { } catch (Exception e) { } catch (ArithmeticException a) { } 17. Modify the following cat method so that it will compile. public static void cat(File file) { RandomAccessFile input = null; String line = null; try { input = new RandomAccessFile(file, "r"); while ((line = input.readLine()) != null) { System.out.println(line); } return; } finally { if (input != null) { input.close(); } } } 18. When is exception objects created? 19. Does an exception have to be handled by the same try-catch block that threw it? 20. How can you make sure you catch every exception that a statement may throw? 21. If an exception isn't caught in a user-defined class, where does it go and what does it do? 22. Suppose you've defined an exception called NotANumberException(). Now suppose that NotAPositiveNumberException extends NotANumberException. Will catch (NotANumberException) { System.out.println("Caught NotANumberException"); } a catch a NotAPositiveNumberException? Now suppose you have the following catch clause and throw a NotAPositiveNumberException. What happens? catch (NotANumberException) { System.out.println("Caught a NotANumberException"); } catch (NotAPositiveNumberException) { System.out.println("Caught a NotAPositiveNumberException"); } 23. In general which catch statement should come first? The one that catches the subclass or the one that catches the superclass? Why? 24. What do you have to do to have an exception handled by both its own catch statement and by its superclass's catch statement? 25. What's the difference between throw and throws? 26. Write a class that keeps a running total of all characters passed to it (one at a time) and throws an exception if it is passed a non-alphabetic character. UNIT-6 JAVA Threads 6.1 Introduction A thread is a single sequential flow of control within a program. It is a lightweight version of a process. It enables a single program to run multiple parts of itself at the same time. For example, one part of a program can print the document in the printer while another part builds new document. These are similar to processes in that they can be executed independently and simultaneously, but are different in that they do not have the entire overhead that a process does. Threads do not make copies of the entire parent process. Instead, only the code needed is run in parallel. This means that threads can be started quickly because they don't have the entire overhead of a complete process. They do, however, have complete access to all data of the parent process. Threads can read and/or write data that any other thread can access. This makes interthread communication simpler, but can lead to multiple threads modifying data in an unpredictable manner. Additional programming care is required with threads. Threads are useful programming tools for two main reasons. First, they enable programs to do multiple things at one time. Second, threads enable the programmer to concentrate on program functionality without worrying about the implementation of multitasking schemes. A single thread has a beginning, a sequence, and an end and at any given time during the runtime of the thread, there is a single point of execution. However, a thread itself is not a program; it cannot run on its own. Rather, it runs within a program. The figure 6.1 shows this relationship. Figure 6.1. A Single Thread 6.2 Creating a Thread There are two different methods for creating a thread: 1. Extending the Thread class 2. Implementing the Runnable interface. In the Thread subclass, implement the run( ) method. The signature of run( ) is as shown in the example. run( ) is the entry point or starting point (or main) of thread. To start a thread, create an object from Thread class. Send the "start()" method to the thread object. This will create the new thread, start it as an active entity in program, and call the run() method in the thread object. Do not call the run() method directly. Calling the run() directly executes the method in the normal sequential manner. class SimpleThread extends Thread { public void run() { for ( int count = 0; count < 4; count++) System.out.println( "Message " + count + " From: Mom" ); } } class TestingSimpleThread { public static void main( String[] args ) { SimpleThread parallel = SimpleThread(); System.out.println( "Create the thread"); new parallel.start(); System.out.println( "Started the thread" ); System.out.println( "End" ); } } In the Second Method for Creating a Thread, the class should implement the Runnable interface, which has one method, run(). This run() plays the same role as the run() in the Thread subclass in the first method. Second, create an instance of the Thread class, passing an instance of class to the constructor. Finally, send the thread object the start() method as shown in the example below,. class SecondMethod implements Runnable { public void run() { for ( int count = 0; count < 4; count++) System.out.println( "Message " + count + " From: Dad"); } } class TestThread { public static void main( String[] args ) { SecondMethod notAThread = new SecondMethod(); Thread parallel = new Thread( notAThread ); System.out.println( "Create the thread"); parallel.start(); System.out.println( "Started the thread" ); System.out.println( "End" ); } } 6.3 The Life Cycle of a Thread A thread can be in any of the following states: New Thread state (Ready-to-run state) Runnable state (Running state) Not Runnable state Dead state Figure 6.2. Thread States New Thread The instantiation of a Thread object creates a new thread but does not start it running. A thread starts life in the Ready-to-run state. Only the start() or stop() methods can be used when the thread is in this state. Calling any method besides start() or stop() causes an IllegalThreadStateException. Runnable When the start() method is invoked on a New Thread() it gets to the runnable state or running state by calling the run() method. A Runnable thread may actually be running, or may be awaiting its turn to run. Not Runnable A thread becomes Not Runnable when one of the following four events occurs: When sleep() method is invoked and it sleeps for a specified amount of time When suspend() method is invoked When the wait() method is invoked and the thread waits for notification of a free resource or waits for the completion of another thread or waits to acquire a lock of an object. The thread is blocking on I/O and waits for its completion Thread switches form a non runnable to a runnable state in the following condition-: If a thread has been put to sleep, then the specified number of milliseconds must elapse (or it must be interrupted). If a thread has been suspended, then its resume() method must be invoked If a thread is waiting on a condition variable, whatever object owns the variable must relinquish it by calling either notify() or notifyAll(). If a thread is blocked on I/O, then the I/O must complete. Dead State A thread enters this state when the run() method has finished executing or when the stop() method is invoked. Once in this state, the thread cannot ever run again. 6.4 Thread Methods All Java threads implement four methods: init, run, start, and stop. These are default methods in the Thread class. If a class implements Runnable (as discussed in next topic), these methods must be declared explicitly. init The init method to initialize a thread objects. Here is an example of an init method, public void init() { index = 0; } This method simply assigns a value of zero to the index variable. Larger, more complex applications might include code that opens databases, creates display objects, or just about anything that should be done only the first time a thread is started. start The start method is called to start a thread execution. This method usually contains the code for actually creating and starting a thread. Here is an example of a start method, public void start() { if (mainThread == null) { new mainThread = Thread(this); mainThread.start(); } } This method checks whether a thread has not yet been created, by testing whether the thread object mainThread is null. If it is not, a new thread object is created using new, and then the thread itself is started by calling the object's start method. stop The stop method contains the code needed to stop a thread's execution. It generates a signal that will be caught by all threads and that causes them to exit. This method can also change an object that causes a calling loop in the run method to exit. In the following example, this method simply sets a variable to false. loop is used in a main loop run method for control flow. public void stop() { loop = false; } run This method contains the main body of code to be executed by a thread. Here is an example of a run method: public void run() { loop = true; while (loop == true) { System.out.println("index = " + index++); try {Thread.sleep(1000);} catch(InterruptedException e){} } } The body of this method consists of the initialization of the loop variable and a while loop that will continue executing until loop no longer has a value of true. The body of the loop prints out the value of the index variable to the screen and then sleeps for one second. 6.5 Using Threads Threads are useful programming tools for two main reasons. First, they enable programs to do multiple things at one time. This is useful for such activities as letting a user do something while something else happens in the background. Second, threads enable the programmer to concentrate on program functionality without worrying about the implementation of multitasking schemes. A programmer can simply spin off another thread for some background or parallel operation without being concerned about interprocess communications. Converting a Class to a Thread Following are the steps to convert the class into threads1. 2. 3. 4. 5. Declare the class as implementing the Runnable interface. Implement the run() method. Declare a Thread object as a data field of the class. Create the Thread object and call its start() method. Call the thread's stop() method to destroy the thread Declaring Threads The Thread object can be declared as a data field of the class as shown below. The thread object will hold a reference to the thread with which the applet is associated. Methods of threads can be accessed through this object. Thread thread; Creating and Starting the Thread Object There are two methods in creating a thread. First, implementing the Runnable interface and Second, extending the thread class. Creating thread by implementing the Runnable interface. This method uses run() method. Here, create an instance of the Thread class, pass it to the constructor. Finally, send the thread object the start() method. class SecondMethod implements Runnable { public void run() { for ( int count = 0; count < 4; count++) System.out.println( "Message " + count + " From: Dad"); } } class TestThread { public static void main( String[] args ) { SecondMethod notAThread = new SecondMethod(); Thread parallel = new Thread( notAThread ); System.out.println( "Create the thread"); parallel.start(); System.out.println( "Started the thread" ); System.out.println( "End" ); } } Creating thread by extending the thread class In the Thread subclass, implement the run() method. The signature of run() must be as it is in this example. run() is the entry point or starting point (or main) of thread. To start a thread, create an object from Thread class. Send the "start()" method to the thread object. This will create the new thread, start it as an active entity in your program, and call the run() method in the thread object. Do not call the run() method directly. Calling the run() directly executes the method in the normal sequential manner. class SimpleThread extends Thread { public void run() { for ( int count = 0; count < 4; count++) System.out.println( "Message " + count + " From: Mom" ); } } class TestingSimpleThread { public static void main( String[] args ) { SimpleThread parallel = new SimpleThread(); System.out.println( "Create the thread"); parallel.start(); System.out.println( "Started the thread" ); System.out.println( "End" ); } } new and the Instantiation of Threads Instances of threads are created using the new keyword. Arguments to new can either use the Thread class explicitly, as in mainThread = new Thread(this); or specify a class that is a subclass of Thread, like this: mainThread = new MyThreadClass(); In the first example, the current instance, this, of an object is initialized as a thread. Any object, however, can be passed as an argument to the Thread class. Note that the Thread class has few constructors. If additional constructor types are needed, creating a subclass of Thread with the needed constructors is quite useful. The second thread-creation example allows for these possibilities. Stopping the Thread When the run() method of a thread ends, so does the thread. In case, switching between threads are required, need to stop the thread as shown in example below, public void stop() { thread.stop(); } Destroying a Thread It is not necessary to explicitly destroy the thread object. Java's garbage collector takes care of this detail. If it is necessary to help the garbagecollection process, make sure all references are removed to the thread object. The simplest way to do this is to assign the value null to all variables containing thread references, as in the following example: Thread myThread = new Thread(); myThread.start(); myThread.stop(); myThread = null; In this example, the thread object is instantiated with new. The thread is then started and stopped. Finally, null is assigned to the variable containing the thread instance. This last step ensures that Java's garbage collector will schedule a resource deallocation for that object. Naming a Thread Java provides a means for assigning names to threads. Names can consist of any valid Java identifier. Naming threads makes it convenient to distinguish one thread from another and enables a parent process to query a thread for its name. A thread can be assigned a name at creation time or at any point thereafter. Threads can also be renamed at any time. To name a thread at creation time, use a Thread constructor that accepts a string as an additional argument. As shown in the example below, the thread is instantiated by new and assigned a name of " Examplethread", Thread myThread = new Thread(this."Examplethread"); The getName( ) Method The getName returns the name associated with a specified thread object, as in the following example: System.out.println("name of thread is " + myThread.getName()); This example prints out the name assigned to the thread object myThread. Using the previous example, this statement would print the following to the screen: name of thread is Examplethread A thread can also query for its own name in the same way: System.out.println("My name is " + this.getName()); The setName Method The name of a thread can be set or changed using setName( ) method. The parent process, the thread itself, or any other method that has access to the thread object can do this. Following is an example of changing a thread name using setName: myThread.setName("Renamedthread"); This example changes the name of the thread from "Examplethread" to "Renamedthread". 6.6 Synchronization of Threads Previous topics of this lesson had examples with independent, asynchronous threads. That is, each thread contained all of the data and methods required for its execution without using any outside resources or methods. In addition, the threads in those examples ran at their own pace without concern over the state or activities of any other concurrently running threads. However, there are many situations where separate, concurrently running threads do share data and must consider the state and activities of other threads. One such set of programming situations are known as producer/consumer scenarios where the producer generates a stream of data which then is consumed by a consumer. For example, imagine a Java application where one thread (the producer) writes data to a file while a second thread (the consumer) reads data from the same file. Or, as the characters were typed on the keyboard, the producer thread places key events in an event queue and the consumer thread reads the events from the same queue. Both of these examples use concurrent threads that share a common resource: the first shares a file, the second shares an event queue. Because the threads share a common resource, they must be synchronized in some way. Producer/Consumer Example The Producer generates an integer between 0 and 9 (inclusive), stores it in a Num object, and prints the generated number. To make the synchronization problem more interesting, the Producer sleeps for a random amount of time between 0 and 100 milliseconds before repeating the number generating cycle: public class Producer extends Thread { private Num numb; private int number; public Producer(Num c, int number) { numb = c; this.number = number; } public void run() { for (int i = 0; i < 10; i++) { numb.put(i); System.out.println("Producer #" + this.number + " put: " + i); try { sleep((int)(Math.random() * 100)); } catch (InterruptedException e) { } } } } The Consumer consumes all integers from the Num (the exact same object into which the Producer put the integers in the first place) as quickly as they become available. public class Consumer extends Thread { private Num numb; private int number; public Consumer(Num c, int number) { numb = c; this.number = number; } public void run() { int value = 0; for (int i = 0; i < 10; i++) { value = numb.get(); System.out.println("Consumer #" + this.number + " got: " + value); } } } The Producer and Consumer in this example share data through a common Num object. And neither the Producer nor the Consumer makes any effort to ensure that the Consumer is getting each value produced once and only once. The synchronization between these two threads actually occurs at a lower level, within the get and put methods of the Num object. Now, assume that these two threads are not synchronized and let us discuss about the potential problems that might arise in that situation. 1. One problem arises when the Producer is quicker than the Consumer and generates two numbers before the Consumer has a chance to consume the first one. Thus the Consumer would skip a number. Part of the output might look like this: ... Consumer #1 got: 3 Producer #1 put: 4 Producer #1 put: 5 Consumer #1 got: 5 ... 2. Another problem that might arise is when the Consumer is quicker than the Producer and consumes the same value twice. In this situation, the Consumer would print the same value twice and might produce output that looked like this: ... Producer #1 put: 4 Consumer #1 got: 4 Consumer #1 got: 4 Producer #1 put: 5 . . . Either way, the result is wrong. The Consumer has to consume each integer produced by the Producer exactly once. These Problems are as called race conditions. They arise from multiple, asynchronously executing threads trying to access a single object at the same time and getting the wrong result. Race conditions in the producer/consumer example are prevented by having the storage of a new integer into the Num by the Producer be synchronized with the retrieval of an integer from the Num by the Consumer. The Consumer must consume each integer exactly once. The activities of the Producer and Consumer must be synchronized in two ways. First, the two threads must not simultaneously access the Num. A Java thread can prevent this from happening by locking an object. When an object is locked by one thread and another thread tries to call a synchronized method on the same object, the second thread will block until the object is unlocked (discussed later in this chapter). And second, the two threads must do some simple coordination. That is, the Producer must have some way to indicate to the Consumer that the value is ready and the Consumer must have some way to indicate that the value has been retrieved. The Thread class provides a collection of methods--wait, notify, and notifyAll (discussed later in this chapter) to help threads wait for a condition and notify other threads of when that condition changes. The Main Program Consider a small stand-alone Java application that creates a Num object, a Producer, a Consumer, and then starts both the Producer and the Consumer. public class ProducerConsumerTest { public static void main(String[] args) { Num c = new Num(); Producer p1 = new Producer(c, 1); Consumer c1 = new Consumer(c, 1); p1.start(); c1.start(); } } The Output Here's the output of ProducerConsumerTest. Producer #1 put: 0 Consumer #1 got: 0 Producer #1 put: 1 Consumer #1 got: 1 Producer #1 put: 2 Consumer #1 got: 2 Producer #1 put: 3 Consumer #1 got: 3 Producer #1 put: 4 Consumer #1 got: 4 Producer #1 put: 5 Consumer #1 got: 5 Producer #1 put: 6 Consumer #1 got: 6 Producer #1 put: 7 Consumer #1 got: 7 Producer #1 put: 8 Consumer #1 got: 8 Producer #1 put: 9 Consumer #1 got: 9 Locking an Object The code segments within a program that access the same object from separate, concurrent threads are called critical sections. In the Java language, a critical section can be a block or a method and are identified with the synchronized keyword. The Java platform then associates a lock with every object that has synchronized code. In the producer/consumer example, the put and get methods of the Num are the critical sections. The Consumer should not access the Num when the Producer is changing it, and the Producer should not modify it when the Consumer is getting the value. So put and get in the Num class should be marked with the synchronized keyword. Here is a code skeleton for the Num class, public class Num { private int contents; private boolean available = false; public synchronized int get() { ... } public synchronized void put(int value) { ... } } Note that the method declarations for both put and get contain the synchronized keyword. Hence, the system associates a unique lock with every instance of Num (including the one shared by the Producer and the Consumer). Whenever control enters a synchronized method, the thread that called the method locks the object whose method has been called. Other threads cannot call a synchronized method on the same object until the object is unlocked. So, when the Producer calls Num's put method, it locks the Num, thereby preventing the Consumer from calling the Num's get method: public synchronized void put(int value) { // Num locked by the Producer ... // Num unlocked by the Producer } When the put method returns, the Producer unlocks the Num. Similarly, when the Consumer calls Num's get method, it locks the Num, thereby preventing the Producer from calling put as shown below, public synchronized int get() { // Num locked by the Consumer ... // Num unlocked by the Consumer } The acquisition and release of a lock is done automatically and atomically by the Java runtime system. This ensures that race conditions cannot occur in the underlying implementation of the threads, thus ensuring data integrity. Also, two threads must be able to notify one another when they have done their job. Synchronized Blocks Synchronization of static methods in a class is independent from the synchronization of instance methods on objects of the class. A subclass decides whether the new definition of an inherited synchronized method will remain synchronized in the subclass. The synchronized block allows execution of arbitrary code to be synchronized on the lock of an arbitrary-object. The general form of the synchronized block is as follows: synchronized (<object reference expression>) { <code block> } A compile-time error occurs if the expression produces a value of any primitive type. If execution of the block completes normally, then the lock is released. If execution of the block completes abruptly, then the lock is released. A thread can hold more than one lock at a time. Synchronized statements can be nested. Synchronized statements with identical expressions can be nested. The expression must evaluate to a non-null reference value, otherwise, a NullPointerException is thrown. Once a thread has entered the code block after acquiring the lock on the specified object, no other thread will be able to execute the code block, or any other code requiring the same object lock, until the lock is relinquished. This happens when the execution of the code block completes normally or an uncaught exception is thrown. Using the notifyAll and wait Methods The Num stores its value in private member variable called contents. Num has another private member variable, available, that is a boolean. available is true when the value has just been put but not yet gotten and is false when the value has been gotten but not yet put. So, here is one possible implementation for the put and get methods: public synchronized int get() { // won't work! if (available == true) { available = false; return contents; } } public synchronized void put(int value) { // won't work! if (available == false) { available = true; contents = value; } } The above two methods will not work. When the Producer has not put anything in the Num and available false then get does nothing. Similarly, if the Producer calls put before the Consumer got the value, put does nothing. Here, it is necessary for the Consumer to wait until the Producer puts something in the Num and the Producer must notify the Consumer when it is done. Similarly, the Producer must wait until the Consumer takes a value (and notifies the Producer of its activities) before replacing it with a new value. The two threads must coordinate more fully and can use wait and notifyAll methods of Object. Here are the new implementations of get and put that wait on and notify each other of their activities, public synchronized int get() { while (available == false) { try { // wait for Producer to put value wait(); } catch (InterruptedException e) { } } available = false; // notify Producer that value has been retrieved notifyAll(); return contents; } public synchronized void put(int value) { while (available == true) { try { // wait for Consumer to get value wait(); } catch (InterruptedException e) { } } contents = value; available = true; // notify Consumer that value has been set notifyAll(); } The code in the get method loops until the Producer has produced a new value. Each time through the loop, get calls the wait method. The wait method relinquishes the lock held by the Consumer on the Num (thereby allowing the Producer to get the lock and update the Num) and then waits for notification from the Producer. When the Producer puts something in the Num, it notifies the Consumer by calling notifyAll. The Consumer then comes out of the wait state, available is now true, the loop exits, and the get method returns the value in the Num. The put method works in a similar fashion, waiting for the Consumer thread to consume the current value before allowing the Producer to produce a new one. The notifyAll method wakes up all threads waiting on the object in question (in this case, the Num). The awakened threads compete for the lock. One thread gets it, and the others go back to waiting. The Object class also defines the notify method, which arbitrarily wakes up one of the threads waiting on this object. Deadlocks A deadlock is a situation that causes two or more threads to hang. In the simplest case, two threads are each trying to acquire a monitor already owned by the other thread. Each thread goes to sleep, waiting for the desired monitor to become available, but the monitors never become available. The first thread waits for the monitor owned by the second thread, and the second thread waits for the monitor owned by the first thread. Because each thread is waiting for the other, each never releases its monitor to the other thread. A deadlock can occur for the following reasons Each thread needed exclusive use of the resources. One thread is not allowed to take a resource from the other. Each thread is waiting while holding a resource that another thread is waiting for. Some of the deadlock prevention method are as listed below, 1. Lock Ordering 2. Lock Timeout 3. Deadlock Detection Lock Ordering Deadlock occurs when multiple threads need the same locks but obtain them in different order. If you make sure that all locks are always taken in the same order by any thread, deadlocks cannot occur. Consider an example, Thread 1: lock A lock B Thread 2: wait for A lock C (when A locked) Thread 3: wait for A wait for B wait for C If a thread, like Thread 3, needs several locks, it must take them in the decided order. It cannot take a lock later in the sequence until it has obtained the earlier locks. For instance, neither Thread 2 or Thread 3 can lock C until they have locked A first. Since Thread 1 holds lock A, Thread 2 and 3 must first wait until lock A is unlocked. Then they must succeed in locking A, before they can attempt to lock B or C. Lock ordering is a simple yet effective deadlock prevention mechanism. However, it can only be used if the information about all locks is known. Lock Timeout Another deadlock prevention mechanism is to put a timeout on lock attempts meaning a thread trying to obtain a lock will only try for so long before giving up. If a thread does not succeed in taking all necessary locks within the given timeout, it will backup, free all locks taken, wait for a random amount of time and then retry. The random amount of time waited serves to give other threads trying to take the same locks a chance to take all locks, and thus let the application continue running without locking. Consider an example of two threads trying to take the same two locks in different order, where the threads back up and retry: Thread 1 locks A Thread 2 locks B Thread 1 attempts to lock B but is blocked Thread 2 attempts to lock A but is blocked Thread 1's lock attempt on B times out Thread 1 backs up and releases A as well Thread 1 waits randomly (e.g. 257 millis) before retrying. Thread 2's lock attempt on A times out Thread 2 backs up and releases B as well Thread 2 waits randomly (e.g. 43 millis) before retrying. In the above example Thread 2 will retry taking the locks about 200 millis before Thread 1 and will therefore likely succeed at taking both locks. Thread 1 will then wait already trying to take lock A. When Thread 2 finishes, Thread 1 will be able to take both locks too (unless Thread 2 or another thread takes the locks in between). If lock times out it does not necessarily mean that the threads had deadlocked. It could also just mean that the thread holding the lock (causing the other thread to time out) takes a long time to complete its task. Additionally, if enough threads compete for the same resources they still risk trying to take the threads at the same time again and again, even if timing out and backing up. This may not occur with 2 threads each waiting between 0 and 500 millis before retrying, but with 10 or 20 threads the situation is different. Then the likeliness of two threads waiting the same time before retrying (or close enough to cause problems) is a lot higher. So what do the threads do if a deadlock is detected? One possible action is to release all locks, backup, wait a random amount of time and then retry. This is similar to the simpler lock timeout mechanism except threads only backup when a deadlock has actually occurred. Not just because their lock requests timed out. However, if a lot of threads are competing for the same locks they may repeatedly end up in a deadlock even if they back up and wait. A better option is to determine or assign a priority of the threads so that only one (or a few) thread backs up. The rest of the threads continue taking the locks they need as if no deadlock had occurred. If the priority assigned to the threads is fixed, the same threads will always be given higher priority. To avoid this you may assign the priority randomly whenever a deadlock is detected. 6.7 Summary The idea of multiple threads of control within a single program may seem like a new and difficult concept, but it is not. All programs have at least one thread already, and multiple threads in a single program are not radically different from multiple programs within an operating system. A Java program can contain many threads, all of which may be created without the explicit knowledge of the developer. For now, when a Java application is written, there is an initial thread that begins its operation by executing the main() method of application. Threads are Java's way of running multiple, parallel code segments simultaneously. They are a lightweight process that does not have all the overhead that a normal process has. Threads do not make complete new copies of variables in the way that the C/C++ fork command does, allowing for faster thread startup. It also means that threads have access to each other's data. This can make communication among threads easier, but synchronization of data access may be a problem. Threads are based on the class Thread and can be implemented by either extending class Thread or using the interface Runnable. Using Runnable, you can add threading to existing classes. All threads implement the init, start, stop, and run methods. init is called the first time a thread is started, and it is a good place to put initialization code. start is called any time a thread is started. This is usually where thread initialization is done and the thread is actually started. stop is used to stop the execution of a thread and usually contains code that will terminate the main body of the thread. Finally, run is started by start and normally contains the body of the thread code. The problem of multiple threads modifying the same variable can arise due to the structure of Java, which allows threads access to common variables. This can be controlled using synchronization, which can be used on an object or on a method, and ensures that only one thread can execute a block of code at a given time Exercises 1. 2. 3. 4. 5. 6. 7. 8. 9. How are threads similar to multitasking? What Java interface must be implemented by all threads? What thread method do you call to start a thread? What method does Java call to get a thread started? What are the methods to stop threads? What is the difference between suspending and stopping a thread? How do you ensure that threads share the computer's processor properly? When would you use the synchronized keyword? What's the difference between a thread created as a subclass of java.lang.Thread and one created as an implementation of Runnable? 10. Why should synchronized blocks of code call wait()? 11. Why would you use a synchronized block vs. synchronized method? 12. What's the difference between the methods sleep() and wait()? 13. What do you understand by Synchronization? 14. There are two classes: A and B. The class B need to inform a class A when some important event has happened. What Java technique would you use to implement it? UNIT-7 JAVA Applets 7.1 Introduction Although Java is a general-purpose programming language suitable for a large variety of tasks, the task most people use it for is applet programming. An applet is a Java program that executes on a World Wide Web page. Applets are being used to accomplish far more than demonstrative goals. An applet is a small program that is intended not to be run on its own, but rather to be embedded inside another application....The Applet class provides a standard interface between applets and their environment. Following are the four definitions of applet A small application A secure program that runs inside a web browser A subclass of java.applet.Applet An instance of a subclass of java.applet.Applet The current uses of applets include the following, Tickertape-style news and sports headline updates Animated graphics Video games Student tests Image maps that respond to mouse movement Advanced text displays Database reports An applet can Draw pictures on a web page Create a new window and draw in it. Play sounds. Receive input from the user through the keyboard or the mouse. Make a network connection to the server from which it came and can send to and receive arbitrary data from that server. An applet cannot Write data on any of the host's disks. Read any data from the host's disks without the user's permission. In some environments, notably Netscape, an applet cannot read data from the user's disks even with permission. Delete files Read from or write to arbitrary blocks of memory, even on a non-memoryprotected operating system like the MacOS. All memory access is strictly controlled. Make a network connection to a host on the Internet other than the one from which it was downloaded. Call the native API directly (though Java API calls may eventually lead back to native API calls). Introduce a virus or trojan horse into the host system. An applet is not supposed to be able to crash the host system. However in practice Java isn't quite stable enough to make this claim yet. 7.2 Applet Examples The Java programming language and libraries enable to create applets that are as simple or as complex as needed. The Simplest Java Applet Consider the following example, MyApplet.java import java.applet.*; public class MyApplet extends Applet { } The first line of example tells the Java compiler that this applet will be using some or all of the classes defined in the applet package. The second line of code declares a new class called MyApplet. This new class is declared as public so that the class can be accessed when the applet is run in a Web browser or in the Appletviewer application. If applet class is not declared as public, the code will compile fine, but the applet will refuse to run. In other words, all applet classes must be public. When this applet is compiled, a class file called MyApplet.class, which is the byte-code file that can be executed by the Java system will be created. To run the applet, just create an HTML document called MyApplet.html as shown below, <title>Applet Test Page</title> <h1>Applet Test Page</h1> <applet code="MyApplet.class" width=250 height=250 name="MyApplet"> </applet> The "Hello World" Applet Following are the steps with example to create and use applets, 1. Create a Java Source File Create a file named HelloWorld.java with the Java code shown here: import java.applet.Applet; import java.awt.Graphics; public class HelloWorld extends Applet { public void paint(Graphics g) { g.drawString("Hello world!", 50, 25); } } 2. Compile the Source File Compile the source file using the Java compiler. If the compilation succeeds, the compiler creates a file named HelloWorld.class in the same directory (folder) as the Java source file (HelloWorld.java). This class file contains Java bytecodes. 3. Create an HTML File that Includes the Applet Using a text editor, create a file named Hello.html in the same directory that contains HelloWorld.class. This HTML file should contain the following text: <HTML> <HEAD> <TITLE> A Simple Program </TITLE> </HEAD> <BODY> Here is the output of my program: <APPLET CODE="HelloWorld.class" WIDTH=150 HEIGHT=25> </APPLET> </BODY> </HTML> Here, applets are embedded in web pages using the <APPLET> and </APPLET> tags. The CODE attribute tells the browser where to look for the compiled .class file. It is relative to the location of the source document The CODEBASE attribute contains a URL that points at the directory where the .class file is. The CODE attribute is the name of the .class file itself. For instance if on the HTML page of the previous section <applet code="HelloWorldApplet" codebase="classes" width="200" height="200"> </applet> Then the browser would have tried to find HelloWorldApplet.class in the classes directory in the same directory as the HTML page that included the applet. On the other hand if you had written <applet code="HelloWorldApplet" codebase=http://www.bar.com/classes width="200" height="200"> </applet> Then the browser would try to retrieve http://www.bar.com/classes/HelloWorldApplet.class regardless of where the HTML page was. the applet from The HEIGHT and WIDTH attributes specifies how big a rectangle the browser should set aside for the applet. These numbers are specified in pixels and are required. 4. Run the Applet To run the applet, load the HTML file into an application that can run Java applets. This application might be a Java-compatible browser or another Java applet viewing program, such as the Applet Viewer provided in the JDK. To load the HTML file, you usually need to tell the application the URL of the HTML file that is created. For example, enter something like the following into a browser's URL or Location field, file:/home/kwalrath/HTML/Hello.html After the completion of these steps, output looks like this, 7.3 The java.applet.Applet Class The Applet class is used to create, execute, and stop running applets. It is part of the format and structure that enables applets to run. The Applet class also provides applet-specific methods. Most of the code in an applet is no different from that in an application. Both use java.lang classes, for example, to do arithmetic functions and string manipulations. Some methods, however, are applet specific and require the presence of a Java-enabled browser. For example, one of these methods is used to retrieve and play an audio clip from across the Net. All the Applet methods are described as follows,. destroy() The destroy() method schedules with the Java interpreter to notify the garbage collector to sweep up unused resources. getAppletContext() The getAppletContext() method returns the environment in which the applet is running. This is usually the browser or applet viewer name. getAppletInfo() The getAppletInfo() method returns a string that was passed to it. It is called when the applet information is requested from the applet viewer. getAudioClip(URL) and getAudioClip(URL, String) The getAudioClip(URL) and getAudioClip(URL, String) methods get an audio clip. getCodeBase() The getCodeBase() method gets the base URL-that is, it returns the directory path in which the applet was started. getDocumentBase() getDocumentBase gets the document URL. getImage(URL) and getImage(URL, String) getImage gets an image retrieved from the URL argument location. getParameter(String) and getParameterInfo() The getParameter() method gets a parameter or an array of strings describing the applet. This information should be overridden in applets so that other applets can access the specific information. init() The init() method initializes the applet. This method normally should be overridden in code, which allows specifying precisely how the applet will be initialized. play(URL) and play(URL, String) The play() method plays an audio clip retrieved by getAudioClip. resize(int, int) and resize(Dimension) The resize() method resizes an applet. The dimensions are in pixels. setStub(AppletStub) The setStub() method sets the applet stub. Generally, this function is performed automatically by the system. showStatus(String) The showStatus() method shows a status message in the applet's context. start() and stop() The start() method starts the applet and the stop() method stops the applet execution. isActive() isActive() true returns true if the applet is active. The status of the method is immediately before start is executed. See Listing 10.9 for a demonstration of the use of isActive(). 7.4 The Five Stages of an Applet's Life Cycle Every Java applet inherits a set of default behaviors from the Applet class. In most cases, these default behaviors do nothing, unless some of Applet's methods are overriden in order to extend the applet's basic functionality. There are five parts in a life cycle, each of which has a matching method that can be overridden. The five stages of an applet's life cycle are as follows, Initialization stage In this stage applet object is created and loaded. Initialize the values that must be valid when the applet runs. The initialization stage occurs only once in the applet's life cycle. This can be done by overriding the init() method of applet class. Start stage. This stage occurs when the system starts running the applet. The start stage can occur right after the initialization stage or when an applet is restarted. This usually happens when the user switches back to the applet's page after viewing a different page in Web browser. The start stage can occur several times over the life of the applet. To provide own start code, override the start() method of Applet class. Paint stage. The paint stage occurs whenever the applet's display must be drawn on the screen. This happens right after the applet's start stage, as well as whenever the applet's display must be restored or changed. This can happen when the applet is exposed from underneath another window or when the program changes the applet's display in some way and explicitly repaints the applet. Almost every applet will have a paint() method, which is overridden. Stop stage. The stop stage is the counterpart to the start stage. Java executes this stage when the applet is no longer visible on the screen, such as when the user switches to a different Web page. The default behavior for this cycle is to keep the applet running in the background. To use stop cycle differently, override the Applet class's stop() method. Destroy stage. This is the counterpart to the initialization stage and occurs when the system is about to remove the applet from memory. Like the initialization cycle, the destroy cycle occurs only once. Before applet exists, resources are cleaned up.This can also be done by overriding the Applet class's destroy() method. Consider an example to override life cycle methods here the statement import java.awt.* is used to override paint() method, import java.applet.*; import java.awt.*; public class MyApplet2 extends Applet { public void init() { // Place initialization cycle code here. } public void start() { // Place start cycle code here. } public void paint(Graphics g) { // Place paint cycle code here. } public void stop() { // Place stop cycle code here. } public void destroy() { // Place destroy cycle code here. } } 7.5 Methods for Adding UI Components In Java, windowing and other graphical user interface functions are handled by the Abstract Windowing Toolkit (AWT) (discussed in detail in Unit-8). The AWT is a set of classes used to build a graphical user interface for Java applications and applets. It also includes classes to handle graphics, fonts, color, and an Event class which enable programs to respond to mouse clicks, mouse movements, and keyboard input. It enables programmers to easily create the following features for programs: Windows and dialog boxes Pull-down menus Buttons, labels, checkboxes, and other simple user interface components Text areas, scroll bars, and other more sophisticated user interface components Layout managers to control the placement of user interface components This topic focuses on how the AWT can be used in the development of applets. However, the same methods apply to the creation of applications. Simple Components Abstract Windowing Toolkit, makes graphical user interface with components. Each element manipulated with a windowing program is represented by its own component. There are components for buttons, text fields, scroll bars. To use these components in a program, one must put them into some kind of container. A container is a blank slate where graphical user interface components can be put. All containers in Java are subclasses of the Container class. There are two basic types of containers: The Window class: Pop-up windows separate from the main program. There are two subclasses of Window: Frame (windows that have a border and menu bar) and Dialog (a special window used in applications to select a file). The Panel class: A container that represents a section of an existing window. The Applet class is a container that is a subclass of the Panel class. Components are placed directly on an applet or use Panel objects to subdivide the applet into smaller sections. A Panel container is not visible when it is added to an applet. Its purpose is to provide a way to organize components when they are being laid out in a window. Consider an example Sample.java for an applet that has a new Panel added to its surface. It does not produce any output other than a blank window. import java.awt.*; public class Sample extends java.applet.Applet { Panel p = new Panel(); public void init() { add(p); } } The method call that puts the Panel object p on the applet window is the statement add(p). The add() method is used whenever a component of any kind is added to a container. Buttons The Button component is a rectangular button that can be pushed by clicking it with a mouse. The following code is used to create a Button component and add it to an applet window, Button b = new Button("Cancel");add(b); The add(b) method does not refer to a specific container object, so it defaults to the applet itself, adding the button to the applet surface. Text Fields The TextField component is an input box in which a user can type a single line of text. The number of characters that can be visible in the text field is configurable. The following code is used to create a TextField component and add it to an applet window, TextField t = new TextField(12); add(t); The parameter 12 in the constructor TextField(12) sets up the text field so that around 12 characters can be displayed in the field at one time. The user can type more characters than that, but only some of the characters will be displayed. Labels The Label component is a string of text displayed on the container; it cannot be modified by the user. The following code is used to create a Label component and add it to an applet window: Label l = new Label("address: "); add(l); The parameter in the constructor Label("address: ") identifies the text to be displayed. Checkboxes The Checkbox component is a toggle box that can be either selected-marked with a checkmark-or unselected. The checkbox usually has a line of text next to it explaining what the box signifies. The following code is used to create a Checkbox component and add it to an applet window, Checkbox c = new Checkbox("HI"); add(c); The parameter in the constructor CheckBox("HI") identifies the text to be displayed. 7.6 Methods for Drawing and Event Handling An event is a way for a program to communicate that something has taken place. Events generate automatic calls to methods in the same way that a paint() method can be called automatically when an applet window has to be redrawn, or an init() method is called automatically when an applet is first run. Events can involve a user interface element-such as a button that has been clicked. Events can also be something unrelated to the interface-such as an error condition that causes the program to stop execution. In Java, the class java.awt.Event handles all events related to the user interface. There are two kinds of events to consider: action events and scroll-list events. Action Events An action() event is generated by most user interface components to signify that an event has taken place. This means different things depending on the component: For buttons, an event means that the button has been clicked. For checkboxes, an event means that the box has been selected or deselected. For lists or choice lists, an event means that one of the list items has been selected. For text fields, an event means that the Enter key has been pressed to indicate that user input is completed. The action() method of the Event class takes the following form, public boolean action(Event e, Object o) { // method code here } All user interface components that generate an action event do so by calling the action() method. To determine which component generated the eventand to gather some other information about what occurred-there are two parameters to the action() method: an instance of the Event class and an Object. The following example Buttons.java creates three buttons on an applet window and sets a TextField in response to the button that was pressed. import java.awt.*; public class Buttons extends java.applet.Applet { Button b1 = new Button("country"); Button b2 = new Button("state"); Button b3 = new Button("place"); TextField t = new TextField(50); public void init() { add(b1); add(b2); add(b3); add(t); } public boolean action(Event e, Object o) { if (e.target instanceof Button) { String s = (String)o; if ( s.equals("country") ) t.setText("India"); else if ( s.equals("state") ) t.setText("Karnataka"); else t.setText("Bangalore"); } return true; } } To test the applet, create an HTML file with the source code given in example Buttons.html below, <html> <body> <applet code="Buttons.class" height=100 width=475> </applet> </body> </html> Scroll Bar Events The Scrollbar component uses the handleEvent() method which takes the following form, public boolean handleEvent(Event e) { // method code here } handleEvent() takes only one parameter: an instance of the Event class. Using the target variable of the Event class, one can determine which component generated the event and respond to it. The following example Scroller.java sets a value in a text field based on user input to a scroll bar. import java.awt.*; public class Scroller extends java.applet.Applet { Scrollbar s = new Scrollbar(Scrollbar.HORIZONTAL, 50,100,0,100); Label l = new Label("Choose Your Own Tax Rate: "); TextField t = new TextField("50%", 3); public void init() { add(s); add(l); add(t); } public boolean handleEvent(Event e) { if (e.target instanceof Scrollbar) { int taxrate = ((Scrollbar)e.target).getValue(); t.setText(taxrate + "%"); return true; } return false; } } Compile the file and create a Web page Scroller.html to put the applet on. <html> <body> <applet code="Scroller.class" height=200 width=200> </applet> </body> </html> 7.7 Summary This chapter describes about how to write an applet, java.applet class, Applet life cycle and methods like init, start, and paint. The init and start methods, along with stop and destroy, are called when major events (milestones) occur in the applet's life cycle. The paint method is called when the applet needs to draw itself to the screen. Need for HTML pages which uses the <APPLET> tag. When a browser user visits a page that contains an applet. The Applet class extends the AWT class, which enables to use components,event handling. This chapter provided a framework for the development of applets, but the actual details of AWT classes are coming up in the next unit. Exercises 1. What is the superclass for all applets? 2. Why do applet classes need to be declared as public? 3. What are the five life-cycle stages of an applet? 4. How is the paint cycle different from the rest of the life-cycle stages? 5. What's the difference between the initialize and start life-cycle stages? 6. What do the life-cycle methods in the Applet superclass do? 7. Write a simple do-nothing applet called TestApplet. Override the paint() method in TestApplet so that the applet displays the text string "Hello there!." The final applet should look like this, 8. Draw ten red circles in a vertical column in the center of the applet. 9. Create a simple holiday card applet using simple graphics for the next holiday 10. Why does an applet have no main() method? 11. What class must be extended when you code an applet? 12. What is the role of the Graphics object? 13. What set of tags is embedded in a text file to tell the browser how to treat each section of text? 14. What method of your applet is called by the browser when it wishes to display it on the monitor? 15. Write an applet that displays your name centered in a circle in the middle of the applet. 16. Write an applet that displays a set of three concentric circles of different colors centered in the applet. 17. Draw a large asterisk * in the center of the applet by drawing three lines that intersect in the center. 18. Write an applet that shows two squares. The user should be able to drag either square with the mouse. 19. How do you cause the applet GUI in the browser to be refreshed when data in it may have changed? 20. Write the method to display an applet in the browser, so that the contents are contained in a rectangle around the phrase "Exercise Applet". Appendix A Java Language Summary Reserved Words The following words are reserved for use by the Java language itself (some of them are reserved but not currently used). These terms cannot be used to refer to classes, methods, or variable names: abstract boolean do double import instanceo f public try return void break else int short byte extends interface static case final long super catch finally native switch char float new class for null this const goto package throw if private throws implements protected transient continue default synchronize d Comments /* this is the format of a multiline comment */ // this is a single-line comment /** Javadoc comment */ volatil e while Literals number Type int number[l | L] Type long 0xhex Hex integer 0Xhex Hex integer 0octal Octal integer [ number ].number Type double number[ f | f] Type float number[ d | D] Type double [ + | - ] number Signed numberenumber Exponent numberEnumber Exponent 'character' Single character "characters" String "" Empty string \b Backspace \t Tab \n Line feed \f Form feed \r Carriage return \" Double quote \' Single quote \\ Backslash \uNNNN Unicode escape (NNNN is hex) true Boolean false Boolean Variable Declaration [ byte | short | int | long ] varname Integer (pick one type) [ float | double ] varname Float (pick one type) char varname Character boolean varname Boolean classname varname Class type type varname, varname, varname Multiple variables The following options are available only for class and instance variables. Any of these options can be used with a variable declaration: [ static ] variableDeclaration Class variable [ final ] variableDeclaration Constants [ public | private | protected ] variableDeclaration Variable Assignment variable = value Assignment variable++ Postfix Increment ++variable Prefix Increment variable---- Postfix Decrement --variable Prefix Decrement variable += value variable -- = value variable *= value variable /= Add and assign Subtract and assign Multiply and assign Divide and assign Access control value variable %= value variable &= value variable | = Modulus and assign AND and assign OR and assign variable ^= value XOR and assign value variable <<= value variable value variable value >>= Left-shift and assign Right-shift and assign <<<= Zero-fill, right-shift, and assign Operators arg + arg Addition arg - arg Subtraction arg * arg Multiplication arg / arg Division arg % arg Modulus arg < arg Less than arg > arg Greater than arg <= arg Less than or equal to arg >= arg Greater than or equal to arg == arg Equal arg != arg Not equal arg && arg Logical AND arg || arg Logical OR ! arg Logical NOT arg & arg AND arg | arg OR arg ^ arg XOR arg << arg Left-shift arg >> arg Right-shift arg >>> arg Zero-fill right-shift ~ arg Complement (type)thing Casting arg instanceof class test ? trueOp : falseOp Instance of Tenary (if) operator Objects new class( ); Create new instance new class(arg,arg,arg...) New instance with parameters object.variable Instance variable object.classvar Class variable Class.classvar Class variable object.method( ) Instance method (no args) object.method(arg,arg,arg... ) object.classmethod( ) object.classmethod(arg,arg,a rg...) Class.classmethod( ) Class.classmethod(arg,arg,ar g...) Instance method Class method (no args) Class method Class method (no args) Class method Arrays Type varname[ ] Array variable type[ ] varname Array variable new New array object type[numElements] array[index] Element access array.length Length of array Loops and Conditionals if ( test) block if ( test ) block Conditional else block Conditional with else switch (test) { case value : statements case value : statements ... switch (only with int or char types) default : statement} for (initializer; test; change ) block for loop while ( test ) block while do block while (test) do break [ label ] Break from loop or switch continue [ label ] Continue loop label: Labeled loops loop loop Class Definitions class classname block Simple class definition [ final ] class classname block No subclasses [ abstract ] class classname block Cannot be instantiated [ public ] class classname block Accessible outside package class classname [ extends Superclass ] block class classname [ implements interfaces ] block Define superclass Implement one or more interfaces Method and Constructor Definitions The basic method looks like this, where returnType is a type name, a class name, or void: returnType methodName() block returnType Basic method methodName(parameter, parameter, ...) block Method with parameters Method parameters look like this: type parameterName Method variations can include any of the following optional keywords: [ abstract ] returnType methodName( ) block Abstract method [ static ] returnType methodName( ) block Class method [ native ] returnType methodName( ) block Native method [ final ] returnType methodName( ) block Final method [ synchronized ] returnType methodName( ) block [ public | private | protected ] returnType methodName( ) Thread lock before executing Access control Constructors look like this: classname() block classname(parameter, Basic constructor parameter, parameter...) block [ public | private | protected] classname() block Constructor with parameters Access control In the method/constructor body, you can use these references and methods: this Refers to current object super Refers to superclass super.methodName() Calls a superclass's method this(...) Calls class's constructor super(...) Calls superclass's constructor return [ value ] Returns a value Importing import Imports specific class name package.className import package.* Imports all classes in package package packagename Classes in this file belong to this package interface interfaceName [ extends anotherInterface ] block [ public ] interface interfaceName block [ abstract ] interface interfaceName block Guarding synchronized ( object ) block try block catch block ( Waits for lock on object Guarded statements exception ) Executed if exception is thrown [ finally block ] Always executed try block [ catch ( exception ) Same as previous example (can use optional catch or block ] finally finally block but not both) Appendix B The Java Class Library This appendix provides a general overview of the classes available in the standard Java packages. java.lang The java.lang package contains the classes and interfaces that are the core of the Java language. Interfaces Cloneable Interface indicating that an object may be copied or cloned Runnable Methods for classes that want to run as threads Classes Boolean Object wrapper for boolean values Byte Object wrapper for byte values (Java 1.1) Character Object wrapper for char values Class Runtime representations of classes ClassLoader Abstract behavior for handling loading of classes Compiler System class that gives access to the Java compiler Double Object wrapper for double values Float Object wrapper for float values Integer Object wrapper for int values Long Object wrapper for long values Math Utility class for math operations Number Abstract superclass of all number classes (Integer, Float, and so on) Object Generic Object class, at top of inheritance hierarchy Process Abstract behavior for processes such as those spawned Interfaces using methods in the System class Runtime Access to the Java runtime SecurityManager Abstract behavior for implementing security policies Short Object wrapper for short values (Java 1.1) String Character strings StringBuffer Mutable strings System Access to Java's system-level behavior, provided in a platform-independent way. Thread Methods for managing threads and classes that run in threads ThreadDeath Class of object thrown when a thread is asynchronously terminated ThreadGroup A group of threads Throwable Generic exception class; all objects thrown must be Throwable Void Object wrapper for void types (Java 1.1) java.util The java.util package contains various utility classes and interfaces, including random numbers, system properties, and other useful classes. Enumeration Methods for enumerating sets of values Observer Methods for enabling classes to observe Observable objects Classes BitSet A set of bits Date The current system date as well as methods for generating and parsing dates Dictionary An abstract class that maps between keys and values (superclass of HashTable) Hashtable A hash table Observable An abstract class for observable objects Properties A hash table that contains behavior for setting and retrieving persistent properties of the system or a class Random Utilities for generating random numbers Stack A stack (a last-in-first-out queue) StringTokenizer Utilities for splitting strings into individual "tokens" Vector A growable array of Objects java.io The java.io package provides input and output classes and interfaces for streams and files. Interfaces DataInput Methods for reading machine-independent typed input streams DataOutput Methods for writing machine-independent typed output streams FilenameFilter Methods for filtering filenames Classes BufferedInputStream A buffered input stream BufferedOutputStrea A buffered output stream m ByteArrayInputStrea An input stream from a byte array m ByteArrayOutputStre An output stream to a byte array am DataInputStream Enables you to read primitive Java types (ints, chars, booleans, and so on) from a stream in a machineb independent way DataOutputStream Enables you to write primitive Java data types (ints, chars, booleans, and so on) to a stream in a machine-independent way File Represents a file on the host's file system FileDescriptor Holds onto the UNIX-like file descriptor of a file or socket FileInputStream An input stream from a file, constructed using a filename or descriptor FileOutputStream An output stream to a file, constructed using a filename or descriptor FilterInputStream Abstract class that provides a filter for input streams (and for adding stream functionality such as buffering) FilterOutputStream Abstract class that provides a filter for output streams (and for adding stream functionality such as buffering) InputStream An abstract class representing an input stream of bytes; the parent of all input streams in this package LineNumberInputStre An input stream that keeps track of line numbers am OutputStream An abstract class representing an output stream of bytes; the parent of all output streams in this package PipedInputStream A piped input stream, which should be connected to a PipedOutputStream to be useful PipedOutputStream A piped output stream, which should be connected to a PipedInputStream to be useful (together they provide safe communication between threads) PrintStream An output stream for printing (used by System.out.println(...)) PushbackInputStream An input stream with a one-byte push-back buffer RandomAccessFile Provides random access to a file, constructed from filenames, descriptors, or objects SequenceInputStream Converts a sequence of input streams into a single input stream StreamTokenizer Converts an input stream into a series of individual tokens StringBufferInputSt ream An input stream from a String object java.net The java.net package contains classes and interfaces for performing network operations, such as sockets and URLs. Interfaces ContentHandlerFactory Methods for creating ContentHandler objects SocketImplFactory Methods for creating socket implementations (instance of the SocketImpl class) URLStreamHandlerFactory Methods for creating URLStreamHandler objects Classes ContentHandler Abstract behavior for reading data from a URL connection and constructing the appropriate local object, based on MIME types DatagramPacket A datagram packet (UDP) DatagramSocket A datagram socket InetAddress An object representation of an Internet host (host name, IP address) MulticastSocket A server-side socket with support for transmitting data to multiple client sockets (Java 1.1) ServerSocket A server-side socket Socket A socket SocketImpl An abstract class for specific socket implementations URL An object representation of a URL URLConnection Abstract behavior for a socket that can handle various Web-based protocols (http, ftp, and so on) URLEncoder Turns strings into x-www-form-urlencoded format URLStreamHandler Abstract class for managing streams to object referenced by URLs java.awt The java.awt package contains the classes and interfaces that make up the Abstract Windowing Toolkit. Interfaces LayoutManager Methods for laying out containers MenuContainer Methods for menu-related containers Classes BorderLayout A layout manager for arranging items in border formation Button A UI pushbutton Canvas A canvas for drawing and performing other graphics operations CardLayout A layout manager for HyperCard-like metaphors Checkbox A checkbox CheckboxGroup A group of exclusive checkboxes (radio buttons) CheckboxMenuItem A toggle menu item Choice A popup menu of choices Color An abstract representation of a color Component The abstract generic class for all UI components Container Abstract behavior for a component that can hold other components or containers Dialog A window for brief interactions with users Dimension An object representing width and height Event An object representing events caused by the system or based on user input FileDialog A dialog box for getting filenames from the local file system FlowLayout A layout manager that lays out objects from left to right in rows Font An abstract representation of a font FontMetrics Abstract class for holding information about a specific font's character shapes and height and width information Frame A top-level window with a title Graphics Abstract behavior for representing a graphics context and for drawing and painting shapes and objects GridBagConstraints Constraints for components laid out using GridBagLayout GridBagLayout A layout manager that aligns components horizontally and vertically based on their values from GridBagConstraints GridLayout A layout manager with rows and columns; elements are added to each cell in the grid Image An abstract representation of a bitmap image Insets Distances from the outer border of the window; used to lay out components Label A text label for UI components List A scrolling list MediaTracker A way to keep track of the status of media objects being loaded over the Net Menu A menu that can contain menu items and is a container on a menu bar MenuBar A menu bar (container for menus) MenuComponent The abstract superclass of all menu elements MenuItem An individual menu item Panel A container that is displayed Point An object representing a point (x and y coordinates) Polygon An object representing a set of points Rectangle An object representing a rectangle (x and y coordinates for the top corner, plus width and height) Scrollbar A UI scroll bar object TextArea A multiline, scrollable, editable text field TextComponent The superclass of all editable text components TextField A fixed-size editable text field Toolkit Abstract behavior for binding the abstract AWT classes to a platform-specific toolkit implementation Window A top-level window and the superclass of the Frame and Dialog classes java.awt.image The java.awt.image package is a subpackage of the AWT that provides interfaces and classes for managing bitmap images. Interfaces ImageConsumer Methods for receiving image created by an ImageProducer ImageObserver Methods for tracking the loading and construction of an image ImageProducer Methods for producing image data received by an ImageConsumer Classes ColorModel An abstract class for managing color information for images CropImageFilter A filter for cropping images to a particular size DirectColorModel A specific color model for managing and translating pixel color values FilteredImageSource An ImageProducer that takes an image and an ImageFilter object and produces an image for an ImageConsumer ImageFilter A filter that takes image data from an ImageProducer, modifies it in some way, and hands it off to an ImageConsumer IndexColorModel A specific color model for managing and translating color values in a fixed-color map MemoryImageSource An image producer that gets its image from memory; used after constructing an image by hand PixelGrabber An ImageConsumer that retrieves a subset of the pixels in an image RGBImageFilter Abstract behavior for a filter that modifies the RGB values of pixels in RGB images java.awt.peer The java.awt.peer package is a subpackage of the AWT that provides the platform-specific AWT classes (for example, Motif, Macintosh, Windows 95) with platform-independent interfaces to implement. Each class in the AWT that inherits from either Component or MenuComponent has a corresponding peer class. Each of those classes is the name of the Component with -Peer added (for example, ButtonPeer, DialogPeer, and WindowPeer). Because each one provides similar behavior, they are not enumerated here. java.applet The java.applet package provides applet-specific behavior. Interfaces AppletContext Methods for referring to the applet's context AppletStub Methods for implementing applet viewers AudioClip Methods for playing audio files Classes Applet The base applet class Appendix D Differences between Java and C/C++ Java language is highly derived from the C and C++ languages. It is important to understand what aspects of C++ Java inherit. The focus of this appendix is to point out the differences between Java and C++. The Preprocessor The C++ preprocessor basically performs an intelligent search-and-replace on identifiers that have been declared using the #define directive. The problem with the preprocessor approach is that it provides an easy way for programmers to inadvertently add unnecessary complexity to a program. Also, it is weak when it comes to type checking and validation. Java does not have a preprocessor. Java uses constant data members in place of the #define directive. The result is that Java source code is much more consistent and easier to read than C++ source code. Additionally, Java programs do not use header files. Java compiler builds class definitions directly from the source code files, which contain both class definitions and method implementations. Pointers C++ programmers regularly use complex pointer arithmetic to create and maintain dynamic data structures. This results in complex bugs. The Java language does not support pointers. Java provides similar functionality by making use of references. Java passes all arrays and objects by reference. This approach prevents common errors caused by pointer mismanagement. The reference approach also makes programming easier. Any pointer task can be carried out just as easily and more reliably with objects and arrays of objects. Java runtime system performs boundary checking on all array indexing operations. Structures and Unions There are three types of complex data types in C++: classes, structures, and unions. Java implements only one of these data types: classes. Java forces programmers to use classes when the functionality of structures and unions is desired. Functions In C, code is organized into functions, which are global subroutines accessible to a program. C++ provides class methods. These are very similar to Java class methods. Java has no functions. It forces programmers to bundle all routines into class methods. Multiple Inheritance Multiple inheritance is a feature of C++ that allows deriving a class from multiple parent classes. Although multiple inheritance is powerful, it is complicated to use correctly and causes lots of problems. It is also very complicated to implement from the compiler perspective. Java does not support multiple inheritance. Instead, it provides interfaces. Java interfaces provide object method descriptions, but contain no implementations. Strings C and C++ have no built-in support for text strings. The standard technique adopted by C and C++ programmers is to use null-terminated arrays of characters to represent strings. In Java, strings are implemented as first-class objects (String and StringBuffer). Java's implementation of strings as objects provides several advantages: The manner in which you create strings and access the elements of strings is consistent across all strings on all systems. Because the Java string classes are defined as part of the Java language, and not part of some extraneous extension, Java strings function predictably every time. The Java string classes perform extensive runtime checking, which helps eliminate troublesome runtime errors. The goto Statement The goto statement causes messy, impossible-to-understand, and sometimes even impossible-to-predict code known as "spaghetti code." For this reason, Java does not provide a goto statement. The Java language specifies goto as a keyword, but its use is not supported. Operator Overloading Operator overloading, which is considered a prominent feature in C++, is not supported in Java. Operator overloading is a technique of defining different types of functionality for a fundamental operator, such as the addition operator (+), based on the types of objects being added. Automatic Coercions Automatic coercion refers to the implicit casting of data types that sometimes occurs in C and C++. For example, in C++, one can assign a float value to an int variable, which can result in a loss of information. Java does not support C++-style automatic coercions. In Java, if coercions will result in a loss of data. Variable Arguments C and C++ allow declaring functions, such as printf, that take a variable number of arguments. It is impossible for the compiler to thoroughly typecheck the arguments, which means problems, can arise at runtime. Again, Java doesn't support variable arguments. Command-Line Arguments The command-line arguments passed from the system into a Java program differ in a couple of ways from the command-line arguments passed into a C++ program. First, the number of parameters passed differs between the two languages. In C and C++, the system passes two arguments to a program: argc and argv. argc specifies the number of arguments stored in argv. argv is a pointer to an array of characters containing the actual arguments. In Java, the system passes a single value to a program: args. args is an array of Strings that contains the command-line arguments. In C and C++, the command-line arguments passed into a program include the name used to invoke the program. This name always appears as the first argument and is rarely used. In Java, name of the program is already known because it is the same name as the class, so there is no need to pass this information as a command-line argument. Therefore, the Java runtime system passes only the arguments following the name that invoked the program.