package ch05;

// 추상 클래스는 new 할 수 없다. 오브젝트가 아니기 때문.
// 추상 클래스는 추상 메서드를 가질 수 있다.
abstract class Food {
	abstract void eat();
}

class 라면 extends Food {

	String name = "라면";

	@Override
	void eat() {
		System.out.println(name + "을 먹었습니다.");
	}

}

class 불고기 extends Food {

	String name = "불고기";

	@Override
	void eat() {
		System.out.println(name + "를 먹었습니다.");
	}

}

class 갈비 extends Food {

	String name = "갈비";

	@Override
	void eat() {
		System.out.println(name + "를 먹었습니다.");
	}

}

public class FoodEx01 {

	static void start(Food f) {
		f.eat();
	}

	public static void main(String[] args) {
		start(new 라면());
	}
}

 

공통 사항은 추상 클래스에서 메서드를 구현해도된다.

package ch05;

abstract class Food {

	void eat() {
		System.out.println("음식을 먹습니다."); // 공통적인것은 사용
	}

	abstract void cook(); // 공통적인데 오브젝트마다 조금씩 다르다면 추상메서드 사용
}

class 라면 extends Food {

	@Override
	void cook() {
		System.out.println("냄비에 끓인다.");

	}

}

class 삼겹살 extends Food {

	@Override
	void cook() {
		System.out.println("불판에 굽는다.");
	}

}

public class FoodEx02 {
	
	static void start(Food f) {
		f.cook();
		f.eat();
	}
	
	
	public static void main(String[] args) {
		start(new 라면());
	}
}

 

추상클래스를 이용해 순서를 정할 수 있다.

package ch05;


// 추상 클래스는 일반 메서드를 가질 수 있다.
// 추상 클래스는 내가 구현할 수 없는 메서드를 오브젝트에게 미룰 수 있다.
// 추상 클래스는 abstract를 붙인다.
// 추상 클래스를 통해서 순서를 정할 수 있다.
abstract class Food {
	
	abstract void standby();
	
	// protected는 자식만 사용가능
	
	protected void eat() {
		System.out.println("음식을 먹습니다."); // 공통적인것은 사용
	}

	abstract void cook(); // 공통적인데 오브젝트마다 조금씩 다르다면 추상메서드 사용
	
	void auto() {  // 이렇게 제작하면 순서 실수를 하지 않는다 (요리 -> 섭취)
		standby();
		cook();
		eat();
	}
}

class 라면 extends Food {
	
	

	@Override
	void cook() {
		System.out.println("냄비에 끓입니다.");

	}

	@Override
	void standby() {
		System.out.println("라면과 냄비를 준비합니다.");
		
	}

}

class 삼겹살 extends Food {

	@Override
	void cook() {
		System.out.println("불판에 굽습니다.");
	}
	
	@Override
	void standby() {
		System.out.println("고기와 불판을 준비합니다.");
		
	}

}

public class FoodEx02 {
	
	static void start(Food f) {
		f.auto();
	}
	
	
	public static void main(String[] args) {
		start(new 라면());
	}
}

 

추상 클래스를 어댑터 용도로 사용

package ch05;

// 어댑터

abstract class 칼 {
	abstract void kill();

	abstract void cook();

	abstract void repair();
}


// 상속 받는 추상 클래스는 부모 클래스의 모든 클래스를 오버라이딩 할 필요가 없다.
// 요리사 어댑터 - 필요없는 기능만 입력한다. (cook메서드만 자식클래스에 구현을 미룬다.)
abstract class 요리사 extends 칼 {
	
	@Override
	void kill() {}
	
	@Override
	void repair() {}
}

// 요리사 클래스가 구현하지 않은 기능만 구현하면 된다.
class 백종원 extends 요리사{
	
	@Override
	void cook() {
		// TODO Auto-generated method stub
		
	}
}

public class FoodEx03 {
	public static void main(String[] args) {

	}
}

 

 

주의 : 이클립스 또는 STS를 한글디렉토리 또는 띄어쓰기가 있는 디렉토리에 설치하신 분은 프로그램이 실행 안될 가능성이 있습니다. 띄어쓰기 없는 영문명 디렉토리에 IDE를 설치해주세요

 

 

 

 

 

 

 

 

 

 

 

 

 

롬복을 사용하면 게터와 세터를 자동으로 만들어준다

package stars1.protoss;

import lombok.Data;

@Data
public class Zealot{
	private String name;
	private int hp;
	private static int attack;
	
	public static void main(String[] args) {
		Zealot z1 = new Zealot();
		z1.getName();
		z1.setHp(10);
		
	}
}

 

게터만 만들려면

package stars1.protoss;

import lombok.Getter;

@Getter
public class Zealot{
	private String name;
	private int hp;
	private static int attack;
	
	public static void main(String[] args) {
		Zealot z1 = new Zealot();
		z1.getName();
		z1.setHp(10);
		
	}
}

 

롬복 디폴트생성자, 모든 변수 생성자, 게터 세터

package stars1.protoss;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


// 어노테이션 - 컴파일러가 읽고 해당 내용을 코드를 띄우기전에 먼저 동작
@AllArgsConstructor // 모든 힙 변수를 받는 생성자 자동생성
@NoArgsConstructor // 디폴트 생성자 자동생성
@Data // 게터와 세터 자동생성 @Getter @Setter 를 이용할 수도 있다.
public class Zealot{
	private String name;
	private int hp;
	private static int attack;
}

 

 

계층별로 패키지 정렬하기

 

 

객체지향 프로그래밍 기술은 코딩을 쉽게 하려고 하는 것이기 때문에, 일부 요소를 제작할 때 어렵다면 사용하지 않아도 된다.

1. 오버라이드 override : 부모 클래스의 메서드를 무효화시킨다.
2. 상속 : (1) 부모의 모든 것을 물려 받는 것.
            (2) 다형성이 충족 되어야 한다 (생물 - 동물 - 사자) -- 사자는 생물이며 동물이며 사자다.
3. 동적 바인딩 : 런타임시 필요한 메서드를 찾아가는 것.

상속

배우는 한국인이 아닐 수 있기 때문에 한국인에 상속되지 않는다

 

 

박서준을 new하면 사람 아시아인 한국인 박서준의 모든 속성이 뜬다

num을 호출하는 순간 부모 클래스들을 쭉 찾아 올라간다

 

 

자료형을 부모 자료형으로 제작하고, 생성자는 자식으로 할 수 있다

 

 

 

 

다운캐스팅

package ch05;

class 사람 {
	int num = 10;
}

class 아시아인 extends 사람 {
	int num = 30;

}

class 한국인 extends 아시아인 {

}

class 박서준 extends 한국인 {
	int num = 20;
}

public class EveryPerson {
	public static void main(String[] args) {

		박서준 b1 = new 박서준();
		System.out.println(b1.num);

		한국인 b2 = new 박서준(); // 한국인 자료형이지만 박서준 클래스의 데이터도 메모리에 떠 있다
		System.out.println(b2.num); 
		
		박서준 downB2 = (박서준)b2; // 업캐스팅이 선행되어 new를 한 경우 다운캐스팅이 가능하다
		System.out.println(downB2.num);
		
		

		사람 b3 = new 한국인();
		System.out.println(b3.num);

//		박서준 b4 = new 한국인(); //오류가 난다
//		System.out.println(b4.num);

	}
}

 

 

오버라이딩, 동적 바인딩

package ch05;

class Car {

	void run() {
		System.out.println("기본 움직임");
	}

}

class Sonata extends Car {

	// 오버라이드 : 부모 클래스의 메서드를 무효화 시키는 것 (재사용과는 다르다는 것을 주의)
	// [실행시!!]에 부모 메서드를 무시한다!
	// 동적 바인딩 (C언어에서는 동적 로딩 이라고 한다)
    // 동적 바인딩은 런타임시 필요한 메서드를 찾아가는 것이다.
	@Override // 어노테이션
	void run() {
		super.run(); // super는 부모의 heap
		System.out.println("소나타만의 움직임");
	}
}

public class CarEx01 {

	public static void main(String[] args) {

		Car c1 = new Car();
		c1.run();

		System.out.println("----------");

		Car s1 = new Sonata();
		s1.run();

	}

}

 

 

package ch05;

class Animal {
	
	
	// 오버라이딩 하려면 원본 메서드가 필요하다.
	String getName() {
		return "동물";
	}
}

class Dog extends Animal {
	final String NAME = "강아지";
	
	// 오버라이딩
	String getName() {
		return NAME;
	}
}

class Cat extends Animal {
	final String NAME = "고양이";
	
	// 오버라이딩
	String getName() {
		return NAME;
	}
}

class Bird extends Animal {
	final String NAME = "새";

	// 오버라이딩
	String getName() {
		return NAME;
	}
}

public class AnimalEx01 {
	
	
	// 매개변수를 Animal 타입으로 받으니 Dog Cat Bird가 묵시적 업캐스팅이 된다.
	// Animal에는 NAME이 없으니 빨간줄이 뜬다. 
	// 그것을 해결 하려면 오버라이딩을 사용한다.
	// 변수 호출은 자료형 기준이다.
	// 함수(메서드)호출은 생성자 기준이다.(오버라이딩)
	// 자식의 오버라이딩을 찾아 내려가는 것을 동적 바인딩이라고 한다.
	static void attack(Animal u1, Animal u2) {
		System.out.println(u2.getName() + "가 " + u1.getName() + "에게 공격 당했습니다.");
	}

	public static void main(String[] args) {

		Dog d1 = new Dog();
		Cat c1 = new Cat();
		Bird b1 = new Bird();

		System.out.println(d1.NAME + "탄생");
		System.out.println(c1.NAME + "탄생");
		System.out.println(b1.NAME + "탄생");

		// 강아지 vs 고양이
		attack(d1, c1);

		// 강아지 vs 새
		attack(d1, b1);

		// 고양이 vs 새
		attack(c1, b1);

	}

}

 

 

추상 클래스

 

 

 

 

객체지향 프로그래밍
1. Object - 실제로 존재할 수 있는 것을 상상 - 생산될 질럿을 머릿 속으로 상상
2. class - 추상적인 설계도, 또는 구체적인 설계도  - 프로토스 또는 질럿의 속성과 기능을 코드로 표현
3. Instance - 클래스를 통해 Object가 실체화 된 것 - 생산된 질럿
4. 생성자 - 클래스의 속성을 초기화
5. this - 인스턴스화 했을때 해당 인스턴스를 가리킨다
6. 행동(책임) - 메서드
7. 속성은 행동에 의해 변경된다.
8. 오버로딩 - 동일한 이름의 메서드를 여러가지 매개변수로 생성
9. final - 한번 초기화 하면 변경 할 수 없다. 불변데이터. Read Only
10. 오버로딩의 한계  - 자료형이 한정되어 있을때 사용

오브젝트 - 구체적인것
클래스 - 추상적이거나, 구체적.  이것을 이용해서 구체적인 것(오브젝트)를 만들 수 있는 것

state - 변수

behavior - 함수(메서드)

------------------

생성자 자동생성

------------------

 

public - 모든 패키지에서 접근 가능

private - 클래스 내부

( 비어있는) - 같은 패키지에서 찾을 수 있음

------------------

시퀀스 - 일정하게 증가

-----------------

아래의 field는  heap 전역변수공간을 말한다

----------------

final 즉, 상수는 대문자로 적는게 약속

---------------

static 변수 - 공유변수 - heap끼리 공유할 수 있는 변수

---------------

package stars;

// 다크템플러 DarkTempler, 리버 River

class Zealot {
	final String NAME; // 한번 초기화하면 Read Only , 대문자로 적는 것이 약속
	int hp;
	static int attack = 10;

	public Zealot(String name) {
		this.NAME = name;
		this.hp = 100;
	}

}

class Dragoon {
	final String NAME;
	int hp;
	static int attack = 15;

	public Dragoon(String name) {
		this.NAME = name;
		this.hp = 100;
	}

}

class DarkTempler {
	final String NAME;
	int hp;
	static int attack = 50;

	public DarkTempler(String name) {
		this.NAME = name;
		this.hp = 100;
	}

}

class River {
	final String NAME;
	int hp;
	static int attack = 70;

	public River(String name) {
		this.NAME = name;
		this.hp = 100;
	}

}

public class GameStart {

	// 질럿이 드라군을 때림
	static void attack(Zealot u1, Dragoon u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	// 오버로딩 - 추가적재 - 다른함수로 인식
	static void attack(Dragoon u1, Zealot u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(Zealot u1, Zealot u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(Dragoon u1, Dragoon u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(Zealot u1, DarkTempler u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(Zealot u1, River u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(Dragoon u1, DarkTempler u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(Dragoon u1, River u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(DarkTempler u1, Zealot u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}
	
	static void attack(DarkTempler u1, DarkTempler u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(DarkTempler u1, Dragoon u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(DarkTempler u1, River u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(River u1, Zealot u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	static void attack(River u1, Dragoon u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 " + u1.NAME + "에 의해서 공격당하고 있습니다.");
		if(u2.hp <= 0) {
			System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
			System.out.println(u2.NAME+ "이 죽었습니다.");
		} else {			
			System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
		}
	}

	static void attack(River u1, DarkTempler u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}
	
	static void attack(River u1, River u2) {
		u2.hp = u2.hp - u1.attack;
		System.out.println(u2.NAME + "이 공격당하고 있습니다.");
		System.out.println(u2.NAME + "의 체력은 : " + u2.hp + "입니다.");
	}

	public static void main(String[] args) {
		// 공격력 업그레이드하기
		Zealot.attack++;

		// 질럿 생성하기
		Zealot z1 = new Zealot("1번질럿");
		System.out.println(z1.NAME + Zealot.attack);

		Zealot z2 = new Zealot("2번질럿");
		System.out.println(z2.NAME + Zealot.attack);

		Dragoon d1 = new Dragoon("1번드라군");
		Dragoon d2 = new Dragoon("2번드라군");

		DarkTempler dt1 = new DarkTempler("1번 다크템플러");
		DarkTempler dt2 = new DarkTempler("1번 다크템플러");

		River r1 = new River("1번 리버");
		River r2 = new River("1번 리버");

		// 공격하기
		attack(z1, d1);
		attack(z1, z2);
		attack(z1, dt1);
		attack(z1, r1);

		attack(d1, z1);
		attack(d1, d2);
		attack(d1, dt1);
		attack(d1, r1);
		
		attack(dt1, z1);
		attack(dt1, dt2);
		attack(dt1, d1);
		attack(dt1, r1);
		
		attack(r1, z1);
		attack(r1, r2);
		attack(r1, d1);
		attack(r1, dt1);
		
		

	}
}

package ch04;

class Rabbit {
	private String name; // heap변수, 전역변수, 맴버변수, 필드, 속성, 프로퍼티
	private int power;

	public Rabbit(String name, int power) {
		this.name = name;
		this.power = power;
	}

	// 행위 - 객체에 접근하는 것을 메서드로 하는게 객체지향의 시작
	// 변수를 변경하는 행위는 신중하게 접근자를 선택해야한다
	// 메서드는 그 클래스의 책임을 담당한다 (중요)
	boolean drink() {
		if (power >= 100) {
			return false;
		}
		power++;
		return true;
	}

	
//	void drink() {
//		if (power < 100) {
//			power++;
//		}
//	}

	public int getPower() {
		return power;
	}
	
	void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	

}

public class RabbitApp {
	public static void main(String[] args) {
		Rabbit r1 = new Rabbit("토끼", 20); // power 는 100이 max라고 가정
		System.out.println(r1.getPower());
		r1.drink();
		System.out.println(r1.getPower());
		r1.drink();
		System.out.println(r1.getPower());

		while (r1.drink()) {}
		System.out.println(r1.getPower());
		
		
		//이름변경
		r1.setName("산토끼");
		System.out.println(r1.getName());
	}
}

public - 모든 패키지에서 접근 가능

private - 클래스 내부

( 비어있는) - 같은 패키지에서 찾을 수 있음

+ Recent posts