나 개발자 진짜 되냐?

[ C# 기본 문법 21 ] 값형과 참조형 / 박싱과 언박싱 본문

C# 을 맛보았어요!/문법정리를 해보았어요!

[ C# 기본 문법 21 ] 값형과 참조형 / 박싱과 언박싱

Snow Rabbit 2024. 9. 23. 22:28

 

 

 

참조형은.. 들어본 같은데..

값형은 뭐지?

 

 

같이 공부해 보자!

 


🌟 값형 🌟

변수에 값을 직접 저장

 

변수가 실제 데이터를 보유

 

해당 변수를 다른 변수에 할당하거나 전달할 때는 값이 복사


복사된다고 해서 걱정될 텐데

 

해당 변수 값만 변경해서  다른 변수에 영향을 주지 않는다.

 

 

EX)

int, float, double, bool 등의 기본 데이터 타입

+

struct

struct MyStruct
{
    public int Value;
}

MyStruct struct1 = new MyStruct();
struct1.Value = 10;

MyStruct struct2 = struct1; // struct2는 struct1의 값 복사

struct2.Value = 20;

Console.WriteLine(struct1.Value); // 출력 결과: 10

 

🌟 참조형 🌟

변수가 데이터에 대한 참조(메모리 주소)를 저장

 

변수가 실제 데이터를 가리키는 참조를 갖고 있으며

 

해당 변수를 다른 변수에 할당하거나 전달할 때는 참조가 복사

 

참조형 변수의 수정은

 

동일한 데이터를 가리키고 있는 다른 변수에 영향을 줄 수 있다.

내용이 바뀌면 그 주소값을 쓰는 모든 애들도 

다 변경된 데이터를 쓰게 됨.

 

EX)

클래스, 배열, 인터페이스 등

 

class MyClass
{
    public int Value;
}

MyClass obj1 = new MyClass();
obj1.Value = 10;

MyClass obj2 = obj1; // obj2는 obj1과 동일한 객체를 참조

obj2.Value = 20;

Console.WriteLine(obj1.Value); // 출력 결과: 20

 

 

 둘의 결괏값이 다르다.

 

하나는 값이 그대로 복사되었고

하나는 주소로 따라간 그 데이터를 직접 수정해서

값이 다르게 나온다.

 

 

 

나름 알기 쉽게 그림으로 정리해 보았다.

 

이 둘의 차이점을

마지막으로 정리한다면

 

값형은 실제 데이터를 변수에 저장하고

( struct 1, 2 )

 

참조형은 데이터에 대한 참조를 ( 주소 ) 변수에 저장

( obj1,2에 넌 클래스의 주소 100번지가 저장 )

 

 

값형은 변수가 독립적인 데이터를 가지며

struct2의 값을 바꿔도 문제 X

 

참조형은 변수가 동일한 데이터를 참조

 

데이터 값 변경 시

참조되는 모든 친구들 값 다 변경

 

 

❗ 편하게 클래스 빼고 다 값형으로 생각해도 된다 ❗

 


 

🌟 박싱 🌟

 

값형참조형으로 변환하는 과정

 

값형 변수의 값을 메모리의 힙 영역에 보내준다.

 

박싱을 통해 값형참조형의 특징을 갖게 되며,

참조형 변수로 다뤄질 수 있습니다.

 

값형을 변환했다고 사라지는 건 아니다.

그러다 보니 메모리를 좀 더  많이 쓰게 되고..

 

박싱 된 값형은 참조로 전달되므로

메모리 오버헤드가 발생할 수 있습니다.

 

🌟 언박싱 🌟

 

박싱과 반대되는 개념이 아니라!!

박싱을 다시 푸는

원래상태로 돌려놓는 것이다.

 

박싱 된 객체를 다시 값형으로 변환하는 과정

박싱된 객체에서 값을 추출하여 값형 변수에 할당

 

박싱 된 객체와 원래 값형은 서로 독립적이기 때문에

상호 간에 영향은 주지 않는다.

 

 

예시를 하나 가지고 왔다.

using System;

class Program
{
    static void Main()
    {
        // 값형
        int x = 10;
        int y = x;
        y = 20;
        Console.WriteLine("x: " + x); // 출력 결과: 10
        Console.WriteLine("y: " + y); // 출력 결과: 20

        // 참조형
        int[] arr1 = new int[] { 1, 2, 3 };
        int[] arr2 = arr1;
        arr2[0] = 4;
        Console.WriteLine("arr1[0]: " + arr1[0]); // 출력 결과: 4
        Console.WriteLine("arr2[0]: " + arr2[0]); // 출력 결과: 4

        // 박싱과 언박싱
        int num1 = 10;
        object obj = num1; // 박싱, 여기서 object는 최상위 클래스이다.
        // 그래서 모든 형식을 참조할수 있는 포괄적 타입
        int num2 = (int)obj; // 언박싱
        Console.WriteLine("num1: " + num1); // 출력 결과: 10
        Console.WriteLine("num2: " + num2); // 출력 결과: 10
    }
}

쉬워 보이죠?

 

보이긴 뭐..

다 쉽지

 

리스트형식으로도 나타낸 예시가 있다.

 

List<object> myList = new List<object>();

// 박싱: 값 형식을 참조 형식으로 변환하여 리스트에 추가
int intValue = 10;
myList.Add(intValue); // int를 object로 박싱하여 추가

float floatValue = 3.14f;
myList.Add(floatValue); // float를 object로 박싱하여 추가

// 언박싱: 참조 형식을 값 형식으로 변환하여 사용
int value1 = (int)myList[0]; // object를 int로 언박싱
float value2 = (float)myList[1]; // object를 float로 언박싱

리스트를 <object>로 선언해주다 보니

 

값을 넣어주면서 박싱이 자동적으로 되며,

다시 돌려놓으려면

리스트의 0번째 즉, object가 있는 곳을 int로 바꿔주는 느낌이다.

 


값형, 참조형

굉장히 중요한 내용이다!

 

박싱, 언박싱 또한

자주 보이는 코드라고 한다.

 

함께 봐두어서

다양하게 활용하고 싶다!