반응형

이슈

POI는 아파치에서 만든 라이브러리로서 마이크로소프트 오피스 파일 포맷을 순수 자바 언어로서 읽고 쓰는 기능을 제공한다.

 

회사 제품에 데이터를 엑셀로 다운받을 수 있는 기능이 있는데 톰캣이나 Jetty was를 사용하였을 때는 아무런 에러가 발생하지 않았지만, weblogic을 사용하는 사이트에서 아래와 같은 에러가 발생하였다.

 

java.lang.NoClassDefFoundError: Could not initialize class org.apache.poi.POIXMLTypeLoader

 

 

원인

제품에서 사용하는 POI 라이브러리와 Weblogic에서 자체적으로 지원하는 POI 라이브러리와 충돌해서 발생하는 에러이다.

 

 

해결

WEB-INF 아래에 weblogic.xml 파일 생성 후 아래와 같은 옵션 추가하여 어플리케이션 내에 라이브러리를 우선적으로 사용하도록 설정한다.

<container-descriptor>
	<prefer-web-inf-classes>true</prefer-web-inf-classes>
</container-descriptor>
반응형
반응형

자바의 최상위 클래스인 Object 클래스에는 finalize 메서드가 존재한다.

   /**
     * Called by the garbage collector on an object when garbage collection
     * determines that there are no more references to the object.
     * A subclass overrides the {@code finalize} method to dispose of
     * system resources or to perform other cleanup.
     * <p>
     * The general contract of {@code finalize} is that it is invoked
     * if and when the Java&trade; virtual
     * machine has determined that there is no longer any
     * means by which this object can be accessed by any thread that has
     * not yet died, except as a result of an action taken by the
     * finalization of some other object or class which is ready to be
     * finalized. The {@code finalize} method may take any action, including
     * making this object available again to other threads; the usual purpose
     * of {@code finalize}, however, is to perform cleanup actions before
     * the object is irrevocably discarded. For example, the finalize method
     * for an object that represents an input/output connection might perform
     * explicit I/O transactions to break the connection before the object is
     * permanently discarded.
     * <p>
     * The {@code finalize} method of class {@code Object} performs no
     * special action; it simply returns normally. Subclasses of
     * {@code Object} may override this definition.
     * <p>
     * The Java programming language does not guarantee which thread will
     * invoke the {@code finalize} method for any given object. It is
     * guaranteed, however, that the thread that invokes finalize will not
     * be holding any user-visible synchronization locks when finalize is
     * invoked. If an uncaught exception is thrown by the finalize method,
     * the exception is ignored and finalization of that object terminates.
     * <p>
     * After the {@code finalize} method has been invoked for an object, no
     * further action is taken until the Java virtual machine has again
     * determined that there is no longer any means by which this object can
     * be accessed by any thread that has not yet died, including possible
     * actions by other objects or classes which are ready to be finalized,
     * at which point the object may be discarded.
     * <p>
     * The {@code finalize} method is never invoked more than once by a Java
     * virtual machine for any given object.
     * <p>
     * Any exception thrown by the {@code finalize} method causes
     * the finalization of this object to be halted, but is otherwise
     * ignored.
     *
     * @throws Throwable the {@code Exception} raised by this method
     * @see java.lang.ref.WeakReference
     * @see java.lang.ref.PhantomReference
     * @jls 12.6 Finalization of Class Instances
     */
    protected void finalize() throws Throwable { }

 

특정 객체에 대한 참조가 더 이상 없다고 판단할 때 가비지 컬렉션이 객체의 finalize를 호출한다. 문서에서도 나와 있듯이 하위 클래스에서 시스템 리소스를 삭제하거나 다른 정리를 수행하기 위해 finalize 메서드를 오버 라이딩하여 작성할 수 있다.

	@Override
	protected void finalize() throws Throwable {
		// do something
		super.finalize();
	}

 

하지만 이펙티브 자바에서는 finalize 사용을 피하라고 권고한다.

finalize는 예측 불가능하며, 대체로 위험하고, 일반적으로 불필요하다.

 

finalize는 언제 수행되는지도 알 수 없으며 수행을 반드시 보장하지 않는다.

1. finalize 메서드는 호출되더라도 즉시 실행된다는 보장이 없으며, 언제 수행되는지도 알 수 없다.

 

finalize는 GC가 호출하게 되는데, GC는 JVM 구현마다 크게 다르기 때문에 finalize가 언제 수행되는지는 알 수 없다. 따라서 중요한 리소스의 해제를 finalize에서 하게 된다면 finalize가 언제 호출될지 모르기 때문에 애플리케이션 실행 중에 리소스 문제가 발생할 수 있으며, 발생하여도 재현하기가 쉽지 않아 디버깅하기 어렵다.

 

2. finalize 수행을 반드시 보장하지 않는다.

 

finalize가 호출되지 않은 상태로 애플리케이션이 종료될 수 있다. 그러므로 지속성이 보장되어야 하는 중요한 상태 정보를 finalize에 작성하면 안 된다. finalize를 반드시 수행하도록 하는 System.runFinalizersOnExit(), Runtime.runFinalizersOnExit() 메서드가 존재하지만, Deprecated 되었다.

     * @deprecated  This method is inherently unsafe.  It may result in
     *      finalizers being called on live objects while other threads are
     *      concurrently manipulating those objects, resulting in erratic
     *      behavior or deadlock.
     * @param value indicating enabling or disabling of finalization
     * @throws  SecurityException
     *        if a security manager exists and its <code>checkExit</code>
     *        method doesn't allow the exit.
     *
     * @see     java.lang.Runtime#exit(int)
     * @see     java.lang.Runtime#gc()
     * @see     java.lang.SecurityManager#checkExit(int)
     * @since   JDK1.1
     */
    @Deprecated
    public static void runFinalizersOnExit(boolean value) {
        Runtime.runFinalizersOnExit(value);
    }

 

 

finalize에서 발생하는 예외는 무시된다.

finalize 메서드 안에서 예외가 발생한다고 하더라도, 해당 예외는 무시되며 스택 트레이스도 표시되지 않는다. 또한 해당 finalize 메서드도 중단된다.

 

아래 예제를 보자.

public class ExceptionInFinalizeTest {

	public static void main(String[] args) throws Throwable {
		ExceptionInFinalizeTest exceptionInFinalizeTest = new ExceptionInFinalizeTest();
		exceptionInFinalizeTest = null;

		// System.gc does not guarantee finalize, but generally works fine.
		System.gc();
	}

	@Override
	protected void finalize() throws Throwable {
		System.out.println("The finalize method start");

		// Exceptions are ignored.
		System.out.println(2 / 0);

		super.finalize();

		System.out.println("The finalize method end"); // not printed
	}
}

 

ExceptionInFinalizeTest 객체를 생성하고, GC를 발생하도록 하기 위해 null로 하여 레퍼런스를 제거하였다. 이후 gc를 발생시켜 finalize()를 호출되게 하였다. finalize의 수행은 항상 보장하지는 않지만 테스트에서는 항상 호출되었다.

 

finalize에 예외를 발생시키도록 divde by zero를 수행하였지만, 어떠한 스택트레이스도 남지 않았으며 이후 코드도 수행되지 않고 종료된다.

 

 

finalize를 재정의할 경우 성능 저하가 발생한다.

finalize를 재정의 하는 것만으로도 성능 저하가 발생한다.

 

아래 에제를 보자.

public class FinalizePerformanceTest {

	/**
	 * TODO Implement performance test case for finalize
	 */
	public static void main(String[] args) {
		long start = System.nanoTime();
		for (int i = 0; i < 1000000; i++) {
			new FinalizePerformanceTest();
		}
		long end = System.nanoTime();
		System.out.println("time: " + (end - start));

	}

	@Override
	protected void finalize() throws Throwable {
		super.finalize();
	}

}

필자의 컴퓨터에서는 finalize를 재정의하여 테스트를 할 경우 위 결과는 152730300ns가 발생하였다. finalize 재정의를 하지 않을 경우 3501900ns 소요되었다. 약 43배 느리다.

 

finalize 사용방법 및 구현 방법

그럼 도대체 이렇게 단점이 많은 finalize는 어디에 사용할까?

 

1. 명시적 종료 메서드 패턴에서 호출되지 않을 것을 대비하기 위한 방어 역할

 

명시적 종료 메서드란 자원을 사용하고 나서 사용을 마쳤으면 메모리 해제를 명시적으로 하도록 만든 메서드를 의미한다. 대표적으로 FileInputStream, FileOutputSteam, Timer, Connection이 있다. 하지만 API 개발자는 항상 클라이언트가 API를 올바르게 사용하지 않을 수도 있다는 것을 고려해야 한다. 따라서 명시적으로 종료 메서드를 호출하지 않았을 경우를 대비하여 finalize 메서드에 메모리 해제를 하도록 작성한다.

 

아래는 java.io.FileInputStream 클래스의 코드이다.

public class FileInputStream extends InputStream
{
    ...

    /**
     * Ensures that the <code>close</code> method of this file input stream is
     * called when there are no more references to it.
     *
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FileInputStream#close()
     */
    protected void finalize() throws IOException {
        if ((fd != null) &&  (fd != FileDescriptor.in)) {
            /* if fd is shared, the references in FileDescriptor
             * will ensure that finalizer is only called when
             * safe to do so. All references using the fd have
             * become unreachable. We can call close()
             */
            close();
        }
    }
}

 

2. 네이티브 피어(native peer) 리소스를 해제할 때

먼저 네이티브(native)란 자바 외의 C나 C++ 등 다른 언어로 작성된 프로그램을 나타낸다. 이런 프로그램을 자바에서 다루기 위해 만들어놓은 객체를 네이티브 피어라고 한다. 그리고 일반적인 클래스들이 이러한 네이티브 피어를 이용해 네이티브 프로그램을 사용한다.

 

이 네이티브 피어(객체)는 일반 객체가 아니기 때문에 GC가 관리하지 않는다. 그렇기 때문에 해당 네이티브 피어를 사용하는 일반적인 클래스의 finalize 메서드에서 해당 네이티브 객체의 리소스를 해제하는 코드를 작성할 수 있다.

 

 

finalize를 사용한다면 반드시 부모의 finalize를 호출해야 한다. 그렇지 않으면, 부모 클래스는 절대 종료되지 않는다.

	@Override
	protected void finalize() throws Throwable {
		try {
			// do something
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			super.finalize();
		}
	}

 

하지만 개발자는 항상 실수를 한다. 아래 예를 들어보자.

 

AClass는 finalize를 재정의하여 반드시 유한한 자원의 메모리를 해제해야 하는 클래스를 구현했다고 가정하자. AClass는 부모의 finalize를 반드시 호출해야 한다는 것을 알고 아래와 같이 구현하였다.

public class AClass {

	private void myClose() {
		System.out.println("Do Something");
	}

	@Override
	protected void finalize() throws Throwable {
		try {
			myClose();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			super.finalize();
		}
	}

}

 

BClass는 AClass를 상속받고 마찬가지로 finalize를 재정의했다. 하지만 BClass는 실수로 super.finliaze()를 호출하지 않았다. 그럼 AClass의 finalize는 호출되지 않아 myClose는 호출되지 않는다.

 

이렇게 하위 클래스에서 잘못 코딩하여 발생할 수 있는 finalize 문제를 부모 클래스에서 막을 수 있는데 이를 Finalizer Guardian 패턴이라고 한다.

 

이는 GC의 기본원리를 이용하여 finalize를 호출하는 방식이다. 먼저 코드는 아래와 같다.

public class AClass {

	private final Object guardian = new Object() {
		@Override
		protected void finalize() throws Throwable {
			myClose();
		}
	};

	private void myClose() {
		System.out.println("Do Something");
	}

}

 

기존에 finalize에서 호출되었던 myClose() 메서드가 guardian이라는 변수에 선언된 익명 클래스의 finalize에 선언되어 있다. 즉, AClass의 자원 해제 역할을 익명 클래스가 대신한다.

 

A 클래스를 재정의한 B 클래스의 객체가 더 이상 레퍼런스가 없어 gc가 발생하게 된다면, B 객체에 존재하는 guaridan에 참조되어 있는 익명 클래스의 객체도 누구도 사용할 수 없다. 그러므로 익명 클래스의 객체도 gc 대상이 되므로 해당 finalize가 반드시 호출된다. 따라서 멍청한 하위 클래스가 부모의 finalize를 호출하지 않아도 문제가 발생하지 않는다.

 

 

요약

자원 반환에 대한 최종적 방어 로직 또는 네이티브 자원을 종료시키려는 것이 아니라면 finalize를 사용하지 말자.

 

 

반응형
반응형

자바는 가비지 컬렉션이 알아서 메모리를 관리해주기 때문에 C와 같은 언어보다 메모리에 대해 생각하지 않고 일반적으로 코딩을 한다.

 

하지만 자바 애플리케이션을 만들어 실행하다 보면 OOM이 떨어지는 경우가 있다.

즉 어디선가 가비지 컬렉션이 청소할 수 없는 객체들이 쌓여서 메모리 누수 (leak)가 발생한 것이다.

 

아래 Stack을 구현한 pop 메서드 예제를 보자.

	/**
	 * This method only decreases the size of the stack.
	 * The object at the corresponding array index becomes an obsolete reference.
	 */
	public Object pop() {
		if (size == 0) {
			throw new EmptyStackException();
		}

		return elements[--size];
	}

 

Stack의 데이터를 꺼내오면서 Stack의 허용치를 1 증가시키기 위해 인덱스를 감소시켰다.

 

위 코드의 문제점은 무엇일까?

pop을 통해 꺼내온 객체는 아직까지도 Stack의 array가 참조하고 있다. 결국 해당 array 위치에 새로운 객체가 할당되지 않는다면 프로그램이 종료될 때까지 가비지 컬렉션은 해당 객체가 가비지인지 알 수 없다.

 

따라서 위 코드는 아래와 같이 명시적으로 null로 만들어 참조를 제거해야 한다.

	public Object popDoThis() {
		if (size == 0) {
			throw new EmptyStackException();
		}
		Object result = elements[--size];
		elements[size] = null; /* to let gc do its work */

		return result;
	}

 

Stack 예시처럼 자체적으로 관리하는 메모리가 있는 클래스를 만들 때는 메모리 누수가 발생하지 않도록 주의해야 한다.

 

java.util.WeakHashMap : key에 대한 메모리 참조가 없으면 자동으로 데이터를 삭제하는 Map

자바에서는 메모리 누수가 발생할 수 있는 자료구조에 대한 몇 가지 해결책을 제공한다. 첫 번째로 java.util.WeakHashMap이다.

 

WeakHashMap은 Map이므로 Key와 Value를 한쌍의 데이터로 관리한다. 이때 Key에 대한 참조가 더 이상 존재하지 않게 되면, Value를 가져올 수 있는 방법이 없다고 판단하여, 해당 Key-Value 쌍은 자동으로 삭제되는 Map이다.

 

아래 예제를 보자.

	/**
	 * We put object reference into a cache and forget that we put it there.
	 * To solve this problem we often implement caches using WeakHaspMap.
	 * A WeakHashMap will automatically remove value when its key is no longer referenced.
	 */
	public static void main(String[] args) {
		WeakHashMap<Integer, String> weakHashMap = new WeakHashMap<Integer, String>();

		Integer key = new Integer(1);
		weakHashMap.put(key, "1");
		key = null;

		// If GC is generated, the output changes to {}.
		while (true) {
			System.out.println(weakHashMap);
			System.gc();
			if (weakHashMap.size() == 0) {
				break;
			}
		}

		System.out.println("End");
	}

Key가 1의 값을 가진 Integer 객체이고, Value를 "1" 로하여 WeakHashMap에 put 하였다. 이후, Key값인 Integer의 참조를 null로 만들어 더 이상 참조가 일어나지 않도록 하였다. 이후 GC를 발생시키면 Key의 대한 참조가 없다고 판단하여, 쌍이 사라진 예제이다.

 

참고로, String 클래스를 Key로 하는 WeakHashMap을 사용하면 의미가 없다. 왜냐하면 규칙 5에서 설명했듯이 String은 내부적으로 한 번 생성된 String에 대해 Constant Pool에 항상 참조가 존재하기 때문이다.

 

java.util.LinkedHashMap : 가장 오래된 데이터를 처리할 수 있는 Map

java.util.LinkedHashMap은 HashMap가 다르게 데이터를 넣은 순서를 알 수 있다. 순서를 알 수 있으므로 LinkedHashMap은 아래와 같은 특별한 메서드를 제공한다.

 

    /**
     * Returns <tt>true</tt> if this map should remove its eldest entry.
     * This method is invoked by <tt>put</tt> and <tt>putAll</tt> after
     * inserting a new entry into the map.  It provides the implementor
     * with the opportunity to remove the eldest entry each time a new one
     * is added.  This is useful if the map represents a cache: it allows
     * the map to reduce memory consumption by deleting stale entries.
     *
	 * ....
     *
     * @param    eldest The least recently inserted entry in the map, or if
     *           this is an access-ordered map, the least recently accessed
     *           entry.  This is the entry that will be removed it this
     *           method returns <tt>true</tt>.  If the map was empty prior
     *           to the <tt>put</tt> or <tt>putAll</tt> invocation resulting
     *           in this invocation, this will be the entry that was just
     *           inserted; in other words, if the map contains a single
     *           entry, the eldest entry is also the newest.
     * @return   <tt>true</tt> if the eldest entry should be removed
     *           from the map; <tt>false</tt> if it should be retained.
     */
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

 

put() 또는 putAll() 메서드를 호출하고 나서 자동으로 호출되는 removeEldestEntry 메서드는 가장 오래된 데이터를 삭제할지를 검사하는 메서드이다.

 

true를 리턴하게 되면 가자 오래된 데이터를 삭제하고, false를 리턴하면 삭제하지 않는다. 디폴트로는 false를 리턴하도록 되어있어 항상 삭제하지 않는다.

 

아래는 Map의 크기가 5인 LinkedHashMap의 예제이다.

	public static void main(String[] args) {
		final int MAX_ENTRIES = 5;
		LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<String, String>() {
			@Override
			public boolean removeEldestEntry(Map.Entry eldest) {
				return size() > MAX_ENTRIES;
			}
		};

		linkedHashMap.put("1", "a");
		linkedHashMap.put("2", "b");
		linkedHashMap.put("3", "c");
		linkedHashMap.put("4", "d");
		linkedHashMap.put("5", "e");
		linkedHashMap.put("6", "f"); /* {1=a} disappear and this item will be added. */

		for (Iterator<String> hashitr = linkedHashMap.values().iterator(); hashitr.hasNext();) {
			System.out.print(hashitr.next() + " ");
		}
	}

 

반응형
반응형

사경인 회계사님이 쓴 재무제표 모르면 주식투자 절대로 하지마라에 나오는 공식인 S-RIM을 계산하여 해당하는 종목을 매주 제공합니다.

 

재무제표 정보를 제공하는 사이트(http://comp.fnguide.com)를 크롤링하여 필요한 정보를 구했습니다.

 

특히, ROE 같은 경우는  당해에 컨센서스가 추측하는 ROE를 기준으로 하였고, 컨센서스가 존재하지 않을 경우 대상에서 제외합니다.

 

목표 수익률은 9%로 하였습니다.

 

당기순이익이 어떠한 이유로 인해(투자, 매각 등) 너무 높아 ROE가 비정상적으로 다른 해보다 높은 기업이 존재합니다.

따라서 아래 종목 리스트는 투자에 참고만 해주시고, 반드시 해당 기업의 재무제표를 다시 확인해주시기 바랍니다.

 

종목명 시가총액 현재가격 매수가격 중간가격 매도가격 지난주 대비 최초 대비
NAVER 671837 409000 513237 781666 1646602 -0.37 0.49
기아 351855 86800 92825 102224 132510 -1.36 2.00
POSCO 248482 285000 613356 668627 846726 0.00 -3.72
KB금융 234516 56400 110688 112756 119422 2.36 -0.35
신한지주 193983 37550 90367 91004 93057 -0.13 -1.83
LG 141571 90000 146856 158920 197793 -3.74 -1.32
하나금융지주 130755 43550 111576 114243 122837 -0.57 -3.22
HMM 110672 27300 33286 49566 102024 2.25 2.44
우리금융지주 95740 13150 35007 35921 38867 -1.13 -0.75
롯데케미칼 74035 216000 431828 451057 513017 -1.60 -3.79
LG디스플레이 72100 20150 37085 39105 45615 -0.98 2.28
한화솔루션 70199 36700 46390 49554 59749 -0.41 -10.16
LG유플러스 62435 14300 17726 18004 18899 1.06 -0.35
현대글로비스 58875 157000 162430 176598 222251 new new
미래에셋증권 58513 9210 16712 17357 19433 4.30 6.11
현대제철 55513 41600 130190 132033 137972 -0.95 -6.41
CJ제일제당 55475 368500 405274 422116 476386 -3.41 -3.03
금호석유 51338 168500 287011 395287 744178 -1.46 -2.03
한국금융지주 48816 87600 163842 201231 321707 0.92 0.69
이마트 45298 162500 396195 439281 578113 new new
삼성증권 42909 48050 79539 90924 127609 2.34 1.48
DB손해보험 40710 57500 95016 98714 110628 -1.03 -2.87
GS 39535 42550 112248 123400 159334 0.95 0.71
NH투자증권 38763 13050 23902 26234 33750 0.77 -0.76
GS건설 35174 41100 54443 56281 62200 -1.44 -0.60
메리츠증권 31530 4625 8362 9255 12131 0.32 -0.75
팬오션 30364 5680 6736 7493 9930 -1.39 -5.65
OCI 28738 120500 139554 163030 238675 0.00 -6.95
키움증권 28710 109500 207048 251358 394134 3.30 4.29
BNK금융지주 27933 8570 27969 28117 28595 1.54 -2.61
대우건설 25311 6090 8936 10182 14197 0.66 -2.56
포스코인터내셔널 25292 20500 28671 30111 34751 -0.48 -5.53
효성티앤씨 24322 562000 684106 1012410 2070278 -0.71 -5.86
한화 23949 31950 71859 78861 101423 -1.54 -4.63
두산 22886 138500 151558 182579 282538 3.75 34.47
현대해상 22797 25500 51675 51686 51718 0.99 -2.86
코오롱인더 22180 80600 88018 90138 96969 -1.59 -1.59
롯데정밀화학 20872 80900 94400 113006 172959 -0.49 -4.94
효성 20860 99000 145470 168831 244103 -0.20 -3.88
한화에어로스페이스 20784 41050 55220 55631 56955 new new
영원무역 19719 44500 46334 47806 52548 2.18 -0.33
JB금융지주 16744 8500 21828 23126 27311 1.19 -4.17
DGB금융지주 16576 9800 31231 31433 32084 0.30 -5.32
동국제강 16319 17100 31768 37405 55570 6.88 0.30
현대두산인프라코어 16051 8130 13525 14493 17613 1.81 92.23
HDC현대산업개발 15719 23850 46027 47850 53727 -3.64 -6.65
에스엘 15329 31800 32893 34220 38494 new -2.90
DL 13475 64300 301465 383482 647758 0.63 0.63
대한유화 11863 182500 317188 323413 343472 0.83 -1.35
SK가스 11630 126000 236615 248418 286448 -2.33 -8.37
LX인터내셔널 10426 26900 54212 65423 101547 1.89 -0.92
GS홈쇼핑 10165 154900 198218 205333 228258 0.00 0.00
유니드 10134 114000 153307 187838 299104 -1.31 -2.15
한섬 9926 40300 48129 48755 50773 -6.28 -4.39
풍산 9080 32400 65135 71938 93860 0.93 -2.11
대한해운 8682 2720 4093 4635 6380 0.18 -3.54
동원산업 8495 231000 381471 393173 430880 -1.70 1.53
대상 8264 23850 34478 35679 39547 0.22 0.00
현대건설기계 7979 40500 71864 74673 83725 -0.49 0.62
효성화학 7896 247500 253212 321656 542196 new new
동원F&B 7795 202000 217479 228290 263124 -0.50 -1.47
세아베스틸 7585 21150 52082 54875 63875 1.44 -2.31
SNT모티브 7312 50000 59378 60732 65093 -0.19 -0.58
SK디앤디 6635 29900 31690 35671 48500 -0.17 -5.23
코오롱글로벌 6340 25150 33174 41487 68272 2.64 -3.28
한국토지신탁 5896 2335 3994 4164 4712 2.86 -0.20
한국자산신탁 5443 4390 7464 8207 10600 0.57 -0.44
매일유업 5365 68400 70571 78044 102122 -1.87 -2.98
국도화학 5298 58800 110750 140779 237540 -3.76 -12.11
한라홀딩스 5048 48200 99092 104989 123987 -3.50 -5.29
SIMPAC 4894 7480 7782 8040 8873 6.69 6.69
한진 4806 32150 104108 117894 162315 -3.16 -7.20
송원산업 4200 17500 23442 25880 33737 0.57 0.57
태영건설 4162 10700 21827 24885 34736 -0.93 -3.61
금호건설 4140 11300 19918 24662 39950 0.00 -6.21
대한제강 4067 16500 33895 41984 68048 0.00 -11.05
원익머트리얼즈 3959 31400 34529 38200 50030 -0.63 -3.53
인탑스 3861 22450 34160 37284 47353 3.21 -3.67
계룡건설 3434 38450 86231 98726 138988 4.47 7.72
동부건설 3309 14550 26456 29723 40249 0.36 -3.27
한세예스24홀딩스 3148 7870 13459 15343 21412 -0.51 -1.25
풍산홀딩스 2962 28450 106661 125239 185104 2.74 -0.17
유니퀘스트 2870 10500 11776 13494 19030 0.46 1.92
KPX케미칼 2754 56900 115141 116308 120071 -2.72 -1.40
랩지노믹스 2702 23600 34235 51552 107351 -11.61 -9.05
KSS해운 2655 11450 15851 18081 25269 -2.96 -3.77
현대코퍼레이션 2381 18000 26782 28272 33075 0.85 -2.18
도이치모터스 2145 7240 11274 11887 13860 -5.96 -4.71
금화피에스시 2058 34300 46145 47469 51733 1.03 4.73
한라 2052 5420 12502 14387 20460 3.06 -3.89
태웅로직스 1581 8090 10343 14853 29386 new new
디와이파워 1402 12700 22156 24406 31656 0.36 0.00
SGC이테크건설 1395 68900 149397 196235 347160 -0.57 -0.57
현대코퍼레이션홀딩스 1129 12400 22817 24129 28356 -1.57 -4.24
휴비츠 1105 9300 9384 10749 15146 new new
코메론 1054 11650 19743 20388 22466 0.00 -4.09
이노인스트루먼트 824 2045 2280 2418 2862 -3.06 -5.07
반응형

'주식' 카테고리의 다른 글

[21년 11월 5주차] S-RIM 종목  (0) 2021.11.28
[21년 11월 4주차] S-RIM 종목  (0) 2021.11.21
[21년 11월 2주차] S-RIM 종목  (0) 2021.11.07
[21년 11월 1주차] S-RIM 종목  (0) 2021.11.01
[21년 10월 5주차] S-RIM 종목  (0) 2021.10.24
반응형

사경인 회계사님이 쓴 재무제표 모르면 주식투자 절대로 하지마라에 나오는 공식인 S-RIM을 계산하여 해당하는 종목을 매주 제공합니다.

 

재무제표 정보를 제공하는 사이트(http://comp.fnguide.com)를 크롤링하여 필요한 정보를 구했습니다.

 

특히, ROE 같은 경우는  당해에 컨센서스가 추측하는 ROE를 기준으로 하였고, 컨센서스가 존재하지 않을 경우 대상에서 제외합니다.

 

목표 수익률은 9%로 하였습니다.

 

당기순이익이 어떠한 이유로 인해(투자, 매각 등) 너무 높아 ROE가 비정상적으로 다른 해보다 높은 기업이 존재합니다.

따라서 아래 종목 리스트는 투자에 참고만 해주시고, 반드시 해당 기업의 재무제표를 다시 확인해주시기 바랍니다.

 

종목명 시가총액 현재가격 매수가격 중간가격 매도가격 지난주 대비
NAVER 674301 410500 513160 781534 1646294 0.86
기아 356720 88000 92825 102224 132510 3.41
POSCO 248482 285000 614835 671168 852684 -3.72
KB금융 229110 55100 110688 112756 119422 -2.65
신한지주 194241 37600 90391 91046 93157 -1.70
LG 147076 93500 148111 161076 202850 2.52
하나금융지주 131506 43800 111576 114243 122837 -2.67
HMM 108240 26700 32903 48909 100483 0.19
우리금융지주 96832 13300 35007 35921 38867 0.38
롯데케미칼 75235 219500 438643 462760 540468 -2.23
LG디스플레이 72815 20350 36972 38911 45158 3.30
한화솔루션 70486 36850 46263 49335 59236 -9.79
LG유플러스 61781 14150 17631 17840 18514 -1.39
CJ제일제당 57432 381500 410540 431159 497596 0.40
미래에셋증권 56098 8830 16682 17304 19310 1.73
현대제철 56047 42000 130331 132275 138539 -5.51
금호석유 52100 171000 280444 384012 717730 -0.58
한국금융지주 48370 86800 163842 201231 321707 -0.23
삼성증권 41926 46950 75658 84260 111976 -0.85
DB손해보험 41135 58100 95016 98714 110628 -1.86
GS 39164 42150 105366 111583 131615 -0.24
NH투자증권 38466 12950 23885 26205 33681 -1.52
GS건설 35687 41700 54443 56281 62200 0.84
메리츠증권 31428 4610 8329 9197 11996 -1.07
팬오션 30791 5760 6711 7450 9829 -4.32
OCI 28738 120500 139554 163030 238675 -6.95
KCC 28037 315500 609006 614478 632112 -5.25
키움증권 27793 106000 206447 250326 391713 0.96
BNK금융지주 27509 8440 27969 28117 28595 -4.09
포스코인터내셔널 25415 20600 28671 30111 34751 -5.07
대우건설 25145 6050 8928 10169 14165 -3.20
효성티앤씨 24495 566000 692221 1026344 2102964 -5.19
한화 24324 32450 71859 78861 101423 -3.13
현대해상 22574 25250 51675 51686 51718 -3.81
코오롱인더 22538 81900 88018 90138 96969 new
두산 22059 133500 151558 182579 282538 29.61
롯데정밀화학 20975 81300 94400 113006 172959 -4.47
효성 20902 99200 145470 168831 244103 -3.69
영원무역 19298 43550 46334 47806 52548 -2.46
JB금융지주 16547 8400 21828 23126 27311 -5.29
DGB금융지주 16526 9770 31257 31477 32188 -5.60
HDC현대산업개발 16312 24750 46027 47850 53727 -3.13
현대두산인프라코어 15765 8100 14001 15004 18233 88.80
동국제강 15269 16000 31768 37405 55570 -6.16
DL 13391 63900 301465 383482 647758 new
SK가스 11907 129000 229510 236217 257828 -6.18
대한유화 11765 181000 317188 323413 343472 -2.16
한섬 10591 43000 48090 48688 50616 2.01
유니드 10268 115500 153307 187838 299104 -0.86
LX인터내셔널 10233 26400 50838 59630 87959 -2.76
GS홈쇼핑 10165 154900 198218 205333 228258 0.00
풍산 8996 32100 65135 71938 93860 -3.02
대한해운 8666 2715 4093 4635 6380 -3.72
동원산업 8642 235000 381471 393173 430880 3.29
대상 8246 23800 34478 35679 39547 -0.22
현대건설기계 8018 40700 71864 74673 83725 1.11
동원F&B 7834 203000 217479 228290 263124 -0.97
세아베스틸 7477 20850 52082 54875 63875 -3.70
SNT모티브 7326 50100 57690 59005 63242 -0.39
SK디앤디 6646 29950 31661 35622 48384 -5.07
코오롱글로벌 6177 24500 32615 40526 66018 -5.77
한국토지신탁 5732 2270 3994 4164 4712 -2.98
국도화학 5505 61100 110750 140779 237540 -8.68
매일유업 5467 69700 70571 78044 102122 -1.14
한국자산신탁 5412 4365 7464 8207 10600 -1.01
한라홀딩스 5231 49950 99092 104989 123987 -1.86
한진 4963 33200 104108 117894 162315 -4.17
SIMPAC 4587 7010 7782 8040 8873 new
태영건설 4201 10800 21827 24885 34736 -2.71
송원산업 4176 17400 23442 25880 33737 new
금호건설 4140 11300 19918 24662 39950 -6.21
대한제강 4067 16500 33895 41984 68048 -11.05
원익머트리얼즈 3984 31600 34042 37365 48069 -2.92
이수화학 3844 13750 18366 24893 45926 -9.55
인탑스 3741 21750 33691 36480 45465 -6.66
동부건설 3297 14500 26456 29723 40249 -3.62
계룡건설 3287 36800 86231 98726 138988 3.11
한세예스24홀딩스 3164 7910 13459 15343 21412 -0.75
랩지노믹스 3057 26700 34235 51552 107351 2.89
풍산홀딩스 2883 27700 106661 125239 185104 -2.83
유니퀘스트 2857 10450 11776 13494 19030 1.46
KPX케미칼 2831 58500 115141 116308 120071 1.36
KSS해운 2736 11800 15851 18081 25269 -0.83
현대코퍼레이션 2361 17850 26782 28272 33075 -3.00
도이치모터스 2281 7700 11274 11887 13860 1.33
금화피에스시 2037 33950 46145 47469 51733 3.66
한라 1991 5260 12502 14387 20460 -6.74
엑시콘 1409 13450 18816 23711 39484 -3.23
SGC이테크건설 1403 69300 149397 196235 347160 0.00
디와이파워 1397 12650 22156 24406 31656 -0.36
현대코퍼레이션홀딩스 1147 12600 22817 24129 28356 -2.71
코메론 1054 11650 19743 20388 22466 -4.09
이노인스트루먼트 850 2110 2280 2418 2862 -2.07
반응형

'주식' 카테고리의 다른 글

[21년 11월 4주차] S-RIM 종목  (0) 2021.11.21
[21년 11월 3주차] S-RIM 종목  (0) 2021.11.14
[21년 11월 1주차] S-RIM 종목  (0) 2021.11.01
[21년 10월 5주차] S-RIM 종목  (0) 2021.10.24
[21년 10월 4주차] S-RIM 종목  (0) 2021.10.19
반응형

자바에서는 new를 사용하여 새로운 객체를 생성한다.

동일한 클래스를 여러 개의 객체를 만들어 사용하는 경우가 많겠지만, 클래스의 용도, 특징에 따라 굳이 객체를 여러 개 만들 필요가 없는 클래스들이 있다.

 

가장 먼저 우리가 자주 사용하는 String이다.

 

String : new vs literal

String 클래스는 두 가지 생성 방식이 있다.

 

1. new

String str = new String("camel");

2. literal

String str = "camel";

 

이 두 가지 방식으로 생성된 String 객체는 기능상으로 다른 점이 있을까? 당연하게도 없다.

하지만 생성된 String 객체가 존재하는 JVM의 위치는 차이가 있다.

 

new를 사용하여 객체를 만들게 되면 어떤 클래스라도 Heap 영역에 객체가 할당된다. 하지만 literal를 사용할 경우 Heap 영역 안에 다른 영역인 String Constant Pool 영역에 String 객체가 할당된다.

 

따라서 아래와 같은 결과가 나타난다.

		String newStr1 = new String("camel");
		String literalStr1 = "camel";

		System.out.println(newStr1 == literalStr1); // false
		System.out.println(newStr1.equals(literalStr1)); // true

기능상으로는 동일하기 때문에 equals는 true를 반환하지만, 객체의 주소 값을 비교하는 ==은 false를 반환한다.

 

그럼 아래의 결과는 어떻게 나올까?

		String newStr1 = new String("camel");
		String newStr2 = new String("camel");

		String literalStr1 = "camel";
		String literalStr2 = "camel";

		System.out.println(newStr1 == newStr2); // false
		System.out.println(literalStr1 == literalStr2); // true

new를 사용하면 항상 객체를 생성하므로 newStr1과 newStr2는 서로 다른 객체이다. 따라서 false가 반환된다.

 

하지만 literal로 선언한 두 값의 비교는 true를 반환하였다. 이유는 무엇일까?

String을 literal로 선언하면 내부적으로 intern() 메서드를 호출하게 된다. intern() 메서드는 주어진 문자열이 String Constant Pool 영역에 존재하는지 먼저 확인하고, 존재한다면 해당 값을 반환하고 없다면 새롭게 생성하기 때문이다.

 

이처럼 String은 특별한 경우가 아니라면 new를 사용하여 객체를 생성하지 말자.

 

정적 팩토리 메서드를 제공하는 변경 불가능 클래스(Immutable Class)

잘 짜인 정적 팩토리 메서드(규칙 1)를 제공하는 변경 불가능 클래스는 정적 팩토리 메서드를 호출하면 이미 만들어진 객체를 반환한다.

// Boolean.java

    public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);

    public static Boolean valueOf(boolean b){
        return b ? TRUE : FALSE;
    }

 

따라서 이런 클래스들은 문서를 잘 읽어보고, new를 사용하여 객체를 생성하지 않아도 되는지 확인하는 것이 좋다.

		Boolean newBool = new Boolean(true); // do not
		Boolean bool = Boolean.valueOf(true); // do it

 

변경 가능한 클래스라도 동일한 값을 가진 객체를 계속 사용할 경우

변경 불가능 클래스라면 동일한 값을 가진 객체를 생성할 필요 없이 재사용하면 된다. 하지만 변경 가능한 클래스라면 해당 객체를 다른 영역에서 변경할 수 있으므로, 필요할 때 객체를 자주 생성해서 사용한다.

 

하지만, 변경되지 않고 해당 영역에서만 사용하고 사라지는 변경 가능한 객체가 있을 수 있다.

아래 예를 보자.

 

	public boolean isBabyBoomer() {
		Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

		gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
		Date boomStart = gmtCal.getTime();

		gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
		Date boomEnd = gmtCal.getTime();

		return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0;
	}

위 코드는 1946년부터 1964년 사이에 태어난 사람인지 확인하는 메서드이다.

 

위 메서드는 어떠한 파라미터도 받지 않고, 항상 동일한 작업을 한다. 하지만 Date 클래스인 boomStart와 boomEnd에 Date 객체는 메서드가 호출될 때마다 새롭게 생성된다.

 

또한 Calendar 클래스는 객체를 생성하는데 비용이 꽤 소요되는 클래스인데, 마찬가지로 항상 새롭게 객체를 생성한다.

위 코드는 아래와 같이 변경하면 약 250배 개선된다.

	private static final Date BOOM_START;
	private static final Date BOOM_END;

	/**
	 * The static initializer block is called only once.
	 */
	static {
		Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

		gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
		BOOM_START = gmtCal.getTime();

		gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
		BOOM_END = gmtCal.getTime();
	}

	public boolean isBabyBoomerDoThis() {
		return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0;
	}

 

API가 객체를 새롭게 생성하는지, 생성하지 않는지 잘 확인하자

위에서 String의 literal 방식, Boolean의 정적 팩토리 메서드 방식, Calendar의 getInstance(), getTime() 등의 예를 들었다. 이렇게 각각의 API들이 객체를 재사용하는지, 아니면 새롭게 만드는지 분명하지 않을 수 있다. 그렇기 때문에 API의 객체를 생성할 때는 항상 문서를 잘 읽고 개발자가 원하는 방식에 맞게 잘 사용해야 한다.

 

아래 예를 들어보자.

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();

		map.put("key1", "val1");
		Set<String> keyset1 = map.keySet();

		map.put("key2", "val2");
		Set<String> keyset2 = map.keySet();

		System.out.println(keyset1 == keyset2); // true

	}

Map의 keySet 메서드는 key값의 목록을 Set 클래스로 반환한다. 위처럼 keyset1을 구하고, 새로운 값을 넣은 후 keyset2를 구했을 때, 일반적으로 생각하기에는 두 값이 서로 다를 것으로 생각한다. 그러나 두 keySet의 값은 동일하다. 

 

그러므로 keySet을 여러 번 호출하여 변수를 여러 개 만들어도 큰일 날 것은 없지만, 쓸데없는 짓이다.

 

다음으로는 많이 알려진 AutoBoxing(자동 객체화)의 문제(?)이다.

AutoBoxing은 기본 자료형(Premitive Type)과 그에 대응하는 객체 클래스와 섞어 사용할 수 있도록 해주는 기능이다.

 

아래 예를 들어보자

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

		Long sum = 0L;
		for (long i = 0; i < Integer.MAX_VALUE; i++) {
			sum += i;
		}
	}

Long 클래스인 sum에 기본 자료형인 i의 값을 더하고 있다. 이때 기본 자료형 i는 AutoBoxing이 되어 자동 객체화된다. 즉 loop를 돌 때마다 객체가 계속 생성된다. 그래서 위의 수행 결과는 글쓴이는 9.988초 소요되었다.

 

위와 같이 짠 개발자가 의도한 게 있는지는 모르겠지만(없을 것이다.) 루프는 기본자료형을 사용하고, 최종적인 결과에서만 Long으로 반환하는 것이 맞을 것이다.

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

		long sum = 0L;
		for (long i = 0; i < Integer.MAX_VALUE; i++) {
			sum += i;
		}
	}

 

반응형
반응형

사경인 회계사님이 쓴 재무제표 모르면 주식투자 절대로 하지마라에 나오는 공식인 S-RIM을 계산하여 해당하는 종목을 매주 제공합니다.

 

재무제표 정보를 제공하는 사이트(http://comp.fnguide.com)를 크롤링하여 필요한 정보를 구했습니다.

 

특히, ROE 같은 경우는  당해에 컨센서스가 추측하는 ROE를 기준으로 하였고, 컨센서스가 존재하지 않을 경우 대상에서 제외합니다.

 

목표 수익률은 9%로 하였습니다.

 

당기순이익이 어떠한 이유로 인해(투자, 매각 등) 너무 높아 ROE가 비정상적으로 다른 해보다 높은 기업이 존재합니다.

따라서 아래 종목 리스트는 투자에 참고만 해주시고, 반드시 해당 기업의 재무제표를 다시 확인해주시기 바랍니다.

 

종목명 시가총액 현재가격 매수가격 중간가격 매도가격
NAVER 668552 407000 513160 781534 1646294
기아 344964 85100 92869 102300 132687
POSCO 258073 296000 614095 669898 849705
KB금융 235347 56600 110717 112807 119541
신한지주 197599 38250 90342 90962 92958
LG 143459 91200 148111 161076 202850
하나금융지주 135109 45000 111576 114243 122837
HMM 108037 26650 32903 48909 100483
우리금융지주 96468 13250 35007 35921 38867
한화솔루션 78137 40850 46101 49057 58583
롯데케미칼 76948 224500 438643 462760 540468
LG디스플레이 70490 19700 36972 38911 45158
LG유플러스 62654 14350 17631 17840 18514
현대제철 59317 44450 130366 132336 138681
CJ제일제당 57206 380000 410540 431159 497596
미래에셋증권 55145 8680 16643 17237 19152
금호석유 52404 172000 280444 384012 717730
한국금융지주 48482 87000 161624 197422 312770
삼성증권 42284 47350 75535 84048 111481
DB손해보험 41914 59200 95016 98714 110628
GS 39257 42250 105366 111583 131615
NH투자증권 39060 13150 23885 26205 33681
GS건설 35388 41350 54415 56231 62085
팬오션 32181 6020 6711 7450 9829
메리츠증권 31769 4660 8252 9066 11688
OCI 30885 129500 139554 163030 238675
KCC 29592 333000 609006 614478 632112
BNK금융지주 28682 8800 27984 28143 28657
키움증권 27530 105000 206006 249569 389938
포스코인터내셔널 26772 21700 28671 30111 34751
대우건설 25976 6250 8928 10169 14165
효성티앤씨 25836 597000 683419 1011231 2067513
한화 25111 33500 71037 77449 98111
현대해상 23468 26250 51675 51686 51718
롯데정밀화학 21956 85100 93097 110769 167711
효성 21703 103000 146778 171077 249371
영원무역 19785 44650 46334 47806 52548
DGB금융지주 17507 10350 31257 31477 32188
JB금융지주 17472 8870 21828 23126 27311
두산 17020 103000 151558 182579 282538
HDC현대산업개발 16839 25550 46087 47953 53968
동국제강 16271 17050 31847 37541 55889
에스엘 15787 32750 32893 34220 38494
SK가스 12692 137500 229510 236217 257828
대한유화 12025 185000 317869 324583 346214
LX인터내셔널 10523 27150 50838 59630 87959
한섬 10382 42150 48090 48688 50616
유니드 10357 116500 153307 187838 299104
GS홈쇼핑 10165 154900 198218 205333 228258
풍산 9276 33100 64751 71279 92314
대한해운 9001 2820 3901 4304 5605
동원산업 8367 227500 381471 393173 430880
현대두산인프라코어 8350 10500 14001 15004 18233
대상 8264 23850 34478 35679 39547
현대건설기계 7930 40250 71864 74673 83725
동원F&B 7911 205000 217479 228290 263124
세아베스틸 7764 21650 52042 54807 63714
SNT모티브 7355 50300 57798 59190 63677
SK디앤디 7001 31550 31661 35622 48384
코오롱글로벌 6555 26000 32615 40526 66018
국도화학 6028 66900 110750 140779 237540
한국토지신탁 5908 2340 3994 4164 4712
매일유업 5530 70500 70571 78044 102122
한국자산신탁 5467 4410 7464 8207 10600
한라홀딩스 5330 50900 99092 104989 123987
한진 5179 34650 104108 117894 162315
대한제강 4572 18550 33895 41984 68048
금호건설 4414 12050 19918 24662 39950
태영건설 4318 11100 21827 24885 34736
이수화학 4250 15200 18366 24893 45926
원익머트리얼즈 4104 32550 34042 37365 48069
인탑스 4008 23300 33691 36480 45465
웅진씽크빅 3864 3345 3391 3578 4179
코리아써키트 3720 15750 15867 16467 18402
동부건설 3421 15050 26456 29723 40249
계룡건설 3188 35700 86231 98726 138988
한세예스24홀딩스 3188 7970 13459 15343 21412
랩지노믹스 2971 25950 34235 51552 107351
풍산홀딩스 2967 28500 106661 125239 185104
유니퀘스트 2816 10300 11776 13494 19030
KPX케미칼 2793 57700 115141 116308 120071
KSS해운 2759 11900 15851 18081 25269
현대코퍼레이션 2434 18400 26850 28389 33350
도이치모터스 2251 7600 11274 11887 13860
한라 2135 5640 12396 14204 20032
금화피에스시 1965 32750 46145 47469 51733
엑시콘 1456 13900 18816 23711 39484
SGC이테크건설 1403 69300 149397 196235 347160
디와이파워 1402 12700 22156 24406 31656
현대코퍼레이션홀딩스 1179 12950 22817 24129 28356
코메론 1099 12150 19743 20388 22466
이노인스트루먼트 868 2155 2280 2418 2862
           
           
           
           
           
           

 

반응형

'주식' 카테고리의 다른 글

[21년 11월 3주차] S-RIM 종목  (0) 2021.11.14
[21년 11월 2주차] S-RIM 종목  (0) 2021.11.07
[21년 10월 5주차] S-RIM 종목  (0) 2021.10.24
[21년 10월 4주차] S-RIM 종목  (0) 2021.10.19
[21년 10월 3주차] S-RIM 종목  (0) 2021.10.10
반응형

개인적으로 규칙 3과 규칙 4의 순서가 바뀌는 것이 좋다고 생각함.

 

클래스가 private 생성자만을 가지고 있다면 자신만이 객체를 생성할 수 있기 때문에 규칙 3. 싱글턴 패턴에서 private 생성자를 사용하였다. 또한 싱글턴은 메모리에 올려야 하는 정보(필드)가 있기 때문에 객체를 만들어서 사용한다.

 

싱글턴과는 다르게 메모리에 올려서 사용할 정보들은 없는 Util 클래스들은 객체를 만들 목적의 클래스가 아니다. 따라서 Util 클래스를 작성할 때는 private 생성자를 사용하여 객체 생성을 막는 것이 좋다.

 

아래는 private 생성자를 사용한 Netty의 io.netty.util.internal.StringUtil 소스코드이다.

public final class StringUtil {

    public static final String EMPTY_STRING = "";
    public static final String NEWLINE = SystemPropertyUtil.get("line.separator", "\n");

    public static final char DOUBLE_QUOTE = '\"';
    public static final char COMMA = ',';
    public static final char LINE_FEED = '\n';
    public static final char CARRIAGE_RETURN = '\r';
    public static final char TAB = '\t';
    public static final char SPACE = 0x20;

    private static final String[] BYTE2HEX_PAD = new String[256];
    private static final String[] BYTE2HEX_NOPAD = new String[256];
    private static final byte[] HEX2B;

    ...
    
    // private 생성자를 사용하여 객체 생성을 막는다. 
    private StringUtil() {
        // Unused.
    }

 

private 생성자가 아닌 클래스를 abstract로 선언하여 객체를 생성하지 못하도록 막을 수도 있다. 하지만 해당 클래스는 상속받은 하위 클래스를 만들게 된다면 객체가 결국에 생성되는 것이니 올바른 방법이 아니다.

 

아래는 abstract 클래스로 선언하여 사용한 Spring의 org.springframework.util.StringUtils 소스코드이다.

// abstract로 선언하여 직접적으로 객체는 만들 수 없지만, 상속 받은 하위클래스는 객체 생성이 가능하다.
public abstract class StringUtils {

	private static final String[] EMPTY_STRING_ARRAY = {};

	private static final String FOLDER_SEPARATOR = "/";

	private static final String WINDOWS_FOLDER_SEPARATOR = "\\";

	private static final String TOP_PATH = "..";

	private static final String CURRENT_PATH = ".";

	private static final char EXTENSION_SEPARATOR = '.';
    
    ...

 

/**
 * Spring의 StringUtils는 클래스는 객체 생성을 막기 위해 abstract를 클래스로 만들었지만
 * 하위 클래스가 상속받는다면 객체 생성이 가능
 *
 * @author gwon
 * @history
 *          2021. 10. 24. initial creation
 */
public class ChildSpringStringUtils extends StringUtils {

	public static void main(String[] args) {
		StringUtils stringUtils = new ChildSpringStringUtils();

		stringUtils.isEmpty("abc");
	}
}

 

 

반응형

+ Recent posts