Lesson: Classes and Objects 1
이제 자바 프로그래밍 언어의 기본에 대한 지식을 갖추었으므로, 자신만의 클래스를 작성하는 방법을 배울 수 있습니다. 이 수업에서는 멤버 변수[필드], 메서드, 생성자를 선언하는 것을 포함하여 자신의 클래스를 정의하는 방법에 대한 정보를 제공합니다.
자신의 클래스를 사용하여 객체를 생성하고, 생성한 객체를 사용하는 방법을 배우게 됩니다.
이 수업에서는 또한 클래스 내에 다른 클래스를 중첩[nested]시키는 방법과 열거형(enum)에 대해서도 다룹니다.
Classes
객체 지향 개념을 소개하는 수업에서는 자전거 클래스(bicycle class)를 예제로 사용했으며, 경주용 자전거, 산악 자전거, 탠덤 자전거를 하위 클래스(subclass)로 예시했습니다. 다음은 클래스 선언 개요를 제공하기 위한 자전거 클래스(Bicycle class)의 가능한 구현 예제 코드입니다. 이 수업의 이후 섹션에서는 클래스 선언을 단계별로 설명할 것입니다. 지금은 세부 사항에 대해 걱정하지 마세요.
public class Bicycle {
// 자전거 클래스는 세 개의 필드를 가집니다.
public int cadence;
public int gear;
public int speed;
// 자전거 클래스는 하나의 생성자를 가집니다.
public Bicycle(int startCadence, int startSpeed, int startGear) {
gear = startGear;
cadence = startCadence;
speed = startSpeed;
}
// 자전거 클래스는 네 개의 메서드를 가집니다.
public void setCadence(int newValue) {
cadence = newValue;
}
public void setGear(int newValue) {
gear = newValue;
}
public void applyBrake(int decrement) {
speed -= decrement;
}
public void speedUp(int increment) {
speed += increment;
}
}
Bicycle 클래스를 상속하는 MountainBike 클래스의 선언은 다음과 같습니다:
public class MountainBike extends Bicycle {
// MountainBike 하위 클래스는 하나의 필드를 가집니다.
public int seatHeight;
// MountainBike 하위 클래스는 하나의 생성자를 가집니다.
public MountainBike(int startHeight, int startCadence,
int startSpeed, int startGear) {
super(startCadence, startSpeed, startGear);
seatHeight = startHeight;
}
// MountainBike 하위 클래스는 하나의 메서드를 가집니다.
public void setHeight(int newValue) {
seatHeight = newValue;
}
}
MountainBike는 Bicycle의 모든 필드와 메서드를 상속받고, seatHeight 필드와 이를 설정하는 메서드를 추가합니다(산악 자전거는 지형에 따라 좌석 높이를 조절할 수 있습니다).
Declaring Classes
다음과 같은 방식으로 정의된 클래스를 보았습니다:
class MyClass {
// 필드, 생성자 및 메서드 선언
}
이것이 클래스 선언입니다. 클래스 본문(중괄호 사이의 영역)에는 클래스에서 생성된 객체의 생명 주기를 제공하는 모든 코드가 포함됩니다: 새로운 객체를 초기화하는 생성자, 클래스와 객체의 상태를 제공하는 필드 선언, 클래스와 객체의 동작을 구현하는 메서드 등이 포함됩니다.
앞서 본 클래스 선언은 최소한의 형태입니다. 여기에는 클래스 선언에 필요한 구성 요소만 포함되어 있습니다. 클래스에 대한 추가 정보를 제공할 수도 있습니다. 예를 들어, 슈퍼클래스의 이름이나 구현할 인터페이스 등을 클래스 선언의 시작 부분에 추가할 수 있습니다. 예를 들어,
class MyClass extends MySuperClass implements YourInterface {
// 필드, 생성자 및 메서드 선언
}
이것은 MyClass가 MySuperClass의 하위 클래스이며 YourInterface 인터페이스를 구현한다는 의미입니다.
또한 맨 처음에 public 또는 private와 같은 수정자를 추가할 수 있습니다. 따라서 클래스 선언의 첫 번째 라인이 상당히 복잡해질 수 있습니다. MyClass에 어떤 다른 클래스가 접근할 수 있는지를 결정하는 수정자인 public과 private는 이 수업의 나중 부분에서 다룹니다. 인터페이스와 상속에 관한 수업에서는 클래스 선언에서 extends와 implements 키워드를 사용하는 방법과 이유를 설명할 것입니다. 지금은 이러한 추가적인 복잡성에 대해 걱정할 필요가 없습니다.
일반적으로 클래스 선언에는 다음과 같은 구성 요소가 순서대로 포함될 수 있습니다:
1. public, private 등 나중에 다룰 다양한 수정자들 (그러나 private 수정자는 중첩 클래스에만 적용될 수 있다는 점에 유의하십시오).
2. 관례(convention)에 따라 첫 글자가 대문자인 클래스 이름.
3. 슈퍼클래스(부모 클래스)의 이름이 있는 경우, extends 키워드로 시작합니다. 클래스는 하나의 부모 클래스만 상속(서브클래스화)할 수 있습니다.
4. 클래스가 구현하는 인터페이스가 있는 경우, implements 키워드로 시작하는 쉼표로 구분된 인터페이스 목록. 클래스는 여러 인터페이스를 구현할 수 있습니다.
5. 중괄호 {}로 둘러싸인 클래스 본문.
Declaring Member Variables
변수에는 여러 종류가 있습니다:
⦁ 클래스 내의 멤버 변수—이들은 필드라고 불립니다.
⦁ 메서드나 코드 블록 내의 변수—이들은 지역 변수라고 불립니다.
⦁ 메서드 선언내의 변수—이들은 파라미터라고 불립니다.
Bicycle 클래스는 다음 코드 라인들을 사용하여 필드를 정의합니다:
public int cadence;
public int gear;
public int speed;
필드 선언은 다음 세 가지 구성 요소로 이루어집니다:
1. public 또는 private과 같은 0개 이상의 수정자.
2. 필드의 타입.
3. 필드의 이름.
Bicycle 클래스의 필드 이름은 cadence, gear, speed이며 모두 정수형(int) 데이터 타입입니다. public 키워드는 이러한 필드가 public 멤버로서, 클래스를 액세스하려 하는 모든 객체에서 접근할 수 있음을 나타냅니다.
Access Modifiers
첫 번째(가장 왼쪽) 수정자는 다른 클래스가 클래스의 멤버 필드에 접근할 수 있는지를 제어할 수 있습니다. 현재로서는 public과 private만 고려하십시오. 다른 접근 수정자는 나중에 논의될 것입니다.
⦁ public 수정자—필드는 모든 클래스들에서 접근할 수 있습니다.
⦁ private 수정자—필드는 자신의 클래스 내에서만 접근할 수 있습니다.
캡슐화의 정신에 따라, 필드를 private으로 만드는 것이 일반적입니다. 이는 Bicycle 클래스에서만 직접 접근할 수 있음을 의미합니다. 그러나 이러한 값에 접근할 필요가 있습니다. 이는 필드 값을 얻기 위한 public 메서드를 추가하여 간접적으로 수행할 수 있습니다:
public class Bicycle {
private int cadence;
private int gear;
private int speed;
public Bicycle(int startCadence, int startSpeed, int startGear) {
gear = startGear;
cadence = startCadence;
speed = startSpeed;
}
public int getCadence() {
return cadence;
}
public void setCadence(int newValue) {
cadence = newValue;
}
public int getGear() {
return gear;
}
public void setGear(int newValue) {
gear = newValue;
}
public int getSpeed() {
return speed;
}
public void applyBrake(int decrement) {
speed -= decrement;
}
public void speedUp(int increment) {
speed += increment;
}
}
Types
모든 변수는 타입을 가져야 합니다. int, float, boolean 등과 같은 기본 타입을 사용할 수 있습니다. 또는 string, array, objects와 같은 참조[reference] 타입을 사용할 수 있습니다.
Variables Names
모든 변수는 필드, 로컬 변수 또는 파라미터인지 여부에 관계없이 Lesson: Language Basics - Variables 레슨의 변수 명명에서 다루었던 동일한 명명 규칙과 관례를 따릅니다.
이 레슨에서는 메서드와 클래스 이름에도 동일한 명명 규칙과 관례가 적용된다는 점에 유의하십시오. 단, 다음과 같은 예외가 있습니다:
⦁ 클래스 이름의 첫 글자는 대문자로 시작해야 합니다.
⦁ 메서드 이름의 첫 번째(또는 유일한) 단어는 동사여야 합니다.
Defining Methods
다음은 일반적인 메서드 선언의 예입니다:
public double calculateAnswer(double wingSpan, int numberOfEngines,
double length, double grossTons) {
// 여기에 계산을 수행합니다
}
메서드 선언의 필수 요소는 메서드의 return 타입, 이름, 괄호 쌍 () 및 중괄호 {} 사이의 본문입니다.
일반적으로, 메서드 선언은 다음의 여섯 가지 요소로 구성됩니다:
1. Modifiers : public, private 등과 같은 수식어는 나중에 더 배우게 됩니다.
2. return type : 메서드가 반환하는 값의 데이터 타입 또는 반환 값이 없는 경우 void.
3. method name : 필드 이름에 적용되는 규칙이 메서드 이름에도 적용되지만, 관례는 약간 다릅니다.
4. Parameter list in (): 괄호 () 안에 쉼표로 구분된 입력 파라미터 목록으로, 각 파라미터는 데이터 타입이 앞에 붙어 있습니다. 파라미터가 없는 경우, 빈 괄호를 사용해야 합니다.
5. exception list: 나중에 예외를 다루게 됩니다.
6. method body between {} : 중괄호 {} 사이에 포함된 메서드의 코드로, 로컬 변수 선언 등을 포함합니다.
modifiers, return type, parameter 이 레슨의 후반부에서 다루어질 것입니다. 예외는 이후의 레슨에서 다루어집니다.
Definition : 메서드 선언의 두 가지 요소는 메서드 시그니처를 구성합니다—메서드의 name과 parameter 타입.
위에서 선언된 메서드의 시그니처는 다음과 같습니다:
calculateAnswer(double, int, double, double)
Naming a Method
비록 메서드 이름이 합법적인 식별자라면 무엇이든 될 수 있지만, 코드 규칙은 메서드 이름을 제한합니다. 관례에 따르면, 메서드 이름은 소문자 동사이거나 소문자 동사로 시작하는 여러 단어의 이름이어야 하며, 그 뒤에 형용사, 명사 등이 올 수 있습니다. 여러 단어로 된 이름에서는 두 번째 단어와 그 이후 단어의 첫 글자를 대문자로 해야 합니다. 다음은 몇 가지 예입니다:
run
runFast
getBackground
getFinalData
compareTo
setX
isEmpty
일반적으로, 메서드는 클래스 내에서 고유한 이름을 가집니다. 그러나 메서드 오버로딩으로 인해 다른 메서드와 동일한 이름을 가질 수 있습니다.
Overloading Methods
자바 프로그래밍 언어는 메서드 오버로딩을 지원하며, 자바는 서로 다른 메서드 시그니처를 가진 메서드를 구별할 수 있습니다. 이는 클래스 내에서 파라미터 목록이 다른 경우, 동일한 이름의 메서드를 가질 수 있음을 의미합니다(이와 관련된 자세한 사항은 "인터페이스와 상속[interfaces and inheritance]" 수업에서 다룰 예정입니다).
예를 들어, 다양한 데이터 타입(string, integer 등)을 그리기 위해 서예를 사용하는 클래스를 가지고 있고, 각 데이터 타입을 그리기 위한 메서드가 포함되어 있다고 가정해봅시다. 각 메서드에 대해 drawString, drawInteger, drawFloat 등 새로운 이름을 사용하는 것은 번거롭습니다. 자바 프로그래밍 언어에서는 동일한 이름을 가진 메서드를 사용하면서 각 메서드에 다른 파라미터 목록을 전달할 수 있습니다. 따라서 데이터 그리기 클래스는 파라미터 목록이 다른 네 가지 draw 메서드를 선언할 수 있습니다.
public class DataArtist {
...
public void draw(String s) {
...
}
public void draw(int i) {
...
}
public void draw(double f) {
...
}
public void draw(int i, double f) {
...
}
}
오버로딩된 메서드는 메서드에 전달된 아규먼트[arguemnt]의 개수와 타입에 따라 구별됩니다. 코드 예제에서 draw(String s)와 draw(int i)는 서로 다른 아규먼트 타입을 필요로 하기 때문에 명확하고 고유한 메서드입니다.
동일한 이름과 동일한 개수 및 타입의 아규먼트를 가진 메서드를 두 개 이상 선언할 수 없습니다. 컴파일러가 이들을 구분할 수 없기 때문입니다.
컴파일러는 메서드를 구분할 때 리턴 타입을 고려하지 않으므로, 리턴 타입이 다르더라도 시그니처가 동일한 두 메서드를 선언할 수 없습니다.
참고: 오버로딩된 메서드는 코드의 가독성을 크게 떨어뜨릴 수 있으므로, 이를 적절히 사용해야 합니다.
Providing Constructors for Your Classes
클래스에는 생성자가 포함되어 있으며, 이 생성자는 클래스 템플릿[설계도]으로부터 객체를 생성하기 위해 호출됩니다. 생성자 선언은 메서드 선언과 비슷해 보이지만, 클래스 이름을 사용하고 반환 타입이 없다는 점이 다릅니다. 예를 들어, Bicycle 클래스에는 하나의 생성자가 있습니다:
public Bicycle(int startCadence, int startSpeed, int startGear) {
gear = startGear;
cadence = startCadence;
speed = startSpeed;
}
새로운 Bicycle 객체를 myBike라는 이름으로 생성하기 위해서는 new 연산자를 사용하여 생성자를 호출합니다:
Bicycle myBike = new Bicycle(30, 0, 8);
new Bicycle(30, 0, 8)는 객체를 위한 메모리 공간을 생성하고 필드를 초기화합니다.
Bicycle 클래스에는 하나의 생성자만 있지만, 다른 생성자도 가질 수 있습니다. 예를 들어, 파라미터가 없는 생성자도 포함할 수 있습니다:
public Bicycle() {
gear = 1;
cadence = 10;
speed = 0;
}
Bicycle yourBike = new Bicycle();는 파라미터가 없는 생성자를 호출하여 yourBike라는 새로운 Bicycle 객체를 생성합니다.
두 생성자는 파라미터 목록이 다르기 때문에 Bicycle 클래스에서 함께 선언될 수 있습니다. 메서드와 마찬가지로, 자바 플랫폼은 파라미터 목록의 아규먼트 개수와 타입에 따라 생성자를 구별합니다. 동일한 클래스에 대해 동일한 개수와 타입의 아규먼트를 가진 두 개의 생성자를 작성할 수 없습니다. 그렇게 하면 자바 플랫폼이 이를 구분할 수 없기 때문에 컴파일 타임 오류가 발생합니다.
클래스에 생성자를 제공할 필요는 없지만, 이 경우 주의해야 합니다. 컴파일러는 생성자가 없는 모든 클래스에 대해 파라미터가 없는 기본 생성자를 자동으로 제공합니다. 이 기본 생성자는 슈퍼클래스의 파라미터가 없는 생성자를 호출합니다. 이 상황에서 슈퍼클래스에 디폴트 생성자가 없으면 컴파일러가 complain을 표시[컴파일 에러 발생]할 것이므로 이를 확인해야 합니다. 클래스에 명시적인 슈퍼클래스가 없으면, 암시적[implicit]으로 Object라는 슈퍼클래스를 가지며, Object에는 파라미터가 없는 생성자가 있습니다.
이 상황에서 슈퍼클래스에 디폴트 생성자가 없으면 컴파일러가 complain을 표시할 것이므로 이를 확인해야 합니다.
위 내용은 자바 클래스 상속 및 생성자와 관련된 설명입니다. 컴파일러가 슈퍼클래스에 no-argument 생성자가 없으면 오류를 발생시키는 상황을 이해하기 위해 실제 코드 예제를 살펴보겠습니다.
다음은 슈퍼클래스와 서브클래스를 포함하는 예제입니다.
슈퍼클래스 코드 (SuperClass.java)
public class SuperClass {
// 매개변수가 있는 생성자만 정의됨
public SuperClass(String message) {
System.out.println(message);
}
}
서브클래스 코드 (SubClass.java)
public class SubClass extends SuperClass {
// SubClass에 생성자가 정의되지 않음
}
위 코드에서 SubClass는 생성자가 정의되지 않았기 때문에 컴파일러는 자동으로 no-argument 생성자를 추가하려고 시도합니다. 하지만 SuperClass에는 no-argument 생성자가 없고 파라미터가 정의되어 있는 생성자만 정의되어 있습니다. 이 때문에 컴파일 오류가 발생합니다.
컴파일 오류 메시지
위 예제를 컴파일하려고 하면 다음과 같은 오류 메시지를 볼 수 있습니다.
Description Resource Path Location Type
Implicit super constructor SuperClass() is undefined for default constructor.
Must define an explicit constructor SubClass.java
/HelloWorld2/src/com/intheeast/bicycle line 3 Java Problem
위 예제들을 통해 컴파일러가 슈퍼클래스에 no-argument 생성자가 없을 때 어떻게 "complain"하는지 알 수 있습니다.
슈퍼클래스 생성자[super 키워드]를 직접 사용할 수도 있습니다. 이 레슨의 시작 부분에 나온 MountainBike 클래스가 바로 그렇게 했습니다. 이는 나중에 인터페이스와 상속에 대한 수업에서 다룰 것입니다.
package com.intheeast.bicycle;
public class Bicycle {
private int cadence = 0;
private int speed = 0;
private int gear = 1;
//
public Bicycle(int startCadence, int startSpeed, int startGear) {
gear = startGear;
cadence = startCadence;
speed = startSpeed;
}
public void changeCadence(int newValue) {
cadence = newValue;
}
public void changeGear(int newValue) {
gear = newValue;
}
public void speedUp(int increment) {
speed = speed + increment;
}
public void applyBrakes(int decrement) {
speed = speed - decrement;
}
public void printStates() {
System.out.println("cadence:" +
cadence + " speed:" +
speed + " gear:" + gear);
}
}
package com.intheeast.bicycle;
public class MountainBike extends Bicycle {
// MountainBike 하위 클래스는 하나의 필드를 가집니다.
public int seatHeight;
// MountainBike 하위 클래스는 하나의 생성자를 가집니다.
public MountainBike(int startHeight, int startCadence,
int startSpeed, int startGear) {
super(startCadence, startSpeed, startGear);
seatHeight = startHeight;
}
// MountainBike 하위 클래스는 하나의 메서드를 가집니다.
public void setHeight(int newValue) {
seatHeight = newValue;
}
}
액세스 수정자를 생성자의 선언에 사용하여 다른 클래스가 생성자를 호출할 수 있는지 제어할 수 있습니다.
참고: 다른 클래스가 MyClass 생성자를 호출할 수 없는 경우, MyClass 객체를 직접 생성할 수 없습니다.
Passing Information to a Method or a Constructor
메서드 또는 생성자의 선언은 해당 메서드 또는 생성자의 아규먼트의 개수와 타입을 선언합니다. 예를 들어, 다음은 대출 금액, 이자율, 대출 기간(기간의 수) 및 대출의 미래 가치를 기준으로 주택 대출의 월 상환금을 계산하는 메서드입니다:
public double computePayment(
double loanAmt,
double rate,
double futureValue,
int numPeriods) {
double interest = rate / 100.0;
double partial1 = Math.pow((1 + interest),
- numPeriods);
double denominator = (1 - partial1) / interest;
double answer = (-loanAmt / denominator)
- ((futureValue * partial1) / denominator);
return answer;
}
이 메서드는 네 개의 파라미터를 가집니다: 대출 금액, 이자율, 미래 가치 및 기간의 수. 처음 세 개는 배정밀도 부동 소수점(double) 숫자이고, 네 번째는 정수(int)입니다. 파라미터는 메서드 본문에서 사용되며, 실행 시 메서드가 호출될 때 전달된 아규먼트의 값을 갖게 됩니다.
참고: 파라미터는 메서드 선언의 변수 목록을 의미합니다. 아규먼트는 메서드가 호출될 때 전달되는 실제 값을 의미합니다. 메서드를 호출할 때 사용되는 아규먼트는 선언된 파라미터의 타입과 순서와 일치해야 합니다.
Parameter Types
메서드나 생성자의 파라미터에는 모든 데이터 타입을 사용할 수 있습니다. 여기에는 computePayment 메서드에서 본 것처럼 double, float, int와 같은 기본[Primitive] 데이터 타입과 객체 및 배열과 같은 참조[Reference] 데이터 타입이 포함됩니다.
다음은 배열을 아규먼트로 받아들이는 메서드의 예입니다. 이 예제에서 메서드는 새로운 Polygon 객체를 생성하고 Point 객체 배열로 초기화합니다(여기서 Point는 x, y 좌표를 나타내는 클래스라고 가정합니다):
public Polygon polygonFrom(Point[] corners) {
// 메서드 본문이 여기에 작성됩니다.
}
참고: 메서드를 메서드에 전달하려면 람다 표현식이나 메서드 참조를 사용하십시오.
Arbitray Number of Arguments
메서드에 임의의 개수의 값을 전달하기 위해 varargs라는 구조를 사용할 수 있습니다. 메서드에 전달될 특정 타입의 아규먼트가 몇 개인지 모를 때 varargs를 사용합니다. 이는 배열을 수동으로 생성하는 것에 대한 지름길입니다(앞의 메서드는 배열 대신 varargs를 사용할 수도 있었습니다).
varargs를 사용하려면 마지막 파라미터 타입 뒤에 줄임표(점 3개, ...), 공백, 파라미터 이름을 차례로 입력합니다. 그런 다음 없음을 포함하여 해당 파라미터를 원하는 만큼 사용하여 메서드를 호출할 수 있습니다.
public Polygon polygonFrom(Point... corners) {
int numberOfSides = corners.length;
double squareOfSide1, lengthOfSide1;
squareOfSide1 = (corners[1].x - corners[0].x)
* (corners[1].x - corners[0].x)
+ (corners[1].y - corners[0].y)
* (corners[1].y - corners[0].y);
lengthOfSide1 = Math.sqrt(squareOfSide1);
// 더 많은 메서드 본문 코드가 이어지며,
// Point들을 연결하여 다각형을 생성하고 반환합니다.
}
메서드 내부에서 corners는 배열처럼 다루어집니다. 메서드는 배열 또는 아규먼트의 시퀀스로 호출될 수 있습니다. 메서드 본문의 코드는 아규먼트를 배열로 처리합니다.
varargs는 주로 출력 메서드에서 많이 볼 수 있습니다. 예를 들어, printf 메서드는 다음과 같습니다:
public PrintStream printf(String format, Object... args)
이 메서드를 사용하면 임의의 개수의 객체를 출력할 수 있습니다. 다음과 같이 호출할 수 있습니다:
System.out.printf("%s: %d, %s%n", name, idnum, address);
또는 다음과 같이 호출할 수도 있습니다:
System.out.printf("%s: %d, %s, %s, %s%n", name, idnum, address, phone, email);
또는 다른 개수의 아규먼트로 호출할 수도 있습니다.
Parameter Names
메서드나 생성자의 파라미터를 선언할 때, 해당 파라미터에 이름을 제공합니다. 이 이름은 메서드 본문 내에서 전달된 아규먼트를 참조하는 데 사용됩니다.
파라미터의 이름은 그 범위 내에서 고유해야 합니다. 동일한 메서드나 생성자는 다른 파라미터와 동일한 이름을 가질 수 없으며, 메서드나 생성자 내의 로컬 변수와도 같은 이름을 가질 수 없습니다.
파라미터는 클래스의 필드와 동일한 이름을 가질 수 있습니다. 이 경우 파라미터가 해당 필드를 가린다고 합니다. 필드 가리기는 코드의 가독성을 어렵게 만들 수 있으며, 일반적으로 특정 필드를 설정하는 생성자와 메서드 내에서만 사용됩니다. 예를 들어, 다음 Circle 클래스와 setOrigin 메서드를 고려해 보세요:
public class Circle {
private int x, y, radius;
public void setOrigin(int x, int y) {
...
}
}
Circle 클래스에는 x, y, radius라는 세 개의 필드가 있습니다. setOrigin 메서드에는 각각 필드와 동일한 이름을 가진 두 개의 파라미터가 있습니다. 각 메서드 파라미터는 이름을 공유하는 필드를 가립니다. 따라서 메서드 본문 내에서 간단한 이름 x 또는 y를 사용하면 필드가 아닌 파라미터를 참조합니다. 필드에 접근하려면 한정된 이름을 사용해야 합니다. 이것은 이 레슨의 "this 키워드 사용" 섹션에서 나중에 논의될 것입니다.
Passing Primitive Data Type Arguments
기본형 아규먼트(int나 double 같은)는 값에 의한 전달로 메서드에 전달됩니다. 이는 파라미터 값의 변경이 메서드의 범위 내에서만 존재한다는 것을 의미합니다. 메서드가 리턴하면 파라미터는 사라지고, 그에 대한 모든 변경 사항도 소실됩니다. 다음은 예제입니다:
public class PassPrimitiveByValue {
public static void main(String[] args) {
int x = 3;
// x를 인수로 전달하여 passMethod() 호출
passMethod(x);
// x의 값이 변경되었는지 확인하기 위해 출력
System.out.println("After invoking passMethod, x = " + x);
}
// passMethod()에서 매개변수 변경
public static void passMethod(int p) {
p = 10;
}
}
이 프로그램을 실행하면 출력은 다음과 같습니다:
After invoking passMethod, x = 3
Passing Reference Data Type Arguments
참조 데이터 타입 파라미터(예: 객체)는 값에 의한 전달로 메서드에 전달됩니다. 이는 메서드가 반환될 때 전달된 참조가 여전히 이전과 동일한 객체를 참조한다는 것을 의미합니다. 그러나 적절한 접근 수준이 있는 경우, 메서드 내에서 객체 필드의 값을 변경할 수 있습니다.
예를 들어, Circle 객체를 이동시키는 임의의 클래스에 있는 메서드를 고려해 보십시오:
public void moveCircle(Circle circle, int deltaX, int deltaY) {
// 원의 원점을 x+deltaX, y+deltaY로 이동시키는 코드
circle.setX(circle.getX() + deltaX);
circle.setY(circle.getY() + deltaY);
// circle에 새로운 참조를 할당하는 코드
circle = new Circle(0, 0);
}
다음과 같은 아규먼트로 메서드를 호출해 보십시오:
moveCircle(myCircle, 23, 56)
메서드 내부에서 circle은 처음에 myCircle을 참조합니다. 메서드는 circle이 참조하는 객체(myCircle)의 x 및 y 좌표를 각각 23과 56만큼 변경합니다. 이러한 변경은 메서드가 반환될 때까지 지속됩니다. 그 후 circle은 x = y = 0인 새로운 Circle 객체에 대한 참조를 할당받습니다. 그러나 이 재할당은 영구적이지 않습니다. 참조가 값에 의해 전달되었기 때문에 변경할 수 없습니다. 메서드 내에서 circle이 가리키는 객체는 변경되었지만, 메서드가 리턴하면 myCircle은 여전히 메서드가 호출되기 전과 동일한 Circle 객체를 참조합니다.