











Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Material Type: Notes; Professor: Thornton; Class: Fund Software Dsgn; Subject: Computing and Information Sciences; University: Kansas State University; Term: Spring 2010;
Typology: Study notes
1 / 19
This page cannot be seen from the preview
Don't miss anything!












Motivation for Classes We can write some fairly complicated programs in a single main method, and we can do just about anything using a bunch of static methods in a single file. However, there is a lot more to programming than just getting it to work – we also want to be able to easily reuse pieces of our code, and for our programs to be easy for other people to read. This requires us to think about good design for our programs instead of just functionality.
Program Design Computer programmers almost always work in teams, which means it is vital that all team members can use and understand code written by others in the group. If you think about how a big program (like a popular computer game) would look if it was written in a single file...it would be a nightmare to read. Programs like that tend to have millions of lines of code – it would be very difficult to ever find what you were after.
It is much easier to read code that is divided into many files and many methods by functionality. That way, you could go directly to the section of code you were interested in without having to wade through everything else. When each method solves a small piece of the problem, and each file holds a group of methods that do related things, it’s very easy to figure out what’s going on.
New Data Types Creating programs with multiple classes also gives us the option to create new specialized data types. Later in this chapter, we will see how to classes into data types, complete with their own fields (pieces of relevant information) and methods to operate on those fields. For example, we will be able to create a Rectangle type that store the width and height for the rectangle, and that has area and perimeter methods that operate on the width and height.
Class Syntax with Static Methods We have already seen how to write several methods within one class. Now, we will learn how to create several classes with different methods. This section will not discuss how to create objects (instances of classes) – for now, we’re just dividing methods into different files as an organization trick.
Example: Separate Class with Static Methods Suppose we want to create a lot of methods that perform mathematical operations (average, round, max, min, etc.). It would be nice to be able to reuse these methods in other projects, so we will want to divide them into a separate class. (Actually, there is a Math class in the Java libraries that contains these methods, but we will create our own.)
Creating a separate class with static methods is exactly like the classes we’ve written in the past
//stored in the file MathOps.java public class MathOps {
//assumes arr has at least one element public static int max(int[] arr) { int m = arr[0]; for (int i = 1; i < arr.length; i++) { if (arr[i] > m) m = arr[i]; }
return m; }
//assumes arr has at least one element public static int min(int[] arr) { int m = arr[0]; for (int i = 1; i < arr.length; i++) { if (arr[i] < m) m = arr[i]; }
return m;
}
public static int round(double num) { if ((int)(num+0.5) > (int) num) { //num must have decimal of .5 or higher //round up return (int)(num+0.5); } else { //round down return (int)num; } }
public static double avg(int[] arr) { int sum = 0; for (int i = 0; i < arr.length; i++) { sum += arr[i]; }
//need to cast to a double to avoid integer division
Objects In this section, we will learn to make classes into our own specialized data types – complete with data fields and methods that operate on the data.
General Class Syntax In the previous section, we looked at a specific kind of class – classes that have only static methods. However, very few classes in Java are written with entirely static methods. In this section, we will explore a more generic definition of a class. These generic classes in Java are made up of three parts:
Here is the format of a general class (note that our classes with static methods also fit this syntax
public class Name { //declare instance variables
//constructor
//methods }
For now, each class should be stored in a separate file. The name of the file should match the name of the class (including capitalization), plus the “.java” extension. For example, the class above should be stored in the file Name.java.
Visibility Modifiers The three parts of a class (instance variables, constructor, methods) should be preceded by a visibility modifier. This specifies where that variable, constructor, or method can be seen. There are three visibility modifiers:
Instance Variables Again, instance variables are special variables that can be used throughout the class. They are defined at the beginning of the class, using the following format:
visibility type name;
For example:
private int size;
Like typical variables, instance variables can also be initialized on the same line as their declaration. For example:
private int size = 0;
However, initialization of instance variables in usually done in the constructor.
Constructor The constructor is a special method that initializes the instance variables in a class. It must have the same name as the class. It can either take values for the instance variables as parameters , or it can assign default values. Here’s the format of a constructor:
public Name(params) { //initialize instance variables }
Here, Name is the name of the class, and params are possible parameters to the constructor. Here is a sample class with a constructor:
public class Dog { //instance variables private String name; public String breed;
//constructor public Dog() { name = “Fido”; breed = “Mutt”; } }
When the constructor is called, the name and breed are set to default values. We could also accept initial values for the name and breed as parameters to the constructor:
public Dog(String n, String b) { name = n; breed = b; }
objectName.variableName
For example, here’s how we would print the breed of both dogs:
System.out.println(d1.breed); System.out.println(d2.breed);
This would print:
Mutt Labrador
Non-Static Methods Non-static methods in Java are fairly similar to the static methods we already know about. The difference is that non-static methods are associated with an object of a given class type, not with the class itself. This means that we can call a method for each of our object variables, and that the method will use that object’s instance variables in its calculations. (This is not always true, but we’ll pretend for now.) Here’s the format of a method:
visibility returnType name(args) { //code //possible return statement }
Let’s talk about each part separately. The visibility can be either public or private, depending on whether we want to call the method outside this class. (It can later be protected as well.) The returnType specifies what type of value will be returned. If the method doesn’t return anything, its return type is void. name is just the name of the method, which you will use when calling this method. args are optional arguments (parameters) for the method.
If a method has a non-void return type, it must have a return statement. This looks like:
return value/variable;
where that value or variable has the same type as returnType.
Here’s a very simple method that just prints “Hello, World!” to the screen:
public void greeting() { System.out.println(“Hello, World!”); }
Method Arguments
Method arguments (parameters) are just values passed to the method. Each method can have zero or many arguments. Here’s what the argument list should look like:
type1 name1, type2 name2, ...
If a method has no arguments, you still need to include the () after the method name (like the greeting method above). Here’s an example of a method that takes two ints, and prints their product to the screen:
public void printProduct(int num1, int num2) { int product = num1num2; System.out.println(“The product is “ + product); }*
Returning a Value So far, we’ve only looked at methods that have a void return type – that don’t return anything. Here’s a method that returns something:
public int product (int num1, int num2) { int product = num1num2; return product; }*
This method has an int return type, and so it includes a return statement. The variable returned (product) also has type int.
Calling Methods (from the Same Class) Now that we can write methods, we need to be able to call them. This will be different depending on whether we’re calling a method that’s in the same class as us, or in a different class. Here’s how we call a method in the same class as us:
methodName(args)
Here, methodName is the name of the method we’re calling, and args are the values of the parameters we’re passing. The parameters must have the same type as the corresponding arguments in the methods definition. Here’s an example of calling the printProduct method (from the same class):
int val1 = 5; int val2 = 7; printProduct(val1, val2);
The VALUES of val1 and val2 (5 and 7) are passed to printProduct, and stored in the arguments num1 and num2.
r1.area();
However, the area method returns a value, so we probably want to store or do something with a result. We’ll store the area of the 4x6 rectangle, and print the perimeter of the 3x5 rectangle:
int result = r1.area(); System.out.println(“The perimeter is “ + r2.perimeter());
Method Overloading Method overloading is when you have two or more versions of the same method, and each version has a different argument list. For example, suppose you wanted to define a method that computed the max of two numbers. You might want to do this for both ints and doubles. Here’s how:
public int max(int num1, int num2) { if (num1 > num2) return num1; else return num2; }
public double max(double num1, double num2) { if (num1 > num2) return num1; else return num2;
}
Notice that the two versions of max have the same name, but different argument lists. They also have different return types, but overloaded methods do not have to work this way. The compiler can figure out which one you want to call based on what types you pass. For example:
max(4, 7)
would call the first version of max since the arguments are both ints. On the other hand,
max(5.4, 8.76)
would call the second version since the arguments are both doubles.
Constructors can also be overloaded. This is done by creating two constructors (both with the name of the class) with different argument lists.
The static Keyword Class variables and class methods are defined with the static keyword. We have written static methods in the past without talking about how they are different from non-static methods.
Variables and methods in a class that are not static are instance variables and instance methods, which means there is a different version of each method and variable for each object instance of the class. Static variables and methods are called class variables and class methods, which means there is only one version of them for all different object instances of the class.
Static methods and variables can also be accessed with the class name (as we’ve done before) without having to create an object instance. Regular variables and methods cannot be accessed in this way.
Here’s how to declare a static variable:
visibility static type name;
And here’s how to declare a static method:
visibility static returnType name(args)
Here’s a sample class with static variables and methods:
public class Circle { public static double pi = 3.14159;
public static double area(double radius) { return piradiusradius; } }**
Now, because pi and area are static, we access them using the class name (Circle). All of the following are valid:
System.out.println (Circle.pi); //prints 3. double area = Circle.area(2); //area = 12.
Circle c1 = new Circle(); Circle c2 = new Circle();
System.out.println (c1.pi); //prints 3. double area = c1.area(2); //area = 12.
Circle.pi = 3.14; //Changes pi for all Circle objects
Static methods cannot refer to any instance variables. They can only refer to class variables (static variables), method arguments, and local variables.
The final Keyword
Arrays of Objects We have already seen how to create arrays of things like ints and doubles, but we can also create arrays of objects, where each element has a class type. The format for declaring an array of objects is just like declaring any other array:
type[] name;
But here, type should be the name of a class. We can also create space for the array just like we’ve done before:
name = new type[size];
Elements in arrays are initialized to the default value of that type, so elements in an array of objects are automatically initialized to null.
To see an example, recall the Rectangle class from the Methods section. Suppose that we want to create an array of 10 rectangles whose values are inputted by the user. Then, we want to print the area and perimeter of each rectangle. Here’s how:
//Declare the array and allocate space Rectangle[] rectArray = new Rectangle[10];
Scanner s = new Scanner(System.in);
for (int i = 0; i < rectArray.length; i++) { System.out.print(“Enter the length: “); int length = Integer.parseInt(s.nextLine()); System.out.print(“Enter the width: “); int width = Integer.parseInt(s.nextLine());
//Create a new Rectangle object with the //correct dimensions, and store it in the array rectArray[i] = new Rectangle(length, width); }
for (int i = 0; i < rectArray.length; i++) { //Print the area and perimeter for the current rectangle System.out.print(“Rectangle “ + i + “: “); System.out.print(“area “ + rectArray[i].area()) System.out.println(“, perim “ + rectArray[i].perim()); }
Notice that we’re treating each object in the array exactly like we would any other object, but instead of having to create a separate variable to refer to each object, we can store them all in an array.
Passing Objects to Methods We can pass objects to methods just like any other type of element. If we pass an object to a method, the type for that parameter is the type of the object (the name of the class). Suppose we want to write a printRectangle method that takes a Rectangle object as a parameter and then prints its area and perimeter. Here’s how the method would look:
public void printRectangle(Rectangle r) { //Now we can treat r just like any other Rectangle object System.out.println(“Area: “ + r.area()); System.out.println(“Perimeter: “ + r.perim()); }
Now, suppose we’re in the same class as the printRectangle method. Then we could do:
Rectangle rect = new Rectangle(3, 4); printRectangle(rect);
Notice that passing objects to methods works exactly like passing other types to methods – the only difference is that the parameter type is now the name of a class.
Objects as Instance Variables We can also make objects be instance variables in another class – again, this works just like other types of instance variables, but the type for the instance variable will be the name of a class. For example, suppose we have the following Person class:
public class Person { public String name; public int age;
public Person(String n, int a) { name = n; age = a; } }
Now, suppose we want to write a Child class that holds a child’s name, grade, school, and parent information. Each parent will be stored as a Person instance variable. Here is the Child class:
public class Child {
variable that you passed to the method will also change. (NOTE: there is a way to pass primitive values by reference, but we will not discuss this in class.)
Consider the following method:
public void setZero(int[] nums) { for (int i = 0; i < nums.length; i++) { nums[i] = 0; } }
Now, consider this call to setZero:
int[] vals = {1, 2, 3, 4}; setZero(vals);
When we return from setZero, every element in the vals array will be 0. This is because if an array is changed by a method, the original array (vals) is also changed.
Passing Objects Passing objects is also a type of call-by-reference. Consider the following class:
public class Person { private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public void incAge() { age++; } }
And consider this outside method:
public void changePerson(Person p) { p.incAge(); }
Now we create a Person object and call the changePerson method:
Person pers = new Person(“Amy”, 26); changePerson(p);
When we return from the changePerson call, pers now has age 27 (since changing the object in the method changed the original object).
However, suppose changePerson instead looked like this:
public void changePerson(Person p) { p = null; }
If I now created a Person object and called changePerson:
Person pers = new Person(“Amy”, 26); changePerson(p);
Then pers would NOT have the value null after the method call. This is rather confusing (and makes more sense in C++, which uses pointers), but p and pers are two different variables that reference the same object in memory. If I change that object’s age (like in the first version of changePerson), then the age changes for BOTH variables. However, if I set p to null, it just makes p reference null instead of the Person object. pers still references the Person object, so it remains unchanged.
Call-by-Value When you pass primitive variables (like ints) to a method, whatever changes you make inside the method will not affect the original variable. For example:
public void inc(int x) { x++; }
int num = 4; inc(num);
Even though the inc method adds one to x, it does not affect the value of num. This is because instead of passing the num variable, only the value is passed. This value ( 4 ) is stored in the method argument (x). When I increment x, it does not change num because they are two separate variables.
Just remember that if you pass an int, double, or char and change it inside a method – the change won’t stick. If you change an object or array, the change will stick.
“This” Keyword
the String[] args array. Suppose you want to get a person’s name, age, and GPA as command-line arguments. Then you might type:
java Test Bob 20 3.
The values “Bob”, “ 20 ”, and “3.45” will be placed in the args array. “Bob” will be at index 0, “ 20 ” will be at index 1, and “3.45” will be at index 2.
Using Command-Line Arguments We can access command-line arguments within the main method by saying args[i], where i is the index of the argument. For example, to store the name, age, and GPA from above:
public static void main(String[] args) { String name = args[0]; //name = ”Bob” int age = Integer.parseInt(args[1]); //age = 20 double gpa = Double.parseDouble(args[2]); //gpa = 3. }
Of course, this program will crash if the user mistakenly doesn’t enter any command-line arguments. To tell if they did, we can make sure args.length (the length of the command-line argument array) is what we expect. If not, we can print an error and exit. Here’s how:
public static void main(String[] args) { if (args.length != 3) { //print a descriptive error message System.out.println(“Usage: java Test name age gpa”); System.exit(0); }
//We know we have 3 command-line arguments String name = args[0]; int age = Integer.parseInt(args[1]); double gpa = Double.parseDouble(args[2]); }