티스토리 뷰

주의 사항!

  • 이 글은 제가 직접 공부하는 중에 작성되고 있습니다.
  • 따라서 제가 이해하는 그대로의 내용이 포함됩니다.
  • 따라서 이 글은 사실과는 다른 내용이 포함될 수 있습니다.


클래스에는 객체가 가져야 할 구성 멤버가 선언됩니다. 구성 멤버에는 필드(Field), 생성자(Constructor), 메서드(Method)가 있습니다. 이 구성 멤버들은 생략되거나 복수 개가 작성될 수 있습니다.

public class ClassName
{
	//필드
	int fieldName;

	//생성자
	ClassName() { ... }

	//메서드
	void methodName() { ... }
}

 

1. 필드

필드는 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳입니다. 선언 형태는 변수와 비슷하지만, 필드를 변수라고 부르지는 않습니다. 변수는 생성자와 메서드 내에서만 사용되고 생성자와 메서드가 실행 종료되면 자동 소멸됩니다. 하지만 필드는 생성자와 메서드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재합니다.

 

자동차 객체를 예로 들어 보면 제작회사, 모델명, 색깔, 최고 속도, 마력 등은 고유 데이터에 해당하고, 현재 속도, 엔진 회전 수, 연료량 등은 상태 데이터에 해당합니다. 그리고 차제, 엔진, 타이어, 브레이크, 엑셀 등은 부품에 해당합니다. 따라서 자동차 클래스를 설계할 때 이런 정보들은 필드로 선언되어야 합니다.

 

1.1 필드 선언

필드 선언은 클래스 중괄호 {} 블록 어디서든 존재할 수 있습니다. 생성자 선언과 메서드 선언의 앞과 뒤 어떤 곳에도 선언이 가능합니다. 하지만 생성자와 메서드 중괄호 블록 내부에는 선언될 수 없습니다.

타입 필드 = 초기값;    //필드 선언과 함께 초기화가 된 예

타입 필드;             //필드 선언은 하되 초기화는 하지 않은 예

타입은 필드에 저장할 데이터의 종류를 결정합니다. 타입에는 기본 타입(byte, short, char, int, long, float, double, boolean)과 참조 타입(배열, 클래스, 인터페이스)이 모두 올 수 있습니다. 필드의 초기값은 필드 선언 시 주어질 수도 있고, 생략될 수도 있습니다. 다음은 올바르게 필드를 선언한 예를 보여줍니다.

public class Car
{
	String company = "현대자동차";
	String model = "그랜저";
	int maxSpeed = 300;
	int productionYear;
	int currentSpeed;
	boolean engineStart;
}

초기값이 지정되지 않은 필드들은 객체 생성 시 자동으로 기본 초기값으로 설정됩니다. 정수 타입은 0, 실수 타입은 0.0, boolean 타입은 false가 기본 초기값입니다.

 

1.2 필드 사용

필드를 사용한다는 것은 필드 값을 읽고, 변경하는 작업을 말합니다. 클래스 내부의 생성자나 메서드에서 사용하는 경우 단순히 필드 이름으로 읽고 변경하면 되지만, 클래스 외부에서 사용할 경우 우선적으로 클래스로부터 객체를 생성한 뒤 필드를 사용해야 합니다. 왜냐하면 필드는 객체에 소속된 데이터이므로 객체가 존재하지 않으면 존재할 수 없기 때문입니다.

//Car.java
package chapter00.exam00;

public class Car 
{
	//필드
	String company = "현대자동차";
	String model = "그랜저";
	String color = "검정";
	int maxSpeed = 350;
	int speed;
}
//exam00.java
package chapter00.exam00;

public class exam00 
{
	public static void main(String[] args)
	{
		//객체 생성
		Car myCar = new Car();
		
		//필드값 읽기
		System.out.println("제작 회사 : " + myCar.company);
		System.out.println("모델명 : " + myCar.model);
		System.out.println("색깔 : " + myCar.color);
		System.out.println("최고속도 : " + myCar.maxSpeed);
		System.out.println("현재속도 : " + myCar.speed);
		
		//필드값 변경
		myCar.speed = 60;
		System.out.println("수정된 속도 : " + myCar.speed);
	}
}

/*
실행결과

제작 회사 : 현대자동차
모델명 : 그랜저
색깔 : 검정
최고속도 : 350
현재속도 : 0
수정된 속도 : 60

*/

 

2. 생성자

생성자는 new 연산자로 호출되는 특별한 중괄호 {} 블록입니다. 생성자의 역할은 객체 생성 시 초기화를 담당합니다. 필드를 초기화하거나, 메서드를 호출해서 객체를 사용할 준비를 합니다. 생성자는 메서드와 비슷하게 생겼지만, 클래스 이름으로 되어 있고 반환 타입이 없습니다.

 

2.1 기본 생성자

모든 클래스는 생성자가 반드시 존재하며, 하나 이상을 가질 수 있습니다. 클래스를 선언할 때 생성자 선언을 생략했다면 컴파일러는 다음과 같이 중괄호 {} 블록 내용이 비어있는 기본 생성자를 바이트 코드에 자동 추가합니다.

클래스이름() { }           

public 클래스이름() { }    //클래스가 public으로 선언된 경우

클래스가 public class로 선언되면 기본 생성자에서도 public이 붙지만, 클래스가 public 없이 선언되면 기본 생성자에도 public이 붙지 않습니다.

 

그러나 클래스에 명시적으로 선언한 생성자가 하나라도 있으면, 컴파일러는 기본 생성자를 추가하지 않습니다. 명시적으로 생성자를 선언하는 이유는 객체를 다양하게 초기화하기 위함입니다.

 

2.2 생성자 선언

기본 생성자 대신 생성자를 명시적으로 선언하려면 다음과 같은 형태로 작성하면 됩니다.

클래스이름(매개변수1, 매개변수2,...)
{
	//객체의 초기화 코드
}

생성자 블록 내부에는 객체 초기화 코드가 작성되는데, 일반적으로 필드에 초기값을 저장하거나 메서드를 호출하여 객체 사용 전에 필요한 준비를 합니다. 매개 변수 선언은 생략할 수도 있고, 여러 개를 선언해도 됩니다. 매개 변수는 new 연산자로 생성자를 호출할 때 외부의 값을 생성자 블록 내부로 전달하는 역할을 합니다.

Car myCar = new Car("그랜저", "검정", 300);

위와 같이 객체를 생성할 때, 두 개의 매개 값은 String 타입이고, 마지막 매개 값은 int 타입입니다. 세 매개 값을 생성자가 받기 위해서는 다음과 같이 생성자를 선언해야 합니다.

public class Car
{
	Car(String model, String color, int maxSpeed) { ... }
}

 

2.3 필드 초기화

클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동 설정됩니다. 만약 다른 값으로 초기화를 하고 싶다면 두 가지 방법이 있습니다. 하나는 필드를 선언할 때 초기값을 주는 방법이고, 또 다른 하나는 생성자에서 초기값을 주는 방법입니다.

 

필드를 선언할 때 초기값을 주게 되면 동일한 클래스로부터 생성되는 객체들은 모두 같은 데이터를 갖게 됩니다. 물론 객체 생성 후 변경할 수 있지만, 객체 생성 시점에는 필드의 값이 모두 같게 됩니다. 하지만 객체 생성 시점에 외부에서 제공되는 다양한 값들로 초기화되어야 한다면 생성자의 매개 값으로 이 값들을 받아 초기화를 해야 합니다.

//Korean.java
package chapter00.exam00;

public class Korean 
{
	//필드
	String nation = "대한민국";
	String name;
	String ssn;    //주민등록번호
	
	//생성자
	public Korean(String name, String ssn)
	{
		this.name = name;
		this.ssn = ssn;
	}
}
//exam00.java
package chapter00.exam00;

public class exam00 
{
	public static void main(String[] args)
	{
		Korean k1 = new Korean("박자바", "124578 - 8456321");
		System.out.println("k1.name : " + k1.name);
		System.out.println("k1.ssn : " + k1.ssn);
		
		Korean k2 = new Korean("KOEY", "658741 - 1874632");
		System.out.println("k2.name : " + k2.name);
		System.out.println("k2.ssn : " + k2.ssn);
	}
}

/*
실행결과

k1.name : 박자바
k1.ssn : 124578 - 8456321
k2.name : KOEY
k2.ssn : 658741 - 1874632

*/

 

2.4 생성자 오버 로딩

외부에서 제공되는 다양항 데이터들을 이용해서 객체를 초기화하려면 생성자도 다양화될 필요가 있습니다. Car 객체를 생성할 때 외부에서 제공되는 데이터가 없다면 기본 생성자로 Car 객체를 생성해야 하고, 외부에서 model 데이터가 제공되거나 model과 color가 제공될 경우에도 Car 객체를 생성할 수 있어야 합니다. 그런데 생성자가 하나뿐이라면 이런 요구 조건을 충족할 수 없습니다.

 

그래서 자바는 다양한 방법으로 객체를 생성할 수 있도록 생성자 오버 로딩을 제공합니다. 생성자 오버 로딩이란 매개 변수를 달리하는 생성자를 여러 개 선언하는 것을 말합니다.

 

다음은 Car 클래스에서 생성자를 오버 로딩한 예입니다.

public class Car 
{
	Car() { ... }
	Car(String model) { ... }
	Car(String model, String color) { ... }
	Car(String model, String color, int maxSpeed) { ... }
}

생성자 오버 로딩 시 주의할 점은 매개 변수의 타입과 개수 그리고 선언된 순서가 똑같을 경우 매개 변수 이름만 바꾸는 것은 생성자 오버 로딩이라고 볼 수 없는 것입니다. 다음의 경우가 이에 해당됩니다.

Car(String model, String color) { ... }
Car(String color, String model) { ... }    //오버로딩이 아님

생성자가 오버 로딩되어 있을 경우, new 연산자로 생성자를 호출할 때 제공되는 매개 값의 타입과 수에 의해서 호출될 생성자가 결정됩니다. 다음은 다양한 방법으로 Car 객체를 생성하는 예입니다.

Car car1 = new Car();
Car car2 = new Car("그랜저");
Car car3 = new Car("그랜저", "흰색");
Car car4 = new Car("그랜저", "흰색", 300);

 

2.5 다른 생성자 호출

생성자 오버 로딩이 많아질 경우 생성자 간의 중복된 코드가 발생할 수 있습니다. 매개 변수의 수만 달리하고 필드 초기화 내용이 비슷한 생성자에서 이러한 현상을 많이 볼 수 있습니다. 이 경우에는 필드 초기화 내용은 한 생성자에만 집중적으로 작성하고 나머지 생성자는 초기화 내용을 가지고 있는 생성자를 호출하는 방법으로 개선할 수 있습니다.

 

생성자에서 다른 생성자를 호출할 때에는 다음과 같이 this() 코드를 사용합니다.

클래스이름(매개변수1, 매개변수2, ...)
{
	this(매개변수1, 매개변수2, ..., 값1, 값2, ...);    //클래스의 다른 생성자 호출
	실행문;
}

this()는 자신의 다른 생성자를 호출하는 코드로, 반드시 생성자의 첫 줄에서만 허용됩니다. this()의 매개 값은 호출되는 생성자의 매개 변수 타입에 맞게 제공해야 합니다. this() 다음에는 추가적인 실행문이 올 수 있습니다.

 

만약 다음과 같이 생성자가 오버 로딩되어 있을 때,

Car(String model)
{
	this model = model;
	this.color = "은색";
	this.maxSpeed = 250;
}

Car(String model, String color)
{
	this model = model;
	this.color = color;
	this.maxSpeed = 250;
}

Car(String model, String color, int maxSpeed)
{
	this model = model;
	this.color = color;
	this.maxSpeed = maxSpeed;
}

세 개의 생성자 내용이 비슷하므로 앞에 두 개의 생성자에서 this()를 사용해서 마지막 생성자인 Car(String model, String color, int maxSpeed)를 호출하도록 수정하면 중복 코드를 최소화할 수 있습니다.

//Car.java
package chapter00.exam00;

public class Car 
{
	//필드
	String company = "현대자동차";
	String model;
	String color;
	int maxSpeed;
	
	//생성자
	Car() {}
	
	Car(String model)
	{
		this(model, "은색", 250);
	}
	
	Car(String model, String color)
	{
		this(model, color, 250);
	}
	
	Car(String model, String color, int maxSpeed)
	{
		this.model = model;
		this.color = color;
		this.maxSpeed = maxSpeed;
	}
}
//exam00.java
package chapter00.exam00;

public class exam00 
{
	public static void main(String[] args)
	{
		Car car1 = new Car();
		System.out.println("car1.company : " + car1.company);
		System.out.println();
		
		Car car2 = new Car("자가용");
		System.out.println("car2.company : " + car2.company);
		System.out.println("car2.model : " + car2.model);
		System.out.println();
		
		Car car3 = new Car("자가용", "빨강");
		System.out.println("car3.company : " + car3.company);
		System.out.println("car3.model : " + car3.model);
		System.out.println("car3.color : " + car3.color);
		System.out.println();
		
		Car car4 = new Car("택시", "노랑", 200);
		System.out.println("car4.company : " + car4.company);
		System.out.println("car4.model : " + car4.model);
		System.out.println("car4.color : " + car4.color);
		System.out.println("car4.maxSpeed : " + car4.maxSpeed);
	}
}

/*
실행결과

car1.company : 현대자동차

car2.company : 현대자동차
car2.model : 자가용

car3.company : 현대자동차
car3.model : 자가용
car3.color : 빨강

car4.company : 현대자동차
car4.model : 택시
car4.color : 노랑
car4.maxSpeed : 200

*/

 

3. 메서드

메서드는 객체의 동작에 해당하는 중괄호 {} 블록을 말합니다. 중괄호 블록은 이름을 가지고 있는데, 이것이 메서드 이름입니다. 메서드는 필드를 읽고 수정하는 역할도 하지만, 다른 객체를 생성해서 다양한 기능을 수행하기도 합니다. 메서드는 객체 간의 데이터 전달의 수단으로 사용됩니다. 외부로부터 매개 값을 받을 수 있고, 실행 후 어떤 값을 반환할 수도 있습니다.

 

3.1 메서드 선언

메서드 선언은 선언부(반환 타입, 메서드 이름, 매개 변수 선언)와 실행 블록으로 구성됩니다. 메서드 선언부를 메서드 시그니처(signature)라고도 합니다.

 

반환 타입

반환 타입은 메서드가 실행 후 반환하는 값의 타입을 말합니다. 메서드가 실행 후 결과를 호출한 곳에 넘겨줄 경우에는 반환 값이 있어야 합니다. 만약 전자계산기 객체에서 전원을 켜는 powerOn() 메서드와 두 수를 나누는 기능인 divide() 메서드가 있다고 가정해 보겠습니다. divide() 메서드는 나눗셈의 결과를 반환해야 하지만 powerOn() 메서드는 전원만 켜면 그만입니다. 따라서 powerOn() 메서드는 반환 값이 없습니다. 이처럼 반환 값이 없는 메서드는 반환 타입에 void가 와야 하며 반환 값이 있는 메서드는 반환 값의 타입이 와야 합니다. divide() 메서드의 반환 값이 doubld 값이라면 double 타입을 반환 타입으로 해야 합니다.

 

반환 값이 있느냐 없느냐에 따라 메서드를 호출하는 방법이 조금 다릅니다.

powerOn();
double result = divide(12, 4);

반환 값이 있는 divide() 메서드를 호출할 때, 이 메서드가 반환하는 값을 받기 위해서 반환 타입과 같은 타입의 변수가 필요합니다. 물론 divide() 메서드의 반환 값이 굳이 필요 없을 때는 다음과 같이 변수를 이용해 반환 값을 받지 않아도 됩니다.

divide(12, 4);

 

매개 변수 선언

매개 변수는 메서드가 실행할 때 필요한 데이터를 외부로부터 받기 위해 사용됩니다. 매개 변수도 필요한 경우가 있고 필요 없는 경우가 있습니다. 예를 들어 powerOn() 메서드는 그냥 전원만 켜면 그만이지만, divide() 메서드는 나눗셈할 두 수가 필요합니다.

 

다음은 매개 변수가 있는 divide() 메서드의 선언 예입니다.

double divide(int x, int y) { ... }
double divide(double x, double y) { ... }

 

매개 변수의 개수를 모를 경우

메서드의 매개 변수는 개수가 이미 정해져 있는 것이 일반적이지만, 경우에 따라서는 메서드를 선언할 때 매개 변수의 개수를 알 수 없는 경우가 있습니다. 예를 들어 여러 개의 수를 모두 합산하는 메서드를 선언해야 한다면, 몇 개의 매개 변수가 입력될지 알 수 없기 때문에 매개 변수의 개수를 결정할 수 없을 것입니다. 이런 문제는 다음과 같이 매개 변수를 배열 타입으로 선언함으로써 해결할 수 있습니다.

int sum1(int[] values) { ... }

sum1() 메서드를 호출할 때 배열을 넘겨줌으로써 배열의 항목 값들을 모두 전달할 수 있습니다.

int[] values = {1, 2, 3};
int result = sum1(values);
int result = sum1(new int[] {1, 2, 3, 4, 5});

그런데 매개 변수를 배열 타입으로 선언하면 메서드를 호출하기 전에 배열을 생성해야 하는 불편함이 있습니다. 그래서 배열을 생성하지 않고 값의 리스트만 넘겨주는 방법도 있습니다. 다음과 같이 sum2() 메서드의 매개 변수를 "..."을 사용해서 선언하게 되면, 메서드 호출 시 넘겨준 값의 수에 따라 자동으로 배열이 생성되고 매개 값으로 사용됩니다.

int sum2(int ... values) { ... }

"..."로 선언된 매개 변수의 값은 다음과 같이 메서드 호출 시 리스트로 나열해주면 됩니다.

int result = sum2(1, 2, 3);
int result = sum2(1, 2, 3, 4, 5);

"..."로 선언된 매개 변수는 배열 타입이므로 다음과 같이 배열을 직접 매개 값으로 사용해도 됩니다.

int[] values = { 1, 2, 3 };
int result = sum2(values);
int result = sum2(new int[] { 1, 2, 3, 4, 5 });
//Computer.java
package chapter00.exam00;

public class Computer 
{
	int sum1(int[] values)
	{
		int sum = 0;
		for(int value : values)
		{
			sum += value;
		}
		return sum;
	}
	
	int sum2(int ... values)
	{
		int sum = 0;
		for(int value : values)
		{
			sum += value;
		}
		return sum;
	}
}
//exam00.java
package chapter00.exam00;

public class exam00 
{
	public static void main(String[] args)
	{
		Computer myCom = new Computer();
		
		int[] values1 = { 1, 2, 3 };
		int result1 = myCom.sum1(values1);
		System.out.println("result1 = " + result1);
		
		int result2 = myCom.sum1(new int[] { 1, 2, 3, 4, 5 });
		System.out.println("result2 = " + result2);
		
		int result3 = myCom.sum2(1, 2, 3);
		System.out.println("result3 = " + result3);
		
		int result4 = myCom.sum2(1, 2, 3, 4, 5);
		System.out.println("result4 = " + result4);
	}
}

/*
실행결과

result1 = 6
result2 = 15
result3 = 6
result4 = 15

*/

 

3.2 return문

메서드 선언에 반환 타입이 있는 메서드는 반드시 return문을 사용해서 반환 값을 지정해야 합니다. 만약 return문이 없다면 컴파일 오류가 발생합니다. return문이 실행되면 메서드는 즉시 종료됩니다.

 

return문의 반환 값은 반환 타입이거나 반환 타입으로 변환될 수 있어야 합니다. 예를 들어 반환 타입이 int인 plus() 메서드에서 byte, short, int 타입의 값이 반환되어도 상관없습니다. 

 

반환 타입이 void로 선언된 반환 값이 없는 메서드에서도 return문을 사용할 수는 있습니다. 하지만 return문 뒤에 반환 값을 지정할 수는 없습니다. 다음과 같이 return문을 사용하면 메서드의 실행을 바로 종료시킵니다.

return;

 

3.3 메서드 호출

메서드는 클래스 내부, 외부의 호출에 의해 실행됩니다. 클래스 내부의 다른 메서드에서 호출할 경우에는 단순한 메서드 이름으로 호출하면 되지만, 클래스 외부에서 호출할 경우에는 우선 클래스로부터 객체를 생성한 뒤, 참조 변수를 이용해서 메서드를 호출해야 합니다. 그 이유는 객체가 존재해야 메서드도 존재하기 때문입니다.

 

객체 내부에서 호출

예를 들어 클래스 내부의 method2() 메서드에서 method1() 메서드를 호출할 경우에는 다음과 같이 작성하면 됩니다.

public class ClassName
{
	void method1(String p1, int p2)
	{
		//실행문
	}

	void method2()
	{
		method1("홍길동", 24);
	}
}

 

객체 외부에서 호출

외부 클래스에서 메서드를 호출하려면 우선 클래스로부터 객체를 생성해야 합니다. 객체가 생성되었다면 참조 변수와 함께 도트(.) 연산자를 사용해서 메서드를 호출할 수 있습니다. 도트(.) 연산자는 객체 접근 연산자로 객체가 가지고 있는 필드나, 메서드에 접근할 때 사용됩니다.

 

다음은 Car 객체의 keyTurnOn() 메서드와 run() 메서드를 호출하는 코드입니다.

Car myCar = new Car();
myCar.keyTurnOn();
myCar.run();

int speed = myCar.GetSpeed();

keyTurnOn() 메서드와 run() 메서드는 반환 값이 없기 때문에 단순 호출만 했고, getSpeed() 메서드는 반환 값이 있으므로 반환 값을 받아 변수 speed에 저장합니다.

//Car.java
package chapter00.exam00;

public class Car 
{
	//필드
	int speed;
	
	//메서드
	int getSpeed()
	{
		return speed;
	}
	
	void keyTurnOn()
	{
		System.out.println("키를 돌립니다.");
	}
	
	void run()
	{
		for(int i = 10; i <= 50; i += 10)
		{
			speed = i;
			System.out.println("달립니다. (시속 : " + speed + "km/h)");
		}
	}
}
//exam00.java
package chapter00.exam00;

public class exam00 
{
	public static void main(String[] args)
	{
		Car myCar = new Car();
		
		myCar.keyTurnOn();
		myCar.run();
		int speed = myCar.getSpeed();
		
		System.out.println("현재 속도 : " + speed + "km/h");
	}
}

/*
실행결과

키를 돌립니다.
달립니다. (시속 : 10km/h)
달립니다. (시속 : 20km/h)
달립니다. (시속 : 30km/h)
달립니다. (시속 : 40km/h)
달립니다. (시속 : 50km/h)
현재 속도 : 50km/h

*/

 

3.4 메서드 오버 로딩

클래스 내에 같은 이름의 메서드를 여러 개 선언하는 것을 메서드 오버 로딩이라고 합니다. 메서드 오버 로딩이 가능하려면 매개 변수의 타입, 개수, 순서 중 적어도 하나가 달라져야 합니다.

 

예를 들어 다음과 같이 plus() 메서드가 있다고 가정해 보겠습니다.

int plus(int x, int y)
{
	int result = x + y;

	return result;
}

plus() 메서드를 호출하기 위해서는 두 개의 int 매개 값이 필요합니다 하지만 int 타입이 아니라 double 타입의 값을 덧셈하기 위해서는 plus() 메서드를 호출할 수 없습니다. 해결 방법은 매개 변수가 double 타입으로 선언된 plus() 메서드를 하나 더 선언하는 것입니다.

int plus(int x, int y)
{
	int result = x + y;

	return result;
}

double plus(double x, double y)
{
	double result = x + y;

	return result;
}

오버 로딩된 메서드를 호출할 경우 JVM은 매개 값의 타입을 보고 메서드를 선택합니다. 예를 들어 다음과 같이 plus() 메서드를 호출하면,

plus(10, 20);

plus(int x, int y)가 실행됩니다. 그리고 다음과 같이 plus() 메서드를 호출하면,

plus(10.5, 20.3);

plus(double x, double y)가 실행됩니다. 그렇다면 다음과 같이 plus() 메서드를 호출하면 어떻게 될까요?

plus(10, 20.3);

첫 번째 매개 값은 int 타입이고, 두 번째 매개 값은 double 타입입니다. 하지만 현재 선언되어 있는 plus() 메서드 중에는 이렇게 매개 변수 타입이 선언된 메서드가 없습니다. 하지만 위 메서드 호출은 오류를 발생시키지 않고, plus(double x, double y) 메서드를 호출합니다. 위와 같이 매개 변수의 타입이 맞지 않을 때는 자동 타입 변환이 가능한지를 검토합니다. int 타입은 double 타입으로 자동 타입 변환이 가능하기 때문에 plus(double x, double y) 메서드를 호출할 수 있습니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함