값 복사와 주소 복사

자바에서 기본 타입의 변수는 값 자체가 복사되고, 참조 타입의 변수는 주소가 복사된다.

이 개념은 메소드를 호출할 때도 동일하게 적용된다.

 

값 복사

메소드의 매개변수가 기본 타입인 경우는 인자로 전달된 값이 매개변수에 복사되어 전달된다.

public class Main {
    public static void main(String[] args) {
        int firstScore = 99;
        int secondScore = 33;

        System.out.println("before(firstScore) : " + firstScore);
        System.out.println("before(secondScore) : " + secondScore);

        swapScore(firstScore, secondScore);

        System.out.println("after(firstScore) : " + firstScore);
        System.out.println("after(secondScore) : " + secondScore);
    }

    private static void swapScore(int score1, int score2) {
        int temp = score1;
        score1 = score2;
        score2 = temp;

        System.out.println("swqpScore() 에서 score1 : " + score1);
        System.out.println("swqpScore() 에서 score2 : " + score2);
    }
}

 

메소드가 호출되면서 매개변수를 통해 값이 복사되면서 main() 메소드 안에서 선언된 firstScore, secondScore 값이 swapScore() 메소드가 호출되는 순간 매개변수에 해당되는 score1, score2 변수에 복사되어 전달된다.

 

swapScore() 메소드에서 temp 변수를 이용하여 score1과 score2의 값을 교환하면 swapScore() 메소드에서는 값이 당연히 바뀌지만 main() 함수에서는 firstScore와 secodScore의 값이 바뀌지 않는다.

 

주소 복사

// 1. 클래스 선언부
public class Student {

    // 2. 멤버 변수
    public String name = "MillPRE";
    public int score = 52;
    public int firstScore;
    public int secondScore;
	
    
    // ~ 생략 ~
}
public class Main {
    public static void main(String[] args) {
        Student millpre = new Student();
        millpre.firstScore = 90;
        millpre.secondScore = 33;

        System.out.println("before(firstScore) : " + millpre.firstScore);
        System.out.println("before(secondScore) : " + millpre.secondScore);

        swapScore(millpre);

        System.out.println("after(firstScore) : " + millpre.firstScore);
        System.out.println("after(secondScore) : " + millpre.secondScore);
    }

    private static void swapScore(Student std) {
        int temp = std.firstScore;
        std.firstScore = std.secondScore;
        std.secondScore = temp;

        System.out.println("swqpScore() 에서 firstScore : " + std.firstScore);
        System.out.println("swqpScore() 에서 secondScore : " + std.secondScore);
    }
}


이전에 값 복사와는 다르게 millpre.firstScore와 millpre.secondScore 의 값이 maind에서도 바뀌는 것을 확인할 수 있다.

이는 main() 함수에서 swqpScore() 메소드를 호출할 때 millpre라는 참조변수가 참조하고 있는 Student 객체의 주소가 매개변수로 선언된 std 변수에 복사되기 때문이다.

swapScore 메소드가 호출되는 시점에 Student 객체는 millpre와 std 두 개의 참조 변수에 의해 공유되고 있는 상태가 된다.

 

728x90

'Language > JAVA' 카테고리의 다른 글

[JAVA] Getter/Setter  (0) 2023.11.02
[JAVA] 생성자  (0) 2023.10.25
[JAVA] Java Collections / Array / ArrayList  (2) 2023.10.25
[JAVA] 테스트코드 작성하기  (1) 2023.10.24
[JAVA] 메소드 Method  (0) 2023.10.19

메소드

메소드를 처음 본 사람에게 가장 쉬운 비교 대상은 함수(function)이다. 사실 자바의 메소드는 형태적으로는 함수와 동일하며, 기능도 함수이기 때문이다. 

 

메소드의 구조

메소드는 리턴 타입, 메소드 이름, 매개변수 목록과 같이 세 가지 요소로 구성된다. 그리고 이 세 개의 요소를 합쳐서 메소드 시그니처라고 한다.

리턴타입 메소드이름(매개변수 목록) {
	// 메소드의 기능(로직);
    return 메소드 실행 결과;
}

 

리턴 타입

리턴 타입은 메소드가 리턴할 데이터에 대한 타입 선언이다. 메소드는 반드시 리턴 타입으로 선언한 데이터를 리턴해야 한다. 만약 데이터를 리턴하지 않거나 선언한 타입과 다른 타입의 데이터를 리턴하면 에러가 발생한다. 

 

만약 메소드가 아무것도 리턴하지 않는다면 리턴 타입을 void로 선언해야 한다. void는 리턴값이 없는 메소드를 선언할 때 사용하는 예약어이다.

 

메소드 이름

메소드 이름은 변수 이름 규칙과 동일한 규칙을 적용하여 선언한다. 중요한 것은 메소드 이름은 메소드가 제공하는 기능을 어느 정도 유추할 수 있게 지어야 한다는 것이다. 

메소드 이름의 길이는 제한이 없으므로 충분히 기능을 유추할 수 있는 적절한 길이의 이름을 사용하는 것이 바람직하다.

 

매개변수

메소드는 매개변수를 통해 외부로부터 메소드의 기능을 수행하는 데 필요한 데이터를 받아들인다. 물론 외부로부터 데이터를 받지 않고 멤버 변수만으로 기능을 처리할 수도 있다. 당연히 이런 경우에는 매새변수를 선언하지 않는다.

 

매개변수는 로컬 변수에 해당하므로 멤버 변수와 달리 메소드가 호출될 때 메모리에 올라간다. 그리고 메소드 수행이 종료되는 순간 곧바로 삭제된다. 매개변수 개수는 적을수록 좋다. 매개변수가 많으면 메소드를 호출할 때마다 매개변수의 개수와 타입을 신경 써야 하기 때문이다.

 

메소드 유형

메소드의 유형은 너무나 다양하지만 크게 두 가지 기준으로 나누면 다음과 같다.

  • 매개변수의 유무
  • 리턴 타입의 유무

 

매개변수의 유무

매개변수가 없는 메소드는 두 가지 형태가 있다. 첫 번째는 자체적으로 변수를 선언하여 사용하는 메소드가 있고, 두 번째는 오직 멤버 변수만을 사용하여 기능을 처리하는 메소드가 있다.

 

리턴 타입 유무

메소드를 구분하는 두 번째 기준은 리턴 타입의 유무다. 

 

Getter/Setter 메소드

자바로 프로그램을 개발하다 보면 클래스의 멤버 변수를 private으로 선언하고 멤버 변수에 접근하여 처리하는 public 메소드가 필요한 경우가 있다.

 

private 멤버 변수에 값을 할당하는 메소드를 Setter 메소드라고 하고, private 멤버 변수에 할당된 값을 리턴한느 메소드를 Getter메소드라고 한다. 그리고 이 둘을 합쳐서 Getter/Setter 라고 한다. 

 

메소드 오버로딩

자바는 하나의 클래스에 이름이 같은 메소드를 여러 개 선언할 수 있는데, 이를 메소드 오버로딩(overloading) 또는 메소드 중복 정의라고 한다.

 

이름이 같은 메소드는 매개변수를 통해서 식별한다.

메소드 이름이 동일해도 매개변수의 개수와 타입이 다르면 메소드를 호출할 때 매개변수의 개수와 타입을 통해 정확하게 원하는 메소드를 호출할 수 있다. 

// 1 
int printAvg(int javaScore, int pythonScore) {
	return (javaScore + pythonScore)/2;
}

// 2
int printAvg(int javaScore, int pythonScore, int sqlScore) {
	return (javaScore + pythonScore + sqlScore)/3;
}

1과 2 는 매개변수의 개수가 다르기 때문에 오버로딩이다.

 

728x90

'Language > JAVA' 카테고리의 다른 글

[JAVA] Java Collections / Array / ArrayList  (2) 2023.10.25
[JAVA] 테스트코드 작성하기  (1) 2023.10.24
[JAVA] 패키지  (0) 2023.10.19
[JAVA] 접근 제어자  (0) 2023.10.19
[JAVA] 클래스 Class (3)  (0) 2023.10.18

패키지

자바에서 패키지(package)는 디렉터리의 개념과 동일하다. 따라서 패키지를 이용하면 비슷한 기능의 클래스들을 같은 디렉터리로 묶어서 관리할 수 있다.

 

패키지 선언

 

패키지를 이용하면 연관된 클래스들을 하나의 디렉터리로 묶어서 관리할 수 있다. 그런데 사실 이런 패키지의 가장 근본적인 용도는 동일한 이름의 클래스를 다른 용도로 사용하기 위함이다.

 

예를 들어 현재 작업 중인 디렉터리에 학생 클래스에 해당하는 Student.java 파일이 존재하는데, 이 Student 말고 다른 용도의 Student 클래스를 작성한다고 가정해보자. 당연히 디렉터리에 두 개의 Student.java 파일이 존재할 수 없으므로 문제가 생길 것이다. 자바에서는 이런 경우 패키지를 통해 클래스를 분리한다.

 

클래스에 패키지를 선언할 때는 package라는 예약어를 사용한다.

package 패키지경로;

패키지 선언은 주석을 제외하고 반드시 클래스 파일의 가장 첫 번째 줄에 위치해야 한다.

패키지가 여러 개의 디렉터리로 구성되어 있는 경우, 패키지 경로를 점(.)을 이용하여 구분하되 관례상 소문자로만 구성한다.

 

현재 대학생의 시험 결과만 관리하던 프로그램에서 고등학생의 성적을 추가로 관리한다고 가정하자. 그런데 현재 프로젝트에 고등학생에 해당하는 Student 클래스를 작성하려고 하면 이미 Student 클래스가 존재한다는 경고 메시지가 출력될 것이다.

 

이때 shcool.high 라는 패키지를 지정하면 경고는 사라지고 정상적으로 Student 클래스를 생성할 수 있게 된다.

패키지는 물리적으로 디렉터리이기 때문에 클래스에 패키지를 선언하면 패키지에 해당하는 디렉터리들이 만들어진다. 따라서 school/high 디렉터리에 Student.java 파일이 위치한 것을 확인할 수 있다.

 

 

 

728x90

'Language > JAVA' 카테고리의 다른 글

[JAVA] 테스트코드 작성하기  (1) 2023.10.24
[JAVA] 메소드 Method  (0) 2023.10.19
[JAVA] 접근 제어자  (0) 2023.10.19
[JAVA] 클래스 Class (3)  (0) 2023.10.18
[JAVA] 클래스 Class (2)  (0) 2023.10.18

객체의 생성

클래스로부터 객체를 생성하기 위해서는 new라는 예약어를 사용해야 한다. new는 객체 생성 연산자이다. 

new 생성자();

다음은 Student 클래스로부터 객체를 생성하는 과정이다.

public class Student {
	String name;
    int score;
}


new Student();

 클래스로부터 객체를 생성할 때 생성자가 자동으로 호출되는데, 이때 클래스의 멤버 변수가 초기화된다. 클래스로부터 객체를 생성하는 것은 배열 객체를 생성하는 것과 비슷하다. 다만 배열은 동일한 타입의 데이터만 저장할 수 있지만, 클래스는 다른 타입의 데이터도 저장할 수 있다. 이는 클래스에 선언된 멤버 변수들의 타입이 다르기 때문이다.

 

객체의 사용

클래스로부터 생성된 객체는 배열과 동일하게 참조 변수를 통해서만 접근할 수 있다. 참조 변수에 생성된 객체의 주소를 할당하는 과정은 다음과 같다.

클래스이름 참조변수;
참조변수 = new 생성자();

// 예시
Student kim;
kim = new Student();

Student lee = new Student();

 

이제 kim이라는 참조 변수를 통해서 메모리에 생성된 Student 객체에 접근할 수 있고, Student 객체에 포함된 멤버 변수를 사용할 수 있다. 

 

public class StudentTest {
    public static void main(String[] args) {
        Student kim = new Student();
        kim.name = "둘리";
        kim.score = 83;
        
        System.out.println("이름 : "+kim.name); // 둘리
        System.out.println("성적 : "+kim.score); // 83
    }
}


class Student {
    String name;
    int score;
}

먼저 생성자를 통해 Student 클래스의 객체를 생성했다. 그리고 kim 이라는 참조 변수를 통해 Student 객체에 포함된 name과 score 변수에 각각 "둘리", 83 이라는 값을 할당했다. 그리고 나서 Student 객체가 가진 name, score 변수의 값을 출력했다.

 

728x90

'Language > JAVA' 카테고리의 다른 글

[JAVA] 패키지  (0) 2023.10.19
[JAVA] 접근 제어자  (0) 2023.10.19
[JAVA] 클래스 Class (2)  (0) 2023.10.18
[JAVA] 클래스 Class (1)  (0) 2023.10.18
[JAVA] 버블 정렬 알고리즘  (0) 2023.10.18

+ Recent posts