Göm menyn

TDDC69 Objektorienterad prog. och Java

Labb 1: Introduktion

Den första laborationen är utformad för att ge er en chans att börja med vissa praktiska aspekter av objektorienterad programmering i Java så tidigt som möjligt, så att vi kan varva teori (föreläsningar) med praktik (labbar) istället för att vänta till de flesta föreläsningar är avklarade.

Eftersom vi börjar så tidigt går vi ännu inte särskilt djupt i de objektorienterade begreppen i denna labb. Istället ligger fokus på att ge ett första smakprov på Java och att demonstrera användbara funktioner i utvecklingsmiljön, vilket ni kan ha stor nytta av under senare laborationer och under projektet. Laborationen är i "tutorial"-form där ni ges konkret ledning i varje steg.

Uppgifterna ni får här kan verka väldigt enkla. Det är meningen! Poängen är just att ni får praktisk erfarenhet av de enklaste aspekterna av Java samtidigt som ni lär er utvecklingsmiljön. När det steget är taget går vi vidare och ökar komplexiteten gradvis.

Den utvecklingsmiljö som används är IntelliJ IDEA. Läs även sidan om utvecklingsmiljöer innan ni går vidare.

Just denna labb är för närvarande på engelska. Resterande labbar kommer att vara på svenska.


Starting IDEA, Creating a Project

Use the following command to copy a couple of necessary files for IDEA:

   ~TDDC69/bin/installidea.sh

Then use the following command to start IDEA:

   ~TDDC69/idea/bin/idea.sh

If you get warnings about the encoding 'UTF-8', please ignore them.

After a while, you will see the IDEA startup screen, which looks approximately like this. (In this screenshot, IDEA is running on a Sun machine but windows are displayed on an X server on a Windows 7 machine.)

Follow these steps to create your first IDEA project.

  • Click "Create New Project" or select File | New Project.
  • In page 1 of the resulting dialog window, "Create project from scratch" should be preselected. Press Next.
  • On page 2, give your project a name, for example "TDDC69-lab1".

    Tell IDEA where the project files should be stored (including all the source code you will write). The default location, a folder named IdeaProjects in your home directory, may not be ideal if you already have a directory structure for your courses.

    Change the project file format to ".ipr".

    An IDEA project consists of a set of modules, where each module can be used in multiple projects. You will use a single Java module for this project. Leave the checkmark indicating that a module should be created. Change the name to "lab1", but leave the content root and module file location unchanged.

    Press Next.

  • Page 3: IDEA wants to know where to store source files for this project. Leave the default path unchanged and press Next.

  • Page 4: IDEA wants to know which JSDK, Java Software Development Kit, you want to use. No JSDK is configured at this point, so press the configure button and navigate to /usr/jdk/instances/jdk1.7.0. Press OK and then Next.

  • Page 5: IDEA wants to know if you need any web-related frameworks or class libraries. You don't so leave all checkboxes empty and press Finish.

You have now created a project. IDEA loads the project files and begins scanning and indexing the Java Development Kit files in the background. This may take a while, but you can continue working with most tasks in parallel.

(If you get a "tip of the day" dialog, you can dismiss it.)

The project view may be hidden by default. If so, open it by pressing Alt+1, clicking "1: Project" at the top left, or selecting View | Tool Windows | Project. This will display the structure of your project. You can expand the view to show all relevant directories and files, including a set of external libraries that your project uses – at this point, only the JDK.

Exercise 1: Shape, Circle, and Rectangle

In this exercise, you will implement a few simple Java classes. We assume that you have already started IDEA and created an IDEA project as shown above.

Note again that the entire point of doing this lab is learning how to use IDEA. The end result does not matter -- we want you to explore some of the functionality available in the environment, and therefore you should make sure you actually use code generation, navigation and other features as described below. Just typing everything from scratch might get you through this tiny lab more quickly, but you won't learn as much and you will waste time during the much larger project.

First, a Shape class.

  1. Follow the instructions below to create a class called se.liu.ida.youremail.TDDC69.lab1.Shape, where youremail is your e-mail address (noone123) or possibly two e-mail addresses (abcde123.fghij456)

    To create a Java class (or interface) in IDEA, first determine (1) the name of the package that should contain the class and (2) the name of the class. Right now you want to create a class called Shape in a package named something like se.liu.ida.noone123.tddc69.lab1.

    The left-hand side of the screen should show the project pane. If it doesn't, select Window | Project: Alt-1.

    In the Project tab of the project pane, you see all modules within your project (though in this course you only use one module). If you double-click the module (a folder icon with a blue cube), you should see a directory/file hierarchy. You can also see the Java class libraries used for your project. This corresponds to the CLASSPATH for a command line system.

    	    [-] ### Lab1         (module, folder with blue cube)
    	    |   |  ### src       (src subdirectory)
    	    |   +--### Lab1.iml  (module definition file, may not appear until later)
    	    +--### Lab1.ipr  (project definition file)
    	    +--### Lab1.iws  (personal workspace config file)
    	    [+] ### External Libraries
    	  

    Since this is the first time you create a class, you don't have any packages yet. It is time to create the package that should contain your new class. Right-click the src node. It is blue to indicate that it is a source path -- you can have more than one, but yellow directories are just plain directories. Select New | Package to create the package, "se.liu.ida.noone123.tddc69.lab1" (with your own account name, of course).

    You will see the package hierarchy as a directory tree. If you think this tree is too deep, you can flatten it using one of the toolbar icons in the project pane.

    Now right-click the destination package and select New | Class to create a new class in the package. Specify the name of the class you want to create, for example "Shape". The full name of the class is then "se.liu.ida.noone123.tddc69.lab1.Shape".

  2. The class should have a constructor without arguments, Shape(), which prints "A shape is constructed".

    Position the cursor where you want the constructor (you may have to insert a few newlines). Select Code | Generate: Alt-Insert. Select "Constructor". An empty constructor is generated.

    In the constructor, enter sout and press TAB. The "sout" live template is automatically expanded to System.out.println(); and the cursor is within the quotes. Enter the rest of the text: "A shape is constructed".

    Notice the syntax highlighting. For example, IDEA knows that System.out is a static field, and highlights it accordingly. The highlighting can be adjusted in the settings (File | Settings: Ctrl-Alt-S).

    Try pressing Ctrl-Q when the cursor is in System, in out and println. This shows a "quick javadoc" popup.

    Also try pressing Ctrl-B when the cursor is in println. Ctrl-B (or ctrl-mouse-click) navigates to the definition of an element. In this case, it navigates to the source code for one of the overloaded println variations in class PrintStream.

    Press Alt-Left to return to where you were.

  3. The class should also have a method void draw() which is both public and abstract. Like methods in interfaces, abstract methods have no implementation: They end with a semicolon instead of with a block of code.

    Add this method manually.

    Since the class is not declared abstract, public class Shape will be underwaved in red, and the little square in the top right corner of the editor will be red. There will also be a red error stripe in the stripe bar located close to the scroll bar. The position of this error stripe corresponds to the proportional position of the error within the current source file.

    Go to the error using Navigate | Next Highlighted Error: F2. You will notice a small yellow or red light bulb popping up. This is the indication that an intention action is available — an action that helps you fix an error by guessing what you meant to do. (No, this is not like the MS paperclip — the suggestions are usually useful...)

    Click the light bulb or press Alt-Enter to pop up the intention menu. You will see one entry: "Make 'Shape' abstract". Click this or press Enter to select it. The class is now abstract.

    If you instead click the right arrow within the menu, or press cursor right, a set of options related to the intention action should pop up. One option should be to turn off the intention action so that it does not pop up automatically in the future. The intention action can still be invoked by pressing alt-enter with the cursor placed appropriately, after which you can turn the intention action on again if you want.

Then, a Circle class.

  1. Create a concrete class Circle in the same package, as a subclass of Shape.

    Create the class just like before. Add extends Shape manually. The declaration is now underwaved in red. This is because we have not yet implemented the abstract method in Shape. Ignore this error for now.

  2. The class should have three public int fields — an x coordinate, a y coordinate, and a radius.

    Add these fields manually.
  3. Add a constructor with three arguments (x, y and radius), which saves the values of the arguments in the three fields and prints "A circle is constructed".

    Like before, create this constructor by placing the cursor where the constructor should be and using Code | Generate | Constructor: Alt-Insert. Mark the fields whose values should be initialized by the constructor (click the first, shift-click the last; using the keyboard: go to the first, press shift-down to extend the selection downwards) and press OK. Initializers are added automatically. Use sout to add the printout.

  4. Implement a concrete draw() method that prints "A circle is drawn".

    To implement an abstract method, place the cursor where the method should be and use Code | Implement Methods: Ctrl-I. Select the method(s) to be implemented in the dialog. Use sout again.

The third shape class is called Rectangle. Do you remember how you did this before?

  • Create a concrete class Rectangle as a subclass of Shape. The class should have four public integer fields — an x coordinate, a y coordinate, a width, and a height.

  • Add a constructor with four arguments (x, y, width, and height), which saves the values in the four fields and prints "A rectangle is constructed".

  • Add a draw() method that prints "A rectangle is drawn".

Finally, a test class.
  • Create another class ShapeTest, which has a main method.

    Use the template psvm to create the main method.

  • In the main method, you should allocate a Shape[] array with 4-6 elements and fill it with circles and rectangles (created using new).

    Try using IDEA's "introduce variable" function. First, type the expression you want: new Shape[5]. Then, use Refactor | Introduce Variable: Ctrl-Alt-V to introduce a new variable for this expression. You can enter a name for the new variable, or just accept the default name. Press Enter.

    This function is quite useful when you want to refactor a very long expression and separate it into smaller parts. Just select a subexpression and use Refactor | Introduce Variable: Ctrl-Alt-V to introduce a variable.

    Note that the new variable is highlighted. This is because it is currently unused.

  • Make sure you didn't just allocate the Shape[] array but that you actually created few circles and rectangles to place in the array!

  • Then, iterate over all elements in the array and call their draw() methods.

    Use the itar live template to iterate over a native Java array. Select Code | Insert Live Template: Ctrl-J and select itar from the menu; this is another way of selecting a live template.

    Now you see why it is called a live template. A number of places in the generated code are outlined in red; these parts can be edited as part of the template. The first one, where the cursor is, is the loop variable, which is usually called i; try typing "index" to rename the variable. Press TAB to reach the array over which we iterate; as you can see IDEA has correctly identified the two arrays that are available in this scope (args and your own array). Pressing TAB again takes you to the variable in which each element is stored. Pressing TAB a final time deactivates the template and puts the cursor where you want to continue typing your code.

  • Extend the code within the loop. If the shape is an instanceof Circle, you should also print the circle's x and y coordinates.

    Start using IDEA's code completion. Type "if (sh[ctrl-space, select shape] inst[ctrl-space] Cir[ctrl-space]) {[enter]".

    Try printing the value of the x field:
    System.out.println("X coordinate is " + shape.x);

    As you notice, you can't do this because you must first cast shape to a Circle. Place the cursor within the word shape and press Ctrl-W. This selects a single word; repeated invocations select larger and larger structures, and Ctrl-Shift-W unselects one step at a time – try it!

    When you have selected shape, select Code | Surround With: Ctrl-Alt-T and then select "((type)expr)". You will get most likely get println(((Circle)shape).x), because IDEA analyzes the preceding code and sees that you have just checked whether Shape was a Circle. If IDEA was correct, you press TAB; if it was wrong, you can select another type from the dropdown or simply overwrite the suggested type.

    Do the same thing for the y field.

What is printed when you run ShapeTest (see instructions below)? Which methods and constructors are executed, and in which order? Make sure that you understand why.

Compiling a project in IDEA

You can compile the entire project using Build | Rebuild project, or use Build | Make Project (Ctrl-F9) to only recompile the files that have changed and the files that depend on them.

Running a Java program in IDEA

Running a program (a class with a main() method) in IDEA requires a run configuration. You can create new run configurations in the following way:
  • Select Run | Edit Configurations. In the dialog window, press the "+" button to create a new application configuration. Give it a name, and specify a main class (use the "..." button to select a class!).

    "VM parameters" are given to the Java virtual machine. Normally this box can be left empty.

    "Program parameters" are the command line parameters specified for your program (given as arguments to the main() method).

    The "working directory" is the directory where your program is started, and is only relevant if your program opens files relative to the current directory.

    In "Use classpath of module:" you should select the module the program "belongs" to. In your case this is quite simple: You only have one module.

    Click  OK .

You can then run your program by selecting a run configuration in the drop-down menu beside the green "play" button in the toolbar, and then pressing the "play" button.

As a shortcut, you can also create a temporary run configuration for any program with a main() method, and then immediately execute this run configuration, in the following way:

  • Right-click the editor for the class you want to run. Select "Run MyClass.main()".

Exercise 2: Data Hiding

In the previous exercise, all the fields you created were public. Now you realize your mistake: They should have been private! Make them private, introduce getters for all the fields (and setters, if you want to), and make sure that you use the getters and setters wherever this is necessary.

Go to the Circle class: Select Navigate | Class: Ctrl-N and type "Cir" (which is auto-expanded), followed by Enter.

Choose Refactor | Encapsulate Fields. Select the checkboxes for x, y and radius to encapsulate these three fields. Select Get Access to create getters, and unselect Set Access (you do not want to create setters). Make the encapsulated fields' visibility private, and the accessor methods' visibility public. Unselect Use accessors even when field is accessible, so that you don't have to use the accessors within Circle, only outside the class. Click Preview . You will get a refactoring preview, where the two uses of x and y in ShapeTest are shown. Here you can unselect items that you don't want to change, if any. Then you click Do Refactor: Alt-D.

Do the same thing in Rectangle. Since we never used Rectangle's fields outside its class, the refactoring preview only contains the fields themselves.

Exercise 3: Changing the Internal Representation

In this exercise, you will extend the program you wrote in Exercise 1 (Shape, Circle, Rectangle).

Create a new class Point. This class should have:

  • Two private integer fields, x and y.

  • A constructor with two arguments, x and y.

    Use Generate Constructor as before.

  • Two accessor methods getX() and getY() that return the x and y coordinates.

    Create these methods by placing the cursor where they should be and then using Code | Generate | Getter: Alt-Insert (mark the fields for which you want to generate getters).

Rewrite ("manually") the Circle class so that it uses a Point object instead of the old x and y fields. The old constructor should still exist, and should still take x and y arguments, but instead of saving x and y directly, it should create a new Point object that it stores in a Point field. You must also rewrite the two getters.

Rewrite the Rectangle class in the same way.

Exercise 4: Implement equals() and HashCode

In this exercise, you will extend the program you wrote in exercise 3 by implementing equals() and hashCode() methods for Point, Rectangle and Circle. (If you don't know what a hash code is, you could take a look at the definition in the Java Glossary or maybe in Wikipedia.)

To automatically generate equals() and hashCode() methods in a class, select Code | Generate: Alt-Insert and then select equals() and HashCode(). Select the fields that should be included in the comparison for equals and then for hashCode. Should you select all fields or only a few? This depends on which fields you think have to be equal for two objects to be considered equal!

If there are non-primitive fields (object-type fields such as the Point field in Circle and Rectangle, then IDEA will ask you for a set of non-null fields. A non-null field is a field whose value cannot be null, so that IDEA does not have to insert a null check for this field. If in doubt, do not select any non-null fields at all. This is always safe, but may be slightly slower. In this example, though, we know that the center of a Circle is never null (always an actual Point).

Take a close look at the methods that are generated and ensure that they are what you intended. Never trust a code generation tool completely. Always double-check what has been generated. Tools are no substitute for knowing what you're doing!

Exercise 5: Using the Collections Framework

In this exercise you will begin using the Java Collections Framework. This framework will be part of lecture 4 in TDDC69, but the lab should provide sufficient guidance for you to continue even without having seen that lecture.

Your main task is to create two new data structures, a Queue and a Stack. These structures will use the ArrayList class of the Java Collections Framework, but unlike a plain ArrayList, they will not allow the user to add or remove inner elements: you can only push and pop elements at the correct "end".

  1. Create a Queue class which does not extend any class.

  2. Add a List field: private List myList.

    Since you haven't imported java.util.List, IDEA will ask you whether you want to do so now. Press Alt-Enter to accept and choose the correct List class (the one from java.util).

  3. Add a constructor with no arguments, which creates an ArrayList.

    If you use Generate Constructor as before, note that you should not mark any fields to be initialized by the constructor -- because the ArrayList should not be given as a parameter to the constructor, it should be created inside the constructor. Use "Select None" in the field dialog.

  4. There are some methods from ArrayList that should be available in Queue too. For example, the size() method should be available in Queue. You can forward or delegate these method calls to the Queue by adding a method public int size() which simply returns myList.size(). (Keep reading!)

    The methods you should delegate to ArrayList are size(), isEmpty(), clear(), and contains(Object).

    Select Code | Delegate Methods. Select the target myList. Select the methods you want to delegate (click the first one, ctrl-click the second, ctrl-click the third, and so on). Press OK.

  5. Add the two new methods void push(Object obj), which adds an object at the end of the list, and Object pop(), which both returns and removes the first object in the list.

Then write a Stack class, which is similar except that pop() returns and removes the last object in the list.

Press F5 while visiting the Queue class to create a clone of that class. Select Stack as the new name. Change the new class according to the instructions above.

Finally, you should write a test program that uses your new classes. For example, you could write a test program that adds some strings to a Queue using push(), and then pop()s all the strings, one at a time, and prints them to the screen. Do the same thing using a Stack.

Exercise 6: The Collections Framework: Sorting and Iteration

Write a program that sorts all its command line arguments in alphabetical order and prints them to the screen.

First, create a list (ArrayList or LinkedList) and add all command line arguments to that list.

Then, sort the list using the static utility method Collections.sort(List list). This method is placed in the utility class Collections rather than in any specific list data type because it can be used for any List.

After typing "Collections.sort(", press ctrl-shift-space to see all items of the appropriate type, that is, all items of type List. This is called SmartType Completion and automatically filters out all items except those of the correct type.

The reason for not using SmartType Completion always is that you may have to go through an intermediate step before you reach the intended type. For example, if you had wanted to type Collections.sort(foo.getBar().getList()), you would have had to use Basic Completion to complete foo and getBar(), and then you could have used SmartType Completion to complete getList().

Finally, print the resulting list by iterating over it using the specialized "for" loop for arrays and collections.

To test this program, run it with some command line parameters to sort.

Create a new run configuration as described earlier in these instructions. Add your command line parameters in the "Program parameters" field. Do not add them in "VM parameters"; those parameters are given to the Java virtual machine, not to your program.

Exercise 7: Rename some Fields

Finally, you just realized that you don't want the x and y coordinate fields in Point to be named simply x and y. Instead, they should be named xCoord and yCoord. Rename them.

Let's suppose you were in the Circle class when you got this idea. If you're not already there, go to Circle using Ctrl-N.

Hold down Ctrl as you move the mouse around the code. You will see tooltips showing information about the items over which the pointer is hovering.

Now ctrl-click Point in the code. You will automatically be moved to the Point class.

In Point, go to the x field and select Refactor | Rename: Shift-F6. Enter the new name for this field and press Enter. IDEA will ask you whether it should also rename the getter; please do so.

If you have referred to x in "plain text", for example in comments, you will get a refactoring preview where you can choose which occurrences of "x" should be changed – IDEA knows what to change in the code, but in comments, it is impossible to tell whether a certain "x" refers to the field Point.x or to something else. After verifying that everything is correct in the refactoring preview, click Do Refactor: Alt-D.

Do the same thing for y.

The end

That's it: You've finished the IDEA exercise. You should now ask the lab assistant to take a look at your code. When this is done, you can hand in the code according to the instructions. If no lab assistant is available right now, simply continue with the next lab.

© 2005-2012 Jonas Kvarnström

Sidansvarig: Jonas Kvarnström
Senast uppdaterad: 2012-08-31