This post is a review of fundamental Java and programming concepts.
Java Class Structure
A Java class is described in a text file with a .java extension. In the example shown below, the Java keywords are highlighted in bold.
package [package_name]; import [other_packages]; public class ClassName { [variables(also known as fields)]; [constructor(s)]; [other methods]; }
- The package keyword defines where this class lives relative to other classes, and provides a level of access control. You use access modifiers (such as public and private) later in this lesson.
- The import keyword defines other classes or groups of classes that you are using in your class. The import statement helps to narrow what the compiler needs to look for when resolving class names used in this class.
- The class keyword precedes the name of this class. The name of the class and the file name must match when the class is declared public (which is a good practice). However, the keyword public in front of the class keyword is a modifier and is not required.
- Variables, or the data associated with programs (such as integers, strings, arrays, and references to other objects), are called instance fields (often shortened to fields).
- Constructors are functions called during the creation (instantiation) of an object (a representation in memory of a Java class).
- Methods are functions that can be performed on an object. They are also referred to as instance methods.
A Simple Class
To run a Java program, you must define a main method in the Java class as shown in below example. The main method is automatically called when the class is called from the command line.
public class Simple { public static void main(String args[]){ } }
Command-line arguments are passed to the program through the args[] array.
Java Naming Conventions
- Class names should be nouns in mixed case, with the first letter uppercase and the first letter of each internal word capitalized. This approach is termed “upper camel case.”
- Methods should be verbs in mixed case, with the first letter lowercase and the first letter of each internal word capitalized. This is termed “lower camel case.”
- Variable names should be short but meaningful. The choice of a variable name should be mnemonic: designed to indicate to the casual observer the intent of its use.
- One-character variable names should be avoided except as temporary “throwaway” variables.
- Constants should be declared by using all uppercase letters.
How to Compile and Run
Java class files must be compiled before running them. To compile a Java source file, use the Java compiler (javac).
$ javac –cp [path to other classes] -d [compiler output path] [path to source].java
You can use the CLASSPATH environment variable to the directory above the location of the package hierarchy. After compiling the source .java file, a .class file is generated. To run the Java application, run it using the Java interpreter (java):
$ java –cp [path to other classes] [package name].[classname]
CLASSPATH
The default value of the classpath is the current working directory (.); however, specifying the CLASSPATH variable or the –cp command line switch overrides this value.
The CLASSPATH variable is used by both the Java compiler and the Java interpreter (runtime).
The classpath can include:
- A list of directory names (separated by semicolons in Windows and colons in UNIX) – The classes are in a package tree relative to any of the directories on the list.
- A .zip or .jar file name that is fully qualified with its pathname – The classes in these files must be zipped with the pathnames that are derived from the directories formed by their package names.
How to Compile and Run: Example
Consider the following simple class in a file named HelloWorld.java in the test directory in the path /home/oracle:
public class HelloWorld public static void main (String [] args) { System.out.println(“ Hello World”); } }
Compile the HelloWorld.java program using below command:
$ javac HelloWorld.java
To run the application, you use the interpreter and the class name:
$ java HelloWorld Hello World
The advantage of an IDE like NetBeans is that management of the class path, compilation, and running the Java application are handled through the tool.
Code Blocks
Java fields (variables) and methods have a class scope defined by the opening left curly brace and ending at the closing right curly brace. Class scope allows any method in the class to call or invoke any other method in the class. Class scope also allows any method to access any field in the class.
For example:
public class SayHello { public static void main(String[] args) { System.out.println("Hello world"); } }
Code blocks are always defined by using braces {}. A block is executed by executing each of the statements defined within the block in order from first to last (left to right).
The Java compiler discards unnecessary white space in a line of code. Line indentation is not required but makes the code much more readable. In this post, the line indentation is four spaces, which is the default line indentation used by the NetBeans IDE.
Primitive Data Types
Integer
Java provides four different integer types to accommodate different size numbers. All the numeric types are signed, which means that they can hold positive or negative numbers.
The integer types have the following ranges:
- byte range is –128 to +127. Number of bits = 8.
- short range is –32,768 to +32,767. Number of bits = 16.
- int range is –2,147,483,648 to +2,147,483,647. The most common integer type is int. Number of bits = 32.
- long range is –9,223,372,036,854,775,808 to +9,223,372,036,854,775,807. Number of bits = 64.
Floating Point
The floating-point types hold numbers with a fractional part and conform to the IEEE 754 standard. There are two types of floating points: float and double.
double is called so because it provides double the precision of float. A float uses 32 bits to store data, whereas a double uses 64 bits.
Numeric Literals
Any number of underscore characters (_) can appear between digits in a numeric field. This can improve the readability of your code.
long creditCardNumber = 1234_5678_9012_3456L; long socialSecurityNumber = 999_99_9999L; long hexBytes = 0xFF_EC_DE_5E; long hexWords = 0xCAFE_BABE; long maxLong = 0x7fff_ffff_ffff_ffffL; byte nybbles = 0b0010_0101; long bytes = 0b11010010_01101001_10010100_10010010;
Rules for Literals
You can place underscores only between digits; you cannot place underscores in the following places:
- At the beginning or end of a number
- Adjacent to a decimal point in a floating point literal
- Prior to an F or L suffix
- In positions where a string of digits is expected
Operators
Simple assignment operator
= Simple assignment operator
Arithmetic operators
+ Additive operator (also used for String concatenation) – Subtraction operator * Multiplication operator / Division operator % Remainder operator
Unary operators
+ Unary plus operator; indicates positive – Unary minus operator; negates an expression ++ Increment operator; increments a value by 1 -- Decrement operator; decrements a value by 1 ! Logical complement operator; inverts the value of a boolean.
Because numbers have been introduced, the above section a list of common operators. Most are common to any programming language, and a description of each is provided. The binary and bitwise operators have been omitted for brevity.
Logical Operators
Equality and relational operators
== Equal to != Not equal to > Greater than >= Greater than or equal to < Less than <= Less than or equal to
Conditional operators
&& Conditional-AND || Conditional-OR ?: Ternary (shorthand for if-then-else statement)
Type comparison operator
instanceof Compares an object to a specified type
if else Statement
The example below demonstrates the syntax for an if-else statement in Java.
1 public class IfElse { 2 3 public static void main(String args[]){ 4 long a = 1; 5 long b = 2; 6 7 if (a == b){ 8 System.out.println("True"); 9 } else { 10 System.out.println("False"); 11 } 12 13 } 14 }
The else statement provides a secondary path of execution when an if clause evaluates to false. The output from the code above is False.
switch Statement
A switch statement is used to compare the value of a variable with multiple values. For each of these values, you can define a set of statements to execute. The switch statement evaluates its expression, then executes all statements that follow the matching case label. Each break statement terminates the enclosing switch statement. The break statements are necessary because without them, statements in switch blocks fall through: All statements after the matching case label are executed in sequence, regardless of the expression of subsequent case labels, until a break statement is encountered.
1 public class SwitchStringStatement { 2 public static void main(String args[]){ 3 4 String color = "Blue"; 5 String shirt = " Shirt"; 6 7 switch (color){ 8 case "Blue": 9 shirt = "Blue" + shirt; 10 break; 11 case "Red": 12 shirt = "Red" + shirt; 13 break; 14 default: 15 shirt = "White" + shirt; 16 } 17 18 System.out.println("Shirt type: " + shirt); 19 } 20 }
In Java SE 7 and later, you can use a String object in the switch statement’s expression. The code snippet above demonstrates using Strings in the switch statement.
while Loop
The while loop performs a test and continues if the expression evaluates to true.
package com.example.review; public class WhileTest { public static void main(String args[]) { int x = 10; while (x < 20) { System.out.print("value of x : " + x); x++; System.out.print("\n"); } } }
The while statement evaluates expression, which must return a boolean value. If the expression evaluates to true, the while statement executes the statements in the while block. The while loop, shown above, iterates through an array by using a counter. The output from the example above:
value of x : 10 value of x : 11 value of x : 12 value of x : 13 value of x : 14 value of x : 15 value of x : 16 value of x : 17 value of x : 18 value of x : 19
There is also a do-while loop, where the test after the expression has run at least once. The difference between do-while and while is that do-while evaluates its expression at the bottom of the loop instead of the top.
for Loop
The for statement provides a compact way to iterate over a range of values – it repeatedly loops until a particular condition is satisfied.
1 public class ForLoop { 2 3 public static void main(String args[]){ 4 5 for (int i = 0; i < 9; i++ ){ 6 System.out.println("i: " + i); 7 } 8 9 } 10 }
A counter is initialized and incremented for each step of the for loop shown in the example above. When the condition statement evaluates to false (when i is no longer less than 9), the loop exits. Here is the sample output for this program.
i: 0 i: 1 i: 2 i: 3 i: 4 i: 5 i: 6 i: 7 i: 8
Arrays and for-each Loop
This class demonstrates how to define arrays in Java and iterate over arrays by using foreach loop.
1 public class ArrayOperations { 2 public static void main(String args[]){ 3 4 String[] names = new String[3]; 5 6 names[0] = "Blue Shirt"; 7 names[1] = "Red Shirt"; 8 names[2] = "Black Shirt"; 9 10 int[] numbers = {100, 200, 300}; 11 12 for (String name:names){ 13 System.out.println("Name: " + name); 14 } 15 16 for (int number:numbers){ 17 System.out.println("Number: " + number); 18 } 19 } 20 }
The first array, names, creates a String array and initializes each element separately. The second array, numbers is an array of integers. Each array is iterated through using the Java for-each construct. The enhanced for loop is used to make the for loop more compact and easy to read. It is used to access each successive value in a collection of values. It is commonly used to iterate over an array or a Collections class (for example, an Array or an ArrayList).The output of the class is shown here:
Name: Blue Shirt Name: Red Shirt Name: Black Shirt Number: 100 Number: 200 Number: 300
Strings
The code below demonstrates how text characters are represented in Java.
1 public class Strings { 2 3 public static void main(String args[]){ 4 5 char letter = 'a'; 6 7 String string1 = "Hello"; 8 String string2 = "World"; 9 String string3 = ""; 10 String dontDoThis = new String ("Bad Practice"); 11 12 string3 = string1 + string2; // Concatenate strings 13 14 System.out.println("Output: " + string3 + " " + letter); 15 16 } 17 }
Single characters can be represented with the char type. However, Java also includes a String type for representing multiple characters. Strings can be defined as shown above and combined by using the “+” sign as a concatenation operator.
The output from the code in the slide is:
Output: HelloWorld a
Caution: The String class is immutable: After being created, the contents of an object of the class String can never be modified. The immutability of String objects helps the JVM to reuse String objects, reducing memory overhead and improving performance.
Strings should always be initialized by using the assignment operator “=” and text in quotation marks, as shown in the examples. The use of new to initialize a String is strongly discouraged. The reason is that “Bad Practice” in line 10 is a String literal of type String. Using the new keyword simply creates another instance functionally identical to the literal. If this statement appeared inside of a loop that was frequently invoked, a lot of needless String instances could be created.
String Operations: StringBuilder
The example below demonstrates usage of the StringBufilder class and commonly used methods.
public class StringOperations { public static void main(String arg[]) { StringBuilder sb = new StringBuilder("hello"); System.out.println("string sb: " + sb); sb.append(" world"); System.out.println("string sb: " + sb); sb.append("!").append(" are").append(" you?"); System.out.println("string sb: " + sb); sb.insert(12, " How"); System.out.println("string sb: " + sb); // Get length System.out.println("Length: " + sb.length()); // Get SubString System.out.println("Sub: " + sb.substring(0, 5)); } }
StringBuilder class
The StringBuilder objects are like String objects except that they may be modified (mutable).The StringBuilder class is used when dealing with larger strings or modifying the contents of a string often.
The example above demonstrates modifying the String by using the append and insert methods and chaining by using the append method.
Output:
string sb: hello string sb: hello world string sb: hello world! are you? string sb: hello world! How are you? Length: 25 Sub: hello
A Simple Java Class: Employee
A Java class is often used to store or represent data for the construct that the class represents. For example, you could create a model (a programmatic representation) of an Employee. An Employee object defined by using this model contains values for empId, name, Social Security Number (ssn), and salary.
1 package com.example.domain; 2 public class Employee { 3 public int empId; 4 public String name; 5 public String ssn; 6 public double salary; 7 8 public Employee () { 9 } 10 11 public int getEmpId () { 12 return empId; 13 } 14 }
A constructor is used to create an instance of a class. Unlike methods, constructors do not declare a return type, and are declared with the same name as their class. Constructors can take arguments and you can declare more than one constructor.
Methods
When a class has data fields, a common practice is to provide methods for storing data (setter methods) and retrieving data (getter methods) from the fields.
1 package com.example.domain; 2 public class Employee { 3 public int empId; 4 // other fields... 5 public void setEmpId(int empId) { 6 this.empId = empId; 7 } 8 public int getEmpId() { 9 return empId; 10 } 11 // getter/setter methods for other fields... 12 }
Adding Instance Methods to the Employee Class
A common practice is to create a set of methods that manipulate field data: methods that set the value of each field, and methods that get the value of each field. These methods are called accessors (getters) and mutators (setters).
The convention is to use set and get plus the name of the field with the first letter of the field name capitalized (lower camel case). Most modern integrated development environments (IDEs) provide an easy way to automatically generate the accessor (getter) and mutator (setter) methods for you.
Notice that the set methods use the keyword this. The this keyword allows the compiler to distinguish between the field name of the class (this) and the parameter name being passed in as an argument. Without the keyword this, the net effect is that you are assigning a value to itself. (In fact, NetBeans provides a warning: “Assignment to self.”)
In this simple example, you could use the setName method to change the employee name and the setSalary method to change the employee salary.
Creating an Instance of a Class
To construct or create an instance (object) of the Employee class, use the new keyword.
/* In some other class, or a main method */ Employee emp = new Employee(); emp.empId = 101; // legal if the field is public, // but not good OO practice emp.setEmpId(101); // use a method instead emp.setName("John Smith"); emp.setSsn("011-22-3467"); emp.setSalary(120345.27);
Creating an instance of the Employee Class
- You need to allocate memory for the Employee object and call a constructor in the class to initialize all the instance variables of the class.
- To allocate memory, new operator is used and to initialize all the instance variables of the class, the constructor is invoked.
- An instance of an object is created when you use the new keyword with a constructor. All the fields declared in the class are provided with memory space and initialized to their default values.
- If the memory allocation and constructor are successful, a reference to the object is returned as a result. In the example above, the reference is assigned to a variable called emp.
- After all the data fields are set with values, you have an instance of an Employee with an empId with a value of 101, name with the string John Smith, Social Security Number string (ssn) set to 011-22-3467, and salary with the value of 120,345.27.
Constructors
A constructor is used to create an instance of a class. Constructors can take parameters. A constructor is declared with the same name as its class.
public class Employee { public Employee() { } }
Employee emp = new Employee();
Default and No-Arg Constructors
- Every class must have at least one constructor.
- If you do not provide any in a class’s declaration, the compiler creates a default constructor that takes no arguments when it’s invoked.
- The default constructor initializes the instance variables to the initial values specified in their declarations or to their default values (zero for primitive numeric types, false for boolean values, and null for references).
- If your class declares constructors, the compiler will not create a default constructor.
- In this case, you must declare a no-arg constructor if default initialization is required.
- Like a default constructor, a no-arg constructor is invoked with empty parentheses
package Statement
The package keyword is used in Java to group classes together. A package is implemented as a folder and, like a folder, provides a namespace to a class.
Packages
In Java, a package is a group of (class) types. There can be only one package declaration for a file. Packages create a namespace, a logical collection of things, like a directory hierarchy. Packages prevent name collision and also provide access control to classes. It is a good practice to always use a package declaration.
import Statements
You could refer to a class using its fully qualified namespace in your applications, as in the following example:
java.util.Date date = new java.util.Date();
But that would require a lot of typing. Instead, Java provides the import statement to allow you to declare that you want to reference a class in another package.
Notes: It is a good practice to use the specific, fully qualified package and class name to avoid confusion when there are two classes with the same name, as in the following example: java.sql.Date and java.util.Date. The first is a Date class used to store a Date type in a database, and java.util.Date is a general purpose Date class. As it turns out, java.sql.Date is a subclass of java.util.Date.
Modern IDEs, like NetBeans and Eclipse, automatically search for and add import statements for you. In NetBeans, for example, use the Ctrl + Shift + I key sequence to fix imports in your code.
Summary
The import keyword is used to identify classes you want to reference in your class. The import statement provides a convenient way to identify classes that you want to reference in your class.
import java.util.Date;
You can import a single class or an entire package:
import java.util.*;
You can include multiple import statements:
import java.util.Date; import java.util.Calendar;
It is good practice to use the full package and class name rather than the wildcard * to avoid class name conflicts.
import Statements
import statements follow the package declaration and precede the class declaration. An import statement is not required. By default, your class always imports java.lang.*. You do not need to import classes that are in the same package:
package com.example.domain; import com.example.domain.Manager; // unused import
Java Is Pass-By-Value
The Java language uses pass-by-value for all assignment operations. This means that the argument on the right side of the equal sign is evaluated, and the value of the argument is assigned to the left side of the equal sign.
To visualize this with primitives, consider the following:
int x = 3; int y = x;
The value of x is copied and passed to y. If x is later modified (for example, x = 5;), the value of y remains unchanged. For Java primitives, this is straightforward. Java does not pass a reference to a primitive (such as an integer), but rather a copy of the value.
Pass-By-Value for Object References
For Java objects, the value of the right side of an assignment is a reference to memory that stores a Java object.
Employee x = new Employee(); Employee y = x;
The reference is some address in memory.
When you assign the value of x to y, you are not creating a new Employee object, but rather a copy of the value of the reference.
Objects Passed as Parameters
4 public class ObjectPassTest { 5 public static void main(String[] args) { 6 ObjectPassTest test = new ObjectPassTest(); 7 Employee x = new Employee (); 8 x.setSalary(120_000.00); 9 test.foo(x); 10 System.out.println ("Employee salary: " 11 + x.getSalary()); 12 } 13 14 public void foo(Employee e){ 15 e.setSalary(130_000.00); 16 e = new Employee(); 17 e.setSalary(140_000.00); 18 }
On line 6, a new Employee object is created and the reference to that object is assigned to the variable x. The salary field is set to 120_000 on line 8.
On line 9, the reference to x is passed to the foo method.
Line 15 of the foo method sets the salary value of e to 130_000. Because e refers to the same reference as x, the salary value for x is now 130_000.
Line 16 creates a new Employee object that changes the reference held in e. Now x is no longer referred to in the foo method.
Line 17 set the salary field, but x is unaffected as e no longer holds a reference to x.
The output from the program is:
Employee salary: 130000.0
Garbage Collection
When an object is instantiated by using the new keyword,memory is allocated for the object. The scope of an object reference depends on where the object is instantiated:
public void someMethod() { Employee e = new Employee(); // operations on e }
When someMethod completes, the memory referenced by e is no longer accessible. Java’s garbage collector recognizes when an instance is no longer accessible and eligible for collection.
Garbage is automatically collected by the JVM. The timing of the collection depends upon many factors.