Java OOP Vocabulary Flashcards (Lectures 3.1–3.7)
3.1 Object Oriented Programming
- Java is an object-oriented programming language: one of the primary ways to organize programs is around objects.
- Objects are a kind of value that combines data and the code that operates on that data into a single unit.
- Objects are defined by classes, which provide a blueprint for creating objects of a certain kind, describing the data and code that all instances of that class have.
- Real-world modeling: classes can represent real-world things (e.g., a Student class to model students in a school).
- Not all classes need to map to real-world entities; some are purely organizational constructs within code.
- In Java, all programs are built out of classes; every Java program starts with public class (at least one class must be defined).
- This is why you see the pattern: public class … in Java programs.
3.2 Introducing Methods
- Terminology note: in Java (and many other languages), the term "methods" is used for code that belongs to a class. In other languages you might hear "functions".
- Prerequisites (from notes): basic Java syntax (if statements), understanding of variables and types, familiarity with the Design Recipe approach.
- Think of methods like recipes: write once, reuse many times.
- Objectives of this section:
- Recognize classes and objects.
- Describe the relationship between classes and objects.
- Describe the difference between objects and data of primitive type.
- Describe the difference between static and instance elements of a class.
- Design a simple class in Java.
- List the basic principles of object-oriented programming.
3.2.1 Why Do We Need Methods?
- Repeated Logic Example (game health/gold):
- Code snippet example shows health and gold increasing after wins.
- Repeated code; if you need to change the reward amount, you’d have to edit every copy.
- Key Insight: when you copy-paste code, it’s a sign you need a method.
3.2.1.1 Quick Check
- Questions to answer:
- Why is copy-pasting code problematic?
- What happens if the reward amount changes?
- How does this relate to the Design Recipe’s "repeated logic" warning?
3.2.2 Creating Your First Method
- Analogy: a method is like a vending machine: you put in parameters, it does work, and you get back a return value.
- Basic recipe:
public static returnType methodName(parameters) { // method body return something; }
- Breakdown of parts:
- public: method is accessible to other code (like a public library).
- static: the method belongs to the class itself, not to any specific instance.
- returnType: type of value returned by the method; use void if it returns nothing.
- methodName: descriptive name (camelCase, starts with a lowercase letter).
- parameters: inputs to the method; each parameter has a type and a name; zero or more parameters; separated by commas.
- Example explained: public static int addTwoNumbers(int a, int b) { int sum = a + b; return sum; }
- It’s public and static, returns int, named addTwoNumbers, takes two int parameters a and b, computes sum, returns it.
- Simple formula inside: ext{sum} = a + b
Compiler reminder
- If you mismatched parameter types, the compiler flags an error, acting as an early alert system for type mismatches; e.g., if a method signature is public static int addTwoNumbers(String a, int b) and you call addTwoNumbers(3, 5), you’ll get a type error because the expected types are (String, int).
3.2.3 Trying a void Method—Why Doesn’t It Work?
- Example: public static void awardVictory(int health, int gold) { /* health and gold are copies */ health += 5; gold += 10; }
- In main(): playerHealth = 10; playerGold = 50;
- Inside the method, health and gold are copies; changes do not affect the originals when the method ends.
- Options to update originals:
- Use void and hope Java changes originals? No.
- Return both values somehow? Not directly—methods return one thing.
- Return the new value and store it back in main? Yes.
- Conceptual takeaway: primitives are passed by value; Java makes copies of primitive parameters.
3.2.5 Many Fields → Multiple Parameters Fiasco
- Problem: as the number of related variables grows, passing them individually becomes unwieldy (health, gold, xp, mana, stamina, luck, etc.).
- Risks:
- Too many parameters to track.
- Difficulty in maintaining correct order; swapping leads to bugs.
- The Design Recipe perspective warns about handling too many pieces individually.
3.2.6 What We’ve Learned (Big Ideas)
- Methods help avoid copying code.
- Java makes copies of numbers we pass to methods (primitive types).
- When methods need to update values, they should return them.
- When there are many parameters, it’s a sign to move toward using classes to bundle related data.
3.2.7 Your Turn
- Practice exercise to apply what you’ve learned about methods and design recipes.
3.2.8 Common Pitfalls to Watch Out For
- Forgetting to return: if your method declares a return type, every code path must return a value.
- Return type mismatch: returning a double from a method declared to return int, etc.
- Parameter type confusion: passing a type that doesn’t match the parameter type.
3.3 Method Parameters
- Recall: methods helped reduce code duplication by passing data in parameters.
- Method Syntax recap:
public static returnType methodName(type1 param1, type2 param2) { // body return value; }
- Key points:
- Methods reduce code duplication.
- Parameters are passed by value (copies).
- Return type must match the declaration.
- void methods don’t return anything.
- static methods belong to the class (not to an instance).
- Design Recipe Steps:
- Formulate data definitions
- Write method signature
- Test with examples
- Implement and verify
3.3.1 The Problem: Too Many Separate Pieces
- Example: a game with many player stats carried as separate variables (health, gold, xp, mana, stamina, etc.).
- Issue: calling multiple methods to update each stat becomes tedious and error-prone.
3.3.2 Why This Is A Problem
- If you need a method that changes multiple pieces, you’d end up with:
- A method with many parameters (e.g., awardVictory(int health, int gold, int xp, int mana, …))
- Risk: swap errors, misordered parameters, and difficulty extending to multiple players.
3.3.3 The Solution: Grouping Related Things Together
- Introduce a class to bundle related data (e.g., a Player class with health, gold, xp, etc.).
- Example: Player p1 = new Player(100, 50, 0, 75, 90); p1.increaseHealth(5);
- Concept: a class acts as a blueprint for creating objects that:
- Keep related data together
- Include methods that work with that data
- Protect their data from accidental misuse
3.4 Classes and Objects
- Already saw the issue of scattered data and line-by-line updates; classes help group data and behavior.
- Idea: treat a player as a single entity (an object) with its own data and operations.
3.4.1 Step 1: An Empty "Container" Called Player
- Minimal class skeleton:
public class Player { // We'll fill details in soon! }
3.4.2 Step 2: Putting Variables Inside That Box
- Move data fields inside the class so each Player has its own data:
public class Player { int health; int gold; }
- Each Player object created with new Player() gets its own storage for health and gold.
3.4.3 Step 3: Setting Initial Values
- Start values aren’t left at 0 by default; use a constructor to set initial values.
- Constructor basics (special method):
- Name matches the class, has no return type, and is public with parameters.
- Example:
public class Player { int health; int gold; public Player(int startHealth, int startGold) { health = startHealth; gold = startGold; } }
- When you write: Player p = new Player(10, 50); what happens:
- new creates space in memory
- defaults are filled (0s)
- constructor runs to initialize fields
- a reference to the new object is returned
- This pattern is standard in Java (e.g., String name = new String("Alice");).
3.4.4 Step 3: Setting Initial Values (continued)
- The constructor example is shown and discussed; constructors set up the object’s initial state.
3.4.5 Step 4: Adding "Operations" for That Player
- Compare static vs instance approaches:
- Static approach (parameters passed in):
public static void healPlayer(int currentHealth, int healAmount) { currentHealth += healAmount; }
- Instance method approach (data is inside the object):
public void heal(int amount) { this.health += amount; }
- Instance methods are often clearer and safer because they operate on the object’s own data.
- Example within a Player class:
public class Player { int health; int gold; public Player(int startHealth, int startGold) { health = startHealth; gold = startGold; } public void heal(int amount) { health += amount; } public void addGold(int amount) { gold += amount; } }
- Creating and using a Player:
Player p = new Player(10, 50); p.heal(5); // health becomes 15
3.4.5.1 The ’this’ Keyword: Who Am I?
- When parameter names clash with field names, use this to refer to the field:
- Example (problem):
public void heal(int health) { health = health; // which health is which? }
- Corrected with this:
public void heal(int health) { this.health = health; }
- How it works in practice: calling p.heal(5) passes the object as this to the method.
- Practical notes:
- this is explicit but often optional when names don’t clash.
- It’s useful when passing the current object to another method or to avoid ambiguity.
3.5 Encapsulation & Abstraction
- Two broad approaches to organizing code:
- Way 1: Keep data and rules separate (traditional, global state, static helpers).
- Way 2: Package data with their rules inside classes (Object-Oriented Programming, OOP).
- OOP goals: encapsulation, abstraction.
- Encapsulation: protect data from invalid changes.
- Abstraction: hide complex details behind simple commands.
- Example: two ways to implement a BankAccount-like structure.
- Encapsulation example: private fields and public methods to operate on them.
- Abstraction example: a clear interface (deposit, withdraw, getBalance) that hides internal workings.
3.5.1 Two Ways: Keep or Package Pieces (Recap)
- Traditional: static state and static methods with scattered data.
- OOP: organize into classes; data is guarded; methods operate on the data.
3.5.2 Beyond Simple Classes
- Problem: external code can break rules by directly setting fields (e.g., hero.health = -999).
- Solution: private fields to prevent direct access.
- Example: private int health; private fields protect data.
3.5.3 Understanding Encapsulation
- Bundling data and code together; protecting data from invalid changes.
- Interface: clear, simple methods a user calls (e.g., heal, takeDamage).
- Invariants: rules that must always be true (e.g., health within 0..maxHealth).
- Example: Player with private health and maxHealth with a setter enforcing bounds.
3.5.3.1 Bundling: Keeping Related Things Together
- Example: BankAccount with private balance, accountNum, interestRate and a method addInterest that uses these values.
3.5.3.2 Protection: Making Sure Data Changes Safely
- Example: Player with private health and a method takeDamage that ensures health doesn’t go below 0.
3.5.3.3 Interface: Making Your Class Easy to Use
- Example: BankAccount with deposit, withdraw, getBalance, and internal private balance.
- The point: public methods provide a simple, safe interface for users.
3.5.3.4 Invariants: Rules That Must Be True
- Example: Player with health and maxHealth; setHealth enforces bounds.
3.5.4 Different Ways to Enforce Rules
- Constructor checks: prevent invalid object creation.
- Method guards: validate inputs inside methods (e.g., if amount < 0, clamp to 0).
- Range enforcement: keep values in bounds (e.g., using Math.max/Math.min).
- Complete rejection: return a success/failure boolean to indicate operation result.
- Choose the approach that makes sense for the situation.
3.5.5 Abstraction: What Users Need vs. What Code Does
- Analogy: a restaurant where you order a cheeseburger; the kitchen handles complex steps (grill temp, cooking time) and you only see a simple interface (orderCheeseburger).
- Code example demonstrates hiding internal steps and exposing a simple method.
- Abstraction and encapsulation together create reliable, easy-to-use code.
3.5.6 Looking Ahead: More OOP Features
- Acknowledgment that there are more features (e.g., inheritance, polymorphism) to explore beyond encapsulation and abstraction.
3.5.7 Encapsulation & Abstraction in Practice (BankAccount Example)
- Step-by-step BankAccount with encap., constructor checks, deposit/withdraw validations, getBalance, and private addInterest.
- Highlights: input validation, balance updates, transaction logging, interest calculation, and user-facing methods.
3.5.8 From Design Recipe to OOP
- Design Recipe steps align with OOP: data definitions, constraints, and methods that work with data.
- OOP enforces constraints through methods and data encapsulation.
3.6 Primitive & Reference Types
- Core memory/datum distinction in Java:
- Primitive types (int, double, boolean, etc.): stored directly by value; copies are independent; type names start with lowercase.
- Reference types (Objects): stored as a reference/address to the actual data; copying the reference shares the same object; type names start with uppercase.
- Real-world analogies:
- Primitives: sticky notes with the value; copying creates independent notes.
- Objects: lockers (references); sharing a locker means changes are visible to all who hold the same locker number.
3.6.1 Two Ways Java Stores Data
- Primitives: stored directly; copies are independent.
- References: store addresses; copies share the same object in memory.
3.6.2 How Primitives Work: Independent Copies
- Example: int score = 100; int backupScore = score; backupScore = 50; score remains 100.
- Demonstrates independent copies for primitives across assignments.
Common primitive examples
- double price = 9.99; double salePrize = price; salePrize = 7.99; // salePrize changes do not affect price
- boolean gameOver = false; boolean lastState = gameOver; lastState = true; // independent copies
- A common mistake: int lives = 3; int extraLives = lives; extraLives--; // lives remains 3
3.6.3 How Objects Work: Sharing Access Through References
- Example: class Player with health field.
- Object example:
- Player hero = new Player(100);
- Player sidekick = hero; // both references point to the same object
- sidekick.damage(25); // affects the shared Player object
- hero.getHealth() shows the updated health (75)
- Memory view: both references point to the same Player instance in memory.
3.6.4 Methods with References: The Right and Wrong Ways
- Area damage scenario: damages to multiple players.
- WRONG WAY: passing primitive health values, which only modify copies and not the actual objects.
- RIGHT WAY: pass references to Player objects and call their methods to modify real objects.
- Example: rightAreaDamage(Player p1, Player p2, int damage) { p1.damage(damage); p2.damage(damage); }
- Memory diagrams show the difference between modifying copies vs. modifying the shared objects.
Common Mistakes when using references
- Mistake 1: Passing a number (health) instead of a Player object to a method that should modify the object (healPlayer(hero, 5) vs healPlayer(hero.getHealth(), 5)).
- Mistake 2: Thinking new variables mean new objects (Player backup = hero; backup.damage(10); affects hero).
- Mistake 3: Pass-by-value misunderstanding: primitives vs objects; objects pass a copy of the reference, not a copy of the object.
3.6.5 What Really Happens Inside Methods
- Wrong Way: passing health value (a primitive) leads to a method’s copy and no change to the original object.
- Right Way: passing the Player reference allows the method to modify the actual object through its methods.
- Visual memory comparison shows how copying references vs copying primitive values affects the outcome.
3.6.6 Sharing Multiple Lockers: Group Methods
- Boss fight example: bossFight(Player hero, Player boss, int damage) {
hero.damage(damage); // modifies hero
boss.damage(damage*2); // modifies boss
} - Create two players and pass them to the method to modify both.
- Key point: a method can receive multiple references and modify all the corresponding objects.
3.6.7 Summary: What You Need to Remember
3.6.7.1 Key Concepts
- Primitives are like sticky notes: each variable has its own copy.
- Objects are like lockers: multiple references can point to the same object; changes via one reference affect all references to that object.
3.6.7.2 Common Mistakes to Avoid
- Wrong: Passing the number instead of the locker (object). Example: void healPlayer(int health, int amount) { health += amount; } // Changes thrown away
- Right: Passing a Player reference: void healPlayer(Player player, int amount) { player.heal(amount); }
- Wrong: Assuming new variables mean new objects; e.g., Player backup = hero; // backup is the same object as hero
- Right: To create a separate object, instantiate a new Player with a value, e.g., Player clone = new Player(hero.getHealth());
- Misunderstanding Pass-by-Value: Java passes copies of references for objects, but the references point to the same underlying objects.
3.6.8 Looking Ahead: Objects in Memory
- This section foreshadows deeper topics on how objects are stored and how method calls interact with objects in memory.
Quick Reference Highlights
- Method formula example: ext{sum} = a + b inside a method returning an int.
- Key method concepts:
- public static: class-level access
- returnType: type of value returned (use void if none)
- parameters: zero or more typed inputs
- Encapsulation essentials:
- Private fields to protect data
- Public methods to manipulate data safely
- Invariants to enforce rules (e.g., health bounds)
- Abstraction vs. Encapsulation:
- Encapsulation protects data
- Abstraction hides internal complexity behind simple interfaces
- Primitives vs. References:
- Primitives: independent copies on assignment
- References: multiple references can share the same object; changes propagate through all references to that object
Notes:
- This study guide mirrors the progression from objects and classes to methods, parameter handling, and encapsulation/abstraction, culminating in the primitive vs. reference distinction and its memory implications. Use these bullets as a structured review to map to code practice and future topics (inheritance, polymorphism, etc.).