본문 바로가기
Back-End/Java

[Java] 스코프와 this

by 찐코딩 2021. 8. 27.

https://jinnnkcoding.tistory.com/32

 

[Java] 접근지정자(접근제어자) 권한

접근지정자(접근제어자)권한 - 접근지정자는 클래스, 멤버변수, 멤버메서드 앞에 사용됨. - 외부로부터 접근을 제어한다는 의미를 가지고 있음. - 접근 지정자가 사용될 수 있는 곳 : 클래스, 멤

jinnnkcoding.tistory.com

 

스코프(Scope)

스코프(scope)란, 변수의 활동 영역

이러한 스코프는 크게 두 종류로, 클래스 스코프와 메소드 스코프로 나누어짐

클래스 스코프 : 클래스 전역에서 활동(예: 필드)
메소드 스코프 : 메소드 내부에서 활동(예: 파라미터, 지역변수)

 

클래스 스코프(Class Scope)

필드(변수)의 활동 영역은 클래스 전체 (클래스 전역)

따라서 메소드 호출 시 필드를 사용할 수 있음

 

클래스 스코프 예시

class Cat {
	
	// 필드(상태) 영역
	String name;
	
	// 메소드(동작) 영역
	// 필드값인 name의 활동영역은 클래스 전체, 즉 클래스 스코프를 갖는다.
	void meow() {
		System.out.printf("%s의 야옹\n", name);
	}
	
	void claw() {
		System.out.printf("%s의 할퀴기 공격\n", name);
	}
}

public class CatTest {

	public static void main(String[] args) {
		
		// 두 고양이 객체 생성
		Cat cat1 = new Cat();
		Cat cat2 = new Cat();
		
		// 객체 필드 초기화
		cat1.name = "네로";
		cat2.name = "나비";
		
		// 두 고양이의 야옹
		cat1.meow();
		cat2.meow();
		
		// 두 고양이의 할퀴기
		cat1.claw();
		cat2.claw();

	}

}

결과

네로의 야옹
나비의 야옹
네로의 할퀴기 공격
나비의 할퀴기 공격

 

메소드 스코프(Method Scope)

파라미터와 지역변수의 경우, 메소드 스코프를 가짐

이들의 활동 영역은 해당 메소드 내부로 제한됨

(※ 지역변수 : 메소드 내부에서 선언된 변수)

 

class DrinkMachine {
	String output;
    
    void pushButton(int num) { // int num은 파라미터
    String[] drinks = {"콜라", "사이다", "환타"};	// drinks은 지역변수
    output = drinks[num];	// output은 필드
    }
    
    void printOutput() {
    	System.out.println(output);
    }
  }

num은 pushButton 메소드의 파라미터이고, 

drinks는 pushButton 메소드 내부에서 선언되었으므로 지역변수이다

이들은 해당 메소드를 벗어나서 호출하면 에러가 생긴다.

이렇게 빨간 밑줄이 생김

 


메소드 스코프 예시02) 변수의 이름이 같은 경우

class Whatever {
	public void cool(int score) {
    	String result = "";
    }
    
	public void great(int score) {		// cool 메소드의 파라미터 이름과 동일
    	String result = "";		// cool 메소드의 지역변수 이름과 동일
    }

두 메소드의 파라미터 이름과 지역변수 이름이 동일해도(=변수 이름이 동일해도)

에러는 생기지 않는다!

각기 다른 변수로 인식하고 컴파일하는 데에는 아무런 문제가 없다. 

package Exam;

public class MethodScope {

	public static void main(String[] args) {
		
		int score = 88; 
		// main메소드의 score를 출력
		System.out.printf("score = %d in main()\n", score);	
		
		// Record 클래스의 메소드 호출, 수행
		Record.minusTen(score);
		
		// main 메소드의 지역변수 score를 출력
		System.out.printf("score = %d in main()\n", score);
	}
}
	
	class Record {
		static void minusTen(int score) {
			
			// minusTen 메소드의 파라미터 score의 값을 10 감소
			score-=10;
			
			// minusTen 메소드의 파라미터 score의 값을 출력
			System.out.printf("score : %d in minusTen()\n", score);
			
		}
	}

결과

score = 88 in main()
score : 78 in minusTen()
score = 88 in main()

메인 메소드에서 minusTen 메소드를 호출하고 난 후인데도 그 다음 출력문에는 본래값인 88이 출력되었다.

즉, 메인메소드의 지역변수 값과, minusTen메소드의 파라미터 값을 구별하고 있음을 알 수 있다.


스코프와 this

위에서 지역변수와 파라미터 이름이 같은 경우는 문제가 생기지 않는다는 걸 확인했다.

다만, 클래스의 필드와 메소드의 파라미터 이름이 같은 경우 문제가 생길 수 있다.

 

public class exCookie {

	public static void main(String[] args) {
		
		Cookie cookie = new Cookie("버터링", 1500);
	}
}

class Cookie {
	// 필드 영역
	private String name;
	private int price;
	
	// 메소드 영역
	public Cookie(String name, int price) {
		name = name;	// 인스턴스 변수 name 초기화 되지 않음
		price = price; 	// 인스턴스 변수 price 초기화 되지 않음
		
		System.out.printf("%s, %d원", name, price);
	}
}

이클립스에서 위 코드를 적어보면

이렇게 노란색 밑줄(=경고)가 뜨면서 커서를 대면

이렇게 변수를 쓰는 건 효과가 없다. 고 친절히 알려준다

뭐 결과는..

버터링, 1500원

잘 떴지만 말이다.

아무튼 비추천

 

 

this()

파라미터와 필드의 이름이 같은 경우 위와 같은 문제를 해결할 때, this 키워드를 사용하면 된다.

this 키워드는 메소드 수행의 주체 객체를 가리킨다.

 

package Exam;

public class exCookie {

	public static void main(String[] args) {
		
		Cookie cookie = new Cookie("버터링", 1500);
	}
}

class Cookie {
	// 필드 영역
	private String name;
	private int price;
	
	// 생성자 메소드
	public Cookie(String name, int price) {
		this.name = name;		// this.name => 인스턴스 변수
		this.price = price; 	// this.price => 인스턴스 변수
		// 파라미터 네임을 this로 던짐
	}
	

	
}

주체객체의 파라미터값을 this로 던짐

=> 버터링 -> this.name으로 던짐

=> 1500 -> this.price로 던짐

 

버터링, 1500원

 

this 예제문제 02

커피 객체를 생성하고 그 가격을 인상하려 한다.

this를 활용하여 문제를 풀어보자

package Exam;

public class CoffeePrice {

	public static void main(String[] args) {
		
        // 커피 객체 생성
		Coffee americano = new Coffee("아메리카노",1500);
		System.out.printf("커피값 인상 전 => %s\n", americano.toString());
		
        // 커피값 인상
        // setter로 값을 우회하여 변경
		americano.setPrice(2000);
		System.out.printf("커피값 인상 후 => %s\n", americano.toString());

	}
}


class Coffee {
	
	private String name;
	private int price;

	// 생성자
	public Coffee(String name, int price) {
		this.name=name;
		this.price=price;
	}

	// Setter 생성 (=>값을 우회하여 변경)
	public void setPrice(int price) {
		this.price = price;	// 파라미터 값을 대입하겠다.
	}
	
	
	public String toString() {
		return String.format("Coffee [name : %s, price :%,d]", 
        						this.name, this.price);
	}
	
}

결과

커피값 인상 전 => Coffee [name : 아메리카노, price :1,500]
커피값 인상 후 => Coffee [name : 아메리카노, price :2,000]

 

 

 

댓글