Things You Need to Know in Java

(Eventually, Probably Not Today)


This page is about stuff that's in the Java language, and that you should know about when you read other people's programs -- and sometimes you need to use it yourself, but mostly not for the programs you are practicing on in this very short session. Bookmark this link and read through it once or twice, then come back when you need it.

Some of these things are in the language because the academics think they are "elegant" (beautiful, which as the saying goes, "is in the eye of the beholder") but tend to be more complicated and/or less useful than the stuff you learn in the main body of this tutorial. Your brain has a fixed and finite number of neurons. The more brain cells you use up learning trivia and stuff you do not need to know to write great programs, the less you will have left over to help you become a great programmer. It is said that the great (fictional) detective Sherlock Holmes, when told about the discovery of the planet Uranus, said "Thank you, but I shall now do my gest to forget what you just told me," because it was not useful for solving crimes. That stuff will make you a fascinating conversationalist, but it will not make you a great programmer -- unless of course you are writing navigational software for interplanetary space craft. You get to choose: whether you want to be a fun person to be around, or if you want to have fun writing awesome programs. You cannot be both. None of us have a red "S" on our blue tights.
 

Contents

Other Iterations
Switch
String Tools
  "Unsafe" Java String Tools
  Use My "Safe" String Tools
Math Tools
Random Numbers
Exceptions
Threads
Objects and Classes
  What You Need To Know About Objects Today
  A Brief Tutorial on Objects
(more TBD)

Other Iterations

Java has several different kinds of iteration commands or structures. You really need to know about only two, while and for. For-loops are useful because they tell other programmers -- and the compiler, which can use that information to make your program more efficient -- what you intend this loop to do and how many times it should run. While-loops (with break and continue) can handle every other kind of loop.

While-loops nominally test their control variable (or expression) at the beginning. The "do ... while(expression)" loop tests the condition after it has done the loop at least once. Fortran do-loops did that, so people got the idea it was important, because Fortran was the first compiler in wide use (it's still the preferred language for science programs), and because C was modelled after Fortran and Java from C. There, you have the whole reason to use do-while loops. You can do the same thing with a while(true) loop, with a break test at the end (or anywhere else inside the loop, as many as you want or need).

More recent versions of Java have other kinds of iterators that step through the members of non-linear data structures. I don't know anything about them, because I never used them. Maybe they work better than while loops when you need to do that, or maybe they only obscure what is going on, so that you can have bugs in your program that are really hard to find. If you run across one of these, you can Google it, and somebody (perhaps Oracle, if they are still in business if and after the Supreme Court decides in their favor and Google crushes Java) will tell you what they do and how. Of course if Oracle gets what they rightly deserve for being so greedy, Java will go away and be replaced with something else -- I hope not Golang, it's not nearly as well-done as Java, but it's something that Google owns and can control, which transition Oracle is unwittingly trying to force on the world -- and this whole tutorial will need to be replaced. sigh

Like I said, I never use these other loop types. You can if you want to, but it will not improve your standing among your peers.
 

Switch

Like for-loops, the switch/case command structure more clearly spells out your intentions to other programmers and (especially) to the compiler. It was originally designed as a "structured" (single-entry, single exit) replacement for Fortran's (and Basic's) so-called "computed goto" as a fast way to do a many-way selection of one block of code to execute, which would otherwise require a (hard to read) nested series of if-else commands. In practice it's a little more costly than nested if-else commands (unless you have a dozen or more cases), so many compilers will convert a switch with not many cases into nested if-elses. The switch is much more readable, so go ahead an use it, the compiler will generally give you the best code.

The general form of a switch command is thus:

switch (expression) {
case A:
  // some code
  break;
case B:
case C:
  // other code
  break;
...
case Z:
  // more code
  break;
default:
  // do this if nothing takes
  break;}


The case labels (A, B, C,...Z) are constants of the same type as the expression, which must be a scalar type (with discrete ordered values like integer or character, not floating-point nor string). For example, if you are looking at typed-in characters, the expression would be the variable with that input, and the case labels would be each character ('r', 'p', 's' ...) that your program wants to respond to. The break statements are nominally optional -- it was intended to let you put more than one case label to a single block of code (like B and C in my example above) -- but with that one exception, you should never omit the break statements, it will make your code do bizarre and unintended things and breaks the promise of structured code. Unfortunately the Java compiler won't help you here. The default case is also optional, and if omitted, the cases for which there are no case labels fall out and do nothing (which is often a desirable and intended result).

The basic principle of scalar numbers is that they are countable in order, 1,2,3,4,... or a,b,c,... This is not true of real numbers (which floating point pretends to be, and almost succeeds at) where you can always insert another value between any two, like 1.5 between 1 and 2, or 3.141592 between 3.14159 and 3.1416. It is also not true of variable strings of characters using the standard dictionary sort, where you can always insert "ax" between "a" and "b" or "axe" between "ax" and "b". Boolean is a trivial case of scalar, because there are only two values, false and true, so you could make a switch on a boolean value, but why bother?
 

String Tools

Why This Topic Is Here

(Skip down to "Use My Safe String Tools") (Skip down to "Unsafe Java String Tools")

Most of a programmer's life is spent debugging, and a very common debugging tool is to print out the values of variables at various parts of the program, so to see why it's not doing what you thought you told it to do. The Java designers knew that, which is why they created System.out.println for just that purpose, and why they made a simple (albeit confusing) "+" operator for combining labels and values onto a single print line, and why most values automatically convert to String in that context.

Besides debugging, text strings are a powerful (but slow) way to process data in an obvious and intuitive way, which is why all scripting languages that I know of, their basic (only) data type is string, and most of them have powerful and/or convenient tools for manipulating those strings.

Text manipulation is slow, probably slower than native data types by a couple orders of magnitude. For pedagogical programs like you will be writing in this session, that is inconsequential (nobody will even notice), but out in the Real World, writing real programs (the kind you get paid for) for real people, and processing real data -- not just a dozen lines, but thousands and millions of records -- you need to do it using native data types and objects as much as possible. But that is not today.

Java is not a scripting language, and its designers made no effort to make String manipulation particularly easy, other than for printing debug lines. This is one of the reasons Python is so popular as a beginning programming language. But we are not here to learn Python, we are here to learn a programming language that real programmers use in real programs, not the kinds of toy programs Python limits you to. On the other hand, we'd rather not make life more difficult for you than necessary.

Therefore, rather than force you to jump through all the arcane hoops Java puts in front of String users, I wrote a bunch of String utility functions that are much easier to use than Java's finest. Some of these are little more than wrappers around the corresponding Java tools, but set up so that they won't crash your program (and the compiler won't complain), basically I disabled the exceptions that Java strings keep throwing at you.

Some of this happens because I treat the String type as a basic type, and not an Object the way Java intended. There is a strong mathematical reason for that: we all have a gut feel for the way the order you add or multiply numbers does not affect the result (the mathematicians call it "commutative"), so that 2*3 = 3*2 and 4+5 = 5+4, stuff like that. The math in your computer works like that (but for a few odd exceptions with floating-point numbers), and Java does too. We have a gut feel that "numbers is numbers" so that 3+2.7 = 2.7+3 = 3.0+2.7 = 5.7; the computer hardware does not do that, integers and floating point (like their Java types int and float) are different types of data and you can't just add them together without converting the integers to floating point (or the other way around, but that would lose the fractional part). This is so natural in our minds that Java will do the conversion ("promotion") automatically.

Working with text, most of what you want to do is concatenate two strings together, and we all know that concatenation is more like subtraction than addition -- that's why choosing to use the "+" operator is A Bad Idea, but it's done now, it ain't gonna change -- in the sense that "John" + "hit" + "Mary" is not at all the same as "Mary" + "hit" + "John" in the same way that 5-3 gives a different result than 3-5. But there is something symmetrical about promoting numbers to strings when the other operand is a string, which Java does do, but not consistently: "2+3=" + 2+3 does not give you the same result as "2+3=" + 5 (String concatenated to a number promotes the number to String), but it's the same operator as between (2+3) (that was the mistake) and Java, like most programming languages, does sequential appications of the same operators in left-to-right order. The mistake is set in concrete, it ain't gonna change -- and the Java compiler won't warn you.

A single-keystroke for concatenation is too easy to use, it ain't gonna change. Just be careful.

Everything else is done with subroutines -- strictly, they are object methods, and you need a valid Object for the left operand, which is one of the sources of unsafety. I did away with that, mine are not Object methods, the two operands have equal rank and power, as you'd expect if you had not been brainwashed by the OOPS priests. It is perfectly possible to write non-OOPS code in an OOPS programming language, and we all did it, you included, because the first Java programs you wrote in this session are not OOPS (except for the stuff you didn't write).

Anyway, here are some Java string tools you might find useful, followed by my "safe" equivalents (plus a few extras that I have not seen in Java).
 

The (Unsafe) Java String Tools

I call these "unsafe" because using them can throw exceptions and crash your program. To use them safely, you must check your parameters -- especially the object they are run from -- and (ahem) "try" to "catch" all the exceptions. But they are all the Java library offers. I use my "safe" alternatives in GameEngine, and you are welcome to use them too, but eventually you need to write your own. On separate lines I give my "safe" versions, which are linked to their definitions. To find out all about the Java versions, Google "Java name" (no quotes) where name is the name between the dot and the parenthesis in the description below:
 
 
   
Java: lxx = aStr.length();
(mine) lxx = StrLength(aStr);
Java: xCh = aStr.charAt(here);
(mine) xCh = CharAt(here,aStr);
Java: xStr = aStr.substring(here,lxx);
(mine) xStr = Substring(here,lxx,aStr);
Java: xStr = aStr.substring(here);
(mine) xStr = RestOf(here,aStr);
Java: lxx = aStr.indexOf(aWord);
(mine) lxx = NthOffset(0,aWord,aStr);
Java: xStr = (""+(aNum));
(mine) xStr = CvInt2Str(aNum);
Java: lxx = Integer.parseInt(aStr);
(mine) lxx = SafeParseInt(aStr)
Java: xStr = (TorF) ? "tru" : "fls";
(mine) xStr = IffyStr(TorF,"tru","fls");

 

Use My "Safe" String Tools

Most of these are tools I use all the time in my own code, adapted for use in the GameEngine. You can use them if they are helpful, or you can use the equivalent built-in Java methods (where they exist). You might want to copy the ones you like into your own private library of handy tools (or rewrite them more to your own liking). Or you can look inside to see how they work, then write all the safety tests into your own code. Each is linked to its documentation in the Game Engine page(s), which may be more complete than the brief description given here. You can find these and others in the complete Method Summary for JavaGame. All of the character offsets are 0-based, that is, an offset 0 means no characters between it and the front of the string.

static int StrLength(String aStr) // (Java version)

Gets the length of the String aStr without exception, even if (the Java object) aStr is null (length=0).


static String IffyStr(boolean whom, String tru, String fls) // (Java version)

A conditional expression usable in print lines where you might want to print out different labels or different data, based on the value of a boolean or comparison.


static String Substring(int here, int lxx, String aStr) // (Java version)

Gets a credible (possibly empty) substring without exception, even if (the Java object) aStr is null or the offset hereand/or size lxx are outside the the bounds of the string.


static char CharAt(int here, String aStr) // (Java version)

Returns the single character at the offset here in aStr without exception, or the null character '\0' if there is none there.


static String RestOf(int here, String aStr) // (Java version)

Like Substring, but returns all the rest of the string after triming off the front here characters.


static int NthOffset(int whom, String aWord, String aStr) // (almost Java version)

Returns the offset of the string aWord in aStr. If there are more than one, whom>0 skips over that many before returning the offset of the next one. If it is not found, or if you ask it to skip more than there are, it returns -1. The not-quite equivalent Java version lets you skip some number of characters (instead of items).


static int Countem(String aWord, String aStr)

Returns the number of non-overlapping instances of aWord in aStr. For example, you can use this with aWord="\n" to find the number of lines.


static String NthItemOf(char delim, int whom, String aStr)

Given a string aStr with several items separated by a single character delim (like comma or tab or line break '\n'), this extracts data elements, making it easy to generate and parse test (and actual) data for small programs. In particular, when the delimiter is a space, the excess white space in normal text is ignored. The same purpose is partly served using the Java trim() method which removes spaces from the front and back of a word otherwise selected. Unlike normal C and Java numbering, the first line or word or other item is index 1 (not zero), so that normal line numbers work properly -- computers work as if zero is the first number, but real people know that one is first   For example, "Y2K" was a supposed computer problem (mostly fixed by the time the year arrived), but even though the year now starts with "20" we still call it the "21st" century, because there is no "year 0" and no "zeroth century." People are not computers.


static String ReplacAll(String nuly, String prio, String theText)

Returns a new string formed by replacing every instance of prio with nuly.


static String ReadWholeTextFile(String filename)
static void WriteWholeTextFile(String filename, String data)

Java has ways to read and write text files, but they are not nearly so simple as these two one-liners. The filename can be either a full path into any directory your computer gives you access to, or else a simple name and BlueJ puts it in the project folder (or at least it did that on this computer).


static String CvInt2Str(int whom) // (Java version)

The Java concatenate operator automatically converts numbers on the right to String, but it is error-prone. This function makes your intentions explicit, and doesn't fail if there's no string to concatenate to. Other number-to-text conversions must be more explicit...


static String SeeHex(String before, int whom, String after)

This converts your number to hexadecimal and attaches a prefix and suffix, making it easier to use in a debug print line.


static String HexIfMore(String before, int whom, String after)

This gives you the best of SeeHex and CvInt2Str: straight decimal if the number will fit into 16 bits, and hexadecimal (including an automatic prefix "0x" if larger. The assumption is that smaller numbers are really numbers, but larger numbers are probably packed data easier to read as hex by real people.


static String FormFixt(String before, int whom)

Some GameEngine data (notably the animation parameters) is stored as fixed-point fractions, nominally 8-bit integer part + 8-bit fraction in 16 bits -- some components are 2-bit integer + 4-bit fraction, which can be extracted into the larger format by a simple shift + mask (see "Packed Numbers") which is fast and easy -- and I needed some way to format these numbers in an understandable way. You can use it too, if you wish.


static int SafeParseInt(String aStr) // (Java version)

The previous four functions convert numbers to text; this one converts the other way. Java can do it too, but it's complicated with a lot of hassle and exceptions to worry about. I wrote this one from scratch a long time ago, and I keep using it. If it finds a number, you get that value, otherwise you get zero. It skips over leading white space, and the number ends at the first character that is obviously not part of the number (more white space, or else other characters). Numbers that begin with "0x" are read in as hexadecimal, so this is able to read the numbers off a text file that was generated using HexIfMore with no extra effort.

Math Tools

I did quite a lot of bit-packing (see "Packed Numbers" and "Bitwise Operators") to make the GameEngine fast and efficient, but mostly that's behind the curtains. If you decide to be a superstar programmer, you will need to learn those things, but for now you don't need to be concerned. If you need to convert numbers to or from text, the last five functions in the previous section (beginning CvInt2Str) do that.
 

static int SignExtend(int here)

Packing and unpacking numbers are easily done with shifts and masks (as explained in "Packed Numbers") which is fast and easy, no functions required. Extracting a signed number from the middle of a packed integer is a few more steps, so I have a function to do the most common situation, where you want the low 16 bits of a 32-bit integer as a signed number. If you want to do this yourself, it's not hard:
ihalf = (here&0x7FFF)-(here&0x8000);
It's based on the fact that the negative of any single bit is that bit replicated to the left all the way to the high end of its integer value. For example, '1' is the lowest bit in an integer (all other bits =0) so -1 is all bits =1. Integer 4 is binary 0100,  so -4 is FFFC = 1111 1111 1111 1100 (in 16 bits), to which you apply SignExtend to get the low 15 bits = 7FFC = 111 1111 1111 1100, then subtract 0x8000 = +FFFF8000 = +1111 1111 1111 1111 1000 0000 0000 0000, which gives you 0xFFFFFFFC = -4 in 32-bit hexadecimal = 1111 1111 1111 1111 1111 1111 1111 1100 binary.


static int TopBit(int whom)

If you have an integer with random bits in it -- like maybe the bits of a graphic image -- and you want to get to the least-significant (right-most, the way we write numbers) bit, it's a simple one-liner: if the number is in variable whom, the lowest non-zero bit is
lobit = whom&-whom;
The other end is much messier, but sometimes we need it, and TopBit is that function.


static int AddPair(int here, int thar)
static int PairNeg(int here)

Like I said, I pack a lot of data into single integers. It comes from the days when memory cost a lot more than today, but I like to think it still serves a purpose. You don't really need it for the games you will be writing in this session, but here it is anyway. AddPair adds two pairs of 16-bit numbers and returns a pair of 16-bit sums. It might not be faster than taking the numbers apart then adding the parts, then putting them back together, but it's certainly less messy.

To subtract a pair of numbers from another, you take its negative using PairNeg, then add.

Random Numbers

Many games where the human plays against the computer -- or if the computer shuffles a deck of cards or rolls the dice -- require a random number generator. Java has a Random class to generate all kinds of random number, but the most common requirement in computer games is an integer within a specified range.

In C-based languages (like Java) all ranges start with element number zero, and Random follows this rule, so if you want your random number to begin at (for example) 1, you need to add +1 to the result you get back from nextInt. In this example we are asking for a number randomly between 1 and 10 (inclusive). See the comments for what numbers to tweak to get other ranges:

import java.util.Random;  // do this before your class declaration

public class Whatever {
  Random rn = new Random(); // "rn" is an instance of the Random class
  ...
  public static main() { // or any other subroutine in your code
    ...
    int aNum = rn.nextInt(10)+1; // get a random number 1..10
    ...

The argument (10) you give to nextInt is the number of different values you can get out, in this case a uniform distribution from 0 to 9 (inclusive). The +1 is for when you want the range to start at 1. If you want only nine possible values, 1..9 then you'd give it a parameter (9) and still add +1.

Dice have six faces, so you'd ask for  rn.nextInt(6)+1 (twice, once for each die). If you want to shuffle a deck of cards -- at first I was going to tell you how, but then I realized the internet probably has better algorithms than I do, so just Google "Java shuffle a deck of cards" and take your pick. You can't just get a random number nextInt(52) as a card number, because after you deal that card, you don't want its card coming up again until you reshuffle, but a truly random number might. But it would work correctly for a roulette wheel.
 

Exceptions

Bad Things Happen. Usually it's a bug in your code, but not necessarily. Sometimes the data is messed up -- perhaps bugs in the code of the guy who prepared that data, or maybe it was handmade. That's the worst kind.

Bad Things Happen, and robust software needs to deal with it. Sometimes it's a local problem and you can deal with it locally. Sometimes something Really Went Bad, and the only way to deal with it is to get all the way out and into some kind of recovery module. That's what exceptions are for. They are not efficient, so you want to use them rarely, but when you need them, that's what they're for.

Mostly you are not writing that kind of software in this session, and exceptions are a pain in the you-know-where. But exceptions are built into the Java language, and you must deal with them. For student programs you wrap an empty try-catch structure around your code and get on with what you are here to do. It's simple, one word and a brace at the top of the method, and one line at the bottom, like this:

try {
  // all the real code you are here for goes here
} catch (Exception ex) {}
That's all there is. If comething in your code breaks, the Java library code throws an exception, which jumps out to the nearest containing catch, and then (the third line above) does nothing. You will quickly see that your progam failed, and look at the console log, and there in red letters is says what kind of exception got thrown and where, and you get to figure out what went wrong and fix it.

When you get out into the Real World, and you are getting paid to write real software for real people, then you can start to think about all the Bad Things that can Happen, and Google "Java exceptions" (or the equivalent spelling in whatever language you happen to be using) and read about what they do and how you can recover from them, and then write some code inside the braces of that catch clause so that your program recovers and does something reasonable. But that day is not today. Unless you are doing the Calculator project, and we have a whole page to explain more about exceptions there.
 

Threads

Computers run very fast, something like 2 billion instructions each second. Numbers like that are completely incomprehensible to us mere mortals. I read once about a guy who got on a helicopter in New York to fly to the airport or something like that, it was $100 fare, and there were a couple billionares also coming, and one of them was fumbling for his wallet, and the other one said, "Let me take care of it," and handed the clerk another BenFranklin. The guy who was writing about this event thought about it for a while, and realized that $100 to a billionaire is like ten cents to a millionaire, and less than a penny to you and me. Can you imagine flying across town for a penny? Your friend doesn't have one handy? "Let me do that, it's a nothing."

One line in your program is like two or five or ten machine instructions (count the operators and keywords for a reasonable estimate). Your computer can do a billion of those lines in a couple seconds. Most of the time the computer sits around twiddling its thumbs, waiting for you to tell it to do something. When you do, it takes off like a bat out of someplace, and finishes it, and then waits again. When you write a program that waits for input, that's what the computer does: it waits. If you have something else it could be doing while waiting, you must tell it to do that.

Threads are a way of letting the computer do something else while waiting. The mechanism is complicated and hard to get right, but somebody else did the hard thinking about it. When you are playing music on your computer, there's another thread running the music, and the computer jumps back and forth between the music player and your program. You don't need to think about it. You do need to think about it if your own program is so big and slow and has so many things going on and events to wait on, that it's hard to think about slicing and dicing all those tasks without bogging down. Then you use threads to do it. When that happens, Google "Java threads" and there will be a zillion websites eager to help you understand how to do that. But that day is not today.

Delaying one second for a dramatic pause is one thing you might want your program to do today, and Java happens to do that in its Thread class. Think of Thread.sleep as a system function with a dot in the middle of its name, sort of like System.out.println.
 

Objects and Classes

Why This Topic Is Here, and Not In the Main Tutorial

(Skip down to "What You Need To Know Today")

Object-Oriented Programming (OOPS) is for many people a "religion" (believing what you know ain't so, or more precisely, the definition of what is known to be true and obligatory, despite any contrary evidence). Some things in the real world fit nicely with OOPS, some do not, and the OOPS proponents stumble all over themselves to force-fit everything into their OOPS paradigm -- or else just give up and call them "static". In Java you see the first kind in Strings (which should have been made a primitive data type), and the second kind in the Math class.

Aside from the goofy (religious) notion that subroutines ("methods") should be attached to data "objects" and not otherwise, the conglomerate of technology that is OOPS has several useful and productive things to offer the programming community.

A. The override facility that is inherent in subclassing is the first time in the history of computer programming that we had type-safe callbacks. Modula-2 attempted to do it with a "procedure type" but it was not in Wirth's original design and came off rather clumsy. Besides, by then M2 was already a dying language. One of the reasons C programs crash all the time is that programmers just use a typeless callback, and if the call does not match the target, Kaboom! There is a whole industry devoted to trying to find the bugs in C programs after the fact, when in better languages like Java, that kind of bug isn't even possible.

B. When you are building a modular and extendable program like the Game Engine, objects are the only way to keep it under control. I know, I tried it both ways. OOPS is more work up-front, but large programs require that effort anyway, and the modularity in OOPS keeps it manageable. When programs grew beyond a few hundred lines 70 or 80 years ago, subroutines were absolutely essential for controlling the complexity. Objects are subroutines writ large. This is not unique with OOPS (other languages had packages and even C has separately compiled files that confer a degree of modularity) but Objects do a better job of closing off the back doors that programmers like to sneak around into to make programs unmaintainable.

C. I know of no other advantages particular to OOPS. Overloading and generics are cute ideas, but in large software they make the code unreadable. Strong types and structured code have been around in Algol since I was in college 60 years ago, and Algol did them better than Java does. Algol died of old age. Ada died of obesity. M2 died in the famine brought on when C-water overran the food crops. C and Java and Python are what we have left. And (retch) JavaScript. Java is far and away the best, but OOPS is only a tiny part of that.

Small programs are easier to write apart from OOPS -- we did that in this session. The Real World is made of huge programs -- most of them in C with more bugs than a downtown walkup flat. Strong data types and Objects (in that order) make robust large software possible. After you've done it for a while, you'll see what I mean. Or not. Not everybody is as analytical and introspective as I am. Whatever. Be your best.
 

What You Need To Know About Objects Today

Java requires each data structure to be in its own class, which is a separate source code file, a separate compilation, a separate yellow rectangle in the BlueJ  dashboard window. That's if you are creating your own data structures, which is really an advanced topic. For the training programs you are doing in this tutorial, and for the games you will be writing, that's mostly not going to happen. Somebody else already did all the classes you need to use. Farther down on this page is a brief introduction on how to do what you need to do, if it turns out you need to do it in a game you are writing for this session.

Anyway, in OOPS languages (including Java), you get access to subroutines (methods) in other parts of the program by reference to an object of the class where that method is defined, or if no object makes sense, by reference to the name of the class itself. System is a predefined class in Java, so when you want to print or read standard input, you use a public object defined in the System class, and then by that object you get to call the method.

When we started out, "System.out.println" was nothing more than a long name with a couple dots in it. Actually, you are using a method defined for the PrintStream class, and the println method is accessed by means of the object reference "out" which is a public static instance variable in the System class. The moniker "static" means that (outside the class, which in your case is always for class System) you use the name of the class + "." + the name of the variable or method to access it ("System.out"). Once you have a variable or other object reference, you use that variable name + "." + the method name (in this case "println") to access (call) the method. If the class which that reference is an object of has its own static variables, you could see them by the variable name (instead of "println"), but that's probably deeper than you need to go today.

I wrote a simple class Zystem to make getting input simpler. You can 2-click its yellow box in BlueJ and see its contents. All its methods are static, so when you want to call one of them, you use the class name + "." + the method name, as for example, "Zystem.ReadLetter()" to read an input letter.

I wrote a huge hairy class "JavaGame" to comprise most of my GameEngine logic. Some of its methods and constants are static, so to use them you use the class name + "." + the method name, as for example, "JavaGame.CvInt2Str(num)" to safely convert an integer to a String, or "JavaGame.Arro_LEFT" to get the constant name for the left-arrow key used in this game engine. A few of the methods you might need to use are not static, so you need a reference to an instance of the game to access them. You created that instance -- actually I wrote that, you just used it -- in the main() program of your game class, but a copy named myGame is made in your game class, and you can use it. The generated code uses it to find the references to your widgets in the StartUp method in your game class, such as

theBall = myGame.FindListWgt("{theBall}");


I wrote two other classes, both a lot smaller than JavaGame, and you need more interaction with them. Mostly you will interact with widgets, which are objects of class GameWgt. There are a lot of methods for interacting with widgets, and you access these methods by using the name of your widget + "." + the name of the method, for example (if you wanted to move this ball to the top-left corner of the game board) theBall.SetPosn(0,0);

Your whole game is a subclass of my base class GameEvent, and most of what you do there is respond to events using event handlers, which are a special case of what I called "callbacks" above, methods that are carefully defined (in this case by me) so that when you declare such a method, it exactly conforms to the type signature I specified (or else the compiler or linker won't connect it), and it cannot crash from being the wrong type when the GameEngine calls your method because an event happened. All the event handlers you might need to use in your game are generated in stub form when you Build your game, so they are already in the correct form; all you need to do is add code to do what you want them to do. OOPS makes that possible, and it's a good thing.
 

A Brief Tutorial on Objects, for Future Reference

(TBD)
 
 
 
 
 
 
 

Revised: 2020 November 10