• 외부에 있는 정보(원시형타입, 참조형타입)를 재사용하고 싶다면? (자유자재로 사용할 수 있도록 연습)
  • 데이터는 가로방향과 세로방향이 존재
    1) 가로방향은 서로 관계가 있다
    - 그 사람의 나이, 키, 혈액형 등 다양한 정보
    → 참조형 타입으로 설계를 해야 한다
    2) 세로 방향은 2500만 가입자의 이름
    - 배열로 처리하면 됨(배열은 같은 타입만 담을 수 있다)
    - 클래스와 배열은 모두 new를 사용해서 생성한다.
<예제1-1>
package com.step4;

class A { 
	int age = 0; // 전역변수
}
class A1 { 
	A a = new A();
	void methodA() {
		a.age = a.age + 1; // 1로 변한다. 
        // 그런데 이때 변경된 값은 A1 안에서만 유지된다
	}
}
public class Amain {

	public static void main(String[] args) {
		 A a = new A();
		 A1 a1 = new A1();
		 a1.methodA();
		 System.out.println(a.age); 
	}
}
출력: 0
  • A 클래스에는 변수만 있고, A1 클래스에는 메소드만 가질 수 있게 나누었다
  • 왜 1이 아닌 0이 출력되었을까? 1을 출력하려면 어떻게 해야할까?
<예제1-2>
package com.step4;

class B { 
	int age = 0; 
}
class B1 { 
	B a = new B();
	void methodA(B a) {
		a.age = a.age + 1; 
	}
}
public class Bmain {

	public static void main(String[] args) {
		 B a = new B();
		 B1 a1 = new B1();
		 a1.methodA(a);
		 System.out.println(a.age); 
	}
}
출력: 1
  • 메소드의 파라미터를 통해서 복사본 대신 원본을 넘겨서 그 원본이 가리키는 전변의 값을 출력한다
<예제2>
package com.step4;

class C {
	// 총점을 담는 변수 선언
	int tot;
	// 평균을 담는 변수 선언
	int avg;
}
class C1 {
	C c = new C();
	// 총점을 구하는 메소드 선언
	// 파라미터 자리는 초기화가 안되어 있다. 그럼 언제 되지?
    // → 메소드가 호출될 때(call by value)
	void hap(int n1, int n2, int n3) {
		c.tot = n1+n2+n3;
	}
	// 평균을 구하는 메소드 선언
	void average() {
	}
}

public class Cmain {

	public static void main(String[] args) {
		int n1 = 70;
		int n2 = 80;
		int n3 = 90;
		C c = new C(); 
        // 이 코드가 추가되는 순간 같은 c.tot라도 값이 달라질 수 있다.
		C1 c1 = new C1();
		c1.hap(n1, n2, n3);
	
		System.out.println(c.tot);
	}
}
출력: 0
  • c1.hap(n1, n2, n3); 메소드를 경유한 것을 보아 0 출력을 원하지 않았다. 계산 된 총점을 찍고 싶다면 어떻게 해야할까?
    (우리가 알고 있는 사실: hap을 구하는 메소드에 리턴타입이 정해지지 않았다. void이기 때문)
<예제2-1.클래스 구조 변경>
package com.step4;
// 사이드이펙트-부수효과 있는 코드는 좀 더 면밀히 살펴야 한다
class D {
	// 하나로 합치니까 C에 대한 인스턴스화가 필요없게 되었다.
	// 이러한 이유로 (static이 아닌데) 원본 하나로 관리되고 있다는 걸 봐야한다
	// 그래서 0이 출력되는 게 아니고 240이 출력된다
	int tot;
	int avg;
	void hap(int n1, int n2, int n3) {
		// Cmain에서는 클래스를 3개로 나눴는데 Dmain에서는 2개로 통합했다
		// c.tot -> c가 필요없는 건 전역변수가 내 안에 있기 때문이다
		// 이것만으로 복사본이 아니라 원본을 유지(웹:쿠키와 세션)할 수 있다
		tot = n1+n2+n3;
}
	void average() {
		
	}
}
public class Dmain {

	public static void main(String[] args) {
		int n1 = 70;
		int n2 = 80;
		int n3 = 90;
		D c = new D(); 
		c.hap(n1, n2, n3); // 합을 구하는 메소드 경유
		System.out.println(c.tot); // 240이 출력
	}
}
<예제2-2.메소드의 리턴타입 이용>
package com.step4;
class C {
	int tot;
	int avg;
}
class C1 {
	C c = new C();

	int hap(int n1, int n2, int n3) {
		c.tot = n1+n2+n3;
		return c.tot;
	}
	void average() {
	}
}

public class Cmain {

	public static void main(String[] args) {
		int n1 = 70;
		int n2 = 80;
		int n3 = 90;
		C1 c1 = new C1();
		int tot = c1.hap(n1, n2, n3);  // tot 지역변수로 선언.
		System.out.println(tot);
	}
}
  • 리턴타입을 void에서 int로 가져간 순간 Cmain에서 C에대한 인스턴스화가 필요 없게 되었다.
    리턴타입이 void여서 메소드의 처리결과를 유지할 방법이 없었다.그런데 지금은 return타입이 생겼다. 그래서 메소드 호출을 통해 반환받을 수 있게 되었다.
    단 인스턴스화가 달라지면 그 값은 당연히 변할 것이고,
    tot를 전역변수로 사용할 이유가 없어졌다.
<예제2-3.참조에 의한 호출로 처리>
package com.step4;
class C{
	int tot;
	int avg;
}
class C1{
	C c = new C();
	// 또 다른 방법이 있을까?? -> 전역변수를 살려서 처리할 수 없을까??
	// 메인에 호출된 C c = new C(); 가 그대로 들어와서 복사본이 아닌 원본으로 유지된다.
	int hap(int n1, int n2, int n3, C c) { // Call by reference(참조에 의한 호출 : C c= null)가 되어서.
		c.tot = n1+n2+n3;
		return c.tot;
	}
	// 평균을 구하는 메소드 선언
	void average() {
		
	}
}

public class Cmain {

	public static void main(String[] args) {
		int n1 = 70;
		int n2 = 80;
		int n3 = 90;
		C c = new C();
		C1 c1 = new C1();
		// 파라미터 자리를 사용하라 라는 말은 C1클래스의 	C c = new C(); 인스턴스화를 사용하지 않고. 라는 말
		// hap 메소드 안에서도 C클래스에 대한 인스턴스화가 필요하였고, main메소드 안에서도
		// 전역변수 tot를 출력하기 위해서 필요하였다.
		// 그런데 메소드 호출이 먼저 이니까 C에대한 인스턴스화를 진행함.
		// 그 주소번지를 hap 메소드의 파라미터로 넘기면. 원본을 넘기는 것 이니까 c.tot가 유지된다.
		c1.hap(n1, n2, n3, c);  
		System.out.println(c.tot);
	}
}
    1. 전역변수를 활용해서 처리하는 방법.
  • : 클래스의 구조를 변경한다 (클래스의 숫자를 3개에서 2개로 줄였다.)
  • : 메소드 호출 시, 파라미터 자리에 참조에 의한 호출로 처리 하였다.
    1. 지역변수 활용해서 처리하는 방법.
  • : 메소드의 리턴타입을 이용하였다.

0개의 댓글