본문 바로가기
JAVA

[JAVA] - 인스턴스 멤버와 정적 멤버

by nam_ji 2024. 1. 31.

인스턴스 멤버, 정적 멤버

1. 용어정리

  • 인스턴스 멤버 : 객체를 생성한 후 사용할 수 있는 필드와 메서드 (인스턴스 필드와 인스턴스 메서드)
  • this : 객체 내부에서도 인스턴스 멤버에 접근하기 위해 this를 사용할 수 있습니다.
    • 주로 생성자와 메서드의 매개변수 이름이 필드와 동일한 경우, 인스턴스 멤버인 필드임을 명시하기 위해 사용합니다.
  • 정적 멤버 : 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메서드입니다.
  • static : 정적 멤버를 선언할 때마다 사용하는 키워드입니다.
  • 싱글톤 : 전체 프로그램에서 단 하나의 객체만 만들도록 보장해야 하는 경우 사용하는 코드 패턴입니다.
  • final 필드 : 초기값이 저장되면 이것이 최종값이 되어 프로그램 실행 도중 수정할 수 없는 필드입니다.
  • 상수 : 불변의 값을 저장하는 정적 필드, final static 키워드로 선언입니다.

2. 인스턴스 멤버와 정적 멤버

  • 인스턴스 멤버 : 객체마다 가지고 있는 멤버
    • 인스턴스 필드 : 힙 영역의 객체마다 가지고 있는 멤버, 객체마다 다른 데이터를 저장합니다.
    • 인스턴스 메서드 : 객체가 있어야 호출 가능한 메서드, 클래스 코드(메서드 영역)에 위치하지만, 이해하기 쉽도록 객체마다 가지고 있는 메서드라고 생각해도 됩니다.
  • 정적 멤버 : 객체와 상관없이 클래스당 하나씩 생기는 멤버입니다. -> 동일한 클래스의 모든 객체들에 의해 공유됩니다.
    • 정적 필드 및 상수 : 객체 없이 클래스만으로도 사용 가능한 필드입니다.
    • 정적 메서드 : 객체 없이 클래스만으로도 호출 가능한 메서드입니다.

 

3. 인스턴스 멤버 및 정적 멤버와 static 실습

  • 인스턴스 멤버 : 객체를 생성한 후 사용할 수 있는 필드와 메서드
    • // 인스턴스 멤버 예시
      public class Member {
          // 필드
          int InstanceMember;
      
          // 메서드
          String setInstanceMember (String instanceMember) {
              return instanceMember;
          }
      }
      
      public class Main {
          public static void main(String[] args) {
              Member member = new Member();
              System.out.println(member.InstanceMember = 10);
              System.out.println(member.setInstanceMember("인스턴스 멤버"));
          }
      }
      
      // 출력 : 10
      // 출력 : 인스턴스 멤버
  • 정적 멤버와 static
    • 클래스에 고정된 멤버로서 객체 생성하지 않고, 사용할 수 있는 필드와 메서드입니다.
    • static과 함께 선언합니다.
    • 메인 실행 파일에서 객체 생성 없이 도트연산자로 접근하여 사용합니다.
    • 인스턴스 필드가 있는 클래스의 객체를 생성하면 객체마다 인스턴스 필드에 새로운 메모리를 할당합니다.
      하지만 static 정적 필드의 경우 클래스 자체에 붙어 있는 것으로 아무리 객체를 많이 생성하더라도 메모리는 한 번만 할당됩니다.
      즉, 정적 필드의 경우 해당 클래스의 모든 객체는 단 하나의 메모리를 참조하고 있는 것입니다.
    • static 메서드는 객체 없이도 존재하기 때문에 this 사용이 불가능하고 static 멤버에만 접근할 수 있습니다.
      이러한 문제는 static 메서드, 필드가 객체 없이도 사용할 수 있어야만 하기 때문에 생기는 문제입니다.
    • // 정적 (static) 멤버
      public class Member {
      	// 정적 필드
          static int staticMember;
      
      	// 정적 메서드
          static String setStaticMember (String staticMember) {
              return staticMember;
          }
      }
      
      public class Main {
          public static void main(String[] args) {
              System.out.println(Member.staticMember = 100);
              System.out.println(Member.setStaticMember("정적 멤버"));
          }
      }
      
      // 출력 : 100
      // 출력 : 정적 멤버

 

4. 멤버 선택 기준

  • 객체마다 다를 수 있는 필드값 -> 인스턴스 필드로 선언합니다.
  • 객체마다 다른 필요 없는 값 -> 정적 필드로  선언합니다.
  • 메서드 블록에 인스턴스 필드 또는 인스턴스 메서드를 사용할 경우 -> 인스턴스 메서드로 선언합니다.
  • 메서드 블록에 인스턴스 멤버 (필드, 메서드)를 사용하지 않을 경우 (매개변수, 메서드 내 변수만 사용) -> 정적 메서드로 선언합니다.

5. 정적 메서드 선언 시 주의점

  • 정적 메서드 선언 시 그 내부에 인스턴스 필드 및 메서드 사용 불가합니다.
  • 정적 메서드 선언 시 그 객체 자신 참조인 this 키워드 사용 불가합니다.
  • 정적 메서드에서 인스턴스 멤버를 사용하려는 경우 -> 객체 우선 생성 후 참조 변수로 접근합니다.
    • public class Member {
          static class InstanceClass {
              // 인스턴스 필드와 메서드
              int instanceMember;
              void instaceMethod() {}
          }
      
          // 정적 필드와 메서드
          static int staticMember;
          static void staticMethod() {
      
          }
      
          // 정적 메서드
          static void Method1 () {
      //        this.instanceMember = 10; // 컴파일 에러
      //        this.instaceMethod(); // 컴파일 에러
          staticMember = 10; // 가능
          staticMethod(); // 가능
          }
      
          // 정적 메서드에서 인스턴스 멤버 사용
          static void Method () {
              InstanceClass instanceClass = new InstanceClass();
              instanceClass.instanceMember = 10;
              instanceClass.instaceMethod();
          }
      }

6. 싱글톤

  • 전체 프로그램에서 단 하나의 객체만 만들도록 보장하는 코딩 기법
    • 작성법
      1. 클래스 외부에서 new 연산자를 통해 생성자를 호출하는 것을 불가하도록 private 접근 제어자 사용합니다.
      2. 자신의 타입인 정적 필드를 선언한 후 자신의 객체를 생성해 초기화합니다.
      3. 외부에서 호출할 수 있는 getInstance() 선언합니다.
      4. 정적 필드에서 참조하는 자신의 객체를 리턴합니다.
    • 정리하자면, 싱글톤은 단 하나의 객체만 만들도록 하는 기법이므로 해당 클래스 파일에서 생성자는 private으로 해주고 정적 필드에 해당 생성자를 이용하여 객체를 만듭니다. 그러면 이제 객체는 단 하나만 있는 상황입니다.
      이때 외부에서 이 객체를 호출할 수 있도록 정적 메서드 getInstance를 선언하여 리턴값으로 해당 객체를 줍니다. 결과적으로 해당 클래스에 해당하는 객체는 단 하나가 되는 것입니다.
      • // 클래스 파일
        public class SingletonClass {
            // 정적 필드
            // 자기 자신의 타입의 필드를 정적으로 선언하고 자기 자신의 객체를 생성합니다.
            // class 내부에서는 private으로 선언된 생성자를 이용해서 객체를 만들 수 있습니다.
            private static final SingletonClass singletonClass = new SingletonClass();
        
            // 생성자
            private SingletonClass () {
        
            }
        
            // 정적 메서드
            // 외부에서 호출할 수 있어야 하므로 private을 붙이면 안됩니다.
            // 자기 자신의 타입을 리턴타입으로 설정합니다.
            static SingletonClass getInstance() {
                return singletonClass;
                // 자기 자신의 타입을 리턴해야 하므로 위에 선언한 필드를 리턴합니다ㅣ.
            }
        }
        
        public class SingletonMain {
            public static void main(String[] args) {
                SingletonClass singletonClass = SingletonClass.getInstance();
            }
        }
    • 단 하나의 객체만 존재하므로 결국 같은 곳을 참조합니다.

7. final 필드와 상수

  • 초기값이 저장되면 최종값이 되어 프로그램 실행 도중 수정이 불가능한 필드입니다.
  • final 필드의 초기값 주는 방법
    • 단순 값일 경우 필드 선언 시 초기화합니다. (주로 정적 필드 (상수)일 경우)
    • 객체 생성 시 외부 데이터로 초기화 필요한 경우 생성자에서 초기화합니다. (주로 인스턴스 필드일 경우)
  • 인스턴스 final 필드
    • 객체에 한번 초기화된 데이터를 변경 불가로 만들 경우
    • final 타입 필드;
  • 정적 final 필드
    • static final로 선언된 필드는 대부분 상수이기 때문에 불변의 상수 값을 저장하는 변수명은 관례적으로 대문자입니다.
    • 불변의 값인 상수를 만들 경우
    •  static final 타입 상수 (변수명) = 초기값;
  • public class FinalClass {
        final String nation = "Korean";
        final String phone;
        final String name;
    
        FinalClass(String phone, String name) {
            this.phone = phone;
            this.name = name;
        }
    }
    
    public class FinalClass2 {
        static final double EARTH_RADIUS = 6400;
        static final double EARTH_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS;
    }
    
    public class FinalMain {
        public static void main(String[] args) {
            FinalClass finalClass = new FinalClass("010-1234-5678", "namji");
            System.out.println(finalClass.nation);
            System.out.println(finalClass.phone);
            System.out.println(finalClass.nation);
            System.out.println(finalClass.nation + " : " + finalClass.name + ", " + finalClass.phone);
    
    //        finalClass.nation = "USA" // 컴파일 에러 (final)
    
    		// 출력 : Korean
            // 출력 : 010-1234-5678
            // 출력 : namji
            // 출력 : Korean
            // 출력 : Korean : namji, 010-1234-5678
    
            System.out.println("지구의 반지름 : " + FinalClass2.EARTH_RADIUS + "KM");
            System.out.println("지구의 표면적 : " + FinalClass2.EARTH_AREA + "KM^2");
            
            // 출력 : 지구의 반지름 : 6400.0KM
    		// 출력 : 지구의 표면적 : 5.147185403641517E8KM^2
        }
    }

'JAVA' 카테고리의 다른 글

[JAVA] - 진법 변환 정리  (0) 2024.02.18
[JAVA] - Object (equals, toString) 클래스  (0) 2024.02.14
[JAVA] - 메서드란 (method)  (0) 2024.01.31
[JAVA] - 필드란 (Field)  (0) 2024.01.31
[JAVA] - 추상화 / 캡슐화 / 상속 / 다형성  (0) 2024.01.30