본문 바로가기

프로그래밍/자바(java)

[자바/java] System 클래스, Class 클래스

System 클래스

 

자바 프로그램은 운영체제상에서 바로 실행되는 것이 아니라 JVM 위에서 실행된다.

따라서, 운영체제의 모든 기능을 자바 코드로 직접 접근하기 어렵다.

하지만 System클래스를 이용하면 운영체제의 일부 기능을 이용할 수 있다.

 

프로그램 종료(exit())

경우에 따라 강제적으로 JVM을 종료 시킬 때도 있다.

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

exit() 메소드 안에 int매개값을 지정하도록 되어있는데, 이 값을 종료 상태값이라고 한다.

일반적으로 정상 종료일 경우 0으로 지정하고 비정상 종료일 경우 0 이외의 다른값을 준다.

 

public class ExitMain {

    public static void main(String[] args) {

        System.setSecurityManager(new SecurityManager(){
            @Override
            public void checkExit(int status) {
                if(status != 5) {
                    throw new SecurityException();
                }
            }
        });

        for(int i = 0 ; i < 10 ; i++) {
            System.out.println(i);
            try {
                System.exit(i);
            } catch(SecurityException e) { }
        }

    }

}

 

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

 

자바는 개발자가 메모리를 직접 코드로 관리하지 않고 JVM이 알아서 자동으로 관리한다.

JVM은 메모리가 부족할 떄와 CPU가 한가할 때에 쓰레기 수집기를 실행시켜 사용허자 않은 객체를 자동으로 제거한다.

 

개발자가 직접 쓰레기를 없앨 수 없지만 빨리 없애달라고 실행시킬 수 있다고 요청은 할수 있다.

 

쓰레기가 생길 때만다 쓰레기 수집기(gc) 가 동작하면 수행할 프로그램의 속도가 떨어져 성능 측면에서 좋지 않다.

그리고 메모리가 충분하면 쓰레기 수집기를 실행할 필요가 없다.

 

public class GCMain {

    public static void main(String[] args) {

        Trash trash;

        trash = new Trash(1);
        trash = null;
        trash = new Trash(2);
        trash = new Trash(3);

        System.gc();
        
    }

}

class Trash {

    public int eno;

    public Trash(int eno) {
        this.eno = eno;
        System.out.println("Trash"+ eno +" 가 메모리에 생성 되었습니다.");
    }

    public void finalize() {
        System.out.println("Thrash"+ eno +"메모리가 제거됨");
    }

}

 

System.gc() 로 가비지 컬렉터 가 작동을 하면서 Trash3는 아직 사용되고 있으므로 Trash1, Trash2 는  사용하고 있지 않아 메모리에서 제거가 된다.

 

현재 시작 읽기(currentTimeMillis(), nanoTime())

 

현재 시간을 읽어서 밀리세컨드(1/1000초) 단위와 나노세컨드(1/10 - 9승) 초 단위의 long 값을 리턴한다.

 

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

 

public class SystemtimeMain {

    public static void main(String[] args) {
        long time1 = System.nanoTime();

        int sum = 0;
        for(int i = 0 ; i <= 1000000; i++) {
            sum += i;
        }

        long time2 = System.nanoTime();

        System.out.println("1 ~ 1000000까지의 합 : " + sum);
        System.out.println("걸린 시간은 : " +  (time2- time1));
    }

}

 

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

 

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

ex) 운영체제의 종류 및 자바 프로그램의 실행시킨 아이디, JVM의 버전 등을 읽을 수 있다.

 

import java.util.Properties;
import java.util.Set;

public class GetPropertyMain {

    public static void main(String[] args) {

        String osName = System.getProperty("os.name");
        String userName = System.getProperty("user.name");
        String userHome = System.getProperty("user.home");

        System.out.println("운영체제 이름: " + osName);
        System.out.println("사용자 이름: " + userName);
        System.out.println("사용자 홈디렉토리: " + userHome);

        System.out.println();
        System.out.println("================");
        System.out.println();

        Properties props = System.getProperties();
        Set keys = props.keySet();
        for(Object objKey : keys) {
            String key = (String) objKey;
            String value = System.getProperty(key);
            System.out.println("[" + key + "] : " + value);
        }


    }

}

 

 

 

위에 운영체제 이름이나 사용자 이름, 사용자 홈디렉터리는 제가 getProperty를  이용해서 직접 내용을 출력해봤습니다.

 

밑에 === 밑에서는 Properties목록을 전체 조회후 출력합니다.

사진 말고 밑에 더 있으니 한번 코드로 작성해보고 확인해주세요~

 

 

환경 변수 읽기 (getenv())

 

대부분의 운영체제는 실행되는 프로그램들에게 유용한 정보를 제공할 목적으로 환경변수(Enviroment Variable)를 제공한다.

환경변수는 운영체제상의 변수가 아니라 운영체제에서 이름과 값으로 관리되는 문자열 정보입니다.

 

public class EnvMain {

    public static void main(String[] args) {
        String javaHome = System.getenv("JAVA_HOME");
        System.out.println("JAVA_HOME: " + javaHome);
    }

}

 

예제로 자바 홈 환경변수를 얻어 와서 출력 해보왔습니다.

 

 


Class 클래스

 

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

Object는 모든 클래스의 최상위 클래스이므로 모든 클래스에서 getClass() 메소드를 호출할 수 있다.

 

public class ClassExample {

    public static void main(String[] args) {

        Car example = new Car();
        Class example1 = example.getClass();
        System.out.println(example1.getName());
        System.out.println(example1.getSimpleName());
        System.out.println(example1.getPackage().getName());

        try {

            Class example2 = Class.forName("Class.Car");

            System.out.println(example2.getName());
            System.out.println(example2.getSimpleName());
            System.out.println(example2.getPackage().getName());

        }catch(ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

}

class Car {

}

 

 

리플렉션(getDeclaredConstructors(), getDeclaredFields(), getDeclaredMethdos())

 

Class 객체를 이용하면 클래스의 생성자, 필드, 메소드 정보를 알아낼 수 있다.

getDeclaredFileds(), getDeclaredMethods() 는 클래스에 선언된 상속 멤버는 가져오지 않습니다.

만약 상속된 멤버도 얻고 싶다면 getFields(), getMethods()를 이용한다. (public 멤버만 가져온다)

 

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

public class ReflectionMain {

    public static void main(String[] args) throws Exception {

        Class clazz = Class.forName("Class.Phone");

        System.out.println("클래스 이름 : " + clazz.getName());

        System.out.println("[생성자 정보]");
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for(Constructor constructor : constructors) {
            System.out.print(constructor.getName() + "(");
            Class[] parameter = constructor.getParameterTypes();
            printParameters(parameter);
            System.out.println(")");
        }
        System.out.println();

        System.out.println("[필드 점보]");
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields) {
            System.out.println(field.getType().getSimpleName()+ " " + field.getName());
        }
        System.out.println();

        System.out.println("[메소드 정보]");
        Method[] methods = clazz.getDeclaredMethods();
        for(Method method : methods) {
            System.out.print(method.getName() + "(");
            Class[] parameters = method.getParameterTypes();
            printParameters(parameters);
            System.out.println(")");
        }

    }

    private static void printParameters(Class[] parameters) {
        for(int i = 0 ; i < parameters.length ; i++) {
            System.out.print(parameters[i].getName());
            if(i<(parameters.length - 1)) {
                System.out.print(",");
            }
        }
    }
}


class Phone {

    public String company;
    public String model;

    public Phone(String company, String model) {
        this.company = company;
        this.model = model;
    }

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }
}

 

 

실행 결과로 Phone의 필드, 생성자, 메소드 정보를 출력한다.

 

 

동적 객체 생성(newInstance())

 

Class 객체를 사용하면 new 연산자를 사용하지 않아도 동적으로 객체를 생성할 수 있다.

하지만, 이 방법은 코드 작성 시에 클래스 이름을 결정할 수 없다.

 

Constructor 객체를 얻어 newInstance() 메소드를 호출하면 된다.

 

public interface Action {
    public void execute();
}
public class SendAction implements Action{

    @Override
    public void execute() {
        System.out.println("데이터를 보냅습니다.");
    }
}
public class ReceiveAction implements Action{

    @Override
    public void execute() {
        System.out.println("데이터를 받습니다.");
    }
}
public class NewInstanceExample {
    public static void main(String[] args) {
        try {

            Class clazz = Class.forName("Class.SendAction");
            Action action = (Action) clazz.newInstance();
            action.execute();

            clazz = Class.forName("Class.ReceiveAction");
            action = (Action) clazz.newInstance();
            action.execute();

        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}