sm 기술 블로그

객체지향(클래스,인스턴스,객체 / 클래스맴버와 인스턴스 맴버) 본문

Java

객체지향(클래스,인스턴스,객체 / 클래스맴버와 인스턴스 맴버)

sm_hope 2022. 4. 14. 22:45
  클래스, 인스턴스, 객체

클래스(class) -> 객체를 만들기 위한 설계도 

인스턴스(instance) -> 설계도에 따른 제품

 

public class CalculatorDemo {
 
    public static void main(String[] args) {
        // 아래의 로직이 1000줄 짜리의 복잡한 로직이라고 가정하자.
        System.out.println(10 + 20);
        System.out.println(20 + 40);
    }
 
}

 

코딩은 중복을 제거할 수 있도록 해야한다. [리펙토링 (Refactoring)]

 

->메소드화

public class CalculatorDemo2 {
 
    public static void sum(int left, int right) {
        System.out.println(left + right);
    }
 
    public static void main(String[] args) {
        sum(10, 20);
        sum(20, 40);
    }
 
}

서로 연관되어있는 데이터와 연산을 그룹핑 할 수 있는 작업을 기능적으로 제공하는 것을 객체지향이라고 한다.

 

 

다음과 같은 코드가 있다고 할때,

public class ClaculatorDemo3 {
 
    public static void avg(int left, int right) {
        System.out.println((left + right) / 2);
    }
 
    public static void sum(int left, int right) {
        System.out.println(left + right);
    }
 
    public static void main(String[] args) {
        int left, right;
 
        left = 10;
        right = 20;
 
        sum(left, right);
        avg(left, right);
 
        left = 20;
        right = 40;
 
        sum(left, right);
        avg(left, right);
    }
 
}

 

만약 10 / 20 부분에서 avg만 혹은 sum만을 이용하고 싶을 때 객체지향이 요구된다.

그래서 다음과 같이 만들 수 있다.

 

//  분석할때 어떻게 사용되는지 로직을 읽어간다 (위에서 아래로 내려가는 하향식 방식 말고)

class Calculator{
	// class 는 지금부터 Calculator라는 객체의 설계도를 알려주겠다 라는 약속된 키워드
    
    int left, right;
      
    public void setOprands(int left, int right){
        this.left = left;
        // this. : c1에 담겨있는 Calculator라고 하는 클래스를 구체적인 제품으로 만든 인스턴스이다.
        // this. 은 int left 혹은 right를 가르킨다. 
        // 즉,   this.left = left
        //       class 내에 있는 int left = main에서 c1.setOparands(int left)로 받은 left 매개변수
        //       객체전역에서 존재할 수 있는 left = 10   
        // this.은 c언어 포인터 같은 느낌이다.
        
        this.right = right;
    }
      
    public void sum(){
        System.out.println(this.left+this.right);
    }
      
    public void avg(){
        System.out.println((this.left+this.right)/2);
    }
}
  
public class CalculatorDemo4 {
      
    public static void main(String[] args) {
          
        Calculator c1 = new Calculator(); 
        // Calculator()라는 변수를 [new] 새로 만들어서 c1에 담았는데 그 변수는
        // Calculator 라고하는 객체를 담을 수 있는 데이텨 형식을 가진 변수이다.
        // 우항이 실행되고 좌항에 대입
       
        c1.setOprands(10, 20);
        // c1 객체에 setOparands라는 메소드 실행
        
        c1.sum(); 
        // c1 객체에 sum라는 메소드 실행
        
        c1.avg();  
        // c1 객체에 avg라는 메소드 실행
          
        Calculator c2 = new Calculator();
        c2.setOprands(20, 40);
        c2.sum();       
        c2.avg();
    }
  
}

인스턴스 : 구체적인 객체 (c1,c2)

 

https://www.youtube.com/watch?v=cls3W2k7v7U&list=PLuHgQVnccGMCeAy-2-llhw3nWoQKUvQck&index=74 

 

첫부분에서 인스턴스, 객체, 클래스 개념을 설명해줌.

 

좋은 말...

 

클래스는 국수틀이고 객체 c1,c2는 인스턴스를 결정짓는 재료(left,right는 데이터,변수,상태)

객체 c1이 쌀이라면 calculator c1 = new calculator(); 이라는 인스턴스는 쌀국수다 .

객체 c2가 메밀이라면 calculator c2 = new calculator(); 인스턴스는 메밀국수다.

국수틀에 어떤 재료를 넣고 돌리느냐에 따라 다른 국수가 나온다. 클래스에 어떤 객체를 넣고 돌리느냐에 따라 다른 인스턴스가 나온다.

쌀국수와 메밀국수는 서로 다름. 특성을 결정짓는 요인들(L10 R20, L20 R40)이 다르듯이

 


맴버

 

클래스 맴버와 인스턴스 맴버

 

클래스와 인스턴스의 차이점

-> 인스턴스가 가지는 값은 전부 다름, 클래스가 가지는 값은 인스턴스를 통해 모두 같음.

    즉, 클래스가 가지는 값은 인스턴스에서 선언하지 않아도 가질 수 있음.

 

 

클래스 변수

class Calculator {
    static double PI = 3.14;
    // 각각의 객체에 PI 값을 선언해 준다면 매우 비효율적이다.
    // 클래스변수로 선언하여 클래스내에 모든 인스턴스가 동일한 값을 가질 수 있도록 함.
    
    int left, right;
 
    public void setOprands(int left, int right) {
        this.left = left;
        this.right = right;
    }
 
    public void sum() {
        System.out.println(this.left + this.right);
    }
 
    public void avg() {
        System.out.println((this.left + this.right) / 2);
    }
}
 
public class CalculatorDemo1 {
 
    public static void main(String[] args) {
 
        Calculator c1 = new Calculator();
        System.out.println(c1.PI);
        // c1 인스턴스가 3.14를 출력
 
        Calculator c2 = new Calculator();
        System.out.println(c2.PI);
        // c2 인스턴스가 3.14를 출력
 
        System.out.println(Calculator.PI);
        // Calculator 클래스가 3.14를 출력
    }
 
}

static을 알아보자.

 

class Calculator2 {
    static double PI = 3.14;
    // 클래스 변수인 base가 추가되었다.
    static int base = 0;
	// static 이 붙어있어 클래스의 맴버로 모든 인스턴스에서 동일하게 사용가능하다.

    int left, right;
    // 인스턴스의 맴버로 매번 변경될 수 있다.
 
    public void setOprands(int left, int right) {
        this.left = left;
        this.right = right;
    }
 
    public void sum() {
        // 더하기에 base의 값을 포함시킨다.
        System.out.println(this.left + this.right + base);
    }
 
    public void avg() {
        // 평균치에 base의 값을 포함시킨다.
        System.out.println((this.left + this.right + base) / 2);
    }
}
 
public class CalculatorDemo2 {
 
    public static void main(String[] args) {
 
        Calculator2 c1 = new Calculator2();
        c1.setOprands(10, 20);
        // 30 출력
        c1.sum();
 
        Calculator2 c2 = new Calculator2();
        c2.setOprands(20, 40);
        // 60 출력
        c2.sum();
 
        // 클래스 변수 base의 값을 10으로 지정했다.
        Calculator2.base = 10;
 
        // 40 출력
        c1.sum();
 
        // 70 출력
        c2.sum();
 
    }
 
}

 

클래스 변수의 용도 

1) 인스턴스에 따라서 변하지 않는 값이 필요한 경우 (위의 예제에서 PI 사용) -> 이 경우는 final 사용이 좋음 (후에 학습)

2) 인스턴스가 생성할 필요가 없는 값을 클래스에 저장하고 싶은 경우

3) 값의 변경 사항을 모든 인스턴스가 공유해야 하는경우

 

클래스 메소드

class Calculator3{
  
    public static void sum(int left, int right){
        System.out.println(left+right);
    } 
    
    //static을 통해 sum 메소드는 클래스의 맴버가 된다.
    //static이 붙지 않은 변수와 다르게 클래스에 직접 접근가능하다.
     
    public static void avg(int left, int right){
        System.out.println((left+right)/2);
    }
}
 
public class CalculatorDemo3 {
     
    public static void main(String[] args) {
        Calculator3.sum(10, 20); //30 출력
        Calculator3.avg(10, 20); //15 출력
        
    // 각각의 메소드가 클래스만 이용하여 사용하는 경우 굳이 메모리를 사용하면서 인스턴스를 만들 필요가 없다.   
         
        Calculator3.sum(20, 40);
        Calculator3.avg(20, 40);
    }
 
}

이 경우는 인스턴스가 존재하지 않는다.

 

1) 인스턴스 메소드는 클래스 맴버에 접근 할 수 있다.

2) 클래스 메소드는 인스턴스 맴버에 접근 할 수 없다.

class C1{
    static int static_variable = 1;  //static으로 인해 클래스 변수
    int instance_variable = 2;   // 인스턴스 변수
    
    static void static_static(){
        System.out.println(static_variable);
    }
    static void static_instance(){
        // 클래스 메소드에서는 인스턴스 변수에 접근 할 수 없다. 
        //System.out.println(instance_variable);
    }
    void instance_static(){
        // 인스턴스 메소드에서는 클래스 변수에 접근 할 수 있다.
        System.out.println(static_variable);
    }
    void instance_instance(){        
        System.out.println(instance_variable);
    }
}
public class ClassMemberDemo {  
    public static void main(String[] args) {
        C1 c = new C1();
        // 인스턴스를 이용해서 정적 메소드에 접근 -> 성공
        // 인스턴스 메소드가 정적 변수에 접근 -> 성공
        c.static_static();
       
        // 인스턴스를 이용해서 정적 메소드에 접근 -> 성공
        // 정적 메소드가 인스턴스 변수에 접근 -> 실패
        c.static_instance();
        
        // 인스턴스를 이용해서 인스턴스 메소드에 접근 -> 성공
        // 인스턴스 메소드가 클래스 변수에 접근 -> 성공
        c.instance_static();
        
        // 인스턴스를 이용해서 인스턴스 메소드에 접근 -> 성공 
        // 인스턴스 메소드가 인스턴스 변수에 접근 -> 성공
        c.instance_instance();
        
        // 클래스를 이용해서 클래스 메소드에 접근 -> 성공
        // 클래스 메소드가 클래스 변수에 접근 -> 성공
        C1.static_static();
        
        // 클래스를 이용해서 클래스 메소드에 접근 -> 성공
        // 클래스 메소드가 인스턴스 변수에 접근 -> 실패
        C1.static_instance();
        
        // 클래스를 이용해서 인스턴스 메소드에 접근 -> 실패
        //C1.instance_static();
        
        // 클래스를 이용해서 인스턴스 메소드에 접근 -> 실패
        //C1.instance_instance();
    }
 
}

인스턴스 매개변수는 변한다. 어떤 인스턴스의 매개변수를 사용해야하냐? 당연히 클래스 입장에서는 모른다.

클래스 매개변수는 인스턴스에서 모두 사용가능하다. 따라서 접근이 가능한 것이다.

 

인스턴스 변수 -> Non-Static Field

클래스 변수 -> Static Field

Comments