Image I/O in Java
An icon in Java GUI is represented by an object of type Icon, and Icon is an interface rather than a class.
A Picture on a Button
Buttons, labels, and menus in a Java graphical interface often show a small picture next to their text. That picture is not simply dropped onto the component. Java expects the picture to be wrapped in a particular kind of object first, and then the graphical interface knows how to display that wrapped object. This article follows that wrapping step from start to finish, so you can see which piece of code is responsible for what.
What do you think happens?
Assume image is already an Image object. Which of these lines compiles without error?
Reveal answer
Only the third line, Icon c = new ImageIcon(image);, compiles.
Icon is an interface, and an interface cannot be created directly with new. The second line tries to store a general Icon into a variable of the more specific type ImageIcon, which is not allowed without a specific cast. The third line creates an ImageIcon, and an ImageIcon can be stored in a variable of type Icon because ImageIcon implements that interface. You will trace the reasons in the sections below.
Icon as a Description, Not a Recipe
An icon in a Java GUI is represented by an object of type Icon. Icon is an interface, not a class. An interface describes what a type promises to provide, and it does not itself say how that promise is kept.
The name Icon refers to a type that describes what an icon is in a Java GUI. It is the general description. Because it is a general description, the name Icon by itself does not tell you how a particular icon is built from a picture. A programmer who declares a variable as Icon is saying that the variable will hold something that behaves as an icon. The specific object behind it can be chosen separately.
This separation is why the general type appears on the left of many declarations. The variable promises only that it holds an icon-like object. The code that decides which concrete class to use can change without changing the declared type of the variable. This is a common reason to prefer writing the interface name in a declaration rather than the concrete class name.
Tracing an Image Into an Icon
Creating an icon from a picture happens in four steps. First, you have an Image object, which holds a picture. Second, you pass that image to the constructor of ImageIcon by writing new ImageIcon(image). Third, Java produces an ImageIcon object whose picture is the image you supplied. Finally, you can store that result in a variable of type Icon, because ImageIcon implements the interface.
Turning a picture into an icon for a button
You already have an Image object named logo. You want a variable that can be used anywhere the GUI expects an icon. Show how the logo becomes an icon.
- 1Start with the picture
The Image object logo already holds the picture. Loading it is a separate job and is not part of this step.
- 2Call the constructor
Write new
ImageIcon(logo). This passes the picture to the ImageIcon constructor. - 3Receive the ImageIcon
Java produces an ImageIcon object whose picture is logo. Store it as ImageIcon wrapped = new
ImageIcon(logo);. - 4Widen the declared type
Assign the result to Icon icon = wrapped; or directly Icon icon = new
ImageIcon(logo);. The variable now promises only that it holds an icon.
The variable icon refers to an ImageIcon object whose picture is logo. Its declared type is Icon, which is the general description.
Declared Type Versus Created Object
The class ImageIcon implements the Icon interface. That relationship has two sides. The interface Icon is the contract: it describes what an icon is. The class ImageIcon is the concrete implementation: it is one specific way of satisfying that contract, built from a picture. Because ImageIcon implements Icon, an ImageIcon object can be stored in a variable whose declared type is Icon.
When a variable is declared as Icon but refers to an ImageIcon object, the object that actually exists in memory is the ImageIcon. The variable's declared type limits what you can rely on through that variable. You can use the operations that the Icon type promises. The variable does not change the object itself, and it does not reveal that the object was built from an Image unless you check its class. The specific class is chosen when the object is created, and it stays the same object behind the general name.
Mistakes When Declaring and Creating Icons
Common mistake Creating an Icon directly with new
What it looks likeIcon a = new Icon(image);Why it failsIcon is an interface, and an interface describes a type without being a class you can instantiate. The line does not compile because there is no concrete object to create.
Do this insteadCreate a concrete class that implements Icon, such as ImageIcon, and then assign it: Icon a = new ImageIcon(image);Common mistake Declaring the more specific type from a general type
What it looks likeImageIcon b = new Icon(image);Why it failsThis tries to create an Icon, which is not allowed because Icon is an interface. Even apart from that, the declared type ImageIcon is more specific than the Icon that would be created.
Do this insteadUse the concrete class on both sides when you need that exact type: ImageIcon b = new ImageIcon(image);Common mistake Confusing the constructor call with loading the picture
Why it failsThe constructor new
ImageIcon(image)only wraps an Image that already exists. Expecting it to read the picture from a file is a mismatch between the two separate jobs.Do this insteadMake sure the Image object exists first, then pass it to the constructor. Loading the image is handled separately.
Common mistake Forgetting that the declared type limits which methods you can call through the variable
| Line | Compiles? | Reason |
|---|---|---|
| Icon a = new Icon(image); | No | Icon is an interface and cannot be created with new |
| ImageIcon b = new Icon(image); | No | An Icon cannot be created, and the types do not match |
| Icon c = new ImageIcon(image); | Yes | ImageIcon implements Icon, so an ImageIcon can be stored as an Icon |
Three declaration and creation lines compared
Practice Tracing Icon Code
You have an Image object named photo. Write the one line that creates an ImageIcon from photo and stores it in a variable named badge whose declared type is Icon. Then explain in one sentence why the declared type Icon is allowed on the left.
Hints
- Use the constructor call new
ImageIcon(photo)on the right side. - Remember that ImageIcon implements the Icon interface, so an ImageIcon can be stored in a variable of type Icon.
- Expected line: Icon badge = new
ImageIcon(photo);
Key Takeaways
- An icon in a Java GUI is represented by an object of type Icon, and Icon is an interface rather than a class.
- ImageIcon is a class that implements Icon, so an ImageIcon object can be stored in a variable whose declared type is Icon.
- The constructor call new
ImageIcon(image)takes an existing Image object and produces an ImageIcon whose picture is that image. - Creating an icon is the wrapping step only; loading the Image from a source such as a resource file is a separate job.
- An interface such as Icon cannot be created directly with new, so the object must be created from a concrete class.