Before we jump into Object Oriented Programming ...

Before we jump into Object Oriented Programming, we will round out our introduction to the structure of Java programs by consdering how we would write the kind of procedural programs we're used to in the Java lanaguage / run-time environment. In theory this is something you should not do! You should use OOP with Java. However, seeing how the pieces fit together in a familiar kind of program will be valuable, and put you in the right place from which to begin our investigation of OOP.
  1. classes as collections of functions (collections of methods in Java parlance)
  2. calling methods/functions of one class from within another
  3. classes as collections of data, i.e. classes as structs
  4. understanding how Java programs involving multiple class files run

A problem to motivate us

Suppose we wanted to write a program that allowed the users to play the card game Blindman's bluff poker. The idea is that each player gets a card, but only gets to see their opponent's card, not their own. A bet is placed by one player, then the next player raises, calls or folds. In case of a raise, the first player can either call or fold. "Call" means match the bet, "fold" means give up (other player gets money), and "raise" means match the bet and then add some more. Let's say there's a 10cent ante (initial amount put in before the game starts) and a 50cent maximum bet. In our game, all players start with $5. The game ends when all but one player is out of money, or at any point the users want to stop. We might not finish the game in class, but the point is to see how our procedural programming ideas in C++ map to Java (although, ultimately, in Java we will want to use object oriented programming, not procedural programming

Representing a cards: We're going to use the same representation of a card as an int that we did in IC210, summarized below:

  1. represent suits by number according to these rules: 0 = ♣, 1 = ♦, 2 = ♥, 3 = ♠
  2. represent face values according to these rules: 2 = 2, 3 = 3, ..., 10 = 10, 11 = J(jack), 12 = Q(queen), 13 = K(king), 14 = A(ace)
  3. represent a card as a number by the rule: cardvalue = 100 × suit + facevalue and (suit = cardvalue/100, facevalue=cardvalue%100)
    So, for example, the card Q♥ → (suit=2,facevalue=12) → 100×2 + 12 = 212
    In the other direction, cardnumber 314 = 100×3 + 14 (i.e. 314/100 = 3, 314%100 = 14) → (suit=3,facevalue=14) → A♠
Our Unix terminal program understands "UTF-8" character encodings, which means we can print card suits to the screen. Here are the suits and the corresponding string for printing them in unicode. ♣ ← "\u2663", ♦ ← "\u2666", ♥ ← "\u2665", ♠ ← "\u2660".

Step 1: will be to write a program that reads in a number N followed by N player names, deals each player a card from a shuffled deck, and prints out the N players in order with their, names, amount of money and card. For example:
3 Joe Sue Pat
Joe $5 10♥
Sue $5 K♦
Pat $5 3♠    
Note: Of course the point is to do this in such a way that we could easily extend it to play more and more of the real game ...

A C++ program for Step 1 (in a Procedural Programming Style!)

Let's start off with a C++ solution for Step 1, as you might write it at the end of IC210/SI204.
Note 1: There are no comments here so I can keep everything to one page, and because we will discuss the code a bit in class.
Note 2: There is a memory leak in this code, can you spot it?
Note 3: The .h files should have #ifndef's protecting against multiple inclusions ...

Important disclaimer ...

DISCLAIMER! We will keep the procedural style, which is not how you are supposed to program in Java! So a few weeks from now, you would do this in a totally different way. You would write it in an object-oriented style, which is what we are supposed to be doing in Java.

Translating card.h/card.cpp into Java

In-class exercise: Your instructor will give you printouts of the C++ code, and ask you to break up into groups of two or three and find all the things that will have to change to translate card.h/card.cpp into Java. Then as a class we will go over the complete translation, which will give us something like ...

  • The .h file isn't needed, because in Java we don't separate the declaration of a function/method's prototype from its definition. They are the same. However, and this is important, the notion of a function's prototype is very much there, except that in Java it is referred to as the function's signature.
  • All the function definitions need to be wrapped up in a public class definition. It might seem natural to name the class "card", but according to Java's naming conventions we really ought to call it "Card", because class names should begin with uppercase letters.
  • The source code file is named Card.java because the file name must match the name of the public class inside.
  • Each function definition must be prefaced with "public static".
  • The function names "cardstring" and "mkdeck" need to be changed to "cardString" and "mkDeck" to match camel-case conventions.
  • Array declaration
    string* F = new string[15]{ ...
    needs to be changed to
    String[] f = new string[]{ ...
    to match Java's array declaration rules and naming conventions. Needing to remove the "15" from the "[ ]" is interesting! It is a compile-time error to both give a size for the array and give an initializer list of values for the array. This makes some sense, since the array length can be inferred from the initializer list. We also make the analogous changes for the "S" array and the "D" array.
  • Important! Creating the f and s arrays in cardString does not cause a memory leak in Java as it did in C++. This is because Java is "garbage collected", so the f and s arrays will be automatically reclaimed when the JVM recognizes they are no longer needed.
  • The shuffle function/method changes the most. This is because there is no "global" function rand that we can call to generate a random number. Instead, we need a Random object that we use to call the nextInt method. (This will make more sense once we get a bit more into OOP.) So, the prototype (or "signature" in Java parlance) for the shuffle function has to change to add a new parameter Random rand> so we can make the call "rand.nextInt(52)".
  • Last, but not least, each public class is allowed to have its own public static void main(String[] args) method. This is a huge benefit when we try "bottom-up" programming, because it makes it easy to add in testing code - in this case that means code that is there to test the function/methods we have put into class Card, but which is not part of the larger program we are ultimately creating. We've made use of exactly that feature here:
    $ java Card
    Testing Card ...
    Orig Deck: 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ K♣ Q♣ A♣ 2♦ 3♦ 4♦ 5♦ 6♦ 7♦ [...]
    Shuffled : 6♠ 5♦ 8♣ 10♦ J♠ 4♥ 2♣ 9♠ 2♠ K♦ A♠ Q♣ K♥ 6♦ 6♥ 7♠ 3♥ 2♦ 5♣ 9♦ [...]
    $ java Card
    Testing Card ...
    Orig Deck: 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ K♣ Q♣ A♣ 2♦ 3♦ 4♦ 5♦ 6♦ 7♦ [...]
    Shuffled : 10♠ 8♥ 5♣ 5♥ 5♦ 9♦ 9♣ Q♠ 6♦ 7♠ A♠ K♠ K♥ 7♦ A♥ J♥ 10♥ 2♠ 6♣ [...]
    	      

Calling Card functions from another file

We will be translating the C++ file game.cpp into a Java file Game.java. However, to do that we need to know how to call Card functions/methods from within another class. The answer is simple: the full name of public static method foo defined within class Bar is Bar.foo. Within class Bar we don't need the full name, outside the class we need the full name. For example:
$ java Bar
d[12] = A♣

Structs in Java

The Java version of C++ struct is a class definition that contains data rather than functions/methods. Important! these data elements must be declared public but not static! [We will discuss "public" and "static" thoroughly in a few classes, at which point these will not be arbitrary rules. But for now, you just have to accept them as arbitrary rules. ] You create instances of these struct-like objects using new, like this:
TypeName x = new TypeName();
... and you access fields using a ".", like this:
System.out.println(x.fieldName);

So we might make a struct-like class Player like this:

$ javac Player.java Rat.java
$ java Rat
Jose
$5.0
114 

Translating game.cpp into Java

Finally we translate game.cpp into Java. We will have public class Game, which will have its own public static main function. And the magic of Java is that the main functions of separate classes can co-exist within the same program!
  • A key idea in this translation is that the array created by
    Player[] p = new Player[n];
    ... is an array of references. I.e. p[i] is not an actual "Player", it is a reference to a player object. Specifically, when you create an array of Objects (as opposed to bultins like int or char), you get an array of references that have all been initialized to null. Thus we have the line
    p[i] = new Player();
    inside the for loop. It creates the actual objects that the array elements refer to.
  • Remember that all the functions/methods from Card have to be prefaced with "Card.", since we are outside of the class definition for Card.
  • Note that we get rid of the "delete[]" statements. In Java memory is collected automatically when it is no longer used.
  • $ javac Game.java 
    $ java Game 
    3 Frodo Gimli Merry
    Frodo $5.0 6♦
    Gimli $5.0 8♣
    Merry $5.0 9♦

All together now

It's helpful to see all three pieces together all at once. So here's what that looks like:

It may be helpful to see the original C++ and the Java versions side by side: