자바(JAVA)

자바 - 객체 지향(1) : 객체 지향, 클래스와 객체, 객체 변수와 메서드

BlueNoa 2023. 9. 8. 18:08
728x90
반응형

<목차>

 

 


• 객체 지향 프로그래밍

객체 지향 프로그래밍(OOP, Object-Oriented Programming)은 소프트웨어 개발에 사용되는 프로그래밍 패러다임 중 하나로, 현실 세계의 개념을 모델링하고 이를 객체(Object)라는 기본 단위로 표현하는 개념이다.

 

주된 목표로는 코드의 재사용성, 유지보수성, 확장성 향상과 복잡한 S/W 시스템을 더욱 효과적으로 설계하고 구현하기 위한 도구이다.

 

OOP의 주요 개념과 원칙

1. 클래스(Class)

클래스는 객체를 생성하기 위한 템플릿 또는 설계도 역할을 한다.

객체의 상태(속성, 멤버 변수) 및 행동(메서드, 함수)를 정의한다.

 

2. 객체(Object)

객체는 클래스의 인스턴스다. 클래스를 실체화하여 생성한 것이 곧 객체라는 것이다.

객체는 데이터와 해당 데이터를 조작하기 위한 메서드를 갖고, 서로 다른 객체 간에 통신이 가능하다.

 

3. 캡슐화(Encapsulation)

캡슐화는 객체의 상태를 숨기고 외부에서 접근을 제어하는 개념이다. 이를 통해 데이터 은닉(Data Hiding)이 가능하며, 객체 내부를 변경하지 않고도 외부 인터페이스를 수정할 수 있다.

 

4. 상속(Inheritance)

상속은 부모  클래스(슈퍼 클래스)의 특성을 자식 클래스(서브 클래스)가 상속 받는 개념이다. 이를 통해서 코드를 재사용할 수 있고, 계층 구조의 클래스를 구성할 수 있다.

 

5. 다형성(Polymorphism)

다형성은 객체가 여러 형태를 가질 수 있는 능력을 의미한다. 같은 이름의 메서드가 서로 다른 클래스에서 구현될 수 있으며, 이를 통해 객체의 유연성이 높아진다.

 

<예시 - 계좌 데이터에 대한 객체 지향 프로그래밍의 유/무>

비객체 지향(Non-OOP) 방식

// 게좌 정보를 저장하는 배열
String[] account = new String[100]; // 계좌 번호
double[] balances = new double[100]; // 잔금
String[] owners = new String[100]; // 소유자

// 계좌에 입금하는 함수
void deposit(int accountIndex, double amount) {
	balances[accountIndex] += amount; // 해당 계좌 인덱스의 잔고에 금액을 저장
}

// 계좌의 잔액을 조회하는 함수
double getBalance(int accountIndex) {
	return balances[accountIndex];
}

...... 나머지 생략

반면 객체 지향 방식을 사용하면 훨씬 간편해진다.

 

객체지향(OOP) 방식

위 예시는 각각의 함수를 호출하여 데이터를 넣어주고 불러오고 기억해야 하지만 객체 지향 방식을 사용하는 경우 각각의 객체를 생성하여 캡슐화된 객체 간 데이터 공유와 조작을 통해 결과를 도출할 수 있어 전역 변수나 함수의 호출을 최소화할 수 있다.

또 필요한 경우 클래스 내부의 메서드를 수정만 하면 이후에도 정상적으로 작동하기 때문에 효율이 매우 좋다.

class BankAccount{
    private String account;
    private double balances;
    private String owner;

    public BankAccount(String account, double balances, String owner) {
        this.account = account;
        this.balances = balances;
        this.owner = owner;
    }

    public void deposit(double amount) {
        balances += amount;
        System.out.println(this.owner + "님의 잔액은 현재 " + amount + "입금하여 " + balances + "입니다.");
    }

    public void withdraw(double amount) {
        if (amount <= balances) {
            balances -= amount;
        } else {
            System.out.println("잔액 부족");
        }
        System.out.println(this.owner + "님의 잔액은 " + amount + "출금하여 " + balances + "입니다.");
    }

    public double getBalances() {
        return balances;
    }
}


public class sample {
    public static void main (String[] args) {
    	// 고객의 정보를 매번 저장하고 호출하는 것이 아닌 객체를 생성하여 관리한다.
        BankAccount account1 = new BankAccount("1141517", 2500.0, "고객1");
        BankAccount account2 = new BankAccount("1542216", 4241.0, "고객2");

        account1.deposit(200.0);
        account2.withdraw(3000.0);
        double balance1 = account1.getBalances();
        System.out.println(balance1);
        double balance2 = account2.getBalances();
        System.out.println(balance2);

    }
}

<결과>

고객1님의 잔액은 현재 200.0입금하여 2700.0입니다.
고객2님의 잔액은 3000.0출금하여 1241.0입니다.
2700.0
1241.0

 

반응형

• 클래스(Class)와 객체(Object)

위에서도 클래스에 대해 간단히 소개했지만 보다 정확히(자세히) 설명해야 된다고 생각한다.

클래스는 객체를 생성하기 위한 청사진 또는 템플릿이다. 클래스는 객체의 속성(멤버 변수, 필드)과 동작(메서드, 함수)를 정의한다.

클래스는 실제로 메모리에 기억(적재)되지는 않는다. 클래스는 객체를 생성하기 위한 설계도이기 때문에 객체를 생성할 때마다 메모리에 할당된다.

 

<예시>

class Car {
    String maker;
    String model;
    int year;

    // 생성자
    public Car(String maker, String model, int year) {
        this.maker = maker;
        this.model = model;
        this.year = year;
    }

    // 메서드
    public void buy() {
        System.out.println(this.maker + " 회사의 " + this.model + " " + this.year + " 연식 차량을 구매하셨습니다.");
    }
}

※ 일반적으로 파일 단위당 하나의 클래스를 생성한다.

 

객체(Object)

- 객체는 클래스의 인스턴스로 클래스를 실체화하여 생성한 것이 객체다. 객체는 클래스에서 정의한 속성과 동작을 가지며, 메모리에 할당된다.

- 클래스를 기반으로 한 여러 개의 객체를 생성할 수 있으며, 이러한 객체들은 각각 고유한 상태와 동작을 가질 수 있다.

 

<예시>

	// Car 클래스의 인스턴스 생성
        Car myCar = new Car("테슬라", "모델3", 2023);
        Car friendsCar = new Car("현대", "아반떼", 2021);

        // 객체의 메서드 호출
        myCar.buy();
        friendsCar.buy();

Car 라는 클래스 하나로 myCar, friendsCar 등 여러 객체를 생성할 수 있다.

 

<예시 전체 코드>

더보기
class Car {
    String maker;
    String model;
    int year;

    // 생성자
    public Car(String maker, String model, int year) {
        this.maker = maker;
        this.model = model;
        this.year = year;
    }

    // 메서드
    public void buy() {
        System.out.println(this.maker + " 회사의 " + this.model + " " + this.year + " 연식 차량을 구매하셨습니다.");
    }
}

public class sample {
    public static void main (String[] args) {
        // Car 클래스의 인스턴스 생성
        Car myCar = new Car("테슬라", "모델3", 2023);
        Car friendsCar = new Car("현대", "아반떼", 2021);

        // 객체의 메서드 호출
        myCar.buy();
        friendsCar.buy();
    }
}

 

 

객체와 인스턴스의 차이점

위 내용에서 객체에 대해 설명할 때 '객체는 클래스의 인스턴스'라고 했다. 간단히 설명하면 위 예시들을 바탕으로 설명하면 'Car myCar = new Car()'에서 myCar는 객체이다. 그리고 myCar 객체는 Car 클래스의 인스턴스다.

즉, 관계 위주로 설명하기 위해서 용어를 구분지은 것이다.

 

728x90

 

• 객체 변수(Instance variable)

객체 변수는 객체에 대한 참조(Reference)를 저장하는 변수를 말한다. 풀어서 설명하면 실제 객체가 아닌 객체의 주소나 참조를 저장하는 변수다. 이를 통해 해당 객체의 속성과 메서드에 접근할 수 있다.

 

꼭 기억해야 하는 내용으로 객체 변수는 결코 서로 공유하지 않는다는 것이다. 무슨 뜻이냐면 각각의 객체 변수의 값은 독립적으로 유지된다는 것이다. 아래 예시에서 student 클래스로부터 생성된 인스턴스인 st1 객체는 name과 classroom, age의 값을 받았고, st2도 받았다. 그렇지만 st1과 st2의 객체 변수가 참조하는 주소는 서로 다르다는 것이다.

 

<예제 - 객체 변수>

class student {
    // 객체 변수
    String name;
    String classroom;
    int age;

    public student(String name, String classroom, int age) {
        this.name = name;
        this.classroom = classroom;
        this.age = age;
    }

    public void Introduction() {
        System.out.println("이름 : " + name);
        System.out.println("학급 : " + classroom);
        System.out.println("나이 : " + age);
        System.out.println("--------------------------");
    }
}


public class sample {
    public static void main (String[] args) {
        // 객체 생성 및 객체 변수 사용
        // 클래스에서 선언된 변수들은 객체 변수라고 생각하면 된다.
        student st1 = new student("김기한", "A", 17);
        student st2 = new student("송하나", "C", 18);

        // 객체 변수를 이용하여 객체 내의 메서드 호출
        st1.Introduction();
        st2.Introduction();
    }
}

 


메서드(Method)

이전 게시물 중에 자바의 소스 코드 구조에 대해 설명하면서 메서드에 대해서 간단하게 언급했던 적이 있다.

[참고 - https://bluenoa.tistory.com/76#text1]

 

자바 - 소스코드(형태, 요소 등)

자바 소스코드의 구성 요소 자바 코드 형태 • 자바 소스코드의 구성 요소 큰 틀로 보면 패키지(Package), 임포트(Import), 클래스(Class), 인터페이스(Interface), 메서드(Method) 등으로 구성된다. 이 요소

bluenoa.tistory.com

 

앞에서 설명한 예시에서 객체 변수를 student 메서드를 통해 이름, 학급, 나이를 대입했다. 하지만 객체 생성과 동시에 값을 전달해주었기 때문에 이번에는 좀 변형시킨 예시를 사용하려 한다.

 

<예시 - 이전 예시에서 변경>

class student {
    // 객체 변수
    String name;
    String classroom;
    int age;

    public void student(String name, String classroom, int age) {
        this.name = name;
        this.classroom = classroom;
        this.age = age;
    }

    public void Introduction() {
        System.out.println("이름 : " + name);
        System.out.println("학급 : " + classroom);
        System.out.println("나이 : " + age);
        System.out.println("--------------------------");
    }
}


public class sample {
    public static void main (String[] args) {
        student st1 = new student();
        

    }
}

위 예시에서 클래스 이름을 'classr'로 변경하였다. 그리고 student 메서드에서 'void'를 추가하였고, main에서 바로 값을 받으면서 객체를 생성하는 것이 아닌 객체 생성만 하였다.

여기서 student 메서드는 String name, classroom 및 int age를 입력 값으로 받게 되고, void는 '리턴 값'이 없다는 것을 의미한다.

 

'this'의 의미

this.name, this.classroom, this.age 등으로 'this'라는 것을 사용하는 것을 볼 수 있다.

	this.name = name;
        this.classroom = classroom;
        this.age = age;

'this'는 현재 객체를 가리키는 특별한 참조인데 클래스 내부에서 현재 객체의 멤버 변수에 접근할 수 있다.

간단한 예로 클래스 classr에 전역 변수 name이 있다면 메서드 내에서 사용되는 멤버 변수와 구분할 수 있다는 것이다.

 

주의사항으로는 인스턴스 메서드 내에서만 사용 가능하며, 정적(static) 메서드에서는 사용할 수 없다.

this를 사용하는 것은 자유지만, 변수명 충돌을 방지하거나 가독성을 높이기 위해 사용된다.

 

 

매개 변수(Parameter)와 인수(Argument)의 차이점

다시 메서드에 대한 이야기로 돌아가서 다른 프로그래밍 언어에서는 메서드 즉, 함수는 따로 독립적으로 존재할 수 있다. 예를 들어 파이썬에서는 def 등으로 함수를 어디서든 선언하여 사용할 수 있었다. 하지만 자바에서는 클래스 내부에만 존재할 수 있고, 클래스 내에 있는 함수를 메서드라 칭한다.

메서드(함수)는 매개 변수(Parameter) 또는 인수(Arguments)를 전달 받을 수 있는데 두 용어는 자주 헷가릴 수 있다.

간단한 예시로 구별할 수 있다.

// x와 y는 매개 변수
public int add(int x, int y) {
	int result = x + y;
    return result;
}

// 2와 8은 인수
int result = add(2, 8);

 

객체를 매개 변수로 사용하는 메서드

매개 변수로 객체를 전달하면 해당 객체의 상태를 변경하거나 해당 객체에 대한 작업을 수행할 수 있다.

 

<예시 - 학생 정보 객체를 사용하여 성적 계산>

class Student {
    private String name; // 이름
    private int id; // 학생 식별 아아디
    private double grade; // 성적

    // 이름과 아이디를 받아오고 성적은 0으로 고정
    public Student(String name, int id) {
        this.name = name;
        this.id = id;
        this.grade = 0.0;
    }
    
    // 성적을 입력
    public void setGrade(double grade) {
        this.grade = grade;
    }

    public double getGrade() {
        return grade;
    }

    public String getName() {
        return name;
    }

    public int getId() {
        return id;
    }
}

// 성적 계산용 클래스
// Student 클래스로부터 생성된 객체를 받아온다.
class GradeCal {
    public void calculate(Student student, double grade) {
        student.setGrade(grade);
        System.out.println(student.getName() + " 학생의 성적은 " + student.getGrade() + "입니다.");
    }
}


public class sample {
    public static void main (String[] args) {
        Student st1 = new Student("김하늘", 101);
        Student st2 = new Student("송하나", 102);
        
        // 계산하기 위한 객체 생성
        GradeCal cal = new GradeCal();
        cal.calculate(st1, 42.4);
        cal.calculate(st2, 90);
    }
}

<결과>

김하늘 학생의 성적은 42.4입니다.
송하나 학생의 성적은 90.0입니다.

 

위 예시처럼 메서드에 값 대신 객체를 전달하여 수행하는 메서드가 있다. 하지만 값을 전달하는 것객체를 전달하여 수행하는 것에는 차이가 존재한다. 값을 전달받은 경우 독립된 서로 다른 객체는 값을 공유하지 않는다고 위에서 언급한 적이 있다. 하지만 객체 자체를 매개 변수로 전달하면 입력한 객체의 값마저 변경이 된다.

 

위 예시를 통해 설명하면 Student 클래스의 student에서 grade를 0으로 입력하였고, 이를 GradeCal 클래스가 전달 받아 setGrade 메서드로 값을 갱신하였다. 또 private인 객체 변수에 접근하였다.

만약 객체가 아닌 값으로 전달 받았다면 Student 클래스의 값에는 영향이 없었을 것이다.

그래도 이해가 안된다면 다음의 예시를 참고하자.

 

<예시>

값에 의한 호출(Call by Value)

class examValue {
    void examValue(int num) {
        num += 1;
    }
}

class Number {
    int num = 2;
}

public class sample {
    public static void main (String[] args) {
        Number n = new Number();
        examValue exv = new examValue();
        exv.examValue(n.num);
        System.out.println(n.num);
    }
}

결과 : 2

 

객체에 의한 호출(Call by Reference)

class examValue {
    void examValue(Number n) {
        n.num += 1; // 변경
    }
}

class Number {
    int num = 2;
}

public class sample {
    public static void main (String[] args) {
        Number n = new Number();
        examValue exv = new examValue();
        exv.examValue(n); // 변경
        System.out.println(n.num);
    }
}

결과 : 3

 

 

 

728x90
반응형