Java Questions
- Can Java's for-loop contain multiple statements and expressions inside the for-construct? Yes. For example: (source file) public class test_for { public static void main (String[] argv) { // Computes (1/10 + 2/9 + ... + 10/1 - 1) int n = 10; double sum = 0; // Notice how i and j are both defined in the for-loop. for (int i=1, j=n; (i!=j)&&(i<=n); i++, j--) sum += (double) i / (double) j; System.out.println ("Sum = " + sum); } }
- Does Java initialize uninitialized variables for you? Yes and no. Yes, in the sense that all variables are given a default value, but no in the sense that the compiler will somtimes complain about uninitialized local variables. The initial values are quite logical: zero for numbers, false for boolean's and null for object references. Thus, for example (source file), the following compiles without complaint. The instance variables get their default values. public class test_init_var { double x; int[] A; char c; test_init_var t; public static void main (String[] argv) { test_init_var tiv = new test_init_var (); System.out.println ("x = " + tiv.x); System.out.println ("A = " + tiv.A); System.out.println ("c ='" + tiv.c + "'"); System.out.println ("t = " + tiv.t); } }
This will print out: x = 0.0 A = null c ='' t = null
However, for local variables, the compiler will often try to track down instances of uninitialized variables and will force you to do something about it. For example, the following will not compile: (source file) public class test_init_var { public static void main (String[] argv) { double x2; int[] A2; char c2; System.out.println ("x2 = " + x2); System.out.println ("A2 = " + A2); System.out.println ("c2 ='" + c2 + "'"); } }
- Why is it that some classes cannot be instantiated? For example, the following fails to compile: Math m = new Math();
because the compiler complains that Math has no constructor. How can this be? It derives from Object, and so must have one. On the other hand the following does compile: final class blah extends Object { public static void print_blah () { System.out.println ("blah"); } } public class test { public static void main (String[] argv) { blah m = new blah(); System.out.println (m); } }
Here, blah is declared just like Math, without a constructor. The default is put in, and it compiles (and executes). What's going on? Solution: Math has got a constructor declared as private. Here's the code: final class blah extends Object { private blah () {} public static void print_blah () { System.out.println ("blah"); } } public class math_test { public static void main (String[] argv) { // Both of these give the same compiler error. Math m = new Math (); blah b = new blah(); System.out.println (m); } }
- Does concatenation take precedence over addition? What gets printed out with the following code? public class concat_test { public static void main (String[] argv) { int i=5, j=6; System.out.println (i+j); } }
Solution: addition has precedence and thus 11 gets printed out. However, parsing is done left to right, and can create strange effects: public class concat_test { public static void main (String[] argv) { int i=5, j=6; System.out.println (i+j); // 11 System.out.println ((i)+(j)); // 11 System.out.println (i + "" + j); // 56 System.out.println ("" + i + j); // 56 System.out.println (i + j + ""); // 11 } }
- When the compiler compiles a class that imports a package, is the package compiled too? The answer is simple, but complicated to test: the compiler does it best to use a current version. Here's a bunch of tests and a conclusion:
- I created a simple class and placed it within a package.
- I created another test class that used the package.
- Test 1:
- I did not compile the package class at all and tried compiling the test class.
- The compiler compiled the package class for me.
- Test 2:
- I compiled the package class and recorded the creation date.
- Then I compiled the test class.
- This time, the compiler did NOT compile the package class. (The object code was available).
- Test 3:
- I modified the package class so that its creation date was more recent than the test class. However, I did not compile it, so that the .class file was out of date.
- This time the compiler compiled the package class.
- Test 4:
- Finally, I removed the source file of the package class, leaving only a .class file.
- This time, the compiler simply took what it could find - the object file.
- What happens if you print an object that has not overridden the toString() function? For example: public class Person { String name; // Constructor. public Person (String name_in) { name = name_in; } public static void main (String[] argv) { Person p = new Person ("Ms. X"); System.out.println (p); // What gets printed? } }
Solution: It compiles and runs. What gets printed out is the name of the class and a memory address, e.g., Person@1dc60750
- If a method returns a value, can it be called without using the return value? For example: public class test { public static int get_int() { return 5; } public static void main (String[] argv) { // Return value not used. get_int(); } }
Solution: Yes. - Can a function return an array? Solution: Yes. For example, public class TestArray { public static double[] double_arr (int size) { double[] D = new double[size]; return D; } public static void main (String[] argv) { double D[] = double_arr (5); } }
- Can you inherit "main"? Solution: Yes. Consider: class Test { static int x = 5; static void printx () { System.out.println ("Test: x = " + x); } public static void main (String[] argv) { System.out.println ("main: x = " + x); printx(); } } public class TestMain extends Test { static void printx () { System.out.println ("TestMain: x = " + x); } }
Here's what gets printed out: main: x = 5 Test: x = 5
From this, we can make two observations: (1) You can inherit "main" - the linker has no problem finding it in TestMain above. (2) The code is statically linked so that overriding printx() above does not find the new printx and instead calls the superclass printx. This is because the call is hardcoded rather than through a function pointer.
- Why can't I clone an Object? Solution: Object's clone method is protected. This is done to prevent default cloneability in classes. In some cases, you may not want a class to be cloned. If Object's clone method were public, it could be accessed from anywhere. Subclasses cannot reduce the access of a method while overriding it (e.g., overriding a public method to be protected). Therefore, if clone were public in Object, all classes would automatically be cloneable. One of the consequences of having Object's clone method protected is that you can not write general-purpose methods that take an Object as a parameter and clone the Object. There is a way around this, however. Normally, in order to make a class cloneable, it must implement the interface Cloneable and override Object's clone method so that it is public. If you try to clone an Object directly, your program will not compile. Let's take a look at an example: (source file) class ObjA implements Cloneable { int x; public ObjA(int x) { this.x = x; } public Object clone() { Object o = null; try { o = super.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(); } return o; } public String toString() { return "x = " + String.valueOf(x); } } public class test_clone1 { public static Object doclone(Object obj) { return obj.clone(); } public static void main(String argv[]) { ObjA a = new ObjA(12); ObjA b = (ObjA) doclone(a); } }
If you tried compiling this, you'd get the following error: test_clone1.java:26: clone() has protected access in java.lang.Object return obj.clone();
In order to avoid this error, you would have to first cast obj to ObjA, and then call the clone method. This defeats the purpose of having a method that is general for different classes. One way to get around this is to make your own interface, TrulyCloneable for example, that extends Cloneable and does nothing but change the clone method to public. Then, instead of making your cloneable object implement Cloneable, make it implement TrulyCloneable. Then, in method doclone, cast obj to TrulyCloneable: (source file) interface TrulyCloneable extends Cloneable { public Object clone(); } class ObjA implements TrulyCloneable { int x; public ObjA(int x) { this.x = x; } public Object clone() { Object o = null; try { o = super.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(); } return o; } public String toString() { return "x = " + String.valueOf(x); } } public class test_clone2 { public static Object doclone(Object obj) { return ((TrulyCloneable) obj).clone(); } public static void main(String argv[]) { ObjA a = new ObjA(12); ObjA b = (ObjA) doclone(a); } }
This has the desired effect and calls the clone method properly. This might be useful in cases where you would like to generically clone an array of objects. Each of the objects in the array would have to implement TrulyCloneable. The array can then be cloned by cloning the array itself followed by cloning each of the array's elements. [Written by Luv Kohli]
- Are static initializer blocks inherited? Solution: No. Here is an example: (source file) class A { public static int x = 0; static { x++; System.out.println("Hi, this is A!"); } } class B extends A { public static int x = 0; } public class test_staticinit1 { public static void main(String argv[]) { System.out.println("A.x = " + A.x); System.out.println("B.x = " + B.x); } }
Running this program results in the following output: Hi, this is A! A.x = 1 B.x = 0
As soon as A.x is accessed, class A is loaded and its static initializer block is run. A's static variable x is incremented to 1. If the A's static initializer block were inherited by class B, then B.x should have been equal to 1 also. However, B.x still equals 0. Note that a static initializer block is executed only once: when a class is first loaded: (source file) class A { static { System.out.println("Hi, this is A!"); } } class B extends A { static { System.out.println("Hi, this is B!"); } } public class test_staticinit2 { public static void main(String argv[]) { new B(); new A(); } }
Here is the output from this program: Hi, this is A! Hi, this is B!
When class B is loaded (caused here by doing new B();), class A is loaded first because B extends A. A's static initializer block is executed, and then B's static initializer block is executed. The subsequent code new A(); does not cause anything else to be displayed, so the static initializer blocks are not called more than once. [Written by Luv Kohli]
- What is the difference between checked exceptions and unchecked exceptions? Solution: Java has two kinds of exceptions: checked and unchecked. Checked exceptions are subclasses of Exception that are not subclasses of RuntimeExceptions. Any checked exception that may be thrown in a method must be either caught by that method or declared in the method's throws clause. An unchecked exception does not need to be caught. RuntimeException is a subclass of Exception and is an unchecked exception. RuntimeException's are generally indicative of software bugs. For example, NullPointerException is a subclass of RuntimeException and is unchecked. This exception can be thrown just about anywhere in a program. Whenever an attempt is made to deference null a NullPointerException is thrown. It would be counterintuitive to require that such exceptions be caught in the code, because it is impossible to predict exactly where these exceptions may happen. So how do you throw exceptions? Let's look at checked exceptions first: class TestException extends Exception { public TestException() { } public TestException(String s) { super(s); } } public class test_exceptions { static void a() throws TestException { throw new TestException(); } public static void main(String argv[]) { a(); // generates a compile-time error } }
If you tried to compile this program, you would get a compile-time error. The method a() throws the exception TestException and must be caught or again thrown by the caller of the method. If you did not have the throws clause in the method a(), the program would also not compile, saying that you would need to either catch or declare TestException. To catch the exception in main() you would do this: public static void main(String argv[]) { try { a(); } catch(TestException e) { System.out.println(e); } }
Alternatively, you could have main() throw the exception to the virtual machine: public static void main(String argv[]) throws TestException { a(); }
How about unchecked exceptions? One way to create an unchecked exception is to extend RuntimeException: class UnpredictableException extends RuntimeException { public UnpredictableException() { } public UnpredictableException(String s) { super(s); } } public class test_exceptions { static void b() { throw new UnpredictableException(); } public static void main(String argv[]) { b(); } }
This program will compile properly because UnpredictableException is an unchecked exception; it is not necessary to catch or declare it. The exception can be declared in method b()'s throws clause, but it still will not be necessary to catch it. Note that it is not a good idea to use unchecked exceptions simply to avoid the "hassle" of having to catch them. Exceptions are a very valuable tool for creating robust code. [Written by Luv Kohli]
- How do I print a stack trace for exceptions? Solution: Printing a stack trace is accomplished by calling Throwable's printStackTrace() method. Here is an example: (source file) class MyException extends Exception { public MyException() { } public MyException(String s) { super(s); } } public class test_stacktrace { static void a() throws MyException { b(); } static void b() throws MyException { c(); } static void c() throws MyException { throw new MyException(); } public static void main(String argv[]) { try { a(); } catch(MyException e) { e.printStackTrace(); } } }
Upon executing this program, the following will be displayed: MyException at test_stacktrace.c(test_stacktrace.java:20) at test_stacktrace.b(test_stacktrace.java:16) at test_stacktrace.a(test_stacktrace.java:12) at test_stacktrace.main(test_stacktrace.java:25)
Note that an uncaught exception that is thrown by main to the virtual machine is automatically displayed with a stack trace. It is not necessary to have an exception in order to display a stack trace. You can display a stack trace from anywhere in your code by doing this: new Throwable().printStackTrace();
[Written by Luv Kohli]
- How do I make an executable JAR file? Solution: If your program is an applet compressed in a JAR file, there is only one change you need to make. Normally when you run an applet, your html file would have the following: <applet code=TheApplet.class width=200 height=200> </applet>
For a JAR file, you simply have to add an additional archive parameter: <applet code=TheApplet.class archive="applets/TheApplet.jar" width=200 height=200> </applet>
The archive parameter specifies the relative path to the JAR file that contains the applet. If your program is an application, you need to include a line in the JAR file's manifest file. The manifest file can contain special information about the files that are packaged in the JAR file. When you create a JAR file, a default manifest file is created and always has this pathname: META-INF/MANIFEST.MF
The manifest file is simply a text file with some information in it. In order to make your JAR file executable, you need to specify which class in your JAR file contains your main method. This information is provided in the manifest with the following form: Main-Class: classname
How do you get this information into the manifest file? Let's suppose you have the following classes: FunGame.class GUI.class DataStore.class
Now you want to create an executable JAR file that will run the class FunGame.class. In order to do this, simply create a text file (e.g. mainClass) that has the following line in it: Main-Class: FunGame
Then, create your JAR file with the following command: jar cmvf mainClass FunGame.jar *.class
The cmvf parameters mean the following: c - create a new archive m - include manifest information from the specified manifest file v - display verbose output f - specify archive filename
To execute your newly created JAR file, simply type: java -jar FunGame.jar
If you already created a JAR file but forgot to include the manifest information, you can use the u option instead of the c option to update the JAR file instead of recreating it: jar umvf mainClass FunGame.jar
[This is essentially a compressed set of information based on Sun's Java Tutorial trail on JAR files. More information can be found here: JAR Files]
- How do I know if I am using a Just-in-Time (JIT) compiler and how do I turn it off? Solution: You can tell if you are using a JIT by checking the version of the VM: java -version
You might get something like this: java version "1.3.0" Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C) Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)
If you are using Java 2 SDK v1.3, then you can disable the default JIT with the -classic parameter: java -classic -version
This will give you something like this: java version "1.3.0" Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C) Classic VM (build 1.3.0-C, native threads, nojit)
If you are using Java 2 SDK v1.2, then you can disable the JIT by doing this: java -Djava.compiler=NONE MyApp
[Written by Luv Kohli]
- Can a static class be passed as a method parameter? Solution: No. You can, however, pass a Class object as a parameter: class A { } public class statictest { static void blah(Class c) { System.out.println(c); } public static void main(String argv[]) { try { blah(Class.forName("A")); } catch(ClassNotFoundException e) { e.printStackTrace(); } } }
The forName method in Class returns a Class object for the specified classname string. The forName method throws ClassNotFoundException if the specified classname is not found, so this exception must be caught. [Written by Luv Kohli]
- Are final variables optimized by the compiler? Solution: This may depend on the specific compiler that you are using and any special parameters you pass to the compiler. Nevertheless, let's take a look at what the Java 2 SDK compiler does with final boolean variables. Assume there is a program that we are trying to debug. Every so often we are displaying debug information using System.out.println() calls. After a while, this information can become cumbersome, so we specify a boolean variable that will allow us to turn off debugging output. Here is a very simple example: public class test_final { public static void main(String argv[]) { boolean DEBUG = false; if(DEBUG) System.out.println("debug output"); } }
Note that the variable DEBUG is set to false so this program will not display anything. After compiling this code, let's take a look at the bytecode that was generated by the compiler by using the javap tool (the class file disassembler) that comes with the Java 2 SDK: javap -c test_final
The following will be displayed: Compiled from test_final.java public class test_final extends java.lang.Object { public test_final(); public static void main(java.lang.String[]); } Method test_final() 0 aload_0 1 invokespecial #1 <Method java.lang.Object()> 4 return Method void main(java.lang.String[]) 0 iconst_0 1 istore_1 2 iload_1 3 ifeq 14 6 getstatic #2 <Field java.io.PrintStream out> 9 ldc #3 <String "debug output"> 11 invokevirtual #4 <Method void println(java.lang.String)> 14 return
Do not worry about all the details of this bytecode listing right now. Just note that the bytecode listing for method main contains code for the if statement and code for loading the String "debug output" and calling the println method with that String. Let's look at another program, with one minor modification. Instead of boolean DEBUG = false;, we will have final boolean DEBUG = false;: public class test_final2 { public static void main(String argv[]) { final boolean DEBUG = false; if(DEBUG) System.out.println("debug output"); } }
Let's look at the generated bytecode for this program: Compiled from test_final2.java public class test_final2 extends java.lang.Object { public test_final2(); public static void main(java.lang.String[]); } Method test_final2() 0 aload_0 1 invokespecial #1 <Method java.lang.Object()> 4 return Method void main(java.lang.String[]) 0 return
The bytecode for the main method is much shorter! What happened? The compiler realized that the final variable DEBUG was false. Since this is a final variable, its value is known at compile-time, and the compiler can effectively remove any code that would not be executed because of DEBUG's value being false. Even if the value of the final variable DEBUG were true, the bytecode would still be smaller than the original case. Let's take a look: public class test_final3 { public static void main(String argv[]) { final boolean DEBUG = true; if(DEBUG) System.out.println("debug output"); } }
The following bytecode is generated: Compiled from test_final3.java public class test_final3 extends java.lang.Object { public test_final3(); public static void main(java.lang.String[]); } Method test_final3() 0 aload_0 1 invokespecial #1 <Method java.lang.Object()> 4 return Method void main(java.lang.String[]) 0 getstatic #2 <Field java.io.PrintStream out> 3 ldc #3 <String "debug output"> 5 invokevirtual #4 <Method void println(java.lang.String)> 8 return
In this case, there is no bytecode for the if statement. This is because the compiler knows that DEBUG is true and simply includes the code that is inside the if statement. Important note: This optimization will only occur if you specify the value of the final variable when you first declare it. If you specify its value later on in your code (as is possible for local final variables), this optimization will not be done. [Written by Luv Kohli]
- How do you load packages and classes that are outside your classpath? Solution: Use a URLClassLoader. Instantiate the loader with the paths of the classes you want to load. Then call ClassLoader.loadClass("Class/Package Name").newInstance() and store the variable in some class based on your plugin implementation. For example, if you have a plugin class that: (1) implements the ProgramPlugin interface; (2) is stored in the folder /plugins/PluginA/; (3) is named plugin.class; (4) and thus is in a package called PluginA the following code will instantiate that plugin: //This is normally just a "\" or a "/" String separator = System.getProperty("file.separator"); //This is the start directory for your main class String dir = System.getProperty("user.dir"); //Look in the plugins' sub directory File path = new File(dir + seperator + "plugins"); //List all the files and directories in this folder File[] files = path.listFiles(); Vector vurls = new Vector(); Vector loadables = new Vector(); File furl; String pname; //store the base url vurls.add(path.toURL()); // If you have a .jar file in the plugins directory you // will need to specifically add that jar file to the // classloader path. This for loop adds all the jar // files and checks for duplicates between folders and // jar files for(int i=0; i < files.length; i++) { String protocolFile = files[i].getAbsolutePath(); furl = new File(protocolFile); pname = furl.getName(); if(protocolFile.endsWith(".jar")) { vurls.add(new File(protocolFile).toURL()); pname = pname.substring(0, pname.length()-4); } if(loadables.contains(pname)) { System.out.println("ERROR: duplicate class names!"); } else { // store the names of all the loadable plugins loadables.add(pname); } } // Set up your loader URL[] urls = (URL[])vurls.toArray(new URL[0]); URLClassLoader loader = new URLClassLoader(urls); // Assume the vector loadables contains "PluginA" at element 0 // Calls packages PluginA.plugin ProgramPlugin class = loader.loadClass(loadables.elementAt(0)+".plugin").newInstance();
[Written by Justin Cohen]
- Why does a Swing GUI freeze or lock up? Solution: Most likely because the event-handling thread is being forced into "busy" work. Swing threads work like this:
- Once you fire up your GUI (a JFrame, let's say), the main thread continues executing.
- Swing creates a new thread just to listen for events and for handling them.
- What's important is that a single thread is used for all components. Thus, you might fire up multiple components, but a single thread is used to listen for all events. This means if any one component keeps this one thread busy, the other components will not respond to the user.
- Why is it done this way? See the Java website for a detailed explanation, but briefly, it's because most applications can be written with the one-thread model and it's easy to write with. The thinking is, each event is usually handled quickly ("load a file", "cut-and-paste", whatever) and not in parallel with other events.
If you run and then click on the "spin" button, the GUI freezes for about 10 seconds (i.e., won't respond to "quit"). This is because the single event thread is made to execute the spinWheels() method and spends all its time there instead of picking off new events from the event queue. If you have to do such a thing, it's fairly easy to encapsulate the "busy work" in a thread: import javax.swing.*; import javax.swing.event.*; import java.awt.*; import java.awt.event.*; // This class will be run as a thread to do the busy work. class ThreadedSpinner implements Runnable { public void run () { try { System.out.println ("Start spin ... "); // Sleep for 10 seconds Thread.sleep (10000); System.out.println ("... end spin."); } catch (InterruptedException e){ e.printStackTrace (); } } } public class JFrameDelay2 extends JFrame { public JFrameDelay2 () { this.setSize (600,400); // A quit button JButton quitB = new JButton ("Quit"); quitB.addActionListener ( new ActionListener () { public void actionPerformed (ActionEvent a) { System.exit(0); } } ); this.getContentPane().add (quitB, BorderLayout.SOUTH); // A "spin" button to create busy work. JButton spinB = new JButton ("Spin"); spinB.addActionListener ( new ActionListener () { public void actionPerformed (ActionEvent a) { spinWheels (); } } ); this.getContentPane().add (spinB, BorderLayout.NORTH); this.setVisible (true); } void spinWheels () { // Fire off a new thread to do the work. Thread t = new Thread (new ThreadedSpinner ()); t.start (); // The event thread simply continues from here. } public static void main (String[] argv) { JFrameDelay2 delayF = new JFrameDelay2 (); } }
- How do I know where my application is being run? Solution: There are two directories that's useful to an application:
- An application wants to know the current user directory from which the application was launched. This is the so-called "working directory". You, the programmer, would like to know that so you can look for particular files etc.
- An application wants to know its "install" directory, i.e., where the executables are located. Usually, this is how you, the programmer, can read properties or configuration files which came with the installation.