클래스와 객체1

Minji Lee·2025년 3월 19일
0

JAVA

목록 보기
8/13

객체지향프로그래밍과 클래스

객체지향프로그래밍(Object-Oriented Programming;OOP)`

어떤 대상(객체)를 가지고 프로그래밍한다.

절차지향 vs 객체지향
절차지향프로그래밍은 순서대로 일어나는 일을 시간순으로 프로그래밍하는 것
객체지향프로그래밍은 객체 정의하고 객체 간 협력을 프로그래밍하는 것

클래스

객체지향프로그램은 클래스를 기반으로 프로그래밍한다.
클래스 = 객체의 속성 + 기능

  • 클래스 이름은 보통 대문자로 시작함
(접근 제어자) class 클래스명 {
	멤버 변수;
    메서드;
}

ex) 학생 클래스 만들기

public class Student {
    // 멤버 변수 → 기본 자료형 또는 참조 자료형(다른 클래스형)으로 선언 가능
    // 참조 자료형 ex) String, Date, Person(다른 클래스명) 등
    int studentID; // 학번
    String studentName; // 학생 이름
    int grade; // 학년
    String address; // 사는 곳
    
     // 메서드 
    public void showStudentInfo(){
        System.out.println(studentName+","+address);
    }
}

패키지

클래스 파일의 묶음으로, 계층구조를 가질 수 있음!

// 패키지 선언
package classpart;

메서드

메서드는 함수의 한 종류이다!

함수

하나의 기능을 수행하는 일련의 코드

함수반환형 함수이름 (매개변수1, 매개변수2, ...){
	자료형 변수명1;
    ...
    return 반환값;
}
public class Exam {
    public static void main(String[] args) throws Exception{
        int n1 = 10;
        int n2 = 20;
        int sum = add(n1, n2);
        System.out.println(n1+" + "+n2+" = "+sum);
    }
    public static int add (int num1, int num2){
        int result;
        result = num1 + num2;
        return result;
    }
}

함수 호출과 스택 메모리

함수 호출하면 그 함수만을 위한 메모리 공간이 할당되는데, 이 메모리 공간을 스택(stack)이라고 부름

함수의 장점

  1. 기능을 나누어 코드를 효율적으로 구현 가능
  2. 기능별로 함수 구현해 놓으면 같은 기능을 재활용 가능
  3. 오류 수정하는 디버깅 작업 용이

클래스 기능 구현하는 메서드(=멤버 함수)

멤버 변수 사용하여 클래스의 기능 구현

public class Student {
    // 멤버 변수
    int studentID; // 학번
    String studentName; // 학생 이름
    int grade; // 학년
    String address; // 사는 곳

    // 메서드
    // 학생 이름 반환하는 메서드
    public String getStudentName(){
        return studentName;
    }
    // 학생 이름을 멤버 변수에 대입하는 메서드
    public void setStudentName(String name){
        studentName = name;
    }
}

⭐️ 자바 이름 짓기 규약

  1. 클래스 이름은 대문자로 시작
  2. 하나의 자바 파일에 클래스 여러 개 있을 수 있지만, public 클래스는 단 하나이고 public 클래스 이름과 자바 파일 이름은 같아야함
  3. 패키지이름은 모두 소문자
  4. 변수와 메서드는 소문자로 시작, 길어지면 중간에 새 단어로 바뀔 때 대문자 사용(카멜케이스)

클래스와 인스턴스

클래스 사용과 main() 함수

main() 함수는 자바 가상 머신(JVM)이 프로그램을 시작하기 위해 호출하는 함수로, 클래스의 메서드X
[main() 함수에서 클래스 사용하는 방법]
1. 만든 클래스 내부에 main() 함수 만드는 것

package classpart;

public class Student {
    // 멤버 변수
    int studentID; // 학번
    String studentName; // 학생 이름
    int grade; // 학년
    String address; // 사는 곳

    // 메서드
    // 학생 이름 반환하는 메서드
    public String getStudentName(){
        return studentName;
    }
    // 학생 이름을 멤버 변수에 대입하는 메서드
    public void setStudentName(String name){
        studentName = name;
    }

    public static void main(String[] args){
        Student studentAhn = new Student(); // Student 클래스 생성
        studentAhn.studentName = "안경";

        System.out.println(studentAhn.studentName); // 안경
        System.out.println(studentAhn.getStudentName()); // 안경
    }
}
  • 클래스 내부에 main() 함수를 넣으면 모든 클래스가 main()함수를 포함해야함! 보통은 외부에 테스트용 클래스 따로 만들어서 실행함
  1. 외부에 테스트용 클래스 만들어 사용하는 것
package classpart;

public class StudentTest {
    public static void main(String[] args) throws Exception{
        Student studentAhn = new Student(); // Student 클래스 생성
        studentAhn.studentName = "안경";

        System.out.println(studentAhn.studentName); // 안경
        System.out.println(studentAhn.getStudentName()); // 안경

    }
}
  • 같은 패키지인 경우에는 import 따로 안해줘도 되지만, 다른 패키지인 경우 import문 사용해서 클래스 불러와야 함

new 예약어로 클래스 생성

클래스형 변수이름 = new 생성자;

  • 클래스 생성 = 클래스를 실제 사용할 수 있도록 메모리 공간(힙 메모리)을 할당 받는다는 뜻

인스턴스: 실제로 사용할 수 있도록 생성된 클래스
참조변수: 인스턴스를 가리키는 클래스형 변수

ex) Student studentAhn = new Student();

  • studentAhn은 참조변수이고, 이 변수가 생성된 인스턴스를 가리킴

인스턴스와 참조 변수

package classpart;

public class StudentTest {
    public static void main(String[] args) throws Exception{
        Student student1 = new Student(); // 첫 번째 학생 생성
        student1.studentName = "홍길동";
        System.out.println(student1.getStudentName());
        Student student2 = new Student(); // 두 번째 학생 생성
        student2.studentName = "김철수";
        System.out.println(student2.getStudentName());
    }
}
  • 참조 변수 사용
    참조변수.멤버변수
    참조변수.메서드

⭐️ 인스턴스와 힙 메모리

new Student()를 선언하면 Student 하나가 생성되는데 각 Student는 studentID, studentName 등의 멤버 변수를 가지고 있음! 이 변수들을 저장하는 공간을 힙 메모리라고 함

힙 메모리
힙(heap)은 프로그램에서 사용하는 동적 메모리 공간

  • 일반적으로 프로그램은 스택, 힙, 데이터 세 영역을 사용하는데, 객체가 생성될 때 사용하는 공간을 힙
  • 힙은 동적으로 할당되며 사용이 끝나면 메모리 해제해 주어야 하는데, C나 C++은 프로그래머가 직접 메모리 해제해주어야 하지만, 자바는 가바지 컬렉터가 자동으로 메모리 해제해줌

즉, 클래스 생성자가 하나 호출하면 인스턴스가 힙 메모리에 생성됨

  • 지역변수 studentAhn에 인스턴스가 생성된 힙 메모리 주소가 대입됨
  • 생성된 두 인스턴스는 각각 다른 메모리 공간 차지함
package classpart;

public class StudentTest {
    public static void main(String[] args) throws Exception{
        Student student1 = new Student(); // 첫 번째 학생 생성
        student1.studentName = "홍길동";
        System.out.println(student1); // classpart.Student@7a81197d -> 클래스이름@주소값
        Student student2 = new Student(); // 두 번째 학생 생성
        student2.studentName = "김철수"; //classpart.Student@5ca881b5
        System.out.println(student2);
    }
}

⭐️ 용어 정리 ⭐️

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

생성자(constructor)

생성자: 클래스를 처음 만들 때 멤버 변수나 상수를 초기화하는 것

  • 생성자는 클래스를 생성할 때만 호출함
  • 생성자 이름은 클래스 이름과 같고, 생성자는 반환 값이 없
  • 생성자가 없는 클래스는 클래스 파일을 컴파일할 때 자바 컴파일러에서 자동으로 생성자를 만들어줌
  • 자바 컴파일러는 생성자가 하나도 없는 경우에만 디폴트 생성자 제공하므로, 프로그래머가 직접 생성자 추가하면 디폴트 생성자는 만들어지지 않음!

디폴트 생성자

  • 자동으로 만들어주는 생성자
  • 매개변수 X, 구현 코드 X
package classpart;

public class Person {
    String name; // 이름
    int height; // 키
    double weight; // 몸무게
    char gender; // 성별
    boolean married; // 결혼 여부
    
    // 자바 컴파일러가 자동으로 제공하는 디폴트 생성자
    public Person() {}
}

생성자 만들기

필요한 경우 프로그래머가 직접 생성자 구현 가능

  • 주로 멤버 변수에 대한 값들을 매개변수로 받아서 인스턴스가 새로 생성될 때 멤버 변수 값들을 초기화하는 역할
  1. 생성자 만들기
package classpart;

public class Person {
    String name; // 이름
    int height; // 키
    double weight; // 몸무게
    char gender; // 성별
    boolean married; // 결혼 여부

    // 생성자 만들기
    public Person(String pname){
        name = pname;
    }
}
  1. 생성자 테스트
package classpart;

public class PersonTest {
    public static void main(String[] args){
        Person person = new Person(); // 오류 발생
    }
}
  • 오류난 이유는 생성자를 직접 구현하여 디폴트 생성자가 없기 때문임!
    따라서, 오류 없애려면 만들어 놓은 생성자로 호출하거나, 직접 디폴트 생성자 추가해야함
package classpart;

public class Person {
    String name; // 이름
    int height; // 키
    double weight; // 몸무게
    char gender; // 성별
    boolean married; // 결혼 여부
    
    // 디폴트 생성자 추가
    public Person(){}

    // 생성자 만들기
    public Person(String pname){
        name = pname;
    }
}
  • Person 클래스 생성할 때 두 생성자 중 하나 선택해서 사용

생성자 오버로드

클래스에 생성자가 두 개 이상 제공되는 경우로, 필요에 따라 매개변수가 다른 생성자를 여러 개 만들 수 있음

  • 클래스를 사용하는 코드에서는 원하는 생성자 선택해서 사용 가능
package classpart;

public class Person {
    String name; // 이름
    int height; // 키
    double weight; // 몸무게
    char gender; // 성별
    boolean married; // 결혼 여부

    // 디폴트 생성자
    public Person() {}
    // 이름을 매개변수로 입력받는 생성자
    public Person(String pname) {
        name = pname;
    }
    // 이름, 키, 몸무게를 매개변수로 입력받는 생성자
    public Person(String pname, int pheight, double pweight){
        name = pname;
        height = pheight;
        weight = pweight;
    }
}

참조 자료형

클래스 자료형으로 선언

package classpart;

public class Student {
    int studentID;
    String studentName; // String이 JDK에서 제공하는 참조 자료형
    int koreaScore;
    int mathScore;
}

만약 위 클래스에 과목의 이름 변수도 함께 추가할 경우

package classpart;

public class Student {
    int studentID;
    String studentName; // String이 JDK에서 제공하는 참조 자료형
    int koreaScore;
    int mathScore;
    String koreaSubject;
    String mathSubject;
}

위 같이 작성하면, 학생에 대한 클래스인데 과목에 대한 변수도 늘어나고 있음
따라서, 과목의 이름과 성적을 Subject 클래스로 분리하고, 학생에 Subject 변수를 각 과목별로 추가

// 과목 클래스
package classpart;

public class Subject {
    String subjectName;
    int scorePoint;
}
package classpart;

public class Student {
    int studentID;
    String studentName; // String이 JDK에서 제공하는 참조 자료형
    Subject korean; // Subject형 사용하여 선언
    Subject math; // Subject형 사용하여 선언
}

정보 은닉

접근 제어자: 예약어를 사용해 클래스 내부의 변수나 메서드, 생성자에 대한 접근 권한 지정 가능

  • public: 선언한 변수나 메서드는 외부 클래스에서 접근 가능
  • private: 선언한 변수나 메서드는 외부 클래스에서 사용 X
  • protected: 같은 패키지 내부와 상속 관계의 클래스에서만 접근 가능
  • default(아무것도 없는 경우): 같은 패키지 내부에서만 접근 가능
package classpart;

public class Student {
    int studentID;
    private String studentName; // private으로 선언
    Subject korean; // Subject형 사용하여 선언
    Subject math; // Subject형 사용하여 선언
}
package classpart;

public class StudentTest {
    public static void main(String[] args) throws Exception{
        Student student = new Student();
        student.studentName = "aa"; // 오류 발생 private으로 선언된 변수에 접근할 수 없음
    }
}
  • private으로 선언된 변수를 외부 코드에서 사용하는 방법
    → public 메서드 제공해야 함! get(), set() 메서드
package classpart;

public class Student {
    int studentID;
    private String studentName; // private으로 선언
    Subject korean; // Subject형 사용하여 선언
    Subject math; // Subject형 사용하여 선언

    // private 변수인 studentName에 접근해서 값 가져오는 public get() 메서드
    public String getStudentName(){
        return studentName;
    }
    // private 변수인 studentName에 접근해서 값 지정하는 public set() 메서드
    public void setStudentName(String studentName){
        this.studentName = studentName;
    }
}
package classpart;

public class StudentTest {
    public static void main(String[] args) throws Exception{
        Student student = new Student();
        // student.studentName = "aa"; // 오류 발생
        student.setStudentName("aa");

        System.out.println(student.getStudentName()); // aa
    }
}

정보은닉
클래스 내부에서 사용할 변수나 메서드는 private으로 선언해서 외부에서 접근하지 못하도록 하는 것

❓ 변수를 public으로 선언하는 것과 변수를 private으로 선언하고 나서 그 변수를 사용할 수 있도록 public 메서드 제공하는 것의 차이는 무엇인가?

package classpart;

public class MyDate {
    public int day;
    public int month;
    public int year;
}
package classpart;

public class MyDateTest {
    public static void main(String[] args){
        MyDate date = new MyDate();
        date.month = 2;
        date.day = 31; // 2월은 31일이 없지만, 그래도 값이 넣어짐!
        date.year = 2018;
    }
}
  • 위 코드 같이 잘못된 데이터 값을 넣어도 public 이므로 값이 들어가짐
    따라서, 잘못된 데이터가 들어가는 것을 방지하기 위해 변수를 private으로 바꾸고 public 메서드르 별도로 제공
package classpart;

public class MyDate {
    private int day;
    private int month;
    private int year;

    public void setDay(int year, int month, int day){
        if(month==2) {
            if(day<1 || day>28){
                System.out.println("오류 입니다.");
            }else{
                this.year = year;
                this.month = month;
                this.day=day;
                System.out.println(year+"년 "+month+"월 "+day+"일");
            }
        }
    }
}
package classpart;

public class MyDateTest {
    public static void main(String[] args){
        MyDate date = new MyDate();

        date.setDay(2018,2,31); // 오류 입니다.
        date.setDay(2018,2,28); // 2018년 2월 28일
    }
}

0개의 댓글