The Complete Java Crash Course - Learn Interactively
The Complete Java Crash Course - Learn Interactively
Learn the basic structure of a Java program, while writing code to draw a smiley face.
Here is a Java program to draw a circle. We’ll dissect it in a minute. First, run
it by clicking on the Run button below the code.
class DrawCircle {
public static void main(String[] args) {
// set up a canvas for drawing:
Canvas c;
c = new Canvas(200, 200);
}
}
2. Draw the eyes. Put your code for drawing the eyes after the line
// draw the eyes .
3. Bonus challenge: draw the mouth. Hint – draw a circle, and then erase
the top part of it by drawing a yellow rectangle that covers the top of the
mouth but fits within the face. (Experiment with c.rect , which takes
four parameters.)
You can test your code with the Run button, and click on the second tab to
compare to a sample solution when you are done.
import com.educative.graphics.*;
class Smiley {
public static void main(String[] args) {
Canvas c;
c = new Canvas(200, 200);
c.draw();
}
}
Writing your own static methods
Learn to write static methods, which play a similar role to ordinary functions in other languages.
The main unit of organization in a Java program is the class. The simplest
Java program contains just one class. Among other things, a class is a
collection of methods.
There are two types of methods: static methods and non-static methods. We
will focus on static methods first, since they are simpler. A static method plays
a similar role to an ordinary function in other languages.
2. Factor the drawing code, except c.draw() , into these functions. Leave the
code c = new Canvas(200, 200); in main . The variable c will be available
to all three of these functions, since it is declared in the class, outside of
any function. This is necessary so that you can make calls to c.circle ,
etc.
3. Call your functions from main using drawOutline() , etc., to draw the
smiley. (Static methods within the same class can be called just like
functions in other languages, so no dot is required.)
SmileyFactored.java SmileyFactoredSolution.java
import com.educative.graphics.*;
class SmileyFactored {
static Canvas c;
public static void main(String[] args) {
c.draw();
}
}
3. Coding style: blank lines. Are there blank lines between your method
definitions? Do blank lines separate logical groupings in the main
method?
4. Coding style: make sure there is space around operators and after
commas.
5. All of your methods should be declared using public static void . We’ll
see shortly what these keywords mean.
Printing to the screen
• Exercise: Beatles
• String concatenation
• Special characters: printing quotes, newlines, tabs, etc.
• Exercise: translate from Python
• Formatted printing with format
print commands aren’t the most exciting thing in coding, but eventually,
you’ll want to print something out, even if only for debugging or testing your
code. You won’t find anything too surprising in Java’s methods for printing,
but there are some slight differences from C, Python, and Javascript.
You can print the text “Hello, World!” to the screen using a the method call
System.out.println("Hello, World!"); .
Why so much typing for a simple print? Frequently, method calls require an
object to act on in Java. In the method call c.circle(150, 100, 25); from the
first section, the method circle is called to draw a circle, acting on the object
referenced by c , a Canvas object that we first had to create.
System.out is also the name of an object: the main printed output device for
your program. So System.out.println calls the method println on the
System.out object.
println requires one parameter, which should be a string of text, like "Hello,
World" , or something that Java can convert to a string, like 6 . Strings are
marked by double quotes " in Java.
Exercise: Beatles #
As practice writing a complete program, write a program that prints out the
text:
Hello, hello.
I don't know why you say goodbye.
I say hello.
You’ll need a class name that matches the name of the file, a main function
(don’t forget the public static void or the required parameters), and a few
println calls. Run your code to make sure it works, and then take a look at
the solution in the second tab.
Beatles.java BeatlesSolution.java
note: The System.out.println method prints a newline after the text. Use
System.out.print if you don’t want the newline.
String concatenation #
Strings can be concatenated in Java using the + operator.
System.out.println("My name is " + "Inigo Montoya") first concatenates the
two strings, and then prints the result. As long as one of the items is a string,
the two items are converted to strings before concatenation. So
In some languages, like Python, you can use either single, double, or triple
quotes to create a string, and a clever choice will allow you to print quotes of a
different type within a string. Java doesn’t have this capability, so if you want
to print double quotes, you’ll need the code \" .
2. Python concatenates adjacent string literals. Java does not. If you want to
split the long line into multiple lines, you’ll need to concatenate several
strings, as done in the sample solution.
Sometimes, you’d like to print out a combination of text data and values, but
you’d like to keep your code clean and readable without a lot of string
concatenation. For example, maybe you’d like to print out the value of π . The
format method will let you use a format string as the first parameter, and
substitute later parameters into that string.
The %f is a format specifier marks the location where the parameter 3.14159
should be substituted. The letter f in %f indicates that the value will be a
floating point number. For an integer, use %d .
Sometimes you’d like your output to be formatted nicely. You can do things
like round the number as it is inserted, or pad the number with spaces. A
format specifier like %9.2f would print a floating point number with 2 digits
after the decimal, left-padded with spaces to take up 9 characters (including
the decimal). A few examples:
printExamples.java
class printExamples {
public static void main(String args[]) {
System.out.format("My favorite number is %.3f.\n", 3.141592654);
Java is a statically-typed language, which means that you must explicitly create each variable and tell what type of
data (for example, an integer) that variable will store before using it.
• Variable declaration
• Java variable naming convention: camel case
• Combined declaration and assignment
Here is an example of creating and using a variable that will store an integer
value:
class FortyTwo {
public static void main(String args[]) {
int meaningOfLife;
meaningOfLife = 42;
System.out.println(meaningOfLife);
}
}
Variable declaration #
The statement int meaningOfLife is called a variable declaration and it
causes Java to reserve a space in memory to hold an integer value; it names
that space meaningOfLife . In languages like Python or Javascript, you can skip
this step, but C and C++ also require variable declarations.
The structure of a variable declaration is the type of the variable ( int in this
case) followed by the name of the variable ( meaningOfLife ).
seem inconvenient, but has an advantage: if you stated the intent that
meaningOfLife be an integer, and later try to store something else in that
variable, there is an inconsistency between intent or action, a likely bug. It’s
better to catch such bugs at compile-time rather than during deployment.
class CombinedDeclarationAndAssignment {
public static void main(String args[]) {
int x = 5;
System.out.println(x);
}
}
Fractional values of numbers with `double`
Use a double to store a number that has values after the decimal point.
The int data type only represents numbers without a fractional part. What if
we want to store an approximation for π in a mathematics program? We can
use a different data type, called a double , to store numbers that have values
after the decimal point. double is short for double-precision floating point.
Floating point means that there is a decimal point that can be placed at
different locations (or float), in the number.
Declare and give initial values to variables r and pi representing the radius
of a circle, and an approximation of the mathematical constant π. Use those
values to compute and print the area of the circle. You can square a number
in Java by multiplying it by itself.
class CircleArea {
public static void main(String args[]) {
double area;
}
}
Notice from the sample solution that you can declare multiple variables of the
same type using a single line of code.
The code below will draw a smiley face on the screen, and you can use the
variables x and y to change where the smiley face is drawn. But the smiley
face is always the same size. Add a new variable, scale , that allows you to
change the size of the smiley face to make the face either larger or smaller.
For example, if scale had the value 2 , then the code would draw the smiley
face twice as large (but still centered on x and y ).
Any time you create a variable, you should first ask what type of data it will
hold, since you will need that information in order to declare the variable.
Should scale be an integer? No, not if you’d like it to hold a value like 0.5 to
make the smiley smaller.
Test your code by changing variable values a few times to draw the smiley
face at different locations at both small and large scales.
Hint: Some values should be scaled; others should not be. For example, if the x
location of the left eye is x - 20 , then the 20 should be scaled, but the x
should not be, since x will still be the x location of the center of the entire
smiley, even if the smiley is scaled.
import com.educative.graphics.*;
class BigSmile {
public static void main(String[] args) {
Canvas c;
c = new Canvas(200, 200);
int x;
int y;
x = 100;
y = 100;
}
}
Arithmetic expressions and operators
Learn how to compute expressions in Java, and how to convert between different types of data using casting. Be
careful of the difference between integer and oating-point division!
Computing values in Java works much like you’d expect from most other
languages:
class ExpressionOperand {
public static void main(String args[]) {
int x;
x = (3 * 6) + 24;
System.out.println(x);
}
}
Let’s say I have 18 cents and 5 nieces. How much money should I give to each?
With floating point division, 18/5 = 3.6, but it’s hard to distribute .6 cents in
cash, and my nieces prefer hard currency. Integer division would give the
value 3. If both operands of / are integers, Java uses integer division. If either
operand is a floating point value, then Java uses floating point division.
You can ensure floating point division by adding a decimal point and a zero:
class DivisionTypes {
public static void main(String args[]) {
System.out.println(18 / 5);
System.out.println(18.0 / 5.0);
}
}
If you want the remainder that would be left over after integer division, you
can use the modulus operator % :
Modulus.java
class Modulus {
public static void main(String args[]) {
// Three cents left over after distributing
// three pennies to each of my five nieces:
System.out.println(18 % 5);
}
}
Typecasting operators #
Sometimes, you need to force Java to convert one type of data to another. For
example, if you have two int variables and would like to divide them to get a
fractional number, you might convert those values into double values. You
can do this by typecasting the values, or casting, for short. A cast operator is
written using parentheses and the name of the target type, and precedes the
value to be cast. For example, (double) 5 yields the value 5.0 .
For now, we’ll mostly cast between numerical types. Unlike in Javascript or
Python, you cannot cast an int or double to or from a string, but must rather
use special methods of the String , Integer , or Double class.
Exercise: casting #
Use casting to print out the floating point result of dividing the value in the
variable numerator by denominator in the code below.
class Cast {
public static void main(String args[]) {
int numerator = 18;
int denominator = 5;
}
}
On the other hand, int x = 5.6 will not work. Java will notice that you are
trying to put a floating point into an int , and warn you that this may entail a
loss of precision. You can reassure Java by using a casting operator: int x =
(int) 5.6 . Notice that when casting to an integer, the part after the decimal is
truncated, not rounded, so this expression will compute the value 5, not 6.
These operators are most cleanly used like the combined assignment
operators in Python: you can replace the line of code x += 1 with x++ .
Increment.java
class Increment {
public static void main(String[] args) {
int x;
x = 5;
x += 1;
System.out.println("x = " + x);
x++;
System.out.println("x = " + x);
}
}
Preincrement.java
class Preincrement {
public static void main(String[] args) {
int x = 5;
int y = 5;
System.out.println(x++); // post-increment
System.out.println(++y); // pre-increment
Learn how to de ne methods in Java, with typed method parameters and typed return values.
• Method parameters
• Exercise: smile method
• Method overloading and method signatures
• Method return values
• Exercise: circle area method
• The main method returns void
• Exiting a program with System.exit()
Like C, Python, and Javascript functions, a method may take parameters, and
may return a single value. Of course, that single value may be a reference to a
list, an object, or an array that contains other values. All value in Java must
have a type, and method declarations must indicate the type of parameters
and the return value.
Method parameters #
Here is an example of the syntax to declare a method that takes parameters:
class MethodParameters {
}
}
Parameters are local variables of the method. In the definition of
printMyNumber(int x) , the code int x declares a new int variable, x . When
the method is called, the value 42 is copied into the variable x , and then the
code of printMyNumber is executed.
What happens if you call printMyNumber with a double value? The compiler
will notice that you are passing in a double, and that the precision of the
variable x is int. The compiler will give you an error message and halt. If you
want to round a double down and pass it in, you are welcome to use the (int)
cast: an example of explicit casting.
On the other hand, if you have a method that expects a double, you can pass
in an int. Java will notice and do the conversion for you automatically: an
implicit cast. For example:
class CastParameter {
public static void main(String[] args) {
// This works, since the int 42 can be cast
// implicitly into a double:
double x = Math.sqrt(42);
System.out.println(x);
}
Test your method by calling it a few times from main . Your main method will
need to create the canvas, and pass that canvas as well as other parameters to
drawSmile .
Smile.java Sample solution
import com.educative.graphics.*;
class Smile {
public static void main(String[] args) {
Canvas c;
c = new Canvas(200, 200);
int x;
int y;
double scale;
x = 100;
y = 100;
scale = .5;
In Java, you can write two different methods with the same name in the same
class, as long as the methods take different parameter types. Here’s an
example:
class Overload {
public static void printMyFavoriteNumber(int x) {
System.out.println("My favorite number is the integer " + x);
}
The name of a method, together with the types of its parameters in order, is
called the method signature.
The names of the parameters are not part of the method signature, so you
cannot define two methods with the same name that take the same types of
parameters, even if the parameters have different names. Why? When the
method is called, Java knows the types of the arguments being passed in, and
can use that to determine which of the overloaded methods you intended. But
Java can’t tell the names of the intended formal parameters from argument
values or types.
For similar reasons, the return type of the method, which we will see next,
cannot be used for overloading.
An example:
class ReturnExample {
public static double square(double x) {
return x * x;
}
public static boolean isEven(int x) {
return x % 2 == 0;
In the method declaration, the last word before the name of the method
indicates the type of the return value. So we can see that square returns a
double, isEven returns a boolean.
Every method must have its return type declared, even if the method has no
return value. A function for drawing a smile, for example, might not return
anything at all, so it should have a return type of void .
class CircleArea {
}
}
class HardStop {
public static void main(String[] args) {
System.out.println("Do or do not.");
System.out.println("There is no try.");
}
}
Text values with String and char
• String is a class
• The static method String.valueOf()
• Strings are objects
• Static vs non-static methods of the String class
• The char data type
• Strings are immutable in Java
A variable used to hold a string value in Java has the type String . The string
data itself, when typed in quotes in code, is called a string literal; Java should
interpret it as literal string data, and not as code.
What does the following code print? Is there an error in the code? Fix it.
Fixme.java
class Fixme {
public static void main(String args[]) {
String greeting;
greeting = "hello";
System.out.println(greeting);
System.out.println(hello);
System.out.println("greeting");
System.out.println("hello");
}
}
String is a class #
Each of the Java programs you have seen so far was defined as a single class
containing some methods. A class in Java has two purposes:
The String class serves both purposes: it provides some methods that are
useful for Strings , and it defines a String data type that you can use to make
string objects.
Let’s look at the first use first. The String class is contained somewhere in a
Java file called String.java . It contains within it several static methods. You
can call a static method of a class by using the format Classname.methodname() .
Usually, before using the static methods of a class, you need to import that
class, which we will see how to do later, but String is special and built-in.
class StringExampleOne {
public static void main(String args[]) {
String myFavoriteNumber;
int x = 42;
myFavoriteNumber = String.valueOf(x);
of each character in the string, as well as the length of the string. Some things
you can do with objects are:
3. Read or modify data from the object, using dot notation to get at instance
variables. In Java, the String method has no directly useful instance
variables, so we’ll see examples of this with other classes.
class StringsAsObjects {
public static void main(String[] args) {
String s;
s = "Rumplestiltskin";
System.out.println(s.length());
System.out.println(s.toUpperCase());
System.out.println("The character at index 5 is: " + s.charAt(5));
To access static methods of the String class, recall that you use both the name
of the class and the method name: String.valueOf(5) . You need the class
name because there might be other methods named valueOf() out there.
(Indeed, there is a class called Integer that also has a valueOf method.)
Static methods do not need access to a particular string object’s data. The
static valueOf method takes a parameter that is not a String, and creates a
String. Static methods are just like functions in Javascript, C, or Python. Java
just uses classes to organize these functions.
Non-static methods require a string as input, and instead of passing that string
as a parameter, dot-notation is used: s.toUpperCase() . It’s possible that there
might be other methods named toUpperCase out there. Java knows which
method to call because Java knows that s is a String, so Java looks in
String.java for the method.
Data types like int , double , and boolean in Java are called primitive data
types, because variables of those types are built-in, and do not have methods
available to act on them. char is also a primitive data type, representing a
single character of text.
Although the String data type is built-in, the String data type is not a
primitive: it is defined by a class, with methods and an internal representation
defined by that class.
To distinguish between String and char data, Java uses single quotes for
character literals and double quotes for Strings:
class CharExample {
public static void main(String[] args) {
char character = 'Z';
String magicWord = "XYZZY";
char anotherChar = magicWord.charAt(0);
System.out.println(character + anotherChar);
}
}
The code above prints out 178, which might surprise you. The + operator
concatenates strings, but characters are internally represented using
numbers, with a code called Unicode. Since the unicode value of ‘X’ is 88, and
the unicode value of ‘Z’ is 90, the + operator adds the two up and returns an
int .
However, you can concatenate a character to a string easily with + , since the
+ operator converts both operands to strings if one of the operands is a string.
One implication is that if you pass the reference to an object to a method, the
method may change the object. This is different than primitive types. If I pass
the value of a variable to the sqrt method, I can rest assured that the sqrt
function has no way to change that variable: the method only has the
variable’s value.
Therefore, although there is a way to get a character from a String using the
charAt() method, there is no way to change a character within a string: if you
want a variable to refer to some other string, you need to create a new string.
There’s another class in Java, StringBuffer , that is useful if you need to
efficiently manipulate character arrays. For example, you might use a
StringBuffer to store the text data if you were writing a text editor.
Arrays
Arrays in Java, like Python lists, Javascript arrays, and C arrays, store ordered values. Java arrays cannot be resized
without creating a new array and making a copy.
• Declaring arrays
• Initializing arrays: shortcut notation
• Initializing arrays with new
• The array in main (String[] args)
• The java.util.Arrays class
Java arrays, like C arrays, are more limited than their counterparts in Python
or Javascript. Java arrays cannot be resized once created, and you must
declare the type of the variables that the array will store in advance. The
ArrayList class is more flexible, and a frequent alternative to arrays, but first
let’s see how to use arrays.
class ArrayExample {
public static void main(String[] args) {
// an array of ints
int[] myNumbers = {10, 15, 20, 25, 30};
System.out.println(myNumbers[2]);
Notice that although you can determine the length of a string using the
method someString.length() , you determine the length of an array using the
instance variable someArray.length . I consider this inconsistency to be a
design flaw in Java; you’ll just have to remember it.
Declaring arrays #
Like any other variable, an array must be declared, and its type specified. The
type for an array of int values is int[] . You can think of the empty brackets
as shorthand for the word “array”:
int[] myNumbers;
This is only a declaration of the variable that will hold the array. The array
does not yet exist and so does not have a length.
int[] myNumbers;
declares the variable myNumbers , but does not yet create the array object. The
special keyword new in Java is used to create objects, including arrays.
class NewArray {
public static void main(String[] args) {
int[] myNumbers;
myNumbers = new int[5];
myNumbers[0] = 10;
myNumbers[1] = 10;
myNumbers[2] = 10;
myNumbers[3] = 10;
myNumbers[4] = 10;
wc README.txt
could be typed into a unix terminal to count the words in README.txt. The
first word, wc , is the name of the program to execute. The second word,
README.txt , is passed as a string as the first item in the array of strings, args .
ArraysExample
import java.util.Arrays;
class ArraysExample {
public static void main(String[] args) {
int[] myNumbers = {42, 1, 17, 27, 16};
Arrays.sort(myNumbers);
System.out.println(Arrays.toString(myNumbers));
}
}
Notice that Arrays.sort works in place. Also notice that there are several
overloaded toString methods that work on arrays containing ints, doubles,
and even objects. There is no reverse method; you’ll have to write your own
or use an ArrayList object to store your list of data.
Conditional and logical operators
Learn to use boolean values in Java, a necessary tool for loops and conditionals.
A boolean variable can hold either the value true or the value false .
Boolean values are quite useful when directing a program to take repeated
actions, or to take actions only under some circumstances.
Note that Java’s true and false values are written with lowercase, unlike
Python’s.
class BooleanValues {
public static void main(String[] args) {
boolean b = true;
System.out.println(b);
System.out.println(false);
}
}
A very typical coding error is to type = when you meant == : assigning a value
to a variable when you meant to test the value of that variable. Be careful –
the Java compiler will not catch this error for you:
class AssignmentError {
public static void main(String args[]) {
int x = 5;
System.out.println(x = 4);
}
}
class EvenInRange {
• Exercise: thermometer
• Exercise: I see a wall!
• Exercise: Coin ip
• else and else if statements
The keyword if can be used to run a block of code only if some condition has
the boolean value true . The syntax is like that of C or Javascript: the
conditional expression must be wrapped in parentheses, and the statements
to be executed should be in curly braces. If you are familiar with those
languages, you may wish to skip this section.
class IfExamples {
public static void main(String args[]) {
if(true) {
System.out.println("This code gets executed.");
}
if(false) {
System.out.println("This code does not.");
}
if(5 > 3) {
System.out.println("This code gets executed, too.");
}
if(3 > 5) {
System.out.println("This code does not.");
}
}
}
Exercise: thermometer #
Write an if-statement in the following code that checks if the variable
temperature has a negative value, and if so, prints out, “It’s very, very cold!”
Then change the value of temperature to ensure that nothing is printed out.
class Temperature {
The type of value that the method returns depends on the particular method.
Math.sqrt(9.0) returns a number. In the code below, you can use the method
r.blocked() , which returns a boolean value of true or false , depending on
whether or not there is a wall in front of the robot r .
In the following code, write an if-statement that prints out “I see a wall!” after
the robot drives a few steps, if there is a wall in front of the robot. Try
changing the movement commands to verify that the robot doesn’t report a
wall if there is not one.
r.forward();
r.right();
r.forward();
r.left();
}
}
Exercise: Coin ip #
The code below picks a random number that is either 0 or 1, and stores the
result in the variable n . Add some if statements so that the program randomly
prints out “Heads” or “Tails”. Run the program several times to make sure that
you eventually get both outcomes.
import java.util.Random;
class CoinFlip {
}
}
• Exercise: charge!
• Translation exercise: factor
The examples and exercises are worth working through anyway, to gain
comfort with code organization in Java. Here is a simple example of using a
while-loop to count in Java:
class WhileExample {
public static void main(String[] args) {
int number = 0;
while(number < 100) {
System.out.println(number);
number += 2;
}
}
}
Exercise: charge! #
In Java, while-loops are rarely used for counting, since for-loops provide a
briefer syntax. But while-loops are great for doing an action some unspecified
number of times until a condition changes. In the code below, write a static
method charge that causes the robot to drive forwards until it has gone either
maxDist squares or until it hits a wall, whichever is sooner.
You may call the method blocked() on the robot; blocked() returns true if
there is a wall in front of the robot, and false otherwise.
class ChargingRobotDemo {
You probably noticed that the syntax for calling charge() on a robot is
different than the syntax for calling forward() , since the robot is passed as the
first parameter to charge , rather than appearing before the dot. This is
because charge is a static method of the current class, while forward is a
method of the SimpleRobot class. We’ll see how to write non-static methods
soon.
number = 42
possible_factor = 1
while possible_factor <= number:
if number % possible_factor == 0:
print( str(possible_factor) + " is a factor of " + str(number) + "." )
possible_factor = possible_factor + 1
It would be even nicer to have a method that returns a list of factors, rather
than printing the numbers out on the screen. One way to return the list of
numbers would be to create an array; unfortunately, since we don’t know how
many factors there will be ahead of time, we’d either have to create an array
that was too large, or first count the factors. Later, we’ll see how to use an
ArrayList object that will serve as an extensible list.
for-loops
For-loops in Java are identical to those in C and Javascript, and if you are
familiar with those languages, you may skip this section. If you are most
familiar with Python, you’ll want to work through this lesson carefully. Here’s
a for-loop in Java:
ForExample.java
class ForExample {
public static void main(String[] args) {
for(int i = 1; i < 11; i++) {
System.out.println(i);
}
}
}
Python for-loops iterate over elements of a list. The for loop shown above does
not. Let’s first look at a while-loop that has a very similar intention as the
above for-loop.
class WhileExample {
public static void main(String[] args) {
int i = 1; // initialize a variable
while(i < 11) { // test a condition
System.out.println(i);
i++; // modify the variable value
}
}
}
The while-loop shows an obvious way to count by incrementing the variable
i , and the pattern is very standard. Create and initialize a variable i , test if
i satisfies some condition, execute the body, increment i , and so forth.
Here’s the basic structure in pseudocode:
init
while(condition) {
// body
modify
}
class BlastOff {
public static void main(String[] args) {
int i = 10;
while(i > 0) {
System.out.println(i);
i--;
}
System.out.println("Blast off!");
}
}
There’s a slight difference between the while-loop and the for-loop in the
sample solution. The variable i created in the initialization section of the for-
loop is in scope only for the for-loop body, and goes out of scope after the
body. On the other hand, the while-loop creates the variable i before the
loop, so i is available after the loop as well.
foreach-loops
Python for-loops loop over sequences; a list is one type of sequence. This can
be very convenient, and Java 8 introduced a similar capability, called a
foreach-loop. In spite of the name, a foreach-loop uses the keyword for . Here
is an example:
class ForEachExample {
public static void main(String[] args) {
int[] primes = {2, 3, 5, 7, 11, 13};
for(int p: primes) {
System.out.println(p);
}
}
}
The instruction before the colon creates a variable. That variable then takes
on every value in the collection after the colon. An array is a particular type
of collection; so are ArrayLists and other data structures that we will see later.
Only the value of an array item is copied into p above; changing p does not
change the array.
A class is used to de ne the custom data structure that makes up an object of that class.
• A class declares what instance variables an object of that class will contain
• Creating an object of a class
• Constructors
• The special variable this
• Exercise: Ball class
We have seen that classes are the organizational unit of a Java program.
Source code for methods is always within a class, and we might expect related
methods to be in the same class.
However, classes do much more than this, and are the heart of object-oriented
programming in Java:
class Circle {
public int x;
public int y;
public int r;
}
class CircleTest {
public static void main(String[] args) {
Circle circ; // declare a variable to store a reference to Circle object
Notice that there are two different classes defined in this file. Typically in
Java, each class would get its own file, with the name of the file
ClassName.java . So Circle might be defined in a class Circle.java . This is a
good convention and we should follow it; the classes are in the same file here
only because it is easier to read on the web page.
Also notice the keyword public before each of these instance variables. This
indicates that methods of other classes can access these variables. We’ll see
more later about the difference between public and private variables or
methods.
Circle circ;
circ = new Circle();
You can think of the reference as the address of the object in memory. So the
above code creates a new object on the heap with the code new Circle() , and
stores a referene to that object in the variable circ . Like every other variable
in Java, circ must have a type. The declaration Circle circ creates the
variable and indicates that it will store a reference to an object of type Circle .
You might notice that there is no definition for a function or method Circle()
anywhere in the code. Java creates a default constructor function for you
automatically, with the same name as the name of the class.
Constructors #
Object-oriented design drives the structure of the Java language. Classes and
objects are intended to model specialized types of data; in this case, a circle.
When you first create an object using the default constructor, space in
memory is allocated for the variables, but they are not assigned any values.
You almost always want to write your own constructor, which will let you give
initial values to instance variables. Here’s an example:
import com.educative.graphics.*;
class Circle {
public int x;
public int y;
public int r;
class CircleTest {
public static void main(String[] args) {
Circle circ; // declare a variable to store a reference to Circle object
Like in other languages, constructors are a nice place to check for good values.
For example, you might verify that the value of the radius for the circle is non-
negative, and if not, halt the program.
The special variable this #
Instance variables of an object are accessed using dot-notation, which
requires a reference to an object, a dot, and the name of the instance variable.
The job of the constructor is to initialize the instance variables of some object.
That object was just created with the command new , followed by a call to the
constructor. In order to access the instance variables, the constructor requires
a reference to that newly created object. The variable this is maintained by
Java , and contains the needed reference.
The code this.x = initX therefore takes the value of the constructor
parameter initX , 100 in this case, and stores it into the instance variable x of
the object referenced by this .
The variable this is essentially identical to the variable self in Python, and
somewhat related to the variable this in Javascript: each of these variables
stores a reference to some object, which can be used to manipulate the
instance variables of that object.
The variable this is also available in non-static method calls other than the
constructor, as we will see shortly, even though this is not an explicit
parameter to those methods.
Sometimes you will see Java code that omits the this. when accessing
instance variables. For now, I recommend that you always use this when
accessing instance variables in the constructor: the keyword makes it
extremely clear that you are accessing an instance variable, and not some
local variable or parameter to the call.
Since you will see it code written by others, here’s an example of omitting
this :
class Circle {
public int x;
public int y;
public int r;
I chose to name the first parameter to the constructor initX . Some might
choose to call that parameter x , since it will contain the value of the x
coordinate of the circle’s center. There’s nothing wrong with that choice, but if
parameters and instance variables have the same name, you cannot omit the
word this. from the assignment to the instance variable:
All of the instance variables should be declared as public, so that they may be
accessed by the drawBall method in the main BallExample class.
Read the code in main to see how your constructor should be organized.
class Ball {
// you write this part:
}
class BallExample {
public static void drawBall(Canvas canvas, Ball ball) {
canvas.fill(ball.color);
canvas.stroke("black");
canvas.circle(ball.x, ball.y, 10);
}
drawBall(c, b);
}
}
Classes contain methods
Classes contain the code for methods that act on objects; methods have access to the object using the special
variable "this".
Here is some code to create a custom Ball class that is used to store
information about a ball that will bounce on the screen. The main method of
BallExample creates a Ball object using the new keyword and a call to the
constructor. Read the code carefully now:
import com.educative.graphics.*;
class Ball {
public String color;
public int x;
public int y;
public int vx;
public int vy;
class BallExample {
public static void drawBall(Canvas canvas, Ball ball) {
canvas.fill(ball.color);
canvas.stroke("black");
canvas.circle(ball.x, ball.y, 10);
}
drawBall(c, b);
}
}
The BallExample class also has a method drawBall that accesses instance
variables of the Ball object and uses them, together with a Canvas object to
draw a circle in the right place on the screen.
Classes group together methods. It seems like the code for drawBall might
naturally be in the Ball class. Like this:
import com.educative.graphics.*;
class Ball {
public String color;
public int x;
public int y;
public int vx;
public int vy;
}
}
class BallExample {
public static void main( String args[] ) {
Canvas c = new Canvas(200, 200);
2. In the code for draw , the special instance variable this is available, and
contains a reference to the object that appeared before the dot. So this
refers to the same object that b refers to.
A class may included both static and ordinary, or non-static, methods. Related
static methods are grouped together by a class. For example, the Math class
contains the sqrt method to take square roots, and the pow method to raise a
number to a power. Neither method requires an object, but every method
must occur within a class, and the Math class is a nice place to put both of
these methods.
You can think of Java static methods as being like ordinary functions in
Python or Javascript. Java non-static methods are like methods in Python or
Javascript.
import com.educative.graphics.*;
class Ball {
public String color;
public int x;
public int y;
public int vx;
public int vy;
}
}
class BallExample {
public static void main( String args[] ) {
Canvas c = new Canvas(200, 200);
}
}
}
import com.educative.graphics.*;
class Ball {
public String color;
public int x;
public int y;
public int vx;
public int vy;
}
}
class BouncingBall {
public static void main( String args[] ) {
Canvas c = new Canvas(200, 200);
b.move();
b.bounce();
// instruct the drawing code to pause for 20 milliseconds
c.wait(20);
}
}
}
Access specifiers: public and private data and methods
Learn how to use the keywords public and private, and how to use getter and setter methods to maintain
consistent object state.
• Setter methods
• Exercise: setLocation method
• The keyword private
• Getter methods
• Exercise: methods getX , getY , getRadius
• Most instance variables should be private
• Some methods are public, and others are private
• Think hard about which methods you should make public
Instance variables of an object can be accessed using dot notation, just like in
Python, Javascript, or C++. Here’s the simple example of defining a Circle
class, which allows Circle objects to be created. Each circle object has the
instance variables x , y , and r :
class Circle {
public int x;
public int y;
public int r;
}
class CircleTest {
public static void main(String[] args) {
Circle circ;
circ = new Circle();
c.fill("yellow");
c.stroke("black");
We can access the radius of the circle with circ.r in Java, just like in Python
or Javascript, and we’ve done so in the above code.
Setter methods #
If we are not allowed to set the value of r directly from outside the Circle
class, how should we change the radius of the circle? One way of modifying
instance variables is a setter method. Such a method may be called from
outside the class, and handles the management of instance variables as
needed. For example:
class Circle {
public int x;
public int y;
public int r;
class CircleTest {
public static void main(String[] args) {
Circle circ;
circ = new Circle();
Run the above code. Then change the argument in circ.setRadius(20) to -20,
and run the code again. You’ll see that an exception is generated and the code
crashes. Good! Now the programmer knows that there is a bug and can fix it.
class Circle {
public int x;
public int y;
public int r;
class CircleExample {
public static void main(String[] args) {
Circle circ;
circ = new Circle(100, 50, 40);
c.circle(circ.x, circ.y, circ.r);
circ.setLocation(100, 125);
circ.setRadius(20);
}
}
In the sample solution, I called the methods setLocation and setRadius from
the constructor. Although this is not required, it’s nice to make use of the error
checking in setRadius when setting the initial radius using the constructor,
and if I later add new behavior to setLocation , then the constructor will make
use of it automatically.
powerful capability, and often not needed. I do not need the capability of
changing the radius of a circle to be a negative number.
Now that we have methods to set the location and radius of the circle, we
don’t ever need to write lines of code like circ.r = 20 . In fact, we’d like to
force programmers to use setRadius rather than accessing the instance
variable directly, so that we can make sure that error checking is always
performed.
So far, we have always made instance variables public . This means that any
code can access those variables with a reference to the object and dot
notation. public is called an access specifier.If we change the access specifier
to private , then only code within the Circle class can access the instance
variable. circ.r = 20 is an illegal instruction if r is a private instance
variable.
class Circle {
private int x;
private int y;
private int r;
class CircleExample {
public static void main(String[] args) {
Canvas c = new Canvas(200, 200);
c.fill("yellow");
c.stroke("black");
Circle circ;
circ = new Circle(100, 50, 40);
c.circle(circ.x, circ.y, circ.r);
circ.setLocation(100, 125);
circ.setRadius(20);
}
}
Run the above code. Notice that the compiler gives you some error messages.
Specifically, there is something wrong with the line of code c.circle(circ.x,
circ.y, circ.r); .
Aha! We used the private access specifier: we cannot modify or even use the
value of the instance variables x , y , or r from outside the class.
One way to handle this problem would be to write a method public void draw
within the Circle class, like we did for the Ball class in the previous lesson.
The draw method is inside the Ball class and has access to the instance
variables of the object referred to by this . In general, the this keyword is
the only way to access a private instance variable. (You may eventually omit
the keyword this , leaving it implied, but for now, you should use it.)
Try writing a draw method and using it to replace the code c.circle(circ.x,
circ.y, circ.r); . Make sure your draw method accepts a reference to a
Canvas object, since it will need it to call circle .
Getter methods #
What if you really want to know the radius of some Circle object from outside
of the Circle class? If the instance variables are private , and they should be,
circ.r is unavailable. One way to handle this is to write a method getRadius
that returns the value of the radius. Such a method is called a getter. Let’s do
it:
Exercise: methods getX , getY , getRadius #
Write getter methods that get the values of x , y , and r instance variables.
Notice that each of these methods returns an int , so make sure to specify that
in the method header. The body of each method should be only one line long.
class Circle {
private int x;
private int y;
private int r;
class CircleExample {
public static void main(String[] args) {
Circle circ;
circ = new Circle(100, 50, 40);
}
}
Writing getter methods may seem annoying, but you do not need to write a
getter method for every instance variable: just for the ones you want direct
access to. And in fact, getter methods have an additional features: they can
separate internal representation of data from the external view of that data.
For example, perhaps you have written a thermometer class. Internally, you
might represent the temperature using the Kelvin scale. You could write getter
methods getCelsius and getFahrenheit to do the conversions and access the
data.
The only time you might have a public instance variable is for a very small
class that packages simple values together. For example, the class
java.awt.geom.Point2D provided by Java has public x and y instance
variables. These variables represent the integer coordinates of a point and are
not restricted in any way.
Once you have created a public method, other people may use that method,
and you must always make sure that as your code evolves, that method is still
You now have the tools and techniques needed to write interesting and
complete Java programs. In the lessons of this tutorial, we’ll walk through
writing a complete falling-blocks puzzle game. To do this, you’ll need to install
a Java development environment on your computer, but first, let’s talk about
the rules of the game and some elements of how we might design the code.
The basic rules of the game are the same as for the game Tetris™; you can
easily find several browser-based implementations of Tetris with a web
search.
If a horizontal row is completely filled with blocks, that row is destroyed and
all blocks above that row fall downwards one row. The goal of the game is to
destroy as many rows as possible before the board becomes so cluttered that a
new piece cannot start falling from the top.
Code design #
Before writing a program of any interesting size, you should sit down with
pencil and paper and plan out the code design. With Java, this usually entails
mapping out what classes you’ll need and how they will work together. You
should also think about what instance variables and methods each class will
include.
Don’t implement anything yet! Work through the design carefully, and read
through the next remarks. The clearer a picture you have before you start
coding, the better it will go. I usually take a day or two to think over my plans,
and you should too.
Since there are blocks of different colors, each block should keep track of
what color it is. I created a Block class with an instance variable storing that
color.
The game board will keep track of the location of each block somehow.
Therefore, I decided that a block didn’t need an instance variable to keep
track of where it was.
That’s a lot, and it’s too much to implement all at once. For an implementation,
just putting some blocks into an array and drawing them on the screen would
be a great first step.
As usual, it’s good to work out a complete design for the Piece class, but be
flexible. When you implement a class to represent the Piece, start with
something simple. Perhaps you might start with a falling piece that is just a
single block, rather than four blocks. Then add a method to translate the
piece, maybe add the color, and a draw method.
Next steps #
Ok, with design thought through, and a tentative plan for what you might
implement first, it’s time to start coding. The next lessons will:
Install and use the tools you'll need to start writing complete Java programs on your own machine.
• Java
• Eclipse IDE
• Hello World in Eclipse
• Exercise: creating a new class
To write Java code on your own computer, rather than in the web browswer,
you’ll need a Java Development Kit (JDK) to compile and run Java code, and
some way of editing Java files.
Java #
You’ll need to download and install the JDK first; the current version is Java 9.
You can download it from the download link on Oracle’s Java page.
Eclipse IDE #
Although a standard text editor like Atom, Sublime, Notepad++, or Emacs are
fine ways to edit code, an Integrated Development Environment, or IDE for
short, provides some features that you might find useful. There are several
good IDEs available, including Eclipse, Netbeans, and Intellij IDEa. We’ll use
Eclipse.
Once you’ve added the code to Eclipse, run it using either “Run As” from the
“Run” menu, or using the small green arrow icon from the top Eclipse toolbar.
In the console at the bootom of the screen, you should see the text Hello,
world. .
The class HelloWorld is stored in its own file, HelloWorld.java . Each new class
you create will get its own file, and you can use the package explorer on the
left to move between files.
Here’s the code that I wrote to test Eclipse; notice that the Location class is in
a different file than HelloWorld . The sample code is not executable and you
should not look at it unless you are having trouble getting Eclipse to run the
code.
Explore the provided code for the Tetrominos user interface, in preparation for writing the game.
To get you started, and let you focus on practicing Java skills rather than
writing user interface code, I have written the complete Tetrominos class and
a little bit of the Board class. To use them, create a class for each using Eclipse,
and cut-and-paste the code for each class into Eclipse. The code is below in the
two tabs of the code window. Don’t worry yet about how this code works;
we’ll go over it soon.
Once you have added this code to your Eclipse project, use Eclipse to run
Tetrominos.java. You should see a window with a black background,
containing a blue rectangle.
Tetrominos.java Board.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.Timer;
class Tetrominos {
frame.getContentPane().add(board);
board.nextTurn();
}
});
frame.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
//System.out.println("key pressed " + e.getKeyCode());
if(key == KeyEvent.VK_D) {
board.rotateLeft();
} else if (key == KeyEvent.VK_G) {
board.rotateRight();
} else if (key == KeyEvent.VK_S) {
board.slide(-1);
} else if (key == KeyEvent.VK_F) {
board.slide(1);
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
});
timer.start();
}
}
Step 2: The Board class
The interesting modeling of the game will be in `Board.java` and other class les. So start reading code at
`Board.java`.
To focus on learning Java, you may reasonably ignore the Tetrominos class. It
will be the file that you run to start the program, but the Board class can be
thought of as the core of your Tetrominos program, and it’s where you’ll write
the most code. Go to Eclipse and start reading the code now.
The keyword extends and some provided code in the constructor set the
Board up as a user interface component that can be added to a window, and
you may safely ignore this code.
Each of the other existing methods in the Board class will be called in
response to certain actions, either by the user, or due to time passing.
Specifically:
paintComponent will be called any time you need to draw the blocks on
the screen.
slide , rotateLeft , and rotateRight will be called when the user presses
control keys to move the game piece. Calls to repaint() in these methods
request that paintComponent be called so that you can see the results of
the action.
So, if you put drawing code in paintComponent of the Board class, that drawing
code will be called at least once, when the main window is initially drawn.
When paintComponent is drawn, it is passed a parameter, a reference to a
Graphics object. You can draw on the component using methods of this
Graphics object.
The fillRect() method has parameters that indicate the x and y coordinates
of the upper left of the rectangle, and width in height. Go to Exlipse and
experiment with drawing a few other rectangles. Don t forget to run the
program using Tetrominos.java.
When you are done, delete all of the code in paintComponent except the first
two calls that draw a black rectangle as the background for your game.
You might notice the calls to getWidth() and getHeight() . These calls are
methods of the JComponent class, and therefore are available to call on the
this object passed into paintComponent .
Step 3: The Block class
Add a new class to represent and draw individual square blocks in the Tetrominos game.
Block.java BlockSolution.java
import java.awt.Color;
import java.awt.Graphics;
class Block {
Each block has exactly one instance variable, as we can see from the line
public int colorIndex . If the block has a colorIndex of 2, then this would
indicate that the block should be drawn using the magenta color. When a
block is created using its constructor, the index of the color of the block
should be passed in, and stored in the instance variable.
Write the body of the constructor, which should be only one line long. When
you are done, you may check your work by looking at the second tab of the
code above, BlockSolution.java .
At this point, you should have a well-organized working program that lets you
draw colored blocks on the screen. As this is a challenge project, the rest is up
to you. I recommend breaking the project down into manageable chunks,
setting some intermediate goals, and reaching those goals one at a time. There
is no hurry – take plenty of time to think through each step, and test it before
going on to the next item.
1. Create the falling pieces, which are made up of multiple blocks. I wrote a
class Piece to keep track of information for a small group of blocks.
2. Each block needs a physical location within the piece – the layout of the
piece. I created a class Location that simply stores an x, y pair. A Piece
then contains a list of locations.
3. Each Piece needs to be able to fall, so each piece needs to know where it
is on the screen. I added an instance variable position of type Location
to the Piece class. I wrote a method translate in the Piece class. To
actually make the piece fall, I had a line of code activePiece.translate(0,
-1); in the nextTurn method of the Board class. Since the nextTurn
method is called every second or so by the Tetrominos user interface, this
causes the active piece to fall downwards one step at a time.
4. The blocks should translate left and write as the user presses the s and
f keys on the keyboard. When those keys are pressed, the slide method
of Board.java is called. Finish the slide method.
5. Add rotation in response to key presses. This step is trickiest, and you
might leave it until last, since you can write a working game without it.
You’ll need to figure out how locations within a piece change on rotation.
6. Check for collisions between the falling active piece and the bottom of the
screen, and blocks that are already sitting on the bottom of the screen.
When there is a collision, copy block locations from the Piece to the Board
to represent the leftover blocks, and then create a new active piece.
7. Check for complete rows of blocks in in the board, and delete them.
What you need to know about the built-in Java user interface library to write Tetrominos.
User interface coding is an involved task. You will not need to write any user
interface code yourself for Tetrominos, since I will provide this portion for
you. However, it’s nice to know what types of things you can do with a user
interface library, and this section will give a very brief introduction.
There are several user interface libraries for Java. We will use Swing, which is
provided with Java. The user interface library handles putting windows,
buttons, menus, and other elements on the screen, and allows for user input
such as mouse motion, clicking, or key presses.
Let’s start with an example. First, create a new project with Eclipse. Call it
whatever you like; for example, SwingExamples . Create a new class, called
SwingTest. Then copy-paste the following code into SwingTest. (This code is
based on Oracle’s HelloWorldSwing example.) Do not worry too much about
the details of how the code works yet.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
The reasons invokeLater is needed are somewhat arcane, and have to do with
the interaction between Swing and the operating system. The operating
system captures events like key presses and mouse clicks from the user, and
must pass those events along to a Swing program for handling. The call to the
invokeLater method initializes Swing in such a way that it can properly
receive and handle those events. To create a new Swing program, you can
copy this main method in, without worrying about the details too much.
Creating a window #
The Swing library is built around the idea of components: items like windows,
labels, buttons, or drawing areas are created by created appropiate objects.
The first line of code executed in createAndShowGUI creates a JFrame object
representing a window on the screen. A window often has a title, shown at the
top, and the constructor sets the title of the new window to "Welcome to
Swing" .
Although the Frame is a window, a window has different parts, including the
title of the window, scrollbars, etc. frame.getContentPane() fetches the main
region of the window where custom components might be added. Then add is
called on that region to add the label to it.
Timer events #
It can be useful for a program to take a certain action every once in a while.
For example, in a game of Tetris, blocks must move down a row every 300
milliseconds or so. Swing provides the capabilities to do this, using a Timer
object. If you add the following code to the end of createAndShowGUI after the
frame has been displayed, the println method will be called every 300
milliseconds.
});
The structure of the code above relies on some Java concepts that have not
been introduced in these lessons. For now, it is enough to experiment with the
results.
Keyboard events #
It is also useful if a program can execute some piece of code every time a
particular key is pressed. In the Tetrominos game, pressing the s key should
trigger a method to be called that moves the piece to the left. Take a look at the
provided code for the Tetrominos user interface in the next section to see how
keys can be captured using a KeyListener object.
Then a Timer is created that will call the method nextTurn() of the board
class every 300 milliseconds. You’ll write the body of the nextTurn() method
later on.
Finally, keyboard input handling is set up. When the user presses one of the
keys s , d , f , or g , certain methods of the Board class will be called.