자바에서는 기본 타입 데이터뿐 아니라, 객체를 원소로 하는 개체 배열도 만들 수 있다.
Circle [] c; // Circle 배열에 대한 레퍼런스 변수 c 선언
c = new Circle[5]; // 레퍼런스 배열 생성
for (int i=0; i<c.length; i++) {
c[i] = new Circle(i); // 배열의 각 원소 객체 생성
}
객체 배열을 만들기 위해서는 다음의 3단계가 필요하다.
다음은 Circle 클래스의 배열에 대한 레퍼런스 변수 c를 선언한다.
Circle [] c;
이 선언문은 레퍼런스 변수 c만 선언할 뿐, 배열을 생성하는 것은 아니다. 그러므로 다음과 같이 배열의 원소 개수를 지정해서는 안 된다.
Circle[5] c; // 오류. 배열의 크기를 지정하면 컴파일 오류 발생
두 번째로 5개의 레퍼런스를 원소로 하는 배열을 생성한다. 배열의 원소는 객체가 아니라 레퍼런스이다.
c = new Circle[5]; // Circle 객체에 대한 레퍼런스 5개 생성
이 코드의 실행 결과는 Circle 객체에 대한 레퍼런스 배열이 생성되며, 변수 c가 이를 가리킨다. Circle 객체들은 아직 존재하지 않는다.
이제 다음 코드를 이용하여 Circle 객체를 하나씩 생성하여 배열 c[]의 각 레퍼런스에 대입한다.
for (int i=0; i<c.length; i++) {
c[i] = new Circle(i); // i 번째 Circle 객체 생성
}
배열의 크기만큼 Circle 객체를 생성하여 레퍼런스 배열에 하나씩 대입한다. 이렇게 하면 비로소 Circle 객체 배열이 생성된다.

배열 c의 i번째 객체에 접근하기 위해서는 c[i] 레퍼런스를 사용하면 된다. 다음 코드는 배열 c에 들어 있는 모든 Circle 객체의 면적을 출력한다.
for (int i=0; i<c.length; i++) {
System.out.print((int)(c[i].getArea()) + " ");
}
이 코드의 실행 결과는 다음과 같다.
0 3 12 28 50
메소드는 클래스의 멤버 함수로서, 메소드 앞에 접근 지정자를 선언한다는 점을 제외하면 C/C++의 함수 작성법과 동일하다. 접근 지정자는 public, private, protected, 디폴트의 4가지 유형으로, 메소드가 다른 클래스에서 호출될 수 있는지 지정하기 위해 사용된다.
// public: 접근 지정자, int: 리턴 타입, getSum: 메소드 이름
public int getSum(int i, int j) {
int sum;
sum = i + j; // 메소드 코드
return sum;
}
자바의 메소드 호출시 인자 전달 방식(argument passing)은 '값에 의한 호출'(call-by-value)이다. 호출하는 실인자의 값이 복사되어 메소드의 매개 변수에 전달된다.
메소드의 매개변수가 기본 타입(byte, char, short, int, long, float, double, boolean)으로 선언된 경우, 호출자(caller)가 건네는 값이 매개변수에 복사되어 전달된다.
int n = 10;
increase(n);
increase(int m) 메소드가 호출되면, 매개변수 m이 생성되고 10으로 초기화된다. 그러고 나서 m 값을 1 증가시킨다. increase()에서 리턴하여 main() 메소드로 돌아오면 변수 n 값은 여전히 10으로 남아 있다.
메소드의 매개변수가 클래스 타입인 경우, 객체가 아니라 객체의 레퍼런스 값이 전달된다.
increase(pizza);
이 호출문에 의해 increase(Circle m)가 호출되면 매개변수 m이 생기고, pizza 변수에 저장된 값(레퍼런스)이 m에 복사되어, m은 pizza가 가리키는 객체를 함께 가리키게 된다. 그러므로 m.radius++;에 의해 radius는 11로 변경되고 increase()가 종료한 후에도 그대로 남는다. 메소드 호출 시 객체가 전달되는 경우, 객체에 대한 레퍼런스만 전달되지 객체가 통째로 복사되지 않는다.
public class ReferencePassing {
public static void main (String args[]) {
Circle pizza = new Circle(10);
increase(pizza);
System.out.println(pizza.radius); // 실행결과: 11
}
static void increase(Circle m) {
m.radius++;
}
배열이 메소드에 전달되는 경우도 객체 레퍼런스가 전달되는 경우와 동일하다. 배열이 통째로 전달되는 것이 아니며 배열에 대한 레퍼런스만 전달된다.
public class ArrayPassing {
public static void main(String args[]) {
int a[] = {1, 2, 3, 4, 5};
increase(a);
for (int i=0; i<a.length; i++) {
System.out.println(a[i]+" "); // 실행결과: 2 3 4 5 6
}
}
static void increase(int[] array) {
for (int i=0; i<array.length; i++) {
array[i]++;
}
}
}
main()에서 생성된 배열 a가 increase()에 전달된다. increase(int [] array)의 매개변수 array는 정수형 배열에 대한 레퍼런스로서 배열 a를 가리키게 되어 두 레퍼런스는 하나의 배열을 공유하게 된다. increase() 메소드에서 array 배열의 각 원소를 1씩 증가시키고 리턴한 후, main()에서 배열 a를 출력하면 변경된 값 2 3 4 5 6이 출력된다.
자바에서는 한 클래스 내에, 이름이 같지만 매개변수의 타입이나 개수가 서로 다른 여러 개의 메소드를 중복 작성할 수 있다. 이것을 메소드 오버로딩 혹은 메소드 중복이라고 부른다. 메소드 오버로딩은 자바 다형성의 한 경우이다. 여러 개의 메소드가 오버로딩되려면 다음 두 조건을 모두 만족하여야 한다.
메소드의 리턴 타입이나 접근 지정자는 메소드 오버로딩과 관계없다.
다음은 2개의 getSum() 메소드가 정상적으로 오버로딩된 사례이다. 메소드 이름이 동일하고 매개변수의 개수가 서로 다르기 때문에, 두 메소드는 한 클래스 내에 공존하는데 아무 문제가 없다.
class MethodOverloading { // getSum() 메소드의 정상적인 오버로딩 사례
public int getSum(int i, int j) {
return i + j;
}
public int getSum(int i, int j, int k) {
return i + j + k;
}
}
메소드 오버로딩은 자바 컴파일러에 의해 판단되며, 컴파일러가 이름이 같은 메소드들을 구분할 수 있으면 메소드 오버로딩이 성공한다. 다음 코드는 오버로딩이 실패한 경우이다.
class MethodOverloadingFail { // 메소드 오버로딩이 실패한 사례
public int getSum(int i, int j) {
return i + j ;
}
public double getSum(int i, int j) {
return (double)(i + j);
}
}
앞의 코드에서 2개의 getSum() 메소드의 매개변수 개수와 타입이 모두 같다. 그러므로 이 두 메소드는 호출자의 입장에서 구분할 수 없으며 자바 컴파일러는 컴파일 오류를 발생시킨다. 혹은 독자들이 메소드의 리턴 타입이 서로 다르니 두 메소드가 서로 다른 것이라고 생각할 수 있겠지만, 리턴 타입은 메소드를 구분하는 기준으로 사용하지 않는다.