Before you write code for a big program, it helps to draw it. A UML class diagram is that drawing. UML stands for Unified Modeling Language, which is just a standard way of drawing software designs so that everyone reads them the same way.
A class diagram shows:
- the classes, interfaces and enums in the program
- what each one holds (its attributes, also called fields)
- what each one can do (its operations, also called methods)
- how they are connected to each other
You can use a class diagram in two ways:
- Design first. You draw the classes, talk about them with your team, and then write the code.
- Code first. You already have the code, and a tool draws the diagram from it. This helps a new person understand the program without reading every file.
Teams usually draw a rough diagram at the start of a project and update it as the project grows. It shows the real-world things the system is about (like Customer and Order), what gets stored, and how the big parts fit together.
Once you can read a class diagram, you can see what parts a system has and how they work together, even if you have not read the code.
This note is about the boxes: what goes inside a class box, how to show who can access what, how interfaces, abstract classes and enums look, and how much detail to draw for different people. The lines between the boxes are covered in Class Relationships. Section 9 below has a short summary of them.
1. The class box
A class is drawn as a rectangle with three parts, one on top of the other:
| Part | What goes in it |
|---|---|
| Top | The name of the class |
| Middle | The attributes (the data it keeps) |
| Bottom | The operations (the methods it has) |
Here is a Person class drawn by hand:
+---------------------------+
| Person | <- name
+---------------------------+
| - name: String | <- attributes
| + age: int = 21 |
+---------------------------+
| + getName(): String | <- operations
| - isAdult(age: int): bool |
+---------------------------+
And here is the same box in Mermaid. Mermaid is the tool this website uses to draw diagrams from text, so you will see it in every diagram in this note:
Every line inside the box has three things: a small symbol at the start (the next section explains it), a name, and a type. For an attribute, the type is the kind of data it holds, such as String. For a method, the brackets hold the inputs, and the type after them is what the method gives back.
You do not have to show all three parts. If a class has no attributes, leave that part out. You can even draw a box with only the name. Section 8 explains when to do that.
A small difference to know about: real UML writes the name first and the type after a colon, like
age: int. Mermaid writes the type first, likeint age. They mean the same thing. The tables in this note show the real UML way, and the Mermaid diagrams use the Mermaid way.
2. Visibility markers
The first character on every attribute and method says who is allowed to use it. This is called visibility.
| Marker | Name | Who can use it | Java word |
|---|---|---|---|
+ | Public | Any other class | public |
- | Private | Only the class itself | private |
# | Protected | The class itself and the classes that extend it | protected |
~ | Package | Classes in the same package | (nothing, the default) |
These markers show encapsulation. This means the data stays hidden inside the class, and other classes can reach it only through methods. The usual good pattern is private attributes (-) with public methods (+).
How to read this: balance is private, so no outside class can change it directly. They have to call deposit(), which can check the amount first. If you see a + in front of an attribute, ask why that data is open to everyone.
3. How to write an attribute
The pattern is:
visibility name: Type [multiplicity] = defaultValue
| Part | What it means | Must you write it? |
|---|---|---|
| visibility | +, -, # or ~ | Yes |
| name | The name of the attribute | Yes |
| Type | The kind of data, like int or String | Yes |
| multiplicity | How many values it holds, like 0..1 or 1..* | No |
| defaultValue | The value it starts with | No |
Multiplicity is just a count. 0..1 means "none or one" (the value is optional). 1..* means "one or many". 0..* means "any number, even none".
Here is the same attribute in Java and in UML:
| Java | UML |
|---|---|
public int age = 21; | + age: int = 21 |
private String name; | - name: String |
private List<String> phones; | - phones: String [0..*] |
private String nickname; (may be null) | - nickname: String [0..1] |
protected static int count = 0; | # count: int = 0 (underlined) |
Notice the last row. A static member belongs to the class itself, so all objects share one copy. In UML you underline the whole line, which plain text cannot show here. In Mermaid you add a $ at the end instead. The # is the protected marker, not a static marker.
4. How to write a method
The pattern is:
visibility name(parameterName: Type, ...): ReturnType
| Part | What it means |
|---|---|
| visibility | +, -, # or ~ |
| name | The name of the method |
| parameterName | The name of each input |
| Type | The type of each input |
| ReturnType | What the method gives back (void if nothing) |
Take this Java class:
class Person {
private boolean isAdult(int age) {
return age >= 18;
}
}The method in UML is:
- isAdult(age: int): boolean
Read it from left to right: private, called isAdult, takes an int called age, and gives back a boolean.
More examples:
| Java | UML |
|---|---|
public void deposit(double amount) | + deposit(amount: double): void |
public String getName() | + getName(): String |
public Order place(Cart c, String coupon) | + place(c: Cart, coupon: String): Order |
protected abstract void refund() | # refund(): void (written in italics) |
A constructor is shown with the class name and no return type. Some people add the label <<constructor>>. Most diagrams leave constructors out so the box stays small.
5. Interface
An interface is a list of promises. It says what a class must be able to do, but not how it does it. For example, Payable says "I can calculate pay". It does not say how.
An interface box has two parts:
- The top part has the label
<<interface>>above the name. A label in double angle brackets is called a stereotype. It tells you what kind of box this is. - The bottom part lists the method signatures.
There is no attribute part, because an interface does not store data. The only time you add one is when the interface has constants (fixed values).
interface Payable {
double calculatePay();
}The dashed line with a hollow triangle means "implements". Employee signs up to the promise, so it must write its own calculatePay(). The triangle always points at the interface.
6. Abstract class
An abstract class is a half-finished class. You cannot create an object from it with new. It can have normal methods that already work, and abstract methods that have no body yet. Child classes must write the body of each abstract method.
It is drawn like a normal class, with two changes:
- The label
<<abstract>>goes above the name. - The class name is written in italics. Abstract methods are in italics too.
abstract class Animal {
protected String name;
public abstract void makeSound();
public void sleep() { /* the same for all animals */ }
}In Mermaid, a * after the brackets marks an abstract method. Dog is a normal class, so it has to give makeSound() a real body. It gets name and sleep() from Animal for free. The solid line with a hollow triangle means "inherits from" (a Dog is an Animal).
Here is how to tell the three kinds of box apart:
| You see | What it is |
|---|---|
<<interface>> | Only promises. No data and no method bodies. |
<<abstract>> | A half-finished class. You cannot make an object from it. |
| No label | A normal class you can use with new. |
7. Enumeration
An enum is a type that can only be one value from a small, fixed list. Each value is called a literal. A good example is the status of an order: it can be placed, packed, shipped, and so on, and nothing else.
An enum box has the label <<enumeration>> above the name, and the literals listed in the part below.
enum OrderStatus {
PLACED, PACKED, SHIPPED, DELIVERED, CANCELLED
}Order has a field of type OrderStatus, so an arrow goes from Order to OrderStatus. The literals have no + or - in front, because they are always public.
8. Three levels of detail
You can draw the same system with more or less detail, depending on who will read it. UML calls these levels perspectives.
Many beginners draw every field and method every time. That is a mistake. A business person cannot read it, and even a developer gets lost. Pick the level that fits the reader.
| Perspective | Who reads it | Why you draw it | What you show |
|---|---|---|---|
| Conceptual | Business analysts, domain experts | To agree on what things exist | Only class names and how they relate |
| Specification | Architects, designers | To decide who is responsible for what | Interfaces, abstract classes, important public methods |
| Implementation | Developers | To guide the code that will be written | Every attribute and method, with visibility and types |
Here is the same online shop at all three levels.
Conceptual. Only the real-world things, and the words the business uses to link them, such as "places". No attributes and no methods.
Specification. What each part promises to do. You show interfaces and the main public methods, and leave out private details.
Implementation. Everything a developer needs in order to write the class.
At this level, you draw every kind of line: association, aggregation, composition, inheritance, realization and dependency.
A good habit: start with the conceptual view, and add detail only for the part you are explaining right now. In an interview, a specification-level diagram with a few key methods usually works better than one full of fields.
9. The lines between boxes: a short summary
Each kind of relationship has its own line and its own arrow end. The full explanation, with Java code and database tables, is in Class Relationships.
| Relationship | What it means | How it is drawn | Example |
|---|---|---|---|
| Association | One class knows about or uses another | A plain line | Teacher and Student |
| Aggregation | A whole has parts, and the parts can live without it | A hollow diamond on the whole | A Department has Professors |
| Composition | A whole owns its parts, and they die with it | A filled diamond on the whole | A House has Rooms |
| Inheritance | One class is a kind of another | A solid line with a hollow triangle on the parent | A Dog is an Animal |
| Realization | A class implements an interface | A dashed line with a hollow triangle on the interface | A Circle implements Shape |
| Dependency | One class uses another only for a short time | A dashed line with an open arrow | OrderService uses PaymentService |
10. How to read a diagram, step by step
When you get a new diagram, do these things in order:
- Look at the labels first.
<<interface>>,<<abstract>>and<<enumeration>>tell you which boxes are promises and which are real classes. - Follow the hollow triangles. They point from a child to its parent or interface. This shows you the family tree of the design.
- Find the diamonds. A diamond sits on the whole and means "this is made of those parts". A filled diamond means the whole owns the parts.
- Read the numbers on the lines.
1,0..1and*tell you how many objects are on each side. For example, oneOrderhas1..*items. - Check the visibility. Private attributes (
-) and public methods (+) are normal. A public attribute is worth a question. - Look at the dashed arrows. They are short-term uses. If many dashed arrows point at one class, many classes depend on it, so changing it is risky.
11. Common mistakes
| Mistake | Why it is a problem |
|---|---|
| Showing every getter and setter | The box gets long and the important methods get lost |
| Using the implementation level for a business reader | They cannot follow it and stop trusting the diagram |
| Putting the diamond on the wrong end | The diamond always goes on the whole, not on the part |
| Mixing up filled and hollow diamonds | It changes the meaning from "owns" to "just borrows" |
Forgetting <<interface>> or <<abstract>> | Readers think it is a normal class and miss that it is a contract |
| Leaving out the numbers on lines | One-to-one and one-to-many look the same |
| Pointing the triangle at the child | The triangle always points at the parent or the interface |
| Drawing the whole system in one diagram | Split it by area and draw only the classes the story needs |
Related
- Class Relationships for association, aggregation, composition, dependency, the numbers on lines, and database tables.
- OOP Fundamentals for classes, encapsulation, abstraction and inheritance, which are the things this note draws.
- Coupling and Cohesion for what the lines in a diagram cost you when the code changes.
- Interfaces, Abstract Classes and Inheritance and Enums for the Java code behind the three special boxes.
Interview questions
"What is a UML class diagram and what is it used for?"
It is a drawing of the structure of a system. It shows the classes, interfaces and enums, what attributes and methods each one has, and how they are connected. Teams use it to plan a design before coding, to explain a system to new people, and to understand existing code.
"What are the parts of a class box?"
There are three parts. The top has the class name, the middle has the attributes, and the bottom has the methods. Each line in the middle and bottom has a visibility symbol, a name and a type.
"What do the visibility markers mean?"
+is public,-is private,#is protected and~is package. They show encapsulation. Private data with public methods is the usual pattern.
"How do you write an attribute and a method in UML?"
An attribute is
visibility name: Type [multiplicity] = default, for example+ age: int = 21. A method isvisibility name(param: Type): ReturnType, for example- isAdult(age: int): boolean.
"How is an interface different from an abstract class in a diagram?"
An interface has the label
<<interface>>, lists only methods, and has no attributes. A class connects to it with a dashed line and a hollow triangle. An abstract class has the label<<abstract>>and an italic name. It can have attributes and methods with bodies. A child class connects to it with a solid line and a hollow triangle.
"How is an enum shown?"
It is a box with the label
<<enumeration>>above the name, and the values listed below. Classes that use the enum have an arrow pointing to it.
"What are the three perspectives of a class diagram?"
Conceptual shows only the main things and how the business relates them. It is for analysts and domain experts. Specification shows interfaces, abstract classes and the key public methods. It is for architects and designers. Implementation shows every attribute and method with visibility and types. It is for developers.
"What is the difference between aggregation and composition?"
Both mean a whole has parts. In aggregation the parts can live without the whole, like professors in a department. It uses a hollow diamond. In composition the parts die with the whole, like rooms in a house. It uses a filled diamond. The diamond is always on the whole's side.
"Which arrow end means inheritance and which means realization?"
Both use a hollow triangle that points at the parent. Inheritance uses a solid line. Realization, which is a class implementing an interface, uses a dashed line.
"How much detail should you put in a class diagram?"
Only as much as the reader needs. For business people, show names and relationships. For a design discussion, show interfaces and the key public methods. Show every field and method only when developers are about to write the code.