Java Technology Home Page
A-Z Index

Java Developer Connection(SM)
Technical Tips

Downloads, APIs, Documentation
Java Developer Connection
Tutorials, Tech Articles, Training
Online Support
Community Discussion
News & Events from Everywhere
Products from Everywhere
How Java Technology is Used Worldwide
Print Button
 
Tech Tips archive

Tech Tips
August 09, 1999

This issue presents tips, techniques, and sample code for the following topics:


Using Coordinate Transformations With the Java2DTM API

In the JavaTM language, you can use the Graphics class in the AWT (Abstract Window Toolkit) to draw graphical entities such as lines, text, and images. The Java 2 Platform introduced a new class for graphics rendering, Graphics2D. This new class is a subclass of Graphics. It extends the capabilities of the Graphics class in areas such as geometry, color management, text layout, and coordinate transformations. These enhanced graphics features are part of the Java2DTM API.

Let's look at an example of using coordinate transformations:

 
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
    
class myComponent extends JComponent {
  private static final int N = 300;
    
  public Dimension getPreferredSize() {
    return new Dimension(N, N);
  }
    
  public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D)g;
    
    AffineTransform aft = AffineTransform.
      getRotateInstance(Math.PI, N / 2, N / 2);
    g2d.setTransform(aft);
    
    Font f = new Font("monospaced", Font.BOLD, 24);
    g2d.setFont(f);
    String s = "testing";
    g2d.drawString(s, 100, 100);
    FontMetrics fm = getFontMetrics(f);
    int h = fm.getHeight();
    int w = fm.stringWidth(s);
    g2d.drawLine(100, 100 + h, 100 + w, 100 + h);
  }
}
    
public class graph2d {
  public static void main(String args[]) {
    JFrame f = new JFrame("testing");
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    
    JPanel p = new JPanel();
    p.add(new myComponent());
    f.getContentPane().add(p);
    
    f.pack();
    f.setVisible(true);
  }
}

The example draws some text in a window. The text's font style is bold and its font size is 24-point. The example also draws a line under the text. The actual drawing is done relative to an instance of the Graphics2D class, an abstract class that extends Graphics. Because Graphics2D is abstract, you can't create an instance of it directly, but you must subclass it in some way. This example uses an internal class, "sun.awt.image.BufferedImageGraphics2D", for this purpose. You can see this if you add a line:

    System.out.println(g);

just inside the paint method. The paint method uses a parameter of type Graphics rather than Graphics2D, so casting to the subclass is necessary.

just inside the paint method. The paint method uses a parameter of type Graphics rather than Graphics2D, so casting to the subclass is necessary.

Notice the coordinate transformation in the example. There's a 300 x 300 window, and a rotation transform centered around (150,150) is specified. The rotation is for PI radians. If you remember your trigonometry, a circle is divided into 2*PI (about 6.28) radians, and so a rotation of PI radians is one-half of this, or 180 degrees out of a total of 360 degrees.

The net effect of this rotation is to draw the text upside down, with the underline above the text. In other words, the text and line are transformed before they are drawn.

Other kinds of transformations that are available in the Graphics2D context include translation and scaling.


USING LIST COLLECTIONS EFFICIENTLY

Collection classes such as ArrayList are relatively new Java features. These classes implement a collection interface, that is, an abstract data type that represents a collection. Two implementations of the list interface are ArrayList and LinkedList.

The various list class implementations have performance tradeoffs. To see what some of these tradeoffs are, let's look at three short examples. Each example creates and uses an ArrayList or a LinkedList, depending on which statement in the example is used to create the object. Try running each example as is, that is, using an ArrayList. Then run the LinkedList version by commenting out the statement that creates an ArrayList and uncommenting the statement that creates a LinkList.

The first example simply adds elements to the list structure:

   
import java.util.*;
    
public class list1 {
  public static void main(String args[]) {
    List lst = new ArrayList();
    //List lst = new LinkedList();
    final int N = 25000;
    for (int i = 0; i < N; i++)
      lst.add(new Integer(i));
  }
}

The second example adds elements and then looks them up via "get":

public class list2 {
  public static void main(String args[]) {
    List lst = new ArrayList();
    //List lst = new LinkedList();
    final int N = 25000;
    for (int i = 0; i < N; i++)
      lst.add(new Integer(i));
    for (int i = 0; i < N; i++)
      lst.get(i);
  }
}

The third example adds elements and then deletes the first element in the list until all are gone:

import java.util.*;
    
public class list3 {
  public static void main(String args[]) {
    List lst = new ArrayList();
    //List lst = new LinkedList();
    final int N = 25000;
    for (int i = 0; i < N; i++)
      lst.add(new Integer(i));
    for (int i = 0; i < N; i++)
      lst.remove(0);
  }
}

The running times of these programs are:

                 ArrayList   LinkedList

    list1 (add)       0.4          0.4

    list2 (get)       0.4         21.3

    list3 (remove)    6.9          0.4

So adding new elements is pretty fast for either type of list. For the ArrayList, doing random lookup using "get" is fast, but for LinkedList, it's slow. It's slow because there's no efficient way to index into the middle of a linked list. When removing elements, using ArrayList is slow. This is because all remaining elements in the underlying array of Object instances must be shifted down for each remove operation. But here LinkedList is fast, because deletion can be done simply by changing a couple of links. So an ArrayList works best for cases where you're doing random access on the list, and a LinkedList works better if you're doing a lot of editing in the middle of the list.

An ArrayList uses space more effectively than a LinkedList. That's because a LinkedList uses an auxiliary data structure to store each list element. These data structures are instances of an internal class of the form:

   class Entry {
        Object element;
        Entry next;
        Entry previous;
    }

The point of this exercise is not to convince you to use either ArrayList or LinkedList. Instead it's to make the point that there are substantial differences in how the different list representations perform. The same is true in other areas of the collection classes. For example, HashSet and TreeSet are two ways of representing sets. The first uses a hash table, the second a tree structure. There are tradeoffs between the two representations.

One basic programming tip with collection classes is to program in terms of interfaces rather than specific classes. For example, you might say:

   List lst = new ArrayList();

and then use "List" everywhere in your application, such as when declaring method parameter types. If you do this, you can readily change ArrayList to LinkedList (or even to your own list implementation) at some later point.

The Java Developer ConnectionSM Tech Tips are written by Glen McCluskey.


Print Button
[ This page was updated: 21-Sep-2000 ]
Products & APIs | Developer Connection | Docs & Training | Online Support
Community Discussion | Industry News | Solutions Marketplace | Case Studies
Glossary | Feedback | A-Z Index
For more information on Java technology
and other software from Sun Microsystems, call:
(800) 786-7638
Outside the U.S. and Canada, dial your country's AT&T Direct Access Number first.
Sun Microsystems, Inc.
Copyright © 1995-2000 Sun Microsystems, Inc.
All Rights Reserved. Terms of Use. Privacy Policy.