객체지향 프로그래밍
  • 캡슐화 - 관련된 데이터와 기능을 하나의 단위로 묶는 것. 정보를 은닉하고 외부에서 직접적인 접근을 제한하여 안정성과 유지보수성을 높힌다.
  • 상속 - 부모 클래스의 특성과 동작을 자식 클래스가 상속받아 재사용한다. 코드의 중복을 줄이고 코드의 구조화와 유지보수를 용이하게 한다.
  • 다형성 - 오버로딩, 오버라이딩을 통해 하나의 메서드 이름으로 다양한 동작을 할 수 있다. 코드의 가독성과 재사용성을 높힌다.
  • 추상화 - 복잡한 기능을 단순화하여 필요한 기능에 집중한다.(세부 구현을 감추고 개념을 구현)
  • 객체 - 데이터와 메서드를 가지고 있으면서 실제로 상호작용하며 프로그램이 동작하는 것. 클래스로 구현되어 모듈화나 재사용성이 높다.

 

 

클래스

객체를 생성하기 위한 템플릿 또는 설계도. 데이터와 메서드를 하나로 묶은 사용자 정의 타입. 속성이나 동작에 대한 정의가 되어 있다. 클래스를 통해 인스턴스(객체)를 만들 수 있다.

- 구성요소: 필드(맴버변수), 메서드(맴버함수), 생성자(객체가 형성될 때 자동으로 호출되는 메서드), 소멸자(메모리에서 소멸될 때 자동으로 생성되는 메서드)

 

객체

클래스로 생성된 인스턴스. 클래스의 실체화된 형태. 독립적인 상태로 고유의 데이터를 가지고 있다.

 

// 클래스 선언
class Person
{
    public string Name;
    public int Age;

    public void PrintInfo()
    {
        Console.WriteLine("Name: " + Name);
        Console.WriteLine("Age: " + Age);
    }
}

Person p = new Person(); // 레퍼런스 타입
p.Name = "John";
p.Age = 30;
p.PrintInfo(); // 출력: Name: John, Age: 30

 

구조체와 클래스

  • 구조체와 클래스 모두 사용자 정의 형식. 우리가 원하는 자료형과 기능들을 뭉쳐 놓은 상태이다.
  • 구조체는 값 형식이며, 스택이라는 메모리에 각자 자동으로 할당된다.
  • 클래스는 참조 형식이며, 힙 영역에 동적 할당된다.
  • 구조체는 상속을 받을 수 없지만 클래스는 단일 상속과 다중상속이 가능하다.
  • 구조체는 작은 크기의 데이터나 단순한 구조를 작성할 때 적합하고 복잡한 경우에 클래스가 훨씬 더 사용하기 편하다.

 

접근 제한자

  • public: 외부에서 자유롭게 접근 가능
  • private: 같은 클래스 내부의 메서드나 필드에서 접근 가능
  • protected: 같은 클래스 내부와 상속 받은 자식까지만 접근 가능

 

필드

클래스 내부에 선언된 변수(맴버 변수). 데이터를 저장한다.

객체의 특징이나 속성들을 표현하기 위해 사용하며, 일반적으로 외부에서 접근하지 못하도록  private로 접근 제한자를 사용한다.

class Player
{
    // 필드 선언
    private string name;
    private int level;
}

 

메서드

클래스 내부에 선언된 함수(맴버 함수). 클래스의 동작을 정의한다.

클래스나 구조체에 대한 기능들을 정리하며, 일반적으로 외부에서 호출할 수 있도록 public으로 만들어준다.

class Player
{
    // 필드
    private string name;
    private int level;

    // 메서드
    public void Attack()
    {
        // 공격 동작 구현
    }
}

Player player = new Player();  // Player 클래스의 인스턴스 생성
player.Attack();  // Attack 메서드 호출

 

생성자

객체를 생성할 때 호출되는 메서드. 객체를 초기화하고 필요한 초기값을 설정하는 역할을 한다.

  • 클래스와 동일한 이름을 가지고 있으며, 반환 타입이 없다.
  • 여러 개를 정의 할 수 있고 매개변수의 개수와 타입에 따라 다른 생성자를 호출 할 수 있다.(오버로딩)
  • 기본적으로 매개변수가 없는 디폴트 생성자가 자동으로 생성되지만, 최소 하나라도 생성자를 만들었다면 디폴트 생성자는 더 이상 만들어지지 않는다.
class Person
{
    private string name;
    private int age;

    public void PrintInfo()
    {
        Console.WriteLine($"Name: {name}, Age: {age}");
    }
}



Person person1 = new Person();

 

소멸자

객체가 소멸이 될 때 호출되는 메서드.

  • 클래스와 동일한 이름을 가지고 있으며, 이름 앞에 ~ 기호를 붙인다.
  • 가비지 컬렉터(Garbage Collector)가 클래스가 아무데도 사용되지 않아서 메모리를 해제할 때 소멸자가 자동으로 호출된다.
  • 파일 핸들, 네트워트 연결, 데이터베이스 연결 등 외부적인 파일들에 대한 자원을 해제할 수 있다.
  • 배열이나 다른 클래스들의 선언을 인위적으로 해제할 수 있다.
  • 소멸이 언제 되는지에 대한 로깅과 디버깅을 할 수 있다.
  • 오버로딩 할 수 없다.
class Person
{
    private string name;

    public Person(string newName)
    {
        name = newName;
        Console.WriteLine("Person 객체 생성");
    }

    ~Person()
    {
        Console.WriteLine("Person 객체 소멸");
    }
}

 

프로퍼티(Property)

은닉화한 필드값(private 등)을 외부에서도 접근할 수 있는 중간 매개 역할을 만들어주는 것.

프로퍼티를 사용하여 데이터 유효성이나 제한을 거는 등 필드 접근을 제한하면 코드의 안정성과 가독성을 높힐 수 있다.

class Person
{
    private string name;
    private int age;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public int Age
    {
        get { return age; }
        set { age = value; }
    }
}

Person person = new Person();
person.Name = "John";   // Name 프로퍼티에 값 설정
person.Age = 25;        // Age 프로퍼티에 값 설정

Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");  // Name과 Age 프로

보통 변수와 동일한 이름을 사용한다.(완전히 동일하면 안되기 때문에 대문자로 변환)

 

프로퍼티 접근 제한자 적용과 유효성 검사 예제

class Person
{
    private string name;
    private int age;

    public string Name
    {
        get { return name; }
        private set { name = value; } // 프로퍼티 자체는 외부에서 접근 가능하지만 세팅은 클래스 내부에서 하겠다는 제한
    }

    public int Age
    {
        get { return age; }
        set
        {
            if (value >= 0) // 대입하려는 값이 유효한가(나이에 음수가 들어오지 못하도록 제한)
                age = value;
        }
    }
}

Person person = new Person();
person.Name = "John";     // 컴파일 오류: Name 프로퍼티의 set 접근자는 private입니다.
person.Age = -10;         // 유효성 검사에 의해 나이 값이 설정되지 않습니다.

Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");  // Name과 Age 프로퍼티에 접근하여 값을 출력합니다.

 

자동 프로퍼티

프로퍼티를 간단히 정의하고 사용할 수 있도록 한다. 필드의 선언과 접근자 메서드의 구현을 컴파일러가 자동으로 처리한다.

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Person person = new Person();
person.Name = "John";     // 값을 설정
person.Age = 25;          // 값을 설정

Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");  // 값을 읽어 출력

 

 

메서드

중복되는 코드를 뭉쳐놓은 하나의 블록. 코드를 재사용하거나 모듈화 할 수 있게 만들어주는 것.

  • 코드의 재사용성
  • 모듈화
  • 가독성과 유지보수성
  • 중복 제거
  • 추상화

 

메서드의 구조

[접근 제한자] [리턴 타입] [메서드 이름]([매개변수])
{
    // 메서드 실행 코드
}
  • 접근 제한자(Access Modifier): 메서드에 접근할 수 있는 범위 지정. (public, private, protected 등)
  • 리턴 타입(Return Type): 메서드가 반환하는 값의 데이터 타입 지정. (반환 값이 없을 경우 void 사용)
  • 메서드 이름(Method Name): 메서드를 호출할 때 사용하는 이름.
  • 매개변수(Parameters): 메서드에 전달되는 입력 값. 0개 이상의 매개변수를 정의할 수 있다.
  • 메서드 실행에 코드(Method Body): 중괄호({}) 안에 메서드가 수행하는 작업을 구현하는 코드 작성.

 

매개변수와 반환값

static void PrintLine()
{
    for (int i = 0; i < 10; i++)
    {
        Console.Write("=");
    }
    Console.WriteLine();
}

static void PrintLine2(int count)
{
    for (int i = 0; i < count; i++)
    {
        Console.Write("=");
    }
    Console.WriteLine();
}

static int Add(int a, int b)
{
    return a + b;
}

static void Main(string[] args)
{
    // 사용 예시
    PrintLine();
    PrintLine2(20);

    int result = Add(10, 20);
    Console.WriteLine(result);
}

 

 

오버로딩

매개변수 목록이 다중 정의된 것. 매개변수의 개수, 타입, 순서가 다르면 다른 메서드로 취급한다. 메서드의 기능이나 작업은 동일하지만 입력값에 따라 다르게 동작해야 할 때 사용된다.

 

// 오버로딩
static int AddNumbers(int a, int b)
{
    return a + b;
}

static float AddNumbers(float a, float b)
{
    return a + b;
}

static int AddNumbers(int a, int b, int c)
{
    return a + b + c;
}


static void Main(string[] args)
{
    // 오버로딩 메서드 호출
    int sum1 = AddNumbers(10, 20);  // 두 개의 정수 매개변수를 가진 메서드 호출
    float sum3 = AddNumbers(10, 20); // 두 개의 실수 매개변수를 가진 메서드 호출
    int sum2 = AddNumbers(10, 20, 30);  // 세 개의 정수 매개변수를 가진 메서드 호출

 

 

재귀 호출

메서드가 자기 자신을 호출하는 것. 호출 스택에 호출된 메서드의 정보를 순차적으로 쌓고, 메서드가 반환되면서 스택에서 순차적으로 제거되는 방식이다. 메모리 사용량이 더 크고 실행 속도가 느릴 수 있으며,  무한 루프에 빠질 수 있기 때문에 주의해야한다.

 

// 재귀 호출
static void CountDown(int n)
{
    if (n <= 0)
    {
        Console.WriteLine("Done");
    }
    else
    {
        Console.WriteLine(n);
        CountDown(n - 1);  // 자기 자신을 호출
    }
}

static void Main(string[] args)
{
    // 재귀 호출
    CountDown(5);
}

 

 

구조체

여러 개의 데이터를 묶어서 하나의 사용자 정의 형식으로 만들기 위한 방법. 값 형식(대입하거나 값을 할당할 때 복사되는 것)으로 분류되며 struct 키워드를 사용하여 선언한다.

*자세한 내용은 class와 비교하며 언급

 

 

메서드

메서드가 호출될 때마다 코드를 수행한다. 여러 번 작성하지 않고 재사용 할 수 있다는 장점이 있다.

static void Main(string[] args)
{
    singHappyBirthday();
    singHappyBirthday();
    singHappyBirthday();
}
static void singHappyBirthday()
{
    Console.WriteLine("생일 축하합니다.");
    Console.WriteLine("생일 축하합니다.");
    Console.WriteLine("사랑하는 당신의");
    Console.WriteLine("생일 축하합니다.");
}

 

이름을 넣어 노래를 부르기 위해 변수를 만들어보자.

static void Main(string[] args)
{
    String name = "김사람";

    singHappyBirthday();
}
static void singHappyBirthday()
{
    Console.WriteLine("생일 축하합니다.");
    Console.WriteLine("생일 축하합니다.");
    Console.WriteLine("사랑하는 " + name);
    Console.WriteLine("생일 축하합니다.");
}

 

다른 메서드 내의 변수를 불러올 수 없기 때문에 오류가 발생할 것이다.

 

그렇기 때문에 매개변수와 인자를 통해 메서드에 값을 전달하도록 한다.

static void Main(string[] args)
{
    String name = "김사람";

    singHappyBirthday(name);
}
static void singHappyBirthday(String name)
{
    Console.WriteLine("생일 축하합니다.");
    Console.WriteLine("생일 축하합니다.");
    Console.WriteLine("사랑하는 " + name);
    Console.WriteLine("생일 축하합니다.");
}

 

여러 개의 인수를 입력할 수 있다.

마찬가지로 데이터 타입과 변수명을 입력해주면 된다.

static void Main(string[] args)
{
    String name = "김사람";
    int age = 3;

    singHappyBirthday(name, age);
}
static void singHappyBirthday(String name, int age)
{
    Console.WriteLine("생일 축하합니다.");
    Console.WriteLine("생일 축하합니다.");
    Console.WriteLine("사랑하는 " + name + "의");
    Console.WriteLine(age + "번째 생일을");
    Console.WriteLine("생일 축하합니다.");
}

 

또한 매개변수와 변수명이 같지 않아도 된다.

static void Main(string[] args)
{
    String name = "김사람";
    int age = 3;

    singHappyBirthday(name, age);
}
static void singHappyBirthday(String who, int num)
{
    Console.WriteLine("생일 축하합니다.");
    Console.WriteLine("생일 축하합니다.");
    Console.WriteLine("사랑하는 " + who + "의");
    Console.WriteLine(num + "번째 생일을");
    Console.WriteLine("생일 축하합니다.");
}

중요한 것은 데이터 타입과 값의 순서이다.

 

 

'C# > C#' 카테고리의 다른 글

24. 오버로딩(Method Overloading)  (0) 2023.09.26
23. 리턴(Return Keyword)  (0) 2023.09.20
21. ForEach문(Foreach Loop)  (0) 2023.09.18
20. 배열(Arrays)  (0) 2023.09.14
19. 계산기 프로그램(Calculator Program)  (0) 2023.09.13
함수(Methods)

프로그래밍에서는 한줄의 코드가 아니라 여러 줄의 코드를 조합해서 작업을 수행한다. 그런데 반복적으로 어떤 작업을 처리해야 할 때, 동일한 코드를 여러 번 작성하는 것은 비효율적이다. 그렇기 때문에 어떠한 하나의 작업단위를 이루는 여러가지 코드를 한 묶음으로 만들어서 재사용 할 수 있도록 만든 것이 바로 함수, 또는 메서드라고 한다.

일반적으로 메서드(Method)는 클래스(class)의 기능적인 부분을 나타내는 함수(function)를 나타내는데, 자바에서는 모든게 클래스로 관리되기 때문에 메서드라는 이름으로 통용하고 있다.

 

1. 입력과 출력이 모두 있는 경우

출력은 콘솔의 문자 출력이 아닌 데이터 반환을 뜻한다.

static int mod (int a, int b) {
    int result = a % b;
    return result;
}

반환할 데이터 타입을 정한 후, 메서드의 이름을 정의한다. 괄호 안에는 매개변수, 즉 파라미터(parameter)로 정의한다. 그리고 매개 변수로 받은 값을 함수에서 어떤 식으로 사용할지에 대해 코드로 표현한다. 다시 데이터를 반환해서 사용할 수 있도록 하기 위해 return함수를 사용한다.

 

2. 입력은 있는데 출력은 없는 경우

static void printNum (int a) {
    System.out.println(a);
}

출력이 없다는 것은 아무런 데이터형으로도 만들 필요가 없다는 뜻이기 때문에 void라는 키워드를 작성한다. 서로 다른 메소드에서 쓰이는 변수들은 함수 내에서만 공유되므로 이름이 같아도 서로 공유되지 않는다. 위의 코드는 콘솔에서 출력될 뿐, a로 입력받은 데이터를 이후에 활용할 수 있도록 메모리에 저장해주지 않는다. 즉, 콘솔로 출력 후, a라는 데이터는 시스템에서 휘발된다.

 

3. 입력은 없는데 출력이 있는 경우

static String greeting() {
    return "Hello!";
}

입력값이 없기 때문에 파라미터 자리에는 아무 것도 입력하지 않는다. 그리고 위에서 지정한 데이터 타입인 문자열(String)을 리턴할 수 있도록 String 값을 넣어준다.

 

4. 입력과 출력이 모두 없는 경우

static void greeting_2() {
    System.out.println("Hello!");
}

위 코드는 콘솔로 출력만 하고 데이터 자체는 휘발된다.

 

static 안에서 실행되기 위해서는 함수에도 static이 붙어있어야한다.

 

이제 위의 모든 경우의 함수를 main에서 실행해보자.

public static void main(String[] args) {
	int mod_result = mod(3, 2); // 1번의 경우
	System.out.println(mod_result); // 1

	printNum(10); // 2번의 경우 // 10

	String str = greeting(); // 3번의 경우
	System.out.println(str); // Hello!

	greeting_2(); // 4번의 경우 // Hello!
}

 

 

'Back-End > Java' 카테고리의 다른 글

객체지향 - 객체지향 프로그래밍  (0) 2023.05.18
회원가입 프로그램 실습 - 자바(Java) 편  (1) 2023.05.16
자료구조 - 배열, 리스트, 맵  (0) 2023.05.12
제어문 - 조건문과 반복문  (0) 2023.05.11
연산자  (0) 2023.05.10

+ Recent posts