System
클래스 ]자바 프로그램은 운영체제상에서 바로 실행되는 것이 아니라 JVM 위에서 실행되기 때문에 운영체제의 모든 기능을 자바 코드로 직접 접근하기는 어렵다. 하지만 java.lang
패키지에 속하는 System
클래스를 이용하면 운영체제의 일부 기능을 이용할 수 있다.
Ex) 프로그램 종료, 키보드로부터 입력, 모니터로 출력, 메모리 정리, 현재 시간 읽기, 시스템 프로퍼티 읽기, 환경 변수 읽기 등
System
클래스의 모든 필드와 메소드는 정적(static
) 필드와 정적 메소드로 구성되어 있다.
exit()
)
exit()
메소드는 현재 실행하고 있는 프로세스를 강제 종료시키는 역할을 한다.
exit()
메소드는 int
매개값을 지정하도록 되어 있는데, 이 값을 종료 상태값이라고 한다.
일반적으로 정상 종료일 경우 0
으로 지정하며, 비정상 종료일 경우 0 이외의 다른 값
을 준다.
System.exit(0);
gc()
)자바는 개발자가 메모리를 직접 코드로 관리하지 않고 JVM이 알아서 자동으로 관리한다. JVM은 메모리가 부족할 때와 CPU가 한가할 때에 쓰레기 수집기 Garbage Collector
를 실행시켜 사용하지 않는 객체를 자동으로 제거한다.
다음과 같이 new
연산자로 Car
객체를 생성하고 변수 myCar
에 객체 번지를 대입했다고 가정하자.
Car myCar = new Car();
만약 변수 myCar
에 null
을 대입하면, myCar
는 객체의 번지를 잃게 된다. 객체의 번지를 모르니, 더 이상 Car
객체는 사용할 수가 없고 이제부터 쓰레기가 된다.
myCar = null;
변수 myCar
가 다른 Car
객체를 참조할 경우도 마찬가지로, 이전 객체의 번지를 잃기 때문에 이전 객체는 쓰레기가 된다.
Car myCar = new Car(); //이전 참조 객체
myCar = new Car(); //현재 참조 객체
쓰레기 수집기는 개발자가 직접 코드로 실행시킬 수 없고, System.gc()
메소드를 통해 JVM에게 가능한한 빨리 실행해달라고 요청할 수는 있다. System.gc()
메소드가 호출되면 쓰레기 수집기가 바로 실행되는 것은 아니고, JVM은 빠른 시간 내에 실행시키기 위해 노력한다.
System.gc();
쓰레기가 생길 때마다 쓰레기 수집기가 동작한다면 정작 수행되어야 할 프로그램의 속도가 떨어지기 때문에 성능 측면에서 좋지 않다. 그리고 메모리가 충분하다면 쓰레기 수집기를 실행할 필요가 없다. 그렇기 때문에 gc()
메소드는 메모리가 열악하지 않은 환경이라면 거의 사용할 일이 없다.
쓰레기 수집기는 객체를 삭제하기 전에 마지막으로 객체의 소멸자를 실행한다.
currentTimeMillis(), nanoTime()
)
System
클래스의currentTimeMillis()
메소드와nanoTime()
메소드는
컴퓨터의 시계로부터 현재 시간을 읽어서밀리세컨드(1/1000초) 단위
와나노세컨드(1/10^9)초 단위
의long
값을 리턴한다.
long time = System.currentTimeMillis();
long time = System.nanoTime();
리턴값은 주로 프로그램의 실행 소요 시간 측정에 사용된다.
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
클래스로 관리한다.
✅ 메타 데이터: 클래스의 이름, 생성자 정보, 필드 정보, 메소드 정보
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
예외를 발생시키기 때문에 예외 처리가 필요하다.
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
멤버만 가져온다.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()
메소드가 호출된다.
이것이 자바다 책