ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • object 란? boxing unboxing!
    @ 16. 1 ~ 17. 1/C# 2016. 11. 18. 03:21

    object는 System.Object의 별칭으로 C#의 모든 클래스의 최상위 부모 클래스입니다. (사실 C#의 5가지 형식(클래스, 구조체, 열거형, 델리게이트, 인터페이스 ) 중 인터페이스를 제외한 모든 형식은 System.Object를 최상위 공통 클래스로부터 파생됩니다.)

    모든 클래스는 System.Object 공통 클래스로부터 파생됩니다.



    다음은 System.Object의 기본 메소드입니다. 4개의 가상 메소드와 2개의 일반 메소드, 2개의 정적 메소드 이렇게 총 8개의 메소드를 제공합니다.

    1. namespace System

      {

      public class Object

      {

      public virtual bool Equals(object obj);

      public virtual int GetHashCode();

      public virtual string ToString();

      protected virtual void Finalize();

       

      public Type GetType();

      protected object MemberwiseClone();

      public static bool Equals(object left, object right);

      public static bool ReferenceEquals(object left, object right);

      }

      }


    위 8개 메소드에서 3개의 메소드(Equals, static Equals, static ReferenceEquals)는 객체 비교 메소드입니다.

    모두 두 비교 객체가 같으면 true를 아니면 false를 반환합니다.


    1. static void Main(string[] args)

      {

      Point pt1 = new Point(1, 2);

      Point pt2 = new Point(1, 2);

       

      if (pt1.Equals(pt2))

      Console.WriteLine("같다!");

      else

      Console.WriteLine("다르다!");

       

      if (Point.Equals(pt1, pt2))

      Console.WriteLine("같다!");

      else

      Console.WriteLine("다르다!");

       

      if (Point.ReferenceEquals(pt1, pt2))

      Console.WriteLine("같다!");

      else

      Console.WriteLine("다르다!");

      }

      }

      }

    다르다!
    다르다!
    다르다!

    • pt1.Equals(pt2)는 인스턴스(객체) 가상 메소드입니다.
    • Point.Equals(pt1, pt2)는 정적(클래스) 메소드입니다.
    • Point.ReferenceEquals(pt1, pt2)는 정적(클래스) 메소드입니다.

    위 세 Equals 메소드는 모두 System.Object의 메소드를 호출하며 참조가 다르므로 모두 거짓을 반환합니다.


    또 Equals() 정적 메소드는 Equals() 가상 메소드를 호출

    ReferenceEquals() 정적 메소드는 언제나 참조를 비교하며 같은 객체를 참조해야 true입니다



    System.Object의 8개 메소드 중 GetHashCode() 가상 메소드는 객체마다 부여되는 해시 코드 식별 번호로 일반적으로 해시 알고리즘이나 자료구조에서 사용합니다. 한 가지 주의할 점은 Equals() 가상 메소드를 재정의하면 꼭 GetHashCode() 가상 메소드도 함께 재정의해야 합니다. 대부분의 해시 알고리즘에서 이 두 함수를 같이 사용하기 때문입니다.






    17장 상속에서 알 수 있듯 자식 객체는 부모 형식으로 자동(암묵적) 형변환될 수 있으며 부모 형식 객체는 자식 형식으로 명시적 형변환 될 수 있습니다.

    또, 기본 내장 형식은 대부분 값 형식이며(7장 참고) 스택에 객체가 할당됩니다. Object 클래스는 참조 형식이며 힙에 객체가 할당됩니다.

    값 형식은 모두 ValueType으로부터 파생되며 ValueType은 객체가 값 형식으로 동작하도록 가장 메소드를 재정의합니다.




    모든 형식은 부로 형식으로 자동(암시적) 형변환될 수 있으므로 n과 pt는 모두 부모 형식인 Object 클래스 형식으로 변환될 수 있습니다.

    하지만 여기서 한가지 문제가 있습니다. pt는 참조형식(heap 객체이므로)이므로 Object 클래스 형식으로 바로 변환될 수 있지만 n은 값 형식(stack 객체)이므로 Object 클래스 형식으로 바로 변환될 수 없으며 이때 값 형식인 n(stack 객체)을 참조 형식인 box(n) 개체(heap 객체)로 만들어야 합니다. 이와 같은 변환 과정을 박싱(boxing)이라 합니다.

    1. using System;

      namespace NetGong

      {

      class Point

      {

      int x, y;

      public Point(int _x, int _y)

      {

      x = _x;

      y = _y;

      }

      public void Print()

      {

      Console.WriteLine("({0}, {1})", x, y);

      }

      }

      class Program

      {

      static void Main(string[] args)

      {

      int n = 100; //  형식

      Point pt = new Point(3, 5); // 참조 형식

       

      Object o1 = n; //자동 변환(암묵적부모 형식으로 boxing

      Object o2 = pt;//자동 변환(암묵적부모 형식으로 x

       

      Console.WriteLine("{0}", o1);

      Console.WriteLine("{0}", o2);

      }

      }

      }

       

    100
    NetGong.Point

    WriteLine()은 o1과 o2의 ToString()을 호출하므로 o1은 100이 출력되며 o2는 클래스 이름이 출력됩니다.

    n(int)은 o1(object)으로 자동 변환되며 boxing이 발생됩니다.

    pt(Point)은 o2(object)으로 자동 변환되며 (참조 형식에서 참조 형식으로 변환이므로) boxing이 발생되지 않습니다.

     

     

     

    이와 같은 박싱(boxing)은 프로그램 중에 빈번하게 일어납니다.

    이렇게 부모 형식으로 형변환(업 캐스팅)하는 이유는 여러 가지 이유가 있지만 중요한 이유 중 하나는 부모 형식은 자식 형식보다 더 추상적인 형식이며(구체적이 아닌) 이렇게 추상적인 형식을 사용하면 공통된 인터페이스를 사용할 수 있고 재사용성이나 유연성을 키울 수 있으며 다형적으로 동작하게 할 수 있습니다. 이것이 객체지향(OO)의 핵심 개념입니다.

    다음은 아~~~주! 간단한 구체적 인터페이스와 추상적 인터페이스를 보인 예제입니다.


    다음은 언박싱 예제로 박싱된 객체를 다시 언박싱하여 stack객체로 변환합니다.

    1. using System;

      namespace NetGong

      {

      class Program

      {

      static void Main(string[] args)

      {

      int n1 = 100;

      object o = n1;

       

      //언박싱(unboxing) 발생

      int n2 = (int)o; // 명시적으로 형변환(자식 형식으로 다운 캐스팅)

      Console.WriteLine("{0} {1}", n1, n2);

      }

      }

      }

    100 100

    결과는 박싱된 객체 o를 명시적으로 형변환하여 unboxing하며 unboxing된 객체는 stack에 올라옵니다. 이 이름 없는 객체를 n2의 대입하는 예제입니다. 여기서 주의할 점은 unboxing하면 stack에 unboxing된 무명 객체가 생성되며 이 객체를 다시 n2에 대입하게 됩니다. 지금은 상관없지만 다음에 버그가 만들어질 수 있으므로 꼭 알고 있어야 합니다.

     


    '@ 16. 1 ~ 17. 1 > C#' 카테고리의 다른 글

    C#AVL 트리  (0) 2016.11.18
    델리게이트, 이벤트 - 1  (0) 2016.11.18
    참조형식과 값형식 차이, 함수 매개변수(in, out, ref)  (0) 2016.11.18
    getter setter  (0) 2016.11.18
    C# 시작2  (0) 2016.11.16
Designed by Tistory.