Java 2: Object Oriented Programming

From Deep Blue Robotics Wiki
Jump to: navigation, search

To fully utilize the capabilities of Java, one must first learn about Object-Oriented Programming (OOP). In the object-oriented paradigm everything is treated as an object: a collection of data with its own fields and methods. In this section, you will learn how to use the object-oriented aspects of Java and some of the more commonly used classes in the Java libraries.

Objects and Classes

Although many variables are used for basic types of data like integers, some variables are used to store objects. An object is a collection of data. It could represent a motor, a joystick, or even an entire robot. Most objects contain their own variables, and those variables can hold objects as well. For example, a Robot object could have a drivetrain variable, and the DriveTrain object stored in that variable could contain its own leftTalon and rightTalon variables.

If a variable holds an object, then the data type of the variable is that object’s class. A class is a type of object, and an object is an individual member (also known as an “instance”) of a class. For example, Talon is a class that represents Talon speed-controllers in general, but a specific Talon, such as the Talon that controls the left side of the drivetrain, would be an object. Therefore, the name of your variable would be leftTalon, the value would be the Talon object that controls the left side of the drivetrain, and the data type would be the Talon class.

A Java program just consists of various classes that the programmer writes, one of which includes a main method that will be called to start the program.

You can create a class the same way as in the Hello World lesson (right click package and select New > Class) or by selecting New > Class in the File menu.

Methods

In addition to variables, objects can also contain methods. A method is an action that an object can perform. For example, a Talon object has a set method to set the motor output to a certain value. Executing a method is also referred to as “calling” that method. Some methods require information to work. For instance, the set method needs to know what speed you want to set it to. A value that you need to input into a method is called a parameter. In this example the parameter is the desired motor speed. Some methods also have a return value. A return value is a value that the method gives back to you. Methods that do not return a value at all, such as the set method from the first example, are called void methods.

To define a method, use this format:

<return type> <name> (<parameters>) {<code>}

The return type is the data type that the method will return. The name of the method should start with a lowercase letter. The parameters look like variable declarations, with the data type followed by the name of the parameter. Multiple parameters are separated by commas. If there are no parameters, then the parentheses are just empty. To return a value from a method, write the word return followed by the value that you want to return. A class can have two methods with the same name, as long as the number or types of parameters are different, and the correct method will be called based on the arguments that it is called with. This is known as overloading a method.

Here is an example of a method:

public static void main(String[] args) {
    int a = 2;
    int b = 4;
}

double getSum(double a, double b) {
    return a+b;
}

You could overload this method by defining another method with different parameters:

double getSum(double a, double b, double c){
    return a+b+c;
}

To call a method, use this format:

<object>.<method>(<arguments>);

Arguments are the actual values given to the method. However, people often use the words argument and parameter interchangeably. Multiple arguments are separated by commas.

Here is an example of calling a method (and assigning a variable to the returned value):

 int i = object.getSum(10, 10);

Instantiation

Before you can start calling methods, you need an object to call them on. Creating an object is a process called instantiation. Instantiating an object is like calling a method with the name of the class, except prefixed with the word new. This example creates an object of the class MyClass:

 MyClass myObject = new MyClass();

A class can also have a constructor, which is like a method that is called when the object is created. A constructor is defined like a method with the same name as the class, except with no return type. Constructors can have parameters too, just like methods, and they can also be overloaded. Here is an example constructor for a class called MyClass.

MyClass() {
    // Initialization code goes here
}

Fields

Variables that belong to a specific object are called fields, or instance variables. Fields are always declared in the body of a class, outside of any methods. An object's fields can be accessed using this format: <object>.<field>

This format is similar to calling a method, except that there are no parenthesis.

To access a field from inside the same object, you can just use the name of the field (just like when using regular variables), or you can refer to the current object as this. The this keyword is useful when a parameter has the same name as a field. In this example, the parameter and the field are in different colors to help show this:

String name;

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

Variables that are declared inside methods (including the main method) are local variables, not fields, which means that they are created during each execution of the method and are deleted each time the method stops executing. If you want to store a value between method calls, you will need to use a field.

Modifiers

Modifiers are keywords that affect certain properties of a variable, method, or class. They are placed before the declaration of a variable, method, or class.

Access Modifiers

These modifiers control where certain data (fields, methods, classes, etc.) can be accessed from. The principle of hiding information is called encapsulation, and is used to protect data from being used incorrectly. In general, methods and classes are usually public and fields are usually private. There are 4 different access modifiers:

  • public - accessible anywhere
  • protected - accessible to classes in the same package, as well as subclasses (you'll learn about these later)
  • private - only accessible in that class
  • default (no modifier) - only accessible to classes in the same package

Note that classes cannot be protected or private.

Static Modifier

The static modifier indicates that a method or variable belongs to a class as a whole rather than any specific instance of the class. Static fields and methods are referred to using the name of the class rather than any particular object (like the methods in the Math class).

Final Modifier

A field that is declared to be final cannot change its value after the value is first assigned. For example, constants are often final because they never need to change their value. If a final field is declared without being assigned a value, it must be assigned a value in the constructor of the class.

There are a couple other modifiers, such as abstract and volatile, that are not listed here. They will become relevant once you learn about some more complex concepts (inheritance and threading respectively) in lesson 5.

Type Casting

Type casting is a way to convert between different data types using this format:

(<desiredDataType>)<value>

Here is an example of converting a double to an integer:

double x = 5;
int y = (int)x;

The numerical primitive types can all be type casted to each other. However, if you try to perform type casting on incompatible data types (such as a boolean and a double), you will cause your program to crash. Also note that casting between types can cause the value to change. For example, converting a double to an integer will truncate any digits after the decimal point.

There is also a way to convert Strings into other data types called parsing. This technique relies on something called a wrapper class. Although primitive types are not objects, there are special wrapper classes that can represent each primitive type as an object, such as Integer and Double. These have some helpful methods, including static methods for parsing Strings. Here are examples of converting a String to an integer and to a double:

int x = Integer.parseInt("42");
double y = Double.parseDouble("3.14");

The wrapper classes can also be used to convert a primitive type to an object. They can be instantiated with a primitive type value as a parameter. Additionally, a process called auto-boxing will automatically convert between the primitive and wrapper class forms of a value when a wrapper class variable is assigned to a primitive type value or a method that expects a wrapper class parameter is passed a primitive type value. The same process also works in reverse, although it is then called unboxing. For example, these assignments are all legal:

Integer x = new Integer(42); // x holds an Integer
Integer y = 42; // y holds an Integer
int z = new Integer(42); // z holds an int

Imports

An import statement allow code to refer to a class in another package, using just the name of the class. The syntax for importing a class uses this format:

 import <package>.<class>;

Once a class is imported, it can be used just like any other class in your code.

A wildcard import can import an entire package at once. The format for a wildcard import is:

 import <package>.*;

The Java language has numerous built in packages that you can import for use in your own programs. Here are a few commonly used Java libraries:

  • java.lang - Includes many basic Java features. Imported automatically by every Java program.
  • java.util - Contains various utility classes
  • java.io - Contains classes for inputting and outputting data
  • java.awt - Contains classes for creating graphical user interfaces (GUIs)
  • javax.swing - A newer library for creating GUIs

The Java API (Application Programming Interface) contains detailed information on all of the Java packages.

Math

The Math class contains more advanced mathematical functions. All of the methods and constants in the class are static, and the class itself does not need to be imported (because it is in java.lang).

This table contains the more commonly used methods and constants in the Math class. For a complete list of Math methods, read the Math API. All of the mathematical functions listed here will return doubles. Method/Constant Acceptable

Method/Constant Acceptable

Arguments

Mathematical

Equivalent

Description
Math.abs(a) double, int, float, long |a| returns the absolute value of a
Math.ceil(a) double Returns the lowers integer (as a double) that is greater than or equal to a
Math.ceil(1.3)=2.0
Math.ceil(1.0)=1.0
Math.floor(a) double Just like Math.ceil(a), except returns the greatest integer less than or equal to a.
Math.floor(1.3)=1.0
Math.floor(1.0)=1.0
Math.E none e An approximation of the constant e
Math.max(a,b) double, int, float, long N/A Picks and returns the greater of a and b
Math.min(a,b) double, int, float, long N/A Picks and returns the lesser of a and b
Math.PI none π An approximation of the constant π
Math.pow(a,b) double ab Uses a as the base, b as the exponent
Math.random() none N/A Generates a random double between 0 and 1
Math.round(a) double, float N/A This rounds to the nearest whole number
Math.sin(a) double sin(a) The angle is in radians. There are also methods for cosine, tangent, arcsine, arccosine, and arctangent

String

String is a class for manipulating strings of text. Note that Strings are immutable, meaning that their value cannot be changed. Although some methods seem to modify a String, they actually just return a modified copy of it.

Strings can be assigned a value directly in the same way as primitive types:

 String s = "Hello, World";

The charAt method returns the character at a given integer index (the index starts at 0, not 1).

char c1 = "012345".charAt(3); // c1 is equal to '3'
char c2 = "ABCDEF".charAt(3); // c2 is equal to 'D', not 'C'

The indexOf method returns the index of the first occurrence of a given String in the String, or -1 if the String does not occur. An optional index can be given for where in the String to start looking. The lastIndexOf method does the same thing, except starting from the end and searching backwards.

int i1 = "ABCDEABCDE".indexOf("E"); // i1 is equal to 4 
int i2 = "ABCDEABCDE".indexOf("E", 5); // i2 is equal to 9
int i3 = "ABCDEABCDE".indexOf("F"); // i3 is equal to -1
int i4 = "ABCDEABCDE".lastIndexOf("E"); // i4 is equal to 9

The substring method returns a String of all the characters from a start index to one character before the end index (so that the length of the String is the difference between the two indices). If the second index is left out, the substring will go from the first index to the end of the String.

String s1 = "DeepBlue".substring(4,8); // s1 is equal to "Blue"
String s2 = "DeepBlue".substring(4); // s2 is also equal to "Blue"

The length method returns the number of characters in the String. Note that the index of the last character will always be one less than the length, because the index starts at 0.

 int i = Hello.length(); // i is equal to 5

The replaceFirst and replaceAll methods return a String that has replaced either the first or all instances of a given String with another String.

String s1 = "abstract".replaceFirst("a", "@"); // s1 is equal to "@bstract"
String s2 = "abstract".replaceAll("a", "@"); // s1 is equal to "@bstr@ct"

Every object has its own toString method that returns a String representation of itself. However, many classes do not implement these methods very well.

int i = 42;
String s = i.toString(); // s is equal to "42"

Unlike primitive types, == does not work very well on Strings. Instead, use the equals and equalsIgnoreCase methods to see if two Strings are equivalent.

boolean b1 = "Hello".equals("Hello"); // b1 is equal to true
boolean b2 = "Hello".equalsIgnoreCase("hello"); // b2 is also equal to true

The process of adding two Strings together is called concatenation. It is done using the + operator. If a non-String is added to a String, it will automatically be converted to a String using its toString method. As a result, adding the empty String "" to something is an easy way to convert it to a String.

String s1 = "Deep" + "Blue"; // s1 is equal to "DeepBlue"
String s2 = 1 + 1; // s2 is equal to "11", not 2
String s3 = 5 + ""; // s3 is equal to "5"

For additional String methods, see the String API.

Array

An array is a data structure that can store multiple values. Each array can only hold values of one particular data type, which can either be a class or a primitive type. Their size must be specified when they are created, and can never be changed. To declare an array, use this format:

 <datatype>[] name = new <datatype>[length];

For example, this code will create an array that can hold 10 int values:

 
 int[]  myArray = new int[10];

Arrays can also be initialized with actual values by using curly braces:

 int[] myOtherArray = {1, 2, 3};

To access an element in the array, type the name of the array followed by the index of that element in square brackets. By default, all values in the array will start as zero or false (for primitive data types), or null for object data types. Array indices start at zero, not one, so if an array had a length of 10, its index would go from 0 to 9. If you access an index that doesn't exist, it will cause an error.

myArray[0] = 42;
System.out.println(myArray[0]); // Prints 42
System.out.println(myArray[9]); // Prints 0
System.out.println(myArray[10]); // Causes an error

Arrays have a final variable called length that can be used to determine the number of indices in the array.

 System.out.println(myArray.length); // Prints 10;


There is a special type of for-loop, called a for-each loop, that iterates through the elements in an array. It uses this format:

for (<datatype> <element name> : <array name>) { }
The for-loop will be called once for each element in the array. That element's value will be stored in the variable used by the for-each loop.
int[] array = {1, 2, 3};
for(int element:array) {
    System.out.println(element);
}

This can also be done using a regular for-loop, although it is more verbose. However, this approach is useful if you want to keep track of each element's index in the array.

int[] array = {1, 2, 3};
for(int i = 0; i < array.length; i++) {
    int element = array[i];
    System.out.println(element);
}

Arrays of arrays, also called multi-dimensional arrays, can be created using multiple sets of square brackets. Arrays can have any number of dimensions.

int[][] squareArray = new int[5][5];
squareArray[0][3] = 42;
int[] firstRow = squareArray[0];
System.out.println(firstRow[3]); // Prints 42

Methods can be written that take any number of parameters and automatically convert them into an array:

void method(Datatype... parameters) { }

The parameters variable in this code will be an array containing all of the arguments that were put into the method. For example, this program will add an arbitrary amount of numbers:

public void add(int... numbers) {
    int total = 0;
    for(int i:numbers) {
        total += i;
    }
    return total;
}
int sum = add(5, 10, 12, 15); // sum is equal to 42

Java also provides a number of Collection classes, such as ArrayList, HashMap, and Set, that provide additional functionality. To learn more about these classes, see the Oracle collection tutorial.

System I/O

The easiest way to communicate with your program's user is through the Eclipse output log. You have already used the System.out.println method to print out messages. To print text without creating a newline at the end, use the System.out.print method. It is also possible to print out information in a particular format, such as a specific number of digits after the decimal for a number, using the System.out.printf method. For those interested, the Oracle Tutorial has information on how to use formatting strings.

Additionally, Strings can contain escape sequences that use the backslash character to represent non-text characters such as new lines (\n) and tabs (\t), as well as characters that Strings can not normally contain, such as quotation marks (\") and backslashes (\\). For example, compare these lines of code:

System.out.println("The character '\n' will print a newline.");
System.out.println("The character \"\\n\" will print a newline.");

Only the second line will print correctly. In the first line, the compiler will think that the String ended at the quotation mark before the \n. Furthermore, the \n would print a new line rather than the characters \ and n.

To read input from the user, you can use the java.util.Scanner class. Initialize a new Scanner object with System.in as the constructor's parameter, and then use methods like nextLine to read a line of user input. The program will wait until the user enters input before moving on.

Scanner s = new Scanner(System.in);
String input = s.nextLine();


Next Lesson: WPILIB