Without object-oriented programming, your code would be one massive, tangled mess — imagine trying to edit a recipe that is written on a single, mile-long scroll. Every time you wanted to change one ingredient, you risked breaking the whole dish. Object-oriented programming (OOP) solves this by letting you organise your code into independent, reusable blueprints called classes, and then create specific instances of those blueprints called objects. For the 1Z0-829 exam, you must master how to declare and instantiate objects, initialise them correctly with constructors, control access with modifiers, and protect your data using encapsulation — these are the building blocks of every real-world Java application.
Jump to a section
A simple way to picture Java Object-Oriented Programming Deep Dive
A busy coffee shop at 8:00 AM on a Monday, customers streaming in and out, baristas working behind the counter.
The blueprint for the shop is the class — it specifies that every order has a drink type (latte, espresso), a size (small, medium, large), and a customer name. This blueprint is not an order itself; it is the template. When a customer walks up and says, 'I'd like a large oat-milk latte for Sarah,' the barista instantiates an object: a specific order for Sarah. That order object has its own values (large, oat-milk, latte, Sarah), but it follows the rules set by the class blueprint.
Now, encapsulation comes into play. The order slip is kept behind the counter; only the barista can modify it. If Sarah later wants to change her milk to soy, she cannot grab the slip herself — she must ask the barista, who then updates the object through a public method (like a setter). The internal details, like the cost calculation or the order ID, are private and hidden from customers.
Access modifiers are like different areas of the shop. The menu board is public — anyone can see it. The recipe book is private — only the barista can access it. Some procedures, like the syrup pump calibration, are protected — only baristas and shift managers can touch them. The default (package-private) is like the store's internal phone system: other shops in the same franchise can use it, but customers cannot.
Constructors are the order-taking process itself. When a new order is created, the barista must provide the essential details upfront (drink type, size, name). That initialisation is the constructor. If the barista forgets to ask for the size, the order might default to 'medium' — that is a no-argument constructor. The whole system works because each object is an independent, self-contained instance of the class blueprint, and the details are protected from outside interference.
At its heart, object-oriented programming is a way to model real-world things in code. Imagine you want to write a program that manages a library. Without OOP, you would have separate variables for each book's title, author, ISBN, and whether it is checked out, all floating around in your code. That is messy and hard to maintain. OOP lets you create a single template, called a class, that bundles those related properties and behaviours together.
A class is a blueprint. It defines what data (fields or instance variables) an object will hold and what actions (methods) it can perform. For example, a Book class might have fields like title, author, and isCheckedOut, and methods like checkOut() and returnBook(). The class itself is not a book — it is the idea of a book.
An object, also called an instance, is a concrete realisation of that class. When you write new Book(), you are creating a specific object in the computer's memory. That object has its own copy of all the fields defined in the class. So you can have one Book object for "1984" by George Orwell and another for "Pride and Prejudice" by Jane Austen, each with its own isCheckedOut value.
To create an object, you call a constructor. A constructor is a special method that has the same name as the class and no return type. Its job is to initialise the new object. If you write:
Book myBook = new Book("1984", "George Orwell");
The text after new, Book("1984", "George Orwell"), calls the constructor. Inside the class, you define that constructor to set the fields:
public Book(String title, String author) { this.title = title; this.author = author; this.isCheckedOut = false; }
If you do not write any constructor at all, Java provides a default no-argument constructor that sets numeric fields to 0, booleans to false, and object references to null. But if you write any constructor yourself, the default one disappears — you must explicitly add a no-argument constructor if you still need one.
Now, how do you control who can see and modify your object's data? That is where access modifiers come in. There are four levels of access in Java:
private: The member (field or method) is accessible only within the same class. No one outside can see it.
default (also called package-private): No keyword is written. The member is accessible only to classes in the same package.
protected: The member is accessible to classes in the same package and to subclasses (classes that inherit from this class) even if they are in a different package.
public: The member is accessible from anywhere.
Encapsulation is the practice of hiding the internal state of an object and requiring all interaction to be performed through an object's methods. The classic pattern is to make all instance fields private and then provide public getter and setter methods to access or modify them. Why? Because the getter and setter can add logic. For example, a setter for age might check that the age is not negative before storing it. Without encapsulation, any code could set myBook.title = null, breaking your program.
Encapsulation is not just about hiding data; it is about protecting the integrity of your object. It also means you can change the internal implementation later without breaking any code that uses your class, as long as the public methods (the interface) stay the same.
Why does all this matter? Before OOP, code was often written in large, sequential blocks. To reuse a piece of logic, you would copy and paste it, leading to duplication and bugs. With OOP, you define a class once and then create as many objects as you need. Each object is independent. If you change the class blueprint, all objects created from it are affected, but you change the code in only one place. This makes programs easier to design, write, test, and maintain.
For the 1Z0-829 exam, you need to be comfortable with the following:
Declaring a class with fields, constructors, and methods.
Using the new keyword to instantiate an object.
Understanding how constructors chain (a constructor can call another constructor in the same class using this(), or in the parent class using super()).
Recognising the default constructor and when it is not provided.
Applying the correct access modifier to members to enforce encapsulation.
Writing getters and setters following the JavaBeans naming convention (getXxx for non-boolean, isXxx for boolean, setXxx for both).
Declare the class
Write 'public class BankAccount { }' to define the blueprint. This tells Java that a 'BankAccount' type exists. The name must match the filename. This step establishes the container for all related data and behaviour.
Add private instance fields
Inside the class, declare fields like 'private String accountNumber;' and 'private double balance;'. The 'private' keyword ensures that no code outside this class can directly access these fields. This is the first move toward encapsulation.
Write constructors
Create a constructor like 'public BankAccount(String accountNumber, String ownerName) { this.accountNumber = accountNumber; this.ownerName = ownerName; this.balance = 0.0; }'. This initialises the object's state when it is created. Without a constructor, fields would be null or zero by default.
Provide public getters and setters (if needed)
Add methods like 'public double getBalance() { return balance; }' and 'public void deposit(double amount) { if (amount > 0) this.balance += amount; }'. Getters allow controlled read access; setters or specific action methods allow controlled write access. This completes the encapsulation pattern.
Instantiate the object
In another class (like a main method), write 'BankAccount myAccount = new BankAccount("12345", "Alice");'. The 'new' keyword allocates memory, the constructor runs to initialise the object, and the reference is stored in 'myAccount'. Now you have a working object.
Use the object through its public interface
Call methods on the object: 'myAccount.deposit(500.00);' and 'double bal = myAccount.getBalance();'. You never touch the private fields directly. This ensures the object's integrity and makes the code easier to maintain and test.
An IT professional at a company like a streaming service or a bank uses OOP principles every single day, often without thinking about it, because the patterns are embedded in the frameworks and libraries they use.
Consider a developer building the backend for an online banking application. They need to model a BankAccount. Instead of scattering account number, balance, and owner name across different variables and functions, they create a single BankAccount class. This class encapsulates all the data and behaviour related to an account.
Here is what happens step by step:
The developer declares the class with private instance variables: accountNumber (String), ownerName (String), balance (double), and accountType (enum). Making these fields private ensures that no other part of the program can directly change the balance without going through the proper channels.
They write a constructor that requires the account number and owner name at creation. This constructor also initialises the balance to 0.0, because a new account starts with no money. If a client later tries to create an account without providing these essential details, the code will not compile — the constructor enforces that rule.
They provide public getter methods (getAccountNumber(), getOwnerName(), getBalance()) so that other parts of the system (like a web page displaying account details) can read these values. Crucially, they do not provide a setter for balance. Instead, they provide two public methods: deposit(double amount) and withdraw(double amount). Inside the withdraw method, they add validation logic: if the amount is greater than the balance, the method throws an exception (a signal that something went wrong) instead of allowing the balance to go negative. This is encapsulation in action — the object protects its own integrity.
The developer also adds a protected method called calculateInterest() that is used by subclass types like SavingsAccount or CheckingAccount. Because it is protected, only subclasses and classes in the same package can call it; external code cannot. This prevents non-account code from accidentally triggering interest calculations.
Later, the business decides that all new bank accounts must have a unique ID generated by a central system. Because the developer encapsulated the accountNumber field and initialised it in the constructor, they only need to change the constructor code and the getter. Every other piece of code that uses BankAccount objects (the web frontend, the transaction logger, the audit system) works without any changes — they all access the account number through getAccountNumber().
Without encapsulation, the developer would have to hunt through the entire codebase for every place where accountNumber is directly assigned, and update it. That is error-prone and time-consuming.
In real-world enterprise Java, frameworks like Spring heavily rely on these OOP concepts. Spring beans are just objects created from classes. Dependency injection works by passing objects into constructors. Access modifiers prevent accidental misuse. The entire architecture assumes you understand how to properly design classes with constructors, encapsulation, and access control.
Another common real-world activity is refactoring — taking messy legacy code (often called 'spaghetti code') and turning it into well-encapsulated OOP code. A junior developer might start by identifying logical groups of data and behaviour, creating classes for them, then making fields private and exposing public methods. This is a core skill for any professional Java developer.
The 1Z0-829 exam tests this objective (3.1) with a mix of multiple-choice and multiple-select questions. The examiners are known for setting traps that catch candidates who have only a surface-level understanding. Here is exactly what you need to know.
First, the exam loves to test whether you know when the default constructor is provided. The rule is: if you do not write any constructor in your class, Java provides a public, no-argument constructor that does nothing except call super(). However, if you write even one constructor (with any number of arguments), the default constructor vanishes. So if your code calls new MyClass() but you have only written MyClass(int x), the code will not compile. Memorise this.
Second, the order of initialisation is a favourite topic. For a given class, the order is:
Static variable initialisers and static initialiser blocks, in the order they appear in the source code.
Instance variable initialisers and instance initialiser blocks, in the order they appear.
The constructor body.
If a class extends a parent class, the parent class's initialisation (its constructor, via super()) runs before the child's instance initialisers and constructor. The exam will present code with multiple classes and ask you to determine the output. The trap is that many beginners assume the child's constructor runs first, but it does not. Always trace super() first.
Third, access modifiers in the context of overriding. The overriding method cannot have a more restrictive access modifier than the method it overrides. For example, if a parent class has a protected method, the child class cannot override it with a private method. The examiner will present a scenario where a subclass tries to narrow access, and you must recognise that it will not compile. Also, you cannot override a private method at all — it is not inherited, so the child's method with the same name is a new method, not an override.
Fourth, encapsulation with getters and setters. The exam will ask you to identify which design correctly encapsulates a field. The correct pattern is:
private field
public getter
public setter (or no setter for immutability)
Watch out for traps where the getter returns a mutable object reference (like an array or a List) and the code outside can then modify the internal state. The proper defensive approach is to return a copy (using clone() or a new collection). The exam may not test this deeply, but it is a common real-world consideration and sometimes appears in more advanced questions.
Fifth, constructor chaining using this() and super(). The rule: this() must be the first statement in a constructor, and super() must be the first statement in a constructor. They cannot both be present because each must be first. If you do not write either, Java inserts super() automatically (calling the parent's no-arg constructor). If the parent class does not have a no-arg constructor, your code will not compile unless you explicitly call super(arguments). This is a classic exam trap.
Key definitions to memorise:
Class: A blueprint for objects.
Object (or instance): A concrete entity created from a class.
Constructor: A special method used to initialise a new object.
Access modifier: Controls visibility (private, default, protected, public).
Encapsulation: Hiding internal state and requiring all interaction via methods.
Getter: A public method that retrieves the value of a private field.
Setter: A public method that sets the value of a private field, often with validation.
Finally, the exam may present a scenario with multiple classes in different packages and ask which members are accessible. You need to know the access level boundaries precisely: private (same class only), default (same package only), protected (same package + subclasses in any package), public (everywhere).
Traps the exam sets:
A class with a private constructor cannot be instantiated from outside — that is intentional, often used in singleton patterns.
Local variables (declared inside a method) cannot have access modifiers; they are only accessible within that method.
Static fields belong to the class, not to instances, so they are not part of an object's state. Encapsulation still applies to static fields.
An enum is a special type of class; its constructors are implicitly private. The exam may test this.
A class is a blueprint; an object is a concrete instance created from that blueprint using the 'new' keyword.
If you do not write any constructor, Java supplies a default no-argument constructor; if you write any constructor, the default disappears.
In a constructor, the first statement must be either 'this()' (to call another constructor in the same class) or 'super()' (to call a parent constructor); if neither is written, 'super()' is inserted automatically.
Instance initialisation runs in this order: parent constructor, then instance variable initialisers and instance initialiser blocks (in order), then the constructor body.
Encapsulation is achieved by making instance fields 'private' and providing 'public' getter and setter methods that control access and can include validation logic.
The four access levels from most to least restrictive are: private (class only), default (package only), protected (package + subclasses), and public (everywhere).
An overriding method cannot have a more restrictive access modifier than the method it overrides.
A class with a 'private' constructor cannot be instantiated from outside the class, which is a deliberate design pattern (e.g., singleton).
These come up on the exam all the time. Here's how to tell them apart.
Class
A blueprint or template, defined once in code.
Does not occupy heap memory unless a static context is involved.
Cannot be passed around or assigned to variables.
Defines the structure and behaviour.
Object (Instance)
A concrete, individual entity created from a class.
Occupies its own memory on the heap.
Can be stored in variables, passed to methods, and returned.
Has its own state (field values) separate from other instances.
Constructor
Has the same name as the class.
Has no return type (not even void).
Called automatically with the 'new' keyword.
Cannot be called on an existing object (cannot be invoked by name).
Regular Method
Has a distinct name (usually a verb).
Must declare a return type (or void).
Called explicitly on an existing object, e.g., 'myObject.method()'.
Can be called any number of times throughout an object's life.
Private Access Modifier
Member is accessible only within the same class.
Used to hide implementation details (encapsulation).
Cannot be accessed by subclasses or any external code.
Public Access Modifier
Member is accessible from any class in any package.
Forms the public interface (API) of a class.
Should be used sparingly to avoid exposing internal state.
this() (Constructor Chaining)
Calls another constructor in the same class.
Must be the first statement in a constructor.
Used to avoid code duplication among constructors.
super() (Parent Constructor Call)
Calls a constructor from the direct parent class.
Must be the first statement in a constructor.
If omitted, Java inserts a no-arg super() call automatically (if available).
Default Access (Package-Private)
No keyword is written; no modifier at all.
Accessible only to classes within the same package.
More restrictive than protected.
Protected Access Modifier
Written with the 'protected' keyword.
Accessible to classes in the same package AND to subclasses in other packages.
Less restrictive than default, more restrictive than public.
Mistake
A class and an object are the same thing; you can use the terms interchangeably.
Correct
A class is the blueprint or template, while an object is a specific instance created from that blueprint. One class can produce many distinct objects, each with its own state.
Beginners often see code like 'String s = new String("hello")' and think 'String' is the object, not the class. It takes practice to distinguish the template from the concrete copy.
Mistake
If I write a constructor with parameters, I can still call the no-argument constructor without writing one.
Correct
Once you define any constructor, the default no-argument constructor disappears. You must explicitly write a no-argument constructor if you need it.
This catches many candidates off guard because other languages (like Python) handle constructors differently. Java's behaviour is strict and deliberate.
Mistake
Making all fields private and creating getters and setters is always the correct way to encapsulate data.
Correct
Encapsulation means hiding internal state, but it does not require a setter for every field. In fact, for immutable objects, you provide no setters at all, and data is set only through the constructor. Setters should only exist if mutation makes sense.
The JavaBeans convention popularised getters/setters, leading many learners to believe that every field needs both. Real design often favours immutability.
Mistake
The super() call is optional and does not affect program behaviour.
Correct
super() is automatically inserted by Java if you do not write it, but only if the parent class has a no-argument constructor. If the parent class lacks a no-arg constructor, omitting an explicit super(arguments) causes a compilation error.
Beginners often forget that constructors chain upward to Object, and they assume 'super' is only for overriding methods. The impact on compilation is frequently underestimated.
Mistake
Access modifiers control what data is stored in an object at runtime.
Correct
Access modifiers are compile-time checks. They determine which code is allowed to see or use a member. At runtime, if you use reflection, you can bypass access modifiers. But for normal code, the compiler enforces the rules.
Learners confuse the concept of 'access' with 'persistence' or 'memory layout', thinking private means the data is not in memory. It is simply a visibility rule for the source code.
Mistake
encapsulation is the same as data hiding.
Correct
Data hiding is a part of encapsulation, but encapsulation is broader. It also includes bundling data and methods that operate on that data into a single unit (the class), and controlling access through a well-defined interface.
Many resources teach them as synonyms, but the exam expects you to understand that encapsulation is about bundling and controlling access, not just hiding data.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
A class is the blueprint or template that defines what data and behaviour an object will have. An object is a specific, concrete instance of that class, with its own unique values for the fields. Think of the class as a cookie cutter and the object as the actual cookie.
Java automatically provides a default no-argument constructor that does nothing except call super() (the parent class's no-arg constructor). However, if you write any constructor at all, the default one disappears and you must explicitly add a no-arg constructor if you need one.
Yes, you can use 'this()' to call another constructor in the same class. For example, a no-arg constructor can call a parameterised constructor with default values. The 'this()' call must be the very first statement in the constructor.
Making fields private enforces encapsulation. It prevents external code from directly changing the field in an uncontrolled way. Instead, external code must use public methods (getters/setters), which can include validation logic (e.g., rejecting a negative balance). This protects the integrity of your object.
If you do not write an access modifier (private, protected, public), the member has default (package-private) access. It is visible to all classes in the same package, but not to classes in other packages. It is more restrictive than protected but less restrictive than private.
No. A private method is not inherited by subclasses. If you write a method with the same name in the subclass, it is a completely new method, not an override. The parent's private method remains hidden and inaccessible to the subclass.
'super()' calls the constructor of the parent class. If you do not write it, Java automatically inserts a call to the parent's no-argument constructor. If the parent class does not have a no-arg constructor, you must explicitly call 'super(arguments)' with matching parameters, or your code will not compile.
For a given object, initialisation happens in this order: first, the parent class constructor runs (all the way up to Object). Then, the child class's instance variable initialisers and instance initialiser blocks execute in the order they appear in the source code. Finally, the child class's constructor body runs.
You've finished Java Object-Oriented Programming Deep Dive. Continue through the 1Z0-829 study guide to build a complete picture of the exam.
Done with this chapter?