Study/JAVA

[JAVA] 7장 - 클래스 내부 구성 요소(1)

오구민 2022. 9. 30. 18:05

confluence를 사용했던 것처럼 정리해보려고 노력 중이다...

이번 장은 코드가 많아서 나눠 게시글을 올리려고 한다.

책은 [Do it! JAVA 완전 정복]을 읽고 있다. 개념 정리도 잘 돼있고, 코드도 이해하기 쉬우며

무엇보다 책 자체의 가독성이 좋다!!

진작 살 걸 그랬다...

 

 

1. 필드

1.1 필드와 지역 변수의 구분

  1.1.1 개념

  • 필드 : 클래스에 포함된 변수로, 객체의 속성값을 지정할 수 있음
  • 지역 변수 : 메서드에 포함된 변수

 

  1.1.2 구분 방법

  • 클래스의 중괄호 안에 선언된 변수는 필드, 메서드의 중괄호 안에 선언된 변수는 지역 변수
  • 필드는 힙 메모리의 객체 내부에 생성되며, 지역 변수는 스택 메모리에 생성된다.

 

  1.1.3 정리

  • 즉, 힙 메모리의 객체 안에 저장되는 '필드'는 객체가 사라지지 않는 한 절대로 삭제되지 않는다.
  • 하지만 스택 메모리의 변수인 '지역 변수'는 선언된 메서드 중괄호가 닫히면서 메서드가 종료되면 삭제된다.
💡 이때 1개의 메서드 안에 선언된 모든 지역 변수들의 집합을 '프레임'이라고 한다.
💡 스택 메모리는 Last In First Out(LIFO) 구조를 띤다.

 

  1.1.4 이때까지 실습

package study_class;


class A {
	//필드 변수 2개 생성
	int m = 3;
	int n = 4;
	
	void work1() {
		//지역 변수 생성
		int k = 5;
		
		System.out.println(k);
		
		//work2() 안에 정의된 지역 변수를 스택 메모리에 추가
		work2(3);
	}
	void work2(int i) {
		//지역 변수 생성
		int j = 4;
		System.out.println(i+j);
	}
}

public class Class_study {
	public static void main(String[] args) {
		//객체 생성
		A a = new A();
		
		//필드값 출력
		System.out.println(a.m);
		System.out.println(a.n);
		
		//메서드 호출, work1() 안에 정의된 지역 변수를 스택 메모리에 추가
		a.work1();
	}
}

 

  1.1.5 필드와 지역변수의 또다른 차이점

  • 또다른 차이점이 있다면 바로 초깃값이다.
  • 필드는 직접 초기화하지 않아도 강제로 초기화되지만, 지역 변수는 직접 초기화 하지 않으면 빈 공간이 그대로 있어 값을 출력하고자 할 때 오류가 발생한다.
  • 즉, 힙 영역에 저장되는 필드는 초깃값이 없으면 강제 초기화되며, 스택 영역의 지역 변수는 강제로 초기화되지 않는다.
package study_class;


class A {
	boolean m1;
	int m2;
	double m3;
	String m4;
	void printFieldValue() {
		System.out.println(m1);
		System.out.println(m2);
		System.out.println(m3);
		System.out.println(m4);
	}
	void printLocalVariable() {
		int k;
		// System.out.println(k);
		// 지역 변수를 초기화하지 않아 에러 발생함
	}
}

public class Class_study {
	public static void main(String[] args) {
		A a = new A();
		a.printFieldValue();
	}
}

 

 

2. 메서드

2.1 메서드 정의하기

메서드는 클래스의 기능에 해당하는 요소다.

메서드 정의의 문법적 구조는 아래와 같다.

자바 제어자 리턴(반환) 타입 메서드명(입력매개변수) {
     메서드 내용
}
public static int sum(int a, int b) {
     //메서드 내용
}

위의 예문은 입력값으로 int형 2개의 값을 입력받아 처리하며, 메서드가 종료된 이후에 int 값을 return 한다는 뜻이다.

C언어를 배웠다면 많이 마주친 return일 것이다...

  • 리턴 타입 : 메서드 종료 이후 변환/반환되는 값의 자료형
  • 입력매개변수 : 메서드를 호출할 때 전달되는 값의 자료형과 전달받은 값을 저장할 지역 변수명을 정의
  • 중괄호 안 메서드 내용 : 메서드가 수행해야 할 기능

 

2.2 여러 리턴 타입의 메서드

  2.2.1 리턴 타입이 void, 입력매개변수는 없는 메서드

void print() {
	System.out.println("안녕");
}
  • void는 return 값이 없다는 것을 의미한다.

 

  2.2.2 리턴 타입이 int, 입력매개변수가 없는 메서드

int data() {
	return 3;
}
  • 리턴 타입이 int, 호출 후에는 3의 값이 반환된다.

 

  2.2.3 리턴 타입이 double, 입력매개변수가 2개

double sum(int a, double b) {
	return a+b;
}
  • int와 double형 데이터를 하나씩 받아서 둘을 합산, double 형태로 리턴한다.

 

  2.2.4 리턴 타입이 void이나, return 키워드 사용

void printMonth(int m) {
	if(m<0 || m>12) {
    	System.out.println("잘못된 입력");
        return; //메서드 종료
    }
    System.out.println(m + "월 입니다.");
}
  • 이때 return은 반환을 의미하는 것이 아닌, 메서드를 종료하라는 의미다.

 

 

2.3 메서드 호출하기

  2.3.1 클래스 외부에서 메서드를 호출해보자

  • 메서드도 클래스의 멤버로, 객체 안에 존재한다.
  • 때문에 클래스 외부에서 메서드를 사용하려면 먼저 객체를 생성해야 한다.
  • 그리고 객체의 위치를 저장하고 있는 참조 변수를 이용해 메서드를 호출해야 한다.
package study_class;


class A {
	//리턴 타입 void, 입력매개변수 없음.
	void print() {
		System.out.println("안녕");
	}
	//리턴 타입 int, 입력매개변수 없음.
	int data() {
		return 3;
	}
	//리턴 타입 double, 입력매개변수 2개
	double sum(int a, double b) {
		return a+b;
	}
	//리턴 타입 void, 내부에 리턴 포함(함수 종료)
	void printMonth(int m) {
		if(m<0 || m>12) {
			System.out.println("잘못된 입력.");
			return;
		}
		System.out.println(m+"월입니다.");
	}
}

public class Class_study {
	public static void main(String[] args) {
		//객체 생성
		A a = new A();
		//매서드 호출(멤버 활용)
		a.print();
		int k = a.data();
		a.data();
		System.out.println(k);
		double result = a.sum(3,  5.2);
		System.out.println(result);
		a.printMonth(5);
		a.printMonth(15);
	}
}

 

  2.3.2 클래스 내부에서 메서드 호출하기

  • 클래스 내부에 있는 메서드끼리는 객체를 생성하지 않고 서로를 호출할 수 있다.
  • 같은 멤버끼리는 클래스 내부에서 얼마든지 객체를 생성하지 않고 서로를 호출할 수 있다는 뜻이다.
  • 단, 메서드 앞에 static이 붙어 있을 때는 static이 붙은 필드 또는 메서드만 호출할 수 있다.
package study_class;

public class Class_study {
	public static void main(String[] args) {
		//같은 클래스 안에 있는 내부 메서드 호출
		print();
		
		int a = twice(3);
		System.out.println(a);
		
		double b = sum(a, 5.8);
		System.out.println(b);
	}
	
	public static void print() {
		System.out.println("안녕");
	}
	
	public static int twice(int k) {
		return k*2;
	}
	
	public static double sum(int m, double n) {
		return m+n;
	}
}

 

  2.3.3 입력매개변수가 배열인 메서드 호출

  • 입력매개변수를 배열로 사용할 땐, 배열의 선언/초기화를 주의해야 한다.,
  • 주석처리한 printArray({1, 2, 3});처럼 초깃값만 넘겨주면 오류가 발생한다.
package study_class;

import java.util.Arrays;

public class Class_study {
	public static void main(String[] args) {
		//배열을 입력매개변수로 하는 메서드 호출
		int[] a = new int[] {1, 2, 3};
		printArray(a);
		printArray(new int[] {1, 2, 3});
		//printArray({1, 2, 3});
	}
	
	public static void printArray(int[] a) {
		System.out.println(Arrays.toString(a));
	}
}

 

  2.3.4 기본 자료형 입력매개변수와 참조 자료형 입력매개변수의 차이

  • 배열과 같은 참조 자료형이 입력매개변수로 넘겨질 땐 실제 객체가 전달되는 것이 아니라 객체의 위칫값이 전달된다.
  • 기본 자료형을 입력매개변수로 전달하면 전달받은 메서드는 값을 복사해 사용한다.
  • 즉 메서드 twice() 실행이 완료되고도, main() frame 내 a는 변하지 않는 것이다.
package study_class;

public class Class_study {
	public static void main(String[] args) {
		int a = 3; //a는 main() 함수의 지역 변수 a다.
		int result1 = twice(3);
		System.out.println(result1);
		int result2 = twice(a);
		System.out.println(result2);
		System.out.println(a);
	}
	public static int twice(int a) {
		a = a*2; //a는 twice의 지역 변수 a다.
		return a;
	}
}
package study_class;

import java.util.Arrays;

public class Class_study {
	public static void main(String[] args) {
		int[] array = new int[] {1, 2, 3};
		modifyData(array);
		printArray(array);
	}
	public static void modifyData(int[] a) {
		a[0] = 4;
		a[1] = 5;
		a[2] = 6;
	}
	public static void printArray(int[] a) {
		System.out.println(Arrays.toString(a));
	}
}
  • 반면에 참조 자료형을 입력매개변수로 넘겼을 때를 보면 값이 바뀐다.
  • 입력매개변수로 넘겨진 변수의 스택 메모리값이 복사돼 사용되는 것은 동일하나, 참조 자료형은 스택 메모리에 객체의 참좃값(윗치값)을 저장하고 있다.
  • 까닭에 실제 객체가 아닌 객체의 참좃값이 전달돼 복사되고, 호출한 메서드와 호출된 메서드에서 모두 동일한 객체를 바라보게 된다.
  • 그러므로 호출된 메서드에서 객체의 값을 변경한 후 호출한 메서드로 돌아오면 값이 바뀌게 된다.

 

  2.3.5 오버로딩된 메서드

  • 입력매개변수의 개수나 자료형이 다른 여러 개의 동일한 이름을 지닌 메서드를 같은 공간에 정의하는 것
  • 이를 이해하기 위해선 메서드 시그너처의 의미를 알아야 한다.
  • 메서드 시그너처는 메서드명과 입력매개변수의 자료형을 말하는데, 메서드를 구분하는 기준 역할을 한다.
  • 자바 가상 머신은 메서드 시그너처가 다르면 메서드명이 동일해도 다른 메서드로 인식하는데 이를 이용한 것이 메서드 오버로딩이다.
  • 아래 색칠된 것이 바로 메서드 시그너처이다.
리턴 타입 메서드명 (자료형 변수명, 자료형 변수명, ...) {
}
int sum (int a, int b) {
     return 3;
}
package study_class;

public class Class_study {
	public static void main(String[] args) {
		print();
		print(3);
		print(5.8);
		print(2, 5);
	}
	public static void print() {
		System.out.println("데이터가 없습니다.");
	}
	public static void print(int a) {
		System.out.println(a);
	}
	public static void print(double a) {
		System.out.println(a);
	}
	/*
	 * 위의 것 void print(double a){}와 중복된다
	public static void print(double b) {
		System.out.println(b);
	}
	*/
	public static void print(int a, int b) {
		System.out.println("a: " + a + " b: " + b);
	}
	/*
	 * void print(int a, int b){}와 중복된다.
	public static int print(int a, int b) {
		System.out.println("a: " + a + " b: " + b);
		return a+b;
	}
	 */
}

 

  2.3.6 가변 길이 배열 입력매개변수 메서드

  • 개수가 정해지지 않은 가변 길이의 입력을 받는 입력매개변수로 입력된 값들을 배열로 저장하는 것이다.
  • 배열의 크기는 함수가 호출될 때 전달된 입력값의 개수로 정해진다.
  • 오버로딩만 사용될 떄랑 달리, 단 1개의 메서드만 정의해 모든 메서드 호출에 대응할 수 있게 된다.
리턴 타입 메서드명 (자료형... 참조 변수명) {
     //메서드 내용
}
package study_class;

//import java.util.Arrays;
//배열의 출력방법3에서 사용

public class Class_study {
	public static void main(String[] args) {
		//method1(int...values)
		method1(1, 2);
		method1(1, 2, 3);
		method1();
		//method2(String...values)
		method2("안녕", "방가");
		method2("땡큐", "베리", "감사");
		method2();
	}
	public static void method1(int...values) {
		System.out.println("배열의 길이 : " + values.length);
		/* 배열의 출력방법 1
		for(int i=0; i<values.length; i++){
			System.out.print(values[i] + " ");
		} */
		//배열의 출력방법 2
		for(int k: values) {
			System.out.print(k + " ");
		}
		/* 배열의 출력방법 3
		System.out.println(Arrays.toString(values));
		*/
		System.out.println();
	}
	public static void method2(String...values) {
		System.out.println("배열의 길이 : " + values.length);
		/* 배열의 출력방법 1
		for(int i=0; i<values.length; i++){
			System.out.print(values[i] + " ");
		} */
		//배열의 출력방법 2
		for(String k: values) {
			System.out.print(k + " ");
		}
		/* 배열의 출력방법 3
		System.out.println(Arrays.toString(values));
		*/
		System.out.println();
	}
}

 

 

여기까지가 메서드의 내용이다. 생성자부터는 2 게시글로 작성하려고 한다.

위의 예제... 책 펴낸 이의 세대가 보이는 것 같다...