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
Introduction1.1 Introduction
1.2 What Is Java?
Compiling and Running Java2.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 Types3.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 Operators4.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
Strings5.1 Strings
5.2 Immutability
5.3 The substring() method
5.4 Testing for Equality
Program Flow6.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
Arrays7.1 Arrays
7.2 Multidimensional Arrays
Subroutines8.1 Subroutines
8.2 Methods
8.3 Method Modifiers
8.4 Returning Data
8.5 Parameters
Object Orientated Programming9.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
Exceptions10.1 Exceptions
10.2 Throwing Exceptions
10.3 Two Major Kinds of Exceptions
10.4 Checked Exceptions
10.5 Unchecked Exceptions
Advanced Object Oriented Programming11.1 Inheritance
11.2 Overriding
11.3 super
11.4 Abstract Methods
11.5 Abstract Classes
11.6 Polymorphism
Collections12.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 Ends13.1 packages
13.2 The import Statement
13.3 Wrappers for the Primitive Types
13.4 Autoboxing Primitives
Advanced Topics14.1 Garbage Collection & Memory Management
14.2 Reachable vs Unreachable Objects
14.3 Falling Out of Scope
IntroductionThis 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 WorldIn 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.)
public class HelloWorld
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
Save this text into a file named "HelloWorld.java".
Compiling HelloWorldWe use the "javac" command to compile our code. If you're working on the command line, you would type something like this:
javac HelloWorld.javaIf 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 HelloWorldNow that you've compiled our program, you can run it with the following command:
java HelloWorldNote 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 ReviewSo 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 HelloWorldLet'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:
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 CodeAlthough 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.
// 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.
int weight; // in poundsCommenting 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.
/*
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!");
}
}VariablesIn 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.
int x; // declares an integer named "x"Once it has been declared, we can
assign a value to a variable with the
= operator.
int x;
x = 8196;Primitive vs Reference TypesAs 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: intint is a primitive type. As we saw in the previous section, an
int is allocated simply by declaring it.
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: longAnother 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.
long millis = System.currentTimeMillis();The Integer Types: shortAs 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.
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: byteA
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.
byte b = 10;Real Numbers: floatfloat is used to represent floating point (real, i.e. non-integer) numbers.
float uses 4 bytes to store values up to approximately 10
38, positive or negative, with about 7 significant figures.
float PI = 3.14159;Where it would otherwise be ambiguous, you can differentiate
floats from integers in your code by appending f to numbers.
float floatingThree = 3f;Real Numbers: doubledouble is a double-sized float, which uses 8 bytes rather than 4, and can store values up to approximately 10
308, positive or negative, with about 15 significant figures. Append a
d to a number to indicate that it should be a
double.
double trouble = 99.9999d;Character data: charThe
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 '@'.
char c = 'x';char data is based on the Unicode specification, which allows it to represent the many characters of the world's languages.
booleanboolean 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.
boolean b1 = true;
boolean b2 = false;Expressions and OperatorsExpressions 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
=.
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 OperatorsJava provides the following arithmetic operators.
- addition: +
- subtraction: -
- multiplication: *
- division: /
They can be applied to any of the integer or floating point types.
int a = 1 + 1; // 2
int b = a - 1; // 1
int c = a * 2; // 4
int d = c / 2; // 2The 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.
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.
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.
int foo = 1;
int bar = --foo;
System.out.println("foo is: " + foo);
System.out.println("bar is: " + bar);This would result in:
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.
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) OperatorsThe 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.
boolean hasTail = true;
boolean fourLegs = true;
boolean isDog = hasTail && fourLegs;
// trueboolean hasTail = true;
boolean fourLegs = false;
boolean isDog = hasTail && fourLegs;
// falseThe operator
|| (double pipe) returns true only if
either or
both of its operands evaluate to true. This works like "or" in English.
boolean isCat = true;
boolean isDog = true;
boolean hasTail = isCat || isDog;
// trueboolean isCat = true;
boolean isDog = false;
boolean hasTail = isCat || isDog;
// trueboolean isCat = false;
boolean isDog = true;
boolean hasTail = isCat || isDog;
// trueboolean isCat = false;
boolean isDog = false;
boolean hasTail = isCat || isDog;
// falseThe operator ! (exclamation point) returns the
reverse its operand.
boolean isCat = false;
boolean isDog = ! isCat;
// trueboolean isCat = true;
boolean isDog = ! isCat;
// falseStringsStrings 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:
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 EqualityRemember, strings are objects, not primitive types. If you want to compare two strings to see if they are equivalent, you must use
equals().
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:
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 StructuresJava 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 StatementThe
if statement is the most basic means of control in Java.
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:
if (x < 10) {
System.out.println("x is less than 10");
} else {
System.out.println("x is NOT less than 10");
}The while StatementThe
while statement is used to execute a block of code until a particular condition is met.
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 StatementA
while loop can be used in conjunction with a
do statement, so that the test for continuing the loop comes
after the statement.
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 LoopA
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.
for (int i = 0; i < 10; i++)
{
System.out.println(i is: " + i);
}The for Loop Test ExpressionThe 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 ExpressionThe 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.
for (int i = 9; i >= 0; i--)
{
System.out.println("i is: " + i);
}The break StatementThe
break statement is used to interrupt loops such as
for and
while.
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 StatementThe
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.
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 StatementThe
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.
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;
}ArraysAn 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.
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.
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.
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.
String[] stringArray = new String[10];
for (int i = 0; i < stringArray.length; i++)
{
String s = "String number " + i;
stringArray[i] = s;
}Multidimensional ArraysJava supports multidimensional arrays- that is arrays of arrays.
You declare a multidimensional array by appending pairs of
[] brackets to the declaration:
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 2
nd 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.
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.
data[0][0] = 5;
data[1][2] = 9;
data[4][0] = -42;SubroutinesAs 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 JavaWe'll use the following example method
sumValues to explain how methods are defined.
public int sumValues(int[] values)
{
int result;
for (int i = 0; i < values.length; i++)
{
result = result + values[i];
}
return result;
}Method ModifiersThe
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 DataThe keyword
int indicates that this method returns an integer as its result. That means that this method can be used in an expression:
int sum = sumValues(values);Returning Data: voidIf 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.
public void printValues(int[] values)
{
for (int i = 0; i < values.length; i++)
{
int val = values[i];
System.out.println(val);
}
}ParametersA 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.
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 ProgrammingObject-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.
ClassesClasses 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.
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 ObjectsNow that we have a minimally defined class, we can create instances of it with the
new keyword.
Employee emp1 = new Employee();
Employee emp2 = new Employee();This creates two new objects, each with its own
name and
salaryInDollars fields.
nullIn 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:
Employee emp = getEmployee("John Doe");
if (emp != null)
{
// do something with emp...
}Instance VariablesClass 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.
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.
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.
AcessorsIn 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.
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.
Employee emp1 = new Employee();
emp1setName("John Smith");
emp1.setSalaryInDollars(32000);
Employee emp2 = new Employee();
emp2.setName("JD Rockefeller");
emp2.setSalaryInDollars(500000);ConstructorsAlthough 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.
public Employee(String name)
{
this.name = name;
}Now we can create
Employee objects and initialize the
name field at the same time.
Employee emp1 = new Employee("John Smith");
Employee emp2 = new Employee("JD Rockefeller");The Default ConstructorIf 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.
// constructor with "name" initializer
public Employee(String name)
{
this.name = name;
}
// our own "default" constructor
public Employee()
{
this.name = "John Doe";
}The "this" ReferenceIn 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.
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.
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 MethodsJust 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.
/**
* 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;
}InterfacesAn
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
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:
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 InterfacesSo 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.
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 InterfacesA 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.
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 BExceptionsAn 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.
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 ExceptionsYou can of course also throw your own exceptions.
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 ExceptionsJava 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 ExceptionIf 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.
public void myMethod()
{
try {
// do stuff that might throw an IOException
} catch (IOException exception) {
System.error.println("Oops, caught an exception.");
}
}- OR -
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 ExceptionsAn 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: InheritanceInheritance, 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.
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 PetSince
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.
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.
Dog spot = new Dog();
spot.setName("Spot"); // from Pet
spot.setColor("black"); // from Pet
spot.setBreed("Scottie"); // from DogOverridingSubclasses 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.
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 MethodsWe'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.
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.
public abstract void speak();Abstract ClassesSince 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.
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().
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!");
}
}PolymorphismPolymorphism 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.
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.
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.
Trainer trainer = new Trainer();
Dog dog = new Dog();
Cat cat = new Cat();
trainer.trainPet(dog); // prints Woof!
trainer.trainPet(cat); // prints Meow!CollectionsJava 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:
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 - ListThe
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().
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).
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 InterfaceThe
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:
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().
// 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 implementationHashMap 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 - genericsOne 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:
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.
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:
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:
public Collection<Employee> getEmployees()
{
// ect...
}You can also use generics to enforce type safety of the arguments passed into your methods:
public void myMethod(Collection<Employee> employees
{
// ect...
}This ensures that your method will only be called with a collection of
Employee objects.
PackagesAlthought 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.
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.
ImportsIn 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:
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.
import com.example.widgets.Widget;
import java.util.*;
// ect...
Widget widget = new Widget();
List list = new ArrayList();Wrappers for Primitive TypesEarlier 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.
ArrayList<Integer> list = new ArrayList<Integer>();
int anInt = 42;
Integer i = Integer.valueOf(anInt);
list.add(i);Autoboxing PrimitivesThis 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:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(42); // 42 is automatically converted to an Integer objectWhat'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:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(42);
int i = list.get(0); // Integer automatically converted to intGarbage CollectionIn 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 UnreachableSo 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 ReferenceA reference can be removed by setting the referencing value to null:
Dog dog = new Dog();
dog.setName("Spot");
dog = null;The reference can also be removed by setting the reference variable to another object:
Dog dog = new Dog();
dog.setName("Spot");
dog = new Dog(); // reference to "Spot" is now lost
dog.setName("Rex");Falling Out of ScopeAnother 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.
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!!!