객체지향: 클래스, 객체, 상속, 다형성
객체지향과 웹프로그래밍 학습 절입니다.
5장 2절까지는 컴퓨터 내부와 운영체제를 봤습니다.
CPU
메모리
프로세스
스레드
스케줄링
동기화
교착상태
가상기억장치이제 다시 프로그래밍 쪽으로 옵니다. 이번 절은 객체지향프로그래밍입니다.
이번 절의 핵심은 다음과 같습니다.
클래스 = 객체를 만들기 위한 설계도
객체 = 클래스로 만든 실제 대상
캡슐화 = 데이터와 기능을 하나로 묶는 것
정보은닉 = 내부 정보를 숨기는 것
상속 = 부모 클래스의 기능을 물려받는 것
다형성 = 같은 명령이 객체에 따라 다르게 동작하는 것객체지향프로그래밍 출제범위에는 클래스, 객체, 메시지와 메소드, 캡슐화, 상속, 다형성, 절차지향과 객체지향 비교, 생성자, 소멸자, 접근 제한, this, super, 오버로딩, 오버라이딩, 추상 클래스, 인터페이스, 동적 바인딩, 예외 처리가 포함되어 있습니다.
이번 절의 큰 그림
이번 절에서 배울 흐름은 다음과 같습니다.
절차지향과 객체지향
→ 클래스와 객체
→ 멤버변수와 메소드
→ 메시지
→ 캡슐화와 정보은닉
→ 접근 제한자
→ 생성자와 소멸자
→ this와 super
→ 오버로딩과 오버라이딩
→ 상속
→ 다형성
→ 추상 클래스와 인터페이스
→ 정적 멤버
→ 문자열과 라이브러리
→ 예외 처리 맛보기객체지향은 처음에는 말이 추상적입니다.
그래서 이번 절에서는 코드보다 먼저 개념을 확실히 잡습니다.
객체지향 개요
절차지향이란?
절차지향은 프로그램을 순서 중심으로 생각하는 방식입니다.
C언어가 대표적으로 절차지향에 가깝습니다.
예를 들어 은행 계좌 프로그램을 만든다고 가정하겠습니다.
절차지향에서는 이렇게 생각합니다.
1. 계좌 정보를 입력합니다.
2. 입금 함수를 실행합니다.
3. 출금 함수를 실행합니다.
4. 잔액을 출력합니다.코드도 함수 중심으로 나뉩니다.
void deposit() { ... }
void withdraw() { ... }
void printBalance() { ... }무엇을 어떤 순서로 처리할 것인가?입니다.
장점은 단순하고 이해하기 쉽다는 것입니다. 하지만 프로그램이 커지면 데이터와 함수가 흩어져 관리가 어려워질 수 있습니다.
객체지향이란?
객체지향은 프로그램을 객체 중심으로 생각하는 방식입니다.
객체란 현실 세계의 어떤 대상을 프로그램 안에 표현한 것입니다.
학생
자동차
계좌
회원
게시글
상품
몬스터
아이템객체지향에서는 이렇게 생각합니다.
계좌 객체가 있습니다.
계좌 객체는 잔액을 가집니다.
계좌 객체는 입금할 수 있습니다.
계좌 객체는 출금할 수 있습니다.즉 데이터와 기능을 함께 묶습니다.
객체 = 데이터 + 기능예를 들어 계좌 객체는은 다음과 같습니다.
| 구성 | 예 |
|---|---|
| 데이터 | 계좌번호, 잔액, 소유자 |
| 기능 | 입금, 출금, 잔액조회 |
객체지향의 핵심 질문은 다음과 같습니다.
어떤 객체들이 있고, 그 객체들이 서로 어떻게 협력하는가?절차지향과 객체지향 비교
| 구분 | 절차지향 | 객체지향 |
|---|---|---|
| 중심 | 함수, 절차 | 객체 |
| 사고방식 | 순서대로 처리 | 객체들이 협력 |
| 데이터와 함수 | 따로 관리되는 경우 많음 | 하나로 묶음 |
| 장점 | 단순한 프로그램에 적합 | 큰 프로그램 설계에 유리 |
| 대표 언어 | C | Java, C++, C# |
절차지향 = 일의 순서 중심
객체지향 = 객체 중심C에서도 구조체와 함수를 이용해 객체지향 비슷한 설계를 할 수 있지만, Java나 C++는 객체지향 문법을 직접 제공합니다.
클래스와 객체
클래스란?
클래스는 객체를 만들기 위한 설계도입니다.
예를 들어 붕어빵 틀을 생각하자.
붕어빵 틀 = 클래스
실제 붕어빵 = 객체또 자동차 설계도를 생각해도 됩니다.
자동차 설계도 = 클래스
실제로 만들어진 자동차 = 객체프로그래밍에서는 클래스 안에 객체가 가질 데이터와 기능을 정의합니다.
class Student {
String name;
int score;
void study() {
System.out.println("공부한다");
}
}여기서 Student가 클래스입니다.
이 클래스는 학생 객체가 가져야 할 정보를 정의합니다.
name = 이름
score = 점수
study() = 공부하는 기능객체지향 출제범위에서도 클래스와 객체, 멤버변수와 메소드 선언, 객체 생성과 사용이 핵심 항목으로 들어 있습니다.
객체란?
객체는 클래스를 바탕으로 실제로 만들어진 대상입니다.
Student s1 = new Student();
Student s2 = new Student();여기서 s1, s2는 Student 클래스로 만든 객체입니다.
같은 설계도로 여러 객체를 만들 수 있습니다.
Student 클래스
├─ s1 객체
├─ s2 객체
└─ s3 객체각 객체는 자기만의 값을 가질 수 있습니다.
s1.name = "Kim";
s1.score = 90;
s2.name = "Lee";
s2.score = 80;둘 다 Student 객체지만, 내부 데이터는 다릅니다.
클래스와 객체 비교
| 구분 | 클래스 | 객체 |
|---|---|---|
| 의미 | 설계도 | 실제 만들어진 대상 |
| 메모리 | 클래스 자체는 설계 정보 | 객체는 메모리에 실제 생성 |
| 예 | Student | s1, s2 |
| 비유 | 붕어빵 틀 | 붕어빵 |
| 역할 | 어떤 데이터와 기능을 가질지 정의 | 실제 값을 가지고 동작 |
클래스 = 설계도
객체 = 설계도로 만든 실제 물건객체는 무엇으로 구성되는가?
객체는 보통 두 가지로 구성됩니다.
상태 + 동작멤버변수 + 메소드| 구분 | 뜻 | 예 |
|---|---|---|
| 멤버변수 | 객체가 가진 데이터, 상태 | 이름, 점수, 잔액 |
| 메소드 | 객체가 할 수 있는 기능, 동작 | 공부하기, 입금하기, 출력하기 |
class Account {
String owner;
int balance;
void deposit(int money) {
balance += money;
}
void withdraw(int money) {
balance -= money;
}
}owner, balance = 멤버변수
deposit(), withdraw() = 메소드객체지향 예시문제에서 “객체는 클래스와 메소드로 구성됩니다”라는 설명은 틀린 설명으로 나옵니다. 더 정확히는 객체는 클래스로부터 생성된 실체이며, 상태를 나타내는 데이터와 동작을 나타내는 메소드를 가진다고 이해해야 합니다.
메시지와 메소드
객체지향에서는 객체에게 일을 시키는 것을 메시지를 보냅니다고 표현하기도 합니다.
account.deposit(1000);이 코드는 account 객체에게 메시지를 보낸 것입니다.
“1000원을 입금해라.”실제로 실행되는 기능은 deposit 메소드입니다.
| 용어 | 의미 |
|---|---|
| 메시지 | 객체에게 어떤 일을 요청하는 것 |
| 메소드 | 그 요청을 처리하는 함수 |
객체에게 메시지를 보내면, 객체의 메소드가 실행됩니다.캡슐화와 정보은닉
캡슐화
캡슐화는 데이터와 기능을 하나로 묶는 것입니다.
class Account {
private int balance;
public void deposit(int money) {
balance += money;
}
public int getBalance() {
return balance;
}
}이 클래스는 계좌 잔액과 입금 기능을 하나로 묶고 있습니다.
balance 데이터
deposit 기능
getBalance 기능이것이 캡슐화입니다.
캡슐화의 목적은 단순히 묶는 것만이 아닙니다.
관련 있는 데이터와 기능을 하나로 묶고,
외부에서 함부로 내부 데이터를 건드리지 못하게 합니다.객체지향 출제범위에도 캡슐화와 정보은닉이 주요 개념으로 포함됩니다.
정보은닉
정보은닉은 객체 내부의 세부 정보를 외부에서 직접 보지 못하게 숨기는 것입니다.
예를 들어 계좌 잔액을 아무나 직접 바꾸면 위험합니다.
account.balance = -100000;이런 식으로 외부에서 마음대로 바꾸면 계좌가 이상해집니다.
그래서 balance를 private으로 숨깁니다.
private int balance;그리고 정해진 메소드를 통해서만 접근하게 합니다.
public void deposit(int money) {
if (money > 0) {
balance += money;
}
}이렇게 하면 잘못된 값이 들어가는 것을 막을 수 있습니다.
정보은닉 = 내부 데이터에 직접 접근하지 못하게 숨김캡슐화와 정보은닉은 같이 자주 나옵니다.
| 개념 | 핵심 |
|---|---|
| 캡슐화 | 데이터와 기능을 하나로 묶음 |
| 정보은닉 | 내부 구현과 데이터를 숨김 |
접근 제한자
정보은닉을 위해 접근 제한자를 사용합니다.
대표 접근 제한자는 다음과 같습니다.
private
protected
public| 접근 제한자 | 의미 |
|---|---|
private | 클래스 내부에서만 접근 가능 |
protected | 같은 클래스, 자식 클래스 등에서 접근 가능 |
public | 외부에서 접근 가능 |
class Student {
private int score;
public void setScore(int s) {
if (s >= 0 && s <= 100) {
score = s;
}
}
public int getScore() {
return score;
}
}여기서 score는 외부에서 직접 접근할 수 없습니다.
s.score = 200; // 불가능대신 메소드를 통해 접근합니다.
s.setScore(90);객체지향 출제범위에도 접근 제한으로 private, protected, public이 포함됩니다.
getter와 setter
객체의 private 변수에 접근하기 위해 자주 쓰는 메소드가 있습니다.
getter
settergetter
값을 가져오는 메소드입니다.
public int getScore() {
return score;
}setter
값을 설정하는 메소드입니다.
public void setScore(int s) {
if (s >= 0 && s <= 100) {
score = s;
}
}setter를 쓰면 잘못된 값을 막을 수 있습니다.
s.setScore(150);이런 값은 조건문으로 막을 수 있습니다.
즉 getter와 setter는 정보은닉을 유지하면서 안전하게 값을 읽고 바꾸는 방법입니다.
객체 생성과 멤버
생성자
생성자는 객체가 만들어질 때 자동으로 실행되는 특별한 메소드입니다.
객체를 초기화할 때 사용합니다.
class Student {
String name;
int score;
Student(String n, int s) {
name = n;
score = s;
}
}Student s1 = new Student("Kim", 90);이때 생성자가 자동으로 실행됩니다.
name = "Kim"
score = 90클래스 이름과 같습니다.
객체 생성 시 자동 호출됩니다.
주로 멤버변수 초기화에 사용됩니다.객체지향 출제범위에도 생성자와 소멸자가 포함되어 있습니다.
기본 생성자
매개변수가 없는 생성자를 기본 생성자라고 합니다.
class Student {
String name;
int score;
Student() {
name = "unknown";
score = 0;
}
}Student s = new Student();name = "unknown"
score = 0생성자를 따로 만들지 않으면 언어에 따라 기본 생성자가 자동 제공될 수 있습니다. 하지만 생성자를 직접 정의하면 기본 생성자가 자동으로 없어지는 경우도 있으므로 주의해야 합니다.
소멸자
소멸자는 객체가 사라질 때 호출되는 특별한 함수입니다.
C++에는 소멸자 개념이 명확합니다.
class Student {
public:
~Student() {
// 객체 소멸 시 실행
}
};Java에는 C++처럼 명시적인 소멸자를 직접 호출하는 방식보다는 가비지 컬렉션이 객체 메모리를 회수합니다.
정리하면 다음과 같습니다.
| 언어 | 객체 소멸 처리 |
|---|---|
| C++ | 소멸자 사용 |
| Java | 가비지 컬렉션 중심 |
시험에서는 깊게 들어가기보다 이렇게 잡으면 됩니다.
생성자 = 객체가 만들어질 때 초기화
소멸자 = 객체가 사라질 때 정리this
this는 현재 객체 자기 자신을 가리킵니다.
예를 살펴보겠습니다.
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}여기서 왼쪽 this.x는 객체의 멤버변수입니다.
오른쪽 x는 생성자의 매개변수입니다.
this.x = 현재 객체의 x
x = 매개변수 xthis = 현재 객체 자신객체지향 예시문제에도 Point 클래스에서 ( ).x = x; ( ).y = y;에 공통으로 들어갈 키워드를 묻고, 정답은 this입니다.
super
super는 부모 클래스를 가리킬 때 사용합니다.
Java에서 자식 클래스가 부모 클래스의 생성자나 메소드를 호출할 때 씁니다.
class Animal {
void sound() {
System.out.println("동물 소리");
}
}
class Dog extends Animal {
void sound() {
super.sound();
System.out.println("멍멍");
}
}super.sound();는 부모 클래스 Animal의 sound()를 호출합니다.
정리하면 다음과 같습니다.
| 키워드 | 의미 |
|---|---|
this | 현재 객체 |
super | 부모 객체 또는 부모 클래스 부분 |
객체지향 출제범위에도 this, super 키워드가 포함됩니다.
정적 멤버, static
정적 멤버는 객체마다 따로 존재하는 것이 아니라 클래스에 소속되는 멤버입니다.
class Student {
static int count = 0;
Student() {
count++;
}
}count는 모든 Student 객체가 공유합니다.
Student s1 = new Student();
Student s2 = new Student();Student.count = 2가 됩니다.
정리하면 다음과 같습니다.
| 구분 | 의미 |
|---|---|
| 인스턴스 변수 | 객체마다 따로 존재 |
| static 변수 | 클래스에 하나 존재, 모든 객체가 공유 |
| 인스턴스 메소드 | 객체를 통해 호출 |
| static 메소드 | 클래스 이름으로 호출 가능 |
Math.max(3, 5);이런 식으로 클래스 이름으로 호출하는 메소드가 static 메소드인 경우가 많습니다.
오버로딩
개념과 사용 예
오버로딩은 같은 이름의 메소드를 여러 개 정의하는 것입니다.
단, 매개변수의 개수나 자료형이 달라야 합니다.
class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
}모두 이름은 add입니다.
하지만 매개변수가 다릅니다.
add(1, 2)
add(1.5, 2.3)
add(1, 2, 3)컴파일러가 전달된 인수를 보고 어떤 메소드를 호출할지 결정합니다.
오버로딩 = 같은 이름, 다른 매개변수객체지향 출제범위에도 멤버함수 오버로드가 포함됩니다.
오버로딩 주의점
오버로딩은 반환형만 다르게 해서 만들 수 없습니다.
예를 들어 다음은 오버로딩으로 보기 어렵습니다.
int test(int a) {
return a;
}
double test(int a) {
return a;
}매개변수가 같고 반환형만 다릅니다.
test(3);라고 하면 어떤 것을 부를지 애매합니다.
그래서 오버로딩은 매개변수 목록이 달라야 합니다.
매개변수 개수, 자료형, 순서가 달라야 함상속과 오버라이딩
상속
상속은 기존 클래스의 멤버를 새로운 클래스가 물려받는 것입니다.
예를 들어 동물 클래스가 있다고 가정하겠습니다.
class Animal {
String name;
void eat() {
System.out.println("먹는다");
}
}강아지는 동물입니다.
class Dog extends Animal {
void bark() {
System.out.println("멍멍");
}
}Dog는 Animal을 상속받습니다.
그러면 Dog 객체는 Animal의 기능도 사용할 수 있습니다.
Dog d = new Dog();
d.eat();
d.bark();Animal = 부모 클래스, 상위 클래스, super class
Dog = 자식 클래스, 하위 클래스, sub class객체지향 출제범위에도 클래스 상속, 클래스 상속 선언, 생성자와 소멸자 호출 순서, 멤버함수 재정의, 추상 클래스가 포함됩니다.
상속의 장점
상속의 장점은 재사용입니다.
동물 종류가 여러 개 있다고 가정하겠습니다.
Dog
Cat
Bird공통 기능은 Animal에 넣습니다.
class Animal {
void eat() { ... }
void sleep() { ... }
}각 동물 고유 기능은 자식 클래스에 넣습니다.
class Dog extends Animal {
void bark() { ... }
}
class Cat extends Animal {
void meow() { ... }
}이렇게 하면 공통 코드를 반복해서 쓰지 않아도 됩니다.
상속 = 코드 재사용 + 계층 구조 표현객체지향 예시문제에서도 상속은 모듈 재사용과 코드의 간결성에 관련된 개념으로 제시됩니다.
is-a 관계
상속은 보통 is-a 관계일 때 사용합니다.
Dog is an Animal.
강아지는 동물입니다.이것은 자연스럽습니다.
class Dog extends Animal하지만 이런 것은 이상합니다.
Car is an Engine.
자동차는 엔진입니다.자동차는 엔진을 가지고 있는 것이지 엔진 자체는 아닙니다.
이것은 상속보다 포함 관계가 맞습니다.
has-a 관계class Car {
Engine engine;
}정리하면 다음과 같습니다.
| 관계 | 의미 | 구현 |
|---|---|---|
| is-a | ~는 ~입니다 | 상속 |
| has-a | ~는 ~를 가집니다 | 포함, 멤버변수 |
오버라이딩
오버라이딩은 부모 클래스의 메소드를 자식 클래스에서 다시 정의하는 것입니다.
class Animal {
void sound() {
System.out.println("동물 소리");
}
}
class Dog extends Animal {
void sound() {
System.out.println("멍멍");
}
}
class Cat extends Animal {
void sound() {
System.out.println("야옹");
}
}Animal에는 sound()가 있습니다.
그런데 Dog와 Cat이 각자 자기 방식으로 다시 정의합니다.
오버라이딩 = 부모 메소드를 자식이 재정의객체지향 출제범위에도 멤버함수 재정의, 즉 override가 포함되어 있습니다.
오버로딩과 오버라이딩 비교
이 둘은 이름이 비슷해서 자주 헷갈리기 쉽습니다.
| 구분 | 오버로딩 | 오버라이딩 |
|---|---|---|
| 의미 | 같은 이름의 메소드를 여러 개 정의 | 부모 메소드를 자식이 재정의 |
| 조건 | 매개변수 목록이 달라야 함 | 상속 관계가 필요 |
| 이름 | 같음 | 같음 |
| 매개변수 | 달라야 함 | 보통 같아야 함 |
| 목적 | 다양한 입력 처리 | 자식 클래스에 맞게 동작 변경 |
오버로딩 = 같은 이름, 다른 매개변수
오버라이딩 = 부모 것을 자식이 다시 정의다형성과 바인딩
다형성
다형성은 같은 이름의 명령이 객체에 따라 다르게 동작하는 성질입니다.
많은 형태를 가질 수 있음Animal a1 = new Dog();
Animal a2 = new Cat();
a1.sound();
a2.sound();멍멍
야옹변수 타입은 둘 다 Animal처럼 보이지만, 실제 객체가 Dog냐 Cat이냐에 따라 실행되는 메소드가 다릅니다.
이것이 다형성입니다.
객체지향 예시문제에서도 다형성은 “하나의 인터페이스를 이용하여 서로 다른 구현 방법을 제공하는 개념”이며, Java에서는 상속, 추상 클래스, 동적 바인딩 등을 통해, C++에서는 가상함수까지 사용하여 구현된다고 나옵니다.
다형성이 왜 중요한가?
다형성이 없으면 객체 종류마다 따로 처리해야 합니다.
Dog d = new Dog();
Cat c = new Cat();
d.sound();
c.sound();동물이 많아지면 코드가 복잡해집니다.
다형성을 쓰면 공통 부모 타입으로 처리할 수 있습니다.
Animal[] animals = {
new Dog(),
new Cat(),
new Bird()
};
for (Animal a : animals) {
a.sound();
}각 객체가 자기 방식으로 sound()를 실행합니다.
같은 명령 sound()
→ Dog는 멍멍
→ Cat은 야옹
→ Bird는 짹짹즉 다형성은 코드 확장성을 높입니다.
동적 바인딩
바인딩은 어떤 메소드 호출이 실제 어떤 메소드 실행으로 연결되는지 결정하는 것입니다.
정적 바인딩
컴파일 시점에 결정됩니다.
컴파일할 때 어떤 함수가 호출될지 결정동적 바인딩
실행 시점에 실제 객체를 보고 결정됩니다.
Animal a = new Dog();
a.sound();컴파일 시점에는 a가 Animal 타입입니다.
하지만 실행 시점에 실제 객체는 Dog다.
그래서 Dog의 sound()가 실행됩니다.
동적 바인딩 = 실행 중 실제 객체 타입에 따라 메소드 결정다형성은 동적 바인딩과 밀접합니다.
객체지향 출제범위에도 메소드의 동적 바인딩이 포함됩니다.
C++의 가상함수
C++에서는 다형성을 위해 virtual 키워드를 사용합니다.
class Animal {
public:
virtual void sound() {
cout << "동물 소리";
}
};
class Dog : public Animal {
public:
void sound() override {
cout << "멍멍";
}
};Animal* a = new Dog();
a->sound();virtual이 있으면 Dog의 sound()가 실행됩니다.
객체지향 출제범위에서도 C++의 가상함수 선언이 다형성 항목에 포함됩니다.
추상 클래스와 인터페이스
추상 클래스
추상 클래스는 완성되지 않은 클래스로, 직접 객체를 만들 수 없고 자식 클래스가 구현해야 할 메소드를 가질 수 있습니다.
abstract class Animal {
abstract void sound();
void eat() {
System.out.println("먹는다");
}
}abstract void sound();는 몸체가 없습니다.
자식 클래스에서 반드시 구현해야 합니다.
class Dog extends Animal {
void sound() {
System.out.println("멍멍");
}
}추상 클래스 = 일부 메소드를 자식이 구현하도록 남겨둔 클래스직접 객체 생성은 불가능합니다.
Animal a = new Animal(); // 불가능하지만 자식 객체는 만들 수 있습니다.
Animal a = new Dog(); // 가능인터페이스
인터페이스는 클래스가 반드시 구현해야 할 기능 목록을 정한 약속입니다.
interface Flyable {
void fly();
}이 인터페이스를 구현하는 클래스는 fly()를 반드시 구현해야 합니다.
class Bird implements Flyable {
public void fly() {
System.out.println("새가 난다");
}
}인터페이스는 “이런 기능을 제공해야 합니다”는 규칙입니다.
인터페이스 = 기능의 약속객체지향 출제범위에도 Java의 인터페이스 선언, 인터페이스 상속, 인터페이스 다중 상속이 포함됩니다.
추상 클래스와 인터페이스 비교
| 구분 | 추상 클래스 | 인터페이스 |
|---|---|---|
| 목적 | 공통 기능과 미완성 기능을 함께 제공 | 구현해야 할 기능 목록 제시 |
| 객체 생성 | 직접 생성 불가 | 직접 생성 불가 |
| 일반 메소드 | 가질 수 있음 | 언어 버전에 따라 가능 |
| 변수 | 상태를 가질 수 있음 | 보통 상수 중심 |
| 상속/구현 | extends | implements |
| 관계 | is-a 관계에 가까움 | can-do, 할 수 있는 기능에 가까움 |
Dog extends Animal
Dog implements Runnable
Bird implements Flyable추상 클래스 = 미완성 부모 클래스
인터페이스 = 기능 약속Java의 단일 상속과 인터페이스
Java는 클래스 다중 상속을 허용하지 않습니다.
즉 한 클래스가 여러 클래스를 동시에 상속받을 수 없습니다.
class C extends A, B // 불가능하지만 인터페이스는 여러 개 구현할 수 있습니다.
class Bird implements Flyable, Runnable {
...
}C++는 클래스 다중 상속을 지원합니다.
객체지향 출제범위에도 Java의 인터페이스 다중 상속과 C++의 클래스 다중 상속이 포함됩니다.
언어별 객체지향 요소
패키지와 네임스페이스
클래스가 많아지면 이름 충돌이 생길 수 있습니다.
예를 들어 Student라는 클래스가 여러 프로젝트에 있을 수 있습니다.
그래서 관련 클래스를 묶는 방법이 필요합니다.
Java에서는 패키지를 사용합니다.
package school;C++에서는 네임스페이스를 사용합니다.
namespace school {
class Student { ... };
}정리하면 다음과 같습니다.
| 언어 | 클래스 그룹핑 |
|---|---|
| Java | 패키지 |
| C++ | 네임스페이스 |
객체지향 출제범위에도 클래스 그룹핑으로 Java의 패키지, C++의 네임스페이스가 포함됩니다.
템플릿과 제네릭
자료형이 달라도 같은 구조를 쓰고 싶을 때가 있습니다.
정수 리스트
문자열 리스트
학생 리스트모두 구조는 비슷합니다.
C++에서는 템플릿을 사용합니다.
template <typename T>
class Box {
T value;
};Java에서는 제네릭을 사용합니다.
class Box<T> {
T value;
}객체지향 출제범위에도 C++ 템플릿과 Java 제네릭이 포함됩니다.
자료구조 라이브러리에서도 자주 나옵니다.
ArrayList<String>
HashMap<String, Integer>객체지향 라이브러리
객체지향 언어에는 이미 만들어진 클래스 라이브러리가 많습니다.
String
StringBuffer
ArrayList
LinkedList
HashMap
FileReader
FileWriter같은 클래스가 있습니다.
string
vector<T>
list<T>
ifstream
ofstream같은 클래스와 라이브러리가 있습니다.
객체지향 출제범위에도 화면 입출력, 문자열, 파일 입출력, 자료구조 관련 기본 함수 및 클래스 라이브러리가 포함됩니다.
String과 StringBuffer
Java 문자열에서 자주 나오는 개념입니다.
String
StringBufferString
문자열을 저장합니다.
String s = "ABC";String은 한 번 만들어진 문자열이 바뀌지 않는 성질, 즉 불변성을 가집니다.
StringBuffer
문자열을 계속 변경할 때 사용합니다.
StringBuffer sb = new StringBuffer("ABC");
sb.append("DEF");객체지향 예시문제에서도 Java에서 상수 문자열을 사용할 때는 String, 계속 변하는 문자열을 사용할 때는 StringBuffer를 사용한다고 나옵니다.
String = 고정 문자열
StringBuffer = 자주 바뀌는 문자열예외 처리
예외는 프로그램 실행 중 발생하는 비정상 상황입니다.
0으로 나누기
배열 범위 초과
파일 없음
입력 오류
널 포인터 접근예외 처리는 이런 문제를 안전하게 처리하는 방법입니다.
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("0으로 나눌 수 없습니다.");
}| 키워드 | 의미 |
|---|---|
try | 예외가 발생할 수 있는 코드 |
catch | 예외를 잡아 처리 |
throw | 예외를 던짐 |
finally | 예외 여부와 관계없이 실행 |
객체지향 출제범위에도 예외 처리 개념, 예외 클래스, throw, catch 처리가 포함됩니다.
정리와 예제
객체지향 4대 핵심 개념
객체지향에서 특히 중요한 것은 보통 다음 네 가지입니다.
추상화
캡슐화
상속
다형성추상화
중요한 특징만 뽑아 표현하는 것입니다.
예를 들어 자동차를 프로그램으로 표현할 때 모든 부품을 다 넣지는 않습니다.
속도
색상
주행 기능
정지 기능같이 필요한 것만 뽑습니다.
캡슐화
데이터와 기능을 하나로 묶습니다.
상속
부모 클래스의 기능을 자식 클래스가 물려받습니다.
다형성
같은 메소드 호출이 객체에 따라 다르게 동작합니다.
객체지향 개념 시험형 정리
객체지향 예시문제에는 이런 형태가 나옵니다.
보기 1
다형성 - 하나의 인터페이스를 이용하여 서로 다른 구현 방법을 제공이것은 맞습니다.
보기 2
객체 - 클래스와 메소드로 구성이것은 부정확합니다.
객체는 클래스로부터 생성된 실체이고, 상태와 동작을 가집니다.
보기 3
상속 - 모듈 재사용과 코드 간결성이것은 맞습니다.
보기 4
캡슐화 - 정보은닉 방법 이용이것도 맞는 설명입니다.
따라서 “거리가 먼 것”을 고르는 문제에서는 객체를 “클래스와 메소드로 구성”한다고 한 설명이 틀립니다.
예제 코드
예제 코드: 클래스와 객체
Java 스타일로 살펴보겠습니다.
class Student {
String name;
int score;
void printInfo() {
System.out.println(name + " " + score);
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student();
s.name = "Kim";
s.score = 90;
s.printInfo();
}
}Kim 90분석은 다음과 같습니다.
| 코드 | 의미 |
|---|---|
class Student | Student 클래스 정의 |
String name | 이름 멤버변수 |
int score | 점수 멤버변수 |
printInfo() | 정보 출력 메소드 |
new Student() | Student 객체 생성 |
s.printInfo() | 객체의 메소드 호출 |
예제 코드: 캡슐화
class Account {
private int balance;
public void deposit(int money) {
if (money > 0) {
balance += money;
}
}
public int getBalance() {
return balance;
}
}Account acc = new Account();
acc.deposit(1000);
System.out.println(acc.getBalance());1000여기서 balance는 private입니다.
외부에서 직접 바꿀 수 없습니다.
acc.balance = -10000; // 불가능이것이 정보은닉입니다.
예제 코드: 상속과 오버라이딩
class Animal {
void sound() {
System.out.println("동물 소리");
}
}
class Dog extends Animal {
void sound() {
System.out.println("멍멍");
}
}
class Cat extends Animal {
void sound() {
System.out.println("야옹");
}
}Animal a1 = new Dog();
Animal a2 = new Cat();
a1.sound();
a2.sound();멍멍
야옹여기에는 세 개념이 들어 있습니다.
| 개념 | 코드 |
|---|---|
| 상속 | Dog extends Animal |
| 오버라이딩 | sound() 재정의 |
| 다형성 | Animal 타입으로 Dog, Cat 객체 사용 |
개념 연결
객체지향과 자료구조 연결
객체지향은 자료구조와도 연결됩니다.
예를 들어 3장 3절에서 노드를 구조체로 만들었습니다.
struct Node {
int data;
struct Node *next;
};객체지향 스타일로는 Node 클래스를 만들 수 있습니다.
class Node {
int data;
Node next;
}스택도 클래스로 만들 수 있습니다.
class Stack {
int[] data;
int top;
void push(int x) { ... }
int pop() { ... }
}즉 객체지향은 자료구조를 더 깔끔하게 묶어 표현할 수 있습니다.
Stack 객체 = 데이터 배열 + push/pop 기능
Queue 객체 = 데이터 배열 + enqueue/dequeue 기능
Tree 객체 = root + 순회 기능객체지향과 웹 연결
웹프로그래밍에서도 객체 개념이 나옵니다.
JavaScript에서는 객체를 이렇게 만들 수 있습니다.
var customer = {
name: "홍길동",
age: 23
};웹프로그래밍 예시문제에도 JavaScript 객체 선언 문제가 나오고, 속성 이름과 값은 :로 연결하며 { }를 사용한 객체 리터럴 형식이 올바른 선언입니다.
즉 객체 개념은 Java나 C++에만 있는 것이 아닙니다.
Java 객체
C++ 객체
JavaScript 객체
DOM 객체웹의 DOM도 HTML 문서를 객체처럼 다루는 구조입니다.
이 내용은 6장 3절에서 다시 다룹니다.
자주 혼동되는 출제 포인트
혼동 포인트 1. 클래스와 객체 구분
클래스 = 설계도
객체 = 실제 생성된 대상클래스 자체를 객체라고 착각하면 안 됩니다.
혼동 포인트 2. 객체는 클래스와 메소드로 구성된다는 표현은 부정확합니다
객체는 클래스로부터 생성된 실체이고, 상태와 동작을 가집니다. 객체지향 예시문제에서도 이 설명이 틀린 보기로 나옵니다.
혼동 포인트 3. 캡슐화와 정보은닉
캡슐화 = 데이터와 기능을 묶음
정보은닉 = 내부 정보를 숨김둘은 관련 있지만 완전히 같은 말은 아닙니다.
혼동 포인트 4. private, protected, public 구분
private = 클래스 내부
protected = 자식 클래스 등
public = 외부 접근 가능혼동 포인트 5. this
this = 현재 객체 자신멤버변수와 매개변수 이름이 같을 때 자주 씁니다.
this.x = x;혼동 포인트 6. 오버로딩과 오버라이딩
오버로딩 = 같은 이름, 다른 매개변수
오버라이딩 = 부모 메소드를 자식이 재정의혼동 포인트 7. 상속은 is-a 관계일 때 적절합니다
Dog is an Animal → 상속 적절
Car has an Engine → 포함 관계가 적절혼동 포인트 8. 다형성
다형성 = 하나의 인터페이스로 서로 다른 구현 제공객체지향 예시문제에서도 다형성의 정의가 이 형태로 나옵니다.
혼동 포인트 9. 추상 클래스는 직접 객체 생성 불가
Animal a = new Animal(); // 추상 클래스면 불가능자식 클래스가 구현해야 합니다.
혼동 포인트 10. StringBuffer
Java에서 계속 변하는 문자열을 다룰 때는 StringBuffer를 사용한다는 문제가 출제됩니다.
이번 절의 핵심 정리
클래스
객체를 만들기 위한 설계도객체
클래스로부터 생성된 실제 대상
상태와 동작을 가짐멤버변수
객체의 상태, 데이터메소드
객체의 동작, 기능캡슐화
데이터와 기능을 하나로 묶음정보은닉
내부 데이터와 구현을 외부에서 직접 접근하지 못하게 숨김접근 제한자
private
protected
public생성자
객체 생성 시 자동 호출되어 초기화 수행this
현재 객체 자신super
부모 클래스 부분오버로딩
같은 이름의 메소드를 매개변수를 다르게 하여 여러 개 정의오버라이딩
부모 클래스의 메소드를 자식 클래스에서 다시 정의상속
부모 클래스의 속성과 기능을 자식 클래스가 물려받음다형성
같은 명령이 객체에 따라 다르게 동작
하나의 인터페이스로 서로 다른 구현 제공추상 클래스
일부 메소드 구현을 자식에게 맡기는 미완성 클래스인터페이스
구현해야 할 기능의 약속동적 바인딩
실행 시점에 실제 객체 타입에 따라 호출 메소드가 결정됨핵심 한 문장
이번 절의 핵심을 한 문장으로 정리하면 다음과 같습니다.
객체지향프로그래밍은 프로그램을 객체들의 협력으로 바라보며, 클래스라는 설계도로 객체를 만들고, 캡슐화와 정보은닉으로 데이터를 보호하며, 상속과 다형성을 이용해 코드를 재사용하고 확장성 있게 설계하는 방법입니다.
클래스 = 설계도
객체 = 실제 대상
캡슐화 = 묶고 숨김
상속 = 물려받음
다형성 = 같은 명령, 다른 동작확인 문제
문제 1
클래스의 의미로 가장 알맞은 것은?
① 객체를 만들기 위한 설계도 ② 실행 중인 프로그램 ③ 메모리 주소를 저장하는 변수 ④ CPU 내부의 레지스터
문제 2
객체의 의미로 가장 알맞은 것은?
① 클래스로부터 생성된 실제 대상 ② 소스 코드를 컴파일하는 장치 ③ HTML 문서의 제목 태그 ④ 운영체제의 스케줄링 알고리즘
문제 3
객체가 가지는 데이터, 즉 상태를 나타내는 것은?
① 멤버변수 ② 패키지 ③ 인터럽트 ④ 버스
문제 4
객체가 수행할 수 있는 기능이나 동작을 나타내는 것은?
① 메소드 ② 페이지 폴트 ③ 세마포어 ④ 해시 함수
문제 5
데이터와 기능을 하나로 묶는 객체지향 개념은?
① 캡슐화 ② 교착상태 ③ 페이징 ④ 후위순회
문제 6
객체 내부의 데이터와 구현을 외부에서 직접 접근하지 못하게 숨기는 개념은?
① 정보은닉 ② 버블 정렬 ③ 캐시 미스 ④ 주소 지정
문제 7
클래스 내부에서만 접근 가능하게 하는 접근 제한자는?
① public ② private ③ static ④ final
문제 8
객체가 생성될 때 자동으로 호출되어 초기화를 수행하는 것은?
① 생성자 ② 소멸자 ③ 분기문 ④ 반복문
문제 9
현재 객체 자신을 가리키는 키워드는?
① this ② super ③ that ④ parent
문제 10
부모 클래스의 멤버나 생성자를 가리킬 때 사용하는 Java 키워드는?
① this ② super ③ self ④ main
문제 11
같은 이름의 메소드를 매개변수의 개수나 자료형을 다르게 하여 여러 개 정의하는 것은?
① 오버로딩 ② 오버라이딩 ③ 세그멘테이션 ④ 동기화
문제 12
부모 클래스의 메소드를 자식 클래스에서 다시 정의하는 것은?
① 오버로딩 ② 오버라이딩 ③ 해싱 ④ 캐싱
문제 13
상속의 의미로 가장 알맞은 것은?
① 부모 클래스의 속성과 기능을 자식 클래스가 물려받는 것 ② 메모리를 페이지로 나누는 것 ③ CPU를 시간 단위로 나누는 것 ④ 배열을 정렬하는 것
문제 14
다형성의 의미로 가장 알맞은 것은?
① 하나의 인터페이스로 서로 다른 구현 방법을 제공하는 것 ② 모든 객체가 같은 데이터만 갖는 것 ③ 클래스 이름을 반드시 하나로 고정하는 것 ④ 변수를 전부 전역변수로 만드는 것
문제 15
실행 시점에 실제 객체 타입에 따라 호출될 메소드가 결정되는 것은?
① 동적 바인딩 ② 정적 배열 ③ 직접 주소지정 ④ FIFO
문제 16
추상 클래스에 대한 설명으로 알맞은 것은?
① 직접 객체를 만들 수 없고 자식 클래스가 일부 메소드를 구현해야 할 수 있습니다 ② 항상 final 변수만 가집니다 ③ 운영체제의 파일 시스템입니다 ④ 스택의 top을 저장합니다
문제 17
인터페이스의 의미로 알맞은 것은?
① 구현해야 할 기능의 약속 ② 물리 메모리의 조각 ③ 그래프의 간선 수 ④ 2진수의 보수
문제 18
다음 중 오버로딩의 조건으로 가장 알맞은 것은?
① 메소드 이름은 같고 매개변수 목록이 달라야 합니다 ② 메소드 이름은 반드시 달라야 합니다 ③ 반환형만 다르면 무조건 가능합니다 ④ 상속 관계가 반드시 있어야 합니다
문제 19
Java에서 계속 변하는 문자열을 다룰 때 사용하는 클래스로 알맞은 것은?
① StringBuffer ② StringSet ③ StringFormat ④ StringList
문제 20
객체지향의 주요 개념과 거리가 먼 설명은?
① 다형성은 하나의 인터페이스로 서로 다른 구현을 제공합니다 ② 상속은 코드 재사용에 도움을 줍니다 ③ 캡슐화는 정보은닉과 관련됩니다 ④ 객체는 클래스와 메소드로 구성된다는 표현이 정확합니다
정답과 해설은 절별 확인문제 정답해설에서 확인합니다.
다음 6장 2절은 웹 구조, HTTP, HTML, CSS입니다. 6장 1절이 프로그램을 객체 단위로 설계하는 방법이었다면, 6장 2절은 웹페이지가 클라이언트와 서버 사이에서 어떻게 오가고, HTML과 CSS로 어떻게 구조와 디자인을 만드는지 배웁니다.