[Java] 자바란?

언어로그/Java 2013. 2. 16. 01:05


 

벌써 4년전입니다. 2009년도에 비트 자바고급반을 수강하면서 학습한 내용을 Springnote에 꾸준히 

정리했습니다.  Springnote 서비스가 종료되고, 그 때 백업해 두었던 글들을 하나씩 티스토리로 옮기고 

있는데... 열정과 흥미를 가지고 재미있게 공부했었던 그때 기억이 나네요. 





2. 자바란?

자바 언어의 개발사인 썬은 spac 이란 서버제품군을 제작하는 회사였습니다. 

낮은 H/W 마진을 개선하고자, 자사의 H/W 위에 마진이 높은 S/W(유닉스 등)를 얹혀서 팔려했는데

하드웨어마다 소프트웨어를 재작성해야 하는 문제가 있었습니다. 즉 다양한 머신 위에서

한번작성하면 동일하게 동작하는 S/W를 만들려는 노력해서 Java가 탄생하게 되었습니다

위키: http://en.wikipedia.org/wiki/Java_language





3. 자바의 장점

객체지향적, 플랫폼 독립적, 동적이고 배포하기 쉬우며... 견고하고 보안에 강하다!

하지만 객체지향적이고, 보안에 강하다는 특성을 살리는 것은 소프트웨어를 작성하는 개발자에 전적으로 

달려있답니다. (무서운 강사님의 말씀...)





4. 플랫폼 독립적?

c언어는 컴파일러가 머신에 의존적인 기계어 코드(실행파일)를 생성합니다. 유닉스, 리눅스, 윈도우, 맥에서 

실행하기 위해서는 소스 수준에서 재컴파일이 필요합니다. 

자바는 OS와 소스코드 중간에 JVM(Java Virtual Machine)이라는 중간계층을 두어 이를 해결했습니다. 

소스코드를 가산머신이 인식할 수 있는 중간언어인 바이트 코드로 컴파일해서 배포합니다. 그러면 각 OS에 

설치되어 있는 JVM이 바이트 코드를 기계어로 번역하여 실행합니다.

(단, 각 OS 마다 각 머신에 맞는 JVM이 설치되어 있어야 합니다. 한번만 설치하면 되니까 매번 소스를 

재컴파일해야 하는 것보다는 훨씬 유연성이 있죠)





5. 기업 인터넷 환경에서의 Java

유연성을 위해 3-Tier(프레젠테이션 계층-비지니스 계층-데이터(DB) 계층)의 형태로 구성됩니다. 

현재는 더욱 확장된 N-Tier로 구성된다고 하네요. 

PS. Three Tier를 삼-Tier로 읽는 센스 ㅋ





6. JVM 의 동작방식

클래스 로더가 소스코드를 스캔하여 모든 필요한 클래스를 로드합니다. 필요한 클래스 위치는 CLASSPATH 

환경변수를 참조하게 찾게됩니다. JVM Verifier 가 오작동 될 수 있는 코드(무한루프와 같은...)를 검사해서 

사전에 차단합니다. 이어서 바이트 코드를 실행하게 되는데, 이때 JIT(Just-In-Time) 컴파일러가 동작합니다. 

즉 소스코드와 (컴파일된 .class)클래스 파일의 수정일자를 비교해서, 소스코드가 더 나중에 수정됐을 경우에만 

재컴파일하게 됩니다. 

(PS. JIT를 도입해서 자바의 느린 성능을 어느정도 극복했고, 버전업 될때마다 크게 향상되고 있습니다.

      또 가비지 컬렉터라는 메모리 관리자가 더이상 사용되지 않는 객체를 수시로 검사하여 자동으로 메모리를 

     반환해줍니다)




7. 자바환경에서 보안 구현

언어차원과 컴파일러, 클래스 로더, 바이트코드 검증기(Verifier) 등 계층적으로 위해한 코드를 차단해줍니다.





8. 자바 애플리케이션의 배포방식

.zip 또는 .jar로 압축해서 배포합니다. .jar은 단순히 소스만 압축할 수도 있고, 클래스파일까지 함께 압축해서 

실행가능한 형태로 만들 수 있습니다. 웹에서는 .war 형태로 압축해서 배포됩니다. 





9. JDK(Java Development Kit)

통상 J2SE를 지칭합니다.컴파일러, 코어클래스 라이브러리, 디버거, JVM, JAR(Java ARchive utility) 등으로 

구성됩니다. Java 1.2버전 이후부터 대폭 내부구조가 개선되었는데 이를 표현하기 위해 1.2버전 이후부터는 

JAVA2라고 부릅니다. (웹2.0 처럼 큰 변화가 있었다는 의미이지요). 

JAVA2에는 J2SE, J2ME, J2EE 이렇게 3가지가 있습니다. 

J2ME는 모바일 환경의 S/W 작성을 위해 필요한 클래스만 추려낸 버전이고, J2EE는 기업환겨에 맞게 병렬실행 

등을 강화한 버전입니다. 




10. 자바빈즈(JavaBeans)

Beans는 땅콩을 의미하는 땅콩은 알맹이를 껍데이가 감싸는 형태로 되어있죠. 

클래스가 속성과 메소드를 깜싸고 있는 모습이 흡사 땅콩과 같다해서 자바빈즈라고 부릅니다. 

보통 프레임워크에서 데이터 속성과 표준화된 getter, setter를 갖는 클래스를 빈즈라고 합니다. 





11. 기본형 데이터 타입

기본형 

크기

Wrapper 클래스 

비고 

boolean 

 16비트

Boolean 

true, false 

 char

8비트 

Character 

유니코드 사용 

 byte

8비트 

Byte 

 

 short

16비트 

Short 

 

int 

32비트 

 Integer

 

long 

 64비트

 Long

 

 float

32비트 

 Float

 

double 

64비트 

 Double

 






'언어로그 > Java' 카테고리의 다른 글

[java] 글 목록  (0) 2015.09.03
[Java] 자바란?  (0) 2013.02.16
[java] 라이프 게임 (life game)  (1) 2013.02.03
[java] 제13회 한국자바개발자 컨퍼런스  (0) 2013.01.30
Inner Class(내부 클래스)  (0) 2011.04.12
컬렉션(Collection)  (0) 2011.04.11

[java] 라이프 게임 (life game)

언어로그/Java 2013. 2. 3. 00:44




스프링노트를 운영하던 시절 썼던 글인데 티스토리로 옮기면서 다시 읽어 보니 감회가 새롭네요


요즘엔 AWT/Swing 이 거의 쓰이지 않지만 이때 공부했던 GUI 프로그래밍이 이후에 플렉스와 아이폰을 


공부하면서 GUI에 적응하는데 밑거름이 되었던 것 같네요! 






1. 라이프 게임 개발을 시작하다


2008년 6월 25일 수요일 새벽 잠들기 전....


1년간 프로그래밍에 전혀 손 대지 않다가... 다시 프로그래밍을 하려고 하니 영~ 힘들다  


1년이란 시간이 매우 길긴 기나부다...그 많은 것을 잊어버렸다. 자바 Spring 프레임워크를 파보려고 하는데


읽어도 무슨말인지 모르겠고, 이클립스 등 개발환경 셋팅하는데만 하루가 걸렸다. ㅡㅡ;;


잊어버린 자바 관련 지식을 상기시키고자, 첫 번째 프로젝트에 들어갔다. 프로그램은 "콘웨이"에 '라이프 게임!'


게임 알고리즘이 간단해서 연습용 프로젝트에 딱인 것 같다.


그럼 라이프 게임이 무엇인지부터 알아보자!




2. 라이프 게임이란?


라이프 게임(Game of Life) 또는 생명 게임은 영국의 수학자 존 호튼 콘웨이가 고안해낸 세포 자동자의 

일종으로, 가장 널리 알려진 세포 자동자 가운데 하나이다. 미국의 과학잡지 사이언티픽 어메리칸 1970년 

10월호 중 마틴 가드너의 칼럼 〈Mathematical Games(수학 게임)란을 통해 처음으로 대중들에게 소개되어 

단순한 규칙 몇가지로 복잡한 패턴을 만들어낼 수 있다는 점 때문에 많은 관심과 반응을 불러일으켰다.


설명

이 ‘게임’은 사실 게임을 하는 사람이 자신의 의지로 게임의 진행을 결정하는 일반적인 게임과는 다르다. 

라이프 게임의 진행은 처음 입력된 초기값만으로 완전히 결정된다.


라이프 게임은 무한히 많은 사각형(혹은 ‘세포’)로 이루어진 격자 위에서 돌아간다. 각각의 세포 주위에는 

인접해 있는 여덟 개의 ‘이웃 세포’가 있으며, 또 각 세포는 ‘죽어’ 있거나 ‘살아’ 있는 두가지 상태중 

한가지 상태를 갖는다.  격자를 이루는 세포의 상태는 연속적이 아니라 이산적으로 변화한다. 즉, 현재 세대의 

세포들 전체의 상태가 다음 세대의 세포 전체의 상태를 결정한다.

...


패턴의 예

라이프 게임에는 전혀 변화가 없는 고정된 패턴(정물 靜物, still life), 일정한 행동을 주기적으로 반복하는 패턴

(진동자, oscillator), 한쪽 방향으로 계속 전진하는 패턴(우주선, spaceship) 등 여러 패턴이 존재한다.



‘block’과 ‘boat’는 정물이고, ‘blinker’와 ‘toad’는 진동자, 그리고 ‘글라이더(glider)’와 ‘경량급 우주선(lightweight spaceship — LWSS)’은 우주선에 속한다...



출처 Wikipedia

      




3. 게임 규칙


게임규칙을 요약하면 아래와 같다 


* 셀의 상,하,좌,우,각 대각선 8개의 인접한 셀을 이웃으로 한다.

* 셀은 세대를 거듭하며 살거나 죽는다.


1. 정확히 3개의 이웃이 살아있다면,  (죽어있는) 셀이 살아난다.

2. 2개의 이웃이 살아있다면 살아있는 셀은 다음세대에도 살아남든다

3. 1개 이하 또는 4개 이상의 이웃이 살아있다면, 살아있는 셀은 외로워서 또는 질식해서 죽는다.




4. 구현하기


프로그래밍을 하기 위하여 구현한 절차는 아래와 같다. 


먼저 모든 셀들을 순회하면서 살아있는 이웃셀을 카운트하고, 살아있는 이웃의 개수를 저장한다


이를 바탕으로 위 세가지 규칙을 적용하여 다음세대 살아있는 셀들을 결정한다.


간략하게 만들어 화면은 아래와 같다. 







4.1 게임판의 표현


게임판은 JPanel을 상속하는 Cell을 가로, 세로 size 개수 만큼의 요소로 갖는 이차원 배열로 표현하였다. 

LifeGame 클래스는 게임의 전체적인 흐름을 관리하는 메소드들을 갖는다. 

public class LifeGame extends JPanel  {
       ...
	private void init() {	
		setLayout(new GridLayout(size,size));
		cells = new Cell[size][size];
		
		for (int i=0; i < size; i++)
			for (int j=0; j < size; j++) {
				cells[i][j] = new Cell();
				cells[i][j].setBorder(BorderFactory.createLineBorder(Color.BLACK));
				add(cells[i][j]);
			}
		rule = new GameRule(cells);
	}
        ...
	public void transition() {
		rule.countAliveNeibor();
		rule.applyRule();
	}
        ...
}





4.2 셀의 표현과 셀의 상태 


Cell은 live 상태(true이면 살아있고, false 죽어있는 상태)와 살아있는 이웃의 개수에 대한 변수를 갖는다. 

live 상태에서 따라서 셀이 그려지거나 혹은 그려지지 않거나 한다.

public class Cell extends JPanel {
	private boolean live = false;
	private int neighborCount = 0;
	private Image img = null;
	private int w, h;
        ...
       @Override
	protected void paintComponent(Graphics g) {
	        ...
		if (live) {
			gg.drawImage(img, 0, 0, this);
		}
		else {
			gg.setColor(getBackground());
			gg.fillRect(0, 0, getWidth(), getHeight());
		}
		g.drawImage(image, 0, 0, this);
	}
}





4.3 게임규칙의 표현


턴마다 LifeGame 클래스의 transition()메소드가 호출되면, GameRule 클래스의 countAliveNeibor() 메소드가 

먼저 호출되고, 이웃하는 셀들에 개수를 모두 카운팅 한뒤, 살아있는 세대를 결정하기 위해 applyRule()메소드가 호출된다. 

public class GameRule {
    ...
     public void countAliveNeibor() {
         ...
     }
     public void applyRule() {
		int neighborCount;

		for (int r = 0; r < rows; r++) {
			for (int c = 0; c < cols; c++) {
				neighborCount = cells[r][c].getNeighborCount();

				if (cells[r][c].getLife()) {
					if (neighborCount <= 1 || neighborCount >= 4)
						cells[r][c].setLife(false);
				}
	
				else  {
					if (neighborCount == 3) 
						cells[r][c].setLife(true);
				}
			}
		} //for 
	}
}






5. 버려진 프로그램은 싫다! 리팩토링~


2009년 08월 04일


예전에 만든 라이프게임 UI가 허접해서 라이프게임 알고리즘은 그대로 드고, 드로잉부분만 수정해서 다시 만들어봤다. 


기존에는 메인패널 하나에 좌표를 가지고 Graphics 객체의 드로잉 메소드로 그렸지만, 이번에는 


셀하나가 JPanel을 상속하게 했고, 셀이 살아있으면, 이미지를 로딩해서 그리게 했다. 


빠른 드로잉을 위해 역시 더블 버퍼링을 사용한다


Timer로는 javax.util.Timer를 사용했다.


TimerTask 쓰레드를 정의해서, 2초마다 상태전이(transition) 후 드로잉하도록 했다.


pauser 기능은 wait() /  notify() 를 사용해서, TimerTask 쓰레드를 wait()로 대기상태로 만들고


notifyAll()로 다시 깨우도록 처리했다.





6. 개발하게 하면서 이런걸 알게되었다~


 1. AWT의 컴포넌트(Canvas)와 Swing의 컴포넌트(JMenu)를 함께 사용하면, Canvas에 가려 메뉴가 안보인다


    중량컨테이너(High Weight Container)인 AWT 와 경량컨테이너(Light Weight Container)인 Swing을 함께 


    사용해서 그렇다고 한다. 따라서 중량 컨테이너와 중량 컨테이너를 함께 사용하지 말아야 한다.  


    Swing에서는 Canvas대신 Panel을 사용한다


 2. Javax.swing.Timer 객체를 통해 타이머를 구현할 수 있다.

    Javax.swing.Timer timer = new Timer(int timeoutMil, ActionListener listener);

 


 3 . 더블버퍼링

      Image buffer = Component.createImage(int width, int height);    컴포넌트에 버퍼를 얻고,

      Graphics g = buffer.getGraphics(); 그래픽스 객체 g에 드로잉한다

      Componet.getGraphics().drawImage(buffer, posintX, positionY, Componet);   버퍼를 컴포넌트에 덮는다

 


 4. 이차원 배열의 사용

  Cell을 표현하는 이차원 배열의 생성은 다음과 같다

       Cell[][] cell = new Cell[size][size];

       for (int i=0; i < size; i++)

           for (int j=0; j < size; j++)

               cell[i][j] = new Cell();


주의할 점은 Cell 타입의 이차원배열을 생성하고, 그 이차원 배열을 순회하며 실제로 각 배열의 원소에 Cell 객체를 

생성하고 할당해야 한다는 것!




7. 만들면서 삽질하게 만든 요인들


첫째로, 

타이머 이벤트 발생할 때마다,  JPanel 클래스를 상속한 MyPanel에서 public void paint(Graphics g) 

메소드를 오버라이드 했는데, 해당좌표에 셀이 도무지 제대로 그려지지 않았다 --^; 

갖은 실수 끝에 실수로 알고리즘 메소드가 주석처리 되었었다는 사실을 깨닫고 수정했다. otz...


둘째로, 

이전 라이프셀이 지워지지 않는채, 계속 덮입혀져 그려진다. 이것은 더블버퍼링을 이용해서 해결! 

생각보다 자바의 드로잉은 속도가 느려서 더블버퍼링을 사용하지 않으면, 화면갱신이 드로잉을 따라가지 

못하는 것 같다. 


셋째로, 

AWT에서의 Canvas 대신, Swing에서는 JPanel을 사용하는데, 드로잉을 하는데 있어서 잘 생각해야 한다.

프로그램이 시작되자 마자 JPanel에 무엇이 그려져야 한다면, 더더욱 그렇다. 게임이 시작하자마자 셀라인을 

보이게 하려고 했다. JFrame의 생성자에 그리는 코드를 넣을게 아니라, public void paint(Graphics g) 메소드에서

처리하면 해결할 수 있다. 이때 그리는데 필요한 데이터값이 정확히 대입이 됐는지 잘 살펴야, 삽질을 피할수 있다.


어쨌든 이래저래 해서, 몸풀기 자바 프로그램을 완성했다. 요거 하면서 그나마 잊어버렸던 자바 지식들을 조금씩 

기억하게 되어 도움이 되었다.







8. 짜잔~ 최종적으로 만들어진 프로그램




소스 다운로드 

JDK_000_LifeGame.zip




다음은  LifeGame, GameRule, Cell 클래스 소스이다. 


package lifegame;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class LifeGame extends JPanel  {
	private Cell[][] cells;
	private int size; 
	private GameRule rule; 

	public LifeGame(int size) {
		this.size = size;
		init();
	}

	// 초기화 
	private void init() {	
		setLayout(new GridLayout(size,size));
		cells = new Cell[size][size];
		
		for (int i=0; i < size; i++)
			for (int j=0; j < size; j++) {
				cells[i][j] = new Cell();
				cells[i][j].setBorder(BorderFactory.createLineBorder(Color.BLACK));
				add(cells[i][j]);
			}
		rule = new GameRule(cells);
	}

	public void cellAlive(int r, int c) {
		cells[r][c].setLife(true);
	}
	
	public void cellDead(int r, int c) {
		cells[r][c].setLife(false);
	}

	public boolean getLifeCell(int r, int c) {
		return cells[r][c].getLife();
	}

	public void clearGame() {
		for (Cell[] cs : cells) 
			for (Cell c : cs)
				c.setLife(false);
	}

	public void transition() {
		rule.countAliveNeibor();
		rule.applyRule();
	}
	
	@Override
	protected void paintComponent(Graphics g) {
		for (Cell[] cs : cells)
			for (Cell c : cs)
				c.repaint();
	}
}

 

package lifegame;

public class GameRule {
	private Cell[][] cells;
	private static final int LEFT = -1, UP = -1;
	private static final int RIGHT = 1, DOWN = 1;
	private int rows, cols;
	
	public GameRule(Cell[][] cells) {
		this.cells = cells;
		rows = cells.length;
		cols = cells[0].length;
	}

	// 각 셀의 살아있는 이웃을 센다 
	public void countAliveNeibor() {
		int nNeighbor;

		for (int r = 0; r < rows; r++) {
			for (int c = 0; c < cols; c++) {
				
				nNeighbor = 0;
				if (r + UP >= 0)
					if(cells[r + UP][c].getLife())
						nNeighbor++;

				if (r + UP >= 0 && c + RIGHT < cols)
					if (cells[r + UP][c + RIGHT].getLife())
						nNeighbor++;
							
				if (c + RIGHT < cols)
					if (cells[r][c + RIGHT].getLife())
						nNeighbor++;

				if (r + DOWN < rows && c + RIGHT < cols)
					if (cells[r + DOWN][c + RIGHT].getLife())
						nNeighbor++; 
							
				if (r + DOWN < rows)
					if (cells[r + DOWN][c].getLife())
						nNeighbor++;

				if (r + DOWN < rows && c + LEFT >= 0)
					if (cells[r + DOWN][c + LEFT].getLife())
						nNeighbor++;				

				if (c + LEFT >= 0)
					if (cells[r][c + LEFT].getLife())
						nNeighbor++;

				if (r + UP >= 0 && c + LEFT >= 0)
					if (cells[r + UP][c + LEFT].getLife())
						nNeighbor++;

				cells[r][c].setNeighborCount(nNeighbor);
			}
		} // for

	}
	// 살아있는 셀은 이웃이 1명 이하, 4명 이상이면 죽는다
	// 죽어있는 셀은 이웃이  3명이면 살아난다
	// 이웃이 2,3명인 살아있는 셀은 계속 산다 
	public void applyRule() {
		int neighborCount;

		for (int r = 0; r < rows; r++) {
			for (int c = 0; c < cols; c++) {
				neighborCount = cells[r][c].getNeighborCount();

				if (cells[r][c].getLife()) {
					if (neighborCount <= 1 || neighborCount >= 4)
						cells[r][c].setLife(false);
				}
	
				else  {
					if (neighborCount == 3) 
						cells[r][c].setLife(true);
				}
			}
		} //for 
	}

}


package lifegame;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.io.BufferedInputStream;

import javax.swing.JPanel;
import javax.imageio.ImageIO;


@SuppressWarnings("serial")
public class Cell extends JPanel {
	private boolean live = false;
	private int neighborCount = 0;
	private Image img = null;
	private int w, h;
	
	
	public Cell() {
		try {
			img = ImageIO.read(new BufferedInputStream(Res.class.getResourceAsStream("../life.png")));
			w = img.getWidth(this);
			h = img.getHeight(this);
			setPreferredSize(new Dimension(w,h));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void setLife(boolean s) { 
		live = s;
	}
	
	public boolean getLife() {
		return live;
	}
	
	public void setNeighborCount(int n) {
		neighborCount = n;
	}
	
	public int getNeighborCount() {
		return neighborCount;
	}

	@Override
	protected void paintComponent(Graphics g) {
		// 더블 버퍼링 
		Image image = createImage(getWidth(), getHeight());
		Graphics gg = image.getGraphics();
		
		if (live) {
			gg.drawImage(img, 0, 0, this);
		}
		else {
			gg.setColor(getBackground());
			gg.fillRect(0, 0, getWidth(), getHeight());
		}
		g.drawImage(image, 0, 0, this);
	}
}






'언어로그 > Java' 카테고리의 다른 글

[java] 글 목록  (0) 2015.09.03
[Java] 자바란?  (0) 2013.02.16
[java] 라이프 게임 (life game)  (1) 2013.02.03
[java] 제13회 한국자바개발자 컨퍼런스  (0) 2013.01.30
Inner Class(내부 클래스)  (0) 2011.04.12
컬렉션(Collection)  (0) 2011.04.11
  • 2016.10.24 20:21 ADDR 수정/삭제 답글

    비밀댓글입니다

Inner Class(내부 클래스)

언어로그/Java 2011. 4. 12. 00:16



 오래전에 Inner Class  개념을 공부하면서  "Thinking In Java 4/e"  을 바탕으로 정리한 내용이다. 

1. 외곽클래스의 멤버메서드(static이 아닌)에서는 내부클래스의 객체를 다른 클래스 객체처럼 참조할 수 있다.

2. 외곽클래스의 static메서드에서는 반드시 '외곽클래스명.' 통해 내부클래스 객체를 참조할 수 있다

3. 내부 클래스 내부에서는 외곽클래스의 멤버를 자유롭게 참조할 수 있는데, 이것은 내부클래스가 자신을 생성한
    외곽클래스 객체의 참조를 은밀히 가지고 있기 때문이다. 내부클래스 객체 내부에서 '외곽클래스명.this'를 사용하여
    접근할 수 있다.

4.  내부클래스 객체 생성시, 특정 외곽클래스 객체와 연결하고자 할때(앞서 외곽클래스 this참조를 은밀히 갖느다고 했다)에는,
    해당 외곽클래스 객체에 대한 참조를 '.new'키워드에 지정해야 한다

5. 지역내부 클래스(local inner class)는 외곽클래스 멤버메서드 내부 또는 코드블록({}로 둘러싸인)에서 정의되고,  
   객체가 생성되는 것이다.  지역내부 클래스를 사용하는 이유는,
   (1) 특정인터페이스를 구현하는 내부 클래스의 객체를 생성후, 그 참조를 반환시거나,
   (2) 클래스의 접근을 일정범위 내로 제한하고자 할때

 6. 내부 클래스 왜 필요할까?
   내부클래스는 다중상속의 문제점을 해결하는 하나의 방안이다. 여러개의 인터페이스를 구현해서, 다중상속을 구현하지만,
    여전히 하나의 추상클래스 밖에 상속하지 못하기 때문에 제한이 있다. 이를 해결하는 것이 내부클래스로, 특정 클래스를
    내부클래스가 상속하게 하여 보다쉽게 다중상속의 기능을 제공하게 된다.

7. 이벤트 중심 시스템(Event Driven System)과 같은 제어 프레임워크의 구현에서, 내부클래스가 많이 사용된다.
   내부클래스를 사용한 제어 프레임워크의 한가지 예제 코드는 다음과 같다.


이벤트 기반 제어프레임워크 소스 예


이벤트를 정의하는 추상클래스 (어떠한 액션을 캡슐화한다)




이벤트를 큐에 쌓고, 순차적으로 실행시키는 컨트롤러 (이벤트들의 행위를 순차적으로 실행한다)




이벤트 추상클래스를 상속하는 구현 이벤트 클래스들 (구체적인 액션 대한 정의)
(불을 켜고, 끄고 벨을 누르고, 프로그램을 종료하는 이벤트들을 내부클래스를 사용해서 정의하였다.)




프로그램을 실행시키는  entry-point  클래스 



[자바] (1) 자바소개

언어로그/Java 2011. 3. 10. 00:49


나름 잘 보이게 한다고, 노란박스를 사용했는데...굉장히 눈을 자극하네요...otz...   


자바(Java)란?

자바언어의 개발사인 썬은 spac이란 서버제품군을 제작하는 회사였는데, 낮은 H/W 마진을 개선하고자, 자사의 H/W 위에 마진이 높은 SW(유닉스 등)를 얹혀 팔려했는데, H/W 마다 SW를 재작성해야하는 문제가 있었습니다.  이에 해결책으로 , 즉 한번 작성하면  다양한 머신 위에서  동일하게 작동할 수 있는 SW를 작성할 수 있는  java를 개발하게 된겁니다.


자바의 장정

객체지향적이고, 플래폼 독립적이고, 동적이고 배포하기 쉬우며, 견고하고 보안에 강하다고 합니다.

엄밀히 말하면 객체지향적이다는 특성은 전적으로 S/W를 작성하는 개발자에게 달려있습니다.

 

                                       

플랫폼 독립성

c언어와 같이 컴파일러가 머신에 의존적인 기계어 코드(실행파일)를  생성하면, 유닉스, 리눅스, 윈도우, 맥 등 각 머신에서 소스를  재컴파일 해야합니다. (각 머신에 맡는 바이너리를 생성해야함).  반면 자바는 OS  와 소스 사이에 Java Virtual Machine이라는 중간계층을 두어 이를 해결했습니다. 소스코드를 가상머신이 인식할 수 있는 중간언어인 바이트 코드로 컴파일해서 배포하는 겁니다. 그러면 각 OS에 설치되있는, JVM이 바이트코드를 머신 의존적인 기계어 코드로 번역하여 실행하는 겁니다. 

 (단,  OS마다 각 머신에 맞는 JVM을 설치해야하지만, 한번만 설치하면 이후에는 소스를 재컴파일 해야하는 번거로움이 사라집니다. 바이너리 레벨에서의 플랫폼 독립성을 확보하게 됩니다. )  



기업 인터넷 환경에서 자바

유연성을 위해  3 - tier ( 프레젠테이션 계층 - 비지니스 계층 - 데이터(DB) 계층 ) 의 형태로 구성된답니다.

현재는 더욱 확장된 N - tier로  됩니다.  

          


JVM(Java Virtual Machine)의 동작방식

클래스 로더는 먼저 소스코드를 보고 모든 필요한 클래스를 로드합니다. 필요한 클래스 위치는 CLASSPATH 환경변수를 참조하여 해당하는 위치에서 찾게됩니다. JVM Verifier는 오작동을  일으킬 수 있는 코드(무한루프)를 검사해 실행을 차단하고, 이어 바이트 코드를 실행합니다. 또한 Just-In-Time 컴파일러를 호출하여, 소스코드와 클래스 파일을 비교합니다. 클래스 파일이 생성되지 않았거나, 소스코드가 클래스파일보다 나중에 수정됐을 때만 재컴파일을  합니다.

(JIT 를 도입해서 자바의 느린성능을 어느 정도 극복했고, 버전업 될때마다, 개선을 통해 성능을 향상시키고 있습니다.)

가비지 컬레터라는 메모리 관리자는  더 이상 사용되지 않는 객체를 수시로 검사하여 자동으로 메모리를 반환해줍니다.



자바환경에서의 보안

언어차원 - 컴파일러 - 클래스 로더 - bytecode verifyer 등 계층적으로 위해한 코드를 차단해주어 안정성을 제공합니다.

자바애플리케이션은  - .zip 또는 .jar로  형태로 압축하여 배포합니다. .jar은 단순히 소스만 압축 할 수도 있고,  클래스파일

까지 포함하여 같이 압축해서 실행가능한 형태로 만들수 있습니다. 웹 기반 애플리케이션은  .WAR 형태로 압축해서 배포

합니다.



JDK(Java Development Kit)

보통 J2SE(Java2 Standard Edition)를 의미하며, 자바를 기반으로 SW를 개발할 수 있는 환경을 의미합니다.  

컴파일러(javac),  core class 라이브러리, 디버거(jdb), JVM, JAR(Java ARchive utility), 기타 등으로 구성됩니다.

Java1.2 버전 이후 부터 대폭 내부구조가 개선되었으며, 이런 변경을 표현하기 위해 1.2 버전 이후부터는 JAVA2라고 

부릅니다. 개발 아키텍처에 따라 J2SE, J2ME, J2EE 로 나뉘기도 합니다.  J2ME는 모발일 환경  SW 작성을 위해 꼭 필요한 

핵심 클래스만으로 이루어진 버전입니다. J2EE는 기업환경에 적합하게 병렬실행 등을 강화한 버전입니다. 


'언어로그 > Java' 카테고리의 다른 글

(2) 리플렉션(Reflection) 사용하기  (0) 2011.04.07
(1) 리플렉션(Reflection)  (3) 2011.04.07
예외처리 (Exception Handling)  (0) 2011.03.24
[Java] 어노테이션 사용하기  (1) 2011.03.19
[Java] 어노테이션(Annotation)  (2) 2011.03.15
[자바] (1) 자바소개  (0) 2011.03.10

자바 개발자를 위한 루비적 관점

언어로그/Ruby/Rails 2011. 3. 4. 00:02


  1.  

핵심클래스 확장(Core Class)

Java에서는 SDK와 같은 Language Runtime의 핵심클래스에 메서드를 추가할 수 없기 때문에 확장메서드들을

다른 클래스의 정적메서드로 모아두는 방식을 선택함 (공백문자열인지 검사하는 StringUtils의  isBlank 메소드)

루비의 클래스들은 개방되어 있어서, 언제든지 수정 가능함

 

class String
    def blank?
        empty? || strip.empty?
    end
end

 

루비의  nil은 자바의  null 에 해당하지만, 객체이며, 메소드 호출 및 추가가 가능

class NilClass 
    def blank?
        true
    end
end

 

 

 

불변객체의 장점

스레드 안정성 - 객체를 변경할 수 없기 때문에 스레드 충돌이 없음

캡슐화 용이

효율적인 해시키 생성 - 해시코드가 변경되지 않기 때문

 

 

 

가변(Mutable) 객체와 불변(Immutable) 객체

자바는 가변과 불변 2가지 버전의 클래스들이 존재하며, final 키워드를 사용해 불변성을 지원함

루비는 클래스가 아닌 인스턴스 수준에서 가변성이 이루어지는데, freeze 메서드를 호출하면 불변이됨

 

자바의 불변클래스에 변경메소드 호출은 변경된 새로운 객체를 리턴함

루비문자열은 자동 불변속성은 아니지만, 변경메소드에 대해 새로운 객체를 리턴함

 

루비 메소드기호 관례

Boolean 값을 반환하는 메소드는 ?로 끝남

객체의 값을 바꾸는 메소드는 !로 끝남

대입문에 사용되는 메소드는 =로 끝남


패키지와 네임스페이스

자바는  package 키워드를 사용해 네임스페이스를 생성

루비는 module을 사용하여 네임스페이스 생성. 참조하는 모듈다음에 범위연산자 :: 사용

 

 


module Relevance
    class User
        def initialize(name)
            @name = name
        end
        attr_accessor : name
    end
end

 

module Codecite
    class User
        def initialize(name)
            @name = name;  
            attr_accessor : name
        end
    end
end

 

u1 = Relevance::User.new("Justin")
u2 = Codecite::User.new("Stu")

 

include Relevance
u3 = User.new("Jared")
puts "u3 is a #{u3.class}"


코드배포

  • 로드패스(Load Path)

자바는 클래스패스 및 클래스 풀네임을 통해 클래스 단위로 로딩함

루비는 :$ 라는 이름을 가진 로드패스를 가지고 있으며,  소스파일 단위로 코드를 로딩함 

(한 소스에 여러개의 클래스가 있을 수 있고, 아에 클래스 정의가 없을 수도 있기 때문 )

 

require 'super_widget'
w = new SuperWidget('phlange")

 

 

  • 루비젬(RubyGems)

루비젬은 소스파일의 덩어리를 가리키는 말로, 자바에서의 jar 라고 생각할 수 있다. 

 gem 커맨드를 사용하여, 젬으로 그룹핑하고, 문서파일 생성, 웹을 통해 다운받고, 버전을 관리할 수 있다

 

require 'rubygems'// 젬을 로딩하기 위한 사전정의어 정도...   
require_gem 'pdf-writer'


애플리케이션을 특정 버전의 레일스에 바인딩하는 것을 동결(freezing)이라고 함!

레일스는 동결 지정/해제를 위한 freeze란 레이크 태스크를 포함하고 있음

 

 

 

위임

레일스에서 확장한 delegate라는 메소드를 사용하여 위임을 쉽게 사용할 수 있다.

 

require 'rails'

class Manager
    attr_accessor : programmer, :tester
    delegate :code, :debug, :to=> :programmer
    delegate :write_test_plans, :run_tests, :to=>:tester
end

 

 


다형성과 인터페이스

루비에는 컴파일 타임이 없기 때문에, 자바의 다형성과는 다르게 작동함

루비의 타입 안전성은 인터페이스 차원이 아닌 메서드 차원에서 보장됨. 런타임에 실제 구현되지 않은 메소드를
호출하면  NoMethodError 예외를 던짐

자바에서는 컴파일 타임에 객체가 특정 인터페이스 타입이 아니면 에러를 발생시켜 주지만, 루비는 실행시에 실제로 

해당 메소드가 구현되외 있는지 확인하고 예외를 발생시켜준다는 의미이다.


루비 메타프로그래밍

  • 리플렉션

루비의 Object클래스도 자바처럼 객체의 상태와 내용을 볼수 있는 기능을 제공함

리플렉션 메서드로 Object#respond_to?, Object#instance_of?,  Object#instance_variables, Object#kind_of  가 있음

 

  • 메시지 전달

Object클래스의 send메서드를 통해 동적으로 객체의 메소드를 호출 할 수 있으며, 매개변수로 블록전달도 가능

실행할 메서드의 이름을 동적으로 조합해서 지정할 수 있기 때문에 다양한 형태의 메소드 호출, 전달이 가능


  • 없는 메서드 처리(method missing)

존재하지 않는 메서들을 처리해주는 Object#method_missing 메서드를 재정의해서 사용할 수 있음

 

 

오리 타이핑(Duck Typing)

객체의 타입이 클래스(Object#class)가 아닌, 실제 그일을 수행하는 메서드를 가지고 있는지를 기준으로 판단

(오리처럼 걷고, 오리처럼 말하면, 인터프리터 입장에서 오리로 취급해줄게~)

 

  • 오리타이핑의 장점

단위테스트 스텁객체 작성이 용이 - 필요한 메서드만 구현해주면 됨

반복적으로 사용하는 코드에 대해 인위적인 경계를 허물어뜨림 - 유연성?

객체 간의 관계 리팩터링이 쉬움

 

  • 오리타이핑의 단점

자동화 도구들이 변수와 메서드 추측을 어렵게 만들어, 좋은 품질의 코드완성과 리팩터링 제공이 힘듬


 

믹스인

한번 작성한 코드를 믹스인으로  몇 개의 클래스나 모듈과 혼합할 수 있는 방식

위임을 믹스인으로 쉽게 구현할 수 있음

 

module Employer
    def employees
        @employees ||= []
    end
    def add_employee(employee)
        ...
    end

    def remove_employee(employee)
        ...
    end
end

class BusinessPerson < Person
    include Employer, Employee
end

 

특정 객체의 인스턴스를 생성하고 extend를 사용하여 특정 인스턴스에만 적용되게 할수도 있다

p = Persion.new("Stu", "Halloway")
p.extend Employer



함수(Functions)

 함수형 언어에서의 함수를 의미한다.  c, c++, 자바같은 절자지향 또는 객체지향 언어들은  명령형 프로그래밍의

개념들을 따르고 있다.  이들 프로그래밍에서 함수는 객체의 상태를 변경시키는 작업을 한다.

함수형 언어에서의 함수는 특정 입력값에 대해 항상 동일한 결과값을 반환하는 동작만을 한다.

 

루비에는 이런 함수와 유사한 블럭(block)이 존재한다. 자바에서도  인터페이스와 익명클래스를 사용하여  블럭 또는
클로저를 구현할 수 있다. 


자바

public interface Comparator {
    int compare(Object o, Object o1);
}

Collectons.sort(al, new Comparator() {
    public int compare(Object o, Object o1) {
        return ((String)o).length() - ((String)o1).length();
    }
});


루비

sorted = readlines.sort { |x, y| x.length - y.length }
puts "sorted:\n #{sorted.join}


블록은 특정 작업에 대한 래퍼(Wrapper)를 구현할 때 유용함 

 

def expect_exception(type)
    begin
        yield// 전달받은 블록을 호출함, 없으면 무시    
        rescue type=>e      // 해당하는 타입의 예외이면 정상종료        
        return
    end
    raise "Excpected exception: #{type}"// 다른타입의 예외이면 예외를 발생시킴
end

expect_exception(ZeroDivisionError) {10/0}

 

&를 사용하여, 명시적으로 블록을 인자로 전달 받을 수 있다.  block_given?를 호출해서 블록전달 유무도 알수 있다.

def expect_exception(type, &blk)
    begin
        blk.call if block_given?    // 전달받은 블록을 호출함, 없으면 무시    
        rescue type=>e      // 해당하는 타입의 예외이면 정상종료        
        return
    end
    raise "Excpected exception: #{type}"// 다른타입의 예외이면 예외를 발생시킴
end

expect_exception(ZeroDivisionError) {10/0}

 


'언어로그 > Ruby/Rails' 카테고리의 다른 글

자바 개발자를 위한 루비적 관점  (0) 2011.03.04
[Ruby]WEBrick 서블릿 사용하기  (0) 2010.12.12
[Ruby]WEBrick 서버구동  (0) 2010.12.12