본문 바로가기
[Naver Cloud Camp 7] 교육 정리

네이버 클라우드 캠프 29일차 230605

by 우기37 2023. 6. 5.

#1 교육정리

1) 클래스와 객체

2) 메서드

3) 인스턴스

4) 생성자

5) 참조 자료형

 

 

 

#2 클래스와 객체

객체지향 프로그래밍(Object-Oriented Programming)이란, 조립식 프로그래밍이다. 객체를 조립하여 전체 프로그램을 만드는 것이다. 

흔히 OOP 라고 부릅니다.

객체를 정의하고 객체가 어떤 기능을 제공하고 객체 간 협력을 어떻게 구현할 지를 고민 해서 프로그래밍하는 것입니다.

 

조립식으로 프로그램을 만들면 좋다. 고장이 나도 해당 부분만 수리하면 된다. 또 기능을 추가할 때, 만들어서 끼워 넣으면 된다. 

또한 이러한 객체는 클래스로 만들어집니다.

 

 

그렇다면, 클래스란 객체를 만들기 위한 설계도이다. 해당 설계도를 통해 만들어진 무언가! 이를 객체 또 다른 표현으로 인스턴스(instance)라 한다. 

클래스는 객체의 속성과 기능을 코드로 구현한 것입니다.

- 개발자가 자신이 개발하는 프로그램에서 사용할 특별한 형식의 데이터를 다룰 수 있는 새로운 데이터 타입을 정의하게 해주는 문법이다.
- 즉 byte, short, int, long, float, double, boolean, char 외에 새 형식의 새로운 메모리 구조를 갖는 데이터 타입을 정의할 수 있다.
- 이렇게 정의한 새 데이터 타입을 "사용자 정의 데이터 타입(user defined data type)" 이라 한다.

 

클래스 문법의 활용
1) 사용자 정의 데이터 타입과 그 타입의 값을 다루는 연산자를 정의할 때 사용한다.
2) 서로 관련된 일을 하는 메서드를 관리하기 쉽게 분류하여 묶는 용도로 사용한다.

 

프로그램을 만들려면 여러 객체가 필요하다. 여러 객체를 만들려면, 객체별 클래스가 필요하다. 결과적으로, 프로그램을 만들기 위해서는 클래스를 잘 만들어야 한다.

그리고 보통 자바에서 클래스의 이름은 대문자로 시작합니다. 소문자로 해서 오류가 발생하는 것은 아니지만, 이러한 개발자들 사이의 규칙을 코딩 컨벤션(coding convension) 이라고 불립니다.

 

클래수의 구조는 클래스를 잘 만들려면 그 구조를 알아야 한다. 클래스는 두 영역으로 나뉜다. 상태를 정의하는 필드(fields)와 동작을 정의하는 메소드(methods)이다. 

설계 예

고양이를 클래스로 설계해보자. 아래와 같이 클래스를 도식화 한것을 클래스 다이어그램(class diagram)이라 한다. 

구현 예

이제 이를 코드로 구현해야 한다. 왜? 그래야 객체를 만들 수 있다. 

그림 및 글 일부 출처 : https://cloudstudying.kr/lectures/195

 

추가적으로 패키지란 간단히 말하면 클래스 파일의 묶음입니다.

패키지를 만들면 프로젝트 하위에 물리적으로 디렉터리가 생성됩니다. 또한 패키지는 계층 구조를 가질 수 있습니다. 프로젝트를 수행할 때 패키지의 계층 구조를 구성하는 것은 전체 프로젝트의 소스 코드를 어떻게 관리할지와 관련이 있습니다.

 

패키지 선언은 다음과 같이 합니다.

package domain.student.view;

public class StudentView {
}

클래스 이름은 StudentView 이지만, 클래스의 전체 이름은 domain.student.view.StudentView 입니다. 클래스 이름이 같다고 해도 패키지 이름이 다르면 클래스 전체 이름이 다른 것이므로 다른 클래스가 됩니다. 다시 말해 같은 이름의 클래스라도 다른 패키지에 속해 있으면 서로 연관리 없습니다.

 

 

 

#3 메서드

메서드는 객체의 기능을 구현하기 위해서 클래스 내부에 구현되는 함수의 한 종류 입니다.

 

함수는 이름이 있고 입력 값과 결과 값을 갖습니다. 두 수를 입력받아서 '더하기 함수'를 거치면 두 수의 합을 반환합니다.

함수의 이름을 붙일 때는 의미를 알 수 있는 단어를 사용하는 것이 좋습니다. 앞의 예는 두 수를 더하는 함수이므로 add 라고 이름을 짓겠습니다. 그리고 더할 두 수는 각각 num1, num2 라고 정하겠습니다. num1, num2 와 같이 함수의 입력으로 받는 변수를 '매개변수'라고 합니다. 그리고 두 수를 더한 결과 값을 result 변수에 저장하여 돌려줍니다. 이를 '결과를 반환한다'고 하며, 이렇게 함수를 수행한 후 결과로 되돌려 주는 값인 result를 '반환 값' 이라고 부릅니다.

 

코드로 보면 아래와 같습니다.

public class Add1 {
	public static void main(String[] args) {
    
    int add(int num1, int num2) {	// 함수 이름 : add // 매개변수 : num1, num2
    int result;
    result = num1 + num2;	// result : 결과 값
    return result;	// return : 반환 값
  }
 }
}

 

함수의 장점)

1. 함수를 사용하면 기능을 나누어 코드를 효율적으로 구현 할 수 있습니다.

2. 기능별로 함수를 구현해 놓으면 같은 기능을 매번 코드로 만들지 않고 그 기능의 함수를 호출하면 되니깐 편리합니다.

3. 프로그램을 실행할 때 생긴 오류를 수정하는 디버깅 작업을 할 때도 편리합니다. 하나의 기능이 하나의 함수로 구현되어 있기 때문에 오류가 난 기능만 찾아서 수정하면 되기 때문입니다.

 

 

 

 

#4 인스턴스

먼저 아래와 같이 코드를 살펴 보겠습니다.

public class Exam0122 {

	static class Score {	//static class Score 안의 변수를 '멤버 변수' 라 합니다.
    String name;
    int kor;
    int eng;
    int math;
    int sum;
    float aver;
  }

  public static void main(String[] args) {

    // 클래스를 이용하면 성적 정보와 같은 여러 개의 값을 한 번에 리턴 받을 수 있다.
    // main() 함수
    Score s = createScore("홍길동", 100, 100, 100);
    printScore(s);

    Score s2 = createScore("임꺽정", 90, 80, 70);
    printScore(s2);

    Score s3 = createScore("유관순", 80, 70, 60);
    printScore(s3);
  }

  static void printScore(Score s) {
    System.out.printf("%s: %d, %d, %d, %d, %.1f\n",
        s.name, s.kor, s.eng, s.math, s.sum, s.aver);
  }

  // 클래스를 이용하면 성적 정보를 하나로 묶어 리턴할 수 있다.
  // - Score 인스턴스를 생성하여 리턴한다.
  // - 더 정확하게 표현하면, Score 인스턴스를 생성한 후 그 주소를 리턴한다.
  static Score createScore(String name, int kor, int eng, int math) {
    Score s = new Score();

    s.name = name;
    s.kor = kor;
    s.eng = eng;
    s.math = math;
    s.sum = s.kor + s.eng + s.math;
    s.aver = s.sum / 3;

    return s; // s에 저장된 인스턴스의 주소를 리턴한다.
    //! 로컬 변수는 메서드 호출이 끝난 다음에 삭제된다고 했는데
    // 위에서 생성한 s 변수도 삭제되고,
    // 파라미터 name, kor, eng, math도 삭제되는게 아닌가요?
    // => 예 삭제됩니다.
    // => 모든 로컬 변수는 메서드 호출이 끝나면 스택 메모리에서 삭제됩니다.
    //
    // 하나 더?
    // Score 인스턴스도 삭제되는게 아닌가요?
    // => 삭제되지 않습니다. 인스턴스는 힙(heap) 메모리에 생성됩니다.
    //    어떤 메서드에서 인스턴스를 생성하든지 간에
    //    힙에 생성된 것은 메서드 호출이 끝나더라도 삭제되지 않습니다.
    //    오직 스택(stack) 메모리에 생성된 로컬 변수만이 삭제됩니다.
  }
}

홍길동: 100, 100, 100, 300, 100.0
임꺽정: 90, 80, 70, 240, 80.0
유관순: 80, 70, 60, 210, 70.0

 

클래스 영역에 선언되며, 클래스의 인스턴스를 "생성"할 때 ( new 연산자 이용) 만들어진다.

따라서 인스턴스 변수 값을 읽거나 저장하기 전에는 먼저 인스턴스를 생성해야 한다.

 

인스턴스는 메모리의 빈 공간에 저장된다.

만약 인스턴스를 10개 생성했다면, 10개의 독립적인 저장공간이 발생하는 것이다.

따라서 인스턴스마다 고유한 상태를 유지해야할 경우, 인스턴스 변수로 선언한다.

 

EX) 신용카드를 발급할 때 생각해보자. 카드마다 서로 다른 카드번호를 가져야 한다.

이러한 경우 인스턴스 변수를 선언한다.

 

 

인스턴스와 참조변수)

객체란 '의사나 행위가 미치는 대상'이며, 이를 코드로 구현한 것이 클래스입니다. 그리고 클래스가 메모리 공간에 생성된 상태를 인스턴스라고 했습니다. 또한 생성된 클래스의 인스턴스를 객체라고도 합니다.

클래스의 생성자를 호출하면 인스턴스가 만들어집니다. 인스턴스는 여러 개 생성할 수도 있습니다. 클래스는 하나이지만, 이 클래스로부터 여러 개의 각각 다른 인스턴스를 생성할 수 있습니다.

 

참조 변수를 사용하면 인스턴스의 멤버 변수와 메서드를 참조하여 사용할 수 있는데 이 때 도트(.) 연산자를 사용합니다. 다음은 studentAhn 참조 변수로 studentName 멤버 변수에 이름을 저장하고 getStudentName() 메서드를 사용하는 코드입니다.

 

studentAhn.studentName = "홍길동";	// 멤버 변수 사용
System.out.println(studentAhn.getStudentName());	// 메서드 사용

 

인스턴스와 힙 메모리)

new Student() 를 선언하면 student 하나가 생성되는데 각 Student는 studentID, studentName 등의 멤버 변수를 가지고 있습니다. 그런데 이들 변수를 저장할 공간이 있어야 합니다. 이 때 사용하는 메모리가 힙 메모리(heap memory) 입니다. 클래스 생성자를 하나 호출하면 인스턴스가 힙 메모리에 생성되는 것입니다.

Student studentAhn = new Student();

 

그림의 studentAhn 변수는 지역 변수입니다. 지역 변수는 스택 메모리에 생성됩니다. 그리고 인스턴스는 힙 메모리에 생성됩니다. 지역 변수 studentAhn에 생성된 인스턴스를 대입하는 것은 studentAhn에 인스턴스가 생성된 힙 메모리의 주소를 대입한다는 것과 같은 의미입니다.

 

여기서 힙 메모리란 힙은 프로그램에서 사용하는 동적 메모리(dynamic memory) 공간을 말합니다. 일반적으로 프로그램은 스택, 힙, 데이터 이렇게 세 영역을 사용하는데, 객체가 생성될 때 사용하는 공간이 힙입니다. 힙은 동적으로 할당되며 사용이 끝나면 메모리를 해제해 주어야 합니다. C나 C++ 언어에서는 프로그래머가 직접 메모리를 해제해야 하지만, 자바에서는 가비지 컬렉터(garbage collector)가 자동으로 메모리를 해제해 줍니다.

 

자 그럼 아래와 같이 용어 정리를 한번 해보겠습니다.

용어 설명
객체 객체 지향 프로그램의 대상, 생성된 인스턴스
클래스 객체를 프로그래밍 하기 위해 코드로 만든 상태
인스턴스 클래스가 메모리에 생성된 상태
멤버 변수 클래스의 속성, 특성
메서드 멤버 변수를 이용하여 클래스의 기능을 구현
참조 변수 메모리에 생성된 인스턴스를 가리키는 변수
참조 값 생성된 인스턴스의 메모리 주소 값

 

 

 

 

#5 생성자

public class PersonTest {
	public static void main(String[] args) {
    	Person personLee = new Person();	//Person() = 생성자
  }
}

위 예제에서 Person() 같은 함수를 생성자라고 합니다. 클래스의 멤버 변수는 메서드에 의해 값이 변경될 수도 있지만, 처음 클래스를 생성할 때 값을 정해야 하는 경우도 있습니다. 생성자가 하는 일은 클래스를 처음 만들 때 멤버 변수나 상수를 초기화하는 것입니다.

 

디폴트 생성자에 대해서 정리 해보겠습니다. 생성자는 클래스를 생성할 때만 호출합니다. 생성자 이름은 클래스 이름과 같고, 생성자는 반환 값이 없습니다. 그런데 Person 클래스를 살펴보면 Person() 생성자가 따로 없습니다. 생성자가 없는 클래스는 클래스 파일을 컴파일할 때 자바 컴파일러에서 자동으로 생성자를 만들어 줍니다.

 

필요한 경우 프로그래머가 직접 생성자를 구현할 수도 있습니다. 생성자는 주로 멤버 변수에 대한 값들을 매개변수로 받아서 인스턴스가 새로 생성될 때 멤버 변수 값들을 초기화하는 역할을 합니다. 즉, 인스턴스가 생성됨과 동시에 멤버 변수의 값을 지정하고 인스턴스를 초기화하기 위해 생성자를 직접 구현하여 사용합니다.

 

public class PersonTest {
	public static void main(String[] args) {
    	Person PersonKim = new Person();	// main() 함수 안에 디폴트 생성자로 클래스를
        personKim.name = "김유신";			// 생성한 후 인스턴스 변수 값을 따로 초기화
        personKim.weight = 85.5F;
        personKim.height = 180.0F;
        
        Person personLee = new Person("이순신", 175, 75);	// 인스턴스 변수 초기화와 동시에 클래스 생성
     }
   }

 

 

 

#6 참조 자료형

크기가 정해진 기본 자료형(int, char, float, double 등) 으로 선언하는 변수가 있고, 클래스 자료형으로 선언하는 참조 자료형 변수가 있습니다. 참조 자료혀 변수의 특징에 대해 좀 더 자세히 살펴보고, 클래스를 선언하여 참조형을 이용한 프로그램을 구형해 봅시다.

 

public class Student1 {
	int studentID;
    String studentName;
    int koreaScore;
    int mathScore;
  }

 

여기에서 String이 JDK(Java Development Kit) 에서 제공하는 참조 자료형입니다. 나머지 변수는 기본 자료형을 사용했습니다.

성적을 저장하는 변수가 두 개 있는데, 만약 성적뿐만 아니라 이 학생이 수강하는 과목의 이름도 함께 저장해야 한다면 어떻게 할까요? 아주 간단한 방법으로는 String을 사용해서 과목 이름 변수까지 추가할 수 있습니다.

 

 

public class Student2 {
	int studentID;
    String studentName;
    int koreaScore;
    int mathScore;
    String koreaSubject;	// 과목 이름 변수 추가
    String mathSubject;	// 과목 이름 변수 추가
  }

 

이 클래스는 학생에 대한 클래스인데 과목에 대한 변수가 계속 늘어나고 있습니다. 이 문제를 해경하기 위해 과목의 이름과 성적을 Subject라는 클래스로 분리하고, 학생에 Subject 변수를 각 과목별로 추가해 보겠습니다. 

 

public class Subject {	// 과목 클래스
	String SubjectName;
    int scorePoint;
    }

 

public class Student3 {
	int studentID;
	String studentName;
    Subject korean;
    Subject math;
  }

 

기존의 Student2 클래스에 과목 이름을 추가해야 한다면, koreanSubjectName, mathSubjectName 이렇게 두 개의 변수를 추가해야 할 것입니다. 하지만 Subject로 클래스를 분리하면 subjectName은 Subject 클래스에 선언하면 됩니다. 그리고 국어 과목 이름은 korean.subjectName으로 사용하고, 수학 과목 이름은 math.subjectName으로 사용할 수 있어 편리합니다.

 

참조 자료형은 프로그래머가 필요에 의해 만든 클래스를 사용할 수도 있고 JDK에서 제공하는 클래스를 사용할 수도 있습니다. 시본 자요형을 사용하듯이 클래스 작료형 변수를 선언해서 사용한다고 생각하면 이해하기 쉽습니다.

 

 

 

#7 정보 은닉

 

 

 

#8 static 변수