Chapter:Inheritance - Extending your own classes - Exercises

From Juneday education
Jump to: navigation, search

Exercises

Let's write ourself a File browser. Since we don't yet know how to create graphical user interfaces we'll settle for a text interface. We need a class representing the files on the disk - the files we want to manage. If we call this class File we have a name collision with the File class that already exists in Java. Since we have packages this will work fine - but it may be confusing for the reader se we need another name for the class representing files. Let's use: FBFile, as in File Browser File.

We provide a class, FileList, which you can use to create a List (e g ArrayList) files and directories. Copy the code below and save it according to its package declaration.

package com.superpower.filebrowser.utils;

import java.util.List;
import java.util.ArrayList;
import java.io.File;

import com.superpower.filebrowser.*;


public class FileList {

    public static List<FBFile> list() {
        return list(".");
    }

    public static List<FBFile> list(String dir) {
        return list(new File(dir));
    }
    
    public static List<FBFile> list(File dir) {

        if ( (dir==null) || dir.isFile() ) {
            return null;
        }
        
        List<FBFile> list = new ArrayList<FBFile>();

        // Note that we use File below. File is a class in Java.
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                list.add(new FBFile(file.getPath()));
            } else if (file.isDirectory()) {
                System.err.println("Ignoring directory: " + file.getPath());
            }
        }
        return list;
    }

}

Note: this code uses the old File class instead the newer Path classes. We will update this some day.

FBFile class diagram

Q1.

Let's write the class FBFile, with methods and parameters as follows:

  • a private instance variable name representing the actual file's name.
  • a method, name() returning the name of the file.
  • a method, thumbnail() returning a thumbnail image, which in our case will be a String "[file]".
  • a constructor whith which we can set the name variable. No other constructor is needed. Do not create a contrsuctor with an empty argument list.

and the class use the package com.superpower.filebrowser. The package name reflects that we're a company called Superpower and our product is class File Browser.

Note: We could choose several other different ways to solve this but we will settle for this solution since we're currently practicing inheritance

Expand using link to the right to see the full content.

Suggested solution:

package com.superpower.filebrowser;

public class FBFile {

    private String name;

    public FBFile(String name) {
        this.name = name;
    }

    public String name() {
        return name;
    }

    public String thumbnail() {
        return "[file]";
    }

}

Q2.

Write a class called TextMain with a main method. We suggest you use the method list in the class, FileList listed above that returns a List (ArrayList inherits from List) of files. You can get a list of files from that class like this: List<FBFile> files = FileList.list();The class should use the package name com.superpower.filebrowser.main

We provide a zip file Media:Inheritance-files.zip where you can find some example/sample files. Download and unpack the zip file. Make sure that the files directory (in the zip file) is located in the same directory as where you com directory is located. We provide a file listing below to (hopefully) make things clearer:

.
|-- com
|   `-- superpower
|       `-- filebrowser
|           |-- FBFile.java
|           |-- main
|           |   `-- TextMain.java
|           `-- utils
|               `-- FileList.java
`-- files
    |-- directory
    |   `-- new-file.txt
    |-- hello
    |-- hello.c
    |-- medium.txt
    |-- Sample.java
    `-- small.txt

Print the list to stdout using System.out.println in a loop, one FBFile at the time, to see the files. Add this code to TextMain and compile.

Enter the files/ directory you extracted from the zip file, and execute the program. When entering the directory Java will no longer find your class if your using the same command line as before. We need to tell java to look for our Java classes in the parent directory:

$ java -cp ../ com.superpower.filebrowser.main.TextMain

Note:you should enter the files directory before you start your program, hence the -cp flag passed to Java. The -cp flag stands for class path and tells Java where to look for the com/ directory, which will let Java also find the TextMain class which is in the relative path ../com/superpower/filebrowser/main/TextMain.class .

Expand using link to the right to see the full content.

Suggested solution:

package com.superpower.filebrowser.main;

import java.util.List;

import com.superpower.filebrowser.utils.FileList;
import com.superpower.filebrowser.FBFile;

public class TextMain {

    public static void main(String[] args) {

        List<FBFile> files = FileList.list();

        for (FBFile f : files) {
            System.out.println("f: " + f);
	}

    }

}

Q3.

Change the output, in the main method of the TextMain class, so that it prints the thumbnail of the file followed by the name of the file.

The output should look something like this:

[file] ./medium.txt
[file] ./small.txt

Expand using link to the right to see the full content.

Suggested solution:

Change the main method to something like this:

    public static void main(String[] args) {

        List<FBFile> files = FileList.list();

        for (FBFile f : files) {
            System.out.println(f.thumbnail() + " " + f.name());
        }

    }

Q4.

It's a bit disappointing not adding directories to the list of files and instead see a warning printout (see below). Good thing we have already written some code for you to solve this. Do the following to make things work a bit better. In the class FileList we want you to remove the call to System.err.println and instead add code that adds the directory as an FBFile (see below).

Example of warning printouts:

Ignoring directory: ./com
Ignoring directory: ./files

Code to add directories:

            } else if (file.isDirectory()) {
                list.add(new FBFile(file.getPath()));                                                  
            }


Note: you hopefully think that it is not very clever to create and add a FBFile in both branches of the if-statement. We agree, but want you to keep it this way since we will change one of the statements in the coming exercise.

Compile and execute again.

FBDir extends FBFile class diagram

Expand using link to the right to see the full content.

Suggested solution:

            } else if (file.isDirectory()) {
                //             } else if (file.isDirectory()) {
                list.add(new FBFile(file.getPath()));
            }

Q5.

It is rather confusing for the user to see a directory listed as a file, even if a directory is a file in Java. Let's sub class FBFile. Create a new class FBDir extending FBFile. The class should override the method thumbnail and return "[dir ]" instead.

Compile and execute again. Nothing happened. Why?

Expand using link to the right to see the full content.

Suggested solution:

package com.superpower.filebrowser;

public class FBDir extends FBFile {

    public FBDir(String name) {
        super(name);
    }

    public String thumbnail() {
        return "[dir ]";
    }
    
}

Nothing happened since we've only created a class which no one uses.

Also make sure to change the method list in the class FileList so that it creates an FBDir object when it finds a directory.

Expand using link to the right to see the full content.

Suggested solution:

           if (file.isFile()) {
               list.add(new FBFile(file.getPath()));
            } else if (file.isDirectory()) {
               list.add(new FBDir(file.getPath()));
            }

Q6.

Create a class called FBJavaFile that will represent Java files. Change to logic of FileList to create FBJavaFile instances if it finds a Java file. The class should override the method thumbnail and return "[java]" instead.

Hint: to check if a string ends with a string you can use the method endsWith in String. If you write name.endsWith("am") we will get true returned if name ends with "am" and false otherwise.

Concluding remarks: We can see that it is rather easy to create subclasses to FBFile and use them accordingly. It would be fairly easy to extend this software to be able to handle all sorts of files. This will, however, mean that we'll have tons of classes (one per file type) with basically the same content. Are we gaining a lot by using inheritance? Would it be easier to let FBFile have a property (e g an instance variable) representing the file type?

Note: in the root of the it-is-possible-to-extend-your-own-classesdirectory you'll find a file called Makefile. Feel free to use it with the make command. Make (together with a Makefile) is a tool to control the building/compilation of software.

Expand using link to the right to see the full content.

Suggested solution:

package com.superpower.filebrowser;

public class FBJavaFile extends FBFile {

    public FBJavaFile(String name) {
        super(name);
    }

    public String thumbnail() {
        return "[java]";
    }
    
}

Complete FileList (suggested) class:

package com.superpower.filebrowser.utils;

import java.util.List;
import java.util.ArrayList;
import java.io.File;

import com.superpower.filebrowser.*;


public class FileList {

    public static List<FBFile> list() {
        return list(".");
    }

    public static List<FBFile> list(String dir) {
        return list(new File(dir));
    }
    
    public static List<FBFile> list(File dir) {

        if ( (dir==null) || dir.isFile() ) {
            return null;
        }
        
        // By returning a List we can chose any the subclasses (in
        // this case actually sub interfaces - more on that in the
        // coming chapter) and change it afterwards, since the users
        // of this method only uses the methods as "provided" by List
        List<FBFile> list = new ArrayList<FBFile>();
        
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                if (file.getPath().endsWith(".java")) {
                    list.add(new FBJavaFile(file.getPath()));
                } else {
                    list.add(new FBFile(file.getPath()));
                }
            } else if (file.isDirectory()) {
                // System.err.println("Ignoring directory: " + file.getPath());
                //
                //list.add(new FBFile(file.getPath()));
                list.add(new FBDir(file.getPath()));
            }
        }
        return list;
    }

}

Links

Solutions/source code

You can find complete source code to the suggested solutions below in the it-is-possible-to-extend-your-own-classes directory in this zip file or in the git repository.

Further reading

Where to go next

Next page is: Inheritance_-_Examples_from_Swing

« PreviousBook TOCNext »