XCF/CSUA/OCF Help Session Java Programming Tawei Liao Helper 1. What is Java? Java is an object-oriented language based on C++. It was developed at Sun originally for TV settop boxes. When the WWW became popular, Sun started marketing Java as a web develop- ment language. Java is designed to be cross-platform in compiled binary form. Any machine with a Java interpreter can run Java binaries. That is why it is so popular as a web development language. The programmer does not have to worry about the platform specific details. Netscape 2.0 has a built-in Java interpreter, that is the main reason why Java is becoming the de facto stan- dard. 11. Java the language The syntax of Java is very much like C/C++. There are a lot of subtle differences however. Briefly here are some things that Java does not support: 1. No multiple inhertance 2. No pointers 3. No global variables or global standalone functions 4. And no nasty references Java does add a lot of extra features to C and C++, it has: I . Thread support 2. Garbage collection 3. Exception handling that works 4. Strong Object hierarchy The Java Language Specification is very useful in leaming the syntax of the language. There is a list of FTP and WEB sites at the end of this handout that tells you where you can get more infor- mation. 111. Java Applet vs. Java Program A Java applet (short for application) is different from an ordinary Java program. An applet is designed to be included in a HTML file and be executed by anyone visiting that web site. It has to be made secure. E.g., you can write an applet that executes 'rm -rf *', but it will not run.. Netscape will complain about security violation errors. Here is the canonical 'Hello, world!' program in Java: class HelloWorld { public static void main(String args[l) System.out.println("Hello, world!"); After compiling the program with either j avac or Netscape, it will produce a file called 'HelloWorld.class'. If you declared another class named 'Foo' in that same src file, javac will generate 'Foo.class' in addition the HelloWorld class. To run the program, we specify the name of the class WITHOUT the class extension. That is by far the most common mistake that people make. And here is the cannonical 'Hello, world!' applet: import java.awt.Graphics; import java.applet.*; public class HelloWorldApplet extends Applet f public void inito resize(150,25); public void paint(Graphics g) g.drawString("Hello world!", 50, 25); A Java applet is a class that inherits from the Applet class. You must overload specific methods in the Applet to make it runnable. There are five methods that we care about: inito, starto, painto, stopo, and destroys. One thing that you will notice immediately is that we never call the paint method directly in our applet. Where and when did the method get called? It gets called automatically. When you are writing an applet, you are basically writing stubs for the Applet class. Those methods will be called at the right times automatically. Here is a slightly more complicated applet. It will draw square and everytime you click inside the rectangle the color changes: IV. Reference Stuff javac is ajava compiler written in Java. If you have a Java interpreter, such as Netscape, you can compile j ava programs by using that interpreter. 1) Get the 'classes.zip' file from the Java Developer's Kit (JDK). I also have everything on http:Hwww.xcf.berkeley.edu/java/ 2) setenv CLASSPATH /home/tawei/.netscape/classes.zip 3) netscape -java sun.toolsjavac.Main ChangeColorjava 4) To run the j ava interpreter try 'netscape -j ava HelloWorld' The Java Developer's Kit (JDK) is available on the Solaris, VYNT, W95, and Mc 7.5 (beta 1) Plat- forms. There are other ports out there but they are not supported by Sun. Here are some sites and resources that you will find very helpful. http://java.sun.com All the documentation and API reference manuals and JDK are here. http://www.gamelan.com Java repository. It has all sorts of cool stuff. This site is very helpful in getting started on Java programming. http://java.blackdown.org Linux Port of JDK. http://www.sgi.com/Products/cosmo/cosmo-instructions.html http://liawww.epfl.ch/-simon/java/irix-jdk/ SGI Port of JDK. http://www.gr.osf.org:8001/projects/web/java/ HPUX/OSF Port. They don't have it for HPUX 9.0 yet. news://comp.lang.java news://comp.lang.javascript ftp://rtfm.mit.edu/pub/usenet/comp.lang.java/comp.lang.java FAQ The FAQ has a more comprehensive list of the site and a list of books on Java. O@l-L @CA Aix 3. X e, CA VA OS 'C> VI a' O'flt L7@S CS rO V07 t7 0 ll?te-IlWq VP - oe, es. 't ;s s+('(' i, eall@ be@, E import java.awt.*; import java.applet.*; import java.lang.*; public class ChangeColor extends Applet Color whichcolor; public void inito setlayout(new GridLayout(l,l)); setBackground(Color.black); public void paint(Graphics g) g.setColor(Color.red); g.fillRect(5, 5, 140, 140); public void update(Graphics g) g.setColor(whichColor); g.fillRect(5, 5, 140, 140); public boolean handleEvent(Event e) switch (e.id) case Event.MOUSE-DOWN: whichcolor = Color.white; repainto; return true; case Event.MOUSE-UP: whichcolor = Color.red; repainto; return true; default: return false; Lisp-like scoping - An anonymous inner class can access the members of the class in which it was declared, in the same way which an ordinary inner class can - It can also access any lexically scoped variable in the enclosing code which is declared f inal Anonymous inner classes In arbitrary code, when you say new whatever(args), you can create a subclass. new classname(args) { body ) This creates an unnamed subclass of the given class and returns an instance of it - This class can't have a constructor, but there can be assignment statements which are evaluated when the class is created Slu,i4 J.. TdU Scoping rules - Standardjavadisambiguation (lexical scoping) is used - this always refers to the current class - By using classname. this. name, you can explicitly access members of the enclosing class(es) S.pA J.@.Th- Inner classes In java 1.1, you can declare a class within the body of another class - This class can only be instantiated from within the declaring class, as it must have a reference to the class which it is enclosed within. Ove,rvip-w - Anonymous inner classes - Latnbda in disguise - Reflection and the metadata interface - Classloaders S.,gd J.. Tdd. Stupid Java Tricks CSUA Help Session Nick Weaver S.Vid J@.Ti@U Equivalence to Lambda We can access all non-local variables in the satne way as Scheme's lambda - f inal restriction can be overcome through an extra layer of indirection, such as a one element array - Although the affay can't be reassigned once declared, the element within the array can be assigned normally S.rW J-. Td@@ What is this good for? - Programming tools, debuggers, inspectors, etc - Java Beans and other abstractions S.," J.. Tfi@ What to do with a classloader Use it to dynamically load modules - Make a new classioader for each module, so the modules don't interfere with each other Build a cacheing loader - Store the classes locally, but check on the server to see if the classes have updated, make an auto-updating application public MyList(object (I ar){ Assert.assert(ar.length > 0); cdr = null; for(int i = ar.length - 1; i > 0; i--)( cdr = new MyList(ar[i], cdr); car = ar(O]; public java.util.Enumeration enumerates{ return new java.util.Enumerationo{ MyList head = MyList.this; public boolean hasMoreElementso{ return head null;l public Object nextelemento{ MyList tmp = head; head = head.cdr; return tmp.car; public MyList map(Lambdal fn){ return new MyList(fn.fn(car), (cdr null) ? null cdr.map(fn)); public void mapc(Lambdal fn)( fn.fn(car); if(cdr != null){ cdr.mapc(fn); public void mapm(Lambdal fn){ car = fn.fn(car); if(cdr != null){ cdr.mapc(fn); public Object accumulate(Lambda2 fn){ if(cdr == null){ return car;) return fn.fn(car, cdr.accumulate(fn)); public String tostring(final String space){ return '( I + accumulate(new Lambda2()( public Object fn(Object a, Object b){ return a + space + b; public String tostringo{ return tostring(' 11); public static void main(String args[]){ MyList 1 = new HyList( (object [1) args); System.out.println{'Argument list is: " + 1); final String addthis = args[O]; System.out.println(I'Mapped list is: " + I.map(new Lambdal(){ public Object fn(Object o)( return addthis + o; // information. System.err.println("Unable to do mapping + "because the reflection interface..); System.err.println(Ilis not permitted by the current Security Manager"); throw new Error("Unable to comply due to current security policy"); Iterate over all the fields we just got. for(int i = 0; i < allfields.length; ++i)t If the declared type of the field is castable to the type we are iterating over... if(type.isAssignableFrom(allFields(il.getTypeo))( try ( // Get the value in the field and if it is non null ... if(allFields[il.get(o) != null)( // call mapper.fn on the value. mapper.fn(allFields(il.get(o)); If we can't access the field legally catch (IllegalAccessException e)( // Say so and move on. System.err.println('Unable to access + allFields[i]); If the field is an array type, and did NOT match the type we were looking for else if(allFields[i].getTypeo.isArrayo)( try { // If it is non null ... if(allFields(il.get(o) != null){ Get the array and pass it into forAllobjectArraysofType with the declared type of this component. forAllObjectArraysOfType(mapper, type, (Object [j) allPields[ij.get(o), allPields(i].getTypeo. getComponentTypeo); catch (IllegalAccessException e)f // Once again, if we can't access this array, move on. System.err.println("Unable to access 11 + allFields[i]); We now examine the next level up in the class heirarchy. myclass = myClass.getSuperclasso; This is for handling arrays of a given type, and is called by forAllObjectsOfTypeo. @see Mapper#forAllObjectsInObjectofType(MapObject, Class) private static final void forAllObjectArraysOfType(Lambdal mapper, Class type, Object [] array, Class arraytype)( If the type the array holds can be cast to the type we are interested in... if(Eype.isAssignableFrom(arrayType)){ // Iterate over the array List Example continued public String tostring(final String space)( return -( - + accumulate(new Lanibda2()( public object fn(object a, Object b)( return a + space + b; + public String tostringo( return tostring(l S.@d )-. Td@ An example: if(type.iSAssignableFrom( allFields[i].getTypeo))( try ( if(allrieldoli].get(o) '= null)( mapper.fn(allrields[i].get(o)); catch (illegalAccessException a)( System.err.println('Unable to access + allFields[i]); An example: public class @lasoloader extends ClaseLoaderl Hashtable cache - new Hashtable(); protected class loadClase(String name, boolean resolve) tlxrows ClassNotFoundlException( Class c - (Class) cache.get(nww); if(c -= null)( byte data[] - gotDataByName(name); if(data -- null)i return findsystemclass(name);) c - defineclass(name, data, 0, data.length); cache.put(name, c); ) if(resolve) resolveClass(c); return c; ---------- Assert.java ---------- package helpsession; public final class Assert( public static void assert(boolean value)( if(!value)( throw new Error("Assertion failed,,); public static void assert(boolean value, String message)( if(ivalue)f throw new Error("Assertion failed: + message); public static void assert(String s)( assert(false, s); ---------- Lambdal.java ---------- package helpsession; public interface Lambdalf public Object fn(Object o); ---------- Lambda2.java ---------- package helpsession; public interface Lambda2f public Object fn(object ol, object o2); ---------- MyList.java ---------- package helpsession; public class MyList f protected object car; protected MyList cdr; public MyList(Object a)( car = a; cdr = null; public MyList(Object a, MyList b)( car = &; cdr = b; ---------- Mapper.java ---------- This code is written by Nicholas Weaver inweaver@cs.berkeley.edu) and may be freely distributed as long as it is unchanged and this notice remains intact. package helpsession; import java.lang.reflect.Field; - This object provides the ability to map over all fields of a given type I declared in any object which this has access to. There is a * a single method accessable to the outside, @ but it represents a very powerful abstraction. ./ public class Mapper f -This method will iterate over all fields which are castable to a -given type which it @has access to, NOT JUST the public ones. It will also iterate over Iall arrays which contain objects castable to a given type. it calls -mapper.fno on every non-null object it can access of the proper *type. It is based on the declared type of the data, not the dynamic type. -It is even powerful enough so that it will also map over arrays containing -data of the specified type. * @@param mapper This object's fno method will be called on *every non null slot castable to the specified type. -@param type This represents the type of slot being mapped over. IOparam o This is the object being examined. @ *@see Mapper#forAllObjectArraysOfType(MapObject, Class, Object [1, Class); *@see Lambda#fn @/ public static final void forAllObjectsInObjectOfType(Lambdal mapper, object o, Class type)( This is a;l fields in a. given level of the class heirarchy. Field [] allfields; This is the class we are examining, starting with the dynamic type of class o and working up the heirarchy. Class myclass = o.getclasso; // Iterate up the class heirarchy, stop when there is no superclass. while(myclass != null)f try ( Gets the fields declared at the current level of the class heirarchy. allfields = myClass.getDeclaredFieldso; catch (SecurityException e)( However, many security managers (EG, while as applets) don't like the idea of unfettered access to reflection information. Most do allow getfieldso, but this only gives public field List Example continued public MyList utap(L--Id-l fn)( return new MyList(fn.fn(car), (cdr -- mxll) ? null : cd3c.zmap(fn)); public object accumulate(Lambd&2 fn)( if(cdr == null)( return car;) return fn.fn(car, cdr.accumulate(fn)); An example: pUbliC static final void fOrAllObiOctSInObjectOfType(Lambdal mapper, Object o, Class type)( Field [] allfields; Class @lass - o.getclass(); while(myclass I= null)( try(allfields = myClass.getDeclaredFields();) catch (SecurityException a)( throw new Error(,Anal security manager-); for(int i = 0; i < allfields.length; ++i)( @.,W J-. Td@. Classloaders A classloader is a way to define a new way to get a class into the j ava runtime - Such as over the network, from a cache, or some other way Also, a classloader defines a totally separate namespace - Any requests by a class loaded by a given classloader automatically go through the classloader s.ri'd )-,Fdd. List Example continued public Java.util.Enumeration enumerates( return new java.util.Enumerationo( @ ist head - MyList.this; public boolean hasMorsElements()( return head I= null; public object nextelemento( MyList tmp - head; head = head.cdr; return tmp.car; S.pid J.@. TdU Vvlhat the metadata interface does not allow - Runtime code generation - Ability to perform "disallowed" actions - All attempts to obtain the metadata objects is checked by a security manager, and may be limited to just the public members, or denied completely - All attempts to use the metadata objects are only allowed when that code would normally be able to access that data. ,11.pid J.. T4,@, Example-. A Lisp-ish list class lic class MyList ( protected object car; protected MyList cdr; public MyList(Object a)( car = a; cdr = null; public MyList(object a, MyList b)f car = a; cdr = b; What the metadata interface allows -One can take an object and determine its class -Given a class, one can get Field, Method, and Constructor objects which refer to all fields, methods, and constructors S.,WJ..Td@ A couple of interface definitions lic interface Lambdal( public Object fn(object o); lic interface Lambda2f public object fn(object ol, object o2); @l.,id )-. T@@ Reflection and metadata - Metadata refers to data concerning the structure of programs which can be accessed from within a program - Java's metadata interface is contained within the classes in j ava. lang. re f 1 ec t and methods within class Class Sl.rAd J.. Td@V, ---------- This is a simple classloader which first attempts to look for a class.munged file in the classpath (a class file XORed with Ox69) If it doesn't, it has the normal system loader load the class. package helpsession; import java.lang.ClassLoader; import java.lang.reflect.methoa; import java.util.Hashtable; import java.io.1; public class myclassloader extends ClassLoader( Hashtable cache = new Hashtableo; protected static final String []myClassPath protected byte(] getDataByName(String name)( String filename = I'll; for(int i = 0; i < name.lengtho; ++i)f if(name.charAt(i) == '.') C filename = filename + else[ filename = filename + name.charAt(i); filename = filename + ".class.munged"; try[ for(int i 0; i < myClassPath.length; ++i){ File f new File(myClassPath[il,fileName); if(f.exists())( FileInputStream fstream = new FileinputStream(f); byte (I b = new byte[(int) f.lengtho]; fstream.read(b); for(int j = 0; j < b.length; ++j)( b[j] = (byte) (b[j] ' Ox69); return b; )catch (FileNotFoundP-xception e)f It Shouldn't be reached, but needed to placate @ava Assert.assert("Can't find class file ' + filename); )catch (IOException e)( Assert.assert('IO Exception I + e); ) return null; protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException( System.out.println(,Atternpting to load class " + name); Class c = (Class) cache.get(name); if(c == null)( byte data[] = getDataByName(name); if(data == null)( System.out.println('Class not found, loading through systeml)i return findSystemClass(name); System.out.println('Class found, loading,,); for(int i=O; i < array.length; ++i)( // and call mapper.fno on all non-null values. if(array(i] != null)( mapper.fn(array(il); Otherwise if it is an array of arrays ... else if(arrayType.isArrayo){ for(int i=C; i < array.length; i++)( if(array[i] != null)( do a recursive call on all non-null slots with the slot-type as the type argument. forAllObjectArraysOfType(mapper, type, (Object []) array[i], arrayType.getComponentTypeo); ---------- mungeclass.java ---------- package helpsession; import java.io.1; public final class MungeClassf public static void main(String args[])( try{ for(int i = 0; i < args.length; ++i)f String sourcename = args(i]; String destname = args(i]+".munged'; File sourcefile = new File(sourceName); File destfile = new File(destName); Assert.assert(sourceFile.existso, "File + sourcename + .1 does not exist'); if(destFile.existso){ Assert.assert(destFile.deleteo, "Failed to delete destination + destname); FileInputStream sourcestream = new FilelnputStream(sourceFile); FileOutputStream deststream = new FileOutputStream(destFile); byte [] b = new byte[(int) sourceFile.lengtho]; sourceStream.read(b); for(int j = 0; j < b.length; ++j)( bljl = (byte) (blil @ Ox69); destStream.write(b); deststream.closeo; ) catch (Exception e)( e.printStackTraceo; Assert.assert("Caught exception + e); ) ---------- MyClassLoader.java c = defineclass(name, data, 0, data.length); cache.put(name, c); if(resolve){ resolveClass(c); return c; public static void main(String args[l)( try { MyClassLoader cl = new MyClassLoadero; Assert.assert(args.length >= 1, '-Specify the class to run on the command line!"); Class loaded = cl.loadClass(args[O]); System.out.println(I'Loaded class is 11 + loaded); System.out.println("Executing class's main"); Class (I argtypes = f(args).getClasso); String [I argstring = new String(args.length - 11; for(int i = 1; i < args.length; ++i)( argString[i-11 args(i]; Object (I argobjs ((Object) argstringl; loaded.getMethad(I'main", argTypes).invoke(null, argobjs); catch (Exception e){ e.printStackTraceo; Asser'tiassert(false, "Caught exception \nll + e);