This project contains hands-on exercises based on the great Udemy video course about Java Fundamentals by Jean-Claude Bazin.
An access modifier defines the visibility of the class, field/attribute, or method it is applied to:
public: accessible everywhere to everyoneprivate: only accessible in the class in which it is defined.protected: only accessible in:- the same class
- the subclasses (classes that inherit from this class) in the same package or not
- classes in the same package
- package-private (default): accessible only in the package it is defined in.
To use package-private do not specify an access modifier.
| Access Modifier | Same Class | Class in the same package | Class in another package | Subclass in the same package | Subclass in another package |
|---|---|---|---|---|---|
public |
✅ example | ✅ example | ✅ example | ✅ example | ✅ example |
private |
✅ example | ❌ example | ❌ example | ❌ example | ❌ example |
protected |
✅ example | ✅ example | ❌ example | ✅ example | ✅ example |
| package-private | ✅ example | ✅ example | ❌ example | ✅ example | ❌ example |
Let's break down these access modifiers with visual class diagrams. The diagram use colors that define who can access:
- 🟩 green: can access
- 🟥 red: CANNOT access
---
title: public Access Modifier
---
classDiagram
direction TB
namespace SamePackage {
class OtherClassSamePackage["Other class same package"]:::can_access {
}
class Class:::can_access {
+attribute String
+method() void
}
class Subclass["Subclass same package"]:::can_access {
}
}
note for Class "attribute and method have **public** access"
Class <|-- Subclass
namespace OtherPackage {
class SubclassOtherPackage["Subclass different package"]:::can_access {
}
class ClassOtherPackage["Other class different package"]:::can_access {
}
}
Class <|-- SubclassOtherPackage
classDef can_access fill:#76b192
style SamePackage fill:#3B82F620,stroke:#3B82F6,stroke-width:4px
style OtherPackage fill:#F59E0B20,stroke:#F59E0B,stroke-width:4px
---
title: private Access Modifier
---
classDiagram
direction TB
namespace SamePackage {
class OtherClassSamePackage["Other class same package"]:::cannot_access {
}
class Class:::can_access {
-attribute String
-method() void
}
class Subclass["Subclass same package"]:::cannot_access {
}
}
note for Class "attribute and method have **private** access"
Class <|-- Subclass
namespace OtherPackage {
class SubclassOtherPackage["Subclass different package"]:::cannot_access {
}
class ClassOtherPackage["Other class different package"]:::cannot_access {
}
}
Class <|-- SubclassOtherPackage
classDef can_access fill:#76B192
classDef cannot_access fill:#D74345
style SamePackage fill:none,stroke:#3B82F6,stroke-width:4px
style OtherPackage fill:none,stroke:#F59E0B,stroke-width:4px
---
title: protected Access Modifier
---
classDiagram
direction TB
namespace SamePackage {
class OtherClassSamePackage["Other class same package"]:::can_access {
}
class Class:::can_access {
#attribute String
#method() void
}
class Subclass["Subclass same package"]:::can_access {
}
}
note for Class "attribute and method have **protected** access"
Class <|-- Subclass
namespace OtherPackage {
class SubclassOtherPackage["Subclass different package"]:::can_access {
}
class ClassOtherPackage["Other class different package"]:::cannot_access {
}
}
Class <|-- SubclassOtherPackage
classDef can_access fill:#76B192
classDef cannot_access fill:#D74345
style SamePackage fill:none,stroke:#3B82F6,stroke-width:4px
style OtherPackage fill:none,stroke:#F59E0B,stroke-width:4px
---
title: package-private Access Modifier
---
classDiagram
direction TB
namespace SamePackage {
class OtherClassSamePackage["Other class same package"]:::can_access {
}
class Class:::can_access {
~attribute String
~method() void
}
class Subclass["Subclass same package"]:::can_access {
}
}
note for Class "attribute and method have **package-private** (default) access"
Class <|-- Subclass
namespace OtherPackage {
class SubclassOtherPackage["Subclass different package"]:::cannot_access {
}
class ClassOtherPackage["Other class different package"]:::cannot_access {
}
}
Class <|-- SubclassOtherPackage
classDef can_access fill:#76B192
classDef cannot_access fill:#D74345
style SamePackage fill:none,stroke:#3B82F6,stroke-width:4px
style OtherPackage fill:none,stroke:#F59E0B,stroke-width:4px
Source: #55: Access levels
ℹ️ I used Mermaid to build the above class diagrams.
Mermaid is an "extension" of Markdown. It is supported by a growing number of products and platforms among which GitHub. We can describe diagrams and charts using a Mermaid text syntax. It offers a wide range of diagram types:
Here is an example of a class diagram showing the Mermaid source code first, and then the rendering.
Source:
```mermaid
classDiagram
class Person {
-firstName String
-lastName String
+getFullName() String
}
class Student {
-school String
+getSchool() String
}
Person <|-- Student
```
Output:
classDiagram
class Person {
-firstName String
-lastName String
+getFullName() String
}
class Student {
-school String
+getSchool() String
}
Person <|-- Student
package com.ericbouchut.oop.inheritance;
import java.util.Map;
/**
* This class implements several interfaces.
*/
class MyApplicationMultipleInterfaces implements Monitorable, Configurable, Runnable {
private boolean isRunning;
public static void main(String[] args) {
MyApplicationMultipleInterfaces app = new MyApplicationMultipleInterfaces();
System.out.println("isRuning(): " + app.isRunning());
app.run();
app.stop();
}
@Override
public boolean isRunning() {
return isRunning;
}
@Override
public Map<String, Object> getMetrics() {
return Map.of(
"error", 42,
"success", 567
);
}
@Override
public void loadConfig() {
System.out.println("Loading configuration.");
}
@Override
public void saveConfig() {
System.out.println("Saving configuration.");
}
@Override
public void run() {
System.out.println("Running...");
try {
start();
monitor();
} catch (Exception ex) {
// Handle exception
} finally {
stop();
}
}
protected void monitor() {
System.out.println("Monitoring...");
System.out.println("App isRunning?: " + isRunning());
System.out.println("App Metrics:" );
for (Map.Entry<String, ?> metricEntry: getMetrics().entrySet()) {
System.out.print("\t- ");
System.out.println(metricEntry);
}
}
protected void start() {
System.out.println("Starting the App...");
if (!isRunning()) {
loadConfig();
isRunning = true;
}
}
protected void stop() {
System.out.println("Stopping the App...");
if (isRunning()) {
saveConfig();
isRunning = false;
}
}
}The MyApplication class implements several interfaces:
- Monitorable
- Configurable
- java.lang.Runnable which basically defines a
run()method@FunctionalInterface public interface Runnable { void run(); }
classDiagram
class Monitorable {
<<interface>>
+isRunning() boolean
+getMetrics() Map~String, Object~
}
class Configurable {
<<interface>>
+loadConfig()
+saveConfig()
}
class Runnable["java.lang.Runnable"] {
<<interface>>
+run()
}
class MyApplication {
+isRunning() boolean
+getMetrics() Map~String, Object~
+loadConfig()
+saveConfig()
+run()
}
Monitorable <|-- MyApplication: implements
Configurable <|-- MyApplication: implements
Runnable <|-- MyApplication: implements
The Motion Sickness lab is intended as a practice on how to read and write text files.
See Udemy course for details.
Read a text file (symptoms.txt) that contains an unordered list of symptoms.
There is one symptom per line.
A symptom can contain spaces.
The file can contain duplicate symptoms.
- Read the input file
- Process the input file (but do not modify it), so that you:
- Order alphabetically the symptoms (i.e., the lines),
- Remove duplicate symptoms.
- Count the occurrences of each distinct symptom,
- Create a new text file (
results.txt)- With an ordered list of unique symptoms (one per line),
- With duplicates removed,
- Using this format:
symptom = occurrences. For instance if you found 11 occurrences ofhigh blood pressurein the input file (symptoms.txt), you will write once:high blood pressure = 11
Here is what the output file (results.txt) should look like:
anxiety = 7
arrhythmias = 4
blindness = 2
blurred vision = 6
constricted pupils = 3
cough = 7
dialated pupils = 4
dizziness = 6
dry mouth = 10
fever = 9
headache = 4
high blood pressure = 11
inflamation = 9
insomnia = 4
low blood pressure = 4
nausea = 7
rapid heart rate = 1
rash = 6
shortness of breath = 4
stiff neck = 6
stomach pain = 5
tremor = 4
water retention = 1You can find the code here. I provided 2 versions, one using the regular file reader and writer API, the other using the Stream API to learn and practice the functional concepts that have been introduced from Java 1.8 onwards.
- Java File API: FileSymptomCounter
- Java Stream API: StreamSymptomCounter