Most students meet object-oriented programming in week three or four of a Java module, right after they've finally got comfortable with loops and arrays. Then the lecturer uses the words class, object, inheritance and polymorphism in a single breath, the slides fill up with diagrams of dogs and cars, and a good part of the room quietly decides that OOP is something they'll understand later. The catch is that later usually arrives as a coursework brief. A big share of first and second year Java tasks are OOP tasks in disguise: design a small system, split it into classes, make those classes work together, and explain why you built it that way. When people go looking for Java assignment help at that point, the gap they find is rarely syntax. It's that nobody showed them how to think in objects first and write code second. So instead of four unrelated animal examples, this post uses one small library system that grows a little in each section, which is closer to how a real assignment feels.

Classes and objects

A class is a template. An object is one thing built from that template. A book is a good place to start because everyone knows what one looks like.

public class Book { String title; String author; } 
public class Main { public static void main(String[] args) { Book first = new Book(); first.title = "Clean Code"; first.author = "Robert C. Martin"; Book second = new Book(); second.title = "Effective Java"; second.author = "Joshua Bloch"; } } 

first and second come from the same class but hold their own data. Change one title and the other doesn't move. That's all "object" really means in practice.

One thing worth getting right early: writing Book third; does not create a book. It creates a reference that points at nothing. Call a method on it and you get a NullPointerException in Java, one of the most common crashes in early coursework. The new keyword is what actually builds the object.

Encapsulation

The Book above has a problem. Anyone can write first.title = "" and nothing stops them. Encapsulation fixes that by making the fields private and allowing changes only through methods you control.

public class Book { private final String title; private final String author; private boolean onLoan; public Book(String title, String author) { this.title = title; this.author = author; } public String getTitle() { return title; } public boolean isOnLoan() { return onLoan; } public void checkOut() { if (onLoan) { throw new IllegalStateException(title + " is already on loan"); } onLoan = true; } public void giveBack() { onLoan = false; } } 

There is no setOnLoan(boolean) here, and that's deliberate. A book can only become unavailable through checkOut(), which refuses to run twice. If you let the IDE generate a setter for every field, anyone can flip the flag directly and the check is pointless. A getter and setter on every field is just a public field with extra typing.

Inheritance

Libraries don't only lend books. There are DVDs, magazines, audiobooks. Copying the title and loan logic into each class is how the same bug ends up in four places, so the shared part moves into a parent class.

public class LibraryItem { private final String title; private boolean onLoan; public LibraryItem(String title) { this.title = title; } public String getTitle() { return title; } public boolean isOnLoan() { return onLoan; } public void checkOut() { if (onLoan) { throw new IllegalStateException(title + " is already on loan"); } onLoan = true; } public void giveBack() { onLoan = false; } public double lateFee(int daysLate) { return daysLate * 0.10; } } 

The Book class now shrinks to what is specific to books:

public class Book extends LibraryItem { private final String author; public Book(String title, String author) { super(title); this.author = author; } public String getAuthor() { return author; } } 

extends is what links the two, and super(title) hands the title up to the parent constructor. It has to be the first line of the child constructor, which catches a lot of people out. A Book never had to write checkOut() itself, it just has it.

A quick test before using extends: say "a Book is a LibraryItem" out loud. If the sentence sounds wrong, inheritance is probably the wrong tool.

Polymorphism

DVDs usually have heavier late fees, so the Dvd class changes that one method and leaves everything else alone.

public class Dvd extends LibraryItem { private final int minutes; public Dvd(String title, int minutes) { super(title); this.minutes = minutes; } public int getMinutes() { return minutes; } @Override public double lateFee(int daysLate) { return daysLate * 0.50; } } 

Now the interesting part:

LibraryItem[] returned = { new Book("Clean Code", "Robert C. Martin"), new Dvd("The Social Network", 120) }; for (LibraryItem item : returned) { System.out.println(item.getTitle() + " late fee: " + item.lateFee(4)); } 
Clean Code late fee: 0.4 The Social Network late fee: 2.0 

The variable type is LibraryItem, but Java decides which lateFee to run by looking at the actual object at runtime. The loop has no idea which kind of item it's holding and doesn't need to. Add a Magazine class next month and this loop doesn't change at all. (Using double for money is fine for a demo. In anything real, use BigDecimal.)

Abstraction

Nobody walks into a library and borrows a generic "item". LibraryItem only exists so the real things can share it, so it shouldn't be possible to create one directly. That's what abstract is for.

public abstract class LibraryItem { // fields, constructor, checkOut and giveBack stay as they were public abstract double lateFee(int daysLate); } 

Now new LibraryItem("x") won't compile, and every subclass has to supply its own fee rule:

public class Book extends LibraryItem { // author field and constructor as before @Override public double lateFee(int daysLate) { return daysLate * 0.10; } } 

Interfaces are the other half of abstraction. Use an abstract class when the subclasses share state and code. Use an interface when you only want to promise a behaviour.

public interface Reservable { void reserve(String memberName); } 

A Dvd could implement Reservable while a reference-only Book doesn't. A class can only extend one parent, but it can implement as many interfaces as it needs, which is usually the deciding factor.

Quick reference

Concept Problem it solves Where you see it
Encapsulation Outside code breaking an object's rules private, constructors, getters
Inheritance Same code copied into several classes extends, super
Polymorphism Code that has to check what type it's holding @Override, parent type variables
Abstraction Modelling things that shouldn't exist on their own abstract, interface

Mistakes that cost marks

  • Public fields because it was quicker. It stays quicker until validation has to be added in twelve places.
  • Generating setters for everything, which quietly undoes encapsulation.
  • Using extends just to borrow methods. A Member that holds a list of items should have an ArrayList as a field, not extend one. A member isn't a list.
  • Long if and instanceof chains where an overridden method would do the job.
  • Leaving out @Override. Misspell lateFee as latefee and Java happily treats it as a brand new method, so the parent version keeps running and you spend an hour wondering why. With the annotation the compiler tells you immediately.

The library here is small on purpose. Try extending it with a Member class that can hold at most three items and a Magazine that can't be reserved, then check how many of your earlier classes you had to touch. If the answer is none, the design is doing its job. Real coursework briefs are messier, with file input, a menu loop and marking criteria that reward design choices you can justify in writing, and sketching the classes before writing any code is the same approach the Java walkthroughs on Prime Assignment Help follow.