Topic 53 of 119 6. Object-Oriented Programming in Java Interactive Tutorial

Classes in Java: Blueprints, Components, and Syntax Rules

15 mins read Last updated: 22 Aug 2026 28,044 views

Direct Answer & Core Concept

A class is the blueprint that describes what every object of that type holds and what it can do. It is a reference type, defined once, from which any number of objects are created. A class declaration follows a fixed order: access modifier, then the class keyword, then the name in PascalCase, then optional extends and implements clauses, then the body. Everything inside the body is a member, and members come in two families: state, which is fields, and behavior, which is methods and constructors. Java then imposes rules you must follow or the code will not compile. A top-level class can only be public or package-private, never private or protected. A public class must live in a file whose name matches it exactly, including case. And every class name must begin with a letter, an underscore, or a currency symbol. Those rules exist for practical reasons rather than to be arbitrary. The one-public-class rule means the compiler can find the class without scanning every file, and it is why a file that declares public class Employee must be named Employee.java.

Detailed Explanation & Mechanics

1) The Declaration Syntax

Main.java
Run Online
[accessModifier] class ClassName[extends ParentClass][implements Interface1, Interface2] {
    // members
}

Only class and the name are required. The rest is optional, but the order is fixed, and reordering the clauses is a compile error rather than a style complaint.

Main.java
Run Online
public class SavingsAccount extends Account implements Auditable, Closeable {
    // body
}

Here public is the access modifier, SavingsAccount is the name, Account is the single superclass, and Auditable and Closeable are two interfaces.

2) The Members of a Class

MemberPurposeBelongs to
Instance fieldHolds per-object stateEach object has its own copy
Static fieldHolds state shared by all objectsThe class itself
Instance methodBehavior that uses object stateCalled on an object
Static methodBehavior that does not use object stateCalled on the class
ConstructorEstablishes initial stateCalled by new
Initializer blockRuns extra setup in orderBefore the constructor body
Nested typeA class or interface defined insideScoped to the outer class


Anatomy of a Java class declaration with labelled parts from access modifier to closing brace
Every clause in a class declaration, and where the body members fit inside it.

3) Fields: Instance and Static

An instance field belongs to each object separately. A static field belongs to the class, and exactly one copy exists no matter how many objects were made.

Main.java
Run Online
public class Employee {
    private static int nextId = ONE_HUNDRED;
    // one copy, shared by all
    private static final int MAX_NAME_LENGTH = FIFTY;
    private final int id;
    // per object, cannot change
    private String name;
    // per object, can change
    public Employee(String name) {
        this.id = nextId++;
        this.name = name;
    } public int getId() {
        return id;
    } public String getName() {
        return name;
    } public void setName(String name) {
        if (name == null || name.length() > MAX_NAME_LENGTH) {
            throw new IllegalArgumentException("Name is too long");
        } this.name = name;
    } public static int getCreatedCount() {
        return nextId - ONE_HUNDRED;
    }
}

Declare a field final whenever the value cannot change after construction. A static final field with an initialiser is a compile-time constant, which is why the final keyword topic treats it as its own case.

Static state is shared by every instance and every thread. A mutable static field is one of the easiest ways to introduce a race condition, so keep static fields immutable or confine them to a single thread.

4) Methods: Instance and Static

An instance method operates through this, so it needs an object. A static method has no this at all and belongs to the class.

Main.java
Run Online
// Instance: needs an object, and uses this
public boolean isSenior() {
    return yearsOfService() >= SENIOR_THRESHOLD_YEARS;
}// Static: no this, called on the class name
public static int countAll() {
    return registry.size();
}

The compiler enforces the distinction. Referring to this inside a static method is an error, and so is calling an instance method from a static method without an object to call it on.

5) Constructors Are Not Methods

A constructor shares the class name exactly, has no return type, not even void, and is only ever invoked by new. This is why the rule about void matters so much: writing it turns your constructor into an ordinary method that nothing will call.

Main.java
Run Online
public class Employee {
    private final int id;
    private String name;
    // CORRECT: no return type, same name as the class
    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    } // THIS IS NOT A CONSTRUCTOR, it is a method returning Employee
    public void Employee(int id) {
    }
}

If you declare no constructor, the compiler generates a default one that leaves every field at its default value. Declare an explicit constructor as soon as you have a final field, because otherwise there is no legal way to initialise it.

6) The One Public Class Rule

A single source file may contain any number of top-level classes, but at most one of them may be declared public, and that class must match the file name.

Main.java
Run Online
// Employee.java
public class Employee {
    // legal, name matches the file
    // ...
}class AuditHelper {
    // legal, package-private
    // ...
}class ReportBuilder {
    // legal, package-private
    // ...
}

Declare a second class public in the same file and the compiler rejects it, whatever you name the file. Make the class private and that is also rejected, because a top-level class has no enclosing scope to be private within.

ModifierTop-level classNested class
publicAllowedAllowed
defaultAllowedAllowed
protectedNot allowedAllowed
privateNot allowedAllowed

This is precisely where nested classes become useful, since a nested class can use any modifier. The nested and inner classes topic covers all four kinds.

7) Declaration Order Rules

Inside the class body, order is free. These three restrictions are the ones the compiler actually enforces.

RuleReason
Class names are case-sensitiveEmployee and employee are different types
File name must match the public classSo the compiler can locate the class without scanning
Classes are not hoistedA class may reference one declared later, unlike variables

The last one is a genuine surprise. Using a field before its declaration is a compile error, but using a class declared further down the same file is completely fine, because class declarations are resolved by name rather than by position.

8) Naming Conventions

These are not enforced by the compiler, but code that follows them reads as idiomatic Java.

ElementConventionExample
Class and interfacePascalCaseSavingsAccount
Method and variablecamelCasecalculateInterest
ConstantUPPER_SNAKE_CASEMAX_NAME_LENGTH
Packageall lowercasecom.example.banking
InterfaceNo I or Impl prefixAuditable

Package names are the one place where lowercase is genuinely enforced in practice, since file and directory systems differ in how they treat case.

9) Common Misconceptions

ClaimVerdict
A class holds both the blueprint and the dataFalse. The class is the blueprint; data lives on objects.
A constructor is a methodFalse. It has no return type and is called by new.
Constructors are inheritedFalse. Subclasses must declare their own.
A top-level class can be privateFalse. Only public or package-private.
One class per file is requiredFalse. Only one may be public.
A static field has one copy per objectFalse. There is exactly one copy per class.
A class must be used before it is declaredFalse. Class names resolve regardless of order.
Interfaces and abstract classes are interchangeableFalse. Only abstract classes can hold state.

Frequently Asked Questions

What is the difference between a class and an object?


A class is a blueprint defined once in your source code, describing the fields and methods its objects will have. An object is a concrete instance created from that class, holding its own copy of every instance field and living on the heap until it becomes unreachable.

What can a class contain?


Instance and static fields, instance and static methods, constructors, static and instance initializer blocks, and nested types including nested classes, interfaces, enums, and records. Nested types can have any access modifier, while a top-level class is limited to public or package-private.

Why can a top-level class not be private?


Because a top-level class has no enclosing scope, so private would have no meaning. That restriction is exactly why nested classes are useful, since a nested class sits inside another class and can therefore be private, protected, public, or package-private as the situation requires.

Must the file name match the class name?


Only when the class is public. A public class must live in a file whose name matches it exactly, including case, so the compiler can locate it without scanning. A file may contain any number of additional package-private classes whose names can differ freely.

Why does a constructor not have a void return type?


Because Java distinguishes them syntactically. A member whose name matches the class and which has no return type is a constructor and is invoked by new. Adding void, even once, turns it into an ordinary method that returns nothing, and the class then silently has no constructor of that signature.

Are constructors inherited?


No. A subclass does not receive its parent constructors. If the parent declares no no-argument constructor, the compiler generates a default super call for you, and if it declares constructors with parameters you must call one of them explicitly using super.

What is the difference between a static field and an instance field?


An instance field has one copy per object, so each object holds its own value. A static field belongs to the class, so exactly one copy exists regardless of how many objects you create. Static fields are shared, which also makes them shared across threads and a common source of race conditions.

Can I reference a class before its declaration in the file?


Yes. Class names are resolved by name rather than by position, so using a class declared further down the same file is perfectly legal. Field and variable access is different: reading a field before its declaration is a compile error, because those must appear in textual order.

Runnable Code Example: Classes in Java

Java 17+
Main.java
Run Online
// Every component of a class declaration, in one compilable file.
public class ClassesInJavaDemo {
    // A compile-time constant, because it is static final with an initialiser
    private static final int MAX_NAME_LENGTH = 50;
    private static final int ONE_HUNDRED = 100;
    private static final int SENIOR_THRESHOLD_YEARS = 10;
    // A STATIC field: exactly one copy, shared by every Employee
    private static int nextId = ONE_HUNDRED;
    // INSTANCE fields: each Employee gets its own copy
    private final int id;
    private String name;
    private int yearsOfService;
    // A CONSTRUCTOR: same name as the class, no return type at all
    public ClassesInJavaDemo() {
        this("Unnamed", 0);
        // delegates to the other constructor
    } public ClassesInJavaDemo(String name, int yearsOfService) {
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException("Name is required");
        } this.name = name;
        this.yearsOfService = yearsOfService;
        this.id = nextId++;
    } // An INSTANCE initializer block, which runs before the constructor body
{
        if (name != null && name.length() > MAX_NAME_LENGTH) {
            throw new IllegalArgumentException("Name exceeds " + MAX_NAME_LENGTH);
        }
    } public int getId() {
        return id;
    } public String getName() {
        return name;
    } public void setName(String name) {
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException("Name is required");
        } this.name = name;
    } public void accrueYear() {
        yearsOfService++;
    } // A STATIC method: no this, so it belongs to the class
    public static int getCreatedCount() {
        return nextId - ONE_HUNDRED;
    } public static String describeNamingRules() {
        return "Classes are PascalCase, methods are camelCase, " + "constants are UPPER_SNAKE_CASE";
    } // A NESTED class: allowed any access modifier, including private
    private static class ReportingKey {
        private final String label;
        private ReportingKey(String label) {
            this.label = label;
        } private String getLabel() {
            return label;
        }
    } public String getReportLabel() {
        ReportingKey key = new ReportingKey("employee");
        return key.getLabel() + "-" + id;
    } // A LOCAL class: declared inside a method body
    public static String summarise(ClassesInJavaDemo employee) {
        class Summary {
            private final String text;
            Summary(String text) {
                this.text = text;
            } String render() {
                return text;
            }
        } Summary summary = new Summary( employee.getName() + " has " + employee.yearsOfService + " years");
        return summary.render();
    } public static void main(String[] args) {
        ClassesInJavaDemo sarah = new ClassesInJavaDemo("Sarah Connor", 4);
        ClassesInJavaDemo john = new ClassesInJavaDemo("John Connor", 12);
        System.out.println(sarah.getName() + " id is " + sarah.getId());
        System.out.println(john.getName() + " id is " + john.getId());
        // Both names refer to ONE object, so this is visible through sarah
        ClassesInJavaDemo alias = sarah;
        sarah.accrueYear();
        System.out.println("alias sees " + alias.getName() + " with " + summarise(alias));
        System.out.println("created count is " + getCreatedCount());
        System.out.println(describeNamingRules());
        System.out.println("report label: " + john.getReportLabel());
        // SHOWS THE FIVE RULES THIS FILE DEMONSTRATES
        //
        // 1) FILE NAMING. This file is ClassesInJavaDemo.java because the
        //    public class name matches it exactly, including case.
        // 2) ONE PUBLIC CLASS. Only ClassesInJavaDemo is public. Anything
        //    else declared at the top level must be package-private.
        // 3) NO PRIVATE TOP LEVEL. A top-level class can only be public or
        //    package-private, which is why ReportingKey is nested.
        // 4) CONSTRUCTORS ARE NOT METHODS. ClassesInJavaDemo() has no
        //    return type, so it is a constructor called only by new.
        // 5) MEMBERS MAY APPEAR IN ANY ORDER. Fields, constructors,
        //    initializer blocks, and methods can interleave freely.
        /*
            ACTUAL OUTPUT:

                Sarah Connor id is 100
                John Connor id is 101
                alias sees Sarah Connor with 5 years
                created count is 2
                Classes are PascalCase, methods are camelCase, constants are UPPER_SNAKE_CASE
                report label: employee-101

            THE FIVE COMPONENTS TO KNOW
            1) FIELDS. Instance fields give each object its own state.
               A static field gives the class exactly one shared copy, and
               a static final field with an initialiser is a compile-time
               constant the compiler can inline.
            2) METHODS. An instance method runs through this and needs an
               object. A static method has no this, is called on the class
               name, and cannot touch instance state at all.
            3) CONSTRUCTORS. Same name as the class, no return type, not
               even void, and called only by new. They are not inherited,
               so every subclass declares its own.
            4) INITIALIZER BLOCKS. Static and instance blocks run in order,
               before the constructor body, which makes them useful for
               setup that several constructors would otherwise repeat.
            5) NESTED TYPES. Classes, interfaces, enums, and records can be
               declared inside another class, and unlike top-level classes
               they may use any access modifier including private.
        */
    }
}

Common Java Technical Interview Questions & Answers

Interview Prep
Q1: What is the difference between a class and an object?\nA1: A class is a blueprint defined once in source code that describes the fields and methods its instances will have. An object is a concrete instance created from that class, holding its own copy of every instance field and living on the heap until it becomes unreachable and is collected.\nQ2: What components can a Java class contain?\nA2: Instance and static fields, instance and static methods, constructors, static and instance initializer blocks, and nested types such as classes, interfaces, enums, and records. Nested types may use any access modifier, while a top-level class is limited to public or package-private.\nQ3: Why can a top-level class not be private or protected?\nA3: A top-level class has no enclosing scope, so private and protected would have no meaning for it. That restriction is precisely why nested classes are valuable, since a nested class sits inside another class and can therefore be private when it is only an implementation detail.\nQ4: Must the source file name match the class name?\nA4: Only when the class is public. A public class must live in a file whose name matches it exactly including case, so the compiler can locate it without scanning every file. A file may contain any number of additional package-private classes whose names can differ freely.\nQ5: Why do constructors have no return type?\nA5: Java distinguishes them syntactically. A member whose name matches the class and which declares no return type is a constructor, invoked only by new. Adding void, even once, converts it into an ordinary method returning nothing, and the class then silently has no constructor with that signature.\nQ6: Are constructors inherited by subclasses?\nA6: No. A subclass does not receive the constructors of its parent. If the parent declares a no-argument constructor, the compiler inserts a default super call for you, but if it declares only constructors with parameters you must call a matching one explicitly using super as the first statement.\nQ7: How does a static field differ from an instance field?\nA7: An instance field has one copy per object, so each instance holds an independent value. A static field belongs to the class, so exactly one copy exists no matter how many objects are created. Because that copy is shared, it is also shared across threads, which makes mutable static state a common source of race conditions.\nQ8: Can I use a class before its declaration appears in the file?\nA8: Yes, because class names are resolved by name rather than by textual position, so referencing a class declared later in the same file is perfectly legal. Field and variable access behaves differently: reading a field before its declaration is a compile error, since those must appear in textual order.\n

Key Takeaways, Best Practices & Clean Code Rules

Java Best Practice & Production Rules

Name classes in PascalCase, methods and variables in camelCase, and constants in UPPER_SNAKE_CASE.\nKeep each class cohesive, so every member clearly relates to its single responsibility.\nDeclare fields private, and final whenever the value cannot change after construction.\nValidate constructor arguments so an object can never exist in an invalid state.\nOrder members logically: constants, fields, constructors, methods, then nested types.\nPrefer static final constants with initialisers over magic values scattered through methods.\nKeep static state immutable, since a mutable static field is shared across every thread.\nName the file to match its public class exactly, including capitalisation.\nAvoid the I prefix on interfaces and the Impl suffix on implementations.\nUse nested classes for genuine implementation details rather than exposing them at the top level.\nGive each constructor one clear purpose, and avoid many optional parameters that leave the class partly initialised.\nFavour one top-level type per file, since several public classes cannot share a file.\nMake the default constructor explicit once the class has a final field, so initialisation is obvious.\nKeep the public surface small and treat every public member as a promise you must keep.\nLet the compiler enforce the rules rather than assuming a wrong declaration will simply warn.
We value your privacy & transparency

OperateTools uses cookies and local storage to ensure basic tool functionality, preserve preferences, and analyze aggregated traffic. We never sell your personal data or index your document files. Learn more in our Privacy Policy.