새소식

JAVA

자바 기초 : 인스턴스 멤버와 정적 멤버

  • -

핵심개념

  • 인스턴스 멤버 : 객체마다 가지고 있는 멤버.(객체(인스턴스)를 생성 후 사용할 수 있는 필드와 메소드)
    - 인스턴스 필드 : 힙영역의 객체마다 가지고 있는 멤버, 객체마다 다른 데이터를 저장
    - 인스턴스 메소드 : 객체가 있어야 호출 가능한 메소드. 클래스코드(메소드영역)에 위치. 메소드는 코드 블록이므로 객체마다 동일한 코드 블록을 가지고 있을 필요가 없다.
    ex) public class Car{
          //필드
          int gas;
          //메소드
          void setSpeed(in speed){...}
          }
    -----------------------------------------------------
         Car myCar = new Car();
         myCar.gas = 10;
         myCar.setSpeed(60);
         Car yourCar = new Car();
         yourCar.gas = 20;
         yourCar.setSpeed(80);


  • this : 객체 외부에서 인스턴스 멤버에 접근하기 위해 참조 변수를 사용하는 것처럼 객체 내부에서 인스턴스 멤버에 접근하기 위해 this사용가능. 생성자와 메소드의 매개변수 이름이 필드와 동일할 경우 필드임을 지정하기 위해서 주로 사용된다. 아래의 예시에서 this.model은 자신이 가지고 있는 model 필드라는 의미.
    ex) Car(String model){
             this.model = model;
         }
         void setModel(String model){
             this.model = model;
         } // -> 매개변수model의 값을 필드 model에 저장

public class Car {
   //필드
   String model;
   int speed;

   //생성자
   Car(String model){
   this.model = model;
   }
   //메소드
   void setSpeed(int speed) {
   this.speed = speed;
   }
   void run() {
   for(int i=10; i<50; i+=10) {
   this.setSpeed(i);
   System.out.println(this.model + "가 달립니다.(시속:" + this.speed + "km/h)");
   //여기서 this는 필드임을 강조하기 위함. 생략해도 가능
   }
 }
}

-----------------------------------------------------------------------------------------------------------

public class CarEx {
   public static void main(String[] args) {
   Car myCar = new Car("승용차");
   Car yourCar = new Car("버스");

   myCar.run();
   yourCar.run();
   //run() -> 각각의 객체 안에 있는 정보를 출력
   }
}
실행결과 : 
승용차가 달립니다.(시속:10km/h)
승용차가 달립니다.(시속:20km/h)
승용차가 달립니다.(시속:30km/h)
승용차가 달립니다.(시속:40km/h)
버스가 달립니다.(시속:10km/h)
버스가 달립니다.(시속:20km/h)
버스가 달립니다.(시속:30km/h)
버스가 달립니다.(시속:40km/h)

 

  • 정적 멤버 : 클래스에 고정되어  객체를 생성하지 않고 사용할 수 있는 필드와 메소드. 클래스코드(메소드영역)에 위치.
    - 정적 필드 및 상수 : 객체 없이 클래스만으로도 사용 가능한 필드
    - 정적 메소드 : 객체가 없이 클래스 만으로도 호출 가능한 메소드

  • 정적 멤버 선언 : 정적 필드와 정적 메소드를 선언하려면 선언 시 static을 추가로 작성하면된다.
    ex) public class 클래스{
          //정적 필드
          static 타입 필드[=초기값];
          //정적 메소드
          static 리턴 타입 메소드(매개변수선언, ...) {...}

    필드 선언 시 인스턴스 필드와 정적 필드 선언의 판단 기준은 객체마다 가지고 있어야 할 데이터인지의 여부가 중점이된다.
    객체마다 다를 수 있는 필드 값 -> 인스턴스 필드로 선언
    객체마다 다를 필요가 없는 필드 값 -> 정적 필드로 선언
    메소드 블록에 인스턴스 필드 또는 인스턴스 메소드가 포함되어 있는 경우 -> 인스턴스 메소드로 선언
    메소드 블록에 인스턴스 필드 또는 인스턴스 메소드가 없는 경우 -> 정적 메소드로 선언
    ex)public class Calculator{
            String color;  //계산기별로 색깔이 다를 수 있음. -> 인스턴스 필드로 선언
            static double pi = 3.14159;   //계산기마다 파이의 값은 동일 -> 정적 필드로 선언

  • 정적 멤버 사용 : 클래스가 메모리로 로딩되면 정적 멤버를 바로 사용할 수 있다.정적 멤버는 클래스에 고정되어 있어 클래스 로더가 클래스(바이트코드)를 로딩해서 메소드 메모리 영역에 클래스 별로 저장된다. 따라서 클래스의 로딩이 끝나면 바로 정적 멤버 사용 가능. 정적 멤버를 사용하기 위해서는 클래스 이름과 함께 .으로 접근한다.
    ex) 클래스.필드;
          클래스.메소드(매개값, ...);
public class Calculator {
   //필드
   static double pi = 3.14159; //객체마다 변하지 않음. 정적필드로 선언
   //메소드
   static int plus(int x, int y) {
   return x + y;
   }
   static int minus(int x, int y) {
   return x-y;
   }
}

---------------------------------------------------------------------------------------------------

public class CalculatorEx {
   public static void main(String[] args) {
   //정적 메소드는 객체를 생성하지 않아도 사용 가능
   //클래스이름.필드, 클래스이름.메소드로 접근

   double result1 = 10*10*Calculator.pi;
   int result2 = Calculator.plus(10,5);
   int result3 = Calculator.minus(10,5);

   System.out.println("result1 : " + result1);
   System.out.println("result2 : " + result2);
   System.out.println("result3 : " + result3);
   }
}
실행결과 : 
result1 : 314.159
result2 : 15
result3 : 5

 

  • 정적 메소드 선언 시 주의할 점 : 정적메소드는 객체가 없어도 실행되기 때문에 정적 메소드를 선언할 때에는 인스턴스 필드 및 인스턴스 메소드 사용이 불가능하다. 특히 정적 메소드 선언시에는 그 객체 자신의 참조인 this키워드를 사용할 수 없다.
    만약 정적 메소드에서 인스턴스 멤버를 사용하고 싶다면 객체를 먼저 생성하고 참조변수로 접근해야한다.
    ex) public class ClassName{
          //인스턴스 필드와 메소드
          int field;
          void method1() { }
          //정적 필드와 메소드
          static int field2;
          static void method2() { }
          //정적 메소드
          static void method3() {
          this.field = 10;  //(x) 컴파일 오류. 정적 메소드 내부에서 인스턴스 필드 및 인스턴스 메소드 사용 불가
          this.method1(); //(x)
          //정적 메소드 에서 인스턴스 멤버를 사용하는 법 -> 객체 생성 후 참조변수로 접근
          static void method3() {
          ClassName obj = new ClassName();
          obj.field1 = 10;
          obj,method1();

public class CarEx {
   int speed;

   void run() {
   System.out.println(speed + "으로 달립니다.");
   }

public static void main(String[] args) {
   //speed = 60; //main메소드는 정적 메소드.객체 생성 없이 인스턴스 필드 사용 불가
   //run(); //main메소드는 정적 메소드.객체 생성 없이 인스턴스 메소드 사용 불가

   CarEx myCar = new CarEx();
   myCar.speed = 60;
   myCar.run();
   }
}

 

  • 싱글톤 : 전체 프로그램에서 단 하나의 객체만 만들도록 보장하는 코딩 기법

  • 싱글톤 생성방법
    1. 클래스 외부에서 new연산자를 통해 생성자를 호출할 수 없게 생성자 앞에 private접근 제한자 사용
        (생성자를 호출한 만큼 객체가 생성되기 때문)
    2. 자신의 타입인 정적 필드 선언 후 자신의 객체를 생성해 초기화
        (클래스 내부에서는 new연산자로 클래스 호출이 가능함)
    3. 외부에서 필드값을 변경하지 못하도록 정적 필드에 private 사용
    4. 대신 외부에서 호출할 수 있는 정적 메소드인 getInstance()를 선언하고 자신의 객체를 리턴
        (외부에서 객체를 호출할 수 있는 유일한 방법. getInstancd() 메소드는 단 하나의 객체만 리턴한다. 따라서 변수들은 동일한 객체를 참조.)

    ex)public class ClassName{
         //정적필드에 자신의 객체를 저장
         private static ClassName singleton = new ClassName();
         //생성자
         private ClassName() {} //외부에서 객체 생성 불가
         //메소드
         static ClassName getInstance() {
             return singleton;
         }}
public class Singleton {
   //필드
   private static Singleton singleton = new Singleton(); //정적필드 선언 후 자신의 객체를 생성해 초기화, 정적필드에 private사용

   //생성자
   private Singleton() {} //private접근제한자 사용 -> 외부에서 객체 생성 불가

   //메소드
   static Singleton getInstance() { //외부호출 정적 메소드 getInstance()선언
   return singleton; //자신의 객체 리턴
   }
}

----------------------------------------------------------------------------------------------------------------

public class SingletonEx {
   public static void main(String[] args) {
   //Singleton obj1 = new Singleton() //생성자가 private이므로 외부에서 호출 불가

   Singleton obj1 = Singleton.getInstance();
   Singleton obj2 = Singleton.getInstance();
   if(obj1 ==obj2) {
   System.out.println("같은 Singleton 객체입니다.");
   }else
   System.out.println("다른 Singleton 객체입니다.");
   }
}
실행결과 : 같은 Singleton 객체입니다.

 

  • final 필드 : 초기값이 저장되면 이것이 최종값이 되어 프로그램의 실행 도중 수정할 수 없는 필드.
  • final 필드 초기값 주는 법
    1. 단순 값일 경우 필드 선언 시 초기화(주로 정적 필드(상수)일 경우)
    2. 객체 생성 시 외부데이터로 초기화 해야하는 경우 생성자에서 초기화값 지정(주로 인스턴스 필드일 경우)

  • 인스턴스 final 필드
    ex) 객체에 한 번 초기화된 데이터를 변경 불가로 만들 경우 : 주민번호 등
           final 타입 필드[=초기값];   -> final String ssn; //생성자에서 초기화(객체마다 다를 경우)
public class Person {
   final String nation = "Korea"; //필드 선언 시 초기화
   final String ssn; //객체생성 시 외부데이터로 초기화 -> 생성자로 초기화
   //ssn은 person객체가 생성될 때 값이 주어지므로 person클래스 설계 시 미리 초기값을 줄 수 없다.
   String name;
   Person(String ssn, String name){
   this.ssn = ssn;
   this.name = name;
   }
}

-----------------------------------------------------------------------------------------------------------

public class PersonEx {
   public static void main(String[] args) {
   Person p1 = new Person("123456-1234567", "김자바");
   System.out.println(p1.nation);
   System.out.println(p1.ssn);
   System.out.println(p1.name);

   //p1.nation = "USA"; (x)
   //p1.ssn = "123457-9876543"; (x)
   p1.name = "홍땡땡";
   }
}
실행결과 : 
Korean
123456-1234567
김자바

 

  • 상수 (=정적 final 필드) : 불변의 값을 저장하는 정적 필드. static final 키워드로 선언. 불변의 값의 경우 수학에서 사용되는 원주율 또는 지구의 둘레 등이 있다. 상수 이름은 모두 대문자로 작성하는 것이 관례. 다른 단어가 혼합될 시 _로 연결
    final필드의 경우 객체마다 저장되고, 생성자의 매개값을 통해 여러가지 값을 가질 수 있지만, 불변의 값은 객체마다 저장할 필요가 없으며 여러가지 값으로 초기화될 수 없다. 상수는 static이면서 final이어야하고 static final필드는 객체마다 존재하지 않고 클래스에만 저장된다.
    ex) static final 타입 상수 = 초기값;   ->   static final double EARTH_RADIUS = 6400;
public class Earth {
   static final double EARTH_RADIUS = 6400;
   static final double EARTH_AREA = 4*Math.PI*EARTH_RADIUS*EARTH_RADIUS;
   }

--------------------------------------------------------------------------------------

public class EarthEx {
   public static void main(String[] args) {
   System.out.println("지구의 반지름 : " + Earth.EARTH_RADIUS + "km");
   System.out.println("지구의 표면적 : " + Earth.EARTH_AREA + "km^2");
   //Earth.EARTH_RADIUS = 6500;final이므로 값 변경 불가
   }
}
실행결과 :
지구의 반지름 : 6400.0km
지구의 표면적 : 5.147185403641517E8km^2

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.