Author Topic: Intro to Java  (Read 92 times)

Keyani

  • Respect
  • Administrator
  • Newbie
  • ***
  • Posts: 48
  • Thanked +2/-0
  • Location: Belgium
    • View Profile
Intro to Java
« on: July 07, 2011, 06:12:21 pm »
Off Topic: I did not make this tutorial "keyani", i got this from rune-server but it helpt me alot so i hope it helps you aswel.
Credits to The Wanderer.
he got it from a book on his iphone.

Table of Contents
Introduction

1.1 Introduction
1.2 What Is Java?

Compiling and Running Java
2.1 Hello World
2.2 Compiling HelloWorld
2.3 Running HelloWorld
2.4 Review
2.5 Dissecting HelloWorld
2.6 Commenting Code

Variables and Data Types
3.1 Variables
3.2 Data Types: Primitive and Reference
3.3 Integers: int, long, short and byte
3.4 Real Numbers: float and double
3.5 Character Data: char
3.6 boolean

Expressions and Operators
4.1 Expressions Intro
4.2 Assignment Operators
4.3 Arithmetic Operators
4.4 Increment/Decrement
4.5 Equality and Relational Operators
4.6 Conditional (Boolean) Operators

Strings
5.1 Strings
5.2 Immutability
5.3 The substring() method
5.4 Testing for Equality

Program Flow
6.1 Control Structures
6.2 if
6.3 while
6.4 do/while
6.5 for loop
6.6 break
6.7 continue
6.8 switch

Arrays
7.1 Arrays
7.2 Multidimensional Arrays

Subroutines
8.1 Subroutines
8.2 Methods
8.3 Method Modifiers
8.4 Returning Data
8.5 Parameters

Object Orientated Programming
9.1 Object Oriented Programming
9.2 Classes
9.3 null
9.4 Instance Variables
9.5 Class Variables
9.6 Accessors: getters and setters
9.7 Constructors
9.8 "this"
9.9 Class Methods (static methods)
9.10 Interfaces
9.11 Implementing Multiple Interfaces

Exceptions
10.1 Exceptions
10.2 Throwing Exceptions
10.3 Two Major Kinds of Exceptions
10.4 Checked Exceptions
10.5 Unchecked Exceptions

Advanced Object Oriented Programming
11.1 Inheritance
11.2 Overriding
11.3 super
11.4 Abstract Methods
11.5 Abstract Classes
11.6 Polymorphism

Collections
12.1 Collections
12.2 List
12.3 ArrayList
12.4 LinkedList
12.5 Set
12.6 Map
12.7 HashMap
12.8 Generics

Odds and Ends
13.1 packages
13.2 The import Statement
13.3 Wrappers for the Primitive Types
13.4 Autoboxing Primitives

Advanced Topics
14.1 Garbage Collection & Memory Management
14.2 Reachable vs Unreachable Objects
14.3 Falling Out of Scope


Introduction
This guide is a basic introduction to programming in the Java Language. While suitable for any beginner,  it is primarily intended for the Freshman-level Computer Science students, or for High School AP Computer Science class students. A basic familiarity with computers is assumed.

We will cover the basics of compiling and running Java programs on the command line, but we will not cover IDEs (Integrated Development Environments) such as Exclipse or Netbeans.

In general, it's best to use whatever programming environment your instructor recommends, since much can depend on the software available at your school.


What is Java?
Java is a high-level, object-oriented programming language. Java source code is compiled into byte code, which then runs in a Java Virtual Machine or JVM.

The JVM interprets the byte code. It is the JVM that allows Java code to run on almost any computer or operating system, from cellphones, to PCs, to supercomputers.

Java includes an immense set of libraries and APIs, but this guide will focus only on the language basics as typically used in an introductory Computer Science programming class.




Hello World
In programming language documentation it is traditional to start with a very simple program, the simplest way possible to print the words "Hello World!" to the screen.

(Please excuse my conventions as it won't let me use the tab key for some odd reason.)
Code: [Select]
public class HelloWorld
{
      public static void main(String[] args)
      {
            System.out.println("Hello World!");
      }
}

Save this text into a file named "HelloWorld.java".


Compiling HelloWorld
We use the "javac" command to compile our code. If you're working on the command line, you would type something like this:

Code: [Select]
javac HelloWorld.java
If all is well, it will run without printing anything, and you should end up with a HelloWorld.class file in your directory.

If you get any error messages, verify that you have typed everything in correctly and saved any changes before trying to compile again.


Running HelloWorld
Now that you've compiled our program, you can run it with the following command:

Code: [Select]
java HelloWorld
Note that the command we're using is "java", without the "c" at the end, and the argument is "HelloWorld" without the ".java" after it.

When you run it, you should see the program print "Hello World!" to your screen.


HelloWorld Review
So what have we actually accomplished here?

After creating our program in a text editor, we compiled it. The compiler translated out textual program into byte code, storing the results into a file called HelloWorld.class.

Then we ran the program in the Java Virtual Machine. The JVM read in the byte code from HelloWorld.class, interpreted the instructions generated by the compiler, which resulted in the words "Hello World!" being printed to our screen.

Make sure you are able to compile and run HelloWorld in your environment before continuing.


Dissecting HelloWorld
Let's dissect HelloWorld line by line.



public class HelloWorld declared the name of the class to be HelloWorld. Later we'll discuss in more detail what a class is, but for now you can consider it to be a kind of container for your code.

The class name must match the name of your .java file.



public static void main is a special method that serves as an entry point when running your program.

When the JVM starts up, it loads the class file that was specified and looks for a method named "main".

Any class may declare such a method, which then allows it to be the starting point when the program runs.



String[] args declares that the main method takes an array of String arguments. This allows you to get access to whatever arguments were specified to your program (if any) when it was launched by the user.

For example, the following code will print out whatever name the user typed when the program was launched:

Code: [Select]
public static void main(String[] args)
{
      String username = args[0];
      System.out.println("Hello " + username);
}



System.out.println is a method that prints a line of text.

To be more precise, System is a Java class that contains a PrintStream object named out.

So this line of code simply calls the println method of out, with the String that we pass in as an argument.


Commenting Code
Although programs are written for the computer to execute, we still need a way to make them understandable by humans.

Java has two ways to include comments in your programs- lines of text that are ignored by the compiler, but are helpful to people reading the code.


Commenting Code- //
The compiler will ignore any text that comes after two forward slashes- //, until the end of that line.

Code: [Select]
// A program to print a simple
// message to the screen.
//
public class HelloWorld
{
      public static void main(String[] args)
      {
            System.out.println("Hello World!");
      }
}

You can also include comments on the same line as program code.

Code: [Select]
int weight; // in pounds

Commenting Code- /* */
Another way to add comments to code is to place them between /* and */. This style of commenting allows comments to be placed anywhere, even on multiple lines.

Code: [Select]
/*
      A program to print a simple
      message to the screen.
*/
public class HelloWorld
{
      /* main entry point */
      public static void main(String[] args)
      {
            System.out.println("Hello world!");
      }
}




Variables
In programming, we use the term variable to indicate a named piece of computer memory which we use to store (and manipulate) data.

Before a variable can be used, it and its type must be declared.

Code: [Select]
int x; // declares an integer named "x"
Once it has been declared, we can assign a value to a variable with the = operator.

Code: [Select]
int x;
x = 8196;


Primitive vs Reference Types
As you might expect, in Java we have different types to represent different types of data.

There are two main kinds of data in Java- primitive types and reference types.

Reference types are things such as Objects and Arrays, which need to be created dynamically with the "new" keyword. We will cover reference types later.

Primitives in Java are built-in types that are automatically allocated, and are passed by value, rather than reference.


The Integer Types: int
int is a primitive type. As we saw in the previous section, an int is allocated simply by declaring it.

Code: [Select]
int weight;
In Java, an int is represented in your computer's memory with 4 bytes, or 32 bits.

This means that int is big enough to hold values from -2,147,483,648 to 2,147,483,647.

int is a good default choice for representing integer numbers in Java.


The Integer Types: long
Another integer type is long. long is composed of 8 bytes (64 bits), and is large enough to hold values ranging from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.

Use long only when you need to store data that is out of range for int.

Code: [Select]
long millis = System.currentTimeMillis();

The Integer Types: short
As its name implies, short is composed of only 2 bytes (16 bits), and is large enough to hold values ranging from -32,768 to 32,767.

Code: [Select]
short numStudents = 156;
Use short only when you are sure that your values will fit in the range -32,768 to 32,767.


The Integer Types: byte
A byte in Java represents a single byte (8 bits). It can hold integer values from -128 to 127.

Arrays of bytes are often used to hold low-level data, such as pixel color data for images, or audio bytes from an mp3 file.

Code: [Select]
byte b = 10;

Real Numbers: float
float is used to represent floating point (real, i.e. non-integer) numbers.

float uses 4 bytes to store values up to approximately 1038, positive or negative, with about 7 significant figures.

Code: [Select]
float PI = 3.14159;
Where it would otherwise be ambiguous, you can differentiate floats from integers in your code by appending f to numbers.

Code: [Select]
float floatingThree = 3f;

Real Numbers: double
double is a double-sized float, which uses 8 bytes rather than 4, and can store values up to approximately 10308, positive or negative, with about 15 significant figures. Append a d to a number to indicate that it should be a double.

Code: [Select]
double trouble = 99.9999d;

Character data: char
The char primitive is used for character data. A char holds a single character of data, such as the letter 'A', or the number '0', or the symbol '@'.

Code: [Select]
char c = 'x';
char data is based on the Unicode specification, which allows it to represent the many characters of the world's languages.


boolean
boolean can hold boolean data- true or false.

Note also the true and false keywords. You must spell them as indicated, all lowercase or they will not be recognized by the compiler.

Code: [Select]
boolean b1 = true;
boolean b2 = false;




Expressions and Operators
Expressions are statements that represent or calculate a value. The value, or result of an expression can be assigned to a variable or passed in as an argument to a method.

Using operators, expressions can be combined to produce even more complicated expressions.

You have already seen the most basic expression- assignment, which is accomplished with the assignment operator =.

Code: [Select]
int x = 5;      // declare x and
                    // initialize it to 5

int y = x;      // assign value of x to y

// calculate run-time
long duration = System.currentTimeMillis() - startTime;



It's very important to distinguish a single =, which denotes assignment, from the double ==, which tests for equality.

Many hours of frustration have been wasted by programmers mistyping these operators.


Arithmetic Operators
Java provides the following arithmetic operators.


  • addition: +
  • subtraction: -
  • multiplication: *
  • division: /
They can be applied to any of the integer or floating point types.

Code: [Select]
int a = 1 + 1;    // 2
int b = a - 1;     // 1
int c = a * 2;     // 4
int d = c / 2;     // 2


The Increment Operator: ++
The increment operator ++ increments the value of its operand, and returns the result. The operator may appear before or after the variable.

It if appears before the variable, it is known as a pre-increment, and the increment happens before the assignment.

Code: [Select]
int foo = 0;
int bar = ++foo;

System.out.println("foo is: " + foo);
System.out.println("bar is: " + bar);

This would result in:



The Increment Operator: ++
If it appears after the variable, it is known as a post-increment, and the increment happens after the assignment.

Code: [Select]
int foo = 0;
int bar = foo++;

System.out.println("foo is: " + foo);
System.out.println("bar is: " + bar);

This would result in:



The Decrement Operator: --
The decrement operator -- has a pre and post form, and behaves similarly.

Code: [Select]
int foo = 1;
int bar = --foo;

System.out.println("foo is: " + foo);
System.out.println("bar is: " + bar);

This would result in:


Code: [Select]
int foo = 1;
int bar = foo--;

System.out.println("foo is: " + foo);
System.out.println("bar is: " + bar);

This would result in:



[size=10pt10pt]Equality and Relational Operators[/size]
The equality and relational operators are used for comparing two values.



Code: [Select]
x == y // is x equal to y?
x != y  // is x NOT equal to y?
x > y   // is x greater than y?
x >= y // is x greater than OR equal to y?
x < y   // is x less than y?
x <= y // is x less than OR equal to y?


Conditional (Boolean) Operators
The conditional operators are used for forming logical expressions, much in the same way "and", "or" and "not" are used in English.

In Java, the operator && (double ampersand) returns true only if both of its operands evaluate to true. This works like "and" in English.

Code: [Select]
boolean hasTail = true;
boolean fourLegs = true;
boolean isDog = hasTail && fourLegs;
// true

Code: [Select]
boolean hasTail = true;
boolean fourLegs = false;
boolean isDog = hasTail && fourLegs;
// false

The operator || (double pipe) returns true only if  either or both of its operands evaluate to true. This works like "or" in English.

Code: [Select]
boolean isCat = true;
boolean isDog = true;
boolean hasTail = isCat || isDog;
// true

Code: [Select]
boolean isCat = true;
boolean isDog = false;
boolean hasTail = isCat || isDog;
// true

Code: [Select]
boolean isCat = false;
boolean isDog = true;
boolean hasTail = isCat || isDog;
// true

Code: [Select]
boolean isCat = false;
boolean isDog = false;
boolean hasTail = isCat || isDog;
// false

The operator ! (exclamation point) returns the reverse its operand.

Code: [Select]
boolean isCat = false;
boolean isDog = ! isCat;
// true

Code: [Select]
boolean isCat = true;
boolean isDog = ! isCat;
// false




Strings
Strings are simply strings of characters. Strings are objects, as opposed to the primitive types that we have been working with thus far.

You define a String in Java simply by enclosing it between double quote characters, like "Hello".

Be sure to use the double-quote character " for your strings, not ', and not `, else the compiler will complain and your program will not run.

The String class is actually java.lang.String, meaning that it is a class that is part of the java.lang package.

Strings are immutable in Java. This means that once they are created, they cannot be modified in any way. While this may seem like a hindrance, it actually makes the language safer and easier to program.

You can always create a new String by appending two existing strings together with the + operator, or by taking their substring:

Code: [Select]
String fullName = "Robert Smith";
String firstName = fullName.substring(0, 6);
String message = "Hello " + firstName;
System.out.println(message);

This would result in:


Note: since Strings are immutable, the + operator always returns a new String; it does not modify either of its arguments. This is a common stumbling block for beginners, so watch out for it.

In Java, Strings are zero-based, meaning that the first character is always at position 0. (In Computer Science we always start consider zero to be the "first" number... this may take some getting used to, but it is very standard).

The substring method takes two integer arguments, and returns a new String that is created starting at the offset indicated by the first argument, and ending just before the second argument.


Testing Strings for Equality
Remember, strings are objects, not primitive types. If you want to compare two strings to see if they are equivalent, you must use equals().

Code: [Select]
public boolean testStringEquality(String s1, String s2)
{
      return s1.equals(s2);
}

Using == is incorrect, as it will only test if the two strings point to the same object:

Code: [Select]
public boolean areSameObject(String s1, String s2)
{
      return s1 == s2;
}

This is a very common mistake, so make sure you understand the difference.




Program Flow: Control Structures
Java provides several statements that control the flow of your program, allowing for loops, branches (changing the flow based on a logic decision) and conditional execution.


  • if
  • while
  • do/while
  • for
  • break
  • continue
  • switch



Control Structures: The if Statement
The if statement is the most basic means of control in Java.

Code: [Select]
if (x < 10)   {
      System.out.println("x is less than 10");
}

If x is less than 10, the println is executed. if may also be followed by an else clause:

Code: [Select]
if (x < 10)   {
      System.out.println("x is less than 10");
} else {
      System.out.println("x is NOT less than 10");
}


The while Statement
The while statement is used to execute a block of code until a particular condition is met.

Code: [Select]
int i = o;

while (i < 10)
{
      System.out.println("i is: " + i);
      i = i + i;
}

This code will print the numbers 0 through 9, inclusive.


The do/while Statement
A while loop can be used in conjunction with a do statement, so that the test for continuing the loop comes after the statement.

Code: [Select]
int i = 0;

do
{
      System.out.println("i is: " + i);
      i++;
}
while (i < 10);

This syntax is useful because it forces the loop to execute at least once, since the test comes after the println statement.


The for Loop
A for loop is similar to the while loop, but it has a terser syntax that allows you to specify the initializer, the test for loop continuation, and the incrementing expression all in one line of code.

Code: [Select]
for (int i = 0; i < 10; i++)
{
      System.out.println(i is: " + i);
}


The for Loop Test Expression


The second part of the for loop is called the loop test expression.

This test is executed priot to each iteration of the loop. When this statement evaluates to false, the loop terminates.


The for Loop Increment Expression


The third part of the for loop is called the increment expression. This statement is executed after each iteration of the loop.

You can put any statement here, but it is typical to make this statement increment a counting index, which is also used by the loop test expression.

You can also loop down rather than up.

Code: [Select]
for (int i = 9; i >= 0; i--)
{
      System.out.println("i is: " + i);
}


The break Statement
The break statement is used to interrupt loops such as for and while.

Code: [Select]
int[] numbers = {
      0, -2, 10, 42, 100, -4, 39, 20, 23, 89
      };

// assume we don't have 10 unless/until
// we find it
//
boolean hasTen = false;

// iterate over the numbers array
//
for (int i = 0; i < numbers.length; i++)
{
      if (numbers[i] == 10)  { // we found it
            hasTen = true;
            break; //jump out of the
                       //for() loop early
      }
}


The continue Statement
The continue statement is used to skip the current iteration of a loop. It causes the program to return to the beginning of the loop without executing the rest of the statements in the loop.

Code: [Select]
File[] files = getListOfFilesToCopy();
long MAXLENGTH = 8192;

for (int i = 0; i < files.length; i++)
{
      File file= files[i];
     
      // don't copy files that are
      // larger than MAXLENGTH bytes

      if (files.length() > MAXLENGTH) continue;

      copyFile(file);
}

This code will iterate of a list of files to copy. If a file is greater than MAXLENGTH the file is skipped.


The switch Statement
The switch statement is similar to a group of if/else/else statements.

switch takes an argument that is either a byte, short, char, or int and executes the case statement that is equal to the argument.

Code: [Select]
in coinValue = 10;
String coinName;

switch (coinValue)  {
      case 1:
            coinName = "penny";
            break;
     
      case 5:
            coinName = "nickel";
            break;

      case 10:
            coinName = "dime";
            break;

      case 25:
            coinName = "quarter";
            break;

      default:
            coinName = "no such coin";
            break;
}




Arrays
An array is a data structure which holds a fixed number of elements. The length of the array is specified when the array is created.

As with most things in Computer Science, array indices start at zero, not one.


All of the values in an array must be of the same type. You cannot add a String to an array of int.

There is one exception to this rule- for arrays that hold references, all of the references must have an ancestral type or interface that is the same type as the array.

For example, an array of type Object could hold any object, since all objects descend from Object. But don't worry about this just yet.

Arrays are created with the new keyword.

Code: [Select]
int[] data = new int[10];
This statement creates an array called data with space for ten integers.

We can then access individual elements of the array with the [] brackets.

Code: [Select]
data[0] = 50;
data[2] = -7;
data[3] = data[0] + data[1];

We can use the .length member of the array to get its length.

Code: [Select]
for (int i = 0; i < data.length; i++)
{
      data[i] = i;
}

Note that when we created the array of ints we didn't need to new the individual integers; the creation of the array itself also created the space for our 10 ints.

This is the case for all primitive types- creating the array also creates the primitives.

For non-primitive types (i.e. objects), this is not the case; we must create the array and then assign slots in the array to particular objects.

Let's add some strings to an array.

Code: [Select]
String[] stringArray = new String[10];

for (int i = 0; i < stringArray.length; i++)
{
      String s = "String number " + i;
      stringArray[i] = s;
}


Multidimensional Arrays
Java supports multidimensional arrays- that is arrays of arrays.

You declare a multidimensional array by appending pairs of [] brackets to the declaration:

Code: [Select]
int twoDimensions[][] = new int[5][];
This allocates a two-dimensional array. It declares a variable named twoDimensions, which is an array of size 5, of type "array of int".

The size of the 2nd dimension of the arrays has not been specified.

While twoDimensions has been allocated, thanks to new, the individual elements of that array have not. We can create them with a for loop.

Code: [Select]
for (int i = 0; i < twoDimensions.length; i++)
{
      twoDimensions[i] = new int[3];
}

The end result is a 5 x 3 matrix of integers.


When primitive types are created in an array, they are always initialized to their type's default value.

int's default value is zero, so every element of our multi-dimensional array starts off initialized to zero.


To access the values in a multi-dimensional array, we add an index value for each dimension inside of the brackets.

Code: [Select]
data[0][0] = 5;
data[1][2] = 9;
data[4][0] = -42;


Subroutines
As a program grows in size and complexity, it's helpful to keep it organized by breaking it up into smaller pieces. One unit of organization is known as the subroutine. A subroutine is a block of statements gathered together and given a name, such as "computeSalesTax", or "renderWebPage".

A subroutine can declare parameters, which are values that are passed into the routine when it is called.

A subroutine can also return a value to the caller. In this way, subroutines can be used in expressions.

Subroutines are also known as functions, in procedural languages, or as methods in object-oriented languages (such as Java). We will refer to them as methods from here on.


Defining Methods in Java
We'll use the following example method sumValues to explain how methods are defined.

Code: [Select]
public int sumValues(int[] values)
{
      int result;

      for (int i = 0; i < values.length; i++)
      {
            result = result + values[i];
      }

      return result;
}


Method Modifiers


The public keyword at the beginning of this method is known as a modifier. Other modifiers are private, protected, static and final. We will explain these modifiers in a later chapter on object-oriented programming


Returning Data


The keyword int indicates that this method returns an integer as its result. That means that this method can be used in an expression:

Code: [Select]
int sum = sumValues(values);

Returning Data: void
If we don't want to return any data from a method, we set the return type to the special keyword void.

The following method prints the values, but does not return any kind of result to the caller.

Code: [Select]
public void printValues(int[] values)
{

      for (int i = 0; i < values.length; i++)
      {
            int val = values[i];
            System.out.println(val);
      }

}


Parameters
A method can specify parameters that the caller must pass in when calling the method. These parameters are declared in the parenthesis immediately following the name of the method.



sumValues takes an array of int as its sole parameter.

Multiple parameters of varying types can be specified inside the parenthesis, separated by commas.

Code: [Select]
public void printReport(String title, String[] stocks, float[] quotes)
{
      System.out.println(title);

      for (int i = 0; i < stocks.length; i++)
      {
            String stockName = stocks[i];
            float stockQuote = quotes[i];
            System.out.println(stockName + " : " + quote);
      }

}

The printReport method accepts three parameters- a report title, an array of Strings for the stocks, and an array of floats for the stock quotes.




Object-Oriented Programming
Object-Oriented Programming is a technique that uses "objects"- containers that hold both data and the methods that operate upon them.

An object-oriented program can be considered a group of interacting objects, rather than merely a collection of subroutines spread out over various files.

This is a very powerful abstraction. It allows us to manage our program's complexity by encapsulating code and data into classes.


Classes
Classes are types that are defined by you as a programmer.

A class defines the properties and behaviors of a class of objects. When you create an object, you are creating an instance of a particular class.

Classes provide a way to encapsulate the state and actions of an abstract entity.

When you design a class, what you're really doing is defining a kind of recipe for how to make objects. You only define a particular class once (the recipe), but you can have infinitely many objects that are instances of that class.

Let's build a class to represent Employee objects. We'd like an Employee to have a name, as well as a salary, specified in dollars.

Code: [Select]
public class Employee
{
      private String name;
      private int salaryInDollars;
}

The private modifier indicates that the name and salaryInDollars fields can only be accessed by the class itself (so a hypothetical Boss class could not change them directly.)


Creating Objects
Now that we have a minimally defined class, we can create instances of it with the new keyword.

Code: [Select]
Employee emp1 = new Employee();
Employee emp2 = new Employee();

This creates two new objects, each with its own name and salaryInDollars fields.


null
In Java, the constant null is used to represent a void reference. That is, a pointer to nothing.

We use null when we want to indicate that a variable no longer points to a valid object.

We can also test for null before attempting to use an object:

Code: [Select]
Employee emp = getEmployee("John Doe");

if (emp != null)
{
      // do something with emp...
}


Instance Variables
Class fields are also known more formally as instance variables. They are so-called because these variables are created for each instance (object) of a class.

If you create two Employee objects, you will have implicitly created private name and salaryInDollars fields for each of the two employees.

Code: [Select]
public class Employee
{
      private String name;
      private int salaryInDollars;
}


Class Variables
While instance variables are created for each object, class variables are created only once per-class. Class variables are indicated by marking a field with the static qualifier.

Code: [Select]
public Class Employee
{
      private static int count;
      private String name;
      private int salaryInDollars;

      // ect...
}

Each Employee object will contain a reference to a single count field.

You should be careful with class variables, as they are effectively global inside a given class. This is frequently a source of bugs in multi-threaded programs.


Acessors
In addition to simple fields, a class may define methods to manipulate the object's state, or perform other useful work.

Since the name and salaryInDollars fields are private in Employee, this class is not terribly useful.

We'll need to provide some methods to get and set them. These are known as accessors, or simply getters and setters.

Code: [Select]
public class Employee
{
      private String name;
      private int salaryInDollars;

      public void setName(String name)
      {
            this.name = name;
      }

      public String getName()
      {
            return name;
      }

      public void setSalaryInDollars(int salaryInDollars)
      {
            this.salaryInDollars = salaryInDollars;
      }

      public int getSalaryInDollars()
      {
            return salaryInDollars;
      }
}

We can now manipulate the fields of our Employee objects via the accessor methods.

Code: [Select]
Employee emp1 = new Employee();
emp1setName("John Smith");
emp1.setSalaryInDollars(32000);

Employee emp2 = new Employee();
emp2.setName("JD Rockefeller");
emp2.setSalaryInDollars(500000);


Constructors
Although we now have a setter method for setting the name, it might be helpful to set the name field right from the start when our object is constructed. To do this, we need to create a new method known as a constructor.

A constructor is a method that has the same name as the class, and no given return type. This is the method that is actually invoked when you use the new keyword.

A constructor typically has parameters that can be used to initialize the fields of the class.

Code: [Select]
public Employee(String name)
{
      this.name = name;
}

Now we can create Employee objects and initialize the name field at the same time.

Code: [Select]
Employee emp1 = new Employee("John Smith");
Employee emp2 = new Employee("JD Rockefeller");


The Default Constructor
If you create a class and fail to provide a constructor, Java automatically creates a default constructor for you. That's why we were able to say "new Employee()" before we added our own constructor.

However, once you create your own constructor, the default (no-argument) constructor goes away. You can of course create multiple constructors, if you think that makes the class easier to use.

Code: [Select]
// constructor with "name" initializer
public Employee(String name)
{
      this.name = name;
}

// our own "default" constructor
public Employee()
{
      this.name = "John Doe";
}


The "this" Reference
In any piece of Java code you can use the this reference to refer to the current object, i.e. the current instance of the class to which the code belongs.

Code: [Select]
public Employee(String name)
{
      this.name = name;
}

Why is this needed? It's used to disambiguate situations when a parameter of a method has the same name as a field in the class.

For example, in the following code, there is a parameter called "name", as well as a field called "name".

The name parameter is said to hide the name field.

Code: [Select]
public class Employee
{
      private String name;

      public void setName(String name)
      {
            this.name = name;
      }

}

Without "this.name", our field would never get initialized. Watch out for this, as it's a common source of bugs!


Class Methods
Just as we saw that we could create class fields that belong to the class rather than any particular object, we can also create class methods.

A class method is a method with a static modifier. Class methods can be invoked directly on the class; there is no need to have an instance of the class.

Class methods cannot refer to any data belonging to objects of the class (i.e. there is no "this" reference). They can however refer to class variables (i.e. static fields).

Class methods are often used as utility methods (i.e. code that is more procedural than object-oriented), or for various design patterns.

One common pattern is the Factory pattern. A Factory is used to create and manage instances of a class.

Code: [Select]
/**
 * creates a new Employee and increments
 * the global count of employees.
 */
public static Employee createEmployee()
{
      // create a new Employee object
      Employee result = new Employee();

      count++    // keep a count of the
                       // number of employees
                       // we have created

      // return the result from the "factory"
      return result;
}


Interfaces
An interface is a kind of contract for a class. It declares the kinds of methods that a class must implement in order to conform to a particular use case.

A class that contains all of the methods declared in an interface is said to implement that interface.

The implementation can then be used as a kind of "black box"- the client code knows nothing of the details of the class, other than the fact that it conforms to the interface the client is interested in.

This is a very powerful way to achieve modularity (keeping code in small, coherent units), and to keep classes decoupled (so they don't know too much about each other).

As an example, let's consider how we might design an interface for a television remote control.

A simple remote contorl would need to provide the following features:


  • on/off toggle
  • channel up/down methods
  • ability to enter
channel numbers directly for "direct access" to channels


Code: [Select]
public interface RemoteControl
{
      void powerOnOff();
      void channelUp();
      void channelDown();
      void gotoChannel(int channel);
}

So now that we've defined the RemoteControl interface, how do we go about implementing it? We simply create a class that provides each of the methods in the interface, and add "implements RemoteControl to the class declaration:

Code: [Select]
public class RemoteControlImpl implements Remote Control
{
      public void powerOnOff()
      {
            // code to power on off
      }

      public void channelUp()
      {
            // code to increment current channel
      }

      public void channelDown()
      {
            // code to decrement current channel
      }

      public void gotoChannel(int channel)
      {
            // code to go to specific channel
      }
}


Using Interfaces
So how does client code use a RemoteControl interface?

Well-designed client code will refer solely to the methods defined in the interface, and remain ignorant of the details (such as the class name of the actual implementation).

As an example, let's consider a hypothetical class that models a Student. To keep the Student code decoupled from our RemoteControlImpl, we'll simply declare the student constructor to accept a class that implements RemoteControl as a parameter.

Code: [Select]
public class Student
{
      private RemoteControl remote;

      public Student(RemoteControl remote)
      {
            this.remote = remote;
      }

      public void watchTv()
      {
            if (! homeworkDone())
            {
                  throw new Runtime Exception("do homework!");
            }
            else
            {
                  remote.powerOnOff();

                  // watch cartoon network
                  remote.gotoChannel(35);
             }
      }
}

Our Student class remains totally decoupled from RemoteControlImpl (or any other implementation), since it only refers to the methods defined in the interface.


Implementing Multiple Interfaces
A class is free to implement more than one interface at a time. Just separate the interface names with commas, and include code that implements the required methods from each of the interfaces.

This is a handy way to mitigate the fact that Java does not support multiple inheritance- you can't derive a class from more than one superclass, but you can implement more than one interface.

Code: [Select]
public interface A {
      public void aMethod();
}

public interface B {
      public void bMethod();
}

public class A_and_B_Impl implements A, B
{
      public void aMethod()
      {
      }
     
      public void bMethod()
      {
      }
}
A class that implements two interfaces, A and B




Exceptions
An exception is an event that disrupts the normal execution flow of a program.

When an error occurs, an exception object is created and then "thrown". The calling code must then "catch" the exception in order to handle it.

Code: [Select]
String input;

try {

      input = readUserInput();

} catch (IOException exception)      {

     System.err.println("error !");

}

In this code, the println method is only executed if an IOException is thrown when reading the user's input.


Throwing Exceptions
You can of course also throw your own exceptions.

Code: [Select]
public int setAge(int age) {

      // verify user input
      if (age < 0)
      {
            throw new IllegalArgumentException("age must be positive");
      }

      // ect...
}

Exceptions are a great way to validate parameters or other program state. Instead of producing bad output from bad input, you can throw an exception to indicate that something went wrong.


Checked and Unchecked Exceptions
Java has two major classes of exception: checked and unchecked. Checked exceptions are exceptions that you must explicitly handle or declare in your methods. Unchecked exceptions need not be explicitly handled or declared.

IOException is an example of a checked exception; this exception is frequently used by classes in the java.io package to signal a problem reading or writing data.

NullPointerException is an example of an unchecked exception; this exception is thrown whenever code tries to use a variable that is invalid; i.e. it is set to null. As a new Java programmer, you will become very familiar with this exception.


Checked Exception
If code that you call in your method throws a checked exception, you must have a catch block that handles the exception, or else you must declare the exception in the method signature with the throws keyword.

Code: [Select]
public void myMethod()
{
      try {
            // do stuff that might throw an IOException
      } catch (IOException exception) {
            System.error.println("Oops, caught an exception.");
      }
}
- OR -
Code: [Select]
public void myMethod() throws IOException
{
      // do stuff that might throw an IOException
}

The throws keyword means that this method might throw an IOException, and any code that calls it must explicitly handle this error, either with a catch or another throws.

Checked exceptions are typically used for recoverable errors, such as bad user input (for example, you could ask the user to re-enter the data.)

It will be obvious when you fail to catch or declare a throws for a checked exception, because the compiler will print an error when you try to compile your code.


Unchecked Exceptions
An unchecked exception does not require you to explicitly catch it. Unchecked exceptions descend from RuntimeException or Error.

Unchecked exceptions are typically used for non-recoverable errors, such as trying to access an array beyond its physical size, or the JVM running out of memory.

It would be tedious to have to explicitly handle every such exception, and furthermore when an unchecked exception is thrown, you generally want the program to print an error message and exit.

What happens when you don't catch an unchecked exception?

The exception is said to "bubble up" the callstack. What this means is that if your method fails to catch the exception, the method that called your method will see the thrown exception. If that method doesn't handle it, the method that called that method will see the thrown exception, and so on.

The exception bubbles up until it is either caught, or it reaches the top, where the Java Virtual Machine catches it, print a stacktrace, and exits.




Advanced Object-Oriented Programming: Inheritance
Inheritance, or extending an existing class to create a new one, is one of the most powerful abstractions in object-oriented programming.

Inheritance allows you to inherit variables and methods from other classes. When you extend a class in this way, it is referred to as subclassing. The new class is called the subclass, and the existing (parent) class is called the super-class.

For example, let's consider how we might model family pets.

We'll start with a base class called Pet (base is another word for parent/super-class).


In our base class we include only properties found in all Pets... let's choose name and color, since these are attributes present in all pets.

Code: [Select]
public class Pet
{
      protected String name;
      protected String color;

      public void setName(String name)
      {
            this.name = name;
      }

      public String getName()
      {
            return name;
      }

      public void setColor(String color)
      {
            this.color = color;
       }

      public String getColor()
      {
            return color;
       }
}

Now let's create a class Dog that will extend Pet


Since Dog extends Pet, we can say that dog has an "isa" relationship with Pet, since a Dog is a Pet. It inherits both its attributes and its behavior from Pet.

We'll add a new propoerty breed, along with a getter and setter for it to our Dog class.

Code: [Select]
public class Dog extends Pet
{
      protected String breed;

      public void setBreed(String breed)
      {
            this.breed = breed;
       }

       public String getBreed()
       {
             return breed;
        }
}

Dog inherits both its attributes and its behavior from Pet.

Code: [Select]
Dog spot = new Dog();
spot.setName("Spot");      // from Pet
spot.setColor("black");      // from Pet
spot.setBreed("Scottie");  // from Dog


Overriding
Subclasses can provide methods with the exact same signature as methods in their parent class. This is known as overriding.

If we wanted to replace the behavior of setName() in the parent class, we can simply provide our own setName() implementation in Dog.

Code: [Select]
public class Dog extends Pet
{
     public void setName(String name)
     {
           System.out.println("dog name set to " + name);
           // call original setName() in parent class
           super.setName(name);
      }
}

The original setName() is still available in the parent class, and we can call it as super.setName().


Abstract Methods
We'd like all of our pets to be able to speak, so let's introduce a new method speak() in the base class.

We want speak() to be supported by all Pets, but we want it to perform the correct "speaking" behavior that is appropriate for each individual subclass. For example, a dog might bark, a cat might meow, ect.

We could certainly add an empty speak() method to Pet, and hope that subclasses would override it with the proper behavior.

Code: [Select]
public void speak()
{
      // to be filled in by subclasses
}

A better way is to introduce an abstract method.

An abstract method is really just an empty method. That is, a method signature with no corresponding definition.

It defines a kind of interface that subclasses must implement. In fact this is very much like an interface.

Code: [Select]
public abstract void speak();

Abstract Classes
Since Pet now contains an abstract method, the class itself must be declared as abstract. We do this by adding the abstract keyword to its declaration.

Code: [Select]
public abstract class Pet
{
      // ect...

      public abstract void speak();
}

This means that Pet is now an abstract class- it cannot be instantiated (i.e. created) directly. You can no longer say "new Pet()" because the speak() method is undefined.

Any non-abstract subclass must provide an implementation of the speak() method, with a signature to match its parent.

Here is the updated Dog class with its implementation of speak().

Code: [Select]
public class Dog extends Pet
{
      protected String breed;

      public void setBreed(String breed)
      {
            this.breed = breed;
      }

      public String getBreed()
      {
            return breed;
      }

      public void speak()
      {
            System.out.println("Woof!");
      }
}


Polymorphism
Polymorphism is a feature of object-oriented programming languages that lets you refer to various types by a common interface.

Let's assume we have created a Cat class that also extends Pet. Polymorphism lets us refer to instances of Dogs and Cats simply as Pets, regardless of the specific type of Pet.


Let's create our Cat subclass.

Code: [Select]
public class Cat extends Pet
{
      public void speak()
      {
            System.out.println("Meow!");
      }
}

As you can see from the code, the only change that Cat introduces is to implement the abstract method speak().

Now that we have two Pet subtypes- Dog and Cat, we can create another class Trainer, that can train pets.

Code: [Select]
public class Trainer
{
      public void trainPet(Pet pet)
      {
            pet.speak();
      }
}

The trainPet() method takes a Pet argument. The actual object passed into the method may be a Cat, a Dog, or some other Pet subclass.

The trainer class doesn't care what the actual type is, because it's only going to use the speak() method.

It's polymorphism that lets us interact with the Pet in the same manner, whether it's a dog or a cat or something else.

Code: [Select]
Trainer trainer = new Trainer();
Dog dog = new Dog();
Cat cat = new Cat();

trainer.trainPet(dog); // prints Woof!
trainer.trainPet(cat);  // prints Meow!




Collections
Java includes an extremely useful set of classes known as the Collections API. It defines a set of both interfaces and implementations of many common data structures, such as List, Set, Queue, Tree and Map.

The Collections API is a very powerful tool to have in any Java programmer's toolset.

Simply put, a Collection is a group of objects. Java defines the Collection interface from which all the other interfaces (LinkedList, ArrayList, HashSet, ect.) inherit.

Given a Collection object, without knowing anything else about its implementation, we can iterate over its contents:

Code: [Select]
public void printCollection(Collection c)
{
      for (Object o : c)
      {
            System.out.println(o);
      }
}

Note the special for loop syntax we're using to iterate over the collection. This is more concise than the earlier for loop code we have seen, and helps make the code easier to read.


Collections - List
The List interface is an extension of Collection. It's still an interface- meaning it's only a specification of how a class behaves; it does not actually implement that behavior.

But it adds an important distinction on top of the collection- the elements in a List have a specific order. In addition to maintaining this ordering during iteration, List provides a method to access specific objects by their index: get().

Code: [Select]
public void printFifthObject(List list)
{
      Object fifthObject = list.get(5);
      System.out.println(fifthObject);
}

As we said previously, a List is an interface. Let's talk about some List implementations.

ArrayList is a resizable List implementation. It's similar to an array, in that you can access elements directly by index, but it also grows in size dynamically to hold as many objects as you wish to add to it (subject of course to the memory constraints of your computer).

Code: [Select]
public List readAllInput()
{
      ArrayList lines = new ArrayList();
      String line;
      while ((line = readLine()) != null)
      {
            lines.add(line);
      }

      return lines;
}

LinkedList is a List that is implemented internally as a doubly-linked list.

From the user's perspective (that is, you) it looks pretty much like an ArrayList. But operations that would normally be slow in an array, (such as inserting an element at the beginning of a long list) run quickly, because the new element can be spliced in easily without having to move every element in the array forward.

A LinkedList is a good choice if you need to insert or remove data often, especially if you need to insert/remove from the middle rather than from the beginning or end of the list.

It would be a poor choice if you needed to access specific elements by index often, as that involves traversing the list for each get().


Collections - the Set Interface
The Set interface models the mathematical concept of a set. It is used to model collections where the same object (or its equivalent) can appear at most once in the collection. In other words- there can be no duplicate items.

HashSet is an implementation of the Set interface. Let's use it to compute the union of two sets:

Code: [Select]
public Set computeUnion(Set s1, Set s2)
{
      HashSet union = new HashSet()
      union.addAll(s1);
      union.addAll(s2);
      return union;
}


[size=v]Collection - the Map Interface[/size]
The Map interface maps keys to values. Similar to Set, Map cannot contain duplicate keys. (It's fine to include duplicate values, however).

The two principal methods in the Map interface are put() and get().

Code: [Select]
// create a map
Map favorites = new HashMap();

// enter some key -> value mappings
//
favorites.add("color", "blue");
favorites.add("flavor", "chocolate");
favorites.add("movie", "Star Wars");

// retrieve them by key
//
String favColor = (String) favorites.get("color");

String favFlavor = (String) favorites.get("flavor");

String favMovie = (Stirng) favorites.get("movie");


Collections - HashMap Map implementation
HashMap is an implementation of the Map interface using a HashTable. A HashTable uses what's known as a hash value on the key in order to figure out which "bucket" to store the associated data.

This results in a data structure that is very fast for inserts and lookups, typically O (1). That makes HashMap a very good choice for situations where you need to quickly insert and access data, but don't care about the insertion order.


Collections - generics
One problem with using the Collections API is that, by itself, it doesn't specify much information about the kinds of objects a collection might contain. Consider the following:

Code: [Select]
Collection c = getEmployees();
What does this collection contain?

It might contain a collection of Employee objects, or maybe Department objects, or maybe Cats, or maybe even all of the above.

The point is that we know it contains objects, but we know nothing more than that about the kind of objects it contains. It is helpful in programming (and especially in debugging) if we can know a little more about what a Collection contains.

We can better specify what our collection contains by using what is known as "generics". Generics provides a way for you to specify the type of object a collection contains.

Code: [Select]
Collection<Employee> c;
This declares that c can only contain Employee objects (or sub-classes of Employee). If we instead wanted a Collection of Strings, we would declare it like this:

Code: [Select]
Collection<String> c;
Use generics whenever possible; it will make your code easier to read as well as debug.

Our getEmployees() method will also need to be updated to reflect the fact that we are returning a collection of Employee objects:

Code: [Select]
public Collection<Employee> getEmployees()
{
      // ect...
}

You can also use generics to enforce type safety of the arguments passed into your methods:

Code: [Select]
public void myMethod(Collection<Employee> employees
{
      // ect...
}

This ensures that your method will only be called with a collection of Employee objects.


Packages
Althought we have not used it in our example code thus far, Java supports (and in fact encourages) you to put your code into packages. You may have already seen examples of this keyword at the top of Java source code files.

Code: [Select]
package com.example.widgets;

public class Widget
{
      // ect...
}

In this example, the Widget class is in the com.example.widgets package.

It's common practice to use your web site's domain name in reverse. For example, if your company web site is www.example.com, your base package would be com.example.

Packages help to keep code organized and also precent name collision. If you have a Widget, you'll want to put it into a package so that it does not conflict with any other Widget classes from libraries you may be using.

Code that does not specify a package goes into the default package, which offers no naming collision protection.

Classes must be kept in a directory structure that matches their packaging. So our Widget class, belonging to the com.example package, would be kept in com/example/widgets/Widget.java.

This is a common source of errors for new Java programmers, so most of the examples in this guide do not specify a package. Once you have the basics of Java down, you are strongly encouraged to put your code into packages.


Imports
In order to use code that is kept in a package, we must specify the full package path. For example, code that uses our Widget in the com.example package would look like this:

Code: [Select]
com.example.Widget widget = new com.example.Widget();
This quickly becomes tedious, so Java provides the import statement as a kind of shorthand. import statements go at the top of your class file (after the package statement, if there is one) to import any commonly used classes.

Code: [Select]
import com.example.widgets.Widget;
import java.util.*;

// ect...
Widget widget = new Widget();
List list = new ArrayList();


Wrappers for Primitive Types
Earlier in this guide we mentioned that the primitive types- short, int, long, float, double, byte and char are not really objects. This presents a problem with many of the Java APIs since they usually operate on objects, not primitives.

For example how would you add an int to an ArrayList, which can only add objects?

The solution is to use Wrapper types. Each of the primitive types has a corresponding Wrapper class.

Code: [Select]
ArrayList<Integer> list = new ArrayList<Integer>();

int anInt = 42;
Integer i = Integer.valueOf(anInt);
list.add(i);


Autoboxing Primitives
This may seem like a lot of work just to store an integer. In Java 5, a new feature called autoboxing was introduced.

Autoboxing allows you to write code as if your primitives were already objects:

Code: [Select]
ArrayList<Integer> list = new ArrayList<Integer>();

list.add(42); // 42 is automatically converted to an Integer object

What's happening is that behind the scenes, the Java compiler is automatically converting your code to use wrapper objects.

The inverse operation also works as expected:

Code: [Select]
ArrayList<Integer> list = new ArrayList<Integer>();

list.add(42);

int i = list.get(0); // Integer automatically converted to int




Garbage Collection
In the earlier chapters we discussed creating objects with new, but we did not cover how those objects are disposed of. In Java this is handled automatically for you by the JVM. It's known as garbage collection.

The JVM keeps track of every object that is created on the heap (that is, everything you create via new).

Every so often, the JVM will pause and perform a garbage collection sweep. When the JVM determines than an object is no longer "reachable" from anywhere in your code, the object is deleted and its associated memory is returned to the pool.

Garbage Collection may not seem like a big deal if you haven't worked in lower-level languages such as C or C++ that do not support garbage collection.

Keeping track of memory manually is very error-prone, and probably the most common source of bugs in non-GC languages.


Reachable vs Unreachable
So what makes objects "unreachable"? As long as your program contains a reference to the object, either directly, or indirectly via another object, that object is considered reachable.

When you no longer have a reference to an object, it is considered unreachable, and becomes a candidate for garbage collection.

A reference can be removed (thus creating a candidate for garbage collection) in two ways:


  • by setting the reference variable to null, or to some other object
  • by having the referencing variable fall out of scope



Removing a Reference
A reference can be removed by setting the referencing value to null:

Code: [Select]
Dog dog = new Dog();
dog.setName("Spot");
dog = null;

The reference can also be removed by setting the reference variable to another object:

Code: [Select]
Dog dog = new Dog();
dog.setName("Spot");
dog = new Dog();      // reference to "Spot" is now lost

dog.setName("Rex");


Falling Out of Scope
Another way to remove a reference is to have it implicitly fall out of scope. That is, the method or block of code in which the object was created returns, without returning a reference to the created object.

Code: [Select]
public void createTemporaryDog()
{
      Dog dog = new Dog();
      dog.setName("Spot");
      // ect...

      // method returns
}

Since there is no longer any reference to dog after createTemporaryDog returns, dog is now unreachable, and will eventually be garbage collected.



Hope you learned as much as I did!!!

« Last Edit: July 07, 2011, 06:17:21 pm by Keyani »

Share on Bluesky Share on Facebook


Tom

  • Administrator
  • Newbie
  • ***
  • Posts: 12
  • Thanked +0/-0
    • View Profile
Re: Intro to Java
« Reply #1 on: July 07, 2011, 07:05:12 pm »
You're posting some great info here, thanks!

Hayden

  • Forum Owner
  • Administrator
  • Member
  • ***
  • Posts: 77
  • Thanked +7/-0
    • View Profile
Re: Intro to Java
« Reply #2 on: July 08, 2011, 12:53:08 pm »
Stickied. Well done.