14. 클래스

Isaiah IM·2023년 7월 4일
0

java basic

목록 보기
16/38
post-thumbnail

1. 클래스

1.1 클래스란?

클래스란 객체의 설계도와 같다.

만약 우리가 tv를 판매한다고 가정하자.
이때, tv의 크기, 비율, 가격에 관한 정보들을 각각 변수로 각자 관리할 수 있으나, 판매하는 tv의 종류가 많아지면 관리해야 하는 변수가 많아지고 복잡해진다.

이러한 작업을 클래스로 묶어서 관리하면 쉽게 관리할 수 있다. 뿐만 아니라, tv판매에 필요한 각종 메소드(영업, 할인등..)들 역시 한번에 묶어서 관리할 수 있다.

만약 기존에 c언어 등을 배운 사람이라면 클래스는 구조체 안에 변수와 함수가 같이 있는 경우라고 생각해도 좋다.

1.2 클래스의 정의

클래스는 다음과 같이 정의할 수 있다.

접근제어자 class 클래스_이름{
...// 코드
} 

클래스는 위와 같은 형식으로 정의를 하며, 앞서 예를 든것과 같이 tv판매를 클래스로 정의하면 다음과 같이 정의할 수 있다.

public class TvSale{
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    
    public void discount(){// tv 할인 메소드
    ...//tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    ...// tv 판매 코드
    }
}

이때, 많이 못보던 키워드가 있을 것이다.
바로 클래스 앞에 붙은 public키워드는 접근제어자로, 추후에 자세히 다룰 예정이기에 지금은 클래스를 만들기 전에는 public키워드를 붙여야 한다고만 알아두자.

추가적으로 클래스는 소스파일당 하나가 가장 이상적이며, 일반적으로 소스파일 하나에 클래스 하나를 선언한다.

1.3 클래스의 선언

클래스의 선언은 다음과 같이 new키워드를 이용해 선언할 수 있다.
클래스이름 객체_이름= new 클래스이름();

앞에서 우리가 만들었던 TvSale클래스를 선언하면 다음과 같다.

TvSale tv1 = new TvSale();

이때, 클래스 이름은 TvSale이 되고, 객체 이름은 tv1이 된다.
이를 TvSale클래스로부터 tv1 객체를 생성했다라고 한다.
또한, tv1TvSale클래스의 인스턴스라고 한다.

1.4 클래스의 메모리 구조

jvm의 구조를 다시 한번 보자.

클래스를 생성하면 생성한 정보들은 jvm의 static area에 저장이 된다.
또한, 클래스로부터 인스턴스를 생성할때(클래스 선언) new키워드를 사용했기 때문에 jvm의 heap area에 선언한 인스턴스가 저장이 된다.

1.5 인스턴스 변수

인스턴스 변수란 클래스 내에 선언된 변수를 의미한다.

우리가 앞에서 클래스를 생성하면서 만들었던 변수들을 인스턴스 변수라고 한다.
앞서 생성했던 클래스를 다시 보도록 하자.

public class TvSale{
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    
    public void discount(){// tv 할인 메소드
    ...//tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    ...// tv 판매 코드
    }
}

위 코드에서는 size, scale, price가 바로 인스턴스 변수가 된다. 이러한 인스턴스 변수의 경우 아래와 같이 인스턴스 생성후 .을 이용해 접근할 수 있다.

tv class 코드

public class TvSale{
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    
    public void discount(){// tv 할인 메소드
    ...//tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    ...// tv 판매 코드
    }
}

main class 코드

public class ClassStudy {
	public static void main(String[] args) {
		
		TvSale tv1 = new TvSale();// tv1
		TvSale tv2 = new TvSale();// tv2
		
		/*tv1 인스턴스 변수 접근*/
		tv1.price=100;// 100만원
		tv1.scale=169;// 16:9 비율
		tv1.size=55;// 55인치
		
		/*tv2 인스턴스 변수 접근*/
		tv2.price=300;// 300만원
		tv2.scale=169;// 16:9 비율
		tv2.size=100;// 100인치
		
		System.out.println("tv1 가격: "+tv1.price+"만원");
		System.out.println("tv1 비율: "+tv1.scale+"비율");
		System.out.println("tv1 크기: "+tv1.size+"인치");
		
		System.out.println();
		
		System.out.println("tv2 가격: "+tv2.price+"만원");
		System.out.println("tv2 비율: "+tv2.scale+"비율");
		System.out.println("tv2 크기: "+tv2.size+"인치");
	}
}

output

tv1 가격: 100만원
tv1 비율: 169.0비율
tv1 크기: 55.0인치

tv2 가격: 300만원
tv2 비율: 169.0비율
tv2 크기: 100.0인치

이와같이 인스턴스변수는 .을 통해 접근할 수 있다.

1.6 클래스 변수

클래스 변수란 static키워드를 사용한 변수로, 클래스 내에서 모든 인스턴스가 공유하는 변수를 의미한다.

클래스 변수는 static키워드를 사용해 클래스 내의 모든 인스턴스가 공유하는 변수를 의미한다.

앞서 인스턴스 변수에서 확인했듯이 tv1의 price와 tv2의 price를 다르게 설정할 수 있었다.
이는 인스턴스 변수는 인스턴스를 생성하면 아래 그림과 같이 각 인스턴스는 각각의 메모리를 다른 인스턴스와 공유하지 않기 때문이다.

그러나, static키워드를 사용하면 변수가 heap area가 아닌 static area에 할당이 되기 때문에 클래스 내의 변수를 공유할 수 있다. 또한, static키워드를 사용하면 클래스가 생성되는 최초 1번만 초기화가 된다.
또한, 클래스변수의 경우 tv1.cnt와 같이 인스턴스_이름.클래스변수 형식 보다는 TvSale.cnt와 같이 클래스_이름.클래스변수로 작성하는것이 가독성이 더 좋으며, 일반적으로 이와 같이 작성한다.

이러한 클래스변수는 아래와 같이 사용할 수 있다.
만약 tv의 총 판매 수량을 카운트 할때는 일반적인 인스턴스 변수를 사용하면 인스턴스가 생성될때마다 초기화 되기 때문에 인스턴스 변수를 이용해 총 판매수량을 카운트 하는것이 불가능하다.
이런 경우 클래스 변수를 사용하면 인스턴스가 생성되도 초기화되지 않기 때문에 판매수량 카운트를 할 수 있다.

클래스 변수를 이용해 판매수량을 카운트 할 수 있는 코드는 다음과 같다.

tv class 코드

public class TvSale{
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    static int saleCnt=0;// 판매수량
    
    public void discount(){// tv 할인 메소드
    ...//tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    ...// tv 판매 코드
    }
}

main class 코드

public class ClassStudy {
	public static void main(String[] args) {
		
		TvSale tv1 = new TvSale();// tv1
		TvSale tv2 = new TvSale();// tv2
		
		/*tv1 인스턴스 변수 접근*/
		tv1.price=100;// 100만원
		tv1.scale=169;// 16:9 비율
		tv1.size=55;// 55인치
		
		/*tv2 인스턴스 변수 접근*/
		tv2.price=300;// 300만원
		tv2.scale=169;// 16:9 비율
		tv2.size=100;// 100인치
		
		System.out.println("tv 판매수량: "+TvSale.saleCnt+"대");
		TvSale.saleCnt++;// 클래스 변수 값 증가
        
        System.out.println("tv 판매수량: "+TvSale.saleCnt+"대");
		TvSale.saleCnt++;// 클래스 변수 값 증가
        
        System.out.println("tv 판매수량: "+TvSale.saleCnt+"대");
		TvSale.saleCnt++;// 클래스 변수 값 증가
        System.out.println("tv 판매수량: "+TvSale.saleCnt+"대");
        
        System.out.println("tv1 클래스 변수: "+tv1.saleCnt);
        System.out.println("tv2 클래스 변수: "+tv2.saleCnt);
	}
}

output

tv 판매수량: 0대
tv 판매수량: 1대
tv 판매수량: 2대
tv 판매수량: 3대
tv1 클래스 변수: 3
tv2 클래스 변수: 3

2. 메소드

2.1 클래스 메소드

클래스 메소드란 static키워드가 붙은 메소드이다.

앞장에서 메소드를 다룰때를 생각해보자. 기존에 메소드를 다룰때는 int method()와 같은 형식으로만 다뤘을 것이다. 그러나, 클래스 메소드의 경우는 앞에 static키워드가 추가로 붙어 static int method()와 같이 작성한다.
앞서 클래스 변수에서 설명한 내용과 동일하게 메소드에도 static키워드가 붙으면 메소드가 jvm의 static area에 저장이 되며, 메모리에 한번만 할당이 된다.

뿐만 아니라 클래스 메소드의 경우 객체의 생성 없이도 사용이 가능하다.
예를들어 사용자로부터 입력을 받기 위해서는 우리는 Scanner클래스의 객체를 생성해서 사용했으나, 제곱근 등을 구하는 Math.sqrt();와 같은 경우는 Math클래스의 객체를 생성하지 않고 사용할 수 있었다.
이는 Math클래스의 sqrt();메소드가 static키워드로 설계가 되었기 때문이다.

또한 클래스 메소드의 경우 아래와 같이 static이 선언되지 않은 변수의 접근이 불가능하다.

public class StaticMethod {
	
	static String msg1="msg1";
	String msg2="msg2";
	public static void printMsg() {
		System.out.println(msg2);// static변수가 아니라서 접근X
		
	}
}

위 코드를 실생시키면 컴파일 오류가 발생함을 알 수 있다.
이와 같이 static으로 메소드를 선언하면 메모리에 최초로 1번만 선언이 되기 때문에 객체가 생성될때 마다 새로 생성되는 static키워드가 없는 변수는 접근이 불가능하다.

또한, 클래스 메소드의 경우 Math.sqrt();와 같이 객체의 생성 없이도 선언이 가능하기 때문에 되도록이면 객체를 생성하지 않고 클래스_이름.클래스_메소드();형태로 선언을 하는 경우가 대다수이다.


3. 실습

Q1.

인스턴스 변수와 클래스 변수의 메모리적 관점의 차이를 설명하시오.

A1.

인스턴스 변수와 클래스 변수의 가장 큰 차이는 할당되는 메모리의 영역이다.

인스턴스 변수의 경우 메소드를 생성할 경우 아래 그림과 같이 heap영역에 할당이 되며, 메소드가 생성될 때 마다 계속 heap영역에 새로 할당이 된다.

반면에 클래스 변수의 경우 메소드를 생성할 경우 아래 그림과 같이 stack영역에 할당이 되며, 메소드가 계속 생성해도 추가적으로 메모리가 할당되지 않고, 생성된 클래스들이 클래스 변수를 공유한다.

profile
나는 생각한다. 고로 나는 코딩한다.

0개의 댓글