Transcript Document

CS203 Lecture 2
Review of CS 202
Review
• CS202 covers a large volume of difficult material. Use the
ungraded diagnostic quiz to identify areas you need to
review over the weekend.
• This review covers just the key concepts from CS202 and
those that are critical as foundations for the material in
CS203.
Static Vs. Instance Data
•Static data fields are controlled by the class,
not the object. A static field has only one
value for all instances of a class at any point
during runtime
•Instance data fields belong to the object, not
the class, so they can have different values for
each object.
3
Static vs Instance Methods



Static methods like main() can be run using the class code without
instantiating an object.
JOptionPane.showMessageDialog(null, "hey");
Static methods cannot use instance data
Instance (non-static) methods can be run only as methods of particular
objects instantiated from the class:
Scanner sc = new Scanner();
double d = sc.nextDouble();
4
Static Methods and Data
package demos;
public class Borg {
private String name;
private static int borgCount;
public Borg(String nameIn) {
name = nameIn;
borgCount += 1;
}
public void stateName() {
System.out.println(name + " of " + borgCount);
}
public static void main(String[] args) {
int max = 9;
borgCount = 0;
Borg[] borgs = new Borg[max];
for (int counter = 0; counter < max; counter++) {
String name = String.valueOf(counter + 1);
borgs[counter] = new Borg(name);
}
for (int counter = 0; counter < max; counter++) {
borgs[counter].stateName();
}
}
}
5
Why don’t we just use static methods
for everything?
public class Clone{
private String name;
public Clone(String nameIn){
name = nameIn;
}
public static void main(String[] args){
Clone bob = new Clone("Bob");
Clone joe = new Clone("Joe");
Clone mary = new Clone("Mary");
bob.greet();
joe.greet();
mary.greet();
}
private void greet(){
System.out.println("Hi, my name is " + name);
}
}
This example uses three instances of the same class, which each have different
data. We can run the same method from each object, getting different results for6
Public and Private




Public data may be accessed directly by any object that has a reference to
the current object
This means that any other object can change your data in any way that
seems appropriate to whoever wrote it
 This leads to unpredictable behavior, because programmers are almost
as crazy as users
Private fields and methods may only be used from within the current
object
Most classes have private data which can be accessed or changed only by
using7 public methods
 The public methods are part of the object and thus can see or change
the private data
Public and Private

We can reduce the confusion by providing well-defined
interfaces instead of allowing other objects to access our data
directly
 To use an object of a certain class, you only need to know
its public methods.
 You can protect the data in your own classes by allowing it
to be changed or accessed only by methods you wrote and chose
to make publicly available
 This principle is called information hiding or encapsulation
8
Public and Private
(American) football includes several ways to score points.
The main ones are these:
 A touchdown scores 6 points
 A conversion, also called an extra point, scores one point
but can only be scored immediately after a touchdown
 A safety scores 2 points
 A field goal scores 3 points
Note that there is no way to score four, five, seven, etc.
points at once
9
Public and Private
public class FootballScore {
// models the score for one team in a game of American Football
private int score;
public int getScore() {
return score;
}
public void touchdown() {
score += 6;
}
public void extraPoint() {
score += 1;
}
public void safety() {
score += 2;
}
10 public void fieldGoal() {
score += 3;
}
}
Public and Private
How the private data / public methods architecture benefits FootballScore:



If external objects (say, a FootballGame object) could arbitrarily change the
score in FootballScore, buggy or malicious code could interfere with the
functioning of the class
 for example, by adding 5 to the score or dividing it by 2, changes that are
invalid in American Football.
 this kind of problem is hard to find and extremely hard to fix, since the bad
code was probably written by someone else
In FootballScore, the available ways to change the score are limited to the ways
points can actually be scored in Football
If anything else needs to be done when the score changes, like
11
updateScoreboard(); or notifyBookmaker(); the author of FootballScore can take
responsibility for making sure the public methods trigger it
Public and Private
How the private data / public methods architecture benefits objects that use
FootballScore:

Other objects do not have to understand the internal functioning of
FootballScore
 They only need to know that they can find out the score by calling getScore()
and can deal with scoring events by calling, for example, touchdown().
 If you decide to change the design of FootballScore, nothing in any other class
needs to change as long as the public interface remains the same.
 This will become very important as your classes get more sophisticated.
Suppose you write a class with a method that determines whether or not a
touchdown was actually scored. You may sometimes need to change the
algorithm used by the method (eg, to use new electronic sensors or to
accommodate rule changes in the sport.) As long as the method signature
12
remains the same, other objects don't need to understand anything about it
or even know when you change it.
Lists
•
•
Need to import java.util.List as well as whatever specific type of list
you use, eg java.util.ArrayList
Java Lists are parameterized by other data types; a List is a List of,
for example, Strings. The syntax for the parameterization looks
like this:
•
List <String> myStrings = new ArrayList <String>();
•
We will use this syntax for many other data structures this
term.
•
Unlike an array, a list can only contain objects, not primitive types.
For example, you can not declare a list of doubles, but you can
declare a list of Doubles. You will understand this better in a couple
of weeks.
List Methods

Here are some of the key List methods
– add() adds an item to the end of the list
– get(int position) gets a reference to the item
at the specified position in the list
– isEmpty() returns a boolean that indicates just
what it sounds like
– size() shows the number of items in the list
– clear() deletes all items from the list
More List Methods
Some List methods hinge on the fact that a List contains
elements of some other data type.
contains(Object o)
 indexOf(Object o) finds the index of the first occurrence of a
value in the list
 lastIndexOf(Object o) finds the index of the last occurrence of a
value in the list

List Algorithms
Algorithms that iterate through lists, doing some kind of
processing on each value, are very common. Finding the total,
average, least, or greatest values in a list is similar to doing the
same in an array
double[] sizesArray = {6.5, 9.0, 10.0, 8.5, 7.5, 11.0, 10.5};
List<Double> shoeSizes = new ArrayList<Double>();
public double findAverageInListOfDoubles(List<Double> list){
double total = 0;
for(Double d: list) total += d;
return total / list.size();
}
Algorithms like this will be important with many new data structures we will
study this term.
Constructors

Constructor method headers look like this:
public ClassName(parameters){}
By convention, if programmer-defined constructors are present, they
are the first methods listed in a class.
 A class may have more than one constructor (“constructor
overloading”) as long as they take different arguments
 If you write one or more constructors, the compiler does not supply an
implicit constructor. If you want one, you must write it yourself,
which is very easy:
public ClassName(){}
 For example,
public Student(){}

19
Creating an object
 An object can be created using a no-parameter constructor like
this:
access modifier classname objectname = new classname();
For example,
private Student mary = new Student();
Note that
 Student is the name of a class
 mary is a variable whose value is a reference to the object we
created. The value of the variable mary is the address of the
memory location where the data for the object starts
 The data type of the variable mary is Student
 20private means that the variable mary is only visible from this
object.
Composition
• Compose: to create something by combining other things
• In programming, Composition occurs when a class includes variables of
other classes
• This occurs whenever we write classes that contain Strings or Scanners,
but also when we use a variable whose type is a class we wrote or get
from a library.
public class Student{
private String name;
private Double gpa;
Composition
public Student(String nameIn, Double gpaIn) {
name = nameIn;
gpa = gpaIn;
}
public String toString() {
return "Name: " + name + "; GPA: " + gpa;
}
}
public class GradeBook {
List<Student> students = new ArrayList<Student>();
public void addStudent(String name, double gpa) {
students.add(new Student(name, gpa));
}
public void showGrades(){
//[code omitted]
}
}
•
•
•
GradeBook contains an array list of Students
Student contains a Double and a String
Hierarchies like this can be of any depth.
Inheritance
• Classes often have natural hierarchies, which
can be defined in terms of data or in terms of
functionality
• The simplest form of hierarchy is general-tospecific
23
Inheritance
• All vehicles have some variables in common
– weight
– source of locomotion
– manufacturer
• Motor vehicles are a subset of vehicles, and
they have additional data fields
– Engine displacement
– Fuel type
• Trucks are a subset of motor vehicles, and
they have yet more data fields
– Hauling capacity
– Etc
24
Inheritance
• We can model this kind of general-to-specific hierarchy using
class inheritance
• “Super” means above, as in supervisor. “Sub” means under or
below, as in submarine.
• A subclass is a class which is a more specific form of some
other class, which we call its superclass
• Superclasses are more abstract than their subclasses
• The terms parent and child are sometimes used in place of
superclass and subclass.
• To define a class as a subclass of a superclass, use the extends
keyword. See the examples below
Inheritance Hierarchy
• A class can inherit from a hierarchy of superclasses, in the same way you
have parents, grandparents, great-grandparents, etc.
• All Java classes are subclasses of Object. Object is, for example, where the
original forms of toString() is defined. However, most other classes do not
inherit directly from Object.
– Here is the class hierarchy for OutOfMemoryError
java.lang.Object
java.lang.Throwable
java.lang.Error
java.lang.VirtualMachineError
java.lang.OutOfMemoryError
Inheritance
• Subclasses inherit the methods and variables of their superclasses.
• Subclasses can add variables, constants, and methods which are not
present in their superclasses.
• Subclasses can also replace methods inherited from superclasses with
their own methods. This is called overriding.
– toString()!
– Use the @Override annotation
– Make the superclass methods public or protected; can’t override private methods
• Subclass constructors call superclass constructors. If superclass has a
no-argument constructor, it is called by default by a no-argument
subclass constructor
– See example
package vehicles;
Inheritance
public class Vehicle {
protected double weightInKg;
protected double speedInKmPerHr = 0;
// a new vehicle should stop after it rolls
off the assembly line
protected Direction direction = new Direction(); // avoid null pointer exceptions by giving new vehicle the default
direction 0, 0, 0
public Vehicle() {
}
public Vehicle(double weightInKgIn) {
weightInKg = weightInKgIn;
}
public void steer(double bearing, double z) {
direction.setDirection(bearing, z);
}
public void accelerate(double speedIncrement) {
speedInKmPerHr += speedIncrement;
}
public String toString() {
return "vehicle weighs " + weightInKg + " kg: is going "
+ speedInKmPerHr + ": " + direction.toString();
}
}
Inheritance
package vehicles;
public class Direction {
private double bearing, z;
public Direction(){}
public Direction(double bearingIn, double zIn){
setDirection(bearing, z);
}
public void setDirection(double bearingIn, double zIn){
bearing = bearingIn;
z = zIn;
}
public double getBearing() {
return bearing;
}
public double getZ() {
return z;
}
public String toString(){
return "bearing: " + bearing + ": z: " + z;
}
}
Inheritance
package vehicles;
public class MotorVehicle extends Vehicle {
protected double engineDisplacementInCc;
protected String fuelType;
protected String manufacturer;
public MotorVehicle(){}
public MotorVehicle(double weightInKgIn, String manufacturerIn, double displacementIn,
String fuelTypeIn) {
super(weightInKgIn);
manufacturer = manufacturerIn;
engineDisplacementInCc = displacementIn;
fuelType = fuelTypeIn;
}
public double getEngineDisplacementInCc() {
return engineDisplacementInCc;
}
public String getFuelType() {
return fuelType;
}
public String getManufacturer() {
return manufacturer;
}
// this method is unique to MotorVehicles, not common to all vehicles
public void register() {
System.out.println("Registered " + manufacturer + " vehicle with DMV");
}
public String toString() {
return "manufacturer: " + manufacturer + "engine displacement: " + engineDisplacementInCc
+ ": fuelType: " + fuelType + ": " + super.toString();
}
}
Inheritance
package vehicles;
public class Car extends MotorVehicle {
private String licensePlateNumber;
public Car(double weightInKgIn, String manufacturerIn, double displacementIn, String fuelTypeIn, String licensePlateNumberIn){
super(weightInKgIn, manufacturerIn, displacementIn, fuelTypeIn);
licensePlateNumber = licensePlateNumberIn;
}
public String getLicensePlateNumber() {
return licensePlateNumber;
}
public void setLicensePlateNumber(String licensePlateNumber) {
this.licensePlateNumber = licensePlateNumber;
}
public String toString() {
return manufacturer + " car with plate " + licensePlateNumber + " and engine displacement " +
engineDisplacementInCc + " cc " + fuelType + " engine weighs " +
weightInKg + " kg and is going " + speedInKmPerHr +" KPH " +
direction.toString();
}
}
Inheritance
package vehicles;
public class Motorcycle extends MotorVehicle {
private double volumeInDecibels;
public Motorcycle(double weightInKgIn, String manufacturerIn,
double displacementIn, double volumeInDecibelsIn) {
super();
// note the difference between these assignments and the way the same task is done in the Car constructor.
// This way is simpler, but might miss or require duplication of initialization logic in the superclass constructors.
manufacturer = manufacturerIn;
weightInKg = weightInKgIn;
engineDisplacementInCc = displacementIn;
fuelType = "gasoline";
speedInKmPerHr = 0;
volumeInDecibels = volumeInDecibelsIn;
}
public double getVolumeInDecibels() {
return volumeInDecibels;
}
public void setVolumeInDecibels(double volumeInDecibels) {
this.volumeInDecibels = volumeInDecibels;
}
public String toString() {
return manufacturer + " motorcycle with a " + engineDisplacementInCc
+ " cc " + fuelType + " engine weighs " + weightInKg
+ " kg and is going " + speedInKmPerHr + " KPH "
+ direction.toString() + " making noise at " + volumeInDecibels + " db";
}
}
Inheritance
package vehicles;
public class Driver {
public static void main(String[] args) {
Vehicle shredder = new Car(1000, "Mazda", 1900, "gasoline", "ABC-123");
System.out.println(shredder);
shredder.accelerate(20);
shredder.steer(100, 0);
System.out.println(shredder);
System.out.println();
Vehicle hindenburg = new Motorcycle(240, "BMW", 594, 80);
hindenburg.steer(70, 0);
hindenburg.accelerate(90);
System.out.println(hindenburg);
System.out.println();
Vehicle porky = new Motorcycle(400, "Harley-Davidson", 1200, 150);
porky.accelerate(150);
porky.steer(180, 45);
System.out.println(porky);
}
}
Inheritance
• Concrete means particular or tangible, not
abstract.
– Originally meant solidified or hardened. The
building material was named because it has this
quality
• The classes in the previous examples were
concrete classes, ones that can be instantiated
34
Inheritance
• Classes may be abstract
– An abstract class cannot be instantiated, but it can have
subclasses that are concrete.
• Abstract classes may contain data fields that will
be common to all subclasses
35
Inheritance
• Abstract classes may define concrete methods,
but they may also declare abstract methods
– An abstract method isn't defined (written) in the class, but
must be defined in a subclass
• Subclasses that are also abstract can define the method or ignore it,
leaving it to be defined in their own subclasses.
• A concrete class may inherit or override
concrete method definitions from its
superclass(es)
• A concrete class must define any methods
which are abstract in its superclass hierarchy
36
Inheritance
• Syntax for abstract method:
access modifier abstract return type name();
For example:
protected abstract void accelerate(double speedIncrement);
• Syntax to implement a method that is abstract
in the superclass:
– Just add @Override notation above the method
code:
@Override
protected void accelerate(double speedIncrement){
speedInKmPerHr+=speedIncrement;
}
37
Inheritance
• Use an abstract class when you expect to create
subclasses that will implement some methods
identically but other methods in different ways.
• If you don’t need any data fields and don’t need
to define any methods, use an interface (next
week!) instead.
• Implementation of multiple subclasses of the
same class is another form of polymorphism.
38
Inheritance
package vehicleswithabstractclass;
public abstract class Vehicle {
protected double weightInKg;
protected double speedInKmPerHr = 0;
// a new vehicle should stop after it rolls off
the assembly line
protected Direction direction = new Direction(); // avoid null pointer exceptions by giving new vehicle the default
direction 0, 0, 0
public Vehicle() {
}
public Vehicle(double weightInKgIn) {
weightInKg = weightInKgIn;
}
public abstract void steer(double bearing, double z);
public abstract void accelerate(double speedIncrement);
public String toString() {
return "vehicle weighs " + weightInKg + " kg: is going "
+ speedInKmPerHr + ": " + direction.toString();
}
}
39
Inheritance
package vehicleswithabstractclass;
public abstract class MotorVehicle extends Vehicle {
protected double engineDisplacementInCc;
protected String fuelType;
protected String manufacturer;
public MotorVehicle(){}
public MotorVehicle(double weightInKgIn, String manufacturerIn, double displacementIn,
String fuelTypeIn) {
super(weightInKgIn);
manufacturer = manufacturerIn;
engineDisplacementInCc = displacementIn;
fuelType = fuelTypeIn;
}
public double getEngineDisplacementInCc() {
return engineDisplacementInCc;
}
public String getFuelType() {
return fuelType;
}
public String getManufacturer() {
return manufacturer;
}
// this method is unique to MotorVehicles, not common to all vehicles
public void register() {
System.out.println("Registered " + manufacturer + " vehicle with DMV");
}
public String toString() {
return "manufacturer: " + manufacturer + "engine displacement: " + engineDisplacementInCc
+ ": fuelType: " + fuelType + ": " + super.toString();
}
@Override
public void steer(double bearing, double z) {
// supply code to steer like a motor vehicle
}
// accelerate() is still abstract here
}
40
Inheritance
package vehicleswithabstractclass;
public class Car extends MotorVehicle {
private String licensePlateNumber;
public Car(double weightInKgIn, String manufacturerIn, double displacementIn, String fuelTypeIn, String licensePlateNumberIn){
super(weightInKgIn, manufacturerIn, displacementIn, fuelTypeIn);
licensePlateNumber = licensePlateNumberIn;
}
public String getLicensePlateNumber() {
return licensePlateNumber;
}
public void setLicensePlateNumber(String licensePlateNumber) {
this.licensePlateNumber = licensePlateNumber;
}
public String toString() {
return manufacturer + " car with plate " + licensePlateNumber + " and engine displacement " + engineDisplacementInCc + " cc " +
fuelType + " engine weighs " +
weightInKg + " kg and is going " + speedInKmPerHr +" KPH " + direction.toString();
}
@Override
public void accelerate(double speedIncrement) {
// supply code to accelerate like a car
}
}
41
Inheritance
package vehicleswithabstractclass;
public class Motorcycle extends MotorVehicle {
private double volumeInDecibels;
public Motorcycle(double weightInKgIn, String manufacturerIn,
double displacementIn, double volumeInDecibelsIn) {
super();
// note the difference between these assignments and the way the same task is done in the Car constructor.
// This way is simpler, but might miss or require duplication of initialization logic in the superclass constructors.
manufacturer = manufacturerIn;
weightInKg = weightInKgIn;
engineDisplacementInCc = displacementIn;
fuelType = "gasoline";
speedInKmPerHr = 0;
volumeInDecibels = volumeInDecibelsIn;
}
public double getVolumeInDecibels() {
return volumeInDecibels;
}
public void setVolumeInDecibels(double volumeInDecibels) {
this.volumeInDecibels = volumeInDecibels;
}
public String toString() {
return manufacturer + " motorcycle with a " + engineDisplacementInCc
+ " cc " + fuelType + " engine weighs " + weightInKg
+ " kg and is going " + speedInKmPerHr + " KPH "
+ direction.toString() + " making noise at " + volumeInDecibels + " db";
}
@Override
public void accelerate(double speedIncrement) {
// accelerate like a motorcycle
}
}
42
Inheritance
package vehicles;
public abstract class Spacecraft extends Vehicle {
// this class could have a hierarchy of abstract and concrete classes under it
}
43
Inheritance
package vehicleswithabstractclass;
public class Driver {
public static void main(String[] args) {
Vehicle shredder = new Car(1000, "Mazda", 1900, "gasoline", "ABC-123");
System.out.println(shredder);
shredder.accelerate(20);
shredder.steer(100, 0);
System.out.println(shredder);
System.out.println();
Vehicle hindenburg = new Motorcycle(240, "BMW", 594, 80);
hindenburg.steer(70, 0);
hindenburg.accelerate(90);
System.out.println(hindenburg);
System.out.println();
Vehicle porky = new Motorcycle(400, "Harley-Davidson", 1200, 150);
porky.accelerate(150);
porky.steer(180, 45);
System.out.println(porky);
}
}
44
Inheritance
• You can't instantiate an abstract class:
45
Inheritance
• A concrete class must have a definition for each
inherited method. If the method was abstract in the
last superclass, it must be defined in the new class:
46
More On Inheritance
Usually a bad idea
47
Inheritance
• You can use a reference variable to get access to public
methods of the variable's type and supertypes. Using
methods of subtypes of the variable's type requires a
cast and is usually a bad idea. This is true even though
you instantiate an object of the subclass and make the
variable reference it.
public class Motorcycle extends MotorVehicle {
private boolean sidecarPresent;
… stuff omitted
public void installSidecar(){
// this is a method of motorcycle. Its superclasses don't know about it
sidecarPresent = true;
}
…
48
Inheritance
These are both dicy ideas!
49
Types and Data Structure Parameters
• Arrays and Lists (and also other data structures you
will study in CS 203) can be parameterized with
abstract classes.
• An array or list whose type is a class (abstract or
concrete) can hold objects of any class that extends
the class.
50
Need For Interfaces
• Interfaces meet some of the same needs as abstract
classes in a simpler way
• Interfaces provide another way to use polymorphism.
– If you are programming a furnace, you need a heatAir()
method. However, the internal workings of the method will
differ depending on whether you are programming a gas
furnace or an oil one.
• Interfaces contain method declarations and may
contain constants
– No method definitions
– No variables
• Interfaces can’t declare private or protected methods,
just public ones (that's why they're called interfaces!)
51
Interface Syntax
• Syntax for defining an interface:
Access modifier interface name{
final declarations
method declarations
}
For example:
public interface Vehicle {
public static final double KMTOMILES = .609;
public void accelerate(double speedIncrementInKmPH);
public double getSpeedInKmPH();
public void steer(Direction d);
}
52
Need For Interfaces
• Classes implement interfaces. This is declared in
the class header:
public class MyClass implements MyInterface {
Eg
public class Car implements Vehicle {
• The distinction between interface (defined as
the public methods available for a class,
whether or not there is a java interface) and
implementation is very important in OOP.
• A class can have only one parent class, but can
implement any number of interfaces
53
Implementing Interfaces
• A class that implements an interface must
implement the methods declared in the interface
• Thus, if a class implements a particular interface,
we know that we can call certain methods on
objects of the class. We don’t care that the
methods may work differently for different
implementations of the interface.
• Here's another way to make the last point.
Different classes that implement the interface
may use methods whose internal workings are
completely different, as long as they have the
signature defined in the interface
54
Implementing Interfaces
• Implementations of methods required by an
interface need the @Override annotation:
@Override
public void setLocation(String location){
this.location = location;
}
55
Not Breaking Down At The Interfaces
• Other objects that deal with objects of your class
should only have to know the public interface
(whether or not there is a Java interface)
• Other classes should not need to understand the
internal workings of your class
– Reduce what other programmers need to learn (or you
need to remember) in order to use your classes
– Minimize problems at interfaces
– You can change the internal workings of your class
without any problems if the interface stays the same.
56
Not Breaking Down At The Interfaces
• Consider a WeatherReport class and a WeatherBalloon
class.
– A WeatherReport should be able to get the barometric pressure
from a WeatherBalloon by just calling an accessor method. It
shouldn’t be dependent on the particular way WeatherBalloon
determines what the pressure is.
• WeatherReport's programmer doesn’t need to learn how the
measurement is made
• WeatherBalloon's programmer can change the method for determining
pressure without affecting WeatherReport at all.
– Compare this to a computer storing data in permanent storage. I
should be able to swap out my hard drive and controller for an
SSD drive and controller without affecting the CPU, operating
system, etc.
57
Code To The Interface, Not The
Implementation
• Use variables of the most abstract type available
• Use methods from ancestor classes or java interfaces rather
than methods that are unique to particular concrete classes
whenever possible
• Coding to particular implementations, as opposed to interfaces,
exposes you to the risk that your code will break when some
other implementation changes. This is *very* dangerous
because you may not even know when other programmer
change the other classes, and you will also quickly forget how
your own code works.
• Coding to the interface also makes your code more modular. If
you rely on well-defined interfaces, you can more easily swap
out parts of your code later or determine which
58
implementations of an interface to use at runtime.
Types and Data Structure Parameters
ShrinerMobile extends Car, which extends the abstract class MotorVehicle, which
extends the abstract class Vehicle:
package vehicles;
public abstract class Vehicle {
protected double weightInKg;
protected double speedInKmPerHr;
protected Direction direction;
protected abstract void accelerate(double speedIncrement);
protected abstract void register();
protected abstract void steer(double bearing, double angle);
}
59
Types and Data Structure Parameters
60
Code To Interface, Not Implementation
61
Simulators
• Imagine you need data to test software that will be
used to process real-world measurements, like the
ages of college students
• Sometimes you might want linearly-distributed data,
but Gaussian distributions are often more realistic
package simulator;
import java.util.Arrays;
public class Grader {
private double average;
private double std;
private int classSize;
private double[] grades;
private final double MINGRADE = 0;
private final double MAXGRADE = 100;
public enum GradingType {
LINEAR, GAUSSIAN
};
public Grader(double avgIn, double stdIn, int classSizeIn) {
average = avgIn;
std = stdIn;
classSize = classSizeIn;
}
public static void main(String[] args) {
Grader grd = new Grader(80d, 10d, 20);
grd.grade(GradingType.LINEAR);
grd.grade(GradingType.GAUSSIAN);
}
private void grade(GradingType type) {
Simulator sim = new Simulator();
if (type == GradingType.LINEAR)
grades = sim.getLinearData(classSize, MINGRADE, MAXGRADE);
if (type == GradingType.GAUSSIAN)
grades = sim.getGaussianData(average, std, classSize, MINGRADE,
MAXGRADE);
System.out.println("\nData using distribution type: " + type + "\n");
for (int i = 0; i < grades.length; i++) {
System.out.print("Student #" + i + " received a grade of ");
System.out.printf("%3.1f\n", grades[i]);
}
Arrays.sort(grades);
System.out.println("Here are the sorted values from the simulator:");
for (double d : grades)
System.out.printf("%3.1f\n",d);
}
}
package simulator;
import java.util.Random;
public class Simulator {
private static double[] nums;
public double[] getGaussianData(double mean, double std, int count, double min, double max) {
Random r = new Random();
nums = new double[count];
double randDoub;
for (int counter = 0; counter < nums.length; counter++){
randDoub = r.nextGaussian() * std + mean;
// it's pretty hard to set limits for the values in a good way, so here is a hacky way.
if(randDoub > max) randDoub = max;
if(randDoub < min) randDoub = min;
nums[counter] = randDoub;
}
return nums;
}
public double[] getLinearData(int count, double min, double max) {
// it would be better to make sure max < min first, but I am not implementing this in this example
Random r = new Random();
nums = new double[count];
double randDoub;
for (int counter = 0; counter < nums.length; counter++){
randDoub = r.nextDouble() * (max - min) + min;
nums[counter] = randDoub;
}
return nums;
}
}
Separate Things That Are Likely To Change Independently
• Grader is domain-specific (only useful for a narrow type of
problem, in this case grading schoolwork)
• Simulator, on the other hand, does not contain anything that
shows it is from an application that simulates grading. It could
be used to generate test data for a very wide variety of problems
• This is an example of separation of concerns, an important
principle in software engineering. Separate the general from the
specific, and separate things you can probably reuse from things
you can't. If two things are likely to change independently of
each other, don’t combine them.
– "When all you have is a hammer, everything looks like a nail" – folk proverb
– "If I had a hammer, I'd hammer in the morning, I'd hammer in the evening, all over this land.
I'd hammer out danger; I'd hammer out a warning; I'd hammer out love between my
brothers and my sisters, all over this land." –Pete Seeger
Testing
Debugging is twice as hard as writing the code in
the first place. Therefore, if you write the code
as cleverly as possible, you are, by definition,
not smart enough to debug it.
--Brian Kernighan
Testing
•
Besides providing plenty of output that you can check, test various conditions
that should be true or false.
package monsters;
public class MonsterAttackDriver {
public static void main(String[] args) {
Monster dracula;
String dName = "Dracula", dNewName = "Bob", dHome = "Transylvania";
dracula = new Vampire(dName, dHome);
if(dracula.getName() != dName) System.out.println("Name error");
dracula.setName(dNewName);
if(dracula.getName() != dNewName) System.out.println("Name error");
if(dracula.getOriginStory() == null) System.out.println("Origin story error");
// etc. Test all public methods
}
}
Unit Testing
• Unit testing is a systematic way to test parts of your
applications
• Test for every likely error you can think of
• Each test asserts that some condition is true or false;
the assertions will fail if particular errors occur
Unit Testing
• Run all the tests periodically to find errors caused by
later code breaking things that worked before or by
implementation changes in one part of a system
– This is the simplest instance of the concept of regression
testing.
• Regression means "going back". Regression testing
"goes back" to test code again to see if it still works
correctly.
JUnit
• Eclipse includes a unit testing framework called JUnit
• If you have not used JUnit (depends on whom you took CS202 with),
make it a priority to learn it now
• A test case is a class that contains one or more tests, usually all testing
the same target class.
• Create one or more separate packages in each project for test cases.
• Tests use assertions of various kinds
– assertNull(Object o), assertNotNull(Object o)
– assertEquals(Object o, Object p), assertFalse(boolean)
– Many others listed here: https://github.com/junit-team/junit/wiki/Assertions
• A test succeeds if the assertion(s) are true when the test is run and fails
if one or more are false
• The object of a test is to assert something that will be true if the class is
working correctly but false if some plausible error occurs
JUnit
• Let's start by writing unit tests for the Vampire class, which
implements the Monster interface, and for the Crypt class, which is
used by Vampire.
• Test Crypt first, because it can work without Vampire, but Vampire
will not work if Crypt is broken
Monster
package monsters;
public interface Monster {
public void setName(String name);
public String getName();
public void setLocation(String location);
public String getLocation();
public void rampage();
public String getOriginStory();
}
package monsters;
Crypt
public class Crypt {
private String location;
public Crypt(String location) {
this.location = location;
}
public void setLocation(String location) {
this.location = location;
}
public String getLocation() {
return location;
}
public String toString(){
return "a mysterious crypt in " + location;
}
}
package monsters;
Vampire
public class Vampire implements Monster, Cloneable {
private String name;
private Crypt crypt;
public Vampire(String name, String location) {
this.name = name;
crypt = new Crypt(location);
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void setLocation(String location) {
crypt.setLocation(location);// TODO Auto-generated method stub
}
@Override
public String getLocation(){
return crypt.getLocation();
}
@Override
public String getOriginStory() {
return "undead creature which lives by sucking the blood of living humans";
}
@Override
public void rampage() {
StringBuilder sb = new StringBuilder(name
+ " arises from " + crypt.toString() + " and ");
if (crypt.getLocation() == "Transylvania")
sb.append("sucks people's blood all night, then returns to a coffin to hide from sunlight");
else if (crypt.getLocation() == "Burbank")
sb.append("takes over the entire television industry");
else {
System.out.println("wreaks unknown havoc in fresh Vampire territory");
return;
}
System.out.println(sb);
}
@Override
public Object clone() {
Vampire newV;
try {
/* Object clone() returns an Object. It will be a Vampire, but in order to get to anything specific to Vampires, we need
to cast it to a Vampire and use a Vampire reference variable */
newV = (Vampire) super.clone();
newV.crypt= new Crypt(crypt.getLocation());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
return newV;
}
}
Unit Testing
Unit Testing
• JUnit tests are identified with the annotation
@Test:
@Test
public void testCryptCreated(){
String location = "Transylvania";
Crypt c = new Crypt(location);
assertNotNull(c);
}
@Test
public void testToString(){
String location = "Transylvania";
Crypt c = new Crypt(location);
assertNotNull(c.toString());
}
Unit Testing
JUnit Assertions require imports
JUnit Assertions require imports
Unit Testing
• Write assertions that will fail if likely errors occur
• Keep the tests simple. Most tests have only one assertion
each. This way, you can identify problems quickly when
assertions fail.
• Systematically exercise the whole interface
– In this case, "interface" means the public interface of the class being
tested. That may be defined partially or completely by a Java
interface, an abstract class, or a concrete superclass, or it may be
unique to the class.
– Unit testing is not usually used for private methods; if these are
wrong, any errors should come to light through the public interface
• It is possible to instantiate objects and use them in multiple
tests, but it is usually better to start from scratch for each test
– Tests should not have dependencies on each other, which would cause
tests to break if other tests are changed
Unit Testing
package test;
import static org.junit.Assert.*;
import monsters.Crypt;
import org.junit.Test;
public class CryptTester {
@Test
public void testCryptCreated(){
String location = "Transylvania";
Crypt c = new Crypt(location);
assertNotNull(c);
}
@Test
public void testCryptLocation(){
String location = "Transylvania";
Crypt c = new Crypt(location);
assertEquals(c.getLocation(), location);
}
@Test
public void testSetCryptLocation(){
String firstLocation = "Transylvania";
Crypt c = new Crypt(firstLocation);
String secondLocation = "Wisborg";
c.setLocation(secondLocation);
assertEquals(c.getLocation(), secondLocation);
}
@Test
public void testToString(){
String location = "Transylvania";
Crypt c = new Crypt(location);
assertNotNull(c.toString());
}
}
VampireTester
• Vampire has a Crypt (remember, this is composition).
– There is no public method in Vampire that returns the Crypt, so we can’t directly test
that it is correctly creating the crypt.
– This is white box testing, though, and we do know that Vampire.getLocation() gets the
location from Crypt.getLocation()
@Test
public void testLocation() {
String name = "Orlok";
String location = "Transylvania";
Vampire v = new Vampire(name, location);
assertEquals(v.getLocation(), location);
}
VampireTester
• Here are some tests of Vampire.clone()
@Test
public void testCloneIsNewVampire(){
String name = "Orlok";
String location = "Transylvania";
Vampire v1 = new Vampire(name, location);
Vampire v2 = (Vampire) v1.clone(); //clone() returns an object, but it is a Vampire
assertNotSame(v1, v2);
}
@Test
public void testCloneName(){
String name = "Orlok";
String location = "Transylvania";
Vampire v1 = new Vampire(name, location);
Vampire v2 = (Vampire) v1.clone(); //clone() returns an object, but it is a Vampire
assertTrue(v1.getName().equals(v2.getName()));
}
@Test
public void testCloneLocation(){
String name = "Orlok";
String location = "Transylvania";
Vampire v1 = new Vampire(name, location);
Vampire v2 = (Vampire) v1.clone(); //clone() returns an object, but it is a Vampire
assertTrue(v1.getLocation().equals(v2.getLocation()));
}
@Test
public void testCloneChangeLocation(){
String name = "Orlok";
String location = "Transylvania";
Vampire v1 = new Vampire(name, location);
Vampire v2 = (Vampire) v1.clone();
v2.setLocation("Burbank");
assertFalse(v1.getLocation().equals(v2.getLocation()));
}
VampireTester
• To refactor code is to change the implementation
• When refactoring a class, don't change the public
interface unless you can do a major reorganization of
the whole application
– Refactoring should be completely invisible from outside the class, so
that
• other code does not have to change; and
• other programmers don’t have to learn the internal workings of your code
– Changing the interface inherently means other code must change
• Let's refactor Crypt.
VampireTester
• Refactor Crypt without introducing any errors:
public String toString(){
return "a very, very mysterious crypt in " + location;
}
• All test results remain the same
VampireTester
• Let's say we refactor Crypt and make a mistake:
public void setLocation(String location) {
location = location;
}
• Both CryptTester and VampireTester contain tests that will
now fail
• The failing test in VampireTester shows that Vampire will have
to change to match the change in Crypt. This is not desirable,
and it might not even be possible.
VampireTester
VampireTester
Click on *each* line in the JUnit output indicating a failed test
GUIs
• Practically all consumer-oriented software today uses Graphical
User Interfaces (GUIs, pronounced "gooeys")
• An attractive and easy to use UI makes a bigger impression on the
typical consumer than elegant program logic or even performance
does.
– Consumers buy sizzle, not steak.
– Bill Gates is the richest person in the world, but Richard Stallman can’t afford
a razor
• Java is heavily used in several types of GUI-based applications
– Web apps
– Android apps
– BluRay interface
JavaFX
• Until recently Java GUI programming was almost
always taught using a tookit called Swing
• We now use one called JavaFX, but the basic
principles are generally similar to those of Swing.
• If you do not have a basic familiarity with JavaFX,
read chapters 14-16 and ask me for the relevant
lecture notes and labs from CS202.
Event Handlers
• Event handlers specify which events the program will respond to and
what to do when they occur
• In JavaFX, these implement the EventHandler interface and are
parameterized with subclasses of Event, such as ActionEvent.
• You can add EventHandlers to may different types of GUI components
• EventHandlers must implement the method handle(Event event)
• You can create an Event Handler object in many different ways
–
–
–
–
Code a class in a separate file and instantiate an object
Code an inner class and instantiate an object
Code an anonymous class and instantiate an object separately
Code an anonymous class and instantiate a one-of-a-kind object all at once
Separate EventHandler Class
import javax.swing.JOptionPane;
import javafx.event.Event;
import javafx.event.EventHandler;
public class MyClickHandler<ActionEvent> implements
EventHandler<Event>{
@Override
public void handle(Event event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
}
Separate EventHandler Class
public class Hello extends Application {
@Override
public void start(Stage primaryStage) {
StackPane s = new StackPane();
Scene sc = new Scene(s, 300, 300);
Button b = new Button();
b.setText("Click Me!");
EventHandler<Event> handler = new MyClickHandler<Event>();
b.addEventHandler(MouseEvent.MOUSE_CLICKED, handler);
s.getChildren().add(b);
primaryStage.setScene(sc);
primaryStage.show();
}
}
Inner EventHandler Class
public class Hello extends Application {
@Override
public void start(Stage primaryStage) {
StackPane s = new StackPane();
Scene sc = new Scene(s, 300, 300);
Button b = new Button();
b.setText("Click Me!");
EventHandler<Event> handler = new MyClickHandler<Event>();
b.addEventHandler(MouseEvent.MOUSE_CLICKED, handler);
s.getChildren().add(b);
primaryStage.setScene(sc);
primaryStage.show();
}
private class MyClickHandler<ActionEvent> implements EventHandler<Event>{
@Override
public void handle(Event event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
}
}
Anonymous EventHandler Class with Variable
public class Hello extends Application {
@Override
public void start(Stage primaryStage) {
StackPane s = new StackPane();
Scene sc = new Scene(s, 300, 300);
Button b = new Button();
b.setText("Click Me!");
// “anonymous” because we never name the class
EventHandler<Event> handler = new EventHandler<Event>(){
@Override
public void handle(Event event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
};
b.addEventHandler(MouseEvent.MOUSE_CLICKED, handler);
s.getChildren().add(b);
primaryStage.setScene(sc);
primaryStage.show();
}
}
Anonymous Class with Anonymous Object
public class Hello extends Application {
@Override
public void start(Stage primaryStage) {
StackPane s = new StackPane();
Scene sc = new Scene(s, 300, 300);
Button b = new Button();
b.setText("Click Me!");
b.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>(){
@Override
public void handle(Event event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
});
s.getChildren().add(b);
primaryStage.setScene(sc);
primaryStage.show();
}
}
Anonymous Class with Anonymous Object
Open parenthesis begins parameter list for addEventhandler()
Beginning of method call
Call to EventHandler constructor
b.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>(){
@Override
public void handle(Event event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
}
);
Open curly brace begins definition of anonymous class
This idiom may be hard to get used to, but it is very common in many different GUI programming frameworks, and will certainly be on the final exam.
Close curly brace ends definition of anonymous class
Semicolon ends addEventhandler() statement
Close parenthesis ends parameter list for addEventhandler()
Event Handling with Setters
JavaFX can also handle events using setter methods from the various
Node classes, like this:
Label l = new Label("Click Me!");
l.setOnMouseClicked(new EventHandler<MouseEvent>(){
@Override
public void handle(MouseEvent event) {
JOptionPane.showMessageDialog(null, "Thanks!");
}
});
Event Handling with Lambda Expressions
• Simple event handling works well with lambda expressions, a feature
that is commonly used in functional programming and has recently been
introduced to Java.
• A Lambda expression is equivalent to an anonymous method (Liang says
an anonymous class)
• Here is a sample; e is the parameter name for the event, which is passed
into the lambda expression.. Later we will get information from the
event objects.
Label l = new Label("Click Me!");
l.setOnMouseClicked(e -> {
JOptionPane.showMessageDialog(null, "Thanks!");
}
);
Celsius Converter: Version 1
public class CelsiusConverter extends Application{
@Override
public void start(Stage primaryStage) {
GridPane gp = new GridPane();
Scene sc = new Scene(gp);
sc.getStylesheets().add("styles/style.css");
Label lblFahr = new Label("Fahrenheit Value: ");
TextField tfFahr = new TextField();
Label lblCels = new Label("Celsius Value:");
Label lblCelsAns = new Label();
Button btnCalc = new Button("Convert");
btnCalc.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>(){
@Override
public void handle(Event event) {
double cels = (Double.parseDouble(tfFahr.getText())-32)*5/9;
lblCelsAns.setText(String.valueOf(cels));
}
});
gp.getStyleClass().add("pane");
gp.add(lblFahr, 0, 0);
gp.add(tfFahr, 2, 0);
gp.add(lblCels, 0, 1);
gp.add(lblCelsAns, 2, 1);
gp.add(btnCalc, 1, 2);
primaryStage.setScene(sc);
primaryStage.show();
}
}
CelsiusConverter
.pane{
-fx-font-size: 250%;
-fx-padding: 20px;
}
Separate Application Logic From The GUI
• The initial EventHandler examples showed simple responses
coded in the handlers. It is better to separate out any
substantial processing into separate methods, in other
classes, following the general principle of separation of
concerns.
– We may want to reuse code to handle various different events.
– We may want to use the same functionality with a different kind of
GUI
– When we need to change the processing code, it is easier to work with
if it is not mixed with GUI code.
– It's hard to unit test GUIs, so we should get the code that might have
subtle bugs away from the GUI.
Separate Application Logic From The GUI
• Don’t put any substantial processing in the Event Handlers
and don’t access the GUI from the processing code.
• Either
– use separately-defined classes for the GUI app and the processing; or
– In simple cases, use an inner class with processing methods.
Celsius Converter 2.0
• Let's move the conversion calculation to this
class:
package application;
public class CelsiusCalculator {
private final double CONVFACTOR = 5.0/9.0;
private final int FSTART = 32;
public double fToC(double f){
return (f-FSTART) * CONVFACTOR;
}
}
package test;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import application.CelsiusCalculator;
Unit Tests
public class CelsiusCalculatorTester {
@Test
public void testFreezing() {
CelsiusCalculator calc = new CelsiusCalculator();
double freezingF = 32;
double freezingC = 0;
double freezingResult = calc.fToC(freezingF);
// assertEquals for two doubles takes a delta as the third argument!
assertEquals(freezingResult, freezingC, 0.1);
}
@Test
public void testBoiling() {
CelsiusCalculator calc = new CelsiusCalculator();
double boilingF = 212;
double boilingC = 100;
double boilingResult = calc.fToC(boilingF);
assertEquals(boilingResult, boilingC, 0.1);
}
@Test
public void testNegForty() {
CelsiusCalculator calc = new CelsiusCalculator();
double negForty = -40;
double negFortyResult = calc.fToC(negForty);
assertEquals(negFortyResult, negForty, 0.1);
}
}
CelsiusConverterGUI
package application;
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class CelsiusConverterGUI extends Application{
@Override
public void start(Stage primaryStage) {
CelsiusCalculator calc = new CelsiusCalculator();
GridPane gp = new GridPane();
Scene sc = new Scene(gp);
sc.getStylesheets().add("styles/style.css");
Label lblFahr = new Label("Fahrenheit Value: ");
TextField tfFahr = new TextField();
Label lblCels = new Label("Celsius Value:");
Label lblCelsAns = new Label();
Button btnCalc = new Button("Convert");
btnCalc.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>(){
@Override
public void handle(Event event) {
double cels = calc.fToC(Double.parseDouble(tfFahr.getText()));
lblCelsAns.setText(String.valueOf(cels));
}
});
gp.getStyleClass().add("pane");
gp.add(lblFahr, 0, 0);
gp.add(tfFahr, 2, 0);
gp.add(lblCels, 0, 1);
gp.add(lblCelsAns, 2, 1);
gp.add(btnCalc, 1, 2);
primaryStage.setScene(sc);
primaryStage.show();
}
}
ClickCounter
This application uses GUI components and EventHandlers in a slightly
more complex way:
• Place a grid of buttons on a GridPane
• Place a Label into in an Hbox (one-row Pane) indicating how many
buttons are currently clicked
• Attach EventHandlers to each button that track whether the
button is currently clicked or not clicked and update the
count displayed on the Label
• Add both Panes to a BorderPane
• Notice the use of String.valueOf() to convert numeric values to Strings
for display in labels
Click Counter
public class ClickCounter extends Application {
private int numClicked;
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane bp = new BorderPane();
bp.getStyleClass().add("grid");
GridPane gp = new GridPane();
Label clickedLabel = new Label("Buttons Clicked: ");
clickedLabel.getStyleClass().add("clickedLabel");
Label numClickedLabel = new Label("0");
numClickedLabel.getStyleClass().add("clickedLabel");
HBox clickedCounterBox = new HBox();
clickedCounterBox.getStyleClass().add("clickedBox");
clickedCounterBox.getChildren().add(clickedLabel);
clickedCounterBox.getChildren().add(numClickedLabel);
Scene sc = new Scene(bp);
sc.getStylesheets().add("styles/style.css");
numClicked = 0;
for (int rowCounter = 0; rowCounter < 10; rowCounter++)
for (int colCounter = 0; colCounter < 10; colCounter++) {
}
Click Counter
Button b = new Button("Unclicked");
b.setMinWidth(150);
b.getStyleClass().add("button");
b.addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<Event>() {
Boolean clicked = false;
@Override
public void handle(Event event) {
if (clicked == true) {
clicked = false;
b.setText("Unclicked");
numClicked--;
} else {
clicked = true;
b.setText("Clicked");
numClicked++;
}
numClickedLabel.setText(String.valueOf(numClicked));
}
});
gp.add(b, colCounter, rowCounter);
}
bp.setTop(clickedCounterBox);
bp.setBottom(gp);
primaryStage.setScene(sc);
primaryStage.show();
}
}
CSS
.pane{
-fx-font-size: 250%;
-fx-padding: 20px;
}
.grid{
-fx-font-size: 200%;
}
.clickedLabel{
-fx-background-color: #00FFFF;
}
.clickedBox{
-fx-alignment: center;
}
CompareTo
• Java contains a way to make it easy to sort
objects using programmer-defined criteria
• Collections.sort(list) is a static method of the
Collections class. Lists are a type of Collection;
we will cover this when we discuss inheritance.
• Sort() sorts according to the result of running
compareTo() when objects are compared during
the sort
• compareTo() compares the current object with
another one sent as input to the method
• compareTo() can compare objects using any
criteria you can code.
CompareTo
• Objects with compareTo() methods should be
declared to implement the interface
Comparable<>. Here is an example of the
interface declaration:
public class Student implements Comparable<Student>
• Note the parameterization of Comparable,
which looks just like the parameterization
used when declaring a list. For now, use the
class name of the current class as the
parameter.
package demos;
CompareTo
public class Student implements Comparable<Student>{
private String name;
private Double gpa;
public Student(String nameIn, Double gpaIn){
name = nameIn;
gpa = gpaIn;
}
public String toString(){
return "Name: " + name + "; GPA: " + gpa;
}
// getters and setters omitted
@Override
public int compareTo(Student otherStudent) {
return this.gpa.compareTo(otherStudent.gpa);
}
}
CompareTo
package demos;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class GradeBook {
public static void main(String[] args) {
List<Student> students = new ArrayList<Student>();
String[] names = {"Skipper", "Gilligan", "Mary Anne", "Ginger", "Mr. Howell", "Mrs. Howell", "The Professor"};
double[] gpas = {2.7, 2.1, 3.9, 3.5, 3.4, 3.2, 4.0};
Student currStudent;
for(int counter = 0; counter < names.length; counter++){
currStudent=new Student(names[counter], gpas[counter]);
students.add(currStudent);
}
// output the data
System.out.println("Unsorted:");
for(Student s: students)
System.out.println(s);
Collections.sort(students);
System.out.println("\nSorted:");
for(Student s: students)
System.out.println(s);
}
}
.jar files
• .jar files are used for distributing Java applications and
libraries.
• The file format is .zip, but the extension .jar identifies them
as Java Archives
• They contain bytecode (.class files), any other files from the
application or library (like images or audio files), and can also
contain source code
• The JDK contains command line tools for making jar files, but
this is easier to do with Eclipse
• Jar files may be executable, meaning that they are configured
to launch the main() of some class contained in the jar
• Applications that will be distributed as runnable .jars usually
have GUIs. If a user runs the .jar by double clicking on it in
Windows Explorer, MacFinder, etc., he won’t see any
command line I/O. In this course, don’t use command line
i/o in labs that require runnable .jars.
.jar files
.jar files
Mt. Fuji Principle
A wise man climbs Mt. Fuji once. A fool does it twice.
-Japanese proverb
The Stevie Wonder Principle
"When you believe in things that you don't understand, then you suffer."
You should be able to explain any method you write in one sentence. If you can't, break it
down into two methods. Repeat this process until all your methods are easy to understand.
118
Lurking Troll Principle
What you can’t see will hurt you. Never write a method with
more code than you can see on the screen all at once.