1. 예제 프로그램 - '큰 문자'를 출력하는 프로그램
<BigChar.java>
package ch20.Sample;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
// ‘큰 문자’를 나타내는 클래스
// 파일로부터 큰 문자의 텍스트를 읽어 메모리 상에 로드하고,
// print 메소드에서 그것을 표시한다.
// 큰 문자는 메모리를 많이 차지하므로, BigChar의 인스턴스를 공유하자.
public class BigChar {
// 문자의 이름
private char charname;
// 큰 문자를 표현하는 문자열
private String fontdata;
// 인수로 제공된 문자의 ‘큰 문자’ 버전을 작성한다.
public BigChar(char charname) {
this.charname = charname;
try {
BufferedReader reader = new BufferedReader(new FileReader("big"+ charname + ".txt"));
String line;
StringBuffer buf = new StringBuffer();
// 파일로부터 한 라인씩 읽어서, “\n”과 함께 buf 에 추가한다.
while ((line = reader.readLine()) != null) {
buf.append(line);
buf.append("\n");
}
reader.close();
this.fontdata = buf.toString(); // 작성된 문자열을 fontdata에 저장함
} catch (IOException e) {
this.fontdata = charname + "?";
}
}
// 큰 문자를 표시한다.
public void print() {
System.out.print(fontdata);
}
}
<BigcharFactory.java>
package ch20.Sample;
import java.util.Hashtable;
// BigChar의 인스턴스를 작성하는 공장
// 여기서 인스턴스의 공유가 실현된다.
public class BigCharFactory {
// 이미 만들어진 BigChar의 인스턴스를 모아서 관리한다.
private Hashtable pool = new Hashtable();
// Singleton 패턴을 사용함.
private static BigCharFactory singleton = new BigCharFactory();
// 생성자는 private
private BigCharFactory() {
}
// 유일한 하나의 인스턴스를 얻는다.
public static BigCharFactory getInstance() {
return singleton;
}
// Flyweight 패턴의 중심이 되는 메소드
// 인수로 제공된 문자에 대응하는 BigChar 인스턴스를 만든다
public synchronized BigChar getBigChar(char charname) {
BigChar bc = (BigChar) pool.get("" + charname);
if (bc == null) { // 생성된 BigChar 가 없다면...
bc = new BigChar(charname); // 여기에서 BigChar의 인스턴스를 생성
pool.put("" + charname, bc); // pool에 추가한다.
}
// 생성된 BigChar 가 있다면, 이것을 반환한다.
return bc;
}
}
<BigString.java>
package ch20.Sample;
// BigChar들을 모은 ‘큰 문자열’ 클래스
public class BigString {
// "큰 문자"의 배열
private BigChar[] bigchars;
// 생성자
// 입력 인자인 문자열에 해당하는 "큰 문자열"을 만든다.
public BigString(String string) {
bigchars = new BigChar[string.length()];
BigCharFactory factory = BigCharFactory.getInstance();
// 필드 bigchars 배열의 각 원소는
// BigCharFactory로부터 BigChar를 얻어서 참조한다.
for (int i = 0; i < bigchars.length; i++) {
bigchars[i] = factory.getBigChar(string.charAt(i));
}
// 설명:
// BigCharFactory은,
// 이미 생성된 BigChar인 경우에는
// 기존의 BigChar 인스턴스를 반환하므로,
// bigchars 배열의 각 원소는 같은 문자에 대해서는 BigChar 객체를 공유한다.
// (참고) 매번 새로운 인스턴스를 생성하는 경우
/*
for (int i = 0; i < bigchars.length; i++) {
bigchars[i] = new BigChar(string.charAt(i));
}
*/
}
// 표시
public void print() {
for (int i = 0; i < bigchars.length; i++) {
bigchars[i].print();
}
}
}
<Main.java>
package ch20.Sample;
public class Main {
// 명령행 인자로 들어온 문자열을 실인자로 해서,
// BigString( ) 객체를 생성한다.
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Usage: java Main digits");
System.out.println("Example: java Main 1212123");
System.exit(0);
}
BigString bs = new BigString(args[0]);
bs.print();
}
}
2. 연습 문제 1번 + 연습 문제 2번 - BigChar 인스턴스를 공유한 경우와 공유하지 않은 경우의 메모리 소비량을 비교
<BigChar.java>
package ch20.A2;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BigChar {
// 문자의 이름
private char charname;
//큰 문자를 표현하는 문자열 ('#' '.' '\n'의 열)
private String fontdata;
//생성자
public BigChar(char charname) {
this.charname = charname;
try {
BufferedReader reader = new BufferedReader(
new FileReader("big" + charname + ".txt")
);
String line;
StringBuffer buf = new StringBuffer();
while ((line = reader.readLine()) != null) {
buf.append(line);
buf.append("\n");
}
reader.close();
this.fontdata = buf.toString();
} catch (IOException e) {
this.fontdata = charname + "?";
}
}
// 큰 문자를 표시한다.
public void print() {
System.out.print(fontdata);
}
}
<BigCharFactory.java>
package ch20.A2;
import java.util.Hashtable;
public class BigCharFactory {
//이미 만들어진 BigChar의 인스턴스를 관리
private Hashtable pool = new Hashtable();
// Singleton 패턴
private static BigCharFactory singleton = new BigCharFactory();
// 생성자
private BigCharFactory() {
}
// 유일한 하나의 인스턴스를 얻는다.
public static BigCharFactory getInstance() {
return singleton;
}
// BigChar의 인스턴스 생성(공유)
public synchronized BigChar getBigChar(char charname) {
BigChar bc = (BigChar)pool.get("" + charname);
if (bc == null) {
bc = new BigChar(charname); // 여기에서 BigChar의 인스턴스를 생성
pool.put("" + charname, bc);
}
return bc;
}
}
<BigString.java>
package ch20.A2;
public class BigString {
// "큰 문자"의 배열
private BigChar[] bigchars;
// 생성자
public BigString(String string) {
init_shared(string);
}
// 생성자
public BigString(String string, boolean shared) {
if (shared) {
init_shared(string);
} else {
init_unshared(string);
}
}
// 공유해서 초기화
private void init_shared(String string) {
bigchars = new BigChar[string.length()];
BigCharFactory factory = BigCharFactory.getInstance();
for (int i = 0; i < bigchars.length; i++) {
bigchars[i] = factory.getBigChar(string.charAt(i));
}
}
// 공유하지 않고 초기화
private void init_unshared(String string) {
bigchars = new BigChar[string.length()];
for (int i = 0; i < bigchars.length; i++) {
bigchars[i] = new BigChar(string.charAt(i));
}
}
//표시
public void print() {
for (int i = 0; i < bigchars.length; i++) {
bigchars[i].print();
}
}
}
<Main.java>
package ch20.A2;
public class Main {
private static BigString[] bsarray = new BigString[1000];
public static void main(String[] args) {
System.out.println("공유한 경우:");
testAllocation(true);
System.out.println("공유하지 않은 경우:");
testAllocation(false);
if (args.length == 0) {
System.out.println("Usage: java Main digits");
System.out.println("Example: java Main 1212123");
System.exit(0);
}
BigString bs;
bs = new BigString(args[0], false); // 공유하지 않는다.
bs.print();
bs = new BigString(args[0], true); // 공유한다.
bs.print();
}
public static void testAllocation(boolean shared) {
for (int i = 0; i < bsarray.length; i++) {
bsarray[i] = new BigString("1212123", shared);
}
showMemory();
}
public static void showMemory() {
Runtime.getRuntime().gc();
long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
System.out.println("사용 메모리 = " + used);
}
}