Handout: Object Example: Scanners based on Strings
When we write a document, and want to incorporate a paragraph of text from another file “Rules.doc”, consider two ways to do it
1. Copy the paragraph into your own document
2. Use a reference to the Rules.doc: “See paragraph 3.4 of Rules.doc”.
Note there can be multiple references to the same paragraph. If someone edits paragraph 3.4 of Rules.doc, all the readers of documents referring to it will see the new version. Whereas if a copy had been made, they would see the old version. This kind of sharing goes on all the time with Java objects.
This idea of reference is used for Java objects, but not for primitive types. Let’s look at some examples.
Last time we looked at Scanners, and how we can customize them to read hex integers.
(not in book, but used in IT all the time for Ethernet addresses, other things)
Hex Digits 16 digits: 0-9 plus a, b, c, d, e, f, for 10, 11, 12, 13, 14, and 15. Can use A, B, … F too.
2-digit hex numbers: The left-hand digit says the number of 16s in the integer, the following one the number of ones.
For example 21 in hex means 2 16’s plus 1, or 33.
A1 = a1 = 10*16 + 1 = 161
3-digit hex numbers: The leading digit says the number of 16*16 = 256’s in the integer.
Ex: 123 in hex has value 256 + 2*16 + 3 = 291
Ex: 2af in hex has value 2*256 + 10*16 + 15.
We can get a Scanner to interpret these hex numbers.
Last week we looked at using Scanner objects for reading user input. To recap, we create a Scanner with new, as we do with all objects except Strings, which have a shortcut (String s = “abc”;).
Scanner input = new Scanner(System.in);
As originally created, the Scanner is set to interpret numbers base 10, i.e., radix 10.
int x = input.nextInt(); // interpret digits 0-9 into a binary number for the int named x
But we can also customize it to interpret digits 0-9, a-f for hex, by using its “useRadix” method:
input.useRadix(16);
int y = input.nextInt(); // interpret digits 0-9,a-f into a binary number for y
Ex: type “10”, then y = 16. Type “a1”, then y = 161.
So we see we can talk to the Scanner object and get it to work the way we want, within its limits.
Look at handout on Scanners on Strings. There we see the concept of object state, i.e., the internal data of the Scanner as it works.
The basic picture shows a little “reference” pointing to a bigger object holding object state:
Ref “input” --à (big object can do scanning, has a particular radix, input cursor)
We can create a second reference for the same object this way:
Scanner myScanner = input; // just copies the reference, still have only one Scanner object.
<picture of 2 references both pointing to the Scanner object>
Both input and myScanner point to the same object. If we change the Scanner through either reference, it changes for both.
For example, if we start with a Scanner with radix = 16 for hex, and have two references to it, input and myScanner, and then do
myScanner.useRadix(10); // set it back to decimal
This will “show up” as changed for the Scanner known as “input”, since input and myScanner are both referencing the same Scanner object.
We say this is a case of “aliasing”: there are two names for the same object. It can be confusing, but we need to be able to deal with it.
Aliasing happens whenever we pass an object to a method. Only the reference gets copied, so the method gets to work on the important data, the object itself.
The method can make “permanent” changes to the object, ones that survive the return to caller.
Because a Scanner is an object, we can change the radix in our own method and the changes will “stick”--
public static void configHexScanner(Scanner in)
{
in.useRadix(16);
}
In main—
Scanner input = new Scanner(System.in); // start off with radix = 10
configHexScanner(input);
// now input is a hex reader, because it was changed in the method
The Scanner object has been changed. We pass the object around with the help of references like “input”.
int i= 10; //Just an integer named i
int j = i; // copies integer value from i to j
Now if we change i, j won’t be affected.
When primitive types are arguments to a method, they are copied in, and the caller’s value is unaffected--
public static void tryToChangeInt(int x)
{
x = 10;
}
Caller:
x1 = 5;
tryToChangeInt(x1)
// x1 is still 5: we can’t change a caller’s int by passing it to a method
When we pass an int (or any other primitive type) into a method, a copy is made, so the caller’s int is safe from change.
When we pass an object into a method, only the reference is copied, so the object itself can be modified in a way that sticks after method return.
When we read a method header, we should note which parameters are primitive, and which are objects, so we can understand what can happen.
Terminology on pg. 501
OOP—thinking in objects—need examples before this makes sense!
Object: a programming entity that contains state (data) and behavior (methods)
State: a set of volues (internal data) stored in an object
Behavior: a set of actions an oject can perform, often reporting or modifying its internal state.
Example: Scanner object
State: its current input stream, its input cursor (what data has been provided to the program so far) (see pg. 387),
Its current radix (10 or whatever)
Behavior: what it can do, its methods: nextInt(), nextDouble(), hasNextDouble(), useRadix(), radix(), …
Example: String object “abcd”
State: its chars, in order
Behavior: its methods: length(), startsWith(), …
Scanner: somewhere, there’s a Scanner.java—it’s in the JDK. It’s a class, so it starts off public class Scanner…
Similarly a String.java for String objects. Each Whatever object has a same-named Java source.
Scanner.java provides the code needed to create and use Scanner objects.
Scanner input = new Scanner(“abcd”);
This calls the Scanner constructor in Scanner.java. A constructor is a body of code that handles object creation.
double count = input.nextDouble(); // calls method nextDouble in Scanner.java
Where’s the state of the object?
Scanner on a String has
· String as a source
· Position in string
· The current radix
These are held in fields of Scanner.java, i.e., variables trapped inside the objects:
Let’s simplify to Scanners on Strings, and assume each has fields str, position, and radix.
Scanner sc1 = new Scanner(“abc def”);
Now inside sc1, field str = “abc def”, position = 0; radix = 10;
String token = sc1.next();
Now str = “abc def”, position = 3, radix = 10;
sc1.useRadix(16)
Now str = “abc def”, position = 3, radix = 16;
Set up a second Scanner object:
Scanner sc2 = new Scanner(“x yy”);
Inside sc2: str = “x yy”, position = 0, radix = 10.
We see that the fields are inside the objects, and each object has its own values.
Review of points in the x-y plane
Look at PointExample.java, pg. 505
We’ll look at this again next time.