선언위치에 따른 변수의 종류
변수
- 클래스변수
- 인스턴스변수
- 지역변수
멤버변수를 제외한 나머지 변수들은 모두 지역변수이며, 멤버변수 중 static이 붙은 것은 클래스변수, 붙지 않은 것은 인스턴스변수이다.
int iv; //인스턴스변수
static int cv; //클래스변수(static변수, 공유변수)
void method()
{
int lv = 0; //지역변수
}
변수의 종류 | 선언위치 | 생성시기 |
---|---|---|
클래스변수 (class variable) | 클래스 영역 | 클래스가 메모리에 올라갈 때 |
인스턴스변수 (instance variable) | 클래스 영역 | 인스턴스가 생성되었을 때 |
지역변수(local variable) | 크래스 영역 이외의 영역 (메서드, 생성자, 초기화 블럭 내부) | 변수 선언문이 수행되었을 때 |
- 인스턴스변수(instance variable)인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있다.
- 클래스변수(class variable)클래스변수는 인스턴스 변수와 달리 인스턴스를 생성하지 않고도 언제든지 사용이 가능하다는 특징과 모든 인스턴스가 공통된 저장공간(변수)을 공유하게 된다. 클래스가 메모리에'로딩(loading)될 때 생성되어 프로그램이 종료 될 때 까지 유지되며, public을 앞에 붙이면 같은 프로그램 내에서 어디서나 접근할 수 있는 '전역변수(global variable)'의 성격을 갖는다.
- 지역변수(local variable)메서드 내에 선언되어 메서드 내에서만 사용가능 하며 메서드가 종료되면 소멸되어 사용할 수 없게 된다. 지역변수가 선언된 블럭{}내에서만 사용가능하며 블럭{}을 벗어나면 소멸되어 사용할 수 없게 된다.
클래스변수와 인스턴스 변수
package object_oriented_programming;
public class CardTest {
public static void main(String[] args) {
System.out.println("Card.width = "+Card.width);
System.out.println("Card.height = "+Card.height);
Card c1 = new Card();
c1.kind = "Heart";
c1.number = 7;
Card c2 = new Card();
c2.kind = "Spade";
c2.number = 1;
System.out.println("c1은 "+c1.kind+", "+c1.number+ "이며, 크기는 ("+c1.width+", "+c1.height+")");
System.out.println("c2은 "+c2.kind+", "+c2.number+ "이며, 크기는 ("+c2.width+", "+c2.height+")");
System.out.println("c1의 width와 height를 각각 50, 80으로 변경합니다.");
c1.width = 50;
c1.height = 80;
System.out.println("c1은 "+c1.kind+", "+c1.number+ "이며, 크기는 ("+c1.width+", "+c1.height+")");
System.out.println("c2은 "+c2.kind+", "+c2.number+ "이며, 크기는 ("+c2.width+", "+c2.height+")");
}
}
class Card{
String kind;
int number;
static int width = 100;
static int height = 250;
}
//결과
Card.width = 100
Card.height = 250
c1은 Heart, 7이며, 크기는 (100, 250)
c2은 Spade, 1이며, 크기는 (100, 250)
c1의 width와 height를 각각 50, 80으로 변경합니다.
c1은 Heart, 7이며, 크기는 (50, 80)
c2은 Spade, 1이며, 크기는 (50, 80)
Card인스턴스인 c1과 c2는 클래스변수인 width와 height는 Card클래스의 인스턴스를 생성하지 않고도 "클래스이름.클래스변수"와 같은 방식으로 사용할 수 있다.
인스턴스변수는 인스턴스가 생성될 때 마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공토된 값을 갖는다.
메서드(method)
메서드는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다. 기본적으로 수학의 함수와 유사하며, 어떤 값을 이렵하면 이 값으로 작업을 수행해서 결과를 반환한다.
메서드를 사용하는 이유
- 높은 재사용성(reusability)
- 중복된 코드의 제거
- 프로그램의 구조화
메서드의 선언과 구현
반환타입 메서드이름 (타입 변수명, 타입 변수명, ...)
{
//메서드 호출시 수행될 코드
}
int add(int a, int b)
{
int result = a+b;
return result;
}
메서드 선언부(method declartion, method header)
ex) int add(int x, int y)
메서드 선언(parameter declartion)
매개변수는 메서드가 작업을 수행하는데 필요한 값들(입력)을 제공받기 위한 것이며, 필요한 값의 개수만큼 변수를 선언하며 각 변수 간의 구분은 쉼표','를 사용
ex) int add(int x, int y)
메서드의 이름(method name)
메서드는 특정 작업을 수행하므로 메서드의 이름은 'add'와 같이 동사인 경우가 많다.
반환타입(return type)
메서더의 작업수행 결과인 반환값의 타입을 적는다. - void는 반환값이 없음을 의미한다.
메서드의 구현부(method body, 메서드 몸통)
메서드의 선언부 다음에 오는 괄호{}를 '메서드의 구현부'라 한다.
return문
메서드의 반환값이 void가 아닌경우 구현부{}안에 return 반환값; 이 포함되어야한다.
지역변수(local variable)
메서드 내에 선언된 변수들은 그 메서드 내에서만 사용할 수 있으므로 서로 다른 메서드라면 같은 이름의 변수를 선언해도 된다.
메서드의 호출
메서드이름(값1, 값2, ...);
print99();
int result = add(3,5);
인자(argument)와 매개변수(parameter)
메서드를 호출할 때 괄호()안에 지정해준 값들을 인자(argument) 또는 인수라고 하는데, 인자의 개수와 순서는 호출된 메서드에 서언된 매개변수와 일치해야한다.
ex) void add(int a, int b){..}
int result = add(2,4);
메서드의 실행흐름
같은 클래스 내의 메서드끼리는 참조변수를 사용하지 않고도 서로 호출이 가능하지만 static메서드는 같은 클래스 내의 인스턴스 메서드를 호출할 수 없다.
package object_oriented_programming;
public class MyMathTest {
public static void main(String[] args) {
MyMath mm = new MyMath();
long result1 = mm.add(5L, 3L);
long result2 = mm.subtract(5L, 3L);
long result3 = mm.multiply(5L, 3L);
double result4 = mm.divide(5L, 3L);
System.out.println("add(5L, 3L) = "+result1);
System.out.println("subtract(5L, 3L) = "+result2);
System.out.println("multiply(5L, 3L) = "+result3);
System.out.println("divide(5L, 3L) = "+result4);
}
}
class MyMath{
long add(long a, long b) {
long result = a+b;
return result;
// return a+b;
}
long subtract(long a, long b) {return a-b;}
long multiply(long a, long b) {return a*b;}
double divide(double a, double b) {return a / b;}
}
//결과
add(5L, 3L) = 8
subtract(5L, 3L) = 2
multiply(5L, 3L) = 15
divide(5L, 3L) = 1.6666666666666667
return문
return문은 현재 실행중인 메서드를 종료하고 호출한 메서드로 되돌아간다. void인 경우, return문 없이도 문제가 없는 이유는 메서드 마지막에 "return ;"을 자동으로 추가한다.
반환값(return value)
int add(int x, int y){
int result = x+y;
return result;
}
int add(int x, int y) {
return x+y;
}
JVM의 메모리구조
3가지 주요 영역: Method area, call stack, heap
- 메서드 영역(Method area)프로그램 실행 중 어떤 클래스가 사용되면, JVM은 해당 클래스의 클래스파일을 읽고 분석하여 클래스에 대한 정보를 메서드 영역에 저장한다. 또한, 클래스변수에 대해서도 이 곳에 저장한다.
- 힙(heap)인스턴스가 생성되는 공간. 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성된다.
- 호출스택(call stack 또는 execution stack)호출스택은 메서드의 작업에 필요한 메모리 공간을 제공한다. 메서드가 작업을 마치면 할당되었던 메모리공간은 반환되어 사라진다.
- 메서드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받는다.
- 메서드가 수행을 마치고나면 사용했던 메모리를 반환하고 스택에서 제거된다.
- 호출스택의 제일 위에 있는 메서드가 현재 실행 중인 메서드이다.
- 아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드이다.
package object_oriented_programming;
public class CallStackTest {
public static void main(String[] args) {
firstMethod();
}
static void firstMethod() {
secondMethod();
}
static void secondMethod() {
System.out.println("SecondMethod()");
}
}
//결과
SecondMethod()
객체를 생성하지 않고도 메서드를 호출할 수 있으려면, 메서드 앞에 'static'을 붙여야한다.
package object_oriented_programming;
public class CallStackTest2 {
public static void main(String[] args) {
System.out.println("main(String[] args)이 시작됨");
firstMethod();
System.out.println("main(String[] args)이 종료됨");
}
static void firstMethod() {
System.out.println("firstMethod()이 시작됨");
secondMethod();
System.out.println("firstMethod()이 종료됨");
}
static void secondMethod() {
System.out.println("secondMethod()이 시작됨");
System.out.println("secondMethod()이 종료됨");
}
}
//결과
main(String[] args)이 시작됨
firstMethod()이 시작됨
secondMethod()이 시작됨
secondMethod()이 종료됨
firstMethod()이 종료됨
main(String[] args)이 종료됨
기본형 매개변수와 참조형 매개변수
기본형 매개변수 변수의 값을 읽기만 할 수 있다. (read only)
참조형 매개변수 변수의 값을 읽고 변경할 수 있다. (read & write)
기본형 매개변수
package object_oriented_programming;
class Data {int x;}
public class PrimitiveParaEx {
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
System.out.println("main() : x = "+d.x);
change(d.x);
System.out.println("After change(d.x)");
System.out.println("main() : x = "+d.x);
}
static void change(int x) { //기본형 매개변수
x=1000;
System.out.println("change() : x = "+x);
}
}
//결과
main() : x = 10
change() : x = 1000
After change(d.x)
main() : x = 10
참조형 매개변수
package object_oriented_programming;
class Data {int x;}
public class ReferenceParamEx {
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
System.out.println("main() : x = "+d.x);
change(d);
System.out.println("After change(d.x)");
System.out.println("main() : x = "+d.x);
}
static void change(Data d) {
d.x = 1000;
System.out.println("change() : x = "+d.x);
}
}
//결과
main() : x = 10
change() : x = 1000
After change(d.x)
main() : x = 1000
package object_oriented_programming;
public class ReferenceParamEx2 {
public static void main(String[] args) {
int[] x = {10};
System.out.println("main() : x = "+x[0]);
change(x);
System.out.println("After change(x)");
System.out.println("main() : x = "+x[0]);
}
static void change(int[] x) {
x[0] = 1000;
System.out.println("change() : x = "+x[0]);
}
}
//결과
main() : x = 10
change() : x = 1000
After change(x)
main() : x = 1000
package object_oriented_programming;
public class ReferenceParamEx3 {
public static void main(String[] args) {
int[] arr = new int [] {3,2,1,6,5,4};
printArr(arr);
sortArr(arr);
printArr(arr);
System.out.println("sum="+sumArr(arr));
}
private static int sumArr(int[] arr) {
int sum = 0;
for(int i=0; i<arr.length; i++)
sum += arr[i];
return sum;
}
private static void sortArr(int[] arr) {
for(int i=0; i<arr.length-1; i++)
for(int j=0; j<arr.length-1-i; j++)
if(arr[j] > arr[j+1]) {
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
private static void printArr(int[] arr) {
System.out.print("[");
for(int i : arr)
System.out.print(i+",");
System.out.println("]");
}
}
//결과
[3,2,1,6,5,4,]
[1,2,3,4,5,6,]
sum=21
반환값이 없는 메서드로 바꾸는 방법
package object_oriented_programming;
public class ReturnTest {
public static void main(String[] args) {
ReturnTest r = new ReturnTest();
int result = r.add(3,5);
System.out.println(result);
int[] result2 = {0};
r.add(3,5,result2);
System.out.println(result2[0]);
}
void add(int a, int b, int[] result) {
result[0] =a+b;
}
int add(int a, int b) {
return a+b;
}
}
//결과
8
8
참조형 변환타입
반환타입도 참조형이 될 수 있다.
package object_oriented_programming;
class Data{int x;}
public class ReferenceReturnEx {
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
Data d2 = copy(d);
System.out.println("d.x = "+d.x);
System.out.println("d2.x = "+d2.x);
}
static Data copy(Data d) {
Data tmp = new Data();
tmp.x = d.x;
return tmp;
}
}
//결과
d.x = 10
d2.x = 10
반환타입이 '참조형'이라는 것은 메서드가 객체의 주소를 반환한다는 것을 의미한다.
출처 : JAVA의 정석 - (남궁성지음)