티스토리 뷰

728x90

서문



자바의 정석 기초편 챕터 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 변수
      • 클래스 영역은 선언문만 들어갈 수 있음
    • 메서드 영역 : 지역변수
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에서는 객체지향의 의미와 특징, 클래스, 객체의 정의, 인스턴스, 생성자, 변수의 종류, 오버로딩 등을 배웠습니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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 29 30 31
글 보관함