반응형

시스템의 밀리초 구하기.(국제표준시각(UTC, GMT) 1970/1/1/0/0/0 으로부터 경과한 시각)


// 밀리초 단위(*1000은 1초), 음수이면 이전 시각
long time = System.currentTimeMillis ( );
System.out.println ( time.toString ( ) );



현재 시각을 가져오기.


Date today = new Date ();
System.out.println ( today );


결과 : Sat Jul 12 16:03:00 GMT+01:00 2000


경과시간(초) 구하기


long time1 = System.currentTimeMillis ();
long time2 = System.currentTimeMillis ();

system
.out.println ( ( time2 - time1 ) / 1000.0 );


Date를 Calendar로 맵핑하기


Date d = new Date ( );
Calendar c = Calendar.getInstance ( );
c
.setTime ( d );


날짜(년/월/일/시/분/초) 구하기


import java.util.*;
import java.text.*;

SimpleDateFormat formatter = new SimpleDateFormat ( "yyyy.MM.dd HH:mm:ss", Locale.KOREA );
Date currentTime = new Date ( );
String dTime = formatter.format ( currentTime );
System.out.println ( dTime );



날짜(년/월/일/시/분/초) 구하기2


GregorianCalendar today = new GregorianCalendar ( );

int year = today.get ( today.YEAR );
int month = today.get ( today.MONTH ) + 1;
int yoil = today.get ( today.DAY_OF_MONTH );


GregorianCalendar gc = new GregorianCalendar ( );


System.out.println ( gc.get ( Calendar.YEAR ) );
System.out.println ( String.valueOf ( gc.get ( Calendar.MONTH ) + 1 ) );
System.out.println ( gc.get ( Calendar.DATE ) );
System.out.println ( gc.get ( DAY_OF_MONTH ) );



날짜(년/월/일/시/분/초) 구하기3


DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.KOREA);
Calendar cal = Calendar.getInstance(Locale.KOREA);
nal
= df.format(cal.getTime());


- 표준시간대를 지정하고 날짜를 가져오기.


TimeZone jst = TimeZone.getTimeZone ("JST");
Calendar cal = Calendar.getInstance ( jst ); // 주어진 시간대에 맞게 현재 시각으로 초기화된 GregorianCalender 객체를 반환.// 또는 Calendar now = Calendar.getInstance(Locale.KOREA);
System.out.println ( cal.get ( Calendar.YEAR ) + "년 " + ( cal.get ( Calendar.MONTH ) + 1 ) + "월 " + cal.get ( Calendar.DATE ) + "일 " + cal.get ( Calendar.HOUR_OF_DAY ) + "시 " +cal.get ( Calendar.MINUTE ) + "분 " + cal.get ( Calendar.SECOND ) + "초 " );

결과 : 2000년 8월 5일 16시 16분 47초


영어로된 날짜를 숫자로 바꾸기


Date myDate = new Date ( "Sun,5 Dec 1999 00:07:21" );
System.out.println ( myDate.getYear ( ) + "-" + myDate.getMonth ( ) + "-" + myDate.getDay ( ) );



"Sun, 5 Dec 1999 00:07:21"를 "1999-12-05"로 바꾸기


SimpleDateFormat formatter_one = new SimpleDateFormat ( "EEE, dd MMM yyyy hh:mm:ss",Locale.ENGLISH );
SimpleDateFormat formatter_two = new SimpleDateFormat ( "yyyy-MM-dd" );

String inString = "Sun, 5 Dec 1999 00:07:21";


ParsePosition pos = new ParsePosition ( 0 );
Date frmTime = formatter_one.parse ( inString, pos );
String outString = formatter_two.format ( frmTime );


System.out.println ( outString );



숫자 12자리를, 다시 날짜로 변환하기


Date conFromDate = new Date();
long ttl = conFromDate.parse ( "Dec 25, 1997 10:10:10" );
System.out.println ( ttl ); //예 938291839221

Date today = new Date ( ttl );
DateFormat format = DateFormat.getDateInstance ( DateFormat.FULL,Locale.US );
String formatted = format.format ( today );
System.out.println ( formatted );



특정일로부터 n일 만큼 이동한 날짜 구하기

특정일의 시간을 long형으로 읽어온다음..
날짜*24*60*60*1000 을 계산하여.
long형에 더해줍니다.
그리고 나서 Date클래스와 Calender클래스를 이용해서 날짜와 시간을 구하면 됩니다


특정일에서 일정 기간후의 날짜 구하기2


//iDay 에 입력하신 만큼 빼거나 더한 날짜를 반환 합니다.
import java.util.*;

public String getDate ( int iDay )
{

Calendar temp=Calendar.getInstance ( );
StringBuffer sbDate=new StringBuffer ( );


temp.add ( Calendar.DAY_OF_MONTH, iDay );


int nYear = temp.get ( Calendar.YEAR );
int nMonth = temp.get ( Calendar.MONTH ) + 1;
int nDay = temp.get ( Calendar.DAY_OF_MONTH );


sbDate.append ( nYear );
if ( nMonth < 10 )
sbDate
.append ( "0" );

sbDate
.append ( nMonth );
if ( nDay < 10 )
sbDate
.append ( "0" );

sbDate
.append ( nDay );


return sbDate.toString ( );
}



현재날짜에서 2달전의 날짜를 구하기


Calendar cal = Calendar.getInstance ( );//오늘 날짜를 기준으루..
cal
.add ( cal.MONTH, -2 ); //2개월 전....
System.out.println ( cal.get ( cal.YEAR ) );
System.out.println ( cal.get ( cal.MONTH ) + 1 );
System.out.println ( cal.get ( cal.DATE ) );


달에 마지막 날짜 구하기


for ( int month = 1; month <= 12; month++ )
{

GregorianCalendar cld = new GregorianCalendar ( 2001, month - 1, 1 );
System.out.println ( month + "/" + cld.getActualMaximum ( Calendar.DAY_OF_MONTH ) );
}


해당하는 달의 마지막 일 구하기


GregorianCalendar today = new GregorianCalendar ( );
int maxday = today.getActualMaximum ( ( today.DAY_OF_MONTH ) );
System.out.println ( maxday );


특정일을 입력받아 해당 월의 마지막 날짜를 구하는 간단한 예제.(달은 -1 해준다.)...윤달 30일 31일 알아오기.


Calendar cal = Calendar.getInstance ( );
cal
.set ( Integer.parseInt ( args[0] ), Integer.parseInt ( args [1] ) - 1, Integer.parseInt ( args [2] ) );
SimpleDateFormat dFormat = new SimpleDateFormat ( "yyyy-MM-dd" );
System.out.println ( "입력 날짜 " + dFormat.format ( cal.getTime ( ) ) );
System.out.println ( "해당 월의 마지막 일자 : " + cal.getActualMaximum ( Calendar.DATE ) );


해당월의 실제 날짜수 구하기 ( 1999년 1월달의 실제 날짜수를 구하기 )


Calendar calendar = Calendar.getInstance ( );
calendar
.set ( 1999, 0, 1 );
int maxDays = calendar.getActualMaximum ( Calendar.DAY_OF_MONTH );


어제 날짜 구하기

오늘날짜를 초단위로 구해서 하루분을 빼주고 다시
셋팅해주면 쉽게 구할수 있죠..
setTime((기준일부터 오늘까지의 초를 구함) - 24*60*60)해주면 되겠죠..

어제 날짜 구하기2


import java.util.*;

public static Date getYesterday ( Date today )
{
if ( today == null )
throw new IllegalStateException ( "today is null" );

Date yesterday = new Date ( );
yesterday
.setTime ( today.getTime ( ) - ( (long) 1000 * 60 * 60 * 24 ) );


return yesterday;
}



내일 날짜 구하기


Date today = new Date ( );
Date tomorrow = new Date ( today.getTime ( ) + (long) ( 1000 * 60 * 60 * 24 ) );


내일 날짜 구하기2


Calendar today = Calendar.getInstance ( );
today
.add ( Calendar.DATE, 1 );
Date tomorrow = today.getTime ( );


오늘날짜에서 5일 이후 날짜를 구하기


Calendar cCal = Calendar.getInstance();
c
.add(Calendar.DATE, 5);


날짜에 해당하는 요일 구하기


//DAY_OF_WEEK리턴값이 일요일(1), 월요일(2), 화요일(3) ~~ 토요일(7)을 반환합니다.
//아래 소스는 JSP일부입니다.
import java.util.*;

Calendar cal= Calendar.getInstance ( );
int day_of_week = cal.get ( Calendar.DAY_OF_WEEK );
if ( day_of_week == 1 )
m_week
="일요일";
else if ( day_of_week == 2 )
m_week
="월요일";
else if ( day_of_week == 3 )
m_week
="화요일";
else if ( day_of_week == 4 )
m_week
="수요일";
else if ( day_of_week == 5 )
m_week
="목요일";
else if ( day_of_week == 6 )
m_week
="금요일";
else if ( day_of_week == 7 )
m_week
="토요일";



콤보박스로 선택된 날짜(예:20001023)를 통해 요일을 영문으로 가져오기


//gc.get(gc.DAY_OF_WEEK); 하면 일요일=1, 월요일=2, ..., 토요일=7이 나오니까,
//요일을 배열로 만들어서 뽑아내면 되겠죠.
GregorianCalendar gc=new GregorianCalendar ( 2000, 10 - 1 , 23 );
String [] dayOfWeek = { "", "Sun", "Mon", .... , "Sat" };

String yo_il = dayOfWeek ( gc.get ( gc.DAY_OF_WEEK ) );



두 날짜의 차이를 일수로 구하기

각각의 날짜를 Date형으로 만들어서 getTime()하면
long으로 값이 나오거든요(1970년 1월 1일 이후-맞던가?- 1/1000 초 단위로..)
그러면 이값의 차를 구해서요. (1000*60*60*24)로 나누어 보면 되겠죠.


두 날짜의 차이를 일수로 구하기2


import java.io.*;
import java.util.*;

Date today = new Date ( );
Calendar cal = Calendar.getInstance ( );
cal
.setTime ( today );// 오늘로 설정.


Calendar cal2 = Calendar.getInstance ( );
cal2
.set ( 2000, 3, 12 ); // 기준일로 설정. month의 경우 해당월수-1을 해줍니다.


int count = 0;
while ( !cal2.after ( cal ) )
{
count
++;
cal2
.add ( Calendar.DATE, 1 ); // 다음날로 바뀜


System.out.println ( cal2.get ( Calendar.YEAR ) + "년 " + ( cal2.get ( Calendar.MONTH ) + 1 ) + "월 " + cal2.get ( Calendar.DATE ) + "일" );
}


System.out.println ( "기준일로부터 " + count + "일이 지났습니다." );



두 날짜의 차이를 일수로 구하기3


import java.io.*;
import java.util.*;

public class DateDiff
{
public static int GetDifferenceOfDate ( int nYear1, int nMonth1, int nDate1, int nYear2, int nMonth2, int nDate2 )
{
Calendar cal = Calendar.getInstance ( );
int nTotalDate1 = 0, nTotalDate2 = 0, nDiffOfYear = 0, nDiffOfDay = 0;


if ( nYear1 > nYear2 )
{
for ( int i = nYear2; i < nYear1; i++ )
{

cal
.set ( i, 12, 0 );
nDiffOfYear
+= cal.get ( Calendar.DAY_OF_YEAR );
}
nTotalDate1
+= nDiffOfYear;
}
else if ( nYear1 < nYear2 )
{
for ( int i = nYear1; i < nYear2; i++ )
{
cal
.set ( i, 12, 0 );
nDiffOfYear
+= cal.get ( Calendar.DAY_OF_YEAR );
}
nTotalDate2
+= nDiffOfYear;
}


cal.set ( nYear1, nMonth1-1, nDate1 );
nDiffOfDay
= cal.get ( Calendar.DAY_OF_YEAR );
nTotalDate1
+= nDiffOfDay;


cal.set ( nYear2, nMonth2-1, nDate2 );
nDiffOfDay
= cal.get ( Calendar.DAY_OF_YEAR );
nTotalDate2
+= nDiffOfDay;


return nTotalDate1-nTotalDate2;
}


public static void main ( String args[] )
{
System.out.println ( "" + GetDifferenceOfDate (2000, 6, 15, 1999, 8, 23 ) );
}
}



파일에서 날짜정보를 가져오기


File f = new File ( directory, file );

Date date = new Date ( f.lastModified ( ) );
Calendar cal = Calendar.getInstance ( );
cal
.setTime ( date );


System.out.println("Year : " + cal.get(Calendar.YEAR));
System.out.println("Month : " + (cal.get(Calendar.MONTH) + 1));
System.out.println("Day : " + cal.get(Calendar.DAY_OF_MONTH));
System.out.println("Hours : " + cal.get(Calendar.HOUR_OF_DAY));
System.out.println("Minutes : " + cal.get(Calendar.MINUTE));
System.out.println("Second : " + cal.get(Calendar.SECOND));



날짜형식으로 2000-01-03으로 처음에 인식을 시킨후
7일씩 증가해서 1년정도의 날짜를 출력해 주고 싶은데요.


SimpleDateFormat sdf = new SimpleDateFormat ( "yyyy-mm-dd" );
Calendar c = Calendar.getInstance ( );

for ( int i = 0; i < 48; i++ )
{
c
.clear ( );
c
.set ( 2000, 1, 3 - ( i * 7 ) );
java
.util.Date d = c.getTime ( );
String thedate = sdf.format ( d );
System.out.println ( thedate );
}



쓰레드에서 날짜 바꾸면 죽는 문제

Main화면에 날짜와시간이Display되는 JPanel이 있습니다.
date로 날짜와 시간을 변경하면 Main화면의 날짜와 시간이 Display되는 Panel에
변경된 날짜가 Display되지 않고 Main화면이 종료되어 버립니다.

문제소스:


public void run ( )
{
while ( true )
{
try{
timer
.sleep ( 60000 );
}
catch ( InterruptedException ex ) { }

lblTimeDate.setText ( fGetDateTime ( ) );
repaint
( );

}
}


public String fGetDateTime ( )
{
final int millisPerHour = 60 * 60 * 1000;
String DATE_FORMAT = "yyyy / MM / dd HH:mm";
SimpleDateFormat sdf = new SimpleDateFormat ( DATE_FORMAT );
SimpleTimeZone timeZone = new SimpleTimeZone ( 9 * millisPerHour, "KST" );
sdf
.setTimeZone ( timeZone );


long time = System.currentTimeMillis ( );
Date date = new Date ( time );
return sdf.format ( date );
}

해답:


// 날짜와 요일 구한다. timezone 으로 날짜를 다시 셋팅하시면 됨니다.
public String getDate ( )
{
Date now = new Date ( );
SimpleDateFormat sdf4 = new SimpleDateFormat ( "yyyy/MM/dd HH:mm EE" );
sdf4
.setTimeZone ( TimeZone.getTimeZone ( "Asia/Seoul" ) );

return sdf4.format ( now );
}



날짜와 시간이 유효한지 검사하려면...?


import java.util.*;
import java.text.*;

public class DateCheck
{

boolean dateValidity = true;


DateCheck ( String dt )
{
try

{

DateFormat df = DateFormat.getDateInstance ( DateFormat.SHORT );
df
.setLenient ( false );
Date dt2 = df.parse ( dt );

}

catch ( ParseException e ) { this.dateValidity = false; }
catch ( IllegalArgumentException e ) { this.dateValidity = false; }
}


public boolean datevalid ( )
{
return dateValidity;

}


public static void main ( String args [] )
{

DateCheck dc = new DateCheck ( "2001-02-28" );
System.out.println ( " 유효한 날짜 : " + dc.datevalid ( ) );
}
}



두 날짜 비교하기(아래보다 정확)

그냥 날짜 두개를 long(밀리 세컨드)형으로 비교하시면 됩니다...

이전의 데이타가 date형으로 되어 있다면, 이걸 long형으로 변환하고.
현재 날짜(시간)은 System.currentTimeMillis()메소드로 읽어들이고,
두수(long형)를 연산하여 그 결과 값으로 비교를 하시면 됩니다.

만약 그 결과값이 몇시간 혹은 며칠차이가 있는지를 계산할려면,
결과값을 Calender의 setTimeInMillis(long millis) 메소드를 이용해
설정한다음 각각의 날짜나 시간을 읽어오시면 됩니다


두 날짜 비교하기2


//Calendar를 쓸 경우 데이타의 원본을 고치기 때문에 clone()을 사용하여
//복사한 후에 그 복사본을 가지고 비교한다
import java.util.*;
import java.util.Calendar.*;
import java.text.SimpleDateFormat;

public class DayComparisonTest
{
public static void main(String args[])
{
Calendar cal = Calendar.getInstance();
SimpleDateFormat dateForm = new SimpleDateFormat("yyyy-MM-dd");


Calendar aDate = Calendar.getInstance(); // 비교하고자 하는 임의의 날짜
aDate
.set(2001, 0, 1);


Calendar bDate = Calendar.getInstance(); // 이것이 시스템의 날짜


// 여기에 시,분,초를 0으로 세팅해야 before, after를 제대로 비교함
aDate
.set( Calendar.HOUR_OF_DAY, 0 );
aDate
.set( Calendar.MINUTE, 0 );
aDate
.set( Calendar.SECOND, 0 );
aDate
.set( Calendar.MILLISECOND, 0 );


bDate.set( Calendar.HOUR_OF_DAY, 0 );
bDate
.set( Calendar.MINUTE, 0 );
bDate
.set( Calendar.SECOND, 0 );
bDate
.set( Calendar.MILLISECOND, 0 );



if (aDate.after(bDate)) // aDate가 bDate보다 클 경우 출력
System.out.println("시스템 날짜보다 뒤일 경우 aDate = " + dateForm.format(aDate.getTime()));
else if (aDate.before(bDate)) // aDate가 bDate보다 작을 경우 출력

System.out.println("시스템 날짜보다 앞일 경우 aDate = " + dateForm.format(aDate.getTime()));
else // aDate = bDate인 경우
System.out.println("같은 날이구만");
}
}

<출처 : 서비의 다락방 ( http://www.yunsobi.com )>
-출처를 밝혀주신 당신은 아름다운 사람입니다.-
반응형

1> 변수의 초기화란?
    선언된 변수에 최초로 값을 할당하는 것.
   즉, 멤버변수로 선언시 프로그래머가 초기값을 주지 않는경우 자동적으로 값이 할당되는 것.
지역변수는 해당이 안됨.

2> 변수의 종류-- 멤버변수와 지역변수

자바에서 변수로는 멤버변수(=전역변수)와 로컬변수(지역변수) 두 종류가 있다.

멤버변수(Member Variable)
로컬변수(local Variable)
선언부분
클래스내
메소드내
사용범위
해당 클래스내 전체
선언된 해당 메소드내
초기화
자동초기화
안됨.
프로그래머가 직점 초기값을 할당.

3> 기본 데이터형의 초기값

데이터형
기본초기값
boolean
false
char
'\u0000'
byte, short, int, long
0
float
0.0f
double
0.0
object
null

4> 초기화 예제

㉠ Variable_init .java


1 : class Variable_init
2 : {
3 :   public static void main(String[] args)
4 : {
5 :     int x;//x는 main메소드 안에 선언되어 있으므로 지역변수...
6 :     //x=0;
7 :     System.out.println(x);
8 :   }
9 : }


<< 실행 결과 >>

에러가 난다. 그 이유는 변수 x는 main메소드 안에 선언되어 있으므로 지역변수이다. 따라서 자동초기화가 안된다. 따라서 6번라인에서 x에 값을 할당해 주면 에러가 제거된다.


Variable_init2 .java


1 : class Variable_init2
2 : {
3 :    static boolean b;
4 :    static int x;
5 :    static float f;
6 :
7 :   public static void main(String[] args)
8 :   {
9 :       System.out.println("변수 b의 초기값은 : "+b);
10 :     System.out.println("변수 x의 초기값은 : "+x);
11 :     System.out.println("변수 f의 초기값은 : "+f);
12 :    }
13 : }


<< 실행 결과 >>

변수 b의 초기값은 : false
변수 x의 초기값은 : 0
변수 f의 초기값은 : 0.0

변수 b,x,f는 메소드내에 선언된 것이 아니므로 멤버변수들이다. 따라서 프로그래머가 초기값을 할당해 주지 않아도 기본값이 할당된다.

여기서 static이란 키워드가 사용되었는데 이는 객체를 생성하지 않아도 변수를 사용할 수 있게 해주는데 지금은 그렇다는 것만 알고 있자.


클래스 변수와 지역변수, 정적변수등 초기화에 대해 명확히 기억하지 못하고 대충 그럴것이다 생각했었는데
다시한번 보고 넘어가자는 의미에서 정리하였다..

출처:
http://www.it-bank.or.kr/prom/java_main.htm

반응형
자바는 3가지 계열로 볼 수 있습니다.

J2SE, J2EE, J2ME...

J2SE 계열은->개발자 계열이며,

J2EE 계열은-> 웹 어플리케이션 계역

J2ME 계열은->모바일 계열로 생각하시면 됩니다.

물론 이에 따라 각 각의 자격증이  존재합니다.

자바 자격증중 가장 기본이 되는 자격증은 SCJP자격증 입니다.

SCJP란?

SCJP 자격증은 J2SE (Java 2 Platform, Standard Edition) 기반의 Java Programming 언어에 대한 기본적인 지식을 기반으로 Java의 능률성을 실행하는데 관심이 있는 프로그래머들을 위한 자격증입니다.

자바 프로그래머라면 기본적으로 본 자격증을 취득하시기를 권장해 드립니다.


J2SE   -> SCJD

SCJD는 자바 개발자로서의 능력을 검증해 주는 국제공인 자격증으로 웹프로그래머나 기업자바개발자(EJB) 등 다양한 유형으로 경력을 쌓을 수 있는 보증수표라 할 수 있습니다
 

SCJD를 취득하기 위해서는 크게 2가지의 시험을 치뤄야 합니다.
우선 프로그래밍 과정(Programming Assignment)을 거쳐야 합니다.

이는 자바 전반에 관한 지식과 이해력을 바탕으로 직접 프로그래밍해 업 로드하는 방식으로 치뤄지며, 프로그램 디자인의 분석 능력과 실무 능력을 검증한다.
자바 실무능력 검증에 주안점을 둬 데이터베이스(DB)와 네트워크에 관련된 기술과의 연관성도 측정한다.

두 번째는 필기 시험으로 본인이 구성한 프로그램을 바탕으로 이론과 실무에 대한 종합적인 자바 개발능력을 검증한다.


J2ME   -> SCMAD

SCMAD는 J2ME 어플리케이션을 개발하는 Programmer와 Developer를 위한 시험으로서, CLDC (Connected, Limited Device Configuration) 1.0 및 1.1, MIDP(Mobile Information Device Profile) 2.0 스펙을 기반으로 하고 있으며, WMA(Wireless Messaging Application) API(어플리케이션 프로그래밍 인터페이스)와 MMAPI(Mobile Media API) 등 ‘무선 산업을 위한 자바 기술(JTWI)’이나 기타 무선 자바 기술들을 능숙하게 사용하고 있는지를 객관적으로 검증해주는 시험입니다.


J2EE   ---> SCWCD, SCBCD


SCWCD란?

SCWCD 자격증은 Java Technology Servlet과 JSP(JavaServer Pages) APIs(Application Program Interface) 웹 어플리케이션을 사용하는 Java 2 Platform 개발자들의 능력을 검증하기 위한 자격증입니다.

이에 따라 본 자격증은 Java Servlet과 JSP APIs를 이용하여 Web-tier를 프로그래밍하는 능력을 검증하여 기술 경쟁력을 제공합니다.

이 자격시험에 응시하기 위해서 반드시 Java 2 Platform(버전무관)의 썬 공인 프로그래머 자격(SCJP)을 취득한 상태여야 한다. 시험에 응시하기 전에 웹 어플리케이션 개발을 위해 Servlet과 JSP (JavaServer Pages)를 사용하여 최소 6개월 이상의 개발경험이 있는 개발자들에게 추천해 드립니다.

SCBCD란? 

SCBCD (Sun Certified Business Component Developer for the Java 2 Platform, Enterprise Edition 1.3) 자격증 시험은 EJB (Enterprise JavaBeans) 어플리케이션을 설계, 개발, 테스트, 구현 및 통합하는 업무를 담당하는 프로그래머나 개발자들을 위한 자격증 시험입니다.

또한, J2EE 플랫폼 (Java 2 Platform, Enterprise Edition) 기술을 도입하여 어플리케이션의 비즈니스 로직을 캡슐화하는 서버 사이드 컴포넌트를 개발하는 전문성을 가진 개발자들을 위한 자격증 시험입니다.

SCBCD 자격증 응시를 위한 선수조건은 반드시 SCJP를 취득하셔야 합니다.


SCEA란?

SCEA는 높은 확장성과 유연성, 보안성을 자랑하는 Compliant applications인 J2EE Technology (Java 2 Platform, Enterprise Edition)를 설계하고 디자인하는 업무를 담당하는 엔터프라이즈 설계자들을 위한 자격증입니다.

본 자격증은 1단계 객관식 시험과 2단계 설계 및 디자인 프로젝트 프로그래밍 시험, 그리고 3단계 논술시험으로 구성되어 있으며 3단계까지 Pass 하셔야 자격인증이 부여됩니다.

시험은 프로메트릭 센터에서 보실수 있으며,

집에서 가까운 프로메트릭 센터를 검색하셔서 시간과 날짜를 정하시면 됩니다.

응시료는 바우처값이 20만원으로 바우처를 구입하신 후 응시하시면 됩니다.

혹시라도 도움이 되실까 해서 자바 실무강의 및 자격증 대비 교육도 진행되고,

시험도 학원자체에서 볼수 있는 센터 남겨드리니 알아보시는데 참고하세요^^


자바 강의 진행 및 프로메트릭 시험센터-> http://www.webwill.co.kr

자바는 다음 자격증으로 구분되어있습니다. 프로그래밍 방법이나 능력에 대한것입니다.

 
 
반응형
Enumeration : 자바 초기버젼에서 개발된 것으로, HashTable과 Vector에서 사용가능
Iterator : jdk 1.2버젼에서 개발된 것으로, Collection 인터페이스를 구현한 모든 클래스에서 사용가능.

API를 확인해볼까요??
Vector와 HashTable에 있는 메소드입니다.
사용자 삽입 이미지
(HashTable에는 Enumeration 타입의 key()메소드도 존재합니다.)

하지만, ArrayList, LinkedList, HashMap에서는 찾아볼 수 없었습니다.
iterator는 HashTable이든 HashMap이든, Vector든 LinkedList든,
모두 쓸 수 있다는 것이죠.

Iterator에 대해서는 저번에 알아봤으니까.
이번에는 Enumeration의 API를 간단하게 뒤져봐야겠네요.

hasMoreElements

boolean hasMoreElements()
Tests if this enumeration contains more elements.
Returns:
true if and only if this enumeration object contains at least one more element to provide; false otherwise
Iterator의 hasNext()와 똑같은 일을 하는군요!!

nextElement

E nextElement()
Returns the next element of this enumeration if this enumeration object has at least one more element to provide.
Returns:
the next element of this enumeration.
Throws:
NoSuchElementException - if no more elements exist.
다음 elements가 존재하지 않으면, Exception이 발생하네요 ㅋㅋ
이것 또한 Iterator의 next()와 같아 보이는군요..ㅋㅋ

Vector의 요소들을 출력하는 예제입니다.
for (Enumeration e = v.elements() ; e.hasMoreElements() ;) {
System.out.println(e.nextElement());

}
자 그럼, 본격적으로 차이점에 대해서 알아보도록 합시다.

Snap Shot
Enumeration과 Iterator의 가장 큰 차이점은 바로 Snap Shot입니다.
Enumeration은 Snap Shot을 지원합니다. 여기서 'fail-fast
'라는 개념이 나오는데요.
Iterator는 fail-fast 방식이라고 합니다.
그럼 과연 이것이 무엇일까요?? 좋은 아티클이 있어서 긁어왔습니다...-ㅅ-;;

Fail-Fast

자바 2 이전 버전에서 사용되던 Vector, Hashtable의 뷰 객체인 Enumeration은 fail-fast 방식이 아니었으나, 자바 2의 콜렉션 프레임워크에서 콜렉션 뷰인 Iterator, ListIterator 객체는 fail-fast 방식이라는 점이다.

콜렉션 뷰는 콜렉션 객체에 저장된 객체들에 대한 순차적 접근을 제공한다. 그러나, 뷰 객체인 Enumeration 또는 Iterator 객체를 얻고 나서 순차적 접근이 끝나기 전에 뷰 객체를 얻은 하부 콜렉션 객체에 변경이 일어날 경우, 순차적 접근에 실패하게 된다. 여기서 변경이라는 것은 콜렉션에 객체가 추가되거나 제거되는 것과 같이 콜렉션 구조의 변경이 일어나는 경우를 말한다.

이런 상황은 멀티쓰레드 구조와 이벤트 구동 모델에서 일어날 수 있으며, 개발자가 혼자 테스트할 경우 발견하기 어려운 문제이다. 따라서 정확한 이해와 예상이 필요하며, 이에 대한 대처 방안을 마련해야 한다.

하부 콜렉션 객체에 변경이 일어나 순차적 접근에 실패하면 Enumeration 객체는 실패를 무시하고 순차적 접근을 끝까지 제공한다. Iterator 객체는 하부 콜렉션 객체에 변경이 일어나 순차적 접근에 실패하면 ConcurrentModificationException 예외를 발생한다. 이처럼 순차적 접근에 실패하면 예외를 발생하도록 되어 있는 방식을 fail-fast라고 한다.

Iterator는 fail-fast 방식으로 하부 콜렉션에 변경이 발생했을 경우, 신속하고 결함이 없는 상태를 만들기 위해 Iterator의 탐색을 실패한 것으로 하여 예외를 발생하며, 이렇게 함으로써 안전하지 않을지도 모르는 행위를 수행하는 위험을 막는다. 왜냐하면 이러한 위험은 실행 중 불특정한 시간에 멋대로 결정되지 않은 행위를 할 가능성이 있기 때문에 안전하지 않다고 할 수 있기 때문이다.


멋집니다..-ㅅ-; 더이상 설명할 것이 없을 것 같은데요.
흐음.. 일단 정리를 해보면, iterator는 일종의 pointer가 있습니다.
예전에 LinkedList 개념을 그림으로 그려보았는데요.
그거랑 매우 비슷합니다.

사용자 삽입 이미지

포인터가 Array의 자기자신과 다음 객체를 가르키는 것이지요.
그래서 위에 아티클에 써져있는 것처럼 삭제나 수정시 참조무결성 원칙에 어긋나게되어서
에러가 발생하게 되는것입니다.

아티클에 SnapShot에 대한 좋은 내용도 있더군요.

스냅샷

이처럼 콜렉션 뷰 객체인 Iterator와 ListIterator 객체가 fail-fast 방식인 이유는 스냅샷에 대한 보장을 포함하고 있지 않기 때문이다. 즉, 콜렉션의 뷰인 Iterator 객체를 얻었을 때 그 순간의 상태를 따로 생성하지 않기 때문에, Iterator 객체에서 순차적으로 하부 콜렉션 객체를 접근할 때, 콜렉션 객체의 변경에 영향을 받게 된다.

따라서, 콜렉션 뷰인 Iterator를 통하여 순차적 접근을 행하는 도중에 하부 콜렉션 객체에 변경이 일어날 가능성이 있는 경우 스냅샷을 명시적으로 생성하는 것이 좋다. ArrayList를 이용한 스냅샷을 생성하는 간단한 방법은 다음과 같다.

public Iterator snapshotIterator(Collection collection) {
return new ArrayList(collection).iterator();
}

이렇게 스냅샷을 이용하면 스냅샷이 생성된 순간의 상태에 대하여 Iterator를 통한
콜렉션의 뷰를 생성하게 된다. 하부 콜렉션의 변경이 일어나도 스냅샷에는 반영되지
않으며 Iterator는 실패없이 실행된다.

콜렉션 계열 중에 ArrayList를 사용하는 이유는 다른 콜렉션 계열 클래스들보다 생성과순차적 접근이 빠르기 때문이다. ArrayList가 삽입과 삭제에 불리한 단점이 있으나
이 경우에는 삽입과 삭제가 없으므로 고려되지 않는다.


조금 더 쉽게 정리를 해보자면,
Enumeration은 객체를 복사해서 저장합니다. 그래서 삭제나 수정시 전체 콜렉션에는
큰 타격을 주지 않는다는 것이죠.

Synchronization

제가 원래 알고 있던 지식은 "Enumeration은 동기화를 지원한다." 였는데,
어디서 잘 못 주워들었나봅니다. -ㅛ-
아티클에 <<콜렉션 프레임워크의 클래스들은 동기화를 보장하고 있지 않다.>>
라고 써져있더라구요. 그래서 찾아보았습니다. 역시 API에서 Enumeration부분을 봐도,
동기화에 대해서 정의된 부분은 찾을 수 없더라구요.
하지만,  Vector와 ArrayList의 차이점을 공부한 글에서도 알 수 있을 듯이
Vector는 동기화가 아주 넘쳐납니다-ㅅ-; 그러한 사실은 이클립스에서 Vector.class를
가보면, synchronized로 도배가 되어있는 것을 볼 수 있답니다.

아티클에는,
<<멀티쓰레드에서 콜렉션 구현 객체에 동시에 추가, 삭제를 위한 접근이 행해진다면, 그러한 행위가 발생하는 부분에 동기화를 명시적으로 해주어야 한다.>>
라고 써져있더군요. 방법까지 친절하게 명시해주고 있었습니다.
요렇게-ㅅ-;

Collection c = Collections.synchronizedCollection(myCollection);

결론적으로, Enumeration과 Iterator 사이에서 뚜렷하게 차이를 보이는 점은
 "스냅샷을 지원하느냐 하지 않느냐" 라는 것 같습니다.
아티클에서는 "Fail-fast Iterator에 대한 멀티쓰레드 무결성 해결방법" 이라는 제목아래 글을 써내려가고 있는데요. 스냅샷과 동기화가 Iterator의 멀티쓰레드 무결성 해결방법으로 제시되었고, 그와 함께 예시 소스코드도 보여주고 있습니다. 그러니까 Iterator가 스냅샷을 지원하지 않아도, 스냅샷을 명시적으로 생성할 수 있다는 것입니다. 이런건 한번 소스코드를 작성해봐야 확실히 알 수 있겠네요. 일단 이번 포스팅은 여기서 마치고, 소스코딩을 야심차게 시작해보도록 하겠습니다.-ㅛ-; 아자 +ㅅ+ ㅋ
< 출처: http://happystory.tistory.com >
반응형
일단, LikedList에 대하여 살펴봐야겠군요.
1학년때 교재로 썼던 <<Absolute Java>>를 보면,
Liked Data Strutures라는 챕터가 있습니다.
아래는 Introduction에 있는 내용인데요. 야심차게 해석을..-ㅅ-;

A linked data structure consists of capsules of data, known as nodes, that are connected via things called links. These links can be viewed as arrows and thought of as ane-way passages from one node to another. The simplest kind of liked data structure consists of a single chain of nodes, each connected to the next by a link; this is known as a linked list.

linked data structure은 node라고 알려져 있는 data의 캡슐로 구성되어 있다.
이는 link라 불리우는 것을 매개로 하여 연결된다. 이러한 link는 하나의 node에서 다른 node로 가는 한방향의 통로로 간주 될 수 있다. (화살표로 표시된다.)
linked data structure의 가장 간단한 종류는 일련의 단일 node로 구성되어 있다.
각각은 다음 link까지 연결된다. 이러한 것을 linked list라 한다.

워... 큰일났다... 무지하게.. 난해하네요..-ㅅ-;
이걸 이해하려면.. 자료구조를 공부해야겠는데요...-_ㅠ

그러는 와중에.. 저의 구세주 zerry82님께서 등장하셨습니다.!!!
친절한 설명 감사드립니다 ^ ^
그림으로 표현해보면,

사용자 삽입 이미지

멋진 것이었군요+ㅁ+
그렇다면, ArrayList와 LinkedList의 차이점 쯤은 금방 알 수 있겠군요.

여러가지 문서가 있었는데.. '속도'부분에서 많은 논란이 있더라구요.
일단은 괜찮은 영어문서가 있길래.. 무턱대고 해석 들어갔습니다-ㅅ-;

There are two general-purpose List implementations in the Collection Framework, ArrayList and LinkedList, which of the two List implementations you use depends on your specific needs. If you need to support random access, without inserting or removing elements from any place to other than the end, then ArrayList offers you the optimal collection, the LinkedList class provides uniformly named methods to get, remove and insert an element at the beginning and end of the list.

콜렉션 프레임워크에는 ArrayListLinkedList를 병용하는 List implementations1 이 있다.
이것은 당신이 특정한 필요에 의해서 사용하는 두가지 List implementations이다.
만약 당신이 끝 이외에 어디에서든지 요소를 제거하거나 삽입하는 것 없이 자유롭게 접근하는 것이 필요하다면, 그땐, ArrayList가 당신에게 최적의 콜렉션을 제공한다.
LinkedList
클래스는 리스트의 처음과 끝에 요소을 제거하거나 삽입하는 메소드를 제공한다.

Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.

각각의 ArrayList 인스턴스는 용량을 가지고 있다. 용량은 리스트에서 요소들을 저장하기 위해 사용되는 array 크기이고, 언제나 적어도 리스트의 크기만큼 커야한다. 요소들이 ArrayList 추가될 , 그것의 용량은 자동으로 증가한다. 증가방법에 대한 자세한 사항은 지속적으로 상환되는 시간비용을 가진 요소를 더하는 사실 이외에는 기술되어지지 않는다.

An application can increase the capacity of an ArrayList instance before adding a large number of elements using the ensureCapacity operation. This may reduce the amount of incremental reallocation.

에플리케이션은 ensureCapacity 기능을 사용하여 많은 수의 요소들을 추가하기 전에ArrayList 인스턴스의 용량을 증가시킬 있다.
이러한 것은 많은량의 재배치 증가를 감소시킨다.

그렇지요!! 정리를 해보자면,

more..


출력은 다음과 같습니다.
                    [뎅뎅이, 붉은돼지, zerry, Real Study, java, jsp, html/css]
                    첫번째 : 뎅뎅이
                    [Real Study, 뎅뎅이, 붉은돼지, zerry, java, jsp, html/css]
                    [Real Study, 뎅뎅이, 붉은돼지, zerry, java, jsp]
                    첫번째 : Real Study

소스코드를 보면 아시겠지만, addFirst()라던지.. removeLast()라던지
LinkedList에는 ArrayList의 메소드 이외에 추가, 삭제하는 메소드가 추가되어있습니다.
(API 참조 !!)
제가 작성한 코드는 간단한 코드라 아직까지는 그 중요성이 와닿지 않지만,
이러한 것들이 모이다보면..-ㅅ-;
LinkedList가 ArrayList보다 훨씬 빠른성능을 보여주겠지요??
(스택,큐,양방향큐 를 만들 때 편리하게 사용된다는데요. 이건 뭔지 잘 몰라서-ㅅ-;)

< 출처: http://happystory.tistory.com >
반응형
Enum..일단 에자일 책에서 처음 본 신개념입니다.
일단 정의부터 살펴보도록 하지요.

Enum : 정해진 리스트에서만 값을 선택할 수 있다.
            컴파일러가 지원하는 primitive타입이 아니라
            컴퍼일러가 클래스로 변환시킨다.
            불필요한 상수값 부여를 막을 수 있다.
            코드가 간결해진다.

책에 나와있는 소스코드를 보면,
               
enum Grade { A, B, C, D, F };

요런식으로 선언해줍니다.
Grade enum은 다섯 개의 가능한 값을 가지고, 각각은 객체 인스턴스를 표현합니다.

               public static void main(String[] args){

                     System.out.println(Grade.A);

               }

이런식으로 써줄 수 있지요.

이렇듯, Enum은 기본적으로 static입니다.
Enum클래스를 상속받은 static final class로서,
내부요소들은 해당클래스의 인스턴스를 가지게 되지요.

이걸 증명해줄만한, 재밌는 내용이 있어서 가져와봤습니다.1

enum으로 작성한 것을 jad라는 역컴파일러를 통해서 풀어준 코드입니다.

사용자 삽입 이미지

↓ jad로 변환

사용자 삽입 이미지

신기하지요?+ㅅ+ 스터디시간에 발표했던 내용인데, 복습할 겸.. 다시한번 올려봅니다.ㅎ

그때 알고 넘어간 Enum에 관한 사항은 여기까지입니다.
정말 더 깊이 공부하고 싶은 마음은 굴뚝 같으나..-ㅅ-;
아직까지는 너무 어렵네요.
너무 신개념이라 API를봐도 메소드의 정확한 사용법을
알아내기가 쉽지가 않네요.

일단 저 멀리 안드로메다 수준까지 정리를 해 놓으신 zerry님의 글을
트랙백으로 남겨놓겠습니다.-ㅅ-;
두고두고,, 천천히 봐야지.. 한번에 보려니까 머리가 너무 아프네여 ㅠ ㅎ
반응형
아래 그림에서 볼 수 있듯이 Collection과 Map은 따로 존재합니다.
저는 지금까지 Collection 인터페이스를 Map, Set, List가 구현하는 줄 알았는데,
아니더라구요. 이러한 사실은 API를 봐도 알 수 있습니다.

사용자 삽입 이미지

                        List : 순서(index)를 알고 있는 컬렉션.
                        Set : 중복된 것을 허용하지 않는 컬렉션.
                        Map : 키-값 기능 제공.

이러한 개념은 실제 코드를 작성해봐야 알 수 있지요?
에자일 자바책 9장에 이러한 내용이 깊~~게 언급되므로
그때 좀 더 자세히 알아보도록 하겠습니다.-ㅅ-ㅎ


에자일자바 5장을 보면 Collections.sort()가 등장합니다.
Collection이라는 인터페이스 외에, Collections라는 유틸리스 클래스가 또 존재하는데요.
API를 살펴보니, Collection에는 메소드가 거의 없드라구요.
sort()또한 보이지 않았습니다.
sort()는 Collections에 static으로 선언이 되어있습니다.
아래 Collections API를 보면,
사용자 삽입 이미지
-ㅅ-;;;
난해합니다. -_ㅠ
일단 필드와 메소드를 보고 유추해본 결과,
Collections클래스는 List, Set, Map에서 공통으로 사용되는 메소드를 모은
유틸리티 클래스라고 볼 수 있지 않을까 생각됩니다.

static으로 선언되어 있기 때문에
Collections.sort()로 편하게 사용할 수 있습니다.

다음으로 정말 중요한 iterator()입니다.
iterator()는 Iterator타입의 객체를 리턴하는데요.
이 객체를 사용해서 콜렉션 안에 있는 모든 엘리먼트를 하나하나 검색할 수 있습니다.
참 바보스럽게도, 전 여지껏 Iterator라는 인터페이스 없이
iterator()메소드만 Collection, Set, List에 각각 존재하는 줄 알았습니다.-ㅅ-;
하지만, 아니더라구요 ㅎ API를 보면 알 수 있습니다.
Collection, Set, List 인터페이스는 Iterable인터페이스를 구현합니다.
Iterable인터페이스를 보면,
사용자 삽입 이미지
iterator()메소드가 있는것을 볼 수 있습니다.
보면, 메소드가 Iterator형인 것이 확인되지요??
짧은 영어로 해석을 해보면,
<T>타입 요소의 집합을 건네주는 iterator을 리턴한다.-ㅅ-;

그니까.. 제너릭으로 한정한 타입의 요소의 집합으로 iterator을 리턴한다는 뜻이겠지요?

그렇다면.. 이번에는 Iterator인터페이스를 뒤져보도록 하겠습니다.
다음과 같은 메소드들이 존재합니다.

사용자 삽입 이미지

boolean hasNext()
Returns true if the iteration has more elements. (In other words, returns true if next would return an element rather than throwing an exception.)
Returns:
true if the iterator has more elements.
=> 만약 다음에 불러올 요소들이 더 있다면 true을 리턴한다.
    다시말해서, 만약 next가 엘리먼트를 리턴하면 true를 리턴한다.

직역을 하면 도저히 이해하기가 힘들 것 같아서, 엄청난 의역을 해야만 했습니다.ㅎ
제가 이해한 바로는 next()메소드를 통해서 콜렉션에 저장된 다음 요소가 리턴되면
hasNext()는 true를 리턴하고, 리턴될 다음 요소가 없어도
exception은 발생하지 않는다는 것이지요..?ㅋㅋㅋ

그렇다면, 다음으로 next()메소드를 살펴봅시다. 이것을 보면 더욱 이해가 잘됩니다.
E next()
Returns the next element in the iteration. Calling this method repeatedly until the hasNext() method returns false will return each element in the underlying collection exactly once.
Returns:
the next element in the iteration.
Throws:
NoSuchElementException - iteration has no more elements.
=> 반복하면서 다음 요소를 리턴한다.
    이 메소드는 hasNext()메소드가 false를 리턴할 때까지
    기초가되는 콜렉션에 있는 각각의 요소를 정확하게 한번씩
    반복적으로 리턴할 것이다.

영어는 역시 어렵습니다..-_ㅠ
위에 hasNext()메소드에 대한 설명을 보충해주고 있지요??
이래서 API는 보고나면 재밌습니다... 볼때는 괴롭지만 ㅎㅎ

마지막으로 remove()가 있는데, 이것은 Collection안에 있는 모든 요소를 검색하여
어떤 조건을 만족하지 않는 요소를 제거할 때 사용하는데요.
좋은 소스코드가 있습니다.

                        static void filter(Collection c) {
                            Iterator i = c.iterator();
                            while (i.hasNext()) {
                            if (!cond(i.next())) i.remove();
                            }
                        }

                    hasNext()가 true일 경우에만 if문을 반복하는 것입니다.
                    제시하는 조건을 만족하지 않을경우,
                    remove()메소드를 사용해서 해당하는 요소를 제거해줍니다.

iterator() 이전에 Enumeration이 쓰였다고 하는데요.
iterator()와 Enumeration의 차이점은 다음에 포스팅 하도록 하겠습니다.
차이점을 공부하다보면, iterator()에 대해서도 더 자세히 알 수 있겠지요?
출처 : http://happystory.tistory.com
반응형
향상된 for 루프는 J2SE 5.0에서 새로운 언어기능으로 소개된 것으로,
Iterator를 생성하거나, 카운트 변수의 시작과 끝을 계산할 필요 없이
콜렉션을 반복 할 수 있게 해줍니다.

일단, 기본적인 Array에서 향상된 for loop의 사용을 비교해도록 하겠습니다.

more..


이전에 제가 작성한 코드입니다. 이것을 향상된 for문으로 더 간단하게 만들어보겠습니다.

more..



무지 신기하지요??+ㅛ+
자 이제, 이게 어떻게 변하는 가를 설명하도록 하겠습니다.
기존에 for문은 카운트 변수의 시작과 끝을 계산해야했습니다.
즉, row = 0 이고, row가 rowLand(지뢰의 세로 길이 - scanner을 통해서 받은 값)보다
작을 때까지만.. row을 계속 늘려줘라-ㅅ-; 뭐 요런 것인데요.
향상된 for문을 보면
for(String[] row : landMine)

이런식으로 간단하게 줄여졌습니다.
이는, "landMine이라는 이름의 배열의 엘리멘트(row) 반복"으로 읽을 수 있습니다.
자동으로 엘리멘트의 길이를 측정한다고 볼 수 있겠네요..

향상된 for loop의 기본 syntax을 다음과 같이 나타낼 수 있습니다.
   	EnhancedForStatement:
for ( Type Identifier : Expression )
Statement   
Expression must be an instance of a new interface
    called java.lang.Iterable, or an array.

Expression java.lang.Iterable 또는 array라 일컬어지는
새로운 인터페이스의 인스턴스야만 한다.


향상된 for loop에도 단점이 있다고 합니다.

So when should you use the for-each loop? Any time you can. It really beautifies your code. Unfortunately, you cannot use it everywhere. Consider, for example, the expurgate method. The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove. Therefore, the for-each loop is not usable for filtering. Similarly it is not usable for loops where you need to replace elements in a list or array as you traverse it. Finally, it is not usable for loops that must iterate over multiple collections in parallel.

당신은 for-each(향상된 for) 루프를 언제 사용하여야 하는가?
언제든지 가능하다. 그러면 당신의 코드를 정말 아름답게 할 것 이다..-ㅅ-;;
허나.. 불행하게도, 당신은 for-each를 어디에서든지 사용할 수 없다.
예들들어, 삭제 메소드를 고려해보라. 프로그램은 현재 element을 제거하기 위해
iterator에 접근하는 것을 필요로 한다. for-each loop는 iterator를 숨긴다.
그래서 당신은 remove을 부를 수 없다.
그러므로, for-each loop는 필터링에 쓰기에는 편리하지 않다.
유사하게, 당신은 콜렉션을 순회하면서,
list나 array에 element들을 바꾸는 것을 필요로 할 때, 적합하지 않다.
마지막으로, 동시에 복합적인 콜렉션을 되풀이하는 것은 적합하지 않다.

아 ! 그리고,
지뢰찾기 자료 입력 부분도 for-each문으로 바꿔보고자 했는데,
잘되지가 않아서.. 많은 블로그를 돌아다니면서 예제를 찾아보았는데요.
자료를 입력해주는 부분에는
향상된 for 루프를 사용하지 않고, 일반 for loop를 사용하드라구요.
좀 더 조사해봐야 할 것 같네요.-ㅛ-

자자자자자 그렇다면,
ArrayList와 같은 콜렉션에서 향상된 for loop(for-each)는
어떻게 쓰여질까요??(제너릭과 iterator(), hasNext()등등의 사용..-ㅅ-)
그것은...............
콜렉션에 대해 좀 더 공부하는 시간을 가진 후에,
그때 다시 포스팅하도록 하겠습니다. +ㅅ+ ㅋㅋ
위에 해석한 단점도.. 그때서야 비로소 이해할 수 있을 것 같네요-ㅛ-;

< 출처: http://happystory.tistory.com >
반응형

(1) [2006-12-27] 특집5부_ARM과 파워PC에 기반한 임베디드 프로그래밍 최적화 기법
(2) [2006-12-27] 특집4부_성능 이슈 해결을 위한 닷넷 프로그래밍 최적화 기법
(3) [2006-12-27] 특집3부_리팩토링을 이용한 자바 성능 최적화 기법
(4) [2006-12-26] 특집2부_OOP적 개발을 위한 C++ 프로그래밍 최적화 기법
(5) [2006-12-26] 특집1부_개발 환경의 변화와 대응하는 프로그래밍 최적화의 재발견

출처: http://www.dbguide.net/know/know101003.jsp?IDX=1164&K=TITLE&K2=REGID&V=¨?¨????%20?????¡?&catenum=14

분야별 특성에 맞춘 Programming Optimization



프로그래밍 최적화. 코드 몇 줄을 줄이고 실행 속도를 높이기 위해 머리를 쥐어짜던 시절이 있었다. 이미 추억 저편으로 멀어진 그 기억 속에서는 그런 것이 바로 프로그래밍 최적화였다. 그럼 하드웨어의 성능이 예전의 슈퍼컴퓨터와 맞먹을 정도로 높아진 지금, 프로그래밍 최적화가 대체 무슨 의미를 가질 수 있을까? 프로그램의 속도가 조금 빠르거나 느린 정도라면 이제 거의 체감할 수 없는 상황이 되지 않았는가. 성능이 아주 떨어지지만 않는다면 이제 약간의 실행 속도의 차이는 무의미해진 지 오래다. 이처럼 시대가 변했다고는 하지만 분명히 프로그래밍을 위해 갖춰야 할 최적화 항목들은 여전히 존재한다. 코드의 수를 줄이는 것이 아니더라도 OOP적 개발을 위한 기법들이 필요하고, 보다 개선된 프로그램을 위한 리팩토링도 필요하다. 심지어 예전처럼 속도를 따져야 하는 분야도 있다. 바로 임베디드 분야이다. 이번 특집에서는 각 개발 분야에서 중요하게 다뤄져야할 최적화 기법들에 대해 알아본다.


기획·정리
| 정희용 기자 flytgr@imaso.co.kr


리팩토링을 이용한 자바 성능 최적화 기법


허광남 | GS홈쇼핑 EC정보팀 과장


리팩토링, 복잡다단해지는 현대의 소프트웨어 개발에서 이 단어는 점점 중요한 위치를 차지해 가고 있다. 이제 리팩토링은 진정한 개발자의 덕목 중에 하나라고 단언할 수 있을 정도다. 리팩토링을 한다는 것은 개선에 대한 의지가 있음을 뜻하고, 좀 더 나은 코드, 구조, 프로세스를 지향한다는 의미가 된다. 리팩토링으로 소프트웨어의 성능을 직접적으로 높이지는 못 한다. 하지만 코드의 가독성을 증대시켜, 생각하는 프로그래머들의 머릿속 성능을 높여준다. 3부에서는 리팩토링 방법들에 대해 알아본다.


햄버거나 커피 등을 살 때, 또는 백화점이나 편의점에서 물건을 살 때, 우리는 1회용 물건을 쓰는 것에 대한 세금을 낸다. 1회용 물건을 쓰면 환경이 그만큼 빨리 피폐해지기 때문이란다. 그게 사실인지 아닌지 모르겠지만, 내 돈이 나가는 것은 용납이 안 된다. 1회용품의 편리함. 그 반대급부로 만들어지는 쓰레기 처리에 따른 비용을 지불한다고 하는데, 영 맘에 안 든다.

혹시 프로그램을 짤 때도 1회용 프로그램을 짠다는 생각을 해본 적이 있는가? 그런데 우리는 1회용 프로그램을 짜도 세금을 내지 않는다. 다행일까? 1회용 프로그램이 환경 자원을 소모시키지는 않는다. 다만 1회용 프로그램은 쓰레기를 양산한다. 그때 그때 필요한대로 찍어낸 프로그램은 수많은 중복코드를 양산해낸다. 재활용하지 않는 습관 탓에 시스템이라는 환경이 무거워지고 손이 많이 가도록 바뀌는 것이다.

재활용성은 객체지향 프로그램의 핵심원리 중의 하나이다. 재활용성을 높인다는 것은 찍어낼 때 사용하는 템플릿을 얘기하는 것이 아니다. 오히려 업무나 기능을 제어 가능한 곳에 집약시켜서 관리할 수 있도록 시스템 전체의 청결한 상태를 유지하는 것이다. 이리저리 산재된 중복 코드를 정리하는 것이 핵심이다. 이 때 필요한 기술이 리팩토링이다. 이쯤 얘기하면 리팩토링은 정리 정돈에 비견된다. 군대에서 총기수입을 하는 것과도 같고 집에서 설거지를 하는 것과도 같다.




리팩토링이란



Refactoring (Re + Factor + ing) 영어 단어를 요소별로 나눠보면 요소들을 재구성한다는 뉘앙스를 받을 수 있다. 이는 마틴 파울러의 책에서 비롯된 단어인데, 책에 있는 리팩토링의 정의를 보면 다음과 같다.

“리팩토링은 외부 동작을 바꾸지 않으면서 내부 구조를 개선하는 방법으로, 소프트웨어 시스템을 변경하는 프로세스이다.” 마틴 파울러, 리팩토링, P10. 대청출판사 책에 이어서 나오는 내용은 버그가 끼어들지 않도록 주의하면서 코드를 작성한 후에 더 나은 디자인으로 개선하는 방법이라고 한다. 디자인을 먼저 한 후 코드를 만드는 것이 아니라 일단 돌아가는 코드를 작성하고, 그 후에 그 코드가 더 좋은 구성을 갖도록 바꾼다는 것이다. 우리들의 코딩 관행을 돌아보면, 일단 돌아가는 프로그램을 짠다. 그리고? 끝이다. 그 다음으로 넘어간다. 정리? 남은 사람이 알아서 할 것이다. 남은 사람이 자기 밖에 없다면? 날 잡아서 정리하거나, 회사 옮긴다.




리팩토링을 하는 이유



야심찬 초급 개발자가 자주하는 것 중에 하나가 이전 소스에 대한 비평이다. “도대체 어떻게 이렇게 소스를 짤 수 있지. 발로 짜도 이것보다는 낫겠네. 왜 이렇게 if else가 많은 거야. 이 소스 이해할 시간 있으면 차라리 다시 짜고 만다.” 그래서, 다시 짠다. 그리고 오픈하면 이것 저것 버그 리포트와 요구사항이 들어온다. 이것 저것 예외 처리를 해주다 보면 내가 짠 코드지만 보기 싫어진다. 어느 정도 서비스가 안정적으로 돌아가도록 소스를 수정해 놓으니, 이런, 전에 내가 막 뭐라고 했던 이전 개발자의 소스와 별반 차이가 없다.

“제길, 다음 후임이 누가 될지는 몰라도 내 욕 무진장 하겠군.” 문서라도 잘 주면 모르겠지만, 처음 개발할 때 보고했던 문서 그대로다. 요구사항과 수정을 통해서 변경된 내용을 문서에 업데이트하질 못했다. “할 시간이 있어야지.” SM(System Maint enance)분야에서는 거의 이렇게 사는 것이 보통이다.

이전 사람이 만든 소스에서 버릴 것은 거의 없다. 정리가 안 되서 몇 달간 목욕 못한 모습일 뿐이지, 처리할 수 있는 모든 경우의 수는 그 안에 다 가지고 있다. 이런 코드를 새로 짠다는 것은 그 모든 경우의 수를 처음부터 다시 감수하겠다는 의미가 된다.
이전 소스를 씻기고 다듬는 것이 소스 수정을 위한 필수 과정이다. 정리하지 않고 계속해서 소스를 추가해 가는 일은 운동하지 않고 계속해서 먹어대는 것과 같이 시스템을 비만상태로 만들어간다. 움직임이 점차 둔해질 것이다. 정리 안 된 방처럼 발 디딜 팀이 없는 소스가 될 것이다.

무엇인가 소스의 변경이 필요할 때, 기능 추가나 삭제, 수정 작업이 일어날 때 소스의 리팩토링은 포장이사처럼 편하게 작업하도록 도와준다. 리팩토링은 소스의 중복된 부분을 모듈화 시켜준다. 모듈화는 입출력이 명확하기 때문에 이식성을 높여준다. 중복을 제거한다는 것은 시스템의 칼로리를 빼는 것과 같다. 시스템의 복잡도, 즉 코드를 읽는 사람의 머리가 열받는 정도를 낮춰준다. 물론 그렇다 해도 이사 자체는 귀찮은 일이다.




리팩토링을 위한 도구



리팩토링은 그로 인해 영향 받는 프로그램의 수가 적을 대에만 수작업으로 작업해야 한다. 사실 리팩토링을 수작업으로 한다는 것은 추천하지 않는다. 좋은 개발 환경이 있는데 사서 고생할 필요가 없는 탓이다. 리팩토링을 위한 좋은 툴이 많이 나왔다. 일단 통합개발환경(IDE, Integrated Development Environment)을 준비한다. 요즘의 자바 개발 시 많이 사용되는 IDE는 기본적으로 리팩토링을 지원한다.

리팩토링과 함께 진행되어야 할 JUnit 테스트케이스 자동 생성도 같이 지원되고 있다. 리팩토링 작업을 할 경우 여러 줄의 코드들이 수정된다. 이때 영향을 받는 프로그램들을 모두 불러내서 수작업으로 수정할 경우 리팩토링에 대한 공수가 많이 필요한 탓에 감히 리팩토링에 대한 엄두를 낼 수 없다. 하지만 요즘 통합 개발 환경을 지원하는 개발 도구들은 변경 받는 파일들의 목록과 변경 전 후의 코드 비교, 자동 변경 기능을 지원한다. 덕분에 리팩토링에 드는 수고가 전혀 수고로 생각되지 않을 정도다.




리팩토링 진행 방법



리팩토링하는 이유와 리팩토링 도구까지 알아보았으니 이제 리팩토링 방법에 대해 알아볼 차례다. 주저리 주저리 방법들을 늘어놓을 수 도 있겠지만 개발자는 코드로 얘기한다. 바로 이클립스에서 리팩토링을 사용하는 방법을 설명하도록 하자.


<리스트 1> 리팩토링 샘플
1 public void deleteArticle(Connection conn, int seq) throws SQLException {
2 if (conn == null)
3 return;
4
5 // db에서 삭제 - 삭제 테이블로 이동
6 PreparedStatement pstmt = null;
7 pstmt = conn.prepareStatement(QUERY_MOVE);
8 pstmt.setInt(1, seq);
9 pstmt.executeUpdate();
10
11 pstmt.close();
12
13 pstmt = conn.prepareStatement(QUERY_DELETE);
14 pstmt.setInt(1, seq);
15 pstmt.executeUpdate();
16
17 pstmt.close();
18
19 // memo 삭제 생략
20
21 }


리팩토링에 대한 간단한 예를 들기 위해서 <리스트 1>을 보며 설명하겠다. 7~11번 줄의 코드가 13~17번 줄의 코드와 유사한 것을 알 수 있다. 중복이 계속되는 것은 일정한 패턴을 갖고 있는데 중복이 심해지면 패턴 변경에 따른 공수가 많이 필요하므로 소스의 유연성이 떨어지게 된다. 때문에 반복되는 패턴을 메소드화 시켜서 쉽게 코드를 읽을 수 있도록 한다.

<화면 1> 반복되는 부분, 메소드 추출의 대상


<화면 2> 메소드 추출(Extract Method)

이클립스에서 패턴부분을 선택하고, 오른쪽 버튼을 눌러 콘텍스트 메뉴를 열면 중간 위치에 [Refactor…]라는 메뉴가 보인다. 확장 메뉴에서 [Extract Method…]를 선택하면 <화면 2>와 같은 다이얼로그 창이 뜬다. ‘doQuery’라고 메소드명을 입력한 뒤에 파라미터들을 확인한다.

화면 아래쪽의 버튼 중 [Preview]를 클릭하면 <화면 3>과 같이 미리보기 창으로 바뀐다. 이때 화면에 표시되는 정보들이 기가 막힌다. 리팩토링을 통해서 변경되는 소스의 비교와 상단에는 이 리팩토링에 영향을 받는 소스들과 메소드명까지 친절하게 알려준다. 게다가 이클립스가 모두 다 자동으로 바꿔준다.


<화면 3> 리팩토링 결과 미리보기


<화면 4>에서는 다이얼로그에서 만든 doQuery() 메소드의 내용을 볼 수 있다. 소스 비교란의 맨 오른쪽에 있는 네모는 소스 전체에서 변경이 일어난 부분을 표시한 것이다.


<화면 4> 리팩토링으로만들어진 메소드

비교가 끝났다면 [OK] 버튼을 클릭해서 리팩토링을 실행한다. 소스 리팩토링을 마친 뒤에 doQuery() 메소드를 보면, <화면 5>처럼 파라미터가 Connection conn, int seq 두 개임을 알 수 있는데, 여기에 하나가 더 필요하다. 바로 쿼리 부분인데, 이것을 파라미터로 받아야 비로로 doQuery()가 공용으로 쓰일 수 있게 된다.

<화면 5> 리팩토링으로 만들어진 약간 아쉬운 메소드

QUERY_MOVE라는 상수를 파라미터로 대치한다. 이 상수에 마우스 오른쪽 버튼을 클릭한 뒤에 [Refactor]-[Introduce Para meter] 메뉴를 실행시키면 <화면 6>과 같은 다이얼로그 창을 볼 수 있다. 새로운 파라미터 이름을 ‘query’로 정하고 우측의 [up] 버튼을 클릭해서 파라미터의 위치를 조정한다. 파라미터의 변경은 메소드의 모습인 시그니처(signature)를 변경하는 것이다.


마찬가지로 [Preview] 버튼을 클릭하면 <화면 7>과 같이 리팩토링 전후의 소스를 비교할 수 있다.

<그림 7>에서 [OK] 버튼을 클릭해서 만들어진 doQuery() 메소드는 반복되는 쿼리 실행 부분을 메소드 추출(Extract Met hod)과 파라미터로 빼기(Introduce Parameter) 리팩토링을 이용해서 만든 것이다. <리스트 2>는 그것을 이용해서 바뀐 소스의 모습이다.

<그림 7> 파라미터로 만들기 적용하기 전 미리보기


<리스트 2> QUERY_DELETE 부분 리팩토링 과정
1 public void deleteArticle(Connection conn, int seq) throws SQLException {
2 if (conn == null)
3 return;
4
5 // db에서 삭제 - 삭제 테이블로 이동
6 PreparedStatement pstmt;
7 doQuery(conn, QUERY_MOVE, seq);
8 doQuery(conn, QUERY_DELETE, seq);
9
10 pstmt = conn.prepareStatement(QUERY_DELETE);
11 pstmt.setInt(1, seq);
12 pstmt.executeUpdate();
13
14 pstmt.close();
15
16 // memo 삭제 생략
17
18 }

19 private void doQuery(Connection conn, String query, int seq) throws SQLException {
20 PreparedStatement pstmt = null;
21 pstmt = conn.prepareStatement(query);
22 pstmt.setInt(1, seq);
23 pstmt.executeUpdate();
24
25 pstmt.close();
26 }


<리스트 2>는 아직 변경 중인 샘플코드이다. 앞서 만든 doQuery() 메소드를 이용해서 쿼리만 다른 것을 보내면 된다. 필자가 추가한 8번 줄은 10~14번 줄과 동일한 기능을 수행하게 된다. 코드를 정리하면 다음과 같이 된다.


<리스트 3> QUERY_DELETE 부분 리팩토링 후
1 public void deleteArticle(Connection conn, int seq) throws SQLException {
2 if (conn == null)
3 return;
4
5 // db에서 삭제 - 삭제 테이블로 이동
6 doQuery(conn, QUERY_MOVE, seq);
7 doQuery(conn, QUERY_DELETE, seq);
8 // memo 삭제 생략
9
10 }


하단의 구문이 지워지면서 이 deleteArticle() 메소드 내의 PreparedStatement pstmt 선언은 불필요하기 때문에 삭제했다. 처음 보았던 소스에서 많이 정리되었다. 정리를 하고 보니 deleteArticle() 메소드를 호출하는 곳에서 비슷한 기능을 하는 부분을 볼 수 있다.


<리스트 4> 리팩토링 적용 범위 확대
1 // password 확인
2 if (confirmPassword.equals(MASTER_PASSWORD)
3 || confirmPassword.equals(article.getPassword())) {
4 deleteArticle(conn, seq);
5 deleteFiles(conn, seq);
6 } else {
7 resourceName = "/jsp/error.jsp";
8 throw new Exception(CommonUtil.k2a("잘못된 비밀번호"))
9 }

10 public void deleteFiles(Connection conn, int seq) throws SQLException {
11 if (seq == 0){
12 return;
13 }
14
15 // file db에서 삭제 - sts 값 0 로 변경
16 PreparedStatement pstmt = conn.prepareStat ement(QUERY_DEL_SEQ_FILE);
17 pstmt.setInt(1, seq)
18 pstmt.executeUpdate();
19
20 pstmt.close();
21
22 // file 삭제 생략
23 }


<리스트 4>의 16~20번 줄을 보면 앞서 추출한 메소드 doQuery()로 변경할 수 있을 것 같다. 그럼 코드는 <리스트 5>와 같이 수정될 것이다.


<리스트 5> QUERY_DEL_SEQ_FILE 부분 리팩토링 과정

10 public void deleteFiles(Connection conn, int seq) throws SQLException {
11 if (seq == 0){
12 return;
13 }
14
15 // file db에서 삭제 - sts 값 0 로 변경
16 doQuery(conn, QUERY_DEL_SEQ_FILE, seq);
17
18 // file 삭제 생략
19 }


이렇게 정리하고 난 후에 다시 전체적인 코드를 생각해보면 두 개의 메소드가 불필요하다 생각이 든다. 즉 <리스트 6>과 같이 deleteArticles()와 deleteFiles() 메소드를 지우고 바로 doQuery() 를 호출하도록 바꿀 수 있을 것이다. <리스트 6>은 리팩토링을 통해 최종적으로 정리된 소스이다.


<리스트 6> 리팩토링 적용으로 개선된 코드
1 // password 확인
2 if (confirmPassword.equals(MASTER_PASSWORD)
3 || confirmPassword.equals(article.getPassword())) {
4 // db에서 삭제 - 삭제 테이블로 이동
5 doQuery(conn, QUERY_MOVE, seq);
6 doQuery(conn, QUERY_DELETE, seq);
7 // memo 삭제 생략
8 // file db에서 삭제 - sts 값 0 로 변경
9 doQuery(conn, QUERY_DEL_SEQ_FILE, seq);
10 // file 삭제 생략
11 } else {
12 resourceName = "/jsp/error.jsp";
13 throw new Exception(CommonUtil.k2a("잘못된 비밀번호"));
14 }


앞에서 보았던 소스의 if else 구문과 비교해보면 doQuery() 라는 공통으로 사용할 수 있는 메소드와 5줄이 늘어났지만 deleteArticle(), deleteFiles() 두 개의 메소드가 사라졌다. 이전 소스와 비교해보면 메소드 구성은 <화면 8>과 같이 변경되는 것을 알 수 있다.

추가된 메소드는 +화살표, 제거된 메소드는 화살표로 표시되고 변경된 메소드는 그냥 검은 화살표로 표시된다. 화면 아래쪽에 표시되는 소스 비교하는 곳을 보면 더욱 명확하게 알 수 있다.

지금까지 샘플 소스의 구조를 개선하면서 두 가지 리팩토링 기법에 대해 알아보았다. 이 외에도 많은 기법들이 리팩토링 책에 소개되어있고, 이클립스에도 더 많은 리팩토링 기능이 지원된다.


<그림 8> 리팩토링 전 후 메소드 비교



리팩토링 경험담



필자는 이 글을 쓰고 있는 지금 큰 프로젝트를 진행하고 있다. 6년간 하나도 버려지지 않고 운영되면서 그때그때 패치된 페이지를 스프링 프레임워크에 맞춰서 바꾸는 작업이다. 그런데, 작업을 하는 동안 필자가 간과한 것이 있었다. 그렇게 복잡하게 얽히고설킨 페이지를 스프링 프레임워크의 새로운 바닥부터 하나씩 쌓아 올린 것이다. 기존에 운영하고 있는 소스에서 하나씩 뜯어서 새로운 토양으로 옮겨심기를 한 것이다. 이것은 재개발에 가까운 것이었고, 굉장히 많은 시간이 필요했다. 만약 옮겨야 할 소스를 기존의 토양 위에서 조금씩 리팩토링한 후에 옮겼다면 오히려 많은 시간을 절약할 수 있었을 것이다.

실수했다고 생각하는 부분은 다음과 같다. 우선적으로 모든 기능을 다 옮겨올 때까지 신규 페이지는 아직 미완성이다. 하지만 기존의 페이지 내에서 리팩토링을 한다고 하면 이미 모든 기능과 데이터를 다 갖고 있는 상태이다. 다른 파트에서 데이터가 필요하다고 할 때에도 현재 갖고 있는 데이터에서 데이터를 뽑아내서 보다 빨리 전달할 수 있을 것이다.

두 번째로 시간의 압박이다. 기존의 페이지는 언제든지 답이 나온다. 하지만 신규페이지는 모든 테스트를 마칠 때까지 계속 기다리라고 얘기해야만 한다. 바닥부터 모든 것들에 대해서 테스트를 만들어야 하는 탓에 더 많은 테스트 코드들이 필요하다. 여기에도 만만치 않은 시간이 투입된다.

세 번째는 애플리케이션에 대한 자신감이 떨어진다는데 있다. 맥가이버도 아닌데 시간에 쫓기면서 개발할 경우 만들어진 소스는 분명히 수많은 버그를 품고 있을 가능성이 높다. 그 값이 절대 정확하다고 이야기하기 힘들다. 하지만 리팩토링을 통해서 내부로부터 개혁해 나갈 경우 빠진 것 없이 소스를 재구성할 수 있기 때문에 안정된 기반에서 작업할 수 있을 것이다.

전산의 불문율 가운데 유명한 것이 하나 있다. ‘잘 돌아가는 것은 손대지 마라.’ 칼퇴근을 위해서 절대 절명으로 필요한 말이다. 이렇게 관리되는 소프트웨어의 품질은 논하기 힘들다. 그냥 먹고 살기 위한 프로그램과 그것을 관리하는 직장인이 되어버리게 된다. 반면에 리팩토링의 기본 사상은 개선을 위한 노력이다. 막무가내 개선이 아니라 현명한 개선을 위한 방법을 제시하고 있고, 친구격인 테스트 케이스가 그 안전장치가 되어 준다. 한 순간의 품질이 아닌 지속적인 소프트웨어의 건강을 생각한다면 꾸준히 리팩토링으로 손질할 필요가 있다. 그것이 끝없이 변하는 웹 애플리케이션과 같은 소프트웨어일 경우는 더욱 그렇다.
개선을 위한 작은 몸짓에 진정한 프로그래머가 되고 싶은 독자들을 초대한다.


참고 자료
1. 리팩토링, 마틴파울러, 윤성준,조재박 역, 대청, 2002년3월
2. 패턴을 활용한 리팩터링, 죠슈아 케리에브스키, 윤성준,조상민 역, 인사이트,
2006년7월


리팩토링 관련 사이트

1. http://www.refactoring.com/
Refactoring Home Page

2. http://xper.org/wiki/xp/ReFactoring
김창준 님의 Refactoring에 관한 정보

3. http://c2.com/cgi/wiki?CodeSmell
Code Smell

4. http://xper.org/wiki/xp/CodeSmell
Code Smell 번역

5. http://www.okjsp.pe.kr/lecture/ide/eclipse/refactor/eclipse_refactoring.html
Eclipse의 refactoring기능

6. http://www.okjsp.pe.kr/lecture/ide/eclipse/eclipse_install.html
Eclipse 시작하기


 



제공 : DB포탈사이트 DBguide.net

반응형

Jad Decompiler 사용법

Jad home page: http://www.geocities.com/SiliconValley/Bridge/8617/jad.html
Copyright 2000 Pavel Kouznetsov (kpdus@yahoo.com). 


[ 사용방법 ]


1. 클래스 하나만 디컴파일시

           example1.class   를 디컴파일시 

           jad.exe 를 디컴파일할 파일과 동일한 폴더에 놓는다.

         

           Command 창에   jad -o -sjava example1.class   

       

   결과물 : 'example1.java' 

   

2. Package 를 디컴파일시   

         tree  폴더 아래의 모든 클래스파일을 디컴파일시 

         폴더와 같은 폴더에 jad.exe  를 위치하고


          Command 창에    jad -o -r -sjava -dsrc tree/**/*.class 

          

          결과물 : 폴더내에 [src] 폴더가 생성된다. 

=============================================================================================================

윈도우버전(for Windows 9x/NT/2000 on Intel platform)


jad -r -d .\src -s java .\ifxjdbc\**\*.class


참고 : jad -r [-d<directory_for_sources>] [<other_options>] <directory_with_classes>**/*.class



설명 :


-r : 해당 패키지 형태로 디렉토리 구조를 만듬( restore package directory structure)

-d : 디컴파일될 디렉토리(-d <dir> - directory for output files)

 -s java : 디컴파일된 파일의 확장자를 java로 하라


.\ifxjdbc\**\*.class : ifxjdbc 디렉토리 아래의 모든 클래스들 지정



-----------------------------------------------------------------------------------------


이클립스 디컴파일러인 JAD를 설치하는 방법입니다.


이클립스로 개발을하다보면 F3버튼으로 열심히 따라가는 경우가생깁니다.


그러다 라이브러리로 묶여있는 클래스파일들을 로딩하게되면 읽긴읽되 내용을 분석하지못하죠~


그래서 디컴파일러 ~ 컴파일한클래스파일을 다시 자바파일로 보여주는 도구를 설치하게되면


클래스파일도 자바파일처럼 열수있게됩니다^^~



우선 jad.exe, jadclipse_3.1.0.jar를 다운로드 합니다.


jad.exe파일은 이클립스 폴더에 jadclipse_3.1.0.jar파일은 플러그인 폴더에 카피합니다.


window->preference->general->editors->file assosiationsd에서 *.class선택후


하단의 JadClipse Class File Viewr 를 선택후 default 를 선택합니다.


window->preference->java->JadClipse를 선택한후 ignore existing source를 체크해줍니다.


이렇게하시고 이클립스를 실행시키시면 *.class파일을 찾아갈경우 자동으로 디컴파일해줍니다~

http://sourceforge.net/projects/jadclipse



+ Recent posts