본문 바로가기
Programming Language/Java

[국비] Java 내용정리 Day10

by tpleehan 2021. 11. 10.

객체지향 프로그래밍(Object Oriented Programming)

출처: https://m.post.naver.com/viewer/postView.naver?volumeNo=16885254&memberNo=38386150

  • 객체지향 프로그래밍이란 모든 데이터들을 객체로 표현하고 객체들의 상호작용(책임, 협력, 위임) 등을 프로그램으로 표현하는 프로그래밍 기법

객체란?

  • 객체는 물리적으로 존재하거나 추상적으로 생각할 수 있는 것들을 말한다.
  • 물리적으로 눈에 보이는 펜, 자동차, 사람과 같은 것과 추상적인 주문, 강의 등과 같은 것도 모두 객체가 될 수 있다.

현실의 객체와 프로그래밍의 객체

객체간의 관계

객체의 속성과 기능

  • 속성이란 객체가 가진 정보들을 의미한다.
    • 강아지의 속성
    • 견종, 나이, 이름, 키, 몸무게, 예방접종 여부 등
  • 기능이란 객체가 가진 행위들을 의미한다.
    • 강아지의 기능
    • 짖다, 놀다, 사료를 먹다, 꼬리를 흔들다 등

클래스란?

  • 현실에서 객체가 갑자기 어디선가 나타나는게 아닌 설계도를 바탕으로 만들어졌다.
  • 클래스란 프로그래밍에서 객체를 만들기 위한 설계도이다.
  • 클래스로부터 만들어진 객체를 해당 클래스의 인스턴스(instance)라고 부른다.
  • 하나의 클래스로 여러 개의 인스턴스를 만들 수 있다.

클래스의 구성요소

  1. 필드
    • 필드란 객체의 고유 속성데이터, 객체의 상태데이터, 객체의 부품정보를 저장하는 곳이다.
    • 필드 선언 위치는 클래스 블록 안에서만 가능하며, 메서드나 생성자 블록에서는 불가능하다.
    • 생성자나 메서드 안에 선언된 변수는 필드가 아닌 지역변수라고 부른다.
  2. 생성자
    • 생성자란 new 연산자와 같이 사용되어 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당한다.
    • 객체 초기화란 필드 값을 세팅하거나 메서드를 호출하여 객체를 사용할 준비를 하는 것이다.
    • 생성자를 호출하지 않으면 객체를 생성할 수 없으며, 생성자가 정상 호출되면 객체가 Heap 메모리에 올라가며 객체가 생성되고 그 결과로 객체의 메모리 주소값이 리턴된다.
    • 생성자는 여러 개 선언할 수 있으며, 하나도 선언하지 않으면 기본생성자(default constructor)가 자동 선언된다.
    • 생성자는 클래스 블록 안에 선언하며, 이름은 필드나 메서드처럼 사용자 정의가 아닌 클래스이름과 반드시 대/소문자까지 동일하게 작성해야 한다.
    • 생성자는 리턴을 할 수 없으면, 리턴타입이 존재하지 않는다.
    • 매개변수가 없는 생성자를 기본 생성자라고 부른다.
  3. 메서드
    • 메서드는 객체의 동작에 해당하는 블록을 말한다.
    • 메서드는 필드를 읽고 수정하는 역할도 하지만, 다른 객체를 생성해서 다양한 기능을 수행하기도 한다.
    • 메서드는 객체간의 메시징을 담당하며 객체 상호간 데이터 전달의 수단으로 사용된다.
    • static 메서드는 정적 메서드라고 하고 static이 없는 메서드는 인스턴스(instance) 메서드라고 부른다.

패키지란?

  • 프로그램을 개발하다보면 수많은 클래스를 작성하게 된다.
  • 클래스를 체계적으로 관리하지 않으면 클래스간 관계가 뒤엉켜 유지보수가 난해한 프로그램이 된다.
  • 파일을 폴더에 관리하듯 자바에서는 클래스를 관리하기 위해 패키지를 사용한다.
package fruit;

public class Apple {

}
package fruit;

public class Banana {

}
package fruit;

public class Melon {

}
  • 클래스를 묶음으로 관리하려면 패키지 선언을 해야 한다.
  • 패키지 선언문은 반드시 클래스의 최상단에 위치해야 한다.
package traffic.car;

public class Taxi {

}
package traffic.car;

public class Bus {

}
package traffic;

public class Subway {

}
package juice;

public class Apple {

}
package test;

//작성 중인 패키지와 다른 곳에 위치한 클래스를 사용하려면 import 선언이 필요하다.
//import fruit.Apple;
//import fruit.Banana;
//import fruit.Melon;
import fruit.*; //fruit 패키지의 모든 클래스를 import 선언

public class Test {
	public static void main(String[] args) {
		fruit.Apple a = new fruit.Apple();
		juice.Apple a2 = new juice.Apple();
		Banana b = new Banana();
		Melon m = new Melon();
		
	}
}
  • 다른 패키지 내의 같은 이름을 가진 클래스 객체를 생성할 때는 반드시 패키지 경로를 직접 표시해야 한다.

패키지 생성 방법

  • 패키지는 클래스를 컴파일하는 과정에서 자동으로 생성되는 폴더이다. 컴파일러는 클래스를 포함된 패키지 선언을 보고 파일 시스템의 폴더로 자동 생성시킨다.
  • 패키지 이름은 임의로 작성할 수 있지만 몇가지 규칙이 있다.
    • 숫자로 시작 불가, 특수문자 사용 불가($, _ 제외)
    • 최상위 패키지로 java로 시작할 수 없다.
    • 소문자로 작성하는 것이 관례이다.

import문

  • 같은 패키지에 속하는 클래스는 아무런 조건 없이 다른 클래스를 사용할 수 있지만 다른 패키지에 속한 클래스를 사용하려면 2가지 방법이 있다.

  • 패키지 이름이 짧다면 불편함이 없지만 패키지 이름이 길거나, 상하위 구조가 복잡할 경우 사용할 클래스에 전체 패키지명을 사용하면 코드가 복잡하게 보인다.

  • import 키워드를 선언해서 사용하는 것이 코드의 복잡성이 줄어들고 간결해진다.
  • 특정 패키지의 클래스를 여러 개 사용할 경우 import 구문이 많아지는데 *을 사용해서 import를 처리할 수 있다.

package reference;

public class User {

	String id;
	String pw;
	
	User(String uId, String uPw) {
		id = uId;
		pw = uPw;
	}
	
}
package reference;

import java.util.Scanner;

public class CompareStr {
	public static void main(String[] args) {		
		
        Scanner sc = new Scanner(System.in);
		
		User kim = new User("abc1234", "aaa1111");
		
		System.out.print("비밀번호를 입력하세요: ");
		String password = sc.next();
		
		System.out.println("직접 입력한 비번: " + password);
		System.out.println("객체 생성 시 지정한 비번: " + kim.pw);
		
		System.out.println("--------------------------------");
		
		System.out.println("== 연산자의 결과: " + (password == kim.pw));
		System.out.println("equals의 결과: " + (password.equals(kim.pw)));
		
		sc.close();
		
	}

}
  • String은 객체 타입이다. 여러개의 단일 문자를 변수 하나에 넣을 수가 없기 때문에 String객체가 생성되어서 여러 문자들을 한번에 보관하고 문자열을 다룰 수 있는 여러 기능을 제공한다.
  • String 변수에는 문자열이 아니라 문자열 객체의 주소값이 들어 있다.
    String 변수를 그냥 사용해도 문자열이 제대로 나오는 것은 자바에서 편하게 사용하도록 제공하고 있고, 실제로는 주소값으로 접근해서 사용하는 것이다.
  • == 연산자로 변수의 값 자체를 비교하는 것은 주소값을 비교하는 의미와 같다. 문자열의 내용 값 그 자체를 비교할 때는 equals() 메서드를 사용해야 한다.

객체지향 프로그래밍 특징

상속이란?

  • 현실에서 상속은 부모가 자식에게 물려주는 행위를 말한다.
  • 객체지향 프로그래밍에서도 부모 클래스가 가진 멤버를 자식 클래스에게 물려줄 수 있다.
  • 상속은 이미 만들어진 클래스를 기반으로 새로운 클래스를 만들기 때문에 코드의 중복을 줄여준다.

상속을 사용하지 않은 클래스

  • 음반, 도서, 영화의 클래스에 동일한 속성을 가지고 있는 상품명, 발매일이 코드 중복이 발생한다.
  • 클래스 설계에 상솏을 사용하면 동일한 속성과 기능에 대한 중복 코드를 제거하고 새로운 클래스를 빠르게 만들 수 있다.

상속의 코드 표현

public class 자식클래스 extends 부모 클래스 { ... }
  • 자바에서 상속을 표현할 때는 자식 클래스에서 어떤 부모 클래스를 상속받을 지 결정하고, 선택된 부모 클래스는 extends 키워드 뒤에 기술한다.
  • 다른 언어와 달리 자바에서는 다중 상속을 허용하지 않는다. 즉, 하나의 자식 클래스가 여러 부모 클래스를 가질 수 없다.
  • 상속을 해도 부모 클래스의 private 멤버는 상속 대상에서 제외된다.
  • 상속을 사용하면 클래스의 수정을 최소화 할 수 있다. 부모 클래스의 수정으로 모든 자식 클래스가 수정되기 때문이다.

부모 클래스, 상위 클래스 (Parent, super class)

  • 데이터를 다른 클래스에게 상속하는 클래스를 부모 클래스라고 한다.
  • 상속을 사용하면 데이터를 물려받는 클래스에게 부모 클래스의 멤버변수(필드)와 메서드가 상속된다. 단, 생성자는 상속되지 않는다.

자식 클래스, 하위 클래스 (Child, Sub Class)

  • 부모 클래스로부터 멤버변수(필드)와 메서드를 물려받는 클래스를 자식 클래스라고 한다.
  • 상속을 적용시키려면 자식 클래스 선언부의 클래스 이름 뒤에 키워드 extends를 쓰고, 물려 받을 부모 클래스의 이름을 적어야 한다.

오버라이딩이란?

  • 부모 클래스가 물려준 모든 메서드가 자식 클래스에 맞게 설계되어 있디면 가장 이상적인 상속이지만 어떤 메서드는 자식 클래스가 그대로 사용하기에 적합하지 않을 수 있다.
  • 이 때 상속된 일부 메서드는 자식 클래스에서 다시 수정해서 사용할 수 있는데, 메서드 오버라이딩이라고 부른다.
  • 메서드가 오버라이딩되면 부모 객체의 메서드는 숨겨지기 때문에 자식 객체에서 해당 메서들르 호출하면 오버라이딩된 메서드가 호출된다.
  • 오버라이딩 규칙
    • 부모의 메서드와 동일한 시그니처를 가진다. (이름, 리턴타입, 매개변수)
    • 접근제한을 더 강화해서 오버라이딩 할 수 없다.

메서드 오버라이딩(재 정의)

  • 부모가 물려주는 메서드는 모든 자식들에게 맞게 설계되기 힘들기 때문에 부족한 점이 있거나 아예 맞지 않는 경우에는 자식 클래스 쪽에서 내용을 추가하거나 수정할 수 있다. 이를 오버라이딩 이라고 한다.
  • 만약 자식 클래스에서 부모가 물려준 메서드를 새롭게 재정의한다면 자식이 수정한 메서드가 우선적으로 호출된다.
  • 메서드 오버라이딩의 규칙
    • 부모가 물려주는 메서드와 이름이 똑같아야 한다.
    • 부모가 물려주는 메서드와 리턴 타입이 똑같아야 한다.
    • 부모가 물려주는 메서드와 매개변수의 선언이 똑같아야 한다.

Bad Class

package inherit.bad;

public class Warrior {

	String name;
	int level;
	int atk;
	int hp;
	int rage;
	
	void characterInfo() {
		System.out.println("*** 캐릭터의 정보 ***");
		System.out.println("# 아이디: " + name);
		System.out.println("# 레벨: " + level);
		System.out.println("# 공격력: " + atk);
		System.out.println("# 체력: " + hp);
		System.out.println("# 분노: " + rage);
	}
}
package inherit.bad;

public class Mage {
	
	String name;
	int level;
	int atk;
	int hp;
	int mp;

	void characterInfo() {
		System.out.println("*** 캐릭터의 정보 ***");
		System.out.println("# 아이디: " + name);
		System.out.println("# 레벨: " + level);
		System.out.println("# 공격력: " + atk);
		System.out.println("# 체력: " + hp);
		System.out.println("# 정신력: " + mp);
	}
	
}
package inherit.bad;

public class Hunter {

	String name;
	int level;
	int atk;
	int hp;
	String pet;

	void characterInfo() {
		System.out.println("*** 캐릭터의 정보 ***");
		System.out.println("# 아이디: " + name);
		System.out.println("# 레벨: " + level);
		System.out.println("# 공격력: " + atk);
		System.out.println("# 체력: " + hp);
		System.out.println("# 펫 이름: " + pet);
	}
	
}

Good Class

package inherit.good;

public class Player {

	String name;
	int level;
	int atk;
	int hp;
	
	void characterInfo() {
		System.out.println("*** 캐릭터의 정보 ***");
		System.out.println("# 아이디: " + name);
		System.out.println("# 레벨: " + level);
		System.out.println("# 공격력: " + atk);
		System.out.println("# 체력: " + hp);
	}
	
}
package inherit.good;

public class MainClass {
	public static void main(String[] args) {		
		Warrior w1 = new Warrior();
		w1.level = 1;
		w1.atk = 3;
		w1.hp = 50;
		w1.name = "전사1";
		w1.rage = 60;
		w1.characterInfo();
		
		System.out.println("---------------------");
		
		Mage m1 = new Mage();
		m1.level = 1;
		m1.atk = 2;
		m1.hp = 50;
		m1.name = "마법사1";
		m1.mana = 100;
		m1.characterInfo();

		System.out.println("---------------------");
		
		Hunter h1 = new Hunter();
		h1.level = 1;
		h1.atk = 4;
		h1.hp = 50;
		h1.name = "사냥꾼1";
		h1.pet = "댕댕이";
		h1.characterInfo();		
		
	}

}
package inherit.good;

public class Warrior extends Player {

	int rage;
	
	@Override
	void characterInfo() {
		super.characterInfo();
		System.out.println("# 분노: " + rage);
	}
	
}
package inherit.good;

public class Mage extends Player {

	int mana;
	
	@Override
	void characterInfo() {
		super.characterInfo();
		System.out.println("# 정신력: " + mana);
	}
	
}
package inherit.good;

public class Hunter extends Player {

	String pet;
	
	@Override
	void characterInfo() {
		super.characterInfo();
		System.out.println("# 펫 이름: " + pet);
	}
	
}

Quiz

문제)
- 학생(Student), 선생(Teacher), 종업원(Employee) 클래스를 생성
- 세 클래스는 공통적으로 이름과 나이를 가지고 있다.
- 세 클래스는 공통적으로 info() 메서드를 가지고 있다. (리턴 타입: String, 이름: XXX, 나이: XXX )
- 학생은 학번(studentId)을 가지고 있고, 선생은 담당 과목(subject)를 가지고 있고, 종업원은 부서 (departments)를 가지고 있다.
- 부모 클래스의 이름은 Person으로 지정 Person 클래스 생성 후 각각의 자식 클래스 생성 하고 MainClass에서 정보를 출력
package inherit.quizz;

public class Person {

	String name;
	int age;

	String info() {
//		return "이름: " + name + ", 나이: " + age + "세";
		String str = "이름: " + name + ", 나이: " + age + "세";
		return str;
		
	}
	
}​
package inherit.quizz;

public class Student extends Person {

	String studentId;
	
	@Override
	String info() {
		return super.info() + ", 학번: " + studentId;
	}
	
}​
package inherit.quizz;

public class Teacher extends Person {
	
	String subject;

	@Override
	String info() {
		return super.info() + ", 담당과목: " + subject;
	}
	
}​
package inherit.quizz;

public class Employee extends Person {

	String departments;

	@Override
	String info() {
		return super.info() + ", 부서: " + departments;
	}

}​
package inherit.quizz;

public class MainClass {
	public static void main(String[] args) {
		Student stu = new Student();
		stu.name = "홍길동";
		stu.age = 21;
		stu.studentId = "a001";
		System.out.println(stu.info());
		
		System.out.println("--------------------------------");
		
		Teacher t = new Teacher();
		t.name = "김철수";
		t.age = 40;
		t.subject = "수학";
		System.out.println(t.info());
		
		System.out.println("--------------------------------");

		Employee e = new Employee();
		e.name = "김영희";
		e.age = 28;
		e.departments = "영업팀";
		System.out.println(e.info());
	
	}

}
package overloading;

public class Calculator {
	
	void inputData() {}
	
	void inputData(int a) {}
	
	void inputData(int a, int b) {}
//	void inputData(int b, int a) {} (x)
	
	void inputData(String s) {}
	
	void inputData(int a, double d) {}
	
	void inputData(double d, int a) {}
	
//	void inputData(int number) {} (x) 정수 매개값 1개 받는 메서드가 이미 선언되어 있음.
	
//	int inputData(int number) {
//		return 0;
//	} (x) 반환 유형(return type)은 오버로딩에 영향을 미치지 못한다.
		
	int calcRectArea(int r) {
		return r * r;
	}
	
	int calcRectArea(int width, int height) {
		return width * height;
	}
	
	double calcRectArea(int c, int f, int h) {
		return ((c + f) * h / 2.0);
		
	}
	
}
package overloading;

public class MainClass {

	public static void main(String[] args) {

		Calculator c = new Calculator();
		System.out.println("직사각형의 넓이: " + c.calcRectArea(5));
		
		c.calcRectArea(10, 20);
		System.out.println("직사각형의 넓이: " + c.calcRectArea(10, 20));
		
		c.calcRectArea(5, 13, 7);
		System.out.println("사다리꼴의 넓이: " + c.calcRectArea(5, 12, 7));
		
	}

}

인스턴스 멤버

  • 클래스의 구성요소(필드, 생성자, 메서드)를 멤버라고 부른다.
  • 객체 생성을 통해서만 사용할 수 있는 멤버를 인스턴스(instatnce) 멤버라고 부른다.
  • 인스턴스 멤버는 객체 생성 없이는 사용할 수 없다.

클래스 내부에서 인스턴스를 구분하려면?

package this_super;

public class Player {

	String name;
	int level;
	int atk;
	int hp;
	
	Player() {
		System.out.println("Player의 기본 생성자 호출");
		System.out.println("this의 주소값: " + this);
		level = 1;
		atk = 3;
		hp = 50;
	}
	
	Player(String name) {
		System.out.println("Player의 2번 생성자 호출");
		System.out.println("this의 주소값: " + this);
		level = 1;
		atk = 3;
		hp = 50;
		this.name = name;
	}
	
	void characterInfo() {
		System.out.println("*** 캐릭터의 정보 ***");
		System.out.println("# 아이디: " + name);
		System.out.println("# 레벨: " + level);
		System.out.println("# 공격력: " + atk);
		System.out.println("# 체력: " + hp);
	}
	
}
package this_super;
	
public class Warrior extends Player {

	int rage;
	
	@Override
	void characterInfo() {
		super.characterInfo();
		System.out.println("# 분노: " + rage);
	}
	
}
package this_super;

public class Mage extends Player {

	int mana;
	
	@Override
	void characterInfo() {
		super.characterInfo();
		System.out.println("# 정신력: " + mana);
	}
	
}
package this_super;

public class Hunter extends Player {

	String pet;
	
	@Override
	void characterInfo() {
		super.characterInfo();
		System.out.println("# 펫 이름: " + pet);
	}
	
}
package this_super;

public class MainClass {	
	public static void main(String[] args) {		
		Player p1 = new Player();
		System.out.println("p1의 주소값: " + p1);
		p1.name	= "플레이어1";
		p1.characterInfo();
		
		System.out.println("------------------------");
		
		Player p2 = new Player("플레이어2");
		System.out.println("p2의 주소값: " + p2);
		p2.characterInfo();
		
		Player p3 = new Player("플레이어3");
		System.out.println("p3의 주소값: " + p3);
		p3.characterInfo();
	}
	
}

'Programming Language > Java' 카테고리의 다른 글

[국비] Java 내용정리 Day12  (0) 2021.11.21
[국비] Java 내용정리 Day11  (0) 2021.11.20
[국비] Java 내용정리 Day09  (0) 2021.11.06
[국비] Java 내용정리 Day08  (0) 2021.11.05
[국비] Java 내용정리 Day07  (0) 2021.11.03

댓글