<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Liriel</title>
    <description>The latest articles on DEV Community by Liriel (@lirielc).</description>
    <link>https://dev.to/lirielc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4003118%2Fbdffb4ad-a004-421c-a5d1-6c3077136d6f.jpg</url>
      <title>DEV Community: Liriel</title>
      <link>https://dev.to/lirielc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lirielc"/>
    <language>en</language>
    <item>
      <title>Building GitHub Companion taught me a few things about Android architecture...</title>
      <dc:creator>Liriel</dc:creator>
      <pubDate>Thu, 02 Jul 2026 17:04:51 +0000</pubDate>
      <link>https://dev.to/lirielc/building-github-companion-taught-me-some-things-about-android-architecture-1m5f</link>
      <guid>https://dev.to/lirielc/building-github-companion-taught-me-some-things-about-android-architecture-1m5f</guid>
      <description>&lt;p&gt;One of the biggest challenges when learning Android development is moving beyond isolated code examples and building an application that resembles a production environment. Once an application starts interacting with external APIs, local databases, background synchronization, and asynchronous operations, concepts such as MVVM, repositories, dependency injection, and state management become essential rather than optional.&lt;/p&gt;

&lt;p&gt;To explore these concepts in practice, I built GitHub Companion, a native Android application that consumes the GitHub REST API while combining modern Kotlin components with Java interoperability commonly found in real-world Android projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Why Java Still Matters in Android Development
&lt;/h2&gt;

&lt;p&gt;Kotlin is currently the preferred language for Android, but Java remains a foundational pillar of the ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Coexistence and Legacy Codebases&lt;/strong&gt;: A vast number of production Android applications contain legacy systems written entirely in Java. Engineering teams rely on developers who can seamlessly navigate, refactor, and extend Java modules alongside newer Kotlin additions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Interoperability&lt;/strong&gt;: Kotlin and Java compile to the same JVM bytecode and are 100% interoperable. In modern projects, it is common to write UI layers in Kotlin (e.g., Jetpack Compose) while maintaining stable backend interfaces, models, and network libraries in Java.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Solid OOP Foundations&lt;/strong&gt;: Understanding Java's strict object-oriented design, garbage collection, and class hierarchies makes it significantly easier to grasp advanced Android frameworks and design patterns.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Architecture: Demystifying MVVM and Coroutines
&lt;/h2&gt;

&lt;p&gt;The application is built on the &lt;strong&gt;Model-View-ViewModel (MVVM)&lt;/strong&gt; pattern, which enforces a strict separation of concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Model&lt;/strong&gt;: Encapsulates the domain logic, database entities, and API clients.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;View&lt;/strong&gt;: Handles user interaction and rendering (in our case, declarative Jetpack Compose).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ViewModel&lt;/strong&gt;: Holds UI state and coordinates data operations. It communicates with the domain repositories and exposes states (Loading, Success, Error) to the View.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To handle asynchronous networking without blocking the UI thread, we utilize &lt;strong&gt;Kotlin Coroutines&lt;/strong&gt;. Coroutines provide a non-blocking execution model. By launching network requests in a Coroutine scope, we suspend task execution while waiting for the network, and resume automatically when the data arrives, keeping the main thread free to draw the UI.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Under the Hood: Deep Technical Insights
&lt;/h2&gt;

&lt;p&gt;To build reliable applications, we must understand how our frameworks operate underneath the abstraction layers. Here is how our app functions "under the hood."&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Why Room Exists If SQLite Already Exists
&lt;/h3&gt;

&lt;p&gt;SQLite is the engine under Android's local database, but using raw SQLite requires significant boilerplate. Developers must manually write SQL queries as strings, translate &lt;code&gt;Cursor&lt;/code&gt; objects into Java/Kotlin objects, and handle database updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Room&lt;/strong&gt; is an abstraction layer over SQLite that solves these issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Compile-Time Verification&lt;/strong&gt;: Room parses and validates your SQL queries during compilation. If you mistype a table name in a &lt;code&gt;@Query&lt;/code&gt; annotation, the build fails immediately. With raw SQLite, this syntax error would only crash your app at runtime on the user's device.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;No Boilerplate Mapping&lt;/strong&gt;: Room maps database rows directly to Java/Kotlin Data Objects (Entities) using annotation processors, eliminating cursor traversal loops.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reactive Streams&lt;/strong&gt;: Room seamlessly integrates with &lt;code&gt;Flow&lt;/code&gt; and &lt;code&gt;LiveData&lt;/code&gt;. When a row in your SQLite table changes, Room automatically publishes the updated query results to any active subscribers, keeping the UI in sync.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  B. What Actually Happens When Retrofit Executes a Request
&lt;/h3&gt;

&lt;p&gt;When you define a networking interface in Retrofit, it is just an interface with annotations—there is no implementation class. How does it execute?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Dynamic Proxy&lt;/strong&gt;: When you initialize Retrofit and call &lt;code&gt;retrofit.create(GitHubApiService.class)&lt;/code&gt;, Java's reflection mechanism uses &lt;code&gt;Proxy.newProxyInstance()&lt;/code&gt; to construct a dynamic proxy class at runtime.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Annotation Processing&lt;/strong&gt;: When a method (like &lt;code&gt;getRepository()&lt;/code&gt;) is called, Retrofit intercepts the call, parses the annotations (such as &lt;code&gt;@GET&lt;/code&gt; and &lt;code&gt;@Path&lt;/code&gt;) using reflection, and builds an HTTP request configuration.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;OkHttp Core&lt;/strong&gt;: Retrofit passes this request configuration to OkHttp, which manages the low-level connection pool, headers, and HTTP interceptors.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Serialization&lt;/strong&gt;: Once the raw bytes return from the server, Retrofit uses &lt;code&gt;GsonConverterFactory&lt;/code&gt; to deserialize the JSON stream into a Kotlin/Java DTO (Data Transfer Object).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Thread Switching&lt;/strong&gt;: If using Java &lt;code&gt;Call.enqueue()&lt;/code&gt;, Retrofit schedules the HTTP work on a background executor pool and posts the result back to the Android Main Thread. If using Kotlin &lt;code&gt;suspend&lt;/code&gt;, it suspends the Coroutine and resumes on the dispatcher scope.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  C. Coroutines Are Not Threads
&lt;/h3&gt;

&lt;p&gt;A common misconception is that a Coroutine is simply a thread wrapper. It is not.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Threads&lt;/strong&gt; are managed by the Operating System. Context switching between threads is expensive because the OS must save registers and CPU states, costing memory and time. You cannot run millions of threads concurrently.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Coroutines&lt;/strong&gt; are managed by the runtime environment and are cooperative. They use &lt;em&gt;suspension points&lt;/em&gt; where they yield the underlying thread to other coroutines without blocking it. &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Lightweight&lt;/strong&gt;: A coroutine is just a small object allocated on the heap. You can launch 100,000 coroutines on a single thread without memory pressure.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dispatchers&lt;/strong&gt;: Coroutines execute on dispatchers (like &lt;code&gt;Dispatchers.IO&lt;/code&gt; for network/disk operations or &lt;code&gt;Dispatchers.Main&lt;/code&gt; for UI changes). The dispatcher acts as a scheduler, mapping coroutine tasks to a thread pool underneath.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  D. Understanding Dependency Injection Through Hilt
&lt;/h3&gt;

&lt;p&gt;Without Dependency Injection (DI), classes instantiate their own dependencies. For example, a &lt;code&gt;MainActivity&lt;/code&gt; would instantiate a &lt;code&gt;Repository&lt;/code&gt;, which instantiates a &lt;code&gt;RoomDatabase&lt;/code&gt; and a &lt;code&gt;Retrofit&lt;/code&gt; client. This creates tight coupling, makes testing impossible, and violates the Single Responsibility Principle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hilt&lt;/strong&gt; (built on Dagger) is a compile-time DI library:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Service Decoupling&lt;/strong&gt;: Instead of writing &lt;code&gt;new GitHubRepositoryImpl(...)&lt;/code&gt;, we annotate the class constructor with &lt;code&gt;@Inject&lt;/code&gt; and Hilt automatically provides the dependency.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Codegen Graph&lt;/strong&gt;: During compilation, Hilt parses our annotations and generates the dependency graph. It validates that every class has access to the instances it needs. If a dependency is missing, the app fails to compile.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Scope Management&lt;/strong&gt;: Hilt couples dependencies to Android lifecycles (e.g., &lt;code&gt;@Singleton&lt;/code&gt; lives for the app's duration, while &lt;code&gt;@ActivityScoped&lt;/code&gt; exists only as long as the Activity).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  E. Why Repository Exists
&lt;/h3&gt;

&lt;p&gt;The Repository pattern serves a vital architectural purpose: it isolates the domain layer from data origin details.&lt;br&gt;
Without a Repository, the ViewModel would need to coordinate Room database transactions and Retrofit network calls directly. If we decided to migrate our caching engine from Room to Realm, we would have to rewrite the ViewModel.&lt;/p&gt;

&lt;p&gt;The Repository provides a &lt;strong&gt;Single Source of Truth (SSOT)&lt;/strong&gt;. The ViewModel simply requests a repository record, and the Repository decides whether to fetch it from SQLite or trigger a web request. During tests, we mock the Repository interface using mock libraries (like Mockito) to return local test data, verifying our UI states without hitting real APIs.&lt;/p&gt;
&lt;h3&gt;
  
  
  F. The WorkManager + Hilt Crash That Took Hours to Debug
&lt;/h3&gt;

&lt;p&gt;When setting up background syncing, we encountered a runtime crash: &lt;code&gt;NoSuchMethodException: SyncFavoritesWorker.&amp;lt;init&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Cause&lt;/strong&gt;: By default, Android's &lt;code&gt;androidx.startup&lt;/code&gt; library automatically initializes WorkManager. During startup, WorkManager uses reflection to look for a default two-argument constructor &lt;code&gt;(Context, WorkerParameters)&lt;/code&gt;. Because our worker uses &lt;code&gt;@HiltWorker&lt;/code&gt; to inject dependencies, it lacks this constructor, causing reflection to fail.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Resolution&lt;/strong&gt;: We had to disable the automatic WorkManager initializer in the &lt;code&gt;AndroidManifest.xml&lt;/code&gt; via:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta-data&lt;/span&gt;
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"androidx.work.WorkManagerInitializer"&lt;/span&gt;
    &lt;span class="na"&gt;android:value=&lt;/span&gt;&lt;span class="s"&gt;"androidx.startup"&lt;/span&gt;
    &lt;span class="na"&gt;tools:node=&lt;/span&gt;&lt;span class="s"&gt;"remove"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Then, we implemented &lt;code&gt;Configuration.Provider&lt;/code&gt; in our &lt;code&gt;Application&lt;/code&gt; class, manually injecting the custom &lt;code&gt;HiltWorkerFactory&lt;/code&gt; to handle the instantiation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  G. Cache Invalidation Is Harder Than It Looks
&lt;/h3&gt;

&lt;p&gt;Offline synchronization sounds simple: save data locally and show it. But what happens if the data on the server changes?&lt;br&gt;
If the app never checks for updates, the user sees stale information forever. If the app updates too often, it defeats the purpose of caching and drains the battery.&lt;/p&gt;

&lt;p&gt;To solve this, we implemented a &lt;strong&gt;Time-Based Invalidation Policy&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Every database record includes a &lt;code&gt;lastSync&lt;/code&gt; timestamp.&lt;/li&gt;
&lt;li&gt;  When a user searches for a repository, the repository queries Room and checks if &lt;code&gt;System.currentTimeMillis() - lastSync &amp;lt; 30 minutes&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  If valid, it returns the cached data. If expired, it attempts a network fetch. If the network call fails (e.g., no internet), it falls back gracefully to the expired cache.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  H. Why GitHub API Rate Limits Matter
&lt;/h3&gt;

&lt;p&gt;The GitHub REST API enforces a strict rate limit of &lt;strong&gt;60 requests per hour&lt;/strong&gt; for unauthenticated requests. &lt;/p&gt;

&lt;p&gt;If our app did not cache data locally, every tab switch (Commits -&amp;gt; Branches -&amp;gt; Issues) or list reload would count against the user's rate limit. The user would quickly receive a &lt;code&gt;403 Forbidden&lt;/code&gt; error. By caching details in Room for 30 minutes and grouping repository data, we minimize API calls, saving our network budget.&lt;/p&gt;
&lt;h3&gt;
  
  
  I. Why ANRs Happen
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;Application Not Responding (ANR)&lt;/strong&gt; dialog is shown when the Main Thread (UI Thread) is blocked.&lt;br&gt;
In Android, the Main Thread has a message loop managed by a &lt;code&gt;Looper&lt;/code&gt;. It processes layout draws, touch events, and system notifications. If any event takes longer than &lt;strong&gt;5 seconds&lt;/strong&gt; to execute, the OS assumes the app is frozen and shows the ANR dialog.&lt;/p&gt;

&lt;p&gt;Running a database query or an API request synchronously blocks the Thread until the socket completes or disk I/O completes. In our application, we prevent this by executing database queries asynchronously using Room's Flow bindings and performing Retrofit calls inside Kotlin Coroutines or Java's background executor thread pools.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Java-Kotlin Interoperability: The Date Formatter
&lt;/h2&gt;

&lt;p&gt;To show how Java classes integrate with Kotlin, we implemented &lt;strong&gt;&lt;a href="https://github.com/LirielC/GitHubCompanion/blob/main/app/src/main/java/com/example/hubcompanion/util/DateFormatterUtil.java" rel="noopener noreferrer"&gt;&lt;code&gt;DateFormatterUtil.java&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; in Java to parse ISO-8601 strings into user-friendly relative dates (e.g., "3 minutes ago").&lt;/p&gt;

&lt;p&gt;In our Kotlin presentation layer, we consume this Java helper directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;relativeDate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DateFormatterUtil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formatGithubDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Architectural Code Walkthrough
&lt;/h2&gt;

&lt;p&gt;Below are the streamlined core components of the application. The full, concrete implementations can be viewed directly in the &lt;a href="https://github.com/LirielC/GitHubCompanion" rel="noopener noreferrer"&gt;project repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Consuming REST APIs (Retrofit Interface)
&lt;/h3&gt;

&lt;p&gt;Retrofit abstracts network endpoints. In a mixed codebase, we can define our endpoints in Java using &lt;code&gt;Call&amp;lt;T&amp;gt;&lt;/code&gt; or in Kotlin using &lt;code&gt;suspend&lt;/code&gt; functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kotlin (using Coroutines)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;GitHubApiService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"repos/{owner}/{repo}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"owner"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"repo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;RepositoryDto&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Java Equivalent (using &lt;code&gt;Call&amp;lt;T&amp;gt;&lt;/code&gt;)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;GitHubApiService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"repos/{owner}/{repo}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Call&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RepositoryDto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"owner"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"repo"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  B. The Repository Pattern (Cache Management)
&lt;/h3&gt;

&lt;p&gt;The Repository acts as a mediator between data sources, providing a single source of truth.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kotlin Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="err"&gt;`&lt;/span&gt;  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GitHubRepositoryImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GitHubApiService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;repositoryDao&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RepositoryDao&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GitHubReposit&lt;/span&gt;&lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;ory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;forceRefresh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Repository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;localRepo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repositoryDao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFavoriteById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$owner/$name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isCacheValid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;localRepo&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;localRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastSync&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isCacheValid&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;forceRefresh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;localRepo&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDomain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;dto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apiService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDomain&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;also&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;repositoryDao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertFavorite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RepositoryEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromDomain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;localRepo&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toDomain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  C. State Management (ViewModel)
&lt;/h3&gt;

&lt;p&gt;The ViewModel hosts the application state, pushing states lifecycle-safely to the View.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Java LiveData ViewModel&lt;/strong&gt;:&lt;br&gt;
&lt;code&gt;&lt;/code&gt;`java&lt;br&gt;
public class RepositorySearchViewModel extends ViewModel {&lt;br&gt;
    private final GitHubRepositoryImpl repository;&lt;br&gt;
    private final MutableLiveData&amp;gt; searchResult = new MutableLiveData&amp;lt;&amp;gt;();&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public LiveData&amp;lt;Resource&amp;lt;Repository&amp;gt;&amp;gt; getSearchResult() { return searchResult; }

public void searchRepository(String owner, String repo) {
    searchResult.setValue(Resource.loading());
    new Thread(() -&amp;gt; {
        try {
            Repository result = repository.getRepository(owner, repo, true);
            searchResult.postValue(Resource.success(result));
        } catch (Exception e) {
            searchResult.postValue(Resource.error(e.getMessage()));
        }
    }).start();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Key Concepts Comparison: Kotlin vs. Java
&lt;/h2&gt;

&lt;p&gt;Developers working in mixed codebases must understand the structural equivalents across both languages:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Kotlin Pattern&lt;/th&gt;
&lt;th&gt;Java Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Async Operations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Coroutines (&lt;code&gt;suspend&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Executors, &lt;code&gt;Thread&lt;/code&gt;, or Retrofit &lt;code&gt;Call.enqueue()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Observation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;StateFlow&lt;/code&gt; or &lt;code&gt;SharedFlow&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LiveData&lt;/code&gt; or RxJava &lt;code&gt;Observable&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Binding&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Jetpack Compose State&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LiveData.observe()&lt;/code&gt; or View Binding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Classes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;data class Repository(...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Standard Java Class with private fields, getters, and constructor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  7. Application Branding &amp;amp; Interface Preview
&lt;/h2&gt;

&lt;p&gt;To give the application a premium identity, we designed a custom logo combining a robotic companion concept with the GitHub symbol:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnzdwmffl59big6mdn2jv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnzdwmffl59big6mdn2jv.png" alt="GitHub Companion Logo" width="324" height="726"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below is a preview of the search and detailed views of the app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsu2cbqm1gu5p5yhirxhx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsu2cbqm1gu5p5yhirxhx.png" alt="GitHub Companion Mockup" width="324" height="724"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Clean Code &amp;amp; Mobile Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;DRY (Don't Repeat Yourself)&lt;/strong&gt;: Network responses (DTOs) are mapped to domain models in a centralized mapping layer, ensuring parsing logic is never repeated.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;SOLID Principles&lt;/strong&gt;: We respect the Single Responsibility Principle. For example, database DAOs are solely responsible for SQL queries, while the Repository handles cache management logic.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Version Control (Git)&lt;/strong&gt;: Adopted a feature-branch workflow (e.g., &lt;code&gt;feature/retrofit-api&lt;/code&gt;) to keep the main development branch clean, employing semantic commit logs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. Conclusion &amp;amp; Learnings
&lt;/h2&gt;

&lt;p&gt;Building &lt;strong&gt;GitHub Companion&lt;/strong&gt; highlighted the value of structured architecture. By leveraging the &lt;strong&gt;Repository Pattern&lt;/strong&gt; and &lt;strong&gt;MVVM&lt;/strong&gt;, writing clean, encapsulated &lt;strong&gt;Java models&lt;/strong&gt;, and integrating &lt;strong&gt;Kotlin Coroutines&lt;/strong&gt; and &lt;strong&gt;Retrofit REST APIs&lt;/strong&gt;, we built a codebase that is highly testable, scalable, and easy to maintain in a mixed-language development environment.&lt;/p&gt;

&lt;p&gt;Working directly on these layers shows that mobile development is more than just writing UI; it requires understanding JVM thread synchronization, memory architectures, caching thresholds, and how frameworks integrate.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://imgur.com/EosbhJ7" rel="noopener noreferrer"&gt;Video&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  10. References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;p&gt;To learn more about Android architectures, JVM interoperability, and best practices, check out these official developer resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://developer.android.com/topic/architecture" rel="noopener noreferrer"&gt;Android Developers - Guide to App Architecture&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://kotlinlang.org/docs/coroutines-overview.html" rel="noopener noreferrer"&gt;Kotlin Docs - Coroutines Guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://square.github.io/retrofit/" rel="noopener noreferrer"&gt;Retrofit Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://developer.android.com/training/data-storage/room" rel="noopener noreferrer"&gt;Android Developers - Room Persistence Library&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://developer.android.com/topic/libraries/architecture/workmanager" rel="noopener noreferrer"&gt;Android Developers - WorkManager Guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://kotlinlang.org/docs/java-to-kotlin-interop.html" rel="noopener noreferrer"&gt;Kotlin-Java Interop Guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can explore the full implementation code of this project in my GitHub Repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/LirielC/GitHubCompanion" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub Companion Repository&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Java Garbage Collector: Why Creating Objects Is Cheaper Than You Think</title>
      <dc:creator>Liriel</dc:creator>
      <pubDate>Sun, 28 Jun 2026 17:26:32 +0000</pubDate>
      <link>https://dev.to/lirielc/java-garbage-collector-why-creating-objects-is-cheaper-than-you-think-2dlm</link>
      <guid>https://dev.to/lirielc/java-garbage-collector-why-creating-objects-is-cheaper-than-you-think-2dlm</guid>
      <description>&lt;p&gt;When many developers first hear about Java's Garbage Collector, they often associate it with one thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Automatic memory management comes at the cost of performance."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This perception made sense twenty years ago.&lt;/p&gt;

&lt;p&gt;Today, however, some of the largest systems in the world run on the JVM, handling millions of requests per second with strict latency requirements.&lt;/p&gt;

&lt;p&gt;Companies like Netflix, Uber, LinkedIn, and many banks rely heavily on Java in production environments where performance is not optional.&lt;/p&gt;

&lt;p&gt;So what changed?&lt;/p&gt;

&lt;p&gt;The answer lies in understanding how the Java Garbage Collector actually works.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Memory Problem Every Language Must Solve
&lt;/h2&gt;

&lt;p&gt;Imagine the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application allocates memory for the &lt;code&gt;User&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Eventually, that object is no longer needed.&lt;/p&gt;

&lt;p&gt;The question is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Who is responsible for freeing that memory?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In languages such as C, the developer is responsible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Forgetting to free memory causes leaks.&lt;/p&gt;

&lt;p&gt;Freeing memory too early can lead to crashes and undefined behavior.&lt;/p&gt;

&lt;p&gt;Java chose a different approach:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The JVM itself determines when an object is no longer reachable and automatically reclaims its memory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This process is known as &lt;strong&gt;Garbage Collection&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Does Java Know an Object Is Dead?
&lt;/h2&gt;

&lt;p&gt;Java does not determine whether an object is alive based on variables or scope.&lt;/p&gt;

&lt;p&gt;Instead, it uses a concept called &lt;strong&gt;reachability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable &lt;code&gt;user&lt;/code&gt; references the object.&lt;/p&gt;

&lt;p&gt;As long as that reference exists, the object is considered alive.&lt;/p&gt;

&lt;p&gt;Now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If no other references point to that object, it becomes unreachable.&lt;/p&gt;

&lt;p&gt;Unreachable objects become candidates for garbage collection.&lt;/p&gt;

&lt;p&gt;This approach is significantly safer than manual memory management because the JVM avoids both accidental deallocation and most memory corruption issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Observation That Changed Everything
&lt;/h2&gt;

&lt;p&gt;The JVM is built around an observation known as the &lt;strong&gt;Generational Hypothesis&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most objects die young.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Surprisingly, this is true for the majority of modern applications.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP request objects&lt;/li&gt;
&lt;li&gt;DTOs&lt;/li&gt;
&lt;li&gt;JSON parsing structures&lt;/li&gt;
&lt;li&gt;Temporary strings&lt;/li&gt;
&lt;li&gt;Stream operations&lt;/li&gt;
&lt;li&gt;Intermediate collections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These objects often live for only a few milliseconds.&lt;/p&gt;

&lt;p&gt;Meanwhile, objects that survive for longer periods tend to remain alive for a very long time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caches&lt;/li&gt;
&lt;li&gt;Singleton services&lt;/li&gt;
&lt;li&gt;Application configurations&lt;/li&gt;
&lt;li&gt;Database connection pools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This observation fundamentally shaped the design of Java's Garbage Collectors.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Heap Is Divided Into Generations
&lt;/h2&gt;

&lt;p&gt;Instead of treating all objects equally, Java separates memory into generations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Heap
│
├── Young Generation
│   ├── Eden
│   ├── Survivor 0
│   └── Survivor 1
│
└── Old Generation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Eden: Where Objects Are Born
&lt;/h2&gt;

&lt;p&gt;Almost every object starts its life in &lt;strong&gt;Eden Space&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of them are allocated inside Eden.&lt;/p&gt;

&lt;p&gt;When Eden becomes full, the JVM triggers a &lt;strong&gt;Minor GC&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Minor GC
&lt;/h2&gt;

&lt;p&gt;During a Minor GC, the JVM identifies which objects in Eden are still alive.&lt;/p&gt;

&lt;p&gt;Dead objects are discarded immediately.&lt;/p&gt;

&lt;p&gt;Live objects are copied to one of the Survivor spaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Eden → Survivor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This process is extremely efficient because most objects are already dead.&lt;/p&gt;

&lt;p&gt;Remember the Generational Hypothesis:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most objects die young.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a result, the JVM often removes the vast majority of objects during every Minor GC cycle.&lt;/p&gt;




&lt;h2&gt;
  
  
  Survivor Spaces
&lt;/h2&gt;

&lt;p&gt;The JVM alternates between two survivor areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Survivor 0&lt;/li&gt;
&lt;li&gt;Survivor 1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Objects bounce between these spaces while they survive multiple garbage collection cycles.&lt;/p&gt;

&lt;p&gt;Each time an object survives, its age increases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Age 1
Age 2
Age 3
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually, the JVM decides that the object is probably long-lived.&lt;/p&gt;

&lt;p&gt;At this point, it gets promoted.&lt;/p&gt;




&lt;h2&gt;
  
  
  Promotion to Old Generation
&lt;/h2&gt;

&lt;p&gt;Objects that survive enough collection cycles are moved to the &lt;strong&gt;Old Generation&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Young Generation
        ↓
Old Generation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typical examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring Beans&lt;/li&gt;
&lt;li&gt;Caches&lt;/li&gt;
&lt;li&gt;Singleton instances&lt;/li&gt;
&lt;li&gt;Application configuration objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These objects are expected to remain alive for much longer periods.&lt;/p&gt;




&lt;h2&gt;
  
  
  Major GC and Full GC
&lt;/h2&gt;

&lt;p&gt;Cleaning the Old Generation is considerably more expensive.&lt;/p&gt;

&lt;p&gt;This process is often called a &lt;strong&gt;Major GC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In some situations, the JVM may need to collect the entire heap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Young Generation&lt;/li&gt;
&lt;li&gt;Old Generation&lt;/li&gt;
&lt;li&gt;Metaspace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is known as a &lt;strong&gt;Full GC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Historically, Full GCs were among the most feared events in Java applications because they frequently paused the application for long periods.&lt;/p&gt;

&lt;p&gt;Modern collectors significantly reduced this problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stop-The-World Moment
&lt;/h2&gt;

&lt;p&gt;During certain phases of garbage collection, the JVM pauses all application threads.&lt;/p&gt;

&lt;p&gt;This event is called:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Stop-The-World (STW)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While the JVM performs critical operations, application threads remain suspended.&lt;/p&gt;

&lt;p&gt;The goal of modern collectors is not to eliminate these pauses entirely, but rather to make them extremely short and predictable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Enter G1GC
&lt;/h2&gt;

&lt;p&gt;Since Java 9, the default collector is &lt;strong&gt;Garbage First (G1)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of dividing memory into large contiguous spaces, G1 divides the heap into many small regions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+----+----+----+----+
| R1 | R2 | R3 | R4 |
+----+----+----+----+
| R5 | R6 | R7 | R8 |
+----+----+----+----+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some regions contain young objects.&lt;/p&gt;

&lt;p&gt;Others contain old objects.&lt;/p&gt;

&lt;p&gt;This design allows G1 to focus on collecting the regions that provide the highest memory recovery with the smallest pause times.&lt;/p&gt;

&lt;p&gt;Hence the name:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Garbage First.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Secret Behind Fast Object Allocation
&lt;/h2&gt;

&lt;p&gt;One of the biggest misconceptions in Java is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Creating objects is expensive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In reality, object allocation in Java is often incredibly cheap.&lt;/p&gt;

&lt;p&gt;Most allocations happen using a technique called &lt;strong&gt;Bump Pointer Allocation&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Object A | Object B | Free Space |
                       ^
                    Pointer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating a new object frequently means little more than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pointer += object_size
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No complex memory search.&lt;/p&gt;

&lt;p&gt;No traversal.&lt;/p&gt;

&lt;p&gt;No expensive allocation algorithms.&lt;/p&gt;

&lt;p&gt;Just moving a pointer forward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Thread Local Allocation Buffers (TLAB)
&lt;/h2&gt;

&lt;p&gt;The JVM goes even further.&lt;/p&gt;

&lt;p&gt;Each thread often receives its own allocation area called a &lt;strong&gt;Thread Local Allocation Buffer (TLAB)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of multiple threads competing for access to the heap, they allocate objects inside their own local buffers.&lt;/p&gt;

&lt;p&gt;This dramatically reduces contention and synchronization overhead.&lt;/p&gt;

&lt;p&gt;For most applications, object allocation becomes almost lock-free.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sometimes the Object Never Exists
&lt;/h2&gt;

&lt;p&gt;Modern JVMs perform sophisticated optimizations.&lt;/p&gt;

&lt;p&gt;One of the most impressive is &lt;strong&gt;Escape Analysis&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the JVM determines that &lt;code&gt;point&lt;/code&gt; never escapes the method, it may avoid allocating the object entirely.&lt;/p&gt;

&lt;p&gt;In some cases:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The object is never created.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Is Garbage Collection Free?
&lt;/h2&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;Garbage Collection introduces overhead.&lt;/p&gt;

&lt;p&gt;The JVM spends CPU cycles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identifying live objects&lt;/li&gt;
&lt;li&gt;Moving objects&lt;/li&gt;
&lt;li&gt;Compacting memory&lt;/li&gt;
&lt;li&gt;Updating references&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, the trade-off has proven extremely successful.&lt;/p&gt;

&lt;p&gt;Developers gain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory safety&lt;/li&gt;
&lt;li&gt;Higher productivity&lt;/li&gt;
&lt;li&gt;Fewer crashes caused by invalid pointers&lt;/li&gt;
&lt;li&gt;Simpler application code&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;The Garbage Collector is often described as a convenience feature.&lt;/p&gt;

&lt;p&gt;In reality, it is much more than that.&lt;/p&gt;

&lt;p&gt;The JVM combines decades of research in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allocation algorithms&lt;/li&gt;
&lt;li&gt;Concurrent programming&lt;/li&gt;
&lt;li&gt;Memory compaction&lt;/li&gt;
&lt;li&gt;Cache locality&lt;/li&gt;
&lt;li&gt;Latency reduction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern Java applications are not fast despite the Garbage Collector.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In many cases, they are fast precisely because of the engineering behind it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The next time you write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;remember that behind this single line, the JVM is leveraging decades of computer science research to make that operation as efficient as possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Oracle Java HotSpot Garbage Collection Tuning Guide&lt;/li&gt;
&lt;li&gt;Oracle G1 Garbage Collector Documentation&lt;/li&gt;
&lt;li&gt;Aleksey Shipilev — JVM Anatomy Quarks&lt;/li&gt;
&lt;li&gt;Scott Oaks — &lt;em&gt;Java Performance: The Definitive Guide&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Plumbr Garbage Collection Handbook&lt;/li&gt;
&lt;li&gt;OpenJDK Documentation&lt;/li&gt;
&lt;li&gt;GCeasy JVM Performance Articles&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>computerscience</category>
      <category>java</category>
      <category>performance</category>
      <category>programming</category>
    </item>
    <item>
      <title>What Are Classes, Objects, and Methods in Java? (Explained Simply)</title>
      <dc:creator>Liriel</dc:creator>
      <pubDate>Fri, 26 Jun 2026 00:54:29 +0000</pubDate>
      <link>https://dev.to/lirielc/what-are-classes-objects-and-methods-in-java-explained-simply-1big</link>
      <guid>https://dev.to/lirielc/what-are-classes-objects-and-methods-in-java-explained-simply-1big</guid>
      <description>&lt;h1&gt;
  
  
  Classes, Objects, and Methods in Java
&lt;/h1&gt;

&lt;p&gt;When you start learning Java — or any object-oriented language — three concepts will show up everywhere: &lt;strong&gt;classes&lt;/strong&gt;, &lt;strong&gt;objects&lt;/strong&gt;, and &lt;strong&gt;methods&lt;/strong&gt;. Before you can write meaningful code, you need to understand what each of these is, why it exists, and how they relate to each other.&lt;/p&gt;

&lt;p&gt;This article breaks all three down in a practical, straightforward way, using a real-world example you would actually find in a backend application.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is a Class?
&lt;/h2&gt;

&lt;p&gt;A class is a &lt;strong&gt;blueprint&lt;/strong&gt;. It is a definition, a template that describes what a certain type of thing looks like and what it can do — but it is not the thing itself.&lt;/p&gt;

&lt;p&gt;Think of it like an architectural floor plan. The plan tells you how many rooms a house has, where the doors are, and how the kitchen is laid out. But the plan is not a house you can live in. You use the plan to &lt;em&gt;build&lt;/em&gt; a house.&lt;/p&gt;

&lt;p&gt;In the same way, a class tells Java what attributes (data) and behaviors (methods) a certain type of object will have. No memory is allocated for real data yet — the class is just the definition.&lt;/p&gt;

&lt;p&gt;A class defines two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Attributes&lt;/strong&gt; — the data that each object of this type will hold&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Methods&lt;/strong&gt; — the actions that each object of this type can perform&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: the &lt;code&gt;User&lt;/code&gt; class
&lt;/h3&gt;

&lt;p&gt;In a web application, users are everywhere. Let's model one as a class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deactivate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;changeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getUserInfo&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" ("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;") - Active: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class describes what every user in our system has and can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Attributes:&lt;/strong&gt; &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;active&lt;/code&gt; — these are the pieces of data each user carries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Methods:&lt;/strong&gt; &lt;code&gt;deactivate()&lt;/code&gt;, &lt;code&gt;changeEmail()&lt;/code&gt;, and &lt;code&gt;getUserInfo()&lt;/code&gt; — these are the actions a user can perform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that the class alone does nothing. It just declares the structure. To actually work with a user, you need to create an object from it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is an Object?
&lt;/h2&gt;

&lt;p&gt;An object is a &lt;strong&gt;concrete instance of a class&lt;/strong&gt;. While the class is the blueprint, the object is the actual thing built from it — with its own real data stored in memory.&lt;/p&gt;

&lt;p&gt;Every time you write &lt;code&gt;new User(...)&lt;/code&gt;, Java uses the &lt;code&gt;User&lt;/code&gt; class to create a brand new object. That object gets its own copy of &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;active&lt;/code&gt;. Multiple objects can exist from the same class at the same time, and each one holds its own independent data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: creating and using objects
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ana Silva"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ana@email.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Carlos Souza"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"carlos@email.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;user1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deactivate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;user2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;changeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"carlos.souza@newmail.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserInfo&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserInfo&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;user1&lt;/code&gt; and &lt;code&gt;user2&lt;/code&gt; are two separate objects, both created from the same &lt;code&gt;User&lt;/code&gt; class. Even though they share the same structure, they are completely independent. Deactivating &lt;code&gt;user1&lt;/code&gt; has no effect on &lt;code&gt;user2&lt;/code&gt;. Changing the email of &lt;code&gt;user2&lt;/code&gt; does not touch &lt;code&gt;user1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is one of the most important things to internalize: &lt;strong&gt;the class defines the shape, but each object has its own state&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is a Method?
&lt;/h2&gt;

&lt;p&gt;A method defines &lt;strong&gt;what an object can do&lt;/strong&gt;. It is a block of code attached to a class that describes a specific behavior or action.&lt;/p&gt;

&lt;p&gt;In real backend systems, methods tend to represent either business logic or data access. They are not just utility functions — they express what a concept &lt;em&gt;means&lt;/em&gt; in your domain.&lt;/p&gt;

&lt;p&gt;Let's look at the methods from our &lt;code&gt;User&lt;/code&gt; class more carefully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deactivate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;changeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getUserInfo&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" ("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;") - Active: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each method has a clear responsibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;deactivate()&lt;/code&gt; encapsulates the business rule that deactivating a user means setting their &lt;code&gt;active&lt;/code&gt; flag to &lt;code&gt;false&lt;/code&gt;. Instead of writing &lt;code&gt;user.active = false&lt;/code&gt; scattered throughout your code, you put that logic in one place and call it by a meaningful name.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;changeEmail()&lt;/code&gt; provides a controlled way to update the user's email. You could add validation inside it later without changing anything else in your codebase.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getUserInfo()&lt;/code&gt; formats user data into a readable string, separating that concern from whoever is displaying it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the essence of why methods exist: they keep logic organized, named, and reusable.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the Three Concepts Work Together
&lt;/h2&gt;

&lt;p&gt;These three concepts are not independent — they depend on each other to make object-oriented programming work.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;In our example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Class&lt;/td&gt;
&lt;td&gt;Defines the structure and behavior&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;User&lt;/code&gt; blueprint with its fields and methods&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;A real instance with actual data&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;user1&lt;/code&gt; (Ana) and &lt;code&gt;user2&lt;/code&gt; (Carlos) in memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Method&lt;/td&gt;
&lt;td&gt;An action the object can perform&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;deactivate()&lt;/code&gt;, &lt;code&gt;changeEmail()&lt;/code&gt;, &lt;code&gt;getUserInfo()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The relationship is straightforward: you write a &lt;strong&gt;class&lt;/strong&gt; once, create as many &lt;strong&gt;objects&lt;/strong&gt; from it as you need, and interact with those objects by calling &lt;strong&gt;methods&lt;/strong&gt; on them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters in Real Java Development
&lt;/h2&gt;

&lt;p&gt;This is not abstract theory you'll leave behind once you get to "the real stuff". This is exactly the foundation that real backend applications are built on.&lt;/p&gt;

&lt;p&gt;When you work with Spring Boot, for instance, your classes become the backbone of the entire application. The &lt;code&gt;User&lt;/code&gt; class from this article is one annotation away from being a database entity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// same fields and methods&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there, it flows through your entire layered architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Controllers&lt;/strong&gt; receive HTTP requests and work with &lt;code&gt;User&lt;/code&gt; objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Services&lt;/strong&gt; contain business logic that operates on &lt;code&gt;User&lt;/code&gt; objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repositories&lt;/strong&gt; persist and retrieve &lt;code&gt;User&lt;/code&gt; objects from the database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every layer of a Spring Boot API is built on classes. Every piece of data passing through your system is an object. Every interaction with that data goes through methods. Understanding this clearly makes every other concept in Java easier to grasp.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Once you have a solid grip on these three ideas, a lot of what can seem confusing about Java starts to make sense:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Classes&lt;/strong&gt; give your code structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Objects&lt;/strong&gt; are the live, running instances of that structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Methods&lt;/strong&gt; define how those instances behave and interact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else in Java — inheritance, interfaces, annotations, frameworks — builds on top of this foundation. Get comfortable with it, and the rest of the language becomes much more approachable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Go Next
&lt;/h2&gt;

&lt;p&gt;If you feel confident with classes, objects, and methods, the natural next steps are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encapsulation and Access Modifiers&lt;/strong&gt; — understanding why fields are &lt;code&gt;private&lt;/code&gt; and what that protects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inheritance&lt;/strong&gt; — how one class can extend another to reuse and specialize behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spring Boot REST APIs&lt;/strong&gt; — applying these concepts in a real web application context&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>java</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
