static

haribo·2021년 2월 27일
0

Java

목록 보기
9/17

Why?

두근두근, 웹개발자로 처음 출근을 했다. 하단 첨부된 사진을 참고하여 게시판을 위한 데이터 구조를 짜라는 업무를 받았다고 가정하자.

여기서 고정된 값은 무엇일까? 질문을 바꾸겠다. 틀이 되는 값은 무엇일까? 글번호, 제목, 날짜가 될 것이다. 틀이되는 값은 클래스로 생성해줘야지. 그리고 객체로 게시글을 만들거야. 우리는 똑똑한 웹개발자니까! 하며 신나게 클래스를 뚝딱뚝딱 만들었다.

/** 하나의 게시물을 표현하기 위한 클래스 */
public class Article {
		private int num;        // 글 번호
		private String title;   // 제목
    private String regDate; // 날짜
}

자바빈즈의 구조를 위하여 getter, setter 메서드를 추가한 후 자료구조 구성이 완성되었다고 이제 잘했단 소리를 듣겠지?! 하는 희망에 부풀어 있던 찰나, 오더가 내려온다. 전체 게시물 수랑 모든 게시물이 공유하는 카테고리 정보가 있었으면 하는데, 할 수 있겠어? 음, 이것도 클래스에다가 정의하면 되겠지? 싶어서 멤버변수에 추가를 했다. 프라이빗으로 예쁘게 은닉까지 해서.

근데 사실 '전체 게시물 수'란 데이터는 하나만 있어도 족하다. 굳이 객체로 생성된 모든 게시물이 그 데이터를 갖게될 필요가 있을까? 정답은 No다. 게시글이 100개라고 가정했을때, int값으로 한번만 쓰면 될걸 굳이 멤버변수로 지정해서 396바이트나 낭비하는 대참사를 낳게 된다.

메모리는 돈이다. 기업의 존재의 의의는 이윤추구다. 비용이 많이 들면 순수익은 줄어든다. 아, 뭔가 방법이 필요하다. 메모리를 낭비하지 않게 하면서도 포함하게 하는 방법이. 그래서 나타난게 static이다.

static

  • 객체간의 공유 자원을 표현하는 키워드이다.
  • 클래스를 설계할 때 멤버변수 중 모든 객체에서 공통적으로 사용해야 하는 값에 static을 붙인다.
/** 하나의 게시물을 표현하기 위한 클래스 */
public class Article {
		private static int count;       // 전체 글 수
		private static String category; // 카테고리
		private int num;        // 글 번호
		private String title;   // 제목
    private String regDate; // 날짜
}
  • static이 적용된 멤버변수는 객체의 개수에 상관 없이 단 하나만 생성되며, 이를 모든 객체가 공유하기 때문에 메모리를 효율적으로 사용할 수 있다.

<컴퓨터의 메모리 구조> - 좀 더 깊이 공부해보자

(고정 영역) - 프로그램이 실행되면 실행파일이 메모리에 로드되면서, 실행파일의 용량만큼 RAM을 사용한다. 실행파일의 크기는 변할 수 없으므로(다운로드 해둔 파일이 갑자기 커지거나 그러진 않듯) 이 영역의 크기는 고정 크기를 갖는다. (식당의 주방. 손님이 있건 없건 주방에 사람은 늘 있다.)


  • 코드영역 : 프로그램의 코드가 저장되는 영역 이 영역에 저장된 명령어들을 운영체제가 CPU에게 갖다주고, CPU는 받아서 실행한다. 운영체제의 성능 차이에 따라 속도가 달라진다. (우주의 원리)
  • 데이터 영역 : 전역변수와 static으로 선언되는 변수가 할당된다. 이 영역에 할당되는 변수들은 프로그램 시작과 동시에 메모리 공간이 할당되어 종료될 떄 까지 남아있게 된다. (지구, 태양)

(동적 영역) - 프로그래머가 new 키워드를 사용해서 객체나 배열을 생성하면 사용된다. (힙영역) 또 다른 경우는 메서드가 호출되는 동안 사용될 파라미터와 지역변수가 생성된다. (스택영역), 메서드가 종료되거나 객체가 더이상 사용되지 않으면 생성된 변수나 객체는 메모리에서 사라지므로, 이 영역은 유동적인 크기를 갖게 된다. (식당의 홀. 손님은 유동적이고 왔다갔다하며 움직인다.)


  • 힙 영역 : 프로그래머가 원하는 시점에 변수를 할당하고 소멸시키는 영역. 메모리 동적 할당시 사용된다. 객체가 생성되는 영역이다. (C언어의 포인터가 말하는 메모리 영역이기도 하다.) (사람) (손님) FIFO
  • 스택 영역 : 함수가 실행될 때 사용되는 파라미터와 지역변수에 대한 메모리 공간. 함수의 종료와 함께 소멸된다. (살고 먹고) (밥먹고 치우고 하는 역할. LIFO)

<static 데이터의 생성위치>

  • static 데이터는 메모리의 고정영역중 데이터 영역에 생성되고, 일반 멤버변수나 객체는 동적영역중 힙 메모리 영역에 생성된다.
  • 프로그램 메모리를 사용하는 순서 : 최초 실행시 고정 영역에 실행파일만큼의 메모리를 점유한다.프로그램이 각종 동작을 수행하는 동안 동적영역을 사용한다.

<멤버변수 vs static 멤버변수>

  • static 변수는 프로그램 실행과 동시에 객체의 생성 여부와 상관없이 이미 존재하기 떄문에(고정영역 데이터 영역에 존재) 소스코드에서는 특정 클래스 안에 명시하지만, 그 클래스를 통해서 생성되는 객체나 그 안에 포함되는 멤버변수와는 다른 존재이다. (객체와 멤버변수는 힙영역으로 간다. 메모리 영역이 다르다.)
  • 객체가 생성되지 않더라도 이미 존재하고 있기 때문에 static 변수는 객체의 이름을 통해 접근하는 것이 아니라, 클래스의 이름을 통해서 접근해야한다.
  • 단, static 변수가 선언된 클래스 안에서는 변수 이름으로 직접 접근이 허용된다. (같이 있으니까 굳이 부를 필요가 없겠지)

<static 변수와 static 메서드>

  • static 데이터에 접근하기 위한 메서드 : 클래스에서 정의하는 일반 메서드들은 객체의 생성과 동시에 동적 메모리 영역에서 활성화된다. (동적 메모리 영역에서는 고정 메모리 영역의 자원들은 항상 존재한다. 식당에 밥먹으러 갔을때 종업원들은 항상 거기 있듯이. 근데 반대로 식당 종업원이 있다고 해서 식당에 반드시 손님이 있지는 않다. 이 말은 즉슨 고정 메모리 영역의 자원들은 동적 메모리 자원들이 항상 존재할 거라고 보장 못받는단 말이다.)
  • 그러므로 객체의 생성과 상관없이 static 변수에 접근하기 위한 메서드를 만들 필요가 있는데, 메서드의 정의 과정에서 static 키워드를 사용하면 static 자원에 접근하기 위한 메서드를 만들 수 있다.
  • private 멤버변수에 접근하기 위해 getter, setter를 설정하듯이 static이 더 추가된 것으로 이해하였다. (20201014) - 나중에 보면 좀 달라지려나?

<static 메서드 사용시의 제약 사항>

메모리 영역의 차이 떄문에 static 메서드는 동적 메모리 영역의 멤버변수를 사용하거나, static이 아닌 일반 멤버함수를 호출할 수 없다. (고정영역에서 동적영역을 쓰려는 것, 즉 주방 직원이 김철수라는 손님을 컨트롤 하려는건데 김철수 손님이 올지 안올지는 직원 입장에서 어떻게 할 수 있는게 아니다.)

<실습> - 게시판을 만들어 봅시다.

/**
 * 하나의 게시물을 표현하기 위한 JavaBeans
 * 각각의 게시물들이 독립적으로 표현하고 있는 데이터들을 멤버변수 형태로 선언한다.
 */
public class Article {
	/** static은 모든 객체가 공유하는 값이다. static값은 클래스 이름을 통해서
	 * 접근해야 하며, 객체의 생성 여부에 상관없이 사용이 가능하다.*/
	// 전체 게시물의 수를 표현하기 위한 데이터
	private static int count = 0;
	// 모든 게시물은 하나의 카테고리 안에 존재한다고 가정한다.
	// 게시물의 분류를 구별하기 위한 데이터
	private static String category;
	
	// 글 번호
	private int num;
	// 글 제목
	private String title;
	// 작성일시
	private String regDate;
	
	public Article(int num, String title, String regDate) {
		super();
		this.num = num;
		this.title = title;
		this.regDate = regDate;
		
		/* 이 클래스에 대한 객체 생성 --> 게시물 신규 등록
		 * 게시물이 새로 등록될 때 마다, 전체 글 수를 의미하는
		 * count 변수가 1씩 증가한다.
		 * 전체 게시물 수는 모든 객체가 공유하는 값이므로,
		 * static으로 생성되어야 한다.
		 */
		count++; // 꿀팁, 글이 새로 생길때마다 글번호 추가됨. 메서드 추가 생성 필요 x 
	}

	public static int getCount() {
		return count;
	}

	public static void setCount(int count) {
		Article.count = count;
	}

	public static String getCategory() {
		return category;
	}

	public static void setCategory(String category) {
		Article.category = category;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getRegDate() {
		return regDate;
	}

	public void setRegDate(String regDate) {
		this.regDate = regDate;
	}

	@Override
	public String toString() {
		return "글 분류=" + category + ", 전체 글 수=" + count + 
				"Article [num=" + num + ", title=" + title + ", regDate=" + regDate + "]";
	}
	
	
}
public class Main01 {
	public static void main(String[] args) {
		Article.setCategory("자유게시판");
		
		Article a1 = new Article(1, "첫 번째 글 제목", "2014-01-01");
		Article a2 = new Article(2, "두 번째 글 제목", "2015-02-01");
		Article a3 = new Article(3, "세 번째 글 제목", "2016-03-01");
		
		// 출력결과에서 모든 객체가 동일한 count값을 갖는다.
		System.out.println(a1.toString());
		System.out.println(a2.toString());
		System.out.println(a3.toString());
		
		System.out.println("----------------");
		
		// static 변수의 값을 변경하면, 모든 객체가 영향을 받는다.
		Article.setCategory("공지사항");
		
		System.out.println(a1.toString());
		System.out.println(a2.toString());
		System.out.println(a3.toString());

	}

}
이 포스트는 itpaper.co.kr에서 제공되는 강의자료를 바탕으로 작성되었습니다.
profile
그림 그리는 백엔드 개발자

0개의 댓글