본문 바로가기
Everyday Study

2024.06.27 (목) {포인터 변수, 조건문, 반복문, 데이터타입, JVM, new키워드 }

by xogns93 2024. 6. 27.

포인터 변수의 선언

포인터 변수는 다음과 같은 형식으로 선언됩니다.

타입 *포인터이름;

여기서 타입은 포인터가 가리킬 변수의 타입을 의미합니다. 예를 들어, 정수형 변수를 가리키는 포인터는 int *로 선언됩니다.

 

포인터 변수의 초기화

포인터 변수를 초기화하려면 다른 변수의 주소를 대입해야 합니다. 주소 연산자 &를 사용하여 변수의 주소를 얻을 수 있습니다.

int a = 10;
int *p = &a;  // 변수 a의 주소를 포인터 p에 저장

 

포인터 변수의 사용

포인터 변수를 사용하여 해당 주소에 저장된 값에 접근할 수 있습니다. 이를 역참조(dereferencing)라고 합니다. 역참조 연산자 *를 사용합니다.

int a = 10;
int *p = &a;

printf("a의 값: %d\n", a);     // 10
printf("p가 가리키는 값: %d\n", *p);  // 10

*p = 20;  // p가 가리키는 주소에 저장된 값을 20으로 변경
printf("a의 값: %d\n", a);     // 20

 


조건문(conditional statements)

조건문은 주어진 조건식의 결과에 따라 별도의 명령을 수행하도록 제어하는 명령문입니다.

조건문 중에서도 가장 기본이 되는 명령문은 바로 if 문입니다.

 

C언어에서 사용하는 대표적인 조건문의 형태는 다음과 같습니다.

 

1. if 문
2. if / else 문
3. if / else if / else 문
4. switch 문

 

반복문(iteration statements)

반복문이란 프로그램 내에서 똑같은 명령을 일정 횟수만큼 반복하여 수행하도록 제어하는 명령문입니다.

프로그램이 처리하는 대부분의 코드는 반복적인 형태가 많으므로, 가장 많이 사용되는 제어문 중 하나입니다.

 

C언어에서 사용되는 대표적인 반복문의 형태는 다음과 같습니다.

 

1. while 문

2. do / while 문

3. for 문

 


 

C++은 동적 메모리 할당과 해제를 위해 new와 delete 연산자를 제공합니다.

 

new와 delete 연산자의 동작 원리

new 연산자를 사용하여 동적으로 메모리를 할당할 때, C++ 컴파일러는 요청한 크기의 메모리를 힙(heap)이라는 메모리 영역에 할당합니다. 할당된 메모리의 주소를 반환하고, 해당 주소를 가리키는 포인터를 사용하여 할당된 메모리에 접근할 수 있습니다. delete 연산자를 사용하여 동적으로 할당된 메모리를 해제하면 해당 메모리 영역이 반환되어 다른 용도로 사용될 수 있습니다.
 

동적 메모리 할당과 해제의 중요성

동적 메모리 할당은 프로그램의 실행 중에 필요한 만큼의 메모리를 할당하고 해제할 수 있어 메모리 관리를 더욱 효율적으로 할 수 있습니다. 또한, 동적 메모리 할당을 사용하면 필요한 메모리만큼만 할당되므로 불필요한 메모리 낭비를 최소화할 수 있습니다.

 

동적 메모리 할당 시 주의사항

동적 메모리를 사용한 후에는 반드시 delete 연산자를 사용하여 할당된 메모리를 해제해야 합니다. 메모리를 해제하지 않으면 메모리 누수(memory leak)가 발생하여 메모리 자원이 고갈될 수 있습니다. 또한, 이미 해제된 메모리를 다시 해제하려고 시도하는 경우 런타임 에러가 발생할 수 있습니다.
 

패키지(Package)

자바 클래스를 모아놓은 디렉토리, 즉 폴더 개념이에요. 패키지에는 클래스 또는 인터페이스를 포함시킬 수 있고, 서로 관련된 클래스들끼리 그룹 단위로 묶어 놓아 효율적으로 관리할 수 있게 해요.

같은 이름의 클래스여도 폴더로 분리하여 서로 다른 패키지에 존재하는 것이 가능해, 자신만의 패키지 체계를 유지하면서 다른 개발자가 개발한 클래스 라이브러리의 클래스와 이름이 충돌하는 것을 피할 수 있어요.

 

package는 다중 선언이 불가능해요.

하나의 소스 파일엔 오직 하나의 package만 선언이 가능해요. package는 단순히 계층 구성을 표현하는게 아니라 컴파일 시점의 계층 구성을 정의하기 때문이에요. 그래서 package를 다중 선언하게 되면 해당 소스 파일은 다수의 폴더에 존재한다는 의미가 되요.

같은 내용과 이름은 존재할 수 있지만 그 파일 자체가 여럿 존재할 수는 없어요. 그래서 package는 소스 파일 당 하나만 선언이 가능해요.

 

package 특성
1. package는 계층 구조로 클래스 라이브러리를 관리하기 위한 컴파일러 단에서 정의하기 위한 계층 구조 정의 키워드에요.
2. package는 소스 당 하나만 선언 가능해요. 왜냐하면 파일은 오직 하나의 계층 구조를 가지기 때문이에요.
3. 그래서 유지보수를 위해서라도 package을 선언할 때 실제 폴더 구성 경로와 일치시켜야 해요.
4. 클래스의 실제 이름은 {package 구성}.{클래스 이름}이에요.

 


 

기본형(primitive) type의 특징

  • 자바 언어에 내장된 기본 유형으로 기본형 타입(primitive type)을 미리 정의하여 제공
  • 기본값이 있기 때문에 Null이 존재하지 않음
  • 실제 값을 저장하는 공간으로 stack 메모리에 저장
  • wrapper class는 각 privitive type을 클래스로 만든것

참조형(reference) type

참조란?

변수나 메서드를 모은 틀이 클래스이며, 이 클래스라는 틀로부터 만든 실제 객체가 인스턴스이고, 생성된 인스턴스를 사용하려면 그 인스턴스를 적정하는 정보(데이터의 주소?)를 알아 둘 필요가 있다.
그 정보를 참조(포인터)라고 부른다. 그리고 참조라는 값을 보관하는 타입을 참조형(reference)라고 부른다.

기본형(privitive) type을 제외한 모든 타입은 참조형(reference) type이다.
그리고 보통 객체라는 이름으로 부르기도한다.
위의 구조도와 마찬가지로 레퍼런스(reference) type은 다음이 존재한다.

  • 클래스 타입(class type)
  • 인터페이스 타입(interface type)
  • 배열 타입(array type)
  • 열거 타입(enum type)

참조형(reference) type의 특징

  • 기본형(primitive) 타입을 제외한 타입들이 모두 참조형 타입이다.
  • 빈 객체를 의미하는 Null 존재
  • 값이 저장되어 있는 곳의 주소값을 저장하는 공간으로 힙(Heap) 메모리에 저장

 

Java 프로그램은 JVM(Java Virtual Machine)이 실행된다. JVM은 운영체제에서 할당받은 메모리영역을 메소드 영역, 스레드 영역, 힙영역과 같이 세부 영역으로 구분해서 사용한다.

  1. 메소드 영역
  2. 메소드 영역은 JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역이다.
  3. 힙영역
  4. 힙 영역에서 생성된 객체와 배열은 JVM 스택 영역의 변수나, 다른 객체의 필드에서 참조한다. heap 영역에 객체를 참조하는 변수나 field가 존재하지 않으면 Garbage Collector에 의해 자동제거된다.
  5. JVM Stack Area프레임 내부에는 로컬 변수 스택이 있는데 기본 타입 변수와 참조 타입 변수가 추가되거나 제거되고, 변수는 선언된 블록 안에서만 스택으로 존재하고 블록을 벗어나면 스텍에서 제거된다. 다만 배열 같은 경우에는 배열의 변수는 스택 영역에 생성되지만 배열의 데이터 자체는 Heap 영역에 생성되어 제거되지 않습니다. 즉 Java에서 배열은 객체로 취급을 합니다.
  6. JVM 스택 영역은 각 스레드마다 한개씩 존재하고, 스레드가 시작될 때 할당된다. JVM 스택은 메소드를 호출할 때마다 프레임을 추가하고 메소드가 종료되면 해당 프레임을 제거하는 동작을 수행한다.

 

Java에서 클래스는 두 가지 주요 유형으로 나눌 수 있습니다: 외부 클래스(Outer Class)와 내부 클래스(Inner Class)입니다. 각각의 역할과 용도를 설명하겠습니다.

 

외부 클래스 (Outer Class)

외부 클래스는 일반적으로 우리가 정의하고 사용하는 클래스입니다. 이는 다른 클래스 안에 포함되지 않은 독립적인 클래스입니다. 하나의 Java 파일에는 하나의 public 외부 클래스만 있을 수 있으며, 파일 이름은 이 클래스 이름과 일치해야 합니다.

 

내부 클래스 (Inner Class)

내부 클래스는 다른 클래스 내부에 정의된 클래스입니다. 내부 클래스는 외부 클래스의 멤버처럼 행동하며, 외부 클래스의 멤버 변수와 메서드에 접근할 수 있습니다. 내부 클래스는 네 가지 유형이 있습니다:

  1. 인스턴스 내부 클래스 (Instance Inner Class)
  2. 정적 내부 클래스 (Static Inner Class)
  3. 지역 내부 클래스 (Local Inner Class)
  4. 익명 내부 클래스 (Anonymous Inner Class)

 

데이터 캡슐화(Data Encapsulation)는 객체 지향 프로그래밍의 중요한 개념 중 하나로, 데이터와 데이터를 조작하는 메서드를 하나의 단위로 묶고, 외부로부터 데이터를 보호하는 것을 의미합니다. 이를 통해 데이터 무결성을 유지하고, 클래스의 구현 세부 사항을 감추어 외부에서의 직접 접근을 제한합니다. 데이터 캡슐화는 일반적으로 접근 제어자를 통해 구현됩니다.

 

데이터 캡슐화의 주요 개념

  1. 데이터 숨김: 객체의 데이터를 외부에서 직접 접근하지 못하게 하여 보호합니다.
  2. 접근 제어자: 클래스의 멤버 변수와 메서드에 대한 접근 권한을 설정합니다.
    • private: 클래스 내부에서만 접근 가능.
    • protected: 같은 패키지 내에서와 서브클래스에서 접근 가능.
    • default (아무 접근 제어자도 없는 경우): 같은 패키지 내에서만 접근 가능.
    • public: 모든 클래스에서 접근 가능.
  3. 게터와 세터: private로 선언된 변수에 접근하고 수정하기 위해 public 메서드를 제공합니다.

 

getter와 setter는 데이터 캡슐화를 구현하는 데 사용되는 메서드입니다. 주로 private으로 선언된 인스턴스 변수의 값을 읽거나 설정하는 역할을 합니다. 이 메서드들은 객체 지향 프로그래밍에서 정보 은닉(information hiding)을 실현하는 데 중요한 역할을 합니다.

 

Getter  메서드

Getter 메서드는 주로 인스턴스 변수의 값을 반환하는 역할을 합니다. 일반적으로 다음과 같은 특징을 가집니다:

  • 접근 제어자: 대부분 public으로 선언되어야 합니다. 외부에서 접근할 수 있어야 변수 값을 읽을 수 있습니다.
  • 메서드 이름: 보통 get으로 시작하며, 그 뒤에 변수명의 첫 글자를 대문자로 시작한 이름을 붙입니다. 예를 들어, getName() 메서드는 name 변수의 값을 반환합니다.
  • 반환 값: 메서드가 읽어야 할 변수의 데이터 타입과 일치하는 값을 반환합니다.
public class Person {
    private String name;

    // Getter 메서드
    public String getName() {
        return name;
    }
}

Setter  메서드

Setter 메서드는 주로 인스턴스 변수의 값을 설정하는 역할을 합니다. 일반적으로 다음과 같은 특징을 가집니다:

  • 접근 제어자: 대부분 public으로 선언되어야 합니다. 외부에서 접근하여 변수 값을 설정할 수 있어야 합니다.
  • 메서드 이름: 보통 set으로 시작하며, 그 뒤에 변수명의 첫 글자를 대문자로 시작한 이름을 붙입니다. 예를 들어, setName(String name) 메서드는 name 변수의 값을 설정합니다.
  • 매개변수: 메서드가 설정해야 할 변수의 데이터 타입과 일치하는 매개변수를 받습니다.
  • 역할: 주로 입력된 매개변수의 값을 인스턴스 변수에 대입하여 설정합니다.
public class Person {
    private String name;

    // Setter 메서드
    public void setName(String name) {
        this.name = name;
    }
}

 

 

public class Main {
    public static void main(String[] args) {
        Person person = new Person();

        // Setter를 사용하여 변수 설정
        person.setName("Alice");

        // Getter를 사용하여 변수 읽기
        String personName = person.getName();
        System.out.println("Person's name: " + personName); // 출력: Person's name: Alice
    }
}

위 예제에서 Person 클래스의 setName() 메서드는 name 변수의 값을 설정하고, getName() 메서드는 name 변수의 값을 반환합니다. 이렇게 하면 외부에서 Person 객체의 name 변수에 접근하거나 값을 설정할 수 있지만, 직접적으로 변수에 접근할 수 없기 때문에 데이터 캡슐화를 실현할 수 있습니다.

Getter와 setter는 객체의 상태를 캡슐화하고, 외부에 안전하게 접근할 수 있는 인터페이스를 제공하여 객체 지향 프로그래밍의 캡슐화 원칙을 지원합니다.

 

데이터 캡슐화의 장점

  • 데이터 보호: 외부에서 데이터에 직접 접근하는 것을 제한하여 데이터 무결성을 유지합니다.
  • 유지보수 용이: 클래스의 내부 구현을 변경하더라도 외부 인터페이스는 동일하게 유지할 수 있습니다.
  • 코드의 가독성 및 재사용성 향상: 명확한 인터페이스를 제공하여 코드를 더 쉽게 이해하고 재사용할 수 있습니다.

 

게터(getter)와 세터(setter)는 객체 지향 프로그래밍에서 캡슐화 원칙을 구현하기 위해 사용되는 메서드입니다. 이 메서드들은 클래스의 멤버 변수에 접근하고 수정할 수 있는 방법을 제공합니다. 일반적으로 멤버 변수는 private으로 선언하여 직접 접근을 제한하고, 대신 public으로 선언된 게터와 세터 메서드를 통해 간접적으로 접근하도록 합니다.


 

다음은 Person 클래스를 완전하게 구현한 예제입니다. 이 클래스는 name과 age라는 두 개의 private 멤버 변수를 가지고 있으며, 게터와 세터 메서드를 통해 이들 변수에 접근하고 수정할 수 있습니다.

 

public class Person {
    private String name;
    private int age;

    // name 필드의 게터 메서드
    public String getName() {
        return name;
    }

    // name 필드의 세터 메서드
    public void setName(String name) {
        this.name = name;
    }

    // age 필드의 게터 메서드
    public int getAge() {
        return age;
    }

    // age 필드의 세터 메서드
    public void setAge(int age) {
        if (age > 0) {  // 나이는 양수이어야 함
            this.age = age;
        }
    }

    public static void main(String[] args) {
        Person person = new Person();
        person.setName("John");
        person.setAge(30);

        System.out.println("Name: " + person.getName());
        System.out.println("Age: " + person.getAge());
    }
}

 

Class (클래스)

클래스는 객체의 청사진 또는 설계도입니다. 클래스는 데이터와 메서드를 포함하며, 이들을 통해 특정 유형의 객체를 정의합니다. 클래스는 다음과 같은 요소를 포함할 수 있습니다:

  • 속성 (Attributes): 클래스가 가지는 데이터 또는 상태를 나타냅니다. 예를 들어, Person 클래스에는 name, age 같은 속성이 있을 수 있습니다.
  • 메서드 (Methods): 클래스가 가지는 행동 또는 기능을 나타냅니다. 예를 들어, Person 클래스에는 walk(), talk() 같은 메서드가 있을 수 있습니다.

Object (객체)

객체는 클래스의 인스턴스입니다. 즉, 클래스라는 설계도를 기반으로 만들어진 실제 존재하는 개체입니다. 객체는 클래스에서 정의한 속성과 메서드를 실제로 가지고 있으며, 메모리에 할당됩니다.

Instance (인스턴스)

인스턴스는 특정 클래스로부터 생성된 객체를 의미합니다. 일반적으로 "객체"와 "인스턴스"는 거의 동일한 의미로 사용되지만, 인스턴스는 특정 클래스의 구체적인 구현을 강조할 때 사용됩니다.

 

 

 

 

new 키워드의 역할

  1. 객체 생성: new 키워드는 클래스의 새로운 인스턴스를 생성합니다. 클래스는 객체의 설계도이며, 객체는 그 설계에 따라 만들어진 실체입니다.
  2. 메모리 할당: new 키워드는 객체가 필요로 하는 메모리를 할당하고, 객체의 생성자를 호출하여 초기화합니다.
  3. 참조 변수에 할당: new 키워드를 사용하여 생성된 객체는 참조 변수에 할당되어 사용됩니다. 참조 변수는 객체를 참조하고, 객체에 접근할 수 있는 방법을 제공합니다.

 

자바에서 static 키워드는 클래스의 멤버(필드, 메서드, 내부 클래스)와 관련된 중요한 개념입니다. static 키워드를 사용하면 해당 멤버는 인스턴스가 아닌 클래스 자체에 속하게 됩니다. 이는 특정 클래스의 모든 인스턴스가 공유하는 멤버를 만들 때 유용합니다.

  • 정적 필드: 클래스의 모든 인스턴스가 공유하는 변수.
  • 정적 메서드: 인스턴스 없이 호출할 수 있는 메서드.
  • 정적 블록: 클래스가 로드될 때 한 번 실행되는 코드 블록.
  • 정적 내부 클래스: 외부 클래스의 인스턴스 없이 사용할 수 있는 내부 클래스.

static 키워드는 메모리 사용을 효율적으로 하고, 클래스 수준에서 공유되는 멤버를 정의하는 데 매우 유용합니다.

 


자바에서는 메서드를 두 가지 주요 범주로 나눌 수 있습니다: 인스턴스 메서드(오브젝트 메서드)와 클래스 메서드(정적 메서드)입니다. 이 둘은 각각 객체 지향 프로그래밍의 특성을 반영하며, 사용하는 방식과 동작 방식에서 차이가 있습니다.

인스턴스 메서드 (오브젝트 메서드)

인스턴스 메서드는 특정한 객체의 상태(인스턴스 변수)를 조작하거나 활용하기 위해 사용됩니다. 다음은 인스턴스 메서드의 주요 특징입니다:

  • 소속: 객체의 인스턴스에 속합니다. 클래스의 각 객체(인스턴스)마다 별도로 존재하며, 객체를 생성해야만 사용할 수 있습니다.
  • 호출 방법: 객체를 생성한 후에 해당 객체의 참조 변수를 통해 호출됩니다.
  • 예시: 객체의 속성을 읽거나 수정하는 메서드, 객체의 상태를 변경하는 메서드 등이 인스턴스 메서드에 해당됩니다.

 

클래스 메서드 (스태틱 메서드)

클래스 메서드는 특정 클래스에 고정된 메서드로, 객체의 인스턴스와는 독립적으로 동작합니다. 주로 객체의 인스턴스와 관계 없는 공통된 작업을 수행하는 데 사용됩니다. 다음은 클래스 메서드의 주요 특징입니다:

  • 소속: 클래스에 속하며, 객체의 인스턴스와는 독립적으로 호출됩니다.
  • 호출 방법: 클래스의 이름을 사용하여 호출됩니다. 객체의 생성과 관계 없이 호출할 수 있습니다.
  • 예시: 객체를 생성하지 않고도 사용할 수 있는 유틸리티 메서드, 객체들 간의 공유 상태를 관리하는 메서드 등이 클래스 메서드에 해당됩니다.

생성자(Constructor)

생성자는 객체가 생성될 때 호출되어 객체의 초기화를 담당하는 특별한 종류의 메서드입니다. 주로 객체의 필드(멤버 변수)를 초기화하거나, 초기 상태를 설정하는 데 사용됩니다. 생성자의 주요 특징은 다음과 같습니다:

  • 소속: 클래스에 속하며, 객체를 생성할 때 호출됩니다.
  • 호출 방법: new 키워드를 사용하여 객체를 생성할 때 자동으로 호출됩니다.
  • 반환 유형: 생성자는 반환 유형을 가지지 않습니다. 즉, void도 명시하지 않습니다.
  • 예시: 객체가 생성될 때 초기값을 설정하는 생성자가 있습니다.

결론

자바에서는 인스턴스 메서드와 클래스 메서드가 각각 객체 지향 프로그래밍의 특성을 반영하여 사용됩니다. 인스턴스 메서드는 객체의 상태를 조작하거나 객체 간의 상호 작용을 담당하며, 클래스 메서드는 공통된 작업을 수행하거나 객체의 인스턴스와 독립적인 작업을 처리합니다. 생성자는 객체가 생성될 때 초기화를 수행하며, 클래스와 밀접한 관계를 가집니다.