CS 112
Spring 2022

Old version

This is the CS 112 site as it appeared on May 12, 2022.

Lab 2: Strings and arrays; a first look at reference types

Creating the necessary folder

  1. If you haven’t already created a folder named cs112 for your work in this course, follow these instructions to do so.

  2. Then create a subfolder called lab2 within your cs112 folder, and put all of the files for this lab in that folder.

Task 1: Working with Java Strings

Task 1.1: String objects and their methods

In Problem Set 2, there are several problems in which you will need to work with String objects in Java.

It turns out that Java lacks many of Python’s built-in operators and functions for strings. Instead, most operations involving strings – including indexing and slicing – are done using methods that are inside the string object.

If you would like to review, this is an example of a code trace using Java Strings.

The table below compares the ways in which some common string operations would be accomplished in Python and Java:

operation

in Python

in Java

assigning to a variable (and, in Java, declaring the variable)

s1 = 'Boston'
s2 = "University"

String s1 = "Boston";
String s2 = "University";

concatenation

s1 + s2

s1 + s2

finding the number of characters

len(s1)

s1.length()

indexing
(note: Java does not have negative indices)

s1[0]
s2[-1]

s1.charAt(0)
s2.charAt(s2.length()-1)
(see the notes below the table for a key fact about this method)

slicing

s1[1:4]
s2[3: ]
s1[ :5]

s1.substring(1, 4)
s2.substring(3)
s1.substring(0, 5)

converting all letters to uppercase

s1.upper()

s1.toUpperCase()

converting all letters to lowercase

s2.lower()

s2.toLowerCase()

determining if a substring is in a string

s2 in s1
'sit' in s2

s1.contains(s2)
s2.contains("sit")

finding the index of the first occurence of a character or substring

s1.find("o")
s2.find('ver')

s1.indexOf('o')
s2.indexOf("ver")

testing if two strings are equivalent

s1 == s2
s1 == 'Boston'

s1.equals(s2)
s1.equals("Boston")

Additional notes:

Task 1.2: Using String methods

To ensure that you understand how the above string operations work in Java, let’s write a simple Java test program that you can use to play around with the different string operations.

Getting started

  1. If you haven’t already done so, create a folder named lab2 for your work on this lab. You can find instructions for creating folders here.

  2. As needed, open your lab2 folder using the File->Open Folder or File->Open menu option in VS Code.

  3. Select File->New File, which will open up an empty editor window.

  4. Select File->Save, and give the new file the name StringTest.java.

Here are the tasks you should perform as part of your StringTest class:

  1. Create a class header and a main method.

  2. In the main method, begin by initializing two string variables that we will use in the later steps:

    String s1 = "Boston";
    String s2 = "University";
    

    If you have done everything correctly, the statements:

    System.out.println(s1);
    System.out.println(s2);
    

    should output:

    Boston
    University
    

    If for some reason you don’t see this output, make whatever changes are needed before proceeding.

  3. We’re now going to solve a series of puzzles in which we construct an expression involving operations on s1 and/or s2 to produce a specified target value.

    For example, let’s say that we want to construct an expression involving s1 or s2 that produces the following value:

    "ton"
    

    One possible expression that works for this puzzle is s1.substring(3, 6). To see this, we can add the line:

    System.out.println( s1.substring(3, 6) );
    

    which should output:

    ton
    
  4. Now solve the puzzles below. As you do so, add a println statement to your main method to test each expression that you construct.

    1. Construct an expression involving s1 or s2 that produces the following value:

      "Uni"
      
    2. Construct an expression involving s1 or s2 that produces the following value:

      "UNI"
      

      Hint: Chain two method calls together. For example:

      System.out.println( s1.toLowerCase().substring(0, 3) );
      

      should output:

      bos
      
    3. Construct an expression involving s1 or s2 that produces the following value:

      'v'
      

      Note that the single quotes mean that you must produce a char, not a String. See the notes under the table above that discuss the char type.

    4. Construct an expression involving s1 or s2 that produces the following value:

      "STONE"
      
  5. Write a static method called replaceStart that takes two strings s1 and s2, and does the following:

    • If the length of s1 (call it s1Len) is less than the length of s2, the method returns a string in which the first s1Len characters of s2 are replaced by s1. For example:

      System.out.println( replaceStart("abc", "xxxxxxx") );
      

      should output:

      abcxxxx
      

      and,

      System.out.println( replaceStart("hello", "xxxxxxx") );
      

      should output:

      helloxx
      
    • If the length of s1 is greater than or equal to the length of s2, the method just returns s1. For example:

      System.out.println( replaceStart("hello", "bye") );
      

      should output:

      hello
      
  6. Why does the method replaceStart need to be called from within the println method? In other words, what would you expect to happen if our program just made the call to replaceStart on its own line, rather than calling it as part of a println? Make sure you understand.

Task 2: Arrays and references

To get the most out of this task, draw out a memory diagram of the arrays on a piece of paper (follow examples we did in lecture, and the instructions of your TA). This is the best way to understand the correct answer to each of the questions, and why.

  1. Let’s draw what things look like in memory for the each of the following code snippets:

    // snippet A
    int[] a1 = {1, 2, 3, 4};
    int[] a2 = a1;
    
    // snippet B
    int[] b1 = {1, 2, 3, 4};
    int[] b2 = {1, 2, 3, 4};
    
  2. Given the two snippets above, what is the value of the following expression?

    a1 == a2
    
  3. Given the two snippets above, what is the value of the following expression?

    b1 == b2
    
  4. Consider the following static method:

    public static void mystery(int[] vals) {
        for (int i = 0; i < vals.length; i++) {
            vals[i] *= -1;
        }
    
        int[] vals2 = new int[vals.length];
        for (int i = 0; i < vals.length; i++) {
            vals2[i] = vals[i];
        }
        vals = vals2;
    
        for (int i = 0; i < vals.length; i++) {
            vals[i] += 2;
        }
    }
    

    What does the array a1 look like after the execution of the following code snippet, which you many assume is part of the main method of a valid Java class?

    int[] a1 = {1, 2, 3, 4};
    mystery(a1);
    

    Draw pictures to show what things look like in memory. You may find it helpful to use the following template, which shows separate method frames for main() and mystery():

    +--------------+
    | mystery      |
    | -------      |
    |       +----+ |
    | vals2 |    | |
    |       +----+ |
    |       +----+ |
    |  vals |    | |
    |       +----+ |
    +--------------+
    | main         |
    | ----         |
    |       +----+ |
    |    a1 |    | |
    |       +----+ |
    +--------------+
    

Task 3: Array methods

Getting started

  1. As needed, open your lab2 folder using the File->Open Folder or File->Open menu option in VS Code.

  2. Select File->New File, which will open up an empty editor window.

  3. Select File->Save, and give the new file the name ArrayPractice.java.

Here are the tasks you should perform as part of your ArrayPractice class:

  1. Before the class header, you should include the following statement, which will give us access to the methods in the Arrays class:

    import java.util.*;
    
  2. Create a class header and a main method, and add the following initial statements to your main method:

    int[] a = {2, 4, 6, 8};
    
    System.out.println( a );
    
    // What do you expect to see?
    
    System.out.println( Arrays.toString(a) );
    
    // Now, what do you expect to see?
    
  3. Write a static method named equals that takes two arrays of integers and determines if the two arrays are identical (i.e. same elements in the same positions). The method should return true or false accordingly.

    For this (and each of the following methods), you will need to add calls to your main method to test them.

    Example:

    int[] a1 = {1, 2, 3, 4};
    int[] a2 = {1, 2, 3, 4};
    System.out.println( a1 == a2 );
    System.out.println( equals(a1, a2) );
    

    You should expect to see:

    false
    true
    

    Congratulations! You just wrote your own equals method for arrays! However the Arrays class contains many methods, one of which is the equals method. To use the built-in Arrays method, try this:

    Example:

    System.out.println( Arrays.equals(a1, a2) );
    

    You should expect to see:

    true
    
  4. Write a static method named square that takes an array of integers and squares each element of the array.

    This method does not need to return anything. (If you’re not sure why, please ask!)

    Example:

    int[] a1 = {1, 2, 3, 4};
    square(a1);
    System.out.println( Arrays.toString(a1) );
    

    You should expect to see:

    [1, 4, 9, 16]
    

Task 4: Challenge: More practice with array methods

  1. Write a static method named shiftLeft that takes an array of integers and shifts each element one position to the left. The last element of the array should end up being 0, and the original first element should be returned by the method.

    For example:

    int[] a3 = {1, 2, 3, 4, 5, 6};
    System.out.println( shiftLeft(a3) );
    System.out.println( Arrays.toString(a3) );
    

    You should expect to see:

    1
    [2, 3, 4, 5, 6, 0]
    

    Hint: To determine the necessary logic, you may find it helpful to begin by writing down examples of specific assignments statements that the method will need to perform as part of the shifting. Then look for the general pattern in these assignments, and use it to write the necessary loop.

    Other hints:

    • You will need to store the original first element in a variable before you do the shifting, so that you can return the first element at the end of the method.

    • Don’t forget to put a 0 in the last position of the array.

  2. Write a static method named replace that takes an array of integers and two integer variables, val1 and val2 and replaces all occurences of val1 with val2. The method should return how many values were replaced. If no value was replaced (i.e. there were no occurrences of val1 in the array), the method should return a zero.

    For example:

    int[] a4 = {1, 2, 3, 2, 2, 6};
    int numReplaced;
    
    // first test
    numReplaced = replace(a4, 2, 9);
    System.out.println( Arrays.toString(a4) );
    System.out.println( "numReplaced = " + numReplaced );
    

    You should expect to see:

    [1, 9, 3, 9, 9, 6]
    numReplaced = 3
    

    Adding these statements:

    // second test
    numReplaced = replace(a4, 2, 9);
    System.out.println( Arrays.toString(a4) );
    System.out.println( "numReplaced = " + numReplaced);
    

    You should expect to see:

    [1, 9, 3, 9, 9, 6]
    numReplaced = 0
    

    How could I produce the exact same output as above without needing to declare the variable numReplaced?

    What is the output of the following code segment?

    int[] a4 = {1, 2, 3, 2, 2, 6};
    
    replace(a4, 2, 9);
    System.out.println( replace(a4, 2, 9) );
    
  3. Write a static method named interleave that takes two arrays of integers, creates and returns a third array of integers which contains all the elements of the two arrays, but in interleaved order.

    For example:

    int[] a5 = {1, 2, 3, 4, 5};
    int[] a6 = {6, 7, 8, 9, 10};
    int[] a7 = interleave(a5, a6);
    System.out.println( Arrays.toString(a7) );
    

    This should produce:

    [1, 6, 2, 7, 3, 8, 4, 9, 5, 10]
    

    Note:

    • If the arrays passed to the method are of two different sizes, only interleave elements until you run out of elements from the smallest array.
  4. Write a static method named isMirror that takes two arrays of integers and determines if the second array is an exact mirror image of the first array. The method should return true or false accordingly.

    Example 1:

    int[] a8 = {1, 2, 3, 4, 5};
    int[] a9 = {5, 4, 3, 2, 1};
    System.out.println( isMirror(a8, a9) );
    

    This should produce:

    true
    

    Example 2:

    int[] a10 = {1, 4, 5, 2, 1};
    System.out.println( isMirror(a8, a10) );
    

    This should produce:

    false
    
  5. Write a new static method named isMirror that takes two arrays of strings and determines if the second array is an exact mirror image of the first array. The method should return true or false accordingly. (Note: It’s okay for two methods to have the same name, as long as the number and/or types of the parameters are different.)

    Example:

    String[] s1 = { "abc", "def", "ghi" };
    String[] s2 = new String[3];
    s2[0] = new String("ghi");
    s2[1] = new String("def");
    s2[2] = new String("abc");
    
    System.out.println( isMirror(s1, s2) );
    // what do you expect to see?
    

    Hint:

    • If you don’t obtain the expected result, consider how you are testing for equality on strings.

Extra Practice!

If you get through the exercises above, congratulations!

For extra practice, you can try some exercises from an excellent site called Practice-It.