[Java] 기본 API 클래스 ③

kiteB·2022년 2월 2일
0

Java

목록 보기
30/35
post-thumbnail

[ System 클래스 ]

자바 프로그램은 운영체제상에서 바로 실행되는 것이 아니라 JVM 위에서 실행되기 때문에 운영체제의 모든 기능을 자바 코드로 직접 접근하기는 어렵다. 하지만 java.lang 패키지에 속하는 System 클래스를 이용하면 운영체제의 일부 기능을 이용할 수 있다.
Ex) 프로그램 종료, 키보드로부터 입력, 모니터로 출력, 메모리 정리, 현재 시간 읽기, 시스템 프로퍼티 읽기, 환경 변수 읽기 등

System 클래스의 모든 필드와 메소드는 정적(static) 필드와 정적 메소드로 구성되어 있다.


1. 프로그램 종료 ( exit() )

exit() 메소드는 현재 실행하고 있는 프로세스를 강제 종료시키는 역할을 한다.

exit() 메소드는 int 매개값을 지정하도록 되어 있는데, 이 값을 종료 상태값이라고 한다.
일반적으로 정상 종료일 경우 0으로 지정하며, 비정상 종료일 경우 0 이외의 다른 값을 준다.

System.exit(0);

2. 쓰레기 수집기 실행 ( gc() )

자바는 개발자가 메모리를 직접 코드로 관리하지 않고 JVM이 알아서 자동으로 관리한다. JVM은 메모리가 부족할 때와 CPU가 한가할 때에 쓰레기 수집기 Garbage Collector를 실행시켜 사용하지 않는 객체를 자동으로 제거한다.

다음과 같이 new 연산자로 Car 객체를 생성하고 변수 myCar에 객체 번지를 대입했다고 가정하자.

Car myCar = new Car();

만약 변수 myCarnull을 대입하면, myCar는 객체의 번지를 잃게 된다. 객체의 번지를 모르니, 더 이상 Car 객체는 사용할 수가 없고 이제부터 쓰레기가 된다.

myCar = null;

변수 myCar가 다른 Car 객체를 참조할 경우도 마찬가지로, 이전 객체의 번지를 잃기 때문에 이전 객체는 쓰레기가 된다.

Car myCar = new Car();	//이전 참조 객체
myCar = new Car();	//현재 참조 객체

쓰레기 수집기는 개발자가 직접 코드로 실행시킬 수 없고, System.gc() 메소드를 통해 JVM에게 가능한한 빨리 실행해달라고 요청할 수는 있다. System.gc() 메소드가 호출되면 쓰레기 수집기가 바로 실행되는 것은 아니고, JVM은 빠른 시간 내에 실행시키기 위해 노력한다.

System.gc();

쓰레기가 생길 때마다 쓰레기 수집기가 동작한다면 정작 수행되어야 할 프로그램의 속도가 떨어지기 때문에 성능 측면에서 좋지 않다. 그리고 메모리가 충분하다면 쓰레기 수집기를 실행할 필요가 없다. 그렇기 때문에 gc() 메소드는 메모리가 열악하지 않은 환경이라면 거의 사용할 일이 없다.

쓰레기 수집기는 객체를 삭제하기 전에 마지막으로 객체의 소멸자를 실행한다.


3. 현재 시각 읽기 ( currentTimeMillis(), nanoTime() )

System 클래스의 currentTimeMillis() 메소드와 nanoTime() 메소드는
컴퓨터의 시계로부터 현재 시간을 읽어서 밀리세컨드(1/1000초) 단위나노세컨드(1/10^9)초 단위long 값을 리턴한다.

long time = System.currentTimeMillis();
long time = System.nanoTime();

리턴값은 주로 프로그램의 실행 소요 시간 측정에 사용된다.


4. 시스템 프로퍼티 읽기 ( getProperty() )

시스템 프로퍼티(System Property)는 JVM이 시작될 때 자동으로 설정되는 시스템의 속성값을 말한다.

Ex) 운영체제의 종류 및 자바 프로그램을 실행시킨 사용자 아이디, JVM의 버전, 운영체제에서 사용되는 파일 경로 구분자 등

시스템 프로퍼티는 키(key)와 값(value)으로 구성되어 있다. 대표적인 키와 값에 대한 설명은 다음과 같다.

시스템 프로퍼티를 읽어오기 위해서는 System.getProperty() 메소드를 이용하면 된다. 이 메소드는 시스템 프로퍼티의 키 이름을 매개값으로 받고, 해당 키에 대한 값을 문자열로 리턴한다.

String value = System.getProperty(String key);

+) System.getProperties() 메소드는 모든 (키, 값) 쌍을 저장하고 있는 Properties 객체를 리턴한다.
이 객체의 keySet() 메소드를 호출하면 키만으로 구성된 Set 객체를 얻을 수 있다.


[ Class 클래스 ]

자바는 클래스와 인터페이스의 메타 데이터를 java.lang 패키지에 소속된 Class 클래스로 관리한다.

✅ 메타 데이터: 클래스의 이름, 생성자 정보, 필드 정보, 메소드 정보


1. Class 객체 얻기 ( getClass(), forName() )

프로그램에서 Class 객체를 얻기 위해서는 다음과 같이 Object 클래스가 가지고 있는 getClass() 메소드를 이용하면 된다.

Class clazz = obj.getClass();

getClass() 메소드는 해당 클래스로 객체를 생성했을 때만 사용할 수 있는데, 객체를 생성하기 전에 직접 Class 객체를 얻을 수도 있다. Class는 생성자를 감추고 있기 때문에 new 연산자로 객체를 만들 수 없고, 정적 메소드인 forName()을 이용해야 한다. forName() 메소드는 클래스 전체 이름(패키지가 포함된 이름)을 매개값으로 받고 Class 객체를 리턴한다.

try {
    Class clazz = Class.forName(String className);
} catch (ClassNotFoundExcetion e) {
}

Class.forName() 메소드는 매개값으로 주어진 클래스를 찾지 못하면 ClassNotFoundException 예외를 발생시키기 때문에 예외 처리가 필요하다.


2. 리플렉션 ( getDeclaredConstructors(), getDeclaredFields(), getDeclaredMethods() )

리플렉션(Reflection)이란 Class 객체를 이용하여 클래스의 정보(생성자, 필드, 메소드)를 알아내는 것을 말한다.

Class 객체는 리플렉션을 위해 getDeclaredConstructors(), getDeclaredFields(), getDeclaredMethods()를 제공하고 있다.

Constructor[] constructors = clazz.getDeclaredConstructors();
Field [] fields = clazz.getDeclaredFields();
Method[] methods = clazz.getDeclaredMethods();

메소드 이름에서 알 수 있듯이 세 메소드는 각각 Contstructor 배열, Field 배열, Method 배열을 리턴한다.

  • Contstructor, Field, Method 클래스는 모두 java.lang.reflect 패키지에 소속되어 있다.
  • getDeclaredFields(), getDeclaredMethods()는 클래스에 선언된 멤버만 가져오고 상속된 멤버는 가져오지 않는다.
  • 만약 상속된 멤버도 얻고 싶다면 getFields(), getMethods()를 사용해야 한다.
    • 단, getFields(), getMethods()public 멤버만 가져온다.

3. 동적 객체 생성 ( newInstance() )

Class 객체를 이용하면 new 연산자를 사용하지 않아도 동적으로 객체를 생성할 수 있다. 이 방법은 코드 작성 시에 클래스 이름을 결정할 수 없고, 런타임 시에 클래스 이름이 결정되는 경우에 매우 유용하게 사용된다.

다음 코드처럼 Class.forName() 메소드로 Class 객체를 얻은 다음 newInstance() 메소드를 호출하면 Object 타입의 객체를 얻을 수 있다.

try {
    Class clazz = Class.forName("런타임 시 결정되는 클래스 이름");
    Object obj = clazz.newInstance();
} catch (ClassNotFoundException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
}

newInstance() 메소드는 기본 생성자를 호출해서 객체를 생성하기 때문에 반드시 클래스에 기본 생성자가 존재해야 한다. 만약 매개 변수가 있는 생성자를 호출하고 싶다면 리플렉션으로 Constructor 객체를 얻어 newInstance() 메소드를 호출하면 된다.

newInstance() 메소드는 두 가지 예외가 발생할 수 있기 때문에 예외 처리 코드가 필요하다.

  • InstantiationException 예외: 해당 클래스가 추상 클래스이거나 인터페이스일 경우에 발생
  • IllegalAccessException 예외: 클래스나 생성자가 접근 제한자로 인해 접근할 수 없을 경우에 발생

newInstance() 메소드의 리턴 타입은 Object이므로 이것을 클래스 타입으로 변환해야만 메소드를 사용할 수 있다. 이를 위해서는 강제 타입 변환을 해야 하는데, 클래스 타입을 모르는 상태이므로 변환을 할 수가 없다. 이 문제를 해결하려면 인터페이스 사용이 필요하다.

예제

예를 들어 Action 인터페이스와 구현 클래스인 SendAction, ReceiveAction이 있다고 가정해보자.

Class.forName() 메소드의 매개값으로 "SendAction" 또는 "ReceiveAction"을 주면 Class 객체가 만들어지고, Class 객체의 newInstance() 메소드로 Object 객체를 얻을 수 있다. 얻어진 객체는 모두 Actioon 인터페이스를 구현하고 있기 때문에 다음과 같이 Action 인터페이스 타입으로 변환이 가능하다. 그런 다음, Action 인터페이스의 execute() 메소드를 호출하면, 개별 클래스의 실체 메소드인 execute() 메소드가 실행된다.

Class clazz = Class.forName("SendAction" 또는 "ReceiveAction");
Action action = (Action) clazz.newInstance();
action.execute();	//SendAction 또는 ReceiveAction의 execute()가 실행됨

Class.forName() 메소드의 매개값으로 "SendAction" 문자열을 주었다면 SendAction 클래스의 execute() 메소드가 호출되고, 매개값으로 "ReceiveAction" 문자열을 주었다면 ReceiveAction 클래스의 execute() 메소드가 호출된다.


[ 참고자료 ]

이것이 자바다 책

profile
🚧 https://coji.tistory.com/ 🏠

0개의 댓글