JAVA_#3_1
클래스와 객체
클래스 | 객체 |
제품 설계도 | 제품 |
TV 설계도 | TV |
붕어빵 기계 | 붕어빵 |
클래스의 정의 : 객체를 정의해 놓은 것
클래스의 용도 : 객체를 생성하는데 사용
객체의 정의 : 실제로 존재하는 것!, 사물 또는 개념
객체의 용도 : 객체가 가지고 있는 속성과 기능에 따라 다름
객체와 인스턴스 용어 정리
- 객체 : 모든 인스턴스를 대표하는 일반적인 용어 (Tv 객체)
- 인스턴스 : 특정 클래스로부터 생성된 객체 (Tv 클래스를 사용해서 만든 Tv인스턴스)
- 인스턴스화 : 클래스 => 인스턴스(객체)
객체 구성요소
객체 = 속성(변수) + 기능(메서드)
객체의 생성과 배열
객체의 생성
클래스명 변수명;
- 클래스의 객체를 참조하기 위한 참조변수를 선언
변수명 = new 클래스명;
- 생성된 객체의 주소를 참조변수에 저장
객체 생성 방법
- Tv t;
Tv 클래스 타입의 참조변수 t를 선언
- t = new Tv();
Tv인스턴스를 생성한 후
생성된 Tv인스턴스의 주소를 t에 저장
객체의 사용
TV클래스
속성
색깔
전원상태
채널
기능
파워(전원)
채널 증가
채널 감소
TV1 인스턴스1
속성
색깔 : 검정색
전원상태 : false
채널 : 1
기능
파워(전원)
채널 증가
채널 감소
TV1 인스턴스2
속성
색깔 : 흰색
전원상태 : false
채널 : 1
기능
파워(전원)
채널 증가
채널 감소
class Tv1_1 {
// 속성 : 변수 선언
String color; // 색깔
boolean power = false; // 전원상태 : false 로 초기화
int channel = 1; // 채널 : 1 로 초기화
// 기능 : 메서드 선언
void power() { // 전원 기능
power = !power;
if (power) {
System.out.println("전원 ON");
} else {
System.out.println("전원 OFF");
}
}
void channelUp() { // 채널 증가
channel++;
System.out.println("채널 증가");
}
void channelDown() { // 채널 감소
channel--;
System.out.println("채널 감소");
}
}
class Tv1_1Main {
public static void main(String[] args) {
Tv1_1 t1 = new Tv1_1(); // TV1 인스턴스
t1.color = "검정색"; // 색깔 초기화
Tv1_1 t2 = new Tv1_1(); // TV2 인스턴스
t2.color = "흰색"; // 색깔 초기화
System.out.println("TV1 인스턴스 색깔 = " + t1.color);
System.out.println("TV2 인스턴스 색깔 = " + t2.color);
t1.power(); // 메서드 호출
System.out.println("TV1 인스턴스 채널 = " + t1.channel);
t1.channelUp(); // 메서드 호출
System.out.println("TV1 인스턴스 채널 : " + t1.channel);
t1.channelDown(); // 메서드 호출
System.out.println("TV1 인스턴스 채널 : " + t1.channel);
t1.power(); // 메서드 호출
// TV2 인스턴스 참조변수에 TV1 인스턴스의 주소 저장 했을 때
t2 = t1;
System.out.println("TV1 인스턴스 색깔 = " + t1.color); // 검정색
System.out.println("TV2 인스턴스 색깔 = " + t2.color); // 검정색
// 흰색이었던 TV2 인스턴스 의 색깔이 검정색으로 바뀐건가요?
// 아닙니다.
// 참조변수 t2 에 저장되어있던 TV2 인스턴스 의 주소가 없어지고
// TV1 의 주소가 t2 참조변수에 저장이 됩니다
// 따라서 t2 = t1; 이후 부터는
// t2 참조변수로는 더 이상 TV2 인스턴스 에 접근할 수 없습니다.
}
}
}
객체 배열
객체 배열 == 참조변수 배열
- Tv[] tvArr = new Tv[3];
여러 개의 객체를 담을 수 있는 배열
class Tv1_2 {
// 속성 : 변수 선언
String color; // 색깔
boolean power = false; // 전원상태 : false 로 초기화
int channel = 1; // 채널 : 1 로 초기화
// 브랜드 이름 속성 추가
String brand;
// 기능 : 메서드 선언
void power() { // 전원 기능
power = !power;
if (power) {
System.out.println("전원 ON");
} else {
System.out.println("전원 OFF");
}
}
void channelUp() { // 채널 증가
channel++;
System.out.println("채널 증가");
}
void channelDown() { // 채널 감소
channel--;
System.out.println("채널 감소");
}
}
class Tv1_2Main {
public static void main(String[] args) {
Tv1_2[] tvArr = new Tv1_2[3];
tvArr[0] = new Tv1_2();
tvArr[1] = new Tv1_2();
tvArr[2] = new Tv1_2();
tvArr[0].color = "보라색";
tvArr[1].color = "주황색";
tvArr[2].color = "핑크색";
for (int i = 0; i < tvArr.length; i++) {
System.out.println(i + 1 + "번째 Tv인스턴스 색깔: " + tvArr[i].color);
}
for (int i = 0; i < tvArr.length; i++) {
System.out.print(i + 1 + "번째 Tv인스턴스 " );
tvArr[i].power();
}
System.out.println();
// 브랜드명 추가 전 확인
for (int i = 0; i < tvArr.length; i++) {
System.out.print(i + 1 + "번째 Tv인스턴스의 브랜드 명: " );
System.out.println(tvArr[i].brand);
}
System.out.println();
// 새로운 참조변수에 배열 안에 들어있는 객체 주소 값 배정
Tv1_2 samsung = tvArr[0];
Tv1_2 lg = tvArr[1];
Tv1_2 apple = tvArr[2];
// 참조변수를 사용해서 배열안에 넣어준 객체에 접근해서 각 인스턴스에 브랜드 이름 추가하기
samsung.brand = "samsung";
lg.brand = "lg";
apple.brand = "apple";
for (int i = 0; i < tvArr.length; i++) {
System.out.print(i + 1 + "번째 Tv인스턴스의 브랜드 명: " );
System.out.println(tvArr[i].brand);
}
}
}
클래스의 정의
클래스 == 데이터 + 함수
클래스의 탄생 과정
1. 변수 : 하나의 데이터를 저장할 수 있는 공간
2. 배열 : 같은 종류의 여러 데이터를 하나로 저장할 수 있는 공간
3. 구조체 : 서로 연관된 여러 데이터(종류 관계 X)를 하나로 저장할 수 있는 공간
4. 클래스 : 데이터와 함수의 결합(구조체 + 함수)
클래스 == 사용자 정의 타입
원하는 타입을 직접 만들 수 있습니다.
시간을 다루는 타입을 직접 만들고 싶다면?
- 기본형 8개가 아닌 새로운 타입인 시간 클래스를 작성한다.
사용자 3명의 시간을 기록하려고 한다.
- 클래스 사용을 하지 않고 관리해 보기!
class NoneClassTime {
public static void main(String[] args) {
// 총 3명 의 시간을 변수로 관리
int hour1, hour2, hour3;
int minute1, minute2, minute3;
int second1, second2, second3;
// 총 3명 의 시간을 배열로 관리
int[] hour = new int[3];
int[] minute = new int[3];
int[] second = new int[3];
}
}
- 클래스로 만들어서 관리해 보기!
class Time3_1 {
int hour;
int minute;
int second;
}
class Time3_1Main {
public static void main(String[] args) {
// 총 3명 의 시간을 객체로 관리
Time3_1 t1 = new Time3_1();
Time3_1 t2 = new Time3_1();
Time3_1 t3 = new Time3_1();
// 총 3명 의 시간을 객체 배열로 관리
Time3_1[] timeArr = new Time3_1[3];
timeArr[0] = new Time3_1();
timeArr[1] = new Time3_1();
timeArr[2] = new Time3_1();
}
}
변수의 종류
선언 위치에 따른 변수의 종류
변수의 종류 | 선언위치 | 생성시기 |
클래스변수 | 클래스 영역 | 클래스가 메모리에 올라갈 때 |
인스턴스변수 | 인스턴스 생성시 | |
지역변수 | 메서드 영역 | 변수 선언문 수행시 |
클래스 영역 : 클래스 변수
- 클래스가 메모리에 올라갈 때 생성됩니다.
- 객체 생성을 하지 않아도 생성되고 언제든지 사용 가능합니다.
- 접근 방법 : 클래스명.클래스 변수명
클래스 영역 : 인스턴스 변수
- 객체가 생성될 때 인스턴스 변수가 생성됩니다.
- 접근 방법 : 참조변수명.인스턴스변수명
메서드 영역 : 지역 변수
- 메서드가 호출 돼서 실행될 때 생성됩니다.
- 메서드가 종료되면 자동으로 제거됩니다.
class Obj4_1 {
int iv; // 인스턴스 변수
static int cv; // 클래스 변수(static 변수, 공유 변수)
void method() {
int lv;
lv = 30;
// 지역변수는 자동으로 초기화가 되지 않기 때문에 사용하려면 반드시 초기화 필요
System.out.println("lv 지역 변수 = " + lv);
}
}
class Obj4_1Main {
public static void main(String[] args) {
// 클래스 변수 접근 및 사용
// 접근방법 : 클래스명.클래스변수이름
Obj4_1.cv = 10;
System.out.println("ObjVar.cv 클래스 변수 = " + Obj4_1.cv);
// 인스턴스 변수 생성 및 사용
// Obj4_1.iv = 20; // Error, 인스턴스를 통해서만 생성 및 사용 가능
Obj4_1 objVar = new Obj4_1();
objVar.iv = 20;
System.out.println("objVar.iv 인스턴스 변수 = " + objVar.iv);
// 지역 변수 생성 및 사용
// objVar.lv // Error, 인스턴스로 지역 변수 바로 접근 불가능
objVar.method(); // 메서드 호출 시 지역 변수 생성
// 메서드 종료시 지역 변수 삭제
}
}
인스턴스 변수 : iv
공통 변수 : cv => static 부여 class이름.속성 으로 입력해 iv와 혼동갖지 않도록 한다.
공통된 데이터를 따로 저장하게 되면 낭비이기 때문에 공통 변수로 저장해 효율적으로 사용한다.
메서드
반환타입 메서드이름(타입 변수명, 타입 변수명, ...) // (선언부){
//메서드가 호출되면 수행할 코드(구현부)
}
메서드의 장점과 작성
장점
- 중복 코드 제거
- 관리 용이
- 재사용 가능
작성
- 반복적으로 수행되는 여러 문장을 메서드로 작성합니다.
- 하나의 메서드는 한 가지 기능만 수행하도록 작성하는 것이 좋습니다.
함수
값을 입력 받아서 처리하고, 결과를 반환합니다.
int add(int x, int y){
=> int(반환타입) add(메서드 이름) int x, int y(매개변수(입력))
int result = x + y; => 처리
return result; => 결과를 반환
}
void(반환타입) : 메서드 수행 시 아무것도 반환하지 않을 때 사용합니다.
메서드 호출
메서드이름(값1, 값2, ...)
class Method5_1 {
int add(int x, int y) {
int result = x + y;
return result; // 값을 반환
}
}
class Method5_1Main {
public static void main(String[] args) {
Method5_1 method = new Method5_1(); // Method5_1 클래스에 만든 메서드 add 를 사용하기 위해 객체 생성
int result = method.add(3, 5); // add 메서드를 사용해서 입력한 값(3,5)으로 처리된 값을 반환받아 result 변수에 저장
System.out.println("result = " + result);
}
}
return
실행 중인 메서드를 종료하고 호출한 곳으로 되돌아갑니다.
- 반환타입이 void가 아닌 경우, 반드시 return 문이 필요합니다.
- void 는 컴파일러가 자동으로 메서드 마지막에 return; 을 추가해 줍니다.
class Method5_2 {
void gugudan(int dan) {
for (int i = 1; i <= 9; i++) {
if (!(dan >= 2 && dan <= 9)) {
System.out.println(dan + "단은 없습니다.");
System.out.println();
return;
}
}
System.out.println(dan + "단 시작!");
for (int i = 1; i < 10; i++) {
System.out.println(dan + "*" + i + " = " + dan * i);
}
System.out.println();
}
boolean checkMax(int x, int y) {
if (x > y) {
return true;
} else {
return false;
// return 반드시 필요합니다. 만약 없으면 조건문이 false 일 경우, void 가 아닌데 return 문이 없음으로 Error
}
}
}
class Method5_2Main {
public static void main(String[] args) {
Method5_2 method = new Method5_2();
method.gugudan(2);
method.gugudan(5);
method.gugudan(10);
method.gugudan(9);
System.out.println("method.checkMax(10, 8) = " + method.checkMax(10, 8));
System.out.println("method.checkMax(5, 9) = " + method.checkMax(5, 9));
}
}
문장들의 묶음
코드의 중복을 하나의 묶음으로 만들어 코드의 가독성 및 효율을 높여줍니다.
class Method5_3 {
static void initObj(Time5_1 time, int hour, int minute, int second) {
time.hour = hour;
time.minute = minute;
time.second = second;
}
}
class Method5_3Main {
public static void main(String[] args) {
Time5_1 t1 = new Time5_1();
t1.hour = 100;
t1.minute = 20;
t1.second = 43;
Time5_1 t2 = new Time5_1();
t2.hour = 22;
t2.minute = 30;
t2.second = 23;
Time5_1 t3 = new Time5_1();
t3.hour = 45;
t3.minute = 40;
t3.second = 52;
System.out.println("t1.hour = " + t1.hour);
System.out.println("t2.hour = " + t2.hour);
System.out.println("t3.hour = " + t3.hour);
System.out.println();
// 하나하나 인스턴스를 만들고 위처럼 인스턴스 변수를 초기화 하려니 매우 귀찮지 않나요?
// 물론 '생성자' 라는 개념이 뒤에 나오지만 일단은 메서드를 사용하여 코드의 수를 확 줄여 보겠습니다.
Time5_1 t4 = new Time5_1();
Time5_1 t5 = new Time5_1();
Time5_1 t6 = new Time5_1();
Method5_3.initObj(t4, 100, 20, 43);
Method5_3.initObj(t5, 22, 30, 23);
Method5_3.initObj(t6, 45, 40, 52);
System.out.println("t4.hour = " + t4.hour);
System.out.println("t5.hour = " + t5.hour);
System.out.println("t6.hour = " + t6.hour);
// 이처럼 메서드를 사용하니 코드의 수가 굉장히 많이 줄어 가독성이 좋아졌습니다.
}
}
호출 스택(call stack)
메서드 수행에 필요한 메모리가 제공되는 공간
메서드가 호출되면 호출 스택에 메모리가 할당, 종료되면 해제됩니다.
class CallStack5_1 {
static void firstMethod() {
System.out.println("firstMethod()");
secondMethod();
}
static void secondMethod() {
System.out.println("secondMethod()");
thirdMethod();
}
static void thirdMethod() {
System.out.println("thirdMethod()");
finalMethod();
}
static void finalMethod(){
System.out.println("finalMethod()");
}
public static void main(String[] args) {
firstMethod();
}
}
class CallStack5_2 {
static void firstMethod() {
secondMethod();
System.out.println("firstMethod()");
}
static void secondMethod() {
thirdMethod();
System.out.println("secondMethod()");
}
static void thirdMethod() {
finalMethod();
System.out.println("thirdMethod()");
}
static void finalMethod(){
System.out.println("finalMethod()");
}
public static void main(String[] args) {
firstMethod();
}
}
class CallStack5_2 {
static void firstMethod() {
secondMethod();
System.out.println("firstMethod()");
}
static void secondMethod() {
thirdMethod();
System.out.println("secondMethod()");
}
static void thirdMethod() {
finalMethod();
System.out.println("thirdMethod()");
}
static void finalMethod(){
System.out.println("finalMethod()");
}
public static void main(String[] args) {
firstMethod();
}
}
기본형 매개변수
변수의 값을 읽기만 할 수 있습니다.
class Data6_1 {
int x; // 기본형
int y; // 기본형
}
class Data6_1Main {
public static void main(String[] args) {
Data6_1 data = new Data6_1();
data.x = 10;
data.y = 20;
System.out.println("Data6_1 클래스로 만든 data 인스턴스의 인스턴스 변수 x, y 값 확인");
System.out.println("data 인스턴스 변수 x = " + data.x);
System.out.println("data 인스턴스 변수 y = " + data.y);
System.out.println();
// changeParameter 메서드 의 매개변수에 Data 클래스의 인스턴스 변수를 입력한다.
System.out.println("입력받은 매개변수의 값을 바꾸는 메서드 수행");
changeParameter(data.x, data.y);
System.out.println();
// changeParameter(data.x, data.y); 여기서의 data.x 와 data.y 는
// data 의 인스턴스 변수의 값 그자체가 복사되어 넘어갑니다.
// 따라서 changeParameter 메서드에서 입력받은 매개변수의 값을 바꿔도
// 영향을 받지 않습니다.
System.out.println("Data6_1 클래스로 만든 data 인스턴스의 인스턴스 변수의 값이 변경되었는지 확인");
System.out.println("changeParameter 메서드 수행 후 data 인스턴스 변수 x = " + data.x);
System.out.println("changeParameter 메서드 수행 후 data 인스턴스 변수 y = " + data.y);
}
static void changeParameter(int x, int y) {
System.out.println();
System.out.println("changeParameter 메서드 시작");
System.out.println("입력 받은 매개변수 x 와 y의 값 확인");
System.out.println("입력 받은 매개변수 x = " + x);
System.out.println("입력 받은 매개변수 y = " + y);
System.out.println();
System.out.println("입력 받은 매개변수 x 와 y의 값을 변경 한 후 확인");
x = 100;
y = 200;
System.out.println("변경 한 후 x = " + x);
System.out.println("변경 한 후 y = " + y);
System.out.println("changeParameter 메서드 끝");
}
참조형 매개변수
변수의 값을 읽고 변경할 수 있습니다.
class Data6_2 {
Data6_3 data2 = new Data6_3(); // 참조형
}
class Data6_3 {
int x; // 기본형
int y; // 기본형
}
class Data6_2Main {
public static void main(String[] args) {
Data6_2 data = new Data6_2();
data.data2.x = 10;
data.data2.y = 20;
System.out.println("Data6_2 클래스로 만든 data 인스턴스의 data2인스턴스의 인스턴스 변수 값 확인");
System.out.println("참조변수 data2의 인스턴스 변수 x = " + data.data2.x);
System.out.println("참조변수 data2의 인스턴스 변수 y = " + data.data2.y);
System.out.println();
// changeParameter 메서드 의 매개변수에 Data6_2 클래스의 참조형 변수인 data2 를 입력
System.out.println("입력받은 매개변수의 값을 바꾸는 메서드 수행");
changeParameter(data.data2);
System.out.println();
// changeParameter(Data6_3 data2); 여기서 data.data2 는
// data 인스턴스의 참조형 변수 data2의 주소값이 넘어 갑니다.
// 따라서 changeParameter 메서드에서 입력받은 data2의 주소값을 통해
// data2 의 인스턴스에 접근하여 인스턴스 변수를 바꾸기 때문에 영향을 받습니다.
System.out.println("Data6_3 클래스로 만든 data 인스턴스의 참조변수 data2의 인스턴스 변수 값이 변경되었는지 확인");
System.out.println("changeParameter 메서드 수행 후 data2의 인스턴스 변수 x = " + data.data2.x);
System.out.println("changeParameter 메서드 수행 후 data2의 인스턴스 변수 y = " + data.data2.y);
}
static void changeParameter(Data6_3 data2) {
System.out.println();
System.out.println("changeParameter 메서드 시작");
System.out.println("입력 받은 매개변수 data2의 인스턴스 x 와 y의 값 확인");
System.out.println("입력 받은 매개변수 data2의 인스턴스 x = " + data2.x);
System.out.println("입력 받은 매개변수 data2의 인스턴스 y = " + data2.y);
System.out.println();
System.out.println("입력 받은 매개변수 data2의 인스턴스 x 와 y의 값을 변경 한 후 확인");
data2.x = 100;
data2.y = 200;
System.out.println("변경 한 후 data2의 인스턴스 x = " + data2.x);
System.out.println("변경 한 후 data2의 인스턴스 y = " + data2.y);
System.out.println("changeParameter 메서드 끝");
}
}
static 메서드와 인스턴스 메서드
static 메서드 (클래스 메서드)
객체 생성 없이 '클래스 이름. 메서드이름()'으로 호출 : ex) Math.random()
인스턴스 멤버(인스턴스 변수, 인스턴스 메서드)와 관련없는 작업을 하는 메서드
메서드 내에서 인스턴스 변수 사용 불가합니다.
class InstMethod7_1 {
int num1, num2; // 인스턴스 변수 선언
static int num3 = 100;
int add(int num1, int num2) { // 메서드 반환타입 앞에 static 이 없기 때문에 인스턴스 메서드 입니다.
System.out.println();
System.out.println("매개변수로 입력 받은 num1, num2 확인");
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
// 계속된 실습으로 우리는 위에 매개변수 num1, num2 와 InstMethod7_1 의 인스턴스 변수는 다르다는 것을 알았습니다.
// 그럼 이런 의문이 듭니다. InstMethod7_1 클래스로 methodTest 객체를 생성했고
// 참조변수를 통해 methodTest.num1 = 10;와 같이 인스턴스 변수에 값도 넣었는데
// 저 값을 매개변수로 받는 의미가 있는 건가? 확인해 보겠습니다.
// 인스턴스 변수 값 확인 : this 는 뒤에서 배우기 때문에 간단히 설명드리자면 인스턴스 변수와 매개변수를 구분하기 위한 것입니다.
System.out.println("this.num1 = " + this.num1);
// 10 이렇게 10이 출력될겁니다. 그럼 비교를 위해 아래 methodTest.add(methodTest.num1, methodTest.num2);
// 주석 하고 methodTest.add(80,90); 주석을 푸세요!
System.out.println("매개변수 이자 지역변수 num1 = " + num1);
// 값이 달라졌을 겁니다. 이제 인스턴스 num1 과 매개변수 num1 은 이름만 같을 뿐이라는 것을 아셨을 겁니다.
// 그래서 구분을 위해 변수의 이름을 다르게 하거나 this 를 사용해서 구분해야 합니다.
// 그럼 지금 상황에서는 매개 변수를 받지 않고
// return this.num1 + this.num2; // 이렇게 해도 됩니다.
// 이번에는 그럼 일반 메서드니까 클래스 변수는 사용하지 못 할까? 아래 주석 제거하세요!
// System.out.println("InstMethod7_1.num3 = " + InstMethod7_1.num3); // 당연하게도 사용 가능합니다!
return num1 + num2;
}
}
class InstMethod7_1Main {
public static void main(String[] args) {
InstMethod7_1 methodTest = new InstMethod7_1(); // 객체 생성
methodTest.num1 = 10;
methodTest.num2 = 20;
// 참조변수를 사용하여 인스턴스 메서드 호출
System.out.println("result : " + methodTest.add(methodTest.num1, methodTest.num2));
// System.out.println("result : " + methodTest.add(80,90));
}
}
인스턴스 메서드
인스턴스를 생성한 후, '참조변수.메서드이름()'으로 호출
인스턴스 멤버(인스턴스 변수, 인스턴스 메서드)와 관련된 작업을 하는 메서드
메서드 내에서 인스턴스 변수 사용 가능합니다.
class InstMethod7_1 {
int num1, num2; // 인스턴스 변수 선언
static int num3 = 100;
int add(int num1, int num2) { // 메서드 반환타입 앞에 static 이 없기 때문에 인스턴스 메서드 입니다.
System.out.println();
System.out.println("매개변수로 입력 받은 num1, num2 확인");
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
// 계속된 실습으로 우리는 위에 매개변수 num1, num2 와 InstMethod7_1 의 인스턴스 변수는 다르다는 것을 알았습니다.
// 그럼 이런 의문이 듭니다. InstMethod7_1 클래스로 methodTest 객체를 생성했고
// 참조변수를 통해 methodTest.num1 = 10;와 같이 인스턴스 변수에 값도 넣었는데
// 저 값을 매개변수로 받는 의미가 있는 건가? 확인해 보겠습니다.
// 인스턴스 변수 값 확인 : this 는 뒤에서 배우기 때문에 간단히 설명드리자면 인스턴스 변수와 매개변수를 구분하기 위한 것입니다.
System.out.println("this.num1 = " + this.num1);
// 10 이렇게 10이 출력될겁니다. 그럼 비교를 위해 아래 methodTest.add(methodTest.num1, methodTest.num2);
// 주석 하고 methodTest.add(80,90); 주석을 푸세요!
System.out.println("매개변수 이자 지역변수 num1 = " + num1);
// 값이 달라졌을 겁니다. 이제 인스턴스 num1 과 매개변수 num1 은 이름만 같을 뿐이라는 것을 아셨을 겁니다.
// 그래서 구분을 위해 변수의 이름을 다르게 하거나 this 를 사용해서 구분해야 합니다.
// 그럼 지금 상황에서는 매개 변수를 받지 않고
// return this.num1 + this.num2; // 이렇게 해도 됩니다.
// 이번에는 그럼 일반 메서드니까 클래스 변수는 사용하지 못 할까? 아래 주석 제거하세요!
System.out.println("InstMethod7_1.num3 = " + InstMethod7_1.num3); // 당연하게도 사용 가능합니다!
return num1 + num2;
}
}
class InstMethod7_1Main {
public static void main(String[] args) {
InstMethod7_1 methodTest = new InstMethod7_1(); // 객체 생성
methodTest.num1 = 10;
methodTest.num2 = 20;
// 참조변수를 사용하여 인스턴스 메서드 호출
System.out.println("result : " + methodTest.add(methodTest.num1, methodTest.num2));
// System.out.println("result : " + methodTest.add(80,90));
}
}
오버로딩
한 클래스 안에 같은 이름의 메서드를 여러 개 정의하는 것입니다.
오버로딩의 성립 조건
1. 메서드 이름이 같아야합니다.
2. 매개변수의 개수 또는 타입, 위치가 달라야합니다.
3. 반환타입에는 영향을 받지 않습니다.
사용하는 목적
- 매개변수 즉, 입력하는 값이 다르지만 같은 기능을 수행하는 경우가 많을 때 사용성 및 효율을 높이기 위해 오버로딩을 사용합니다.
class Overloading8_1 {
int add(int a, int b) {
System.out.println("int add(int a, int b)");
return a + b;
}
// void add(int a, int b) { // 반환 타입이 다르다고 오버로딩이 성립되지는 않음
// System.out.println("void add(int a, int b)");
// System.out.println("a + b = " + a + b);
// }
long add(long a, long b) {
System.out.println("long add(long a, long b)");
return a + b;
}
long add(long a, int b) {
System.out.println("long add(long a, int b)");
return a + b;
}
long add(int a, long b) {
System.out.println("long add(int a, long b)");
return a + b;
}
}
class Overloading8_1Main {
public static void main(String[] args) {
Overloading8_1 test = new Overloading8_1();
System.out.println(test.add(10, 20));
System.out.println(test.add(13L, 17L));
System.out.println(test.add(5L, 10));
System.out.println(test.add(12, 23L));
System.out.println();
// 그런데 이때 위에 int add(int a, int b) 를 주석한다면
test.add(10, 20); // 여기에 Ambiguous method call Error 가 발생합니다.
// int, int 는 (long, int) , (int, long) 2개의 메서드 모두 가능하기 때문에 컴퓨터가 하나를
// 마음대로 선택할 수가 없어서 발생하는 오류입니다.
}
}
생성자
인스턴스가 생성될 때마다 호출되는 '인스턴스 초기화 메서드' 입니다.
- 인스턴스 생성시 수행할 작업에 사용됩니다.
초기값이 필요한 인스턴스 변수의 값을 초기화 해줍니다.
생성 조건
- 이름이 클래스 이름과 같아야 합니다.
- return 값이 없습니다.
- void는 붙이지 않습니다.
- 오버로딩 가능합니다.
기본 생성자
- 매개변수가 없는 생성자를 의미합니다.
- 생성자를 하나도 선언되어 있지 않았을 때는 컴파일러가 자동으로 추가해 줍니다.
class Tv9_1 {
// 속성 : 변수 선언
boolean power; // 전원상태
int channel; // 채널
String color; // 색깔
long price; // 가격
// 위 속성에서 필수로 초기값이 필요한 값들을 초기화 해주는 기본 생성자
public Tv9_1() {
power = false;
channel = 1;
}
// 오버로딩 한 생성자 - 매장 진열 용 일 경우에는 가격과 색깔의 초기화가 필요합니다. this 는 이전 챕터에서 잠깐 봤었죠! 매개변수와 인스턴스변수를 구분하기 위해 사용하겠습니다.
public Tv9_1(String color, long price) {
power = false; // this.power, power 둘다 지금 상황에서는 인스턴스 변수를 명확하게 판단 할 수 있기 때문에 어떤걸 사용해도 상관 없습니다.
channel = 1;
this.color = color;
this.price = price;
}
// 기능 : 메서드 선언
void power() { // 전원 기능
power = !power;
if (power) {
System.out.println("전원 ON");
} else {
System.out.println("전원 OFF");
}
}
void channelUp() { // 채널 증가
channel++;
System.out.println("채널 증가");
}
void channelDown() { // 채널 감소
channel--;
System.out.println("채널 감소");
}
}
class Tv9_1Main {
public static void main(String[] args) {
// 기본 초기화된 Tv9_1 생성
Tv9_1 tv = new Tv9_1();
System.out.print("기본 생성자 TV: ");
tv.power();
// 진열 용 Tv9_1 생성
Tv9_1 exTv = new Tv9_1("보라색", 3456789);
System.out.print("오버로딩 생성자 TV: ");
exTv.power();
System.out.println("exTv.color = " + exTv.color);
System.out.println("exTv.price = " + exTv.price);
// 근데 이때 주의할 점!
// 기본 생성자는 없고 오버로딩한 생성자만 있을 경우!
// 컴파일러는 기본 생성자를 만들어주지 않기 때문에 기본 생성자를 사용하려고 하면 Error 발생!
// 위 기본 생성자를 주석 하세요!!!!
Tv9_1 tv2 = new Tv9_1(); // Error 발생, 기본 생성자가 없기 때문에 매개 변수를 넣으라고 intellij 가 요구합니다.
}
}
this 와 this()
this
- 인스턴스 자신을 가리키는 참조변수입니다.
- 인스턴스 메서드(생성자 포함)에서 사용 가능합니다.
- 지역 변수와 인스턴스 변수를 구별할 때 사용합니다.
class Tv10_1 {
// 속성 : 변수 선언
boolean power; // 전원상태
int channel; // 채널
String color; // 색깔
long price; // 가격
// 위 속성에서 필수로 초기값이 필요한 값들을 초기화 해주는 기본 생성자
public Tv10_1() {
this.power = false;
this.channel = 1;
}
// 오버로딩 한 생성자 - 매장 진열 용 일 경우에는 가격과 색깔의 초기화가 필요합니다.
public Tv10_1(String color, long price) {
this.power = false;
this.channel = 1;
this.color = color;
this.price = price;
}
// 기능 : 메서드 선언
void power() { // 전원 기능
this.power = !power;
if (this.power) {
System.out.println("전원 ON");
} else {
System.out.println("전원 OFF");
}
}
void channelUp() { // 채널 증가
this.channel++;
System.out.println("채널 증가");
}
void channelDown() { // 채널 감소
this.channel--;
System.out.println("채널 감소");
}
// 색깔을 수정하고 자기 자신을 반환하는 메서드
Tv10_1 changeColor(String color) { // 반환 타입으로 자기자신인 Tv 선언
this.color = color;
System.out.println("색깔 변경 완료!");
return this; // this 는 자기 자신을 가리키는 참조변수!
}
}
class Tv10_1Main {
public static void main(String[] args) {
// 기본 초기화된 Tv10_1 생성
Tv10_1 tv = new Tv10_1();
System.out.print("기본 생성자 Tv10_1: ");
tv.power();
// 진열 용 Tv10_1 생성
Tv10_1 exTv = new Tv10_1("보라색", 3456789);
System.out.print("오버로딩 생성자 Tv10_1: ");
exTv.power();
System.out.println("exTv.color = " + exTv.color);
System.out.println("exTv.price = " + exTv.price);
System.out.println();
// 진열 용 Tv10_1 의 색깔을 수정하고 수정된 객체를 참조변수에 저장하겠습니다.
Tv10_1 exTvThis = exTv.changeColor("파란색");
// 색깔이 변경된 Tv의 주소가 저장된 참조변수 exTvThis 를 사용하여 변경된 색깔 확인
System.out.println("색깔이 변경되었는지 확인 exTvThis.color : " + exTvThis.color);
// 당연히 exTv 이걸로 확인해도 색깔이 변경되어 있습니다.
System.out.println("exTv.color = " + exTv.color);
}
}
this()
- 생성자에서 다른 생성자를 호출할 때 사용합니다.
this()를 사용하지 않고 클래스명(); 이렇게 생성자를 호출하려고 하면 Error가 발생합니다.
- 다른 생성자 호출시 첫 줄에서만 사용 가능합니다.
class Tv10_2 {
// 속성 : 변수 선언
boolean power; // 전원상태
int channel; // 채널
String color; // 색깔
long price; // 가격
// 위 속성에서 필수로 초기값이 필요한 값들을 초기화 해주는 기본 생성자
public Tv10_2() {
this.power = false;
this.channel = 1;
}
// 오버로딩 한 생성자 - 매장 진열 용 일 경우에는 가격과 색깔의 초기화가 필요합니다.
public Tv10_2(String color, long price) {
// 아래 초기화 내용은 위에 기본생성자와 완전히 똑같습니다.
// 이럴 때 this() 를 사용합니다.
// this.power = false;
// this.channel = 1;
this(); // 기본 생성자를 호출합니다.
// Tv10_2() // 이렇게는 불가능 합니다!
this.color = color;
this.price = price;
// this(); // 생성자 호출은 반드시 첫 줄에서만 가능합니다.
}
// 기능 : 메서드 선언
void power() { // 전원 기능
this.power = !power;
if (this.power) {
System.out.println("전원 ON");
} else {
System.out.println("전원 OFF");
}
}
void channelUp() { // 채널 증가
this.channel++;
System.out.println("채널 증가");
}
void channelDown() { // 채널 감소
this.channel--;
System.out.println("채널 감소");
}
// 색깔을 수정하고 자기 자신을 반환하는 메서드
Tv10_2 changeColor(String color) { // 반환 타입으로 자기자신인 Tv 선언
this.color = color;
System.out.println("색깔 변경 완료!");
return this; // this 는 자기 자신을 가리키는 참조변수!
}
}
class Tv10_2Main {
public static void main(String[] args) {
// 기본 초기화된 Tv10_2 생성
Tv10_2 tv = new Tv10_2();
System.out.print("기본 생성자 Tv10_2: ");
tv.power();
// 진열 용 Tv10_2 생성
Tv10_2 exTv = new Tv10_2("보라색", 3456789);
System.out.print("오버로딩 생성자 Tv10_2: ");
exTv.power();
System.out.println("exTv.color = " + exTv.color);
System.out.println("exTv.price = " + exTv.price);
System.out.println();
// 진열 용 Tv10_2 의 색깔을 수정하고 수정된 객체를 참조변수에 저장하겠습니다.
Tv10_2 exTvThis = exTv.changeColor("파란색");
// 색깔이 변경된 Tv의 주소가 저장된 참조변수 exTvThis 를 사용하여 변경된 색깔 확인
System.out.println("색깔이 변경되었는지 확인 exTvThis.color : " + exTvThis.color);
// 당연히 exTv 이걸로 확인해도 색깔이 변경되어 있습니다.
System.out.println("exTv.color = " + exTv.color);
}
}
변수의 초기화
수동 / 자동 초기화
- 지역 변수는 수동으로 초기화 해야합니다.
지역 변수가 동작하는 스택 메모리는 재사용이 빈번하기 때문에 매번 초기화 해주면 성능이 떨어집니다.
그래서 그냥 해당 메모리에 있는 값으로 덮어 씌웁니다.
근데 해당 주소에 어떠한 값이 있는지 모르기 때문에 Java는 개발자에게 수동으로 초기화 하라고 요구합니다.
C언어에서는 이를 grabage value 라 부릅니다.
- 멤버 변수의 초기화
클래스 변수 : 클래스가 처음 로딩될 때 단 한번만 초기화 됩니다.
인스턴스 변수 : 인스턴스가 생성될 때 마다 초기화 됩니다.
초기화 방법
명시적 초기화(=)
class Tv11_1 {
boolean power = false; // 기본형 변수의 초기화
int channel = 1; // 기본형 변수의 초기화
Audio audi = new Audio(); // 참조형 변수의 초기화, 참조형은 객체주소 or null 로 초기화!!
// 참조형의 기본값은 null 입니다!!
...
}
초기화 블럭
class Tv11_2 {
static boolean power;
int channel;
// 클래스 초기화 블럭
static
{
power = false;
}
// 인스턴스 초기화 블럭
{
channel = 1;
}
...
}
생성자 초기화
class Tv11_3 {
// 속성 : 변수 선언
boolean power; // 전원상태
int channel; // 채널
String color; // 색깔
long price; // 가격
// 위 속성에서 필수로 초기값이 필요한 값들을 초기화 해주는 기본 생성자
Tv11_3() {
this.power = false;
this.channel = 1;
}
...
}
많은 정의를 한 번 흘러가는 식으로 기억했다.
이 후 과제를 하면서 이런 내용을 한 번씩 더 익히며 익숙해져야겠다.