Java 코드 컴파일 및 실행 시 'class not found' 오류 해결 방법

JavaBeginner
지금 연습하기

소개

Java 를 사용할 때 개발자들이 가장 흔하게 겪는 좌절 중 하나는 'class not found' 오류입니다. 이 오류는 Java Virtual Machine (JVM) 이 프로그램 실행에 필요한 클래스를 찾을 수 없을 때 발생합니다. 초보자이든 Java 경험이 있는 개발자이든, 이 오류를 진단하고 해결하는 방법을 이해하는 것은 원활한 개발을 위해 필수적입니다.

이 Lab 에서는 'class not found' 오류의 원인, 코드에서 특정 문제를 식별하는 방법, 그리고 이를 해결하기 위한 효과적인 솔루션을 구현하는 방법을 배우게 됩니다. 이 세션을 마치면 Java 프로그래밍에서 이 흔한 장애물을 극복할 수 있는 지식과 실질적인 경험을 갖게 될 것입니다.

Java Class Path 및 패키지 구조 이해

오류 자체에 들어가기 전에, Java 가 클래스를 어떻게 구성하고 찾는지를 이해해 봅시다. 이 기본 지식은 'class not found' 오류를 더 잘 진단하는 데 도움이 될 것입니다.

Java Class Path (클래스 경로)

클래스 경로는 Java Virtual Machine (JVM) 에게 클래스와 패키지를 어디에서 찾아야 하는지 알려주는 매개변수입니다. Java 프로그램을 실행할 때 JVM 은 다음 위치에서 클래스를 검색합니다.

  1. 현재 디렉토리
  2. 클래스 경로에 지정된 JAR 파일
  3. 표준 Java 라이브러리

간단한 Java 프로그램 만들기

Java 가 코드를 컴파일하고 실행하는 방식을 이해하기 위해 간단한 Java 프로그램을 만들어 보겠습니다.

  1. WebIDE 를 열고 /home/labex/project 디렉토리에 HelloWorld.java라는 새 파일을 만듭니다.

  2. 파일에 다음 코드를 추가합니다.

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}
  1. 터미널을 열고 프로젝트 디렉토리에 있는지 확인합니다.
cd ~/project
  1. javac 명령을 사용하여 Java 프로그램을 컴파일합니다.
javac HelloWorld.java
  1. java 명령을 사용하여 프로그램을 실행합니다.
java HelloWorld

다음 출력을 볼 수 있습니다.

Hello, World!

컴파일 과정 이해

javac 명령을 실행하면 HelloWorld.class라는 파일이 생성됩니다. 이 파일에는 JVM 이 실행할 수 있는 바이트코드가 포함되어 있습니다. java 명령을 실행하면 JVM 은 현재 디렉토리에서 이 클래스 파일을 찾아 실행합니다.

이 간단한 프로그램의 성공적인 실행은 Java 의 기본적인 컴파일 및 실행 프로세스를 보여줍니다. 다음으로, 클래스를 찾을 수 없을 때 어떤 일이 발생하는지 이해하기 위해 의도적으로 오류를 생성해 보겠습니다.

'Class Not Found' 오류 발생 및 이해

이제 Java 컴파일 및 실행의 기본 사항을 이해했으므로, 'class not found' 오류가 발생하는 상황을 의도적으로 만들어 보겠습니다. 이를 통해 오류를 인식하고 그 원인을 이해하는 데 도움이 될 것입니다.

누락된 클래스가 있는 프로그램 만들기

  1. /home/labex/project 디렉토리에 다음 코드를 사용하여 MainProgram.java라는 새 파일을 만듭니다.
public class MainProgram {
    public static void main(String[] args) {
        // Try to use a class that doesn't exist yet
        Helper helper = new Helper();
        helper.doSomething();
    }
}
  1. javac 명령을 사용하여 이 프로그램을 컴파일합니다.
javac MainProgram.java

다음과 유사한 오류가 표시됩니다.

MainProgram.java:4: error: cannot find symbol
        Helper helper = new Helper();
        ^
  symbol:   class Helper
  location: class MainProgram

이 오류는 Java 컴파일러가 Helper 클래스를 찾을 수 없기 때문에 컴파일 시간에 발생합니다. 누락된 클래스를 만들어 이 문제를 해결해 보겠습니다.

누락된 클래스 만들기

  1. 동일한 디렉토리에 다음 코드를 사용하여 Helper.java라는 새 파일을 만듭니다.
public class Helper {
    public void doSomething() {
        System.out.println("Helper is doing something useful!");
    }
}
  1. 이제 두 파일을 모두 컴파일합니다.
javac MainProgram.java Helper.java
  1. MainProgram 클래스를 실행합니다.
java MainProgram

다음 출력을 볼 수 있습니다.

Helper is doing something useful!

런타임 'Class Not Found' 오류 이해

이전에 발생한 오류는 컴파일 시간 오류였습니다. 이제 런타임 'class not found' 오류가 발생하는 시나리오를 만들어 보겠습니다.

  1. 다음 코드를 사용하여 DynamicLoader.java라는 새 파일을 만듭니다.
public class DynamicLoader {
    public static void main(String[] args) {
        try {
            // Try to dynamically load a class that doesn't exist
            Class.forName("NonExistentClass");
            System.out.println("Class loaded successfully!");
        } catch (ClassNotFoundException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}
  1. 이 프로그램을 컴파일하고 실행합니다.
javac DynamicLoader.java
java DynamicLoader

다음 출력을 볼 수 있습니다.

Error: NonExistentClass

이것은 try-catch 블록에 의해 잡히는 런타임 'class not found' 오류를 보여줍니다. 실제 애플리케이션에서는 다음과 같은 경우에 이 유형의 오류가 자주 발생합니다.

  • 클래스가 존재하지만 클래스 경로에 없는 경우
  • 클래스 이름의 철자가 틀리거나 대소문자가 잘못된 경우
  • 클래스가 패키지에 있지만 패키지 구조가 잘못된 경우

Java 패키지 및 Class Path (클래스 경로) 작업

대부분의 실제 Java 애플리케이션은 클래스를 패키지로 구성합니다. 이 구성은 패키지 구조가 올바르게 설정되지 않거나 클래스 경로가 제대로 구성되지 않은 경우 'class not found' 오류로 이어질 수 있습니다.

패키지 구조 만들기

  1. 패키지용 디렉토리 구조를 만듭니다.
mkdir -p ~/project/com/example/util
  1. ~/project/com/example/util 디렉토리에 StringUtils.java라는 새 파일을 만듭니다.
package com.example.util;

public class StringUtils {
    public static String reverse(String input) {
        StringBuilder reversed = new StringBuilder();
        for (int i = input.length() - 1; i >= 0; i--) {
            reversed.append(input.charAt(i));
        }
        return reversed.toString();
    }
}

파일 상단의 package 선언에 유의하십시오. 이는 Java 에게 이 클래스가 com.example.util 패키지에 속한다는 것을 알려줍니다.

  1. 이제 ~/project 디렉토리에 PackageDemo.java라는 파일을 만듭니다.
import com.example.util.StringUtils;

public class PackageDemo {
    public static void main(String[] args) {
        String original = "Hello, Java!";
        String reversed = StringUtils.reverse(original);

        System.out.println("Original: " + original);
        System.out.println("Reversed: " + reversed);
    }
}
  1. 프로젝트 디렉토리에서 두 파일을 모두 컴파일합니다.
cd ~/project
javac com/example/util/StringUtils.java
javac PackageDemo.java
  1. PackageDemo 클래스를 실행합니다.
java PackageDemo

다음 출력을 볼 수 있습니다.

Original: Hello, Java!
Reversed: !avaJ ,olleH

일반적인 패키지 관련 오류 문제 해결

문제 해결 방법을 배우기 위해 의도적으로 몇 가지 일반적인 오류를 만들어 보겠습니다.

오류 1: 잘못된 패키지 디렉토리 구조

  1. 패키지 선언이 디렉토리 구조와 일치하지 않는 새 디렉토리와 Java 파일을 만듭니다.
mkdir -p ~/project/wrong/path
  1. ~/project/wrong/path 디렉토리에 MisplacedClass.java라는 파일을 만듭니다.
package correct.path;

public class MisplacedClass {
    public static void sayHello() {
        System.out.println("Hello from MisplacedClass!");
    }
}
  1. 이 파일을 컴파일해 봅니다.
cd ~/project
javac wrong/path/MisplacedClass.java

다음과 유사한 오류가 표시됩니다.

wrong/path/MisplacedClass.java:1: error: package correct.path does not exist
package correct.path;
^

이 오류는 패키지 선언 (package correct.path;) 이 디렉토리 구조 (wrong/path) 와 일치하지 않기 때문에 발생합니다.

오류 2: 누락된 Import (import) 문

  1. ~/project 디렉토리에 ImportDemo.java라는 파일을 만듭니다.
// Missing import: import com.example.util.StringUtils;

public class ImportDemo {
    public static void main(String[] args) {
        // This will cause an error because StringUtils is not imported
        String reversed = StringUtils.reverse("Test");
        System.out.println(reversed);
    }
}
  1. 이 파일을 컴파일해 봅니다.
javac ImportDemo.java

다음과 유사한 오류가 표시됩니다.

ImportDemo.java:5: error: cannot find symbol
        String reversed = StringUtils.reverse("Test");
                          ^
  symbol:   variable StringUtils
  location: class ImportDemo

이 오류는 StringUtils 클래스를 가져오지 않았기 때문에 발생합니다. 이 문제를 해결하려면 import 문을 추가합니다.

import com.example.util.StringUtils;

Java 의 패키지 시스템과 클래스 경로에 대한 올바른 이해는 'class not found' 오류를 방지하고 수정하는 데 필수적입니다. 항상 패키지 선언이 디렉토리 구조와 일치하고 필요한 모든 클래스가 제대로 import 되었는지 확인하십시오.

외부 JAR 파일 사용 및 Classpath (클래스 경로) 설정

많은 Java 애플리케이션은 JAR (Java ARchive) 파일로 배포되는 외부 라이브러리에 의존합니다. 이러한 JAR 파일이 클래스 경로에 제대로 포함되지 않으면, 이러한 라이브러리의 클래스를 사용하려고 할 때 'class not found' 오류가 발생합니다.

사용자 정의 JAR 파일 만들기

외부 라이브러리가 작동하는 방식을 이해하기 위해 간단한 JAR 파일을 만들어 보겠습니다.

  1. 먼저, 앞서 만든 StringUtils 클래스를 컴파일합니다.
cd ~/project
javac com/example/util/StringUtils.java
  1. 이 클래스를 포함하는 JAR 파일을 만듭니다.
jar cf utils.jar com/example/util/StringUtils.class
  1. JAR 파일이 생성되었는지 확인합니다.
ls -l utils.jar

다음과 유사한 출력을 볼 수 있습니다.

-rw-r--r-- 1 labex labex 1234 Jan 1 12:34 utils.jar
  1. 이제 이 JAR 파일을 사용할 새 프로그램을 만들어 보겠습니다. ~/project 디렉토리에 JarDemo.java라는 파일을 만듭니다.
public class JarDemo {
    public static void main(String[] args) {
        try {
            // Try to use a class from our JAR file
            Class<?> clazz = Class.forName("com.example.util.StringUtils");
            System.out.println("Successfully loaded: " + clazz.getName());
        } catch (ClassNotFoundException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}
  1. 이 프로그램을 컴파일합니다.
javac JarDemo.java
  1. 클래스 경로를 지정하지 않고 프로그램을 실행합니다.
java JarDemo

다음 출력을 볼 수 있습니다.

Error: com.example.util.StringUtils

이것은 JVM 이 StringUtils 클래스를 찾을 수 없기 때문에 발생하는 'class not found' 오류입니다. 클래스는 JAR 파일에 있지만, JVM 에게 어디에서 찾아야 하는지 알려주지 않았습니다.

Classpath (클래스 경로) 설정

오류를 해결하려면 JAR 파일을 클래스 경로에 포함해야 합니다.

  1. -classpath 옵션을 사용하여 프로그램을 실행합니다.
java -classpath .:utils.jar JarDemo

이제 다음 출력을 볼 수 있습니다.

Successfully loaded: com.example.util.StringUtils

클래스 경로 구문을 자세히 살펴보겠습니다.

  • .은 현재 디렉토리 ( JarDemo.class를 찾기 위해) 를 의미합니다.
  • :는 Linux/Mac에서 서로 다른 클래스 경로 항목의 구분 기호입니다 (Windows 에서는 ; 사용).
  • utils.jar는 우리의 JAR 파일입니다.

외부 라이브러리 사용

공개 Maven (메이븐) 저장소에서 외부 라이브러리를 사용해 보겠습니다.

  1. 간단하고 가벼운 JSON 라이브러리를 다운로드합니다.
cd ~/project
wget https://repo1.maven.org/maven2/org/json/json/20230618/json-20230618.jar
  1. 이 라이브러리를 사용하는 프로그램을 만듭니다. JsonDemo.java라는 파일을 만듭니다.
import org.json.JSONObject;

public class JsonDemo {
    public static void main(String[] args) {
        // Create a JSON object
        JSONObject json = new JSONObject();
        json.put("name", "Java Student");
        json.put("age", 25);
        json.put("city", "Codeville");

        // Print the JSON object
        System.out.println(json.toString(2));
    }
}
  1. 클래스 경로에 JSON 라이브러리를 포함하여 이 프로그램을 컴파일합니다.
javac -classpath .:json-20230618.jar JsonDemo.java
  1. 클래스 경로에 JSON 라이브러리를 포함하여 프로그램을 실행합니다.
java -classpath .:json-20230618.jar JsonDemo

다음과 유사한 출력을 볼 수 있습니다.

{
  "name": "Java Student",
  "age": 25,
  "city": "Codeville"
}

CLASSPATH 환경 변수 설정

각 명령으로 클래스 경로를 지정하는 대신, CLASSPATH 환경 변수를 설정할 수 있습니다.

export CLASSPATH=.:utils.jar:json-20230618.jar

이제 클래스 경로를 지정하지 않고 프로그램을 실행할 수 있습니다.

java JsonDemo

이전과 동일한 출력을 생성해야 합니다.

CLASSPATH 환경 변수를 사용할 때는 다음 사항을 기억하십시오.

  • 현재 셸 세션에서 실행되는 모든 Java 프로그램에 영향을 미칩니다.
  • 명령줄에서 -classpath를 지정하면 재정의됩니다.
  • 터미널을 닫으면 설정이 손실됩니다 (시작 스크립트에 추가하지 않는 한).

외부 라이브러리를 올바르게 사용하고 클래스 경로를 설정하는 방법을 이해하는 것은 실제 Java 애플리케이션에서 'class not found' 오류를 방지하는 데 매우 중요합니다.

일반적인 'Class Not Found' 시나리오 및 해결 방법

Java 클래스 경로 및 패키지 시스템의 기본 사항을 이해했으므로, 'class not found' 오류로 이어지는 몇 가지 일반적인 시나리오와 이를 해결하는 방법을 살펴보겠습니다.

시나리오 1: 클래스 이름 오타

'class not found' 오류의 가장 일반적인 원인 중 하나는 클래스 이름을 잘못 입력하는 것입니다. 이를 시연해 보겠습니다.

  1. ~/project 디렉토리에 TypoDemo.java라는 파일을 만듭니다.
import java.util.Scanner;  // Correct import
// import java.util.scanner;  // Incorrect import (lowercase 's')

public class TypoDemo {
    public static void main(String[] args) {
        // Scanner scanner = new scanner(System.in);  // Incorrect (lowercase 's')
        Scanner scanner = new Scanner(System.in);  // Correct

        System.out.print("Enter your name: ");
        String name = scanner.nextLine();
        System.out.println("Hello, " + name + "!");

        scanner.close();
    }
}
  1. 이 프로그램을 컴파일하고 실행합니다.
javac TypoDemo.java
java TypoDemo
  1. 메시지가 표시되면 이름을 입력하고 Enter 키를 누릅니다. 인사가 표시됩니다.

잘못된 import 를 주석 해제하고 올바른 import 를 주석 처리하면 컴파일 시간 오류가 발생합니다. Java 는 대소문자를 구분하므로 Scannerscanner는 서로 다른 클래스입니다.

시나리오 2: 종속 클래스 컴파일을 잊어버린 경우

변경 후 종속 클래스를 다시 컴파일하는 것을 잊어버리는 것도 흔한 시나리오입니다.

  1. 앞서 만든 Helper.java 파일을 업데이트합니다.
public class Helper {
    public void doSomething() {
        System.out.println("Helper is doing something useful!");
    }

    // Add a new method
    public void doSomethingElse() {
        System.out.println("Helper is doing something else!");
    }
}
  1. DependencyDemo.java라는 새 파일을 만듭니다.
public class DependencyDemo {
    public static void main(String[] args) {
        Helper helper = new Helper();
        helper.doSomething();
        helper.doSomethingElse();
    }
}
  1. 이 파일들을 컴파일하고 실행합니다.
javac Helper.java
javac DependencyDemo.java
java DependencyDemo

Helper 클래스에서 두 메시지를 모두 볼 수 있습니다.

  1. 이제 변경 후 다시 컴파일하지 않으면 어떻게 되는지 살펴보겠습니다. Helper.java를 다시 업데이트합니다.
public class Helper {
    public void doSomething() {
        System.out.println("Helper is doing something useful!");
    }

    public void doSomethingElse() {
        System.out.println("Helper is doing something else!");
    }

    // Add another new method
    public void doAnotherThing() {
        System.out.println("Helper is doing another thing!");
    }
}
  1. Helper.java를 다시 컴파일하지 않고 DependencyDemo.java를 업데이트합니다.
public class DependencyDemo {
    public static void main(String[] args) {
        Helper helper = new Helper();
        helper.doSomething();
        helper.doSomethingElse();
        helper.doAnotherThing();  // This will cause an error
    }
}
  1. 컴파일하고 실행해 봅니다.
javac DependencyDemo.java
java DependencyDemo

Helper 클래스에 추가했음에도 불구하고 doAnotherThing() 메서드가 존재하지 않는다는 컴파일 시간 오류가 발생합니다. 이는 변경 후 Helper.java를 다시 컴파일하지 않았기 때문입니다.

  1. 이 문제를 해결하려면 두 파일을 모두 다시 컴파일합니다.
javac Helper.java
javac DependencyDemo.java
java DependencyDemo

이제 모든 것이 제대로 작동해야 합니다.

시나리오 3: JDBC 드라이버 누락

실제 애플리케이션에서 흔히 발생하는 'class not found' 오류는 데이터베이스 연결과 관련됩니다. JDBC (Java Database Connectivity) 를 사용할 때는 데이터베이스에 적합한 드라이버가 필요합니다. 이를 시뮬레이션해 보겠습니다.

  1. JdbcDemo.java라는 파일을 만듭니다.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class JdbcDemo {
    public static void main(String[] args) {
        try {
            // This will cause a ClassNotFoundException
            Class.forName("com.mysql.jdbc.Driver");

            // We won't actually connect to a database in this example
            System.out.println("Driver loaded successfully!");

            // In a real application, you would connect like this:
            // Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "username", "password");

        } catch (ClassNotFoundException e) {
            System.out.println("Error: JDBC Driver not found - " + e.getMessage());
            System.out.println("Solution: Add the MySQL JDBC driver to your classpath");
        }
    }
}
  1. 이 프로그램을 컴파일하고 실행합니다.
javac JdbcDemo.java
java JdbcDemo

다음 오류 메시지가 표시됩니다.

Error: JDBC Driver not found - com.mysql.jdbc.Driver
Solution: Add the MySQL JDBC driver to your classpath

실제 애플리케이션에서는 적절한 JDBC 드라이버 JAR 파일을 다운로드하여 클래스 경로에 추가해야 합니다.

해결 방법 요약

'class not found' 오류를 해결하기 위한 빠른 참조 가이드입니다.

  1. 철자와 대소문자 확인: Java 는 대소문자를 구분합니다.
  2. 패키지 구조 확인: 패키지가 디렉토리 구조와 일치하는지 확인합니다.
  3. 종속 클래스 다시 컴파일: 클래스를 변경한 후에는 해당 클래스와 모든 종속 클래스를 다시 컴파일합니다.
  4. 클래스 경로를 올바르게 설정: 필요한 모든 디렉토리와 JAR 파일을 포함합니다.
  5. IDE 사용: IntelliJ IDEA 또는 Eclipse 와 같은 최신 IDE 는 이러한 작업의 많은 부분을 자동화합니다.
  6. 빌드 도구 사용: Maven 또는 Gradle 은 종속성을 관리할 수 있습니다.

이러한 일반적인 시나리오와 해결 방법을 이해하면 Java 애플리케이션에서 'class not found' 오류를 진단하고 수정하는 데 필요한 모든 것을 갖추게 됩니다.

요약

이 Lab 에서는 Java 에서 흔히 발생하는 'class not found' 오류를 진단하고 해결하는 방법을 배웠습니다. 이제 다음 사항을 이해하게 되었습니다.

  • Java 클래스 경로가 어떻게 작동하고 왜 중요한지
  • Java 패키지 구조가 디렉토리 구조와 어떻게 관련되는지
  • 'class not found' 오류의 일반적인 원인, 다음을 포함합니다.
    • 클래스 이름의 오타
    • import 문 누락
    • 잘못된 패키지 선언
    • 종속 클래스를 다시 컴파일하는 것을 잊어버린 경우
    • 클래스 경로에 JAR 파일이 없는 경우

또한 이러한 문제에 대한 실용적인 해결 방법을 배웠습니다.

  • -classpath 옵션을 사용하여 클래스 경로 설정
  • CLASSPATH 환경 변수 사용
  • JAR 파일 및 외부 라이브러리 사용
  • Java 패키지를 적절하게 구성

이러한 지식을 갖추면 Java 애플리케이션에서 'class not found' 오류를 자신 있게 해결하고, 개발 중 시간을 절약하며 좌절감을 줄일 수 있습니다.

Java 개발에 능숙해지려면 연습이 중요하다는 것을 기억하십시오. 더 복잡한 프로젝트를 만들고 다양한 유형의 오류를 의도적으로 도입하여 디버깅 기술을 향상시키십시오.