본문 바로가기
개발/JAVA

[JAVA개념]객체지향언어-2

by Develaniper 2021. 5. 10.

객체지향의 개념이 생각보다 너무 많아서 3~4개로 나워야 할 것 같네요..ㅠ

 

1.변수의 종류(클래스, 인스턴스, 지역)

 변수는 클래스 변수, 인스턴스 변수, 지역변수가 있다. 클래스 클래의 멤버변수 중 static이 붙은 변수, 인스턴스변수는 붙지 않은 변수, 메서드 내부에 선언된 변수는 지역변수이다.

public class Val {
    static int classVal;		// 클래스 변수
    int instanceVal;			// 인스탄스 변수

    void method(){
        int localVal;			// 지역변수
    }
    
}

  각 변수들 마다 생성될 시기의 차이가 있는데 차이는 다음 표와 같다.

변수 종류 생성
클래스변수 클래스가 메모리에 올라갈때
인스턴스 변수 인스턴스가 생성되었을 때
지역 변수 변수 선언문이 수행 될때(메서드가 실행되고 난 후)

쉽게 생각하면 각각 이름에 있는 것이 생성될때 같이 생성된다고 생각하면 된다.

 

클래스 변수는 클래스가 메모리에 올라갈때(생성될때)

인스턴스 변수는 인스턴스가 생성될때(객체를 만들 때)

지역 변수는 그 지역에서 변수를 선언할때

 

 생성 시간에 따른 특징들은 다음과 같습니다.

 

- 클래스 변수

 해당 클래스로 만들어진 인스턴스들은 모두 이 변수를 공유하며 객체가 만들어지지 않아도 클래스이름.클래스변수 형식으로 사용할 수 있다.(접근제한자는 나중에..)

- 인스턴스 변수

 객체가 생성되야만 사용할 수 있다.

- 지역 변수

  해당 지역 안에서만 사용가능하다.

 

다음은 클래스변수와 인스턴스 변수의 특징을 나타낸 코드입니다.

public class ValTest {
    public static void main(String[] args) {
        Val.classVal = 10;
        System.out.println("Val.classVal :  "+Val.classVal);
        //System.out.println("Val.instanceVal :  "+Val.instanceVal);
        //Cannot make a static reference to the non-static field 오류

        Val v1 = new Val();
        Val v2 = new Val();
        
        v1.instanceVal = 10;
        v2.instanceVal = 20;
        
        System.out.println("v1.clasVal : "+v1.classVal+", v1.instanceVal : "+v1.instanceVal);
        System.out.println("v2.clasVal : "+v2.classVal+", v2.instanceVal : "+v2.instanceVal);


        System.out.println("some works...");

        v1.instanceVal++;
        v2.instanceVal++;

        v1.classVal = 30;

        System.out.println("v1.clasVal : "+v1.classVal+", v1.instanceVal : "+v1.instanceVal);
        System.out.println("v2.clasVal : "+v2.classVal+", v2.instanceVal : "+v2.instanceVal);
    }
}

 

클래스 변수를 변화 시키면 모든 클래스 변수들의 값은 같게 나오는 것을 볼 수 있습니다.

즉, 같은 클래스를 사용하는 객체들은 같은 클래스 값을 공유한다는 것을 알 수 있습니다.

인스턴스 변수는 객체마다 고유의 인스턴스 값을 갖고 있습니다.

 

-사용법

그럼 클래스 변수와 인스턴스 변수의 차이점을 알아야겠죠?

 

클래스변수는 객체들이 공통으로 갖는 특징을 생각하면됩니다.

인스턴스변수는 반대로 특징적인 값들을 말할 수 있죠.

트럼프 카드를 예로 들어봅시다.

클래스 변수 인스턴스 변수
카드의 높이 카드의 무늬 (♠♥♣◆)
카드의 넓이 숫자(A,2,3~10, J,Q,K)

위와 같이 공통으로 가지고 있어야 하는 것들은 클래스변수로, 각자 특징을 나타낼 수 있어야 하는 것들은 인스턴스 변수로 나타낼 수 있습니다.

public class Card {
    static int height=100;
    static int width= 75;
    String pattern;
    char number;
}

 

추가로 변수를 부여하고 싶다면 클래스변수로는 재질, 두께, 폰트 등을 사용할 수 있겠고, 인스턴스 변수에는 색, 내구도 등을 지정할 수 있을 것 같네요.

 

2. JVM의 메모리 구조

JVM은 프로그램 수행시 필요한 메모리를 할당받아 용도별 영역을 나누어 관리한다.

그 중 주요영역은 메서드, 호출스택, 힙영역이 있다.

 

- 메서드영역(Method)

어떤 클래스가 사용되면, JVM은 해당 클래스의 *.class를  읽어서 분석하여 해당 클래스에 대한 정보를 메서드 영역에 저장한다. 이때 위에 언급한 클래스 변수도 함께 저장된다.

- 힙 영역(Heap)

인스턴스가 생성되는 공간으로 프로그램 실행 중 생성되는 모든 인스턴스들이 생성되는 공간이다.

- 호출스택(Call Stack)

호출스택은 메서드 작업에 필요한 메모리 공간을 제공한다. 이 공간은 메서드가 수행되는 동안 지역변수들과 중간 결과등을 저장하는데 사용되고 메서드 사용이 끝난경우에는 반환되며 공간이 비워진다.

 호출스택에는 스택과 마찬가지로 처음 실행되는 메서드는 가장 아래에 공간에서 작업을 진행하게 되고 그 후로는 하나씩 위로 쌓이게 된다. 메서드가 끝난 경우에는 반환하며 공간을 비우고 그 아래있는 메서드에서 자신을 실행한 부분으로 돌아가 다시 작업을 수행하게 된다.

 

메서드 호출스택
클래스 정보 인스턴스 생성 메서드 실행
클래스 변수 인스턴스 변수 지역변수

 

 

3. 클래스메서드와 인스턴스메서드

클래스메서드는 클래스 변수와 마찬가지로 static을 붙인 메서드 이다. 또한, 객체 선언 없이도 사용가능한 메서드 이다.

 

클래스메서드와 인스턴스 메서드의 차이점은 무엇일까?

 

메서드는 멤버변수와 관련이 크다. 따라서 인스턴스 변수를 사용하는 메서드는 좋든 실든 인스턴스 메서드가 되어야 사용할 수 있을 것이다. 클래스 메서드는 이와 반대로 인스턴스 변수를 사용하지 않는 메서드를 일반적으로 클래스 메서드로 작성한다.

 

※주의점

1. 클래스 설계시 모든 인스턴스에 공통으로 사용되는 것은  static을 붙인다.

2. 클래스변수, 클래스 메서드는 인스턴스를 생성하지 않아도 사용할 수 있다.

 - static키워드를 가진 변수,메서드의 특징이다.

3. 클래스 메서드는 인스턴스 변수를 사용할 수 없다.

 -생성시점을 생각하면 당연한 것이다.

4. 메서드 내에서 인스턴스변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.

 - 인스턴스 변수를 사용하지 않으면 static을 사용할 수 있다. static을 붙이면 호출시간이 짧아지기 때문에 효율이 높아진다.

 

public class MyMathTest {
    public static void main(String[] args) {
        System.out.println("객체 생성 전");
        System.out.println("static MyMath.add(5,4) :"+MyMath.add(5,4));
        System.out.println("static MyMath.sub(5,4) :"+MyMath.sub(5,4));
        System.out.println("static MyMath.mul(5,4) :"+MyMath.mul(5,4));
        System.out.println("static MyMath.div(5,4) :"+MyMath.div(5,4));
        System.out.println();
        // System.out.println("MyMath.add() :"+MyMath.add());
        // System.out.println("MyMath.sub() :"+MyMath.sub());
        // System.out.println("MyMath.mul() :"+MyMath.mul());
        // System.out.println("MyMath.div() :"+MyMath.div());
        // Cannot make a static reference to the non-static method mul() from the type
        // 에러 발생

        MyMath cm = new MyMath();
        cm.a=10; cm.b=3;
        System.out.println("객체 생성");
        System.out.println("cm.add() :"+cm.add());
        System.out.println("cm.sub() :"+cm.sub());
        System.out.println("cm.mul() :"+cm.mul());
        System.out.println("cm.div() :"+cm.div());
    }
}
class MyMath{
    long a,b;
    long add(){return a+b;}
    long sub(){return a-b;}
    long mul(){return a*b;}
    long div(){return b!=0?a/b:0;}

    
    static long add(long a, long b){return a+b;}
    static long sub(long a, long b){return a-b;}
    static long mul(long a, long b){return a*b;}
    static long div(long a, long b){return b!=0?a/b:0;}
}

위를 통해 static메서드(클래스메서드)의 사용법을 알 수 있다.

 

이와 유사하게 static메서드에서는 instance메서드를 사용할 수 없다. instance메서드 또한 인스턴스가 생성된 후에 사용할 수 있기 때문이다.

class Instance{
    void instanceMethod(){
        staticMethod(); // 사용가능
        instanceMethod(); // 사용가능
    }
    static void staticMethod(){
        // instanceMethod();
        // Cannot make a static reference to the non-static method instanceMethod() 
    }
}

 

또한, 인스턴스 메서드를 단 한번 사용하고 객체가 필요 없는 경우에는 아래와 같은 과정을 통해 코드를 줄일 수 있다.

Method1 m = new Method1();
int res = m.instanceMethod();

////////////////

int res = new Method1().instanceMethod();

 

댓글