본문 바로가기

Java Live Study

Live Study 5주차 : 클래스

자바의 Class에 대해 학습하기

 

습할 것

  • 클래스 정의하는 방법
  • 객체 만드는 방법 (new 키워드 이해하기)
  • 메소드 정의하는 방법
  • 생성자 정의하는 방법
  • this 키워드 이해하기

과제 마감

2020.12.19 1PM

 


 

클래스를 정의하기 전에 객체 지향과 객체에 대해 언급하려 한다.

자바는 객체 지향 언어이며 객체 지향의 장점은

  • 해결하려는 문제의 요소들을 객체로 모델링할 수 있다.
  • 객체들은 독립성이 유지되며 데이터에 의존하지 않으며, 생산성을 향상시킬 수 있다.
  • 객체는 독립된 모듈이기에 다양한 프로그램에서 이 모듈을 재사용 할 수 있다.

등이 있다.

또한, 객체 지향에서는 객체를 만들기 위해 클래스를 이용한다.

 

 

한 번쯤 접하게 되는 붕어빵 틀과 붕어빵의 상관관계

 

 

붕어빵 틀이 클래스이고 붕어빵이 객체이다. 먹을 수 있는 것은 붕어빵이며 붕어빵 틀이 아니다.

즉, 객체 지향에서 데이터를 처리하는 데 사용되는 것은 붕어빵 틀로부터 생성된 붕어빵이다. 붕어빵 = 객체

이제 데이터를 처리하기 위한 클래스를 만들어보자!

 


 

클래스 정의하는 방법

 

1) 클래스의 구조

클래스는 크게 속성과 기능으로 구성되며, 이로부터 생성된 객체 또한 속성과 기능으로 구성된다.

속성에는 멤버 변수가 포함되며

기능에는 생성자와 메소드가 포함된다.

클래스가 멤버 변수, 생성자, 메소드를 모두 포함하여야 하는 것은 아니며 필요에 따라 다양한 형태로 구성될 수 있다.

 

// 멤버 변수, 생성자, 메소드를 가지는 클래스
public class Box{
    int width; // 속성 - 멤버 변수
    int height;
    int depth;
    
    public Box(int w, int h, int d){ // 기능 - 생성자 메소드
        width = w;
        height = h;
        depth = d;
    }
    
    public void Volume(){ // 기능 - 메소드
        int vol;
        vol = width * height * depth;
        System.out.println("Volume is " + vol);
    }
}    

 

// 멤버 변수만 가지는 클래스
public class Box{
    int width; // 속성 - 멤버 변수
    int height;
    int depth;
}    

 

// 멤버 변수와 메소드를 가지는 클래스
public class Box{
    int width; // 속성 - 멤버 변수
    int height;
    int depth;

    public void Volume(){ // 기능 - 메소드
        int vol;
        vol = width * height * depth;
        System.out.println("Volume is " + vol);
    }
}    

 

 

2) 클래스의 선언

클래스의 선언 시 클래스의 특성을 나타내는 접근 한정자를 지정하여 선언할 수 있다.

 

[public/final/abstract] class Box{
...
...
..
.
}

 

 

public 모든 클래스에서 접근 가능(클래스로부터 객체 생성 가능)함을 의미
접근 한정자 사용 안함 클래스 앞에 어떠한 한정자도 지정하지 않은 클래스는 같은 패키지 내의 클래스에서만 접근 가능함을 의미
final 하위 클래스를 가질 수 없는 클래스. 즉, 새로운 클래스가 상속되어 생성될 수 없음을 의미 (6주차에 진행)
abstract 추상 클래스를 의미. 추상 클래스는 객체를 생성할 수 없는 클래스로서 추상 메소드를 가짐

 

 

자바에서 하나의 프로그램에는 하나의 클래스만 정의하는 것이 원칙이며, 다수 개의 클래스가 하나의 프로그램으로 정의될 수 있다.

만일 여러 개의 클래스가 하나의 프로그램에 정의된다면 다음의 규칙을 따라야 한다.

  • 클래스에 붙이는 public 한정자는 main() 메소드를 가진 클래스에만 붙여야 함.
  • 프로그램의 이름은 main() 메소드를 가진 클래스의 이름과 동일해야 함.
  • 한 패키지에는 동일한 이름의 클래스가 중복될 수 없음.

 


 

객체 만드는 방법 (new 키워드 이해하기)

 

객체를 만들기 위해서는 우선 객체를 선언해야 한다. 객체의 선언은 다음과 같다.

클래스명 객체 변수명 ;

객체를 선언만 했을 경우에는 객체 변수의 값은 null이다.

 

Box mybox;
Avg student;
String name;

 

선언만으로 객체가 생성되지 않으며 메모리 상에 생성되기 위해서는 선언된 객체를 명시적으로 생성시켜야 한다.

객체의 생성은 다음과 같다.

객체 변수명 = new 클래스명 ;

 

객체는 생성 연산자 new를 사용하여 생성시켜야 사용할 수 있다.

객체가 생성된다는 의미는 기억 장소에 객체의 요소를 저장할 공간이 배정된다는 의미이다.

 

myBox = new Box();
student = new Avg();
name = new String("Kim");

 

이를 종합하면 하나의 문장으로 선언과 생성을 함께 할 수 있다.

 

Box myBox = new Box();
Avg student = new Avg();
String name = new String("Kim");

 

 


 

메소드 정의하는 방법

메소드는 클래스가 어떤 기능을 수행하는지 나타낸다. 그리고 메소드의 이름은 소문자로 시작하는 것이 관례이다.

[public/private/protected] [static/final/abstract/synchronized] 반환값형 메소드 이름([매개 변수들]) { }

 

 

1) 접근 한정자

메소드 선언 시 사용되는 접근 한정자는 public, private, protected가 있다.

접근 한정자를 이용해 캡슐화와 정보 은폐를 할 수 있다.

 

public 항상 접근 가능하다. 꼭 공개해야 하는 요소만 public으로 지정하는 것이 좋음
private 소속된 클래스 내에서만 사용할 수 있음
protected 6주차 상속에서 설명

 

2) 클래스 메소드 static, 그리고 final, abstract, synchronized 메소드

클래스 메소드는 일반적인 함수 역할을 하는 메소드이다. 클래스 이름을 통하여 접근한다.

객체를 생성하지 않아도 클래스 메소드를 호출할 수 있다.

 

자바의 라이브러리 클래스에서 사용되는 클래스 메소드의 예이다.

 

Arrays.toString(a); // Arrays 클래스의 toString() 메소드를 함수처럼 직접 사용
Arrays.sort(b); // Arrays 클래스의 sort() 메소드를 함수처럼 직접 사용
Integer.parseInt(args[0]); // Integer 클래스의 parseInt() 메소드를 함수처럼 직접 사용
String.valueOf(number); // String 클래스의 valueOf() 메소드를 함수처럼 직접 사용

 

클래스 메소드 내에서는 클래스의 속성 중에서 클래스 변수만 사용이 가능하다. 즉, 클래스 변수와 클래스 메소드 자체 내에서 선언되어 사용되는 지역 변수만 사용 가능하다.

 

static 일반적인 함수 역할을 하는 메소드
final 서브 클래스에서 오버라이딩 될 수 없음을 의미하는 메소드
abstract 추상 클래스 내에서 선언될 수 있는 추상 메소드
synchronized 스레드를 동기화 할 수 있는 기법을 제공하기 위해 사용되는 메소드

 

 

3) 메소드의 반환값

메소드 선언부에는 그 메소드 반환 값의 자료형이 지정되어야 한다.

메소드가 값을 반환하지 않는 경우는 반환 값의 형을 void로 지정하며, void형이 아닌 메소드는 지정된 형과 같은 형의 결과 값을 반환해야 한다. 반환 시 return문을 사용하며 반환 후 종료한다.

return문이 단독으로 사용될 경우에는 반환 값은 없으며 메소드의 수행만 종료한다.

 

 

4) main() 메소드

main() 메소드는 특수한 메소드로서 자바 프로그램의 실행이 시작되는 첫 메소드를 의미한다.

자바 프로그램을 작성한 후 파일로 저장할 때 파일의 이름은 클래스의 이름과 동일해야 한다. 클래스가 여러 개인 경우 main() 메소드를 포함한 클래스의 이름으로 저장한다.

저장된 프로그램이 실행될 때 JVM은 프로그램 이름을 이용하여 main() 메소드를 호출하여 메소드를 실행하게 된다.

 

5) 메소드 오버로딩

하나의 클래스 안에 같은 이름의 메소드를 중첩하여 사용할 수 있다. 물론 중첩된 메소드들은 매개 변수의 형과 개수가 다른 형태여야 한다. 호출 시 매개 변수의 형과 개수를 비교하여 적합한 메소드가 호출된다.

 

class Box{
	private int ivol;
    private double dvol;
    
    public Box(int w, int h, int d){
    	volume(w,h,d);
    }
    
    public Box(double w, double h, double d){
    	volume(w,h,d);
    }
    
    public void volume(int w, int h, int d){
    	ivol = w * h * d;
    }
    
    private void volume(double w, double h, double d){
    	dvol = w * h * d;
    }
    
    public int get_ivol(){
    	return ivol;
    }
    
    public double get_dvol(){
        return dvol;
    }
}

public class Box{
	public static void main(String args[]){
    	Box mybox = new Box(10, 20, 30);
        System.out.println("박스의 부피(정수 매개 변수) : " + mybox.get_ivol());
        
        mybox = new Box(10.5, 20.5, 30.5);
        System.out.println("박스의 부피(실수 매개 변수) : " + mybox.get_dvol());
        
        mybox = new Box(10, 20, 30.5);
        System.out.println("박스의 부피(정수와 실수 혼합) : " + mybox.get_dvol());
    }
}

/**
* 박스의 부피(정수 매개 변수) : 6000
* 박스의 부피(실수 매개 변수) : 6565.125
* 박스의 부피(정수와 실수 혼합) : 6100.0 (혼합시 확대 형 변환)
*/

 

 


 

생성자 정의하는 방법

 

1) 생성자

 

생성자는 클래스로부터 객체가 생성될 때 수행되며, 주로 객체의 초기화를 위해 사용한다.

생성자는 반드시 클래스의 이름과 동일한 이름으로 정의해야 한다.

또한, 생성자는 메소드와 달리 반환형을 지정하지 않는다.

 

클래스 정의 시 생성자가 없는 경우에는 묵시적인 생성자가 자동으로 생성되며 여기서 묵시적인 생성자는 매개 변수가 없는 생성자를 말한다.

 

 

묵시적 생성자가 없는 경우, 묵시적 생성자를 지정하는 경우, 명시적 생성자가 있는 경우 세 가지를 살펴보자.

 

// 묵시적 생성자가 없는 경우 - 생성자 없이 클래스 생성
class Cons1 {
    public int num;
}

public class ConsTest1{
    public static void main(String args[]){
        Cons1 cons = new Cons1();
    }
}   

 

 

// 묵시적 생성자를 지정하는 경우
class Cons2 {
    public int num;
    public Cons2(){
    	System.out.println("묵시적 생성자");
    }
}

public class ConsTest2{
    public static void main(String args[]){
        Cons2 cons = new Cons2();
    }
}


// output : "묵시적 생성자"

 

 

// 명시적 생성자가 있는 경우 - 매개 변수를 지정하여 객체 생성
class Cons3 {
    public int num;
    public Cons3(String s){
    	System.out.println(s + " 명시적 생성자");
    }
}

public class ConsTest1{
    public static void main(String args[]){
        Cons3 cons = new Cons3("1번째");
    }
}   

// output : "1번째 명시적 생성자"

 

 

2) 생성자 오버 로딩

하나의 클래스는 여러 개의 생성자를 가질 수 있다. 같은 이름의 생성자를 여러 개 중첩하여 사용할 수 있다는 뜻이다.

물론 각각의 생성자가 가지는 매개변수의 형과 개수는 달라야 한다. 같은 매개 변수를 가지는 생성자가 있다면 에러가 발생한다.

 

간단한 예제를 살펴보자.

 

class Box{
    int width;
    int height;
    int depth;
    
    public Box(){
        width = 1;
        height = 1;
        depth = 1;
    }
    
    public Box(int w){
    	width = w;
        height = 1;
        depth = 1;
    }
    
    public Box(int w, int h){
    	width = w;
        height = h;
        depth = 1;
    }
    
    public Box(int w, int h, int d){
    	width = w;
        height = h;
        depth = d;
    }
}

public class BoxTest{
	public static void main(String args[]){
        Box myBox = new Box();
        int vol = mybox.width * mybox.height * mybox.depth;
        System.out.println("박스의 부피(매개 변수 없음) : " + vol);
        
        myBox = new Box(10);
        vol = mybox.width * mybox.height * mybox.depth;
        System.out.println("박스의 부피(매개 변수 1개) : " + vol);
        
        myBox = new Box(10, 20);
        vol = mybox.width * mybox.height * mybox.depth;
        System.out.println("박스의 부피(매개 변수 2개) : " + vol);
        
        myBox = new Box(10, 20, 30);
        vol = mybox.width * mybox.height * mybox.depth;
        System.out.println("박스의 부피(매개 변수 3개) : " + vol);
   }
 }
 
 /**
 * 박스의 부피(매개 변수 없음) : 1
 * 박스의 부피(매개 변수 1개) : 10
 * 박스의 부피(매개 변수 2개) : 200
 * 박스의 부피(매개 변수 3개) : 6000
 */

 

매개 변수에 적합한 생성자가 자동 실행된다.

 

 


this 키워드 이해하기

 

this는 자바의 예약어이다. 

생성자나 메소드에서 this가 사용될 때 this는 자신을 가동한 객체를 의미한다.

즉, 생성자나 메소드는 객체를 생성하거나, 객체의 이름을 통해서 호출되는데 그 객체를 의미한다.

 

이전에 사용한 생성자 Box를 살펴보자.

 

public class Box{
    int width;
    int height;
    int depth;
    
    public Box(int w, int h, int d){ // point 1
        width = w;
        height = h;
        depth = d;
    }
}    

 

point 1 ) 생성자의 매개 변수 w, h, d는 변수의 이름만으로 의미를 파악하기 어렵다.

생성자의 매개 변수에 의미 있는 변수명을 지어주자.

 

public class Box{
    int width;
    int height;
    int depth;
    
    public Box(int width, int height, int depth){
        width = width; // point 2
        height = height;
        depth = depth;
    }
}    

 

point 2 ) 자신의 변수에 자신의 값을 저장하게 된다. 생성자 내의 변수로만 취급된다. 아무런 의미를 가지지 못하게 된다.

이런 경우 this를 사용하여 객체 변수에 생성자 매개 변수로 받은 값을 배정할 수 있다.

 

public class Box{
    int width; // left. 객체 변수
    int height;
    int depth;
    
    public Box(int width, int height, int depth){ // right. 생성자 지역 변수
        this.width = width; // point 3
        this.height = height;
        this.depth = depth;
    }
}    

 

point 3 ) 왼쪽은 생성자를 호출한 객체의 width, 오른쪽은 생성자 지역 변수의 width이다.

 

 

this 예약어가 생성자나 메소드에서 사용될 때는 자신을 호출한 객체를 의미하며, this.width는 현재의 객체 변수 width를 의미한다.

생성자나 메소드의 매개 변수 이름이 객체 변수 이름과 같지 않을 경우에는 this를 사용하지 않아도 된다. 그러나 this를 사용함으로써 객체 변수나 생성자, 메소드 매개 변수 이름을 의미적으로 명확하게 사용할 수 있게 해 주는 이점이 있다.

 

this 예약어의 또 다른 용도로는 생성자 내에서 단독으로 사용될 수 있다는 점이 있다. 생성자 내에서 this가 단독으로 사용되는 경우는 클래스 내의 다른 생성자를 호출하는 경우이다.

생성자 내에서 this가 단독으로 사용될 시 반드시 첫 번째 라인에 위치해야 하며, 그렇지 않으면 오류가 발생한다. 예제를 보자!

 

 

class Box{
    int width;
    int height;
    int depth;
    
    public Box(){
    	this(1,1,1); // 3개의 매개 변수를 가진 생성자 호출
        System.out.println("매개 변수 없는 생성자 수행!");
    }
    
    public Box(int width){
    	this(width,1,1);
        System.out.println("매개 변수 1개 생성자 수행!");
    }
    
    public Box(int width, int height, int depth){
    	this(width,1,1);
        System.out.println("매개 변수 3개 생성자 수행!");
        this.width = width;
        this.height = height;
        this.depth = depth;
    }
}

public class BoxTest{
	public static void main(String args[]){
    	Box mybox = new Box();
       	int vol = mybox.width * mybox.height * mybox.depth;
        System.out.println("박스의 부피(매개 변수 없음) : " + vol);
        
        mybox = new Box(10);
        vol = mybox.width * mybox.height * mybox.depth;
        System.out.println("박스의 부피(매개 변수 1개) : " + vol);
        
        mybox = new Box(10,20,30);
        int vol = mybox.width * mybox.height * mybox.depth;
        System.out.println("박스의 부피(매개 변수 3개) : " + vol);
   }
}

/** output
* 매개 변수 3개 생성자 수행!
* 매개 변수 없는 생성자 수행!
* 박스의 부피(매개 변수 없음) : 1
* 매개 변수 3개 생성자 수행!
* 박스의 부피(매개 변수 1개) : 10
* 매개 변수 3개 생성자 수행!
* 박스의 부피(매개 변수 3개) : 6000
*/

 

 


참고

  • Java in a Nutshell, Benjamin J.Evans David Flanagan
  • 처음 시작하는 JAVA 프로그래밍, 김충석 저

 

 

 

'Java Live Study' 카테고리의 다른 글

Live Study 8주차 : 인터페이스  (0) 2021.01.16
Live Study 7주차 : 패키지  (0) 2021.01.02
Live Study 6주차 : 상속  (0) 2020.12.26
Live Study 5주차 : 과제  (0) 2020.12.18
Live Study 4주차 : 제어문  (0) 2020.12.12