Seapegasus Blog

All | Hacks | Java Mobility | Mac | Misc | NetBeans | NetBeans_de
« Previous day (Nov 29, 2006) | Main | Next day (Nov 30, 2006) »
20061130 Thursday November 30, 2006

Taking Notes During Java Class (3)

I already posted my notes from Monday and Tuesday, these are mostly the ones from Wednesday.

Array creation (rows & columns): Everytime I create an Array such as int[][] myArray = new int[r][c] I wonder which dimension is which: Okay, the first dimension is rows and the second columns. If it was a table, you'd first move down vertically and then horizontally to the right. This order makes sense since you often want to loop over array data: You loop slowly over the rows and within each row you loop quickly over each column.
Mnemonic: The order is similar to writing on paper, first you go down to a row (line), then you fill up this line's columns (with letters from left to right). And when the sheet is full, you pull out a new sheet or turn the page, and put it on top of the previous one: That's the third dimension where the content gets stacked in layers on top (so the order is 3dArray[rows][columns][layers]). I prefer the sheet-of-paper metaphor over the Czech "beer crate" metaphor -- beer crates are stacked too, but you don't necessarily fill them with bottles rows-first and then columns (as opposed to letters on paper).

Array creation (dimensions & size): Only the first dimension has to be specified when creating the array: int[][][] myArray = new int[3][][]. The other dimensions can be specified later as soon as they are known. This means, arrays can be assymetric by creating each array of the second dimension with a different size.

myArray[0] = new int[45]; myArray[1] = new int[14]; myArray[2] = new int[21];

See? This array has three rows, the first row has 45 columns, the second one 14, and the third one 21. Make sure to use myArray[i].length in the loop to prevent IndexOutOfBounds exceptions.

The following array creation syntax I habitually get wrong, especially for more-dimensional arrays... We can define an array and fill it in one step if we should need to:

int[]   myArray2 = new int[]   {4,4,6};
int[][] myArray3 = new int[][] {{4,1,6},{4,6,5,7},{6,6},myArray2};

For higher dimensional arrays you can create several 2-dimensional ones, and then create arrays of arrays and so on.

Polymorphism: Java variables are polymorph, this means a variable can also contain data of its subtypes. (is that a good definition?) E.g. a Button goes into a Button, Container, Component, or Object variable. Say you create a class myObject and then create subclasses which extend myObject (e.g.myCar, myDog, myHouse). Each of the subclasses has their own doSomething() method (e.g. myCar.doSomething() honks, myDog.doSomething() barks, and myHouse.doSomething() gathers dust).
If you now have lots and lots of cars, dogs and houses, and you want to show off all of them, it would be quite a nuisance to loop over a myCar array, and then over a myHouse array, and then over a myDog array and call .doSomething() on each type. Instead you put all of these objects into a more general myObject array and call the same method doSomething() on each of them; each will remember what it actually is and execute the method that is typical for it. (hopefully)
In case you get confused which object is of what type, use obj.getClass() to identify its class, or test a class with the instanceof operator, e.g.

if( myCalendar instanceof java.util.GregorianCalendar ) ...

Cast: (Downward) casting of a variable to a different type is actually somewhat the opposite of the polymorphic usecase just mentioned.

int i = 4; double d = (double)i;

Instead of more general, the variable now gets more specific, e.g. after casting an integer to a double data type, 4 becomes 4.0. Interesting, I never looked at polymorphism/casting from this point of view.

Boxing: There are primitive types (like int, bool, float, char) and complex objects (like String, Boolean, File, Date). Officially the content of an array must be all objects. So what to do if you need an array of ints, bools, or chars? Well, for this purpose there are "grown-up" object versions of these primitive types, int -> Integer, bool -> Boolean, char -> Character etc. (note the capitalization). The object versions are called wrappers. Wrapping (converting) a primitive int into an Integer object is called boxing, reverting a big fat Integer back to a slim primitive int is referred to as unboxing.

A second common usecase for those Wrapper classes is type conversion: You read input (from the commandline or from a textfield etc.) as String, and, if it represents a number, use Integer to convert it to an int.

int i = Integer.parseInt(str);

Nowadays, Java performs many of those conversions automatically (autoboxing) -- it works well but be aware that this conversion causes an invisible overhead, so don't rely on it if performance is important. Stay aware whether you use actual primitive or (invisibly) auto-unboxed primitives in your code.

Static vs instance: Static fields and methods are the opposite of instance fields and methods. Instance fields are meant to be used by instances of the class individually to store their data. Static fields and methods are meant to be the same for each instance. Static methods cannot look into instances and cannot use values from instance variables -- you exclusively use them for things that are completely independent of indiviual instances. This is why static methods are not called on an object, they are called directly on the class (cf Integer.parseInt() above, it creates a new Integer from a String, but it does not depend on any existing Integer value to do that).

More notes are on their way, stay tuned, I can't type that fast. :-) And correct me if you find errors or want to recommend your best practises.

Posted by seapegasus ( Nov 30 2006, 05:18:44 PM CET ) Permalink Comments [3]


Taking Notes During Java Class (2)

Continuing from Monday's class, this is mostly Tuesday stuff...

The + Operator: As you know the + operator is overloaded, it responds differently depending on the type of its arguments. If both arguments are numbers, it converts them to the bigger type of both numbers (int to float, float to double) and adds them. (Watch out to which datatype you cast and assign the result back to -- this can have strange side effects which are not always easy to diagnose.) If one of the two arguments is a String, the second one will be converted to String too (automatically using its toString() method), and a new String is created containing both (string concatenation). Well you knew that, it gets slightly more interesting with more than two arguments, because the precedence is from right to left: So "foo"+2+40 will be "foo42", if it's 2+40+"foo" it will be "240foo". That makes a difference...

Efficient Strings: Since Strings are immutable objects, each use of the + operator for String concatenation causes a slight overhead, since a new String object has to be created. This is no problem if you use the operator only in a few isolated cases. If you however plan to change a String a lot after its creation, use a StringBuffer instead of String. StringBuffer (as envoking code completion on a StringBuffer object will show you) has lots of useful append and insert methods for this purpose.

What is this.thing? You often see code like this

int day; // instance variable
public void setDay( int day ) // local variable
            { this.day = day; }

The "normal" day in the method body refers to method argument as expected, whereas this.day is a reference to this object's (!) instance variable with the same name. If you are not sure whether it is "this.day = day;" or the other way round, you can just as well write

public void setDay( int d ) { day = d; }

(To Java both variants are the same, the difference is mostly about readability).

The AND operators "&& versus &" You can connect the outcome of some boolean methods in a conditional statement with AND operators called && and &. The difference between && and & is: If you test for a() & b(), both a() and b() will be executed. If you test for a() && b(), first only a() is executed -- and b() will only be executed if a() has returned true. As you see the destinction is relevant if your methods have side effects, or if b() takes a while to compute and you want to save time. The same is valid for the OR operators | and ||, in this case b() will only be executed if a() was false.

Execution Stack (Call Stack) vs Heap: You don't have to know that, but it's interesting to see how what you learned about stacks and heaps resurfaces in actual programming languages. Say when you calculate something recursively (either on purpose or by accident), you can get a stack overflow after 400 recursions... Each recursive call to a method creates a new entry on the call stack and recursion can reach the stacks limit since all of the first calls have to wait for the later ones to finish. If the recursion was on purpose and you really need to implement something with a deeper level of recursion, you allegedly can increase the size of the stack, though.

Reading input from commandline This is pretty basic, I'm just dotting it down because I can never remember it.

InputStreamReader ir = new InputStreamReader(System.in);
BufferedReader in = new BufferedReader(ir);
while ((s = in.readLine()) != null) {
   System.out.println("Read: " + s);
}

(It needs a try/catch-block which I skipped here since netbeans will lightbulb it into the code anyway... Hm. Is "to lightbulb" a real verb?)

Can anybody please help me out with a mnemonic for these steps? Intuitively, it's not exactly obvious. All I want is to read from the commandline... Why do I need all those BufferedReaders and InputStreamReaders -- why isn't it something simple like s=System.in.readline() and Bob's your uncle? Instead I create a Reader from the inputstream, and THEN, I create a second Reader from the first reader?! What else does this thing think I am doing with System.in apart from reading it? Why doesn't the System.in offer reader and stream methods from the start? *shrug*

Posted by seapegasus ( Nov 30 2006, 12:20:54 PM CET ) Permalink Comments [3]


Taking Notes During Java Class (1)

A random collection of things I (re)learned in this week's Java class... (just jotting down my notes somewhere so I don't forget them) =-)

Pointer? Reference? There are no pointers in Java, "pointers" to objects are called references. One of the differences is that you cannot do pointer arithmetics on Java references. (Believe me. I tried.)

Function? Method? Procedure? A function always returns a value; a procedure does not return a value but it has a side effect (changes data, switches states). In Java both kinds are called methods. Functions are rendered as methods with a return type, and procedures are methods with a return type of void.

Naming convention:

Object-oriented development steps: 1) Analysis: What do you want your program to do? = Determine what kinds of objects you will need. 2) Design: How will the program achieve its goal? = Determine what kinds of methods the objects need. 3) Implementation...

println(myObject) When you print an object for debugging purposes, you only get its reference ID, not its content printed. To see the actual object contents, override the object's toString() method with a return statemaent that returns all fields concatenated into one string. (e.g. using a for() loop) -- I used to create an extra print() method for that purpose, but of course this approach is more obvious and flexible since toString() will work in any String context.

Pass-by-value? Pass-by-reference?

To be continued...

Posted by seapegasus ( Nov 30 2006, 09:45:23 AM CET ) Permalink Comments [2]


Calendar

Content

Search

Links

RSS Feeds

Recent...