객체의 속성 : 필드
필드란?
📌 필드는 객체의 데이터를 저장하는 역할을 한다.
- 객체의 필드는 크게 고유한 데이터, 상태 데이터, 객체 데이터로 분류할 수 있다.
- 이처럼 자동차 객체는 4개의 고유한 데이터와 3개의 상태 데이터 그리고 3개의 객체 데이터를 가질 수 있다.
- 소프트웨어의 부품을 객체라 표현한다.
- 이 3개의 객체 데이터를 자동차를 만들기 위한 부품 데이터라고 이해해도 좋다.
필드의 초기값과 초기화
📌 우리가 정의하여 선언한 클래스의 필드들은 기본적으로 초기값을 제공하지 않을 경우 객체가 생성될 때 자동으로 기본값으로 초기화된다.
- 초기값을 제공하는 방법은 ‘필드타입 필드명 = 값;’ 이렇게 직접 초기화 할 수 있다.
- String model = "Gv80";
필드 타입별 기본값
필드의 사용 방법
📌 ‘필드를 사용한다’ 라는 의미는 필드의 값을 변경하거나 읽는 것을 의미한다.
- 우리가 클래스에 필드를 정의하여 선언했다고 해서 바로 사용할 수 있는 것은 아니다.
- 클래스는 설계도일 뿐 실제로 필드의 데이터를 가지고 있는 것은 객체이다.
- 따라서 객체를 생성한 후에 필드를 사용할 수 있다.
1. 외부 접근
- Car car = new Car();
- 이렇게 객체를 생성했다면 우리는 참조변수 car를 이용하여 외부에서 객체 내부의 필드에 접근하여 사용할 수 있다.
- 이때 객체의 내부 필드에 접근하는 방법은 도트(.) 연산자를 사용하면 된다.
- car.color = "blue";
2. 내부 접근
- 도트 연산자를 사용하여 외부에서 객체 내부에 접근할 수 있을 뿐만 아니라 객체 내부 메서드에서도 내부 필드에 접근할 수 있다.
double brakePedal() {
speed = 0;
return speed;
}
이처럼 brakePedal() 메서드 내부에서 객체의 필드 speed를 바로 호출해서 사용할 수 있습니다.
5. 객체의 행위 : 메서드
📌 메서드는 객체의 행위를 뜻하며 객체간의 협력을 위해 사용된다.
- 메서드의 행위를 정의하는 방법은 블록{ } 내부에 실행할 행위를 정의하면된다.
메서드 선언
리턴타입 메서드명(매개변수, ...) {
실행할 코드 작성
}
리턴 타입
double brakePedal() {...} // double 타입 반환
char changeGear(char type) {...} // char 타입 반환
boolean onOffLights() {...} // boolean 타입 반환
void horn() {...} // 반환할 값 없음
리턴 타입이란 메서드가 실행된 후 호출을 한 곳으로 값을 반환할 때 해당 값의 타입을 의미.
- return 리턴타입의 반환값;
- 주의할 점은 메서드에 리턴타입을 선언하여 반환할 값이 있다면 반드시 return 문으로 해당하는 리턴타입의 반환값을 지정해야 한다.
반환할 값이 없을떄는 리턴타입에 void를 작성해야 한다.
- 반환값이 없음으로 return문을 반드시 지정할 필요는 없다.
- 메서드는 실행할 때 return문을 만나면 그대로 종료하게 되는데 void 타입일 때 return; 이렇게 return문을 사용하여 원하는 지점에서 메서드를 종료할 수도 있다.
매개 변수
double gasPedal(double kmh, char type) {
speed = kmh;
return speed;
}
매개변수는 메서드를 호출할 때 메서드로 전달하려는 값을 받기 위해 사용되는 변수다.
- 매개변수는 메서드를 호출할 때 메서드로 전달하려는 값을 받기 위해 사용되는 변수입니다.
- 위 gasPedal(double kmh, char type) 메서드의 매개변수는 double 타입의 kmh, char 타입의 type 입니다.
- 해당 매개변수에 값을 전달하기 위해서는 순서와 타입에 맞춰 값을 넣어주면 된다.
- gasPedal(100, 'D');
- 전달하려는 값이 없다면 생략 가능하다.
- 가변길이의 매개변수도 선언할 수 있다.
- double … speeds 이렇게 … 을 사용하면 아래처럼 매개값을 , 로 구분하여 개수 상관없이 전달 가능하다.
- carSpeeds(100, 80);
- carSpeeds(110, 120, 150);
void carSpeeds(double ... speeds) {
for (double v : speeds) {
System.out.println("v = " + v);
}
}
메서드 호출 방법
📌 ‘메서드를 호출한다’ 라는 의미는 메서드의 블록 내부에 작성된 코드를 실행한다는 의미다.
- 필드와 마찬가지로 클래스의 메서드를 정의하여 선언했다고 해서 바로 사용할 수 있는 것은 아니다.
- 클래스는 설계도일 뿐 메서드는 객체의 행위를 정의한 것이다.
- 따라서 객체를 생성한 후에 메서드를 사용할 수 있다.
- 외부 접근
- Car car = new Car();
- 이렇게 객체를 생성했다면 우리는 참조변수 car를 이용하여 외부에서 객체 내부의 메서드에 접근하여 호출할 수 있습니다.
- 이때 객체의 내부 메서드에 접근하는 방법은 도트(.) 연산자를 사용하면 됩니다.
- car.brakePedal();
- 또한 메서드가 매개변수를 가지고 있다면 반드시 호출할 때 매개변수의 순서와 타입에 맞게 매개값을 넣어줘야 합니다.
- car.gasPedal(100, 'D');
- Car car = new Car();
- 내부 접근
- 도트 연산자를 사용하여 외부에서 객체 내부에 접근할 수 있을 뿐만 아니라 객체 내부 메서드에서도 내부 메서드에 접근하여 호출할 수 있습니다.
double gasPedal(double kmh, char type) {
changeGear(type);
speed = kmh;
return speed;
}
//이처럼 gasPedal(double kmh, char type) 메서드 내부에서 해당 객체의 changeGear(type); 메서드를 호출할 수 있습니다.
- 반환 값 저장
- 메서드의 리턴타입을 선언하여 반환할 값이 있다면 변수를 사용하여 받아줄 수 있습니다.
- 반드시 리턴타입과 변수의 타입이 동일하거나 자동 타입 변환될 수 있어야합니다.
- double speed = car.gasPedal(100, 'D');
- double 타입의 변수 speed를 사용하여 double gasPedal(double kmh, char type) 메서드의 double 타입의 반환값을 받아 저장할 수 있습니다.
- 메서드의 리턴타입을 선언하여 반환할 값이 있다면 변수를 사용하여 받아줄 수 있습니다.
예제
자동차 클래스
public class Car {
String company; // 자동차 회사
String model; // 자동차 모델
String color; // 자동차 색상
double price; // 자동차 가격
double speed; // 자동차 속도 , km/h
char gear = 'P'; // 기어의 상태, P,R,N,D
boolean lights; // 자동차 조명의 상태
public Car() {} // 기본 생성자
double gasPedal(double kmh, char type) {
changeGear(type);
speed = kmh;
return speed;
}
double brakePedal() {
speed = 0;
return speed;
}
char changeGear(char type) {
gear = type;
return gear;
}
boolean onOffLights() {
lights = !lights;
return lights;
}
void horn() {
System.out.println("빵빵");
}
void carSpeeds(double ... speeds) {
for (double v : speeds) {
System.out.println("v = " + v);
}
}
}
Main 클래스
public class Main {
public static void main(String[] args) {
Car car = new Car(); // 객체 생성
// 메서드 호출 및 반환값 저장
double speed = car.gasPedal(100, 'D');
System.out.println("speed = " + speed);
boolean lights = car.onOffLights();
System.out.println("lights = " + lights);
System.out.println();
// gasPedal 메서드 내부에 호출된 changeGear(type); 메서드의 결과 확인
// gear의 초기값은 'P'
System.out.println("car.gear = " + car.gear); // 'D' 출력
System.out.println();
// 가변길이 매개변수 확인
car.carSpeeds(100, 80);
System.out.println();
car.carSpeeds(110, 120, 150);
}
}
메서드 오버로딩
📌 오버로딩 은 함수가 하나의 기능만을 구현하는것이 아니라 하나의 메서드 이름으로 여러 기능을 구현하도록 하는 Java의 기능입니다.
즉, 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메서드가 있더라도, 매개변수의 개수 또는 타입, 순서가 다르면 동일한 이름을 사용해서 메서드를 정의할 수 있습니다.
- 오버로딩의 조건
- 메서드의 이름이 같고, 매개변수의 개수, 타입, 순서가 달라야 합니다.
- '응답 값만' 다른 것은 오버로딩을 할 수 없습니다.
- 접근 제어자만 다른 것도 오버로딩을 할 수 없습니다.
- 결론, 오버로딩은 매개변수의 차이로만 구현할 수 있습니다.
- 오버로딩의 장점
- 메서드 이름 하나로 상황에 따른 동작을 개별로 정의할 수 있습니다.
- 예를들면 메세지 출력할때 쓰는 println() 이 있습니다.
- println() 의 매개변수로는 int, double, String, boolean 등 다양하게 넣을 수 있습니다.
- 메서드의 이름을 절약할 수 있습니다.
- 만약 오버로딩이 안된다면 println() 는 printlnInt(), printlnDouble() 처럼 메서드명이 길어지고 낭비 되었을 것 입니다.
- 오버로딩된 println() 확인해보기!
- 메서드 이름 하나로 상황에 따른 동작을 개별로 정의할 수 있습니다.
public class PrintStream extends FilterOutputStream
implements Appendable, Closeable
{
...
public void println() {
newLine();
}
public void println(boolean x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
public void println(char x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
public void println(int x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
public void println(long x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
public void println(float x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
public void println(double x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
public void println(char[] x) {
if (getClass() == PrintStream.class) {
writeln(x);
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
public void println(String x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
public void println(Object x) {
String s = String.valueOf(x);
if (getClass() == PrintStream.class) {
// need to apply String.valueOf again since first invocation
// might return null
writeln(String.valueOf(s));
} else {
synchronized (this) {
print(s);
newLine();
}
}
}
...
}
기본형 & 참조형 매개변수
기본형 매개변수
📌 메서드를 호출할 때 전달할 매개값으로 지정한 값을 메서드의 매개변수에 복사해서 전달합니다.
- 매개변수의 타입이 기본형일 때는 값 자체가 복사되어 넘어가기 때문에 매개값으로 지정된 변수의 원본 값이 변경되지 않습니다.
참조형 매개변수
📌 메서드를 호출할 때 전달할 매개값으로 지정한 값의 주소를 매개변수에 복사해서 전달합니다.
- 매개변수를 참조형으로 선언하면 값이 저장된 곳의 원본 주소를 알 수 있기 때문에 값을 읽어 오는 것은 물론 값을 변경하는 것도 가능합니다.
- 메서드의 매개변수 뿐만 아니라 반환타입도 참조형이 될 수 있습니다.
- 반환타입이 참조형이라는 것은 반환하는 값의 타입이 “실제값의 주소”라는 의미입니다.
'JAVA' 카테고리의 다른 글
[JAVA] 지역변수 및 상수 (0) | 2023.05.31 |
---|---|
[JAVA] 인스턴스 멤버와 클래스 멤버 (0) | 2023.05.31 |
[JAVA] 객체 생성과 참조형 변수 (0) | 2023.05.29 |
[JAVA] 클래스 설계 (0) | 2023.05.29 |
[JAVA] 객체지향 프로그래밍 이해하기 (2) (0) | 2023.05.29 |