메소드와 인스턴스, 정적 멤버

이동주·2025년 3월 5일

JAVA

목록 보기
15/30

메소드

  • 클래스를 구성하는 속성과 동작 중 동작에 해당됨!
  • ()가 붙여져있으면 메소드, 없으면 속성!
  • 별도로 하나만 만들어지는 변수와는 달리 메소드는 코드를 공유하는 역할을 함!

메소드 선언

  • 객체의 동작을 실행 블록으로 정의하는 것

  • 리턴타입 : 메소드 실행 후 호출한 곳으로 전달하는 결과값의 타입

  • 메소드명 : 메소드명은 첫 문자를 소문자로 시작하고, 캐멀 스타일로 작성함

  • 매개변수 : 메소드를 호출할 때 전달한 매개값을 받기 위해 사용

  • 실행블록 : 메소드 호출 시 실행되는 부분

  • 함수의 값(return)을 받지 않을 때에는 void 사용

  • 리턴 타입 함수를 사용할 경우 리턴값을 해당 타입에 맞게 지정하기

  • 만약 메소드 안에 if문을 사용할 경우 반드시 else문도 같이 만들어서 if문과 else문 모두 리턴값을 받아야함

  • 형태

// 메소드 선언 클래스 (클래스 내부)

// 리턴값이 없는 메소드
// 인자값이 없는 기본메소드
void 함수명(){
	실행문
}

// 인자값이 두 개인 일반메소드
void 함수명2(타입 값1, 타입 값2) {
	실행문
}


// 리턴 값을 받아야 하는 메소드 (기본형 타입 메소드)
// 인자값이 없는 기본메소드
public 타입 함수명3(){
	실행문
	return 변수명;
}

// 인자값이 두 개인 일반메소드
public 타입 함수명4(타입 값1, 타입 값2){
	실행문
	return 변수명;
}

메소드 호출

  • 메소드 블록을 실제로 실행하는 구문
  • 클래스로부터 객체가 생성된 후에 메소드는 생성자와 다른 메소드 내부에서 호출될 수 있고, 객체 외부에서도 호출될 수 있음
  • 함수의 경우 해당 함수의 인자값의 갯수와 타입에 맞게 매개값을 넣기
  • 형태
// 메소드 호출 클래스 (외부 클래스)

// 객체 생성
필드클래스명 참조변수 = new 필드클래스명();


// 메소드 호출
참조변수.함수명();
참조변수.함수명2(값1, 값2); 
// 인자가 2개이기 때문에 매개값을 2개 넣어주기

참조변수.함수명3();
참조변수.함수명4(값1, 값2);
// 인자가 2개이기 때문에 매개값을 2개 넣어주기

메소드 예제

  • 메소드 선언 클래스 (내부 클래스)
package ch06.sec08.exam01;

public class Calculator {
	
	boolean powered;
	
	//전원을 켰을 때!
	void powerOn() { 
		powered = true;
		System.out.println("전원 on");
	}
	
	// 전원을 껐을 때!
	void powerOff() {
		powered = false;
		System.out.println("전원 off");
	}
	// void 함수 특징 : 리턴 값을 받지 않음
	
	
	// 더하기
	public int plus(int a, int b) {
		// 정수 형태의 두개의 인자를 입력해줘야함
		if(this.powered) {
			// powerOn()이 실행되면
			return a+b;
			// a+b 값을 리턴함
		}
		else {
			// powerOff()가 실행되면
			return 0;
		}
	}
	
	// 빼기
	public int minus(int a, int b) {
		// 정수 형태의 두개의 인자를 입력해줘야함
		if(this.powered) {
			// powerOn()이 실행되면
			return a-b;
			// a-b 값을 리턴함
		}
		else {
			// powerOff()가 실행되면
			return 0;
		}
	}
	
	// 곱셈
	public int multiple(int a, int b) {
		// 정수 형태의 두개의 인자를 입력해줘야함
		if(this.powered) {
			// powerOn()이 실행되면
			return a*b;
			// a*b 값을 리턴함
		}
		else {
			// powerOff()가 실행되면
			return 0;
		}
	}
	
	// 나눗셈
	public double divide (int a, int b) {
		// 정수 형태의 두 개의 인자를 입력해줘야함
		if(this.powered) {
			// powerOn()이 실행되면
			return (double)a/(double)b;
			// a/b 값을 리턴함
			// 본 함수는 실수 형태의 함수이므로 값을 실수형태로 변환해주기
		}
		else {
			// powerOff()이 실행되면
			return 0;
		}
	}
}
  • 메소드 호출 클래스 (외부 클래스)
package ch06.sec08.exam01;

public class CalculatorExam {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Calculator cal = new Calculator();
		// Calculator 객체 생성 (생성자 함수는 없음)
		
		cal.powerOn();
		// void powerOn()에 있는 구문 실행
		// 참조변수.메소드의 형태

		System.out.println(cal.plus(5, 4));
		// plus 메소드 실행 및 5+4=9 값 리턴
		// 인자가 2개인 일반메소드이기 때문에 값을 2개 넣어줘야함
		
		
		System.out.println(cal.minus(5, 4));
		// minus 메소드 실행 및 5-4=1 값 리턴
		
		System.out.println(cal.multiple(5, 4));
		// multiple 메소드 실행 및 5*4=20 값 리턴
		
		System.out.println(cal.divide(5, 4));
		// divide 메소드 실행 및 5/4=1.25 값 리턴
		
		cal.powerOff();
		// void powerOff() 메소드 실행
		
		System.out.println(cal.plus(5, 4));
		// powerOff가 실행되었으므로 결과값은 0
		
		System.out.println(cal.minus(5, 4));
		// powerOff가 실행되었으므로 결과값은 0
		
		System.out.println(cal.multiple(5, 4));
		// powerOff가 실행되었으므로 결과값은 0
		
		System.out.println(cal.divide(5, 4));
		// powerOff가 실행되었으므로 결과값은 0
		
		System.out.println(cal.divide(5, 4));
		// powerOff가 실행되었으므로 결과값은 0.0(실수 형태)
		
	}

}

가변길이 매개변수

  • 메소드가 가변길이 매개변수를 가지고 있다면 매개변수의 개수와 상관없이 매개값을 저장

  • 메소드 호출 시 매개값을 쉼표로 구분해서 개수와 상관없이 제공할 수 있음

  • 매개값들은 자동으로 배열 항목으로 변환되어 메소드에서 사용됨

  • 일종의 배열 형태로 저장됨

  • 형태

// for문
타입 함수명(타입 ... 변수명){
	for(int i=0;i<변수명.length;i++){
    	실행문;
    }
    return 리턴값(또는 변수명);
};

예제

  • 메소드 선언 클래스
package ch06.sec08.exam02;

public class Computer {
	
	int sum(int ... values) {
		// values는 가변길이 매개변수로 배열의 성질을 가짐
		// 함수에 매개변수를 여러개 넣을 수 있음!
		int sum = 0;
		
		for(int i=0;i<values.length;i++) {
			//values가 배열의 성질을 가지게 되어
			//배열 for문처럼 실행해야함
			sum += values[i];
		}
		return sum;
	}

}
  • 메소드 호출 클래스
package ch06.sec08.exam02;

public class ComputerExam {
	public static void main(String[] args) {
		Computer com = new Computer();
		// Computer 객체 선언
		
		System.out.println(com.sum(1,2,3));
		// sum 함수에 매개값을 3개 줌
		
		System.out.println(com.sum(1,2,3,4,5));
		// sum 함수에 매개값을 5개 줌
		
		System.out.println(com.sum(new int[] {1,2,3,4,5}));
		// sum 함수의 매개변수인 values가 배열의 형태이기 때문에
		// 배열을 새로 선언하여 저장할 수도 있음
		
		int[] values = {1,2,3,4,5};
		// sum 함수의 매개변수인 values가 배열의 형태이기 때문에
		// 배열 변수를 직접 넣어 sum 함수에 사용할 수도 있음
		
		System.out.println(com.sum(values));
	}
}

return문

  • 메소드의 실행을 강제 종료하고 호출한 곳으로 돌아간다는 의미
  • 메소드 선언에 리턴 타입이 있을 경우 return문 뒤에 리턴값을 추가로 지정해주기
    -> 값을 가지고 호출한 곳으로 되돌아간다는 뜻
  • return문 이후에 실행문을 작성하면 "Unreachable code"라는 컴파일 오류 발생
  • 내부 클래스 (메소드 선언 클래스)
package ch06.sec08.exam03;

public class Car {
	
	int gas;
	// 멤버변수
	
	void setGas(int g) {
		this.gas = g;
	}
	// 리턴 값을 받지 않기 때문에 void문 사용
	// this 연산자를 사용하여 멤버변수 gas에 값을 대입
	
	boolean isleftGas() {
		// 가스가 부족할 때!
		// boolean 타입의 함수이므로 리턴값은 true/false
		if(gas == 0) {
			// gas가 0이면
			System.out.println("gas가 없습니다");
			return false;
			// false 값을 리턴
		}
		System.out.println("gas가 있습니다");
		// gas가 0이 아닐경우 가스가 있음
		return true;
		// true 값을 리턴
	}
	
	void run() {
		// 자동차가 달린다
		// 동작만을 위한 함수이기 때문에 void 함수 적용
		
		while(true) {
			if(this.gas>0) {
				// gas가 0보다 크면
				System.out.println("달립니다(gas=" + this.gas + ")");
				gas--;
			}
			
			else {
				// gas가 0보다 작거나 같으면
				System.out.println("멈춥니다(gas=" + this.gas + ")");
				return; // 메소드를 종료함
				//return : 메소드를 종료하고 호출한 곳으로 되돌아가기
			}
		}
	}
}
  • 외부 클래스 (메소드 실행 클래스)
package ch06.sec08.exam03;

public class CarExample {
	public static void main(String[] args) {
		Car c = new Car();
		// Car 객체를 생성함 (생성자 메소드는 없음)
		
		c.setGas(5);
		// Car 객체의 .setGas 함수 호출 
		// 인자값이 정수형 하나이므로 숫자 하나만 입력
		
		if(c.isleftGas()) {
			// Car 객체의 .isleftGas 함수 호출
			System.out.println("출발합니다");
			c.run();
			// Car 객체의 .run 함수 호출
			// gas가 0이 될때까지 실행
		}
		
		c.isleftGas();
		// gas = 0이 되어서 false값 호출
		System.out.println("gas를 주입하세요");
	}

}

메소드 오버로딩

  • 메소드 중복 정의를 뜻함
  • 같은 이름의 메소드를 중복적으로 생성은 가능하나 매개변수의 타입, 개수, 순서가 달라야 한다.
  • 내부 클래스
package ch06.sec08.exam04;

public class Calculator {
	double areaRectangle(double width) {
		//정사각형 구하는 함수
		return width * width;
	}
	
	double areaRectangle(double width, double height) {
		//직사각형 구하는 함수
		return width * height;
	}
	
	// 메소드 오버로딩 : 같은 함수명은 사용 가능하나 
	// 매개변수의 타입과 갯수가 달라야함
}
  • 외부 클래스
package ch06.sec08.exam04;

public class CalculatorExam {
	public static void main(String[] args) {
		Calculator cal = new Calculator();
		// Calculator 객체 생성
		
		System.out.println(cal.areaRectangle(10));
		// 매개변수가 1개인 areaRectangle() 함수 호출!
		// 100.0
		
		System.out.println(cal.areaRectangle(10, 5));
		// 매개변수가 2개인 areaRectangle() 함수 호출!
		// 50.0
	}
}

멤버

인스턴스 멤버

  • 필드와 메소드 등 객체에 소속된 멤버 : 객체를 생성해야만 사용할 수 있는 멤버
  • 변수와 함수로 구성됨! (속성과 동작)
  • 일종의 내부클래스 (함수 선언클래스) 에 있는 구문들이라고 생각하면 됨!
  • this 연산자 : 같은 클래스의 멤버변수를 지정하는 연산자로, 내부 클래스에서만 사용하는 연산자
  • 인스턴스 멤버 : 코드(메소드)와 데이터(변수)로 이루어져있음
    -> 데이터(변수)의 경우 공유하지 않고 각각 만들어짐 (new를 통해 객체를 만들어야지만 만들어짐)
    -> 코드(메소드)는 공유하는 성질을 가짐 (공유변수 : 전역변수)
  • 내부 클래스 (메소드 선언 클래스)
package ch06.sec09;

public class Car {
	// 멤버변수
	String model;
	int speed;
	
	// 매개변수가 1개인 일반생성자 (String 타입)
	Car(String m){
		this.model = m;
		// 입력받은 매개변수의 값을 멤버변수 model에 대입
	}
	
	// 매개변수가 1개인 일반메소드 (int 타입)
	void setSpeed(int s) {
		this.speed = s;
		// 입력받은 매개변수의 값을 멤버변수 speed에 대입
	}
	
	void run() {
		// 동작
		this.setSpeed(100);
		// 내부에 생성된 setSpeed 함수를 실행시킴
		// 매개값이 정수 타입이 되어야함
		System.out.println(this.model + "가 달립니다.(시속:" + this.speed + "km/h)");
	}
}
  • 외부 클래스(메소드 실행 클래스)
package ch06.sec09;

public class CarExample {
	public static void main(String[] args) {
		Car c1 = new Car("벤츠");
		// 매개변수가 1개인 일반생성자 객체 선언
		
		Car c2 = new Car("포르쉐");
		// 매개변수가 1개인 일반생성자 객체 선언
		
		// run 함수 호출
		c1.run();
		// 벤츠가 달립니다.(시속:100km/h)
		c2.run();
		// 포르쉐가 달립니다.(시속:100km/h)
	}

}
  • 참조변수.메소드명(); 을 컴파일 돌리면
    -> 클래스명.메소드명(참조변수); 의 형태로 변환됨
  • void 메소드명() 을 컴파일 돌리면
    -> void.메소드명(클래스명 this)의 형태로 변환됨

정적 멤버

  • 정적 멤버란 메소드 영역의 클래스에 고정적으로 위치하는 멤버로 공유 변수를 뜻함!

  • 일반 멤버 메소드 호출시 컴파일러 내부에서는 객체를 전달하는데 이와는 다름!

  • 일반 멤버(인스턴스 멤버)와 정적 멤버를 구분하는 것이 중요!

  • 객체를 직접 생성하지 않고 내부 클래스에 있는 변수를 외부에서 사용할 수 있음!
    -> 객체를 생성해야 사용할 수 있는 인스턴스 멤버와는 차이가 있음!

  • 객체별로 소속이 되는 인스턴스 멤버와는 달리 클래스에 소속되어 있음

  • static
    -> 정적 멤버를 사용하기 위한 용어로 함수나 변수 앞에 선언해주면 됨!
    -> static을 선언해주는 동시에 클래스에 소속이 된 변수나 함수가 됨!
    -> static 변수 또는 함수는 하나만 만들어짐! (중복 불가)
    -> 정수 형태의 정적 변수는 초기값이 0
    -> 일반 멤버함수에는 객체를 생성해야지만 메소드와 변수를 사용할 수 있었지만 static 함수에서는 클래스에 바로 소속이 되있기 때문에 클래스명으로 접근을 꼭 해주기 (변수명으로 해도 되지만 경고뜸)
    -> 정적 멤버 변수/메소드 안에서는 인스턴스 멤버 변수, 메소드로 접근 안되고, this 사용도 불가능! (정적 멤버만 사용 가능함)

  • 내부 클래스에서 정적 멤버의 사용 : static 변수명 / static 함수명()

  • 외부 클래스에서 정적 멤버의 사용 : 클래스명.메소드명(); / 클래스명.변수명;

예제

  • 내부 클래스 (메소드 선언 클래스)
package ch06.sec10.exam01;

public class Calculator {
	static double pi = 3.14159;
	// double 타입의 정적 변수 선언
	
	static int plus(int x, int y) {
		return x+y;
	}
	// 정적 메소드 선언 : 더하기 공식
	
	static int minus(int x, int y) {
		return x-y;
	}
	// 정적 메소드 선언 : 빼기 공식
}
  • 외부 클래스 (메소드 실행 클래스)
package ch06.sec10.exam01;

public class CalculatorExam {
	public static void main(String[] args) {
		System.out.println(10 * 10 * Calculator.pi);
		// Calculator 객체에서 만든 정적 변수 pi를 선언
		// 314.159
		
		System.out.println(Calculator.plus(5, 3));
		// Calculator 객체에서 만든 정적 메소드 plus()를 선언
		// 8
		
		System.out.println(Calculator.minus(5, 3));
		// Calculator 객체에서 만든 정적 메소드 minus()를 선언
		// 2
		
		// 정적 멤버 : 인스턴스 멤버처럼 객체를 선언하지 않고 함수나 변수를 선언 가능한 것
		// 정적 멤버는 소속이 해당 클래스가 되기 때문에
		// 정적 변수나 함수를 불러올 때는 함수나 변수명 앞에 클래스를 붙여준다.
	}
}

정적 블록

  • 정적 필드를 선언할 때 복잡한 초기화 작업이 필요할 때 사용함!

  • 정적 블록은 클래스가 메모리로 로딩될 때 자동으로 실행

  • 정적 블록이 클래스 내부에 여러 개가 선언되어 있을 경우에는 선언된 순서대로 진행

  • 정적 필드는 객체 생성 없이도 사용할 수 있기 때문에 생성자에서 초기화 작업을 하지 않음!

  • 형태

static {
	변수명 = 값;
}

내부 클래스 (메소드 선언 클래스)

package ch06.sec10.exam02;

public class BaseballTeam {
	static String manager = "이숭용";
	// 문자열 타입 변수 manager를 정적 변수로 사용
	
	static String out = "나가";
	// 문자열 타입 변수 out을 정적 변수로 사용
	
	static String landers;
	// 문자열 타입 정적 변수 선언
	
	static {
		landers = manager + "-" + out;
		// 정적 블록을 이용하여 
		// landers라는 정적변수에 값을 조합하여 초기화함
	}
}

외부 클래스 (메소드 실행 클래스)

package ch06.sec10.exam02;

public class ManagerOutExam {
	public static void main(String[] args) {
		System.out.println(BaseballTeam.manager); // 이숭용
		// 정적 변수 manager를 클래스와 함께 선언
		
		System.out.println(BaseballTeam.out); // 나가
		// 정적 변수 out을 클래스와 함께 선언
		
		System.out.println(BaseballTeam.landers); // 이숭용-나가
		// 정적 블록을 통해 만들어진 문자열 landers 출력
		
		
		// ! 이숭용 나가 !
	}
}

정적 멤버와 인스턴스 멤버를 같이 사용하는 법

  • 정적 메소드와 정적 블록은 내부에 인스턴스 필드와 메소드를 사용할 수 없음

  • 정적 메소드와 정적 블록에서 인스턴스 멤버를 사용하고 싶으면 정적 멤버 내부에 객체를 먼저 생성하고 참조 변수로 접근

  • 형태

static void 함수명(){
	클래스명 참조변수 = new 클래스명();
    참조변수.변수 = 값;
    참조변수.함수명();
}

public static void main(String[] args){
	정적함수명();

예제

public class Car {
	// 인스턴스 변수
	int speed;
	
	// 인스턴스 메소드
	void run() {
		System.out.println(speed + "km/h로 달립니다");
	}
	
	// 정적 메소드
	static void simulate() {
		Car c = new Car();
		// Car 객체를 생성하여 인스턴스 멤버 함수와 메소드를 가져옴
		c.speed = 200;
		// 참조변수에 인스턴스 변수 speed를 선언하여 값을 대입
		c.run();
		// 참조변수에 인스턴스 메소드 run()을 선언
	}
	
	public static void main(String[] args) {
		simulate();
		// 정적 메소드 simulate()
		// 같은 클래스 내에 만들어진 메소드이기 때문에 클래스명을 붙이지 않아도 됨
		
		Car c = new Car();
		c.speed = 60;
		c.run();
	}
}

final 필드와 상수

final 필드 선언

  • final 필드는 초기값을 저장하면 그 값이 최종적인 값이 되어서 프로그램 실행 도중에 수정 불가
  • final 필드에 초기값을 주려면 필드 선언 시에 초기값을 대입하거나 생성자에서 초기값을 대입
  • 해당 변수가 값이 변동이 있을지 없을지 판단하고 변동이 없을 가능성이 큰 경우 선언
  • 변수 값을 특별하게 바꿀 일이 없을 경우에는 final을 선언하는 것이 좋음
  • 논리 오류를 구문 오류로 만드는 것이 목적임!
  • 지역변수, 인스턴스 변수, 정적 변수에서 모두 사용 가능!
  • 상수로 만드는게 목적!
  • 내부 클래스 (메소드 선언 클래스)
package ch06.sec11.exam01;

public class Landers {
	final String manager;
	// final : manager라는 필드를 상수값으로 선언
	final String out = "나가";
	// out이라는 필드에 "나가" 라는 값을 주면서 선언과 동시에 초기화!
	// final을 사용함으로서 "나가"라는 값이 부동의 값이 됨
	
	String team = "SSG랜더스";
	// final을 사용하지 않았으므로 변경이 가능한 값
	
	public Landers(String m) {
		// 인자값이 1개인 일반생성자
		this.manager = m;
	}
	// m이라는 매개변수를 입력받아 해당 클래스의 manager 변수에 저장
	// final 필드인 manager에 값을 저장함으로서 해당 값이 부동의 값이됨
}
  • 외부 클래스 (메소드 호출 클래스)
package ch06.sec11.exam01;

public class LandersExample {
	public static void main(String[] args) {
		Landers ssg = new Landers("이숭용");
		// String 타입의 매개값을 가지는 생성자를 호출
		// 해당 매개값은 final 필드에 저장되는 값이므로 불변
		
		System.out.println(ssg.team);
		// SSG랜더스
		System.out.println(ssg.manager);
		// 이숭용
		System.out.println(ssg.out);
		// 나가
		
		// manager와 out은 final 필드에 저장된 값으므로
		// 다른 값으로 변경할 수 없음
//		ssg.manager = "김원형";
//		ssg.out = "종신감독";
		
		ssg.team = "SK와이번스";
		// 하지만 변수 team은 final 필드를 사용하지 않았기 때문에
		// 값을 변경 할 수 있음
		
		System.out.println(ssg.team);
		// SK와이번스
		
	}
}

정적 변수의 final 선언

  • 불변의 값을 저장하는 필드로, 상수의 값을 저장함

  • 하나의 값을 가지면서 변하지 않는 값을 저장할 때 사용함

  • 형태 : static final 타입 상수 = 값(초기값);

  • 내부 클래스

package ch06.sec11.exam02;

public class Earth {
	static final double EARTH_RADIUS = 6400;
	// static final : 하나의 값을 가지며 절대로 변하지 않을 때 사용
	// 지구를 예로 들자면 우주상의 지구는 하나밖에 없고, 지구의 반지름은 변하지 않음
	
	static final double EARTH_SURFACE_AREA;
	// 지구의 표면적
	// 지구의 표면적 또한 변하지 않는 값이기 때문에 static final 사용
	
	static {
		EARTH_SURFACE_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS;
	}
	// 정적 블록을 사용하여 복잡한 초기화식을 따로 저장
	// 표면적 구하는 식
}
  • 외부 클래스
package ch06.sec11.exam02;

public class EarthExample {

	public static void main(String[] args) {
		System.out.println("지구의 반지름= " + Earth.EARTH_RADIUS + "km");
		// 정적 필드를 사용하였기 때문에 앞에 해당 클래스명만 붙여주면 됨
		
		System.out.println("지구의 표면적= " + Earth.EARTH_SURFACE_AREA + "km^2");
		// 정적 필드를 사용하였기 때문에 앞에 해당 클래스명만 붙여주면 됨
		
		// 값 변경 불가능
//		Earth.EARTH_RADIUS = 6500;
//		Earth.EARTH_SURFACE_AREA = 5000;
	}

}
profile
끄작끄작

0개의 댓글