클래스
- 클래스란 : 객체 생성을 위한 틀
- 붕어빵 틀 (클래스) : 붕어빵 (객체)
- 객체지향의 기본 모토 : 현실세계에 존재하는 모든 것을 프로그램의 객체로 구현할 수 있다.
- 객체는 프로그램 안에서 사용할 수 있어야 한다. 객체화시키기위한 도구가 클래스이다.
class 붕어빵 {
속재료변수;
피재료변수;
붕어빵만들기(){}
}
붕어빵 a = new 붕어빵(); -> 붕어빵 객체
클래스의 구성 요소
- 멤버 변수(클래스 변수) - 데이터(값) 저장 용도
- 메소드 - 기능
클래스 만들기
public class Student {
String hakbun, name;
int kor, eng, mat;
double tot, avg;
void sum() {
this.tot = kor + eng + mat;
}
void average() {
this.avg = this.tot / 3.0;
}
void output() {
System.out.println("이름: " + this.name + "총점: " + this.tot + "평균: " + this.avg);
}
}
클래스 사용
public class StudentMain {
public static void main(String[] args) {
Student st = new Student();
st.hakbun = "2122222";
st.name = "홍동우";
st.kor = 100;
st.eng = 70;
st.mat = 50;
st.sum();
st.average();
st.output();
}
}
- 문제점
- 외부에서 멤버변수에 직접 접근할 수 있기 때문에 보안상 취약하다.
private, setter, getter
- 외부에서 멤버변수에 접근할 수 없도록 private 키워드를 붙여 선언한다. 이렇게 하면 자기 클래스 내부에서만 멤버변수에 접근할 수 있게 된다.
- private 멤버변수에 접근할 수 있는 setter와 getter 를 만든다.
public class Student {
private String hakbun, name;
private int kor, eng, mat;
private double tot, avg;
void sum() {
this.tot = kor + eng + mat;
}
void average() {
this.avg = this.tot / 3.0;
}
void output() {
System.out.println("이름: " + this.name + " 총점: " + this.tot + " 평균: " + this.avg);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
한꺼번에 getter/setter 만들기
- 멤버변수 영역 block 잡기 → source → generate Getters and Setters → generate
멤버변수 값 한번에 setting
- 세팅이 필요한 멤버변수를 한꺼번에 세팅할 수 있는 메소드 setStudent 만들기
public void setStudent(String hakbun, String name, int kor, int eng, int mat) {
this.hakbun = hakbun;
this.name = name;
this.kor = kor;
this.eng = eng;
this.mat = mat;
}
public static void main(String[] args) {
Student st = new Student();
st.setStudent("1234566", "홍동우", 100, 90, 70);
st.sum();
st.average();
st.output();
}
생성자(함수) ⭐
- 클래스를 가지고 객체를 생성하기 위한 특수한 함수
- 반드시 클래스명과 일치해야 한다.
- JVM이 자동 호출한다.
- 사용자가 생성자를 정의하지 않는 경우, 기본 생성자가 추가된다. (기본 생성자 함수)
- 생성자가 오버로딩된 경우, 기본 생성자를 사용하고자 한다면 수동으로 추가해주어야 한다. (오버로딩 시 생략된 기본 생성자를 덮어씌우기 때문!)
- 오버로딩된 다른 생성자를 호출할 때는 this()로 호출하고, 생성자 내의 가장 첫 명령에 사용한다.
- 인스턴스(객체)를 생성할 때 2가지를 결정해야 한다.
- 어떤 클래스를 생성할 것인가?
- 선택한 클래스의 어떤 생성자로 인스턴스를 생성할 것인가?
생성자 함수 오버로딩
public class Student {
public Student() {
}
public Student(String hakbun, String name, int kor, int eng, int mat) {
this.hakbun = hakbun;
this.name = name;
this.kor = kor;
this.eng = eng;
this.mat = mat;
}
}
Student st = new Student("1234566", "홍동우", 100, 90, 70);
생성자 내부에서 또 다른 생성자 호출
- 생성자 내부에서 또 다른 생성자(오버로딩된 생성자)를 호출할 때는 this() 를 사용한다.
public class Car {
String color;
String gearType;
int door;
Car() {
this("white", "auto", 3);
System.out.println("기본생성자");
}
Car(String color) {
this(color, "stick", 5);
System.out.println("색상값만 지정");
}
Car(String color, String gearType, int door) {
this.color = color;
this.gearType = gearType;
this.door = door;
}
}
public class CarMain {
public static void main(String[] args) {
Car c1 = new Car("blue", "auto", 4);
Car c2 = new Car();
Car c3 = new Car("black");
System.out.println(c1.color + c1.gearType + c1.door);
System.out.println(c2.color + c2.gearType + c2.door);
System.out.println(c3.color + c3.gearType + c3.door);
}
}
구매-판매 클래스 만들기
판매자 클래스
public class FruitSeller {
int numOfApple;
int myMoney;
final int APPLE_PRICE;
public FruitSeller (int money, int appleNumber, int price) {
this.myMoney = money;
this.numOfApple = appleNumber;
this.APPLE_PRICE = price;
}
public int saleApple(int money) {
int num = money / APPLE_PRICE;
numOfApple -= num;
myMoney += money;
return num;
}
public void showSaleResult () {
System.out.println("남은 사과: " + numOfApple);
System.out.println("판매 수익: " + myMoney);
}
}
구매자 클래스
public class FruitBuyer {
int numOfApple;
int myMoney;
public FruitBuyer(int money) {
this.myMoney = money;
this.numOfApple = 0;
}
public void showBuyResult () {
System.out.println("구입한 사과: " + numOfApple);
System.out.println("현재 잔액: " + myMoney);
}
public void buyApple(FruitSeller seller, int money) {
numOfApple += seller.saleApple(money);
myMoney -= money;
}
}
메인 클래스
public class FruitSaleMain {
public static void main(String[] args) {
FruitSeller seller1 = new FruitSeller(0, 100, 1500);
FruitSeller seller2 = new FruitSeller(0, 300, 2000);
FruitBuyer buyer = new FruitBuyer(100000);
buyer.buyApple(seller1, 5000);
buyer.buyApple(seller2, 8000);
System.out.println("판매자 1 현재상황");
seller1.showSaleResult();
System.out.println("판매자 2 현재상황");
seller2.showSaleResult();
System.out.println("구매자 현재상황");
buyer.showBuyResult();
}
}

상속
- 부모는 자식이다!
- 자식 —/→ 부모
- 자식은 부모타입으로 치환(사용)가능하다! ⭐ → 이것 때문에 상속구조를 사용
- 상속 ⇒ 자식을 부모타입으로 치환하기 위해 사용하는 것 → 유지보수가 편리해진다
- 부모 타입을 여러 개의 자식 타입으로 사용할 수 있는 것 ⇒ 다형성
오버라이딩
- 부모로부터 상속받은 메소드를 자식이 재정의하여 사용하는 것
<A> a, a()
<B> b, b()
A a = new A(); // a.a, a.a()
B b = new B(); // b.b, b.b() b.a, b.a()
A c = new B(); // c.a, c.a() [b의 변수와 메소드는 사용할 수 없음]
→ B는 A를 상속

주소록 만들기 실습
상속구조
- HighFriend와 UnivFriend 클래스는 Friend 클래스를 상속한다. 따라서 두 클래스는 Friend 타입으로 치환될 수 있다.
- FriendInfoHandler 클래스는 주소록 기능을 담당한다. 주소록에 친구 추가, 주소록에 저장된 친구 정보를 출력한다. 입력받은 정보로 Friend 객체를 생성해 myFriends 배열에 추가한다.
- Main클래스에서는 FriendInfoHandler 객체를 생성해 친구 추가, 친구정보 출력 등의 메소드를 호출한다.


Friend 클래스 (부모 클래스)
public class Friend {
String name;
String phoneNum;
String addr;
public Friend(String name, String phone, String addr) {
this.name = name;
this.phoneNum = phone;
this.addr = addr;
}
public void showData() {
System.out.println("이름: " + name);
System.out.println("전화: " + phoneNum);
System.out.println("주소: " + addr);
}
public void showBasicInfo() {
}
}
UnivFriend 클래스
public class UnivFriend extends Friend{
String major;
public UnivFriend(String name, String phone, String addr, String major) {
super(name, phone, addr);
this.major = major;
}
public void showData() {
super.showData();
System.out.println("전공: " + major);
}
public void showBasicInfo() {
System.out.println("이름: " + name);
System.out.println("전화: " + phoneNum);
}
}
HighFriend 클래스
public class HighFriend extends Friend{
String work;
public HighFriend(String name, String phone, String addr, String job) {
super(name, phone, addr);
this.work = job;
}
public void showData() {
super.showData();
System.out.println("직업: " + work);
}
public void showBasicInfo() {
System.out.println("이름: " + name);
System.out.println("전화: " + phoneNum);
}
}
FriendInfoHandler 클래스
import java.util.Scanner;
public class FriendInfoHandler {
private Friend[] myFriends;
private int numOfFriends;
public FriendInfoHandler(int num) {
myFriends = new Friend[num];
numOfFriends = 0;
}
private void addFriendInfo(Friend fren) {
myFriends[numOfFriends++] = fren;
}
public void addFriend(int choice) {
String name, phoneNum, addr, work, major;
Scanner sc = new Scanner(System.in);
System.out.print("이름: "); name = sc.nextLine();
System.out.print("전화: "); phoneNum = sc.nextLine();
System.out.print("주소: "); addr = sc.nextLine();
if (choice == 1) {
System.out.print("직업: "); work = sc.nextLine();
this.addFriendInfo(new HighFriend(name, phoneNum, addr, work));
} else {
System.out.print("전공: "); major = sc.nextLine();
this.addFriendInfo(new UnivFriend(name, phoneNum, addr, major));
}
System.out.println("입력 완료!");
}
public void showAllData() {
for (int i=0; i<numOfFriends; i++) {
myFriends[i].showData();
}
}
public void showAllSimpleData() {
for (int i=0; i<numOfFriends; i++) {
myFriends[i].showBasicInfo();
}
}
}
MyFriendInfoBook 클래스
public class MyFriendInfoBook {
public static void main(String[] args) {
FriendInfoHandler handler = new FriendInfoHandler(3);
while(true) {
System.out.println("1. 고교 친구 저장");
System.out.println("2. 대학 친구 저장");
System.out.println("3. 전체 정보 출력");
System.out.println("4. 기본 정보 출력");
System.out.println("5. 프로그램 종료");
System.out.print("선택 >>");
Scanner sc = new Scanner(System.in);
int choice = sc.nextInt();
switch (choice) {
case 1: case 2:
handler.addFriend(choice);
break;
case 3:
handler.showAllData();
break;
case 4:
handler.showAllSimpleData();
break;
case 5:
System.out.println("프로그램을 종료합니다.");
break;
}
}
}
}
Item 실습
package oop.item;
import java.util.Scanner;
public class MainTest {
public static void main(String[] args) {
ItemHandler itemHandler = new ItemHandler(3);
while (true) {
System.out.println("1. CD 구매");
System.out.println("2. DVD 구매");
System.out.println("3. 책 구매");
System.out.println("4. 전체 정보 출력");
System.out.println("5. 프로그램 종료");
System.out.println("선택 >> ");
Scanner sc = new Scanner(System.in);
int choice = sc.nextInt();
switch (choice) {
case 1: case 2: case 3:
itemHandler.addItem(choice);
break;
case 4:
itemHandler.showAllData();
break;
case 5:
System.out.println("프로그램을 종료합니다.");
return;
}
}
}
}
package oop.item;
import java.util.Scanner;
public class ItemHandler {
private Item[] myItems;
private int numOfItems;
public ItemHandler(int num){
myItems = new Item[num];
numOfItems = 0;
}
private void addItemInfo(Item I) {
myItems[numOfItems++] = I;
}
public void addItem(int choice) {
int itemNo, price, trackNum, runtime, pageNum;
String title, singer, actor, name, outDate;
Scanner sc = new Scanner(System.in);
System.out.println("제품번호: "); itemNo = Integer.parseInt(sc.nextLine());
System.out.println();
System.out.println("이름: "); title = sc.nextLine();
System.out.println();
System.out.println("가격: "); price = Integer.parseInt(sc.nextLine());
if (choice == 1) {
System.out.println("가수: "); singer = sc.nextLine();
System.out.println("트랙수: "); trackNum = Integer.parseInt(sc.nextLine());
System.out.println("출고일자: "); outDate = sc.nextLine();
this.addItemInfo(new CDItem(itemNo, title, price, singer, trackNum, outDate));
} else if (choice == 2) {
System.out.println("주연배우: "); actor = sc.nextLine();
System.out.println("상영시간: "); runtime = Integer.parseInt(sc.nextLine());
System.out.println("출고일자: "); outDate = sc.nextLine();
this.addItemInfo(new DVDItem(itemNo, title, price, actor, runtime, outDate));
} else {
System.out.println("저자명: "); name = sc.nextLine();
System.out.println("쪽수: "); pageNum = Integer.parseInt(sc.nextLine());
System.out.println("출고일자: "); outDate = sc.nextLine();
this.addItemInfo(new BookItem(itemNo, title, price, name, pageNum, outDate));
}
System.out.println("입력 완료!");
}
public void showAllData() {
for (int i=0; i<numOfItems; i++) {
myItems[i].output();
}
}
}
package oop.item;
public class BookItem extends Item{
private String name, outDate;
private int pageNum;
public BookItem(int itemNo, String title, int price, String name, int pageNum, String outDate){
super(itemNo, title, price);
this.name = name;
this.pageNum = pageNum;
this.outDate = outDate;
}
public void output() {
super.output();
System.out.println("저자명: " + name);
System.out.println("쪽수: " + pageNum);
System.out.println("출고일자: " + outDate);
}
}
package oop.item;
public class CDItem extends Item {
private String singer;
private int trackNum;
private String outDate;
public CDItem(int itemNo, String title, int price, String singer, int trackNum, String outDate) {
super(itemNo, title, price);
this.singer = singer;
this.outDate = outDate;
this.trackNum = trackNum;
}
public void output() {
super.output();
System.out.println("가수: " + singer);
System.out.println("트랙수: " + trackNum);
System.out.println("출고일자: " + outDate);
}
}
package oop.item;
public class DVDItem extends Item {
private String actor, outDate;
private int runtime;
public DVDItem(int itemNo, String title, int price, String actor, int runtime, String outDate) {
super(itemNo, title, price);
this.actor = actor;
this.runtime = runtime;
this.outDate = outDate;
}
public void output() {
super.output();
System.out.println("주연배우: " + actor);
System.out.println("상영시간: " + runtime);
System.out.println("출고일자: " + outDate);
}
}
package oop.item;
public class Item {
private int itemNo;
private String title;
private int price;
public Item(int itemNo, String title, int price) {
this.itemNo = itemNo;
this.title = title;
this.price = price;
}
public void output() {
System.out.println("제품번호: " + itemNo);
System.out.println("이름: " + title);
System.out.println("가격: " + price);
}
}
추상 클래스
- 객체화해서 사용할 목적이 아니라, 자식클래스들에게 공통된 속성&메소드를 배포해주기위한 목적의 클래스는 추상 클래스로 만든다.
- 부모 클래스에는 메소드 껍데기만 만들어 두고, 자식클래스에 공통된 메소드명을 배포해준다.
- 추상 메소드는 자식 클래스에서 오버라이딩해 사용한다.
- 추상클래스는 이탤릭체로 표현
- 추상클래스에는 abstract 키워드를 추가한다.
- 추상메소드에는 abstract 키워드를 추가하고 구현 블록을 제거한다.

abstract public class MessageSender {
String title, senderName;
public MessageSender(String title, String senderName) {
this.title = title;
this.senderName = senderName;
}
abstract void sendMessage(String rec);
}
추상 클래스 및 메소드 특징
- 자체적으로 객체를 생성할 수 없다.
- 추상 클래스는 추상 메소드, 일반 메소드, 필드(멤버변수), 생성자로 구성된다.
- 추상 클래스를 상속받는 클래스는 추상 메소드를 반드시 오버라이딩 해야 한다. 오버라이딩 시 메소드 시그니쳐가 동일해야 한다.
추상 클래스를 사용하는 이유
- 공통된 필드나 메소드들을 추출해 통일된 내용으로 작성하도록 규격화하기 위해 사용
- 프로젝트가 커질수록 유지보수를 위해 필요
인터페이스
구성요소
목적
- 배포 : 전체 시스템의 통일성을 구현할 수 있다.
- 틀 제공
interface A {
}
interface B extends A {
}
class C implements A {
}
class D extends C implements B {
}
A, B, C, D a = new D();

다형성 구현방법 4가지