클래스 | 객체 |
---|---|
제품 설계도 | 제품 |
TV 설계도 | TV |
붕어빵 기계 | 붕어빵 |
클래스의 정의
: 클래스란 객체를 정의해 놓은 것
클래스의 용도
: 클래스는 객체를 생성하는데 사용함
객체의 정의
: 실제로 존재하는 것, 사물 또는 개념
객체의 용도
: 객체가 가지고 있는 속성과 기능에 따라 다름
객체 = 속성(변수) + 기능(메서드)
클래스명 변수명;
- 클래스의 객체를 참조하기 위한 참조변수를 선언
변수명 = new 클래스명;
- 생성된 객체의 주소를 참조변수에 저장
객체 생성 방법
- Tv t;
- Tv 클래스 타입의 참조변수 t를 선언
- t - new Tv();
- Tv 인스턴스를 생성한 후
- 생성된 Tv인스턴스의 주소를 t에 저장
TV 클래스
속성
- 색깔
- 전원상태
- 채널
기능
- 파워(전원)
- 채널 증가
- 채널 감소
TV1 인스턴스
속성
- 색깔 : 검정색
- 전원상태 : false
- 채널 :1
기능
- 파워(전원)
- 채널 증가
- 채널 감소
TV2 인스턴스
속성
- 색깔 : 흰색
- 전원상태 : 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 인스턴스 에 접근할 수 없습니다.
}
}
Result
객체 배열 == 참조변수 배열
- 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);
}
}
}
Result
클래스 == 데이터 + 함수
원하는 타입을 직접 만들 수 있음
사용자 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(); // 메서드 호출 시 지역 변수 생성
// 메서드 종료시 지역 변수 삭제
}
}
Result
즉 트럼프 카드에서 무늬와 숫자는 iv이고, 카드의 폭과 넓이는 cv이다
Card c = new Card(); //객체 생성
c.kind = "HEART"; // iv 객체 사용
c.number = 5; // iv 객체 사용 2
c.width = 200; // cv 객체 사용 but
c.height = 300; // cv는 Card.width = 200; Card.height = 300; 과 같이 앞에 클래스이름을 써 주는것이 권장된다. 이렇게 써야한다.
반환타입 메서드이름 (타입 변수명, 타입 변수명, ...)//(선언부)
{
// 메서드가 호출되면 수행할 코드(구현부)
}
장점
- 중복 코드 제거
- 관리 용이
- 재사용 가능
작성
- 반복적으로 수행되는 여러 문장을 메서드로 작성한다
- 하나의 메서드는 한 가지 기능만 수행하도록 작성하는 것이 좋다
값을 입력 받아서 처리하고, 결과를 반환한다
int add(intx, inty){
=> 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);
}
}
Result = 8
실행 중인 메서드를 종료하고 호출한 곳으로 되돌아간다
- 반환타입이 void가 아닌 경우 , 반드시 return 문이 필요함
- void 는 컴파일러가 자동으로 메서드 마지막에 return; 을 추가해 준다
class Method5_2 {
void gugudan(int dan) {
if (!(dan >= 2 && dan <= 9)) {
System.out.println(dan + "단은 없습니다.");
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));
}
}
Result
코드의 중복을 하나의 묶음으로 만들어 코드의 가독성 및 효율을 높여준다
class Time5_1 {
int hour;
int minute;
int second;
}
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);
// 이처럼 메서드를 사용하니 코드의 수가 굉장히 많이 줄어 가독성이 좋아졌습니다.
}
}
Result
메서드 수행에 필요한 메모리가 제공되는 공간
메서드가 호출되면 호출 스택에 메모리가 할당, 종료되면 해제된다
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();
}
}
Result
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();
}
}
Result
먼저 스택이란?
호출 스택
☆ 맨 위의 한개의 메서드만 실행되고 나머지는 대기중!
스택이 비어있음
main 메서드가 시작됨
main이 println 메서드 호출함.
main이 대기상태가 되고, println 메서드가 실행됨
println 에서 메세지가 출력되고
자신의 메모리를 반환하고 종료함.
자신을 호출한 main 메서드로 돌아가고 main이 실행상태로 돌아감
main도 더이상 실행할 메서드가 없으니 종료됨.
실행할 메서드도 더이상 없으니 프로그램도 종료됨
결과는 Hello 출력됨
이렇게 코드를 보고 스택의 변화단계를 그려보면 아주 큰 도움이 된다.
.
.
.
.
.
.
.