slanted W3C logo

Day 07 — Developing a Small Program

We start today's class by attempting to develop a small program that attempts to explain why elite leapers seem to hang in the air. We need to read the java.lang.Math API to help us solve this problem.

The remainder of the class is spent studying what happens when the client invokes a method.

Hangtime

Elite basketball players seemingly defy gravity by hanging in the air.

In his prime, Michael Jordan's vertical leap was approximately 1.2 meters. Assuming that the acceleration due to gravity is g = 9.8 m/s2, MJ would have to jump vertically with an initial velocity of v0 = 4.8497 m/s to acheive a maximum height of 1.2 meters.

How much time does MJ spend in the top 20 cm of his jump?

Note: The total amount of time MJ spends in the air is 0.9897 s

Solving Hangtime

To solve this problem, I claim that you need to solve the following equation for the time x:



where:

a = (1 / 2) * g
b = -v0
c = 1

Recall that the quadratic formula solves for both roots of a quadratic equation.

x1 =   ,   x2 =

Solving Hangtime

public class Hangtime
{
   public static void main(String[] args)
   {
      final double ACCEL_G = 9.8;
      final double INITIAL_VEL = 4.8497;
      
   }
}

Method Invocation

What happens a client invokes a method.

When You Invoke a Method: Part 1

When you invoke a method, the compiler needs to determine if the method exists, if the method has been invoked with the correct argument types, and which version of the method should be used.

The compiler uses 3 steps to determine if a method invocation is correct:

  1. determine the class to search for the method
  2. determine the method signature
  3. determine if the method is appropriate

Each step can be complicated. We only sketch what happens in the following slides.

Determine the Class to Search

The first step the compiler takes is to deduce the class that contains the method. The compiler does this by looking at the type of the class used to invoke the method:

   double Math.min(1.0, 2.0);

The compiler deduces that the method invocation belongs to the class named Math (because the name Math was used before the method name).

Determine the Method Signature

The second step the compiler takes is to deduce which version of the method is being invoked. This is necessary because Java allows the implementer to use the same method name for different versions of the method. Methods in a class that share the same name are called overloaded methods.

Consider the family of methods named min in java.lang.Math:

static double min(double a, double b)
static float min(float a, float b)
static int min(int a, int b)
static long min(long a, long b)

Here, all of the methods have the same number of parameters but the parameters have different types.

Determine the Method Signature

The compiler will search for all methods that are compatible with the method invocation. A compatible method is one that has the same number of parameters as the number of arguments supplied by the client, and the parameter types must match or be compatible with the types of the arguments supplied by the client.

Consider the two methods named nextInt in java.io.PrintStream:

void println()
void println(String x)

import java.io.PrintStream;
import java.util.Scanner;

public class MethodExample2
{
   public static void main(String[] args)
   {
      PrintStream out = System.out;
      Scanner input = new Scanner(System.in);
      
      int first = input.nextInt();
      int second = input.nextInt();
      out.println(first);
      out.println();
      out.println(second);
   }
}

In the example above, the compiler determines which method to use based on the number of arguments supplied by the client.

Determine the Method Signature

Consider the family of methods named min in java.lang.Math:

static double min(double a, double b)
static float min(float a, float b)
static int min(int a, int b)
static long min(long a, long b)

public class MethodExample3
{
   public static void main(String[] args)
   {
      double min = Math.min(10.0, 20.0);
   }
}

In the above example, there is only compatible version of the method named min, namely min(double a, double b).

public class MethodExample4
{
   public static void main(String[] args)
   {
      int min = Math.min(10, 20);
   }
}

In the above example, all versions of the method named min are compatible based on their signature because the int arguments 10 and 20 can be promoted to long, float, or double.

Determine the Method Signature

When there are multiple compatible method signatures, the Java compiler will try to pick the most specific method.

Consider the family of methods named min in java.lang.Math:

static double min(double a, double b)
static float min(float a, float b)
static int min(int a, int b)
static long min(long a, long b)

public class MethodExample5
{
   public static void main(String[] args)
   {
      double minDouble = Math.min(10.0, 20.0);
      int minInt = Math.min(10, 20);
   }
}

Determine the Method Signature

static double min(double a, double b)
static float min(float a, float b)
static int min(int a, int b)
static long min(long a, long b)

Which version of min is selected by the compiler for each of the following statements?

Math.min( 1F, 2.0F );
Math.min( 1L, 2L );
Math.min( 1, 2L );
Math.min( 1F, 2.0 );

Determine if the Method is Appropriate

The final step the compiler performs is to determine if the most specific method is appropriate. One thing that the compiler checks is if a non-static method is called in a static way (which is illegal):

import java.io.InputStream;
import java.io.PrintStream;
import java.util.Scanner;

public class MethodExample6
{
   public static void main(String[] args)
   {
      InputStream in = System.in;
      PrintStream out = System.out;

      int first = Scanner.nextInt();
   }
}

In the example above, the expression in red is illegal because the method nextInt is not static and can only be called using an object.

When You Invoke a Method: Part 2

When you invoke a method, the compiler computes the values of each of the arguments from left to right. The compiler then passes the values (not the variables!) to the method.

Consider the following program:

public class MethodExample7
{
   public static void main(String[] args)
   {
      int x = 10;
      int y = 20;
      int z = Math.min(y, x);
   }
}

The method min receives the values 20 and 10; it knows nothing about the variables x and y.

Recap: What Does int x = 10; Mean?

Recall that the statement int x 10; reserves a block of memory large enough to hold an int, labels the block with the identifier x, and assigns the value 10 to x.

0
  ¦
  main
 
x ⇒ 50 10
 
 
  ¦

Loading the Math Class

The first time that the running program uses the Math class, the compiled class is loaded somewhere into memory. In our memory diagram model, the class is shown as a block of memory that contains the attributes and methods of the class.

0
  ¦
  main
 
x ⇒ 50 10
y ⇒   20
  ¦
  ¦
400 Math class
E ⇒ 2.718281828459045
PI ⇒ 3.141592653589793
 
min  
a ⇒  
b ⇒  
  ¦

Invoking min

When the client invokes the min method, the values of the arguments get passed to the method.

0
  ¦
  main
 
x ⇒ 50 10
y ⇒   20
  ¦
  ¦
400 Math class
E ⇒ 2.718281828459045
PI ⇒ 3.141592653589793
 
min  
a ⇒   10
b ⇒   20
  ¦

Returning a Value

The method returns the value of the result back to the client, who can then store the result in z.

0
  ¦
  main
 
x ⇒ 50 10
y ⇒   20
z ⇒   10
  ¦
  ¦
400 Math class
E ⇒ 2.718281828459045
PI ⇒ 3.141592653589793
 
min  
a ⇒   10
b ⇒   20
result ⇒   10
  ¦

When You Invoke a Method: Part 2

Java's mechanism for passing arguments to methods is called pass by value. What is the implication of method only receiving the value of the arguments?

Consider the following method in some hypothetical utility MakeBelieve:

static void swap(int a, int b)
Swaps the values of a and b.

Parameters:
a – a value
b – another value

public class MethodExample8
{
   public static void main(String[] args)
   {
      int x = 10;
      int y = 20;
      MakeBelieve.swap(x, y);
      System.out.print("x : ");
      System.out.println(x);
      System.out.print("y : ");
      System.out.println(y);
   }
}

What does the program print?