티스토리 뷰
서문
자바의 정석 기초편 챕터 6편을 기재합니다.
목적은 공부한 내용을 기록하는 것에 있기 때문에 완전한 문장이 아닐 수도 있습니다.
또한 모든 내용을 적은 것은 아닙니다.
- 참고 자료
자바의 정석 ( CH.6 ) - 객체지향
소프트웨어의 빠른 발전에 대응할 수 있는 근본적인 접근법은 무엇인가? 절차지향적 -> 객체지향적
- 코드의 재사용성
- 유지보수의 용이성
- 중복코드 제거
- 캡슐화
- 추상화
- 상속
- 다형성
클래스와 객체
- 클래스의 정의 : 클래스란 객체를 정의해 놓은 것
- 클래스의 용도 : 클래스는 객체를 생성하는데 사용
클래스 | 객체 |
---|---|
제품 설계도 | 제품 |
tv 설계도 | tv |
자동차 설계도 | 자동차 |
객체의 구성요소
- 속성 : 크기, 길이, 높이, 색상, 볼륨 등등
- 기능: 켜기, 끄기, 볼륨높이기, 낮추기, 채널변경하기 등등
class Tv{
// 속성, 변수
String color;
boolean power;
int channel;
// 기능, 메서드
void power(){
power = !power;
}
void channelUp(){
channel++
}
void channelDown(){
channel--
}
}
객체와 인스턴스
- 객체 : 모든 인스턴스를 대표하는 일반적인 용어
- 인스턴스 : 특정 클래스로부터 생성된 객체(예: Tv인스턴스)
클래스/설계도 ---(인스턴스화)---> 인스턴스(객체)/제품
Q. 클래스가 왜 필요한가?
- 객체를 생성하기 위해
Q. 객체가 왜 필요한가?
- 객체를 사용하기 위해
Q. 객체를 사용한다는 것은 무엇인가?
- 객체가 가진 속성과 기능을 사용한다는 것
하나의 소스파일에 여러 클래스 작성
기본적으로 하나의 소스파일에 하나의 클래스를 작성하는 것
그러나 여러 이유에서 하나의 소스파일에 여러 클래스를 넣을 상황이 발생할 수 있음
- 기본적으로 소스파일 이름과 public(하나)이 붙은 클래스이름은 동일해야 함
- 만약 public class가 하나도 없을 경우, 소스파일 이름은 그 소스파일 안에 있는 모든 클래스 이름이 될 수 있음
- 올바른 예
public class Hello1{
}
class Hello2{
}
-------------
class Hello1{
}
class Hello2{
}
- 잘못 사용한 예
// public이 하나 이상인 경우
public class Hello1{
}
public class Hello2{
}
--------------
// Hello1.java 소스파일에서 public이 잘못 쓰인 경우
class Hello1{
}
public class Hello2{
}
--------------
// public이 붙은 클래스 이름과 소스파일 이름이 일치하지 않을 때
// Hello1.java
public class Hello2{
}
class Hello3{
}
객체의 생성과 사용
- 두개 이상의 참조변수가 하나의 인스턴스를 가리키는 것은 가능하다
- 하나의 참조변수가 여러 인스턴스를 가리키는 것은 불가능하다.
- 참조변수는 하나의 값만 저장할 수 있기 때문에
// 객체 생성
public class Tv{
int channel;
void channelUp(){
channel++;
}
void channelDown(){
channel--;
}
}
Tv t; // 1) Tv클래스 타입의 참조변수 t를 생성
t = new Tv(); // 2) new Tv()로 Tv인스턴스를 생성 후 3) 참조변수와 연결
---------------
// 객체 사용
t.channel = 7;
t.channelUp(); // Tv클래스에 있는 메서드를 사용
System.out.println(t.channel);
> 8
---------------
// 여러 객체를 만들 수 있으며 이들은 독립적이다.
Tv t1 = new Tv();
Tv t2 = new Tv();
t1.channel = 7;
System.out.println(t1.channel);
System.out.println(t2.channel);
> 7
> 0
객체의 배열
- 객체의 배열 == 참조변수 배열
- Tv tv1,tv2,tv3; == Tv[] tvArr = new Tv[3];
- 중요한 점은 참조변수만 만들고 객체와 연결하지 않으면 소용이 없음
Tv t1 = new Tv();
Tv t2 = new Tv();
Tv t3 = new Tv();
Tv[] tvArr = new Tv[3]; // 배열 생성, 참조변수만 생성
tvArr[0] = new Tv(); // 참조변수에 객체를 생성하여 연결해주어야 함
tvArr[1] = new Tv();
tvArr[2] = new Tv();
클래스의 정의 (1)
- 클래스 == 데이터 + 함수
- 변수는 하나의 값만 저장
- 배열은 같은 타입의 여러 데이터들을 저장
- 구조체는 서로 관련된 여러 데이터(타입상관없음)를 하나로 저장할 수 있음
- 클래스는 구조체에 함수까지 넣어 저장
클래스의 정의 (2)
- 사용자 정의 타입 : 원하는 타입을 직접 만들 수 있음
// 시간을 다룰 변수 생성
int hour;
int minute;
int second;
class Time{
int hour;
int minute;
int second;
}
Time time = new Time();
-----------
int hour1, hour2, hout3;
int minute1, minute2, minute3;
int second1, second2, second3;
Time time1 = new Time();
Time time2 = new Time();
Time time3 = new Time();
-----------
int[] hour = new int[3];
int[] minute = new int[3];
int[] second = new int[3];
Time[] time = new Time[3];
time[0] = new Time();
time[1] = new Time();
time[2] = new Time();
선언위치에 따른 변수의 종류
- 영역 : 클래스 영역, 메서드 영역
- 클래스 영역 : 인스턴스 변수, static 변수
- 클래스 영역은 선언문만 들어갈 수 있음
- 메서드 영역 : 지역변수
- 클래스 영역 : 인스턴스 변수, static 변수
class a{
int iv; // 인스턴스 변수
static int cv; // static변수, class변수, 공유변수
void method(){
int lv = 0; // 지역변수
}
}
변수의 종류 | 선언 위치 | 생성시기 |
---|---|---|
클래스변수 | 클래스영역 | 클래스가 메모리에 올라갈 때 |
인스턴스변수 | 클래스영역 | 인스턴스가 생성될 때 |
지역변수 | 클래스 영역 이외의 영역(메서드, 생성자, 초기화 블럭내부) | 변수 선언문이 수행되었을 때 |
클래스변수(cv)와 인스턴스 변수(iv)
예컨대 트럼프카드를 생각해보자.
개별 카드마다 다르게 유지되어야 할 속성은 카드 번호, 카드 무늬일 것이다.
개별 카드가 동일하게 유지되어야 하는 속성은 폭과 높이일 것이다.
공통속성(cv)는 static을 붙이고 개별속성은 iv로 만들면 된다.
cv는 객체생성 전에도 사용 가능하다. 왜냐하면 클래스가 이미 메모리에 올라가 있으며 거기에 있는 변수에 접근하기 때문에
public class Card{
String kind; // 무늬, iv
int number; // 숫자, iv
static int width = 100; // 폭, cv
static int height = 250; // 높이, cv
}
Card c = new Card();
c.kind = "heart";
c.number = 5;
c.width = 200;
c.height = 300; // cv를 이렇게 써도 상관은 없지만 권장하지 않음
Card.width = 200; // cv는 클래스로 접근하여 사용하는 것을 권장. c는 하나의 객체만의 값을 바꾸기 때문에
Card.height = 300;
메서드
작업단위로 문장을 묶은 것
값(입력)을 받아서 처리하고, 결과를 반환(출력)
메서드와 함수의 차이?
- 메서드는 클래스에 들어가 있어야하고
- 함수는 독립적으로 존재할 수 있음
장점
- 중복을 제거
- 관리 용이
- 재사용성
- 코드의 이해성 높임
반환타입 메서드이름 (타입 변수명, 타입 변수명 ...){
//메서드 호출 시 실행되는 블록
}
// int a, int b는 매개변수로 메서드가 종료될 때까지 유효함
int add(int a, int b){
int result = a + b; // result는 lv로 지역변수
return result;
}
메서드의 호출
- 메서드이름(매개변수);
int add(int a, int b){
int result = a + b;
return result;
}
int result = add(3,5);
return 문
- 실행 중인 메서드를 종료하고 호출한 곳으로 되돌아감
- 반환타입이 void가 아니면 반드시 return이 필요함
- 일반적으로 반환타입과 return되는 변수의 타입이 일치해야함
- 일치하지 않는다면 자동변환이 가능한 변수일 경우 자동변환이 되고 안되면 오류
void print99dan(int dan){
if (!(2 <= dan && dan<= 9)){
return; // dan이 2와 9사이가 아니면 호출한 곳으로 되돌아감
}
for (int i =1; i<10; i++){
System.out.printf("%d * %d = %d%n", dan, i ,dan*i);
}
return; // 반환타입이 void이므로 생략가능
}
호출 스택(call stack)
- 스택(stack) : 밑이 막힌 상자. 위에 쌓이는 자료구조
- FILO의 형태
- 메서드 수행에 필요한 메모리가 제공되는 공간
- 메서드가 호출되면 호출스택에 메모리 할당, 종료되면 해제
public class ex1{
public static void main(String[] args){
System.out.println("처음 실행");
}
}
main(실행) -> main(실행, println 호출) -> main(대기), println(실행) -> main(대기), println(종료) -> main(실행) -> main(종료, 프로그램종료)
기본형 매개변수
- 기본형 매개변수 : 변수의 값을 읽기만 할 수 있다(read only)
- 참조형 매개변수 : 변수의 값을 읽고 변경할 수 있다(read & write)
- 기본형 매개변수에 대한 예시
// 기본형 매개변수에 대한 예시
class Data1{
int x;
}
public class ex1{
public static void main(String[] args){
Data1 d = new Data1(); // 객체 생성
d.x = 10;
System.out.println("main() : x = " + d.x);
change(d.x);
System.out.println("After change(d.x)");
System.out.println("main() : x = " + d.x);
}
static void change(int x){
x = 1000;
System.out.println("change() : x = )" + x);
}
}
> main() : x = 10
> change() : x = 1000
> After change(d.x)
> main() : x = 10
- 참조형 매개변수에 대한 예시
// 참조형 매개변수에 대한 예시
class Data2{
int x;
}
public class ex2{
public static void main(String[] args){
Data2 d = new Data2(); // 객체 생성
d.x = 10;
System.out.println("main() : x = " + d.x);
change(d);
System.out.println("After change(d.x)");
System.out.println("main() : x = " + d.x);
}
static void change(Data2 d){
d.x = 1000;
System.out.println("change() : x = )" + d.x);
}
}
> main() : x = 10
> change() : x = 1000
> After change(d.x)
> main() : x = 1000
- 참조형 반환타입에 대한 예시
class Data3{
int x;
}
public class ex3{
public static void main(String[] args){
Data3 d = new Data3();
d.x = 10;
Data3 d2 = copy(d); // tmp 참조변수 주소가 반환
System.out.println("d.x = " + d.x);
System.out.println("d2.x = " + d2.x);
}
static Data3 copy(Data3 d){
Data3 tmp = new Data3();
tmp.x = d.x; // d.x에 있는 값 10이 tmp.x에 저장
return tmp; // tmp 참조변수 ( 주소 )가 반환
}
}
> d.x = 10
> d2.x = 10
static 메서드와 인스턴스 메서드
인스턴스 메서드
- 인스턴스 생성 후, '참조변수.메서드이름()'으로 호출
- 인스턴스 멤버(iv, im)와 관련된 작업을 하는 메서드
- 메서드 내에서 인스턴스 변수(iv) 사용가능
static 메서드
- 객체생성없이 '클래스이름.메서드이름()'으로 호출
- 인스턴스 멤버(iv, im)와 관련없는 작업을 하는 메서드
- 메서드 내에서 인스턴스 변수(iv) 사용 불가능
iv를 사용하는가 vs 하지 않는가?
- 사용하면 인스턴스 메서드
- 사용하지 않으면 static 메서드
class TestClass{
int iv; // 인스턴스 변수
static int cv; // 클래스 변수
void instanceMethod(){ // 인스턴스 메서드
System.out.println(iv); // 인스턴스 메서드는 iv 사용가능
System.out.println(cv);
}
static void staticMethod(){ // static 메서드
System.out.println(iv); // error , iv를 사용할 수 없음, , 객체가 없을 수도 있기 때문에
System.out.println(cv);
}
}
class TestClass2{
void instanceMethod(){}; // 인스턴스 메서드
static void staticMethod(){}; // static 메서드
void instanceMethod2(){ // 인스턴스 메서드
instanceMethod(); // 다른 인스턴스 메서드 호출
staticMethod(); // static 메서드 호출
}
static void staticMethod2(){
instanceMethod(); // error , 인스턴스 메서드를 호출 할 수 없음
staticMethod(); // static 메서드는 호출 가능
}
}
오버로딩 ( overloading, 과적 )
한 클래스 안에 같은 이름의 메서드 여러 개 정의하는 것
오버로딩의 조건
- 메서드 이름이 같아야 함
- 매개변수의 개수 또는 타입이 달라야 함
- 변환 타입은 영향이 없음
void println();
void println(boolean x);
void println(char x);
void println(char[] x);
void println(String x);
void println(String[] x);
void println(int x);
void println(int[] x);
void println(long x);
void println(long[] x);
void println(float x);
void println(float[] x);
void println(double x);
void println(double[] x);
void println(Object x);
println("안녕하세요") // void println(String x)가 호출
------------------------
// 오버로딩 x, 메서드 중복 정의
int add(int a, int b){return a+b;}
int add(int x, int y){return x+y;}
// 반환 타입은 영향이 없음, 오버로딩 x
int add(int a, int b){return a+b;}
long add(int a, int b){return (long)(a+b);}
// 오버로딩 ok
long add(int a, long b){return a+b;}
long add(long a, int b){return a+b;}
add(3,3); // 이 때는 컴퓨터가 결정할 수 없다. ambiguous error
생성자 ( constructor )
인스턴스가 생성될 때마다 호출되는 인스턴스 초기화 메서드
인스턴스 생성 시 수행할 작업(iv 초기화)에 사용
생성자 조건
- 이름이 클래스 이름과 동일해야 함
- 리턴값이 없음 (void 안붙임)
- 모든 클래스는 반드시 하나 이상의 생성자를 가져야 함
- 기본적으로 컴파일러가 생성자가 하나도 없을 때 기본 생성자를(default constructor) 자동으로 만들어 줌
class Time{
int hour;
int minute;
int second;
private Time(){ // 기본생성자, 매개변수가 없는 생성자
}
private Time(int hour, int minute, int second){ // 매개변수가 있는 생성자
this.hour = hour;
this.minute = minute;
this.second = second;
}
}
Time t = new Time();
t.hour = 12;
t.minute = 30;
t.second = 11;
Time t2 = new Time(12, 30, 11);
- 생성자 this()
- 생성자에서 다른 생성자를 호출할 때 사용
- 반드시 첫줄에 생성해야 함
class Car1{
String color;
String gearType;
int door;
}
Car1(){
this("white", "auto", 4); // 첫 줄에 생성
}
Car1(String color){
this(color, "auto", 4)
}
Car1(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}
- 참조변수 this
- 인스턴스 자신을 가리키는 참조변수
- 인스턴스 메서드(생성자 포함)에서 사용가능
- 지역변수(lv)와 인스턴스 변수(iv)를 구별할 때 사용
Car(String c, String g, int d){
color = c; // color 는 iv, c는 lv
gearType = g;
door = d;
}
Car(String color, String gearType, int door){
this.color = color; // this.color는 iv, color는 lv
this.gearType = gearType; // 만약에 this가 없다면, 구별이 안되고 모두 lv로 간주된다.
this.door = door;
}
변수의 초기화
지역변수(lv)는 수동 초기화 해야함(사용전 꼭!!!!)
멤버변수(iv,cv)는 자동초기화된다.
cv, iv 초기화
- 자동 초기화
- 간단 초기화
- 복잡 초기화
자료형 | 기본값 |
---|---|
boolean | false |
char | '\u0000' |
byte, short, int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d 또는 0.0 |
참조형 | null |
1. 명시적 초기화(=)(간단 초기화)
class Car {
int door = 4; // 기본형 변수의 초기화
Engine e = new Engine(); // 참조형 변수의 초기화, 객체를 연결해주어야 함
}
---------------------------
2. 초기화 블럭 (복잡 초기화)
- 인스턴스 초기화 블럭 : {}
- 클래스 초기화 블럭 : static {}
class StaticBlockTest{
static int[] arr = new int[10]; // 명시적 초기화, 배열 선언
static { // 클래스 블럭 초기화 - 배열 arr에 난수로 초기화
for (int i = 0; i<arr.length; i++){
arr[i] = (int)(Math.random() * 10)+1;
}
}
}
---------------------------
3. 생성자(iv초기화) (복잡초기화)
Car(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
멤버변수의 초기화
클래스 변수 초기화시점 : 클래스가 처음 로딩될 때 단 한번
인스턴스 변수 초기화시점 : 인스턴스가 생성될 때마다
cv가 우선, 그 다음 iv
자동 -> 간단(=) -> 복잡(블럭)
- 자바의 정석 챕터 6와 7은 가장 중요한 내용을 담고 있어서 여러 번 반복이 필요
- 챕터 6에서는 객체지향의 의미와 특징, 클래스, 객체의 정의, 인스턴스, 생성자, 변수의 종류, 오버로딩 등을 배웠습니다.