오류, 기능, 문제해결(JAVA)

Class, System, Math, Random 클래스

seungmin576 2025. 1. 15. 14:17

Class 클래스

시작하기 앞서서 Class 클래스에 대한 정보는 이런게 있다 정도로만 알면된다. 나같은 왕초보입문 단계에서는 다른 내용을 배우는게 더 급하다.

 

클래스의 정보(메타데이터)를 다루는데 사용된다. Class 클래스를 통해 개발자는 실행 중인 자바 애플리케이션 내에서 필요한 클래스의 속성과 메서드에 대한 정보를 조회하고 조작할 수 있다.

 

주요기능은 다음과 같다.

  • 타입 정보 얻기 : 클래스의 이름, 슈퍼클래스, 인터페이스, 접근 제한자 등과 같은 정보를 조회할 수 있다.
  • 리플렉션 : 클래스에 정의된 메서드, 필드, 생성자 등을 조회하고, 이들을 통해 객체 인스턴스를 생성하거나 메서드를 호출하는 등의 작업을 할 수 있다.
  • 동적 로딩과 생성 : Class.forName() 메서드를 사용하여 클래스를 동적으로 로드하고, newInstance() 메서드를 통해 새로운 인스턴스를 생성할 수 있다.
  • 애노테이션 처리 : 클래스에 적용된 애노테이션(anntation)을 조회하고 처리하는 기능을 제공한다.

예시로 String.class 는 String 클래스에 대한 Class 객체를 나타내며, 이를 통해 String 클래스에 대한 메타데이터를 조회하거나 조작할 수 있다.

package lang.clazz;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ClassMetaMain {

    public static void main(String[] args) throws Exception{
        //Class 조회
        Class clazz = String.class; // 1. 클래스에서 조회
//        Class clazz1 = new String().getClass(); //2. 인스턴스에서 조회
//        Class clazz2 = Class.forName("java.lang.String");   //3. 문자열로 조회

        //모든 필드 출력
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println("field = " + field.getType() + " " + field.getName());
        }

        //모든 메서드 출력
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println("method = " + method);
        }

        //상위 클래스 출력
        System.out.println("superClass : " +clazz.getSuperclass().getName());
        
        //인터페이스 정보 출력
        Class[] interfaces = clazz.getInterfaces();
        for (Class i : interfaces) {
            System.out.println("Interfaces = " + i.getName());
        }
    }
}

class는 자바의 예약어이기에 패키지명, 변수명으로 사용할 수 없다.

이런 이유로 clazz 라는 이름을 관행으로 사용한다.

main 옆에 throws Exception은 예외 처리를 배워야 알 수 있다. 지금은 컴파일 오류를 피하기 위해 작성한다.

 

메소드 넘 많아서 중간은 자름

 

Class 클래스는 3가지 방법으로 조회할 수 있다.

Class clazz = String.class; // 1. 클래스에서 조회
Class clazz1 = new String().getClass(); //2. 인스턴스에서 조회
Class clazz2 = Class.forName("java.lang.String");   //3. 문자열로 조회 <- 이건 나중에 스캐너로 입력 받는 식으로 활용 가능

 

 

 

Class 클래스의 주요 기능

  • getDeclaredFields() : 클래스의 모든 필드를 조회한다.
  • getDeclaredMethods() : 클래스의 모든 메서드를 조회한다.
  • getSuperClass() : 클래스의 부모 클래스를 조회한다.
  • getInterFaces() : 클래스의 인터페이스들을 조회한다.

 

 

클래스 생성하기

Class 클래스에는 클래스의 모든 정보가 들어있다. 이 정보를 기반으로 인스턴스를 생성하거나, 메서드를 호출하고, 필드의 값도 변경할 수 있다. 여기선 간단하게 인스턴스를 생성한다.

package lang.clazz;

public class Hello {

    public String hello(){
        return "hello!";
    }
}



package lang.clazz;

public class ClassCreateMain {

    public static void main(String[] args) throws Exception{
        Class helloClass = Hello.class;
//        Class.forName("lang.clazz.Hello");

        Hello hello = (Hello) helloClass.getDeclaredConstructor().newInstance();
        String result = hello.hello();
        System.out.println("hello = " + hello);
        System.out.println("result = " + result);
    }
}

getDeclaredConstructor().getnewInstance()

  • getDeclaredConstructor() : 생성자를 선택한다.
  • newInstance() : 선택된 생성자를 기반으로 인스턴스를 생성한다.

 

 

리플렉션 - reflection

Class 를 사용하면 클래스의 메타 정보를 기반으로 클래스에 정의된 메서드, 필드, 생성자 등을 조회하고, 이들을 통해 객체 인스턴스를 생성하거나 메서드를 호출하는 작업을 할 수 있다. 이런 작업을 리플렉션이라 한다. 추가로 애노테이션 정보를 읽어서 특별한 기능을 수행할 수 도 있다. 최신 프레임워크들은 이런 기능을 적극 활용한다.


System 클래스

시스템과 관련된 기본 기능들을 제공한다.

package lang.system;

import java.util.Arrays;

public class SystemMain {

    public static void main(String[] args) {
        //현재 시간(밀리초) 가져옴
        long currentTimeMillis = System.currentTimeMillis();
        System.out.println("currentTimeMillis = " + currentTimeMillis);

        //현재 시간(나노초)를 가져옴
        long currentTimeNano = System.nanoTime();
        System.out.println("currentTimeNano = " + currentTimeNano);

        // 환경 변수를 읽는다.
        System.out.println("getenv = " + System.getenv());

        // 시스템 속성을 읽는다.
        System.out.println("properties = " + System.getProperties());
        System.out.println("Java version : " + System.getProperty("java.version"));

        //배열을 고속으로 복사한다.
        char[] originalArray = {'h', 'e', 'l', 'l', 'o'};
        char[] coppiedArray = new char[5];
        System.arraycopy(originalArray, 0, coppiedArray, 0, originalArray.length);
        System.out.println("coppiedArray = " + coppiedArray);
        System.out.println("coppiedArray = " + Arrays.toString(coppiedArray));

        //프로그램 종료
        System.exit(0);
        System.out.println("hello");
    }
}

  • 표준 입력, 출력, 오류 스트림 : System.in, System.out, System.err 는 각각 표준 입력, 표준 출력, 표준 오류 스트림을 나타낸다.
  • 시간 측정 : System.currentTimeMillis() 와 System.nanoTime()은 현재 시간을 밀리초 또는 나노초 단위로 제공한다.
  • 환경 변수 : System.getenv() 메서드를 사용하여 OS 에서 설정한 환경 변수의 값을 얻을 수 있다.
  • 시스템 속성 : System.getProperties() 를 사용해 현재 시스템 속정을 얻거나 System.getProperty(String key) 로 특정 속성을 얻을 수 있다. 시스템 속성은 자바에서 사용하는 설정 값이다.
  • 시스템 종료 : System.exit(int status) 메서드는 프로그램을 종료하고, OS에 프로그램 종료의 상태 코드를 전달한다.
    • 상태 코드 0 : 정상 종료
    • 상태 코드 0이 아님 : 오류나 예외적인 종료
  • 배열 고속 복사 : System.arraycopy 는 시스템 레벨에서 최적화된 메모리 복사 연산을 사용한다. 직접 반복문을 사용해서 배열을 복사할 때 보다 수 배 이상 빠른 성능을 제공한다.

Math, Random 클래스

Math 클래스

Math 는 수 많은 수학 문제를 해결해주는 클래스이다. 왕 많은 기능이 있기 때문에 검색하거나 API 문서를 찾아보자.

 

package lang.math;

public class MathMain {

    public static void main(String[] args) {
        //기본 연산 메서드
        System.out.println("max(10, 20) : " + Math.max(10, 20));
        System.out.println("min(10, 20) : " + Math.min(10, 20));
        System.out.println("abs(-10) : " + Math.abs(-10));//절대값

        //반올림 및 정밀도 메서드
        System.out.println("ceil(2.1) : " + Math.ceil(2.1));//올림
        System.out.println("floor(2.1) : " + Math.floor(2.1));//내림
        System.out.println("round(2.5) : " + Math.round(2.5));//반올림

        //기타 유용한 메서드
        System.out.println("sqrt(4) : " + Math.sqrt(4)); //제곱근
        System.out.println("random() : " + Math.random()); // 0.0 ~ 1.0 사이의 double 값
    }
}

정밀한 숫자와 반올림 계산이 필요하다면 BigDecimal을 이용하면 좋다.

 

 

Random 클래스

Math.random()을 사용해도 되지만 Random 클래스를 사용하면 더욱 다양한 랜덤값을 구할 수 있다.

Math.random() 도 내부에는 Random 클래스를 사용한다.

 

package lang.math;

import java.util.Random;

public class RandomMain {

    public static void main(String[] args) {
        Random random = new Random();
//        Random random = new Random(1);//seed가 같으면 Random의 결과가 같다

        int randomInt = random.nextInt();
        System.out.println("randomInt = " + randomInt);

        double randomDouble = random.nextDouble();
        System.out.println("randomDouble = " + randomDouble);

        boolean randomBoolean = random.nextBoolean();
        System.out.println("randomBoolean = " + randomBoolean);

        // 범위 조회
        int randomRange1 = random.nextInt(10);
        System.out.println("0 ~ 9: = " + randomRange1);

        int randomRange2 = random.nextInt(10) + 1;
        System.out.println("1 ~ 10 : = " + randomRange2);
    }
}

  • nextInt() : 랜덤 int 값을 반환한다.
  • nextDouble() : 0.0d ~ 1.0d 사이의 랜덤 double 값을 반환한다.
  • nextBoolean() : 랜덤 boolean 값을 반환한다.
  • nextInt(int bound) : 0 ~ bound 미만의 숫자를 랜덤으로 반환한다.
    • 1부터 특정 숫자의 int 범위를 구하는 경우는 nextInt(int bound)의 결과에 +1 을 하면 된다.

 

씨드 - Seed

랜덤은 내부에서 씨드 값을 사용해서 랜덤 값을 구한다. 그런데 이 씨드 값이 같으면 항상 같은 결과가 출력된다.

Random random = new Random(1);//seed가 같으면 Random의 결과가 같다

  • new Random() : 생성자를 비워두면 내부에서 System.nanoTime() 에 여러가지 복잡한 알고리즘을 섞어서 씨드값을 생성한다. 따라서 반복 실행해도 결과가 항상 달라진다.
  • new Random(int seed) : 생성자에 씨드 값을 직접 전달할 수 있다. 씨드 값이 같으면 여러번 반복 실행해도 실행 결과가 같다. 이렇게 씨드 값을 직접 사용하면 결과 값이 항상 같기 때문에 결과가 달라지는 랜덤 값을 구할 수 없다. 하지만 결과가 고정되기 때문에 테스트 코드 같은 곳에서 같은 결과를 검증할 수 있다.