Java Basics

  1. Learn how to use terminal. First, figure out how to open a terminal window (a.k.a. command shell, a.k.a. console) in your favorite operating system. (If you have trouble finding the terminal window, use your favorite search engine to get some help.)

    Next, search for a simple tutorial about using shell commands. I recommend spending at least 15 minutes becoming comfortable using a terminal. This will be important for your survival throughout the rest of this semester.

    Make sure you are at least comfortable using each of the following commands:
    • "cd [dirname]" to change directories.
    • "cd .." to back up one directory.
    • "ls" to list directory contents. ("dir" on Windows.)
    • "mkdir [dirname]" to make a new directory. ("md [dirname]" on Windows.)
    • "rmdir [dirname]" to remove an empty directory. ("rd [dirname]" on Windows.)
    • "rm [filename]" to remove a file. ("del [filename]" on Windows.)
    • "rm *" to remove all the files in the current folder. ("del *.*" on Windows.)
    • "nano [filename]" to open a file in a crappy text editor. ("notepad [filename]" on Windows.)
    • "cat [filename]" to print the contents of a file to the shell. ("type [filename]" on Windows.)
    • "echo banana" to print "banana" to the console. (Also works with grapes and pineapple =)
    • "cp [fileA] [fileB]" to make a copy of [fileA] named [fileB]
    • "thunar ." (in XFCE), "dolphin ." (in KDE), "nautilus ." (in Gnome), "open ." (in OSX, the Mac window manager), "start ." (in Explorer, the Windows window manager) to open the current folder in a GUI.
    • "exit" to exit the terminal.


  2. Choose a text editor. We will do a lot of text-editing in this class, so please find a light-weight text editor that you like better than nano (or notepad). Do not choose an IDE. You are not allowed to use an IDE for assignments 1 or 2. NetBeans, Eclipse, IntelliJ, VisualStudio, and XCode are IDEs, and they are banned until assignment 3.

    IDEs are are not light weight. On Linux, I like "kate". "gedit" is decent. The hard-core users seem to like either "vi" or "emacs", but I do not recommend either of these editors because the barrier-to-entry is very high. On Windows, "notepad2" is less-awful than "notepad". On Mac, I have heard that Komodo Edit is a good choice. If you have other suggestions, the class forum would be a good place to say so.



  3. Make sure you have a current version of the Java Development Kit (JDK) installed:
    Open a command shell or terminal. Enter this command:
    javac -version
    
    If it prints something like this,
    javac 1.8.0-ea
    
    then you already have a current version of the JDK installed. (Yay! Go to the next step.) If "javac" is not a recognized command, then you need to install the JDK. If you have version 1.7, that should suffice for this class. If you have an earlier version, well, it might work.

    If you use Ubuntu

    sudo apt-get install openjdk-7-jdk
    
    or
    sudo apt-get install openjdk-8-jdk
    
    or, if you want the official Oracle version:
    sudo add-apt-repository ppa:webupd8team/java
    sudo apt-get update
    sudo apt-get install oracle-java8-installer
    
    or use a search engine to find other ways to do it. (If these instructions are out-of-date, please yell at me so I will know to update them.)

    If you use Windows

    Download and install it. Get the JDK (Java Development Kit), not the JRE (Java Runtime Environment). The JDK includes the compiler (javac). the JRE does not include the compiler. You don't need the "Development Kit with Demos and Samples", just get the "Development Kit". Unless your computer is really old, you probably want the 64-bit version. (If these instructions are out-of-date, please yell at me so I will know to update them.)

    Then test to see if you did it right

    javac -version
    
    If your command shell still cannot find javac, then you probably need to tweak your PATH environment variable to tell your computer where javac is located. First, figure out where javac is located. (Where did you install it to? Find it.) Next, use Google to learn how to adjust your PATH environment variable. Add the folder where javac is located to the list, so your computer will be able to find it. Then, test it again.


  4. Write a simple java program: Open your favorite text editor. (For this step, please use a simple text editor, not something integrated with the Java compiler. You will use an IDE in later steps, but I want you to prove that you can do it both ways.) Make a file called Main.java with the following contents:
    public class Main {
    	public static void main(String[] args) {
    		System.out.println("Hello Java");
    	}
    }
    


  5. Compile it.
    javac Main.java
    
    (If you get a compiler error, fix it and compile again.) Then, run your program.
    java Main
    
    It should print
    Hello Java
    
    Yay! You have now compiled a program in Java. Note that Java automatically appends ".class" to the name you specify, so that command actually executes the Main method in "Main.class". Don't do
    java Main.class
    
    or it will try to execute Main.class.class, which doesn't exist. The compiler, however, does not automatically append any extensions, so you must be more explicit with "javac".


  6. Write a shell script (or batch file, if you must use Windows) that will compile and run your code: If you use Linux, make a text file named build.bash with this content:
    #!/bin/bash
    set -e -x
    javac Main.java
    java Main
    
    (The first line, #!/bin/bash, tells your operating system which shell language you want to use. Linux supports many different shells. In this case, we are using Bash, which is a popular choice. The second line, set -e -x, tells the shell how to behave while the script is executing. The "-e" says to abort if any errors occur, and "-x" says to print each command before executing it.)

    If you use Windows, omit the first two lines from your script, and save it with the extension ".bat" instead of ".bash". (Be careful on Windows. I don't know how to make batch files abort if an error occurs, so an old version of your compiled program may run, even if there were compile errors in your most recent build, which may trick you into thinking your latest changes had no effect.)

    If you use Linux, make your shell script executable with this command:
    chmod 755 build.bash
    
    Then test it
    ./build.bash
    
    On Windows, you do not need to specify "./" to execute a script in the current folder because Windows looks in the current folder by default. So, you can execute your script with this command:
    build.bat
    


  7. Now, let's move on to some code with a graphical interface. Download this program. Unzip it. On Linux, the command is:
    unzip starter.zip
    
    (I recommend you learn to use the shell for simple tasks, like zipping and unzipping folders, instead of some graphical program. Graphical tools are very difficult to use in scripts. Those who learn to use the shell can automate such tasks. In software development, automation is very important.)

    Now, build and run this program. (Note that the script I included in that zip file only builds it.) You should see a button. When you push the button, it prints something in the console window.


  8. Examine Game.java. Observe the following points. If any of these points are unclear, use a search engine find some information to help you understand it better:
    • Java programs begins in "main".
    • The main function makes a "new Game" object. That means it allocates a portion of memory big enough to hold an instance of "Game".
    • We call such allocated portions of memory "class instances" or "objects".
    • When you make a new object, it implicitly calls the constructor. A constructor is a method with the same name as the class. The usual purpose of a constructor is to initialize the values in a new object.
    • The Game constructor makes two local variables named "controller" and "view". A variable is a reference (or pointer) to some place in memory. In this case, these variables reference two new objects of type "Controller" and "View".
    • Note that it is a common convention to start type names with a capital letter and to start variable names with a lowercase letter.
    • "this" refers to the object that is being initialized by the constructor.
    • Notice that the Game class extends JFrame. JFrame is a class that comes with the Java class library. By extending JFrame, the Game class inherits all the methods and member variables in the JFrame class. A JFrame is the frame around a graphical program. It is basically basically a window with a close button and a maximize button.


  9. Examine View.java. Observe the following points. An important part of this exercise is learning the language that I will use to communicate with you about Java code. So, read these points carefully and try to understand. Again, using a search engine is a good idea:
    • View extends JPanel. A JPanel represents the big gray area inside the JFrame. It is the place where the graphical components of your program go.
    • The View class has a member variable of type "JButton", named "b1". A member variable is a variable stored in an object.
    • Notice that the View constructor requires a parameter. This parameter is passed to it when a "new View()" is instantiated.
    • The View constructor instantiates a new JButton and uses the member variable, b1, to reference this new object.
    • The method "addActionListener" is a member of the JButton class. This method tells the button which object will handle the event that occurs when someone presses the button. We will use our controller object to handle this event, so we pass a reference to our controller object to the addActionListener method.
    • We also add b1 to "this" object, meaning we add the button to the panel. If you don't do that, it won't appear in the window.


  10. Examine Controller.java. Here are some points to observe:
    • This class "implements ActionListener". That means "This class is capable of handling ActionEvents, such as when someone pushes a button." In order to implement ActionListener, a class must provide a method named "actionPerformed", which is the method that will handle the event.
    • The "actionPerformed" method just prints a silly message to the console. "System" is a class provided by the Java class library that provides some important system functionality. "out" is a reference to an object that represents where text will be printed. By default, "out" is connected to your console, but it is possible to redirect it to go to other places.


  11. Make the button remove itself when you press it. Change the text of the button to something else. (I do not care what you change it to.)

    I recommend that you build and run after every little change that you make. That way, if the code breaks, you won't have to guess about which change is responsible. Also, it doesn't hurt to make full backups at regular intervals.

    In the Controller class (in Controller.java), add a member variable to reference the View:
    	View view;
    
    (If you need an example, the View class has a member variable in it that you can look at. I like to put all of my member variables at the top of the class, before the methods. I like the constructor to always be the first method after the member variables. However, these are just my preferences. You can put things where ever you want, as long as it works.)

    Add a method to the Controller class that lets the caller set the object that "view" references.
    	void setView(View v)
    	{
    		view = v;
    	}
    
    Call that setter method from the View constructor:
    		c.setView(this);
    
    Now, the view and controller objects both have references to each other.

    Add a method to the View class that removes the button:
    	void removeButton()
    	{
    		this.remove(b1);
    		this.repaint();
    	}
    
    Finally, change the behavior of the button so that it removes itself. So replace this line,
    		System.out.println("Hey! I said never push that button!");
    
    with
    		view.removeButton();
    
    When you run the program, you should see that pushing the button makes it disappear.


  12. Load a turtle image and change the background color of the View. Save this picture in the folder with your code:

    Add a member variable to your view to reference this image:
    	BufferedImage turtle_image;
    
    Add the following code to the View constructor to load this image from disk:
    		try
    		{
    			this.turtle_image =
    				ImageIO.read(new File("turtle.png"));
    		} catch(Exception e) {
    			e.printStackTrace(System.err);
    			System.exit(1);
    		}
    
    Add a method to the View class that will draw it:
    	public void paintComponent(Graphics g)
    	{
    		g.fillRect(0, 0, this.getWidth(), this.getHeight());
    		g.drawImage(this.turtle_image, 50, 200, null);
    	}
    
    paintComponent is already a method in the JPanel class, which the View class extends. By putting this method in your View class, you are overriding the one in JPanel, so it calls yours instead.

    Notice that the background is now black. Let's change it to a cyan color by inserting this line
    		g.setColor(new Color(128, 255, 255));
    
    just before the call to "g.fillRect". Now, when you build, you might get the following compiler error:
    View.java:31: error: cannot find symbol
    		g.setColor(new Color(128, 255, 255));
    		               ^
      symbol:   class Color
      location: class View
    1 error
    
    It cannot find the symbol "Color" because we have not told it where to look. Add this line near the top of the file:
    import java.awt.Color;
    
    This line tells it that the "Color" symbol is found in the namespace "java.awt". A "namespace" is a hierarchical system that Java uses to keep all of its classes organized. Now the program should build without errors, and when you run, you will have a Cyan background.

    But, where is the turtle? Well, we loaded it into memory, but we never actually told the program to draw it. So, right now, it's just filling up some memory. (Computers are not generally intelligent. They do not do obvious things unless they are explicitly instruct to do them.)


  13. Make a new class to represent the state of the game and draw the turtle. Add a new file to your project named "Model.java". Put the following contents in this file:
    class Model
    {
    	int turtle_x;
    	int turtle_y;
    	int dest_x;
    	int dest_y;
    
    	Model()
    	{
    	}
    
    	public void update()
    	{
    		// Move the turtle
    		if(this.turtle_x < this.dest_x)
    			this.turtle_x += 1;
    		else if(this.turtle_x > this.dest_x)
    			this.turtle_x -= 1;
    		if(this.turtle_y < this.dest_y)
    			this.turtle_y += 1;
    		else if(this.turtle_y > this.dest_y)
    			this.turtle_y -= 1;
    	}
    
    	public void setDestination(int x, int y)
    	{
    		this.dest_x = x;
    		this.dest_y = y;
    	}
    }
    
    Add "Model.java" to the list of files that your build script builds.

    In the Game constructor, instantiate a new Model object. Also, in Controller, add a member variable to reference the Model object:
    	Model model;
    
    Add a new parameter of type Model to the Controller constructor, and use it to initialize the "model" member variable:
    	Controller(Model m)
    	{
    		model = m;
    	}
    
    Also, add this method to your controller:
    	void update()
    	{
    	}
    
    Now, if you try to build, it will tell you:
    Game.java:11: error: constructor Controller in class Controller
    		cannot be applied to given types;
    		Controller controller = new Controller();
    		                        ^
      required: Model
      found: no arguments
      reason: actual and formal argument lists differ in length
    
    This means there is a problem in Game.java on line 12. (It might be a different line number for you.) The problem is that the Controller constructor requires one parameter value, but you are currently supplying zero. (You are supposed to be able to determine that by reading the error message. In this case, the error message is not worded very clearly, so it helps to have some experience reading error messages. Start building that experience now by carefully reading the error messages that go with each problem that you fix. Don't just be happy to get it working--a little time spent learning to understand the compiler will pay off in the long run.) Now, fix this problem by passing the model object when you instantiate your controller:
    	public Game()
    	{
    		Model model = new Model();
    		Controller controller = new Controller(model);
    
    The View is also going to need a reference to the model. So, go ahead and do that, just like you did with the Controller: add a member variable of type Model to your View and initialize it by passing a model object to the View constructor.

    Adjust the paintComponent method to draw the turtle where the model says the turtle is located:
    g.drawImage(this.turtle_image, model.turtle_x, model.turtle_y, null);
    


    Change the title of the JFrame to "Turtle attack!"



  14. Animate it. Then, add the following method to your Game class:
    public void run()
    {
    	while(true)
    	{
    		controller.update();
    		model.update();
    		view.repaint(); // Indirectly calls View.paintComponent
    		Toolkit.getDefaultToolkit().sync(); // Updates screen
    
    		// Go to sleep for 50 miliseconds
    		try
    		{
    			Thread.sleep(50);
    		} catch(Exception e) {
    			e.printStackTrace();
    			System.exit(1);
    		}
    		System.out.println("hi"); // remove this line
    	}
    }
    
    When you build, now, you will get an error about "cannot find symbol". Read that error message and see if you can figure out what it is saying. (Especially note the line number and the name of the symbol it cannot find.)

    ...

    Okay, I'll tell you what it means. It is saying that you cannot access "model" or "view" here, because those variables were declared in a different place. Now, see if you can figure out how to fix this problem. (If you can't figure it out, scroll way down.)

    Call your run method:
    public static void main(String[] args)
    {
    	Game g = new Game();
    	g.run();
    }
    
    Now it will redraw the view every 50 miliseconds. (1000 miliseconds-per-second / 50 miliseconds-per-event = 20 frames-per-second). Change it to update at a rate of 25 frames per second.

    However, it is difficult to tell that it is drawing many times per second because nothing moves. So, let's fix that. Make your Controller class also implement the MouseListener interface:
    class Controller implements ActionListener, MouseListener
    {
    
    and add the following methods:
    	public void mousePressed(MouseEvent e)
    	{
    		model.setDestination(e.getX(), e.getY());
    	}
    
    	public void mouseReleased(MouseEvent e) {    }
    	public void mouseEntered(MouseEvent e) {    }
    	public void mouseExited(MouseEvent e) {    }
    	public void mouseClicked(MouseEvent e) {    }
    
    and add this line to your Game constructor to tell it that the Controller is in charge of handling mouse clicks
    		this.addMouseListener(controller);
    
    Now, when you build and run, you should see that you can control the turtle by clicking somewhere inside the window. The turtle should move to the location where you clicked. (If the animation appears jerky, try wiggling your mouse inside the window. Some Java virtual machines try to reduce computational requirements by skipping screen refreshes. When the mouse moves, however, they know you are watching, so they don't try to get away with that.)


  15. Let's give it keyboard controls too. Start by making Controller implement the KeyListener interface.
    import java.awt.event.MouseListener;
    import java.awt.event.MouseEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.ActionEvent;
    import java.awt.event.KeyListener;
    import java.awt.event.KeyEvent;
    
    class Controller implements ActionListener, MouseListener, KeyListener
    
    Then, add these member variables,
    	boolean keyLeft;
    	boolean keyRight;
    	boolean keyUp;
    	boolean keyDown;
    
    and these methods:
    	public void keyPressed(KeyEvent e)
    	{
    		switch(e.getKeyCode())
    		{
    			case KeyEvent.VK_RIGHT: keyRight = true; break;
    			case KeyEvent.VK_LEFT: keyLeft = true; break;
    			case KeyEvent.VK_UP: keyUp = true; break;
    			case KeyEvent.VK_DOWN: keyDown = true; break;
    		}
    	}
    
    	public void keyReleased(KeyEvent e)
    	{
    		switch(e.getKeyCode())
    		{
    			case KeyEvent.VK_RIGHT: keyRight = false; break;
    			case KeyEvent.VK_LEFT: keyLeft = false; break;
    			case KeyEvent.VK_UP: keyUp = false; break;
    			case KeyEvent.VK_DOWN: keyDown = false; break;
    		}
    	}
    
    	public void keyTyped(KeyEvent e)
    	{
    	}
    
    	void update()
    	{
    		if(keyRight) model.dest_x++;
    		if(keyLeft) model.dest_x--;
    		if(keyDown) model.dest_y++;
    		if(keyUp) model.dest_y--;
    	}
    
    Also, add this line to your Game constructor to tell it that the Controller is in charge of handling key events:
    		this.addKeyListener(controller);
    


  16. Make the turtle move 4 times faster by changing each "1" in Model.java to "4". Tweak the code so that the turtle does not overshoot its destination, then jump back and forth trying to get there. For example, instead of always moving 4 pixels to the right, like this:
    turtle_x += 4;
    
    you could move 4 pixels to the right, or the distance to the destination, whichever is smaller, like this:
    turtle_x += Math.min(4, dest_x - turtle_x);
    
    (Do something similar for moving left, up, or down.)


  17. Clean up your code. Make sure your tabluations are consistent (for your own benefit--I am not going to check for it). Add comments, so you will remember what various things do (also for your own benefit--I am not going to check for this either). I like to group my code into "blocks" separated by blank lines, such that each block of lines performs one task. I start each block with a comment describing the one task that this block performs. If a particular line within a "block" requires annotation, I add a comment for that line at the end of the line. You don't have to use my style. However, future assignments will build on top of this one, so it is worth your time to keep your code clean. Also, future assignments will not provide nearly as explicit instructions as this one, so be sure you understood what you did.























Answer to the challenge in step 16:

Local variables cannot be accessed in other methods. Member variables, however, can be accessed anywhere in the class. So, you need to change "model" and "view" to be member variables instead of local variables. Here is an example of a local variable:
class Game
{
	public Game()
	{
		Model model = new Model();
Here is an example of a member variable:
class Game
{
	Model model;

	public Game()
	{
		model = new Model();
You need to make a similar change for "view" as well.








FAQ:

  1. Can you provide the solution?
    A: Here it is. Please don't look at it until after you have tried to do it on your own.