GWU

CS 1111

Introduction to Software Development

GWU Computer Science


Lecture Notes 08: Methods, encapsulation, and scope


Objectives

By the end of this module, for simple HelloWorld-like programs, you will be able to:




Why are functions useful in computation?

Writing and using Methods that use Input and/or return Output

In the previous module with Strings, we practiced using methods that resolve (or return) something and that might need input parameters to run.
In this segment we'll practice writing and invoking such methods.

First, two definitions:

Look at this program:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18


  public class IOMethods1
  {
    public static void main(String args[])
    {
      int num1 = 5;
      int num2 = 13;
      // Invoke the myOperation method and save result in the num3 variable
      int num3 = myOperation(num1, num2);  // myOperation(num1, num2) resolves into the resulting value
      System.out.println ("myOperation on " + num1 + " and " + num2 +  " is: " + num3);
    }

    public static int myOperation(int localNum1, int localNum2)
    {
      int localNum3 = (localNum1 * localNum2) - (localNum1 - localNum2);
      // this causes the method invocation to resolve into localNum3
      return localNum3;
    }
  }
  

Note the following:

Activity 1: In IOMethods1.java write the above program and see what gets printed.
Now, let us run it inside the Java Visualizer to understand the way these parameters are passed around.

Activity 2: In IOMethods1.java inside the method myOperation, modify the values of localNum1 and localNum2 before returning localNum3 by using these two lines:


localNum1 = localNum1 + 99;
localNum2 = localNum2 + 99;


then, inside the main, add the following statement:


System.out.println ("num1 after modifying localNum1 is: " + num1 );
System.out.println ("num2 after modifying localNum2 is: " + num2 );


What do you print? why?



Now look at this program:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30


  public class IOMethods2
  {
    public static void main(String args[])
    {
      String base = "Pizza should not have pineapple";
      String part = "pine";

      // Invoke the extract method and save result in out variable
      String out = extract(base, part);  // extract(base, part) resolves into the resulting string
      System.out.println ("The new String is: " + out);
    }

    public static String extract(String localBase, String localPart)
    {
      // The return variable
      String localOut = "";

      // Get the index of localPart inside localBase
      int idx = localBase.indexOf ( localPart );
      // Get the size of localPart
      int partSize = localPart.length();

      // copy localBase up to the start of localPart
      localOut = localBase.substring (0, idx);
      // copy localBase after localPart until the end of localBase
      localOut = localOut + localBase.substring (idx + partSize);

      return localOut;
    }
  }
  

Activity 3: In IOMethods2.java write the above program and see what gets printed.
Now, let us run it inside the Java Visualizer to understand the way these parameters are passed around.

Note the following:



Activity 4: In IOMethods2.java inside the method extract, modify the values of localBase and localPart before returning localOut by using these two lines:

localBase = "New Base";
localPart = "New Part";


then, inside the main, add the following statement:


System.out.println ("base after modifying localBase is: " + base );
System.out.println ("part after modifying localPart is: " + part );


What do you print? why?



Activity 5: In IOMethods3.java Write a method that takes no parameters but returns a value. Then invoke that method from main and print the return value.

Activity 6: In IOMethods4.java Write a method that takes one character array parameter (called arr), one integer parameter (called idx), and one char parameter (called ch).
The method should modify the array with the character at index idx replaced with the character ch. Then invoke that method from main and print the return value.




Variables declared outside of methods

You may have seen variables that were declared outside methods in our homework (for example, turning a test case on or off) -- these were used to control whether or not a problem gets tested. You may have observed that our main method was able to see these variables, even though they were declared outside of the method. Let's formally explore what's going on now.

Consider the following program:

Activity 1: Execute the above program in the Java Visualizer. What does it print?

Let us point out a few things:

Activity 2: Define another field, an int, and two new void methods with no input parameters: increaseIt(), and decreaseIt(), which increase and decrease the new field by 1 respectively. Demonstrate its use by printing the values of the field both before and after modification.

Why are fields useful? In a few lectures, we'll introduce classes and Object Oriented Programming formally, and we'll see how classes make use of fields to store the state of an object. Methods will typically involve accessing this stored state via the fields of the class.




Variable shadowing and scope

Consider this program:

  • Consider the method foo:

    The local definition of a variable with the same name y shadows the name of the field (global).

  • Something similar happens with the method bar:

    Thus, parameter variables shadow (obscure) field (global) variables of the same name. Typically, this is bad and undesirable: it makes the code much harder to understand and trace, as we'll see below.

In general, variables can be defined in any block of code (a block is code between two curly braces):

  • Here, the m and n in main refer to the global m and n

  • However, the m in foo is a local variable that shadows the global one:

  • The scope of a variable is the block of code that can access a variable.

  • The scope of the global variable m is any method inside the class.

  • Similarly, one can see the scope of the other variables in method foo, for example m:

  • And the others:

Now consider this example:

Activity 4: What gets printed out? The value 1 repeatedly or increasing values of m?

Activity 5: Open the class AnotherShadowingExample and run it in the Java Visualizer Observe the following:

  • Examine the variables within each of the scopes and experiment with which ones are shadowed.
  • Add a new method, with parameters that shadow global variables, and with local variables that also shadow other variables.
  • When does shadowing work as expected, and when does it yield a compiler error?





Packaging and encapsulation

Consider the following program:

  • Here, we see that there is an array and a bunch of methods that "do things" with the array.

  • Now, the methods appear to be of general use to a variety of arrays, and could be useful in the future.

  • Suppose we were to "package" these useful methods into a class called ArrayTool as follows:

  • Then, these could be used in the future by any program in the same directory as ArrayTool, e.g.,

  • This type of packaging is called encapsulation.
    • Related code can be together.
    • Other programs need not know the details, they can just use (i.e., call) the methods in the class.

  • Such encapsulation and re-use is a key part of how efficiencies are realized in software development.

Compiling Classes with Dependencies

Notice that compiling FutureApp depends on compiling the other class ArrayTool. If they are in the same directory on your computer, you can compile them with javac *.java. If they are in different directories, or one is in an external library, it gets more complicated -- you'll learn about that later.




Visibility and Encapsulation

Consider the following program that is split into two files. Make sure both files are in the same folder/directory. First, VisibilityTest.java:

public class VisibilityTest {
    public static int a = 3;
    static int b = 4;
    private static int c = 5;

    private static int helper() {
        return 1;
    }

    public static int helper2() {
        return helper() + 1;
    }
}
Second, VisibilityMain.java:

public class VisibilityMain {
    public static void main(String[] args) {
        System.out.println(VisibilityTest.helper());
        System.out.println(VisibilityTest.helper2());
        System.out.println(VisibilityTest.a);
        System.out.println(VisibilityTest.b);
        System.out.println(VisibilityTest.c);
    }
}
It is quite common to break the main method into a separate class.

Next class:

We'll go through some tracing of code together to understand methods, return statements, memory, and scope.

Assignments for next lecture:

Work on Quiz5 problems before coming to class.