자바의 정석 <기초편> 📌chapter7. 객체지향 프로그래밍 Ⅱ

모깅·2023년 2월 1일
0

📖 01. 상속


📖 02. 상속 예제

<예제 7-1 >

✍️ 입력

class Tv {
	boolean power; // 전원상태(on/off)
	int channel;	// 채널

	void power()       {   power = !power; }
	void channelUp()   {   ++channel;      }
	void channelDown() {   --channel;      }
}

class SmartTv extends Tv {  // CaptionTv는 Tv에 캡션(자막)을 보여주는 기능을 추가
	boolean caption;     // 캡션상태(on/off)
	void displayCaption(String text) {
		if (caption) {   // 캡션 상태가 on(true)일 때만 text를 보여 준다.
			System.out.println(text);
		}
	}
}

class Ex7_1 {
	public static void main(String args[]) {
		SmartTv stv = new SmartTv();
		stv.channel = 10;			// 조상 클래스로부터 상속받은 멤버
		stv.channelUp();			// 조상 클래스로부터 상속받은 멤버
		System.out.println(stv.channel);
		stv.displayCaption("Hello, World");
		stv.caption = true;	// 캡션(자막) 기능을 켠다.	       
		stv.displayCaption("Hello, World");
	}
}

💻 출력
11
Hello, World


📖 03. 클래스 간의 관계 - 포함관계


📖 04. 클래스 간의 관계 결정하기


📖 05. 단일 상속(single ingeritance)

-> 다중상속을 하게 되면 메소드 등의 이름이 겹칠 경우 무엇을 써야 할 지 모른다. 불리한 점이 많이 생김!


📖 06. Object클래스 - 모든 클래스의 조상

-> println은 참조변수를 출력할때 toString()메소드를 적용해서 출력한다.
ex) Sys..println(c) == Sys..println(c.toString())


📖 07. 오버라이딩(overriding)


📖 08. 오버라이딩의 조건


📖 09. 오버로딩 vs 오버라이딩


📖 10. 참조변수 super

<예제 7-2 >

✍️ 입력

class Ex7_2 {
	public static void main(String args[]) {
		Child c = new Child();
		c.method();
	}
}

class Parent { int x=10; }

class Child extends Parent {
	int x=20;

	void method() {
		System.out.println("x=" + x);
		System.out.println("this.x=" + this.x);
		System.out.println("super.x="+ super.x);
	}
}

💻 출력
x=20
this.x=20
super.x=10

<예제 7-3 >

✍️ 입력

class Ex7_3 {
	public static void main(String args[]) {
		Child2 c = new Child2();
		c.method();
	}
}

class Parent2 { int x=10; }

class Child2 extends Parent2 {
	void method() {
		System.out.println("x=" + x);
		System.out.println("this.x=" + this.x);
		System.out.println("super.x="+ super.x);
	}
}

💻 출력
x=10
this.x=10
super.x=10


📖 11. super() - 조상의 생성자

-> point3D 클래스에서 생성자를 써주지 않으면 부모의 있는 기본 생성자를 가져온다.(super()) but 현재 문제에서는 부모클래스(point)에 기본 생성자가 존재하지 않으므로 오류가 난다.
-> 해결방법
1. 부모클래스에 기본 생성자를 넣어준다.
-> 컴파일 단계에서 생성자가 없으면 기본 생성자를 만들어준다. 하지만 Point클래스에는 생성자가 존재하여 기본생성자를 만들어 주지 않는다.
2. 조상의 매개변수가 있는 생성자를 사용한다.

  • 주의! 클래스를 만들 때 기본생성자를 잘 만들도록 하자!

📖 12. 패키지(package)

  • 같은 이름의 클래스일 지라도 서로 다른 패키지에 속하면 패키지명으로 구별이 가능하다.
    -> 클래스 라이브러리를 만들 수 있음
  • java.lang패키지에서 lang패키지는 java패키지의 하위패키지이다.

📖 13. 패키지의 선언


-> 패키지 최상위 폴더의 이전폴더로 경로 이동 후 프로젝트를 실행시키자.


📖 14. 클래스 패쓰(classpath)

  • 환경변수에서 원하는 패키지 이전폴더로 클래스 패쓰를 적용시키자.

📖 15. import문


📖 16. static import문

  • static import문을 사용하면 static멤버를 호출할 때 클래스 이름을 생략할 수 있다.

<예제 7-6 >

✍️ 입력

import static java.lang.System.out;
import static java.lang.Math.*;

class Ex7_6 {
	public static void main(String[] args) {	
		// System.out.println(Math.random());
		out.println(random());

		// System.out.println("Math.PI :"+Math.PI);
		out.println("Math.PI :" + PI);
	}
}

💻 출력
0.9201018187215498
Math.PI :3.141592653589793


📖 17. 제어자(modifier)


📖 18. static - 클래스의, 공통적인


📖 19. final - 마지막의, 변경될 수 없는


📖 20. abstract - 추상의, 미완성의


📖 21. 접근 제어자(access modifier)

-> 클래스는 public과 default만 가능하다.


📖 22. 캡슐화와 접근 제어자

-> 상속을 통해 확장될 것이 예상되는 클래스라면 멤버에 protected를 사용하자.


📖 23. 다형성(polyvorphism)


📖 24. 참조변수의 형변환

  • 객체의 주소를 저장하는 것이다.
  • 사용할 수 있는 멤버 개수를 조절하기 위해 참조변수의 형변환을 사용한다.

📖 25. 참조변수의 형변환 예제

<예제 7-7 >

✍️ 입력

class Ex7_7 {
	public static void main(String args[]) {
		Car car = null;
		FireEngine fe = new FireEngine();
		FireEngine fe2 = null;

		fe.water();
		car = fe;    // car = (Car)fe;에서 형변환이 생략됨
//		car.water();
		fe2 = (FireEngine)car; // 자손타입 ← 조상타입. 형변환 생략 불가
		fe2.water();
	}
}

class Car {
	String color;
	int door;

	void drive() { 	// 운전하는 기능
		System.out.println("drive, Brrrr~");
	}

	void stop() {  	// 멈추는 기능	
		System.out.println("stop!!!");	
	}
}

class FireEngine extends Car {	// 소방차
	void water() {	// 물을 뿌리는 기능
		System.out.println("water!!!");
	}
}

💻 출력
water!!!
water!!!

-> fe2 = (FireEngine)car; : car(4개 멤버)를 fe2(5개 멤버)로 바꾸면 불안전하기 때문에 형변환 해주어야 한다,


📖 26. instanceof 연산자


📖 27. 매개변수의 다형성 && 28. 매개변수의 다형성 예제

<예제 7-8 >

✍️ 입력

class Product {
	int price;			// 제품의 가격
	int bonusPoint;	// 제품구매 시 제공하는 보너스점수

	Product(int price) {
		this.price = price;
		bonusPoint = (int)(price/10.0);	// 보너스점수는 제품가격의 10%
	}
}

class Tv1 extends Product {
	Tv1() {
		// 조상클래스의 생성자 Product(int price)를 호출한다.
		super(100);		// Tv의 가격을 100만원으로 한다.
	}

	// Object클래스의 toString()을 오버라이딩한다.
	public String toString() { return "Tv"; }
}

class Computer extends Product {
	Computer() { super(200); }

	public String toString() { return "Computer"; }
}

class Buyer {	// 고객, 물건을 사는 사람
	int money = 1000;	  // 소유금액
	int bonusPoint = 0; // 보너스점수

	void buy(Product p) {
		if(money < p.price) {
			System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
			return;
		}

		money -= p.price;            // 가진 돈에서 구입한 제품의 가격을 뺀다.
		bonusPoint += p.bonusPoint;  // 제품의 보너스 점수를 추가한다.
		System.out.println(p + "을/를 구입하셨습니다.");
	}
}

class Ex7_8 {
	public static void main(String args[]) {
		Buyer b = new Buyer();

		b.buy(new Tv1());
		b.buy(new Computer());

		System.out.println("현재 남은 돈은 " + b.money + "만원입니다.");
		System.out.println("현재 보너스점수는 " + b.bonusPoint + "점입니다.");
	}
}

💻 출력
Tv을/를 구입하셨습니다.
Computer을/를 구입하셨습니다.
현재 남은 돈은 700만원입니다.
현재 보너스점수는 30점입니다.


📖 29. 여러 종류의 객체를 배열로 다루기 && 30. 여러 종류의 객체를 배열로 다루기

<예제 7-9 >

✍️ 입력

class Product2 {
	int price;			// 제품의 가격
	int bonusPoint;	// 제품구매 시 제공하는 보너스점수

	Product2(int price) {
		this.price = price;
		bonusPoint = (int)(price/10.0);
	}

	Product2() {} // 기본 생성자
}

class Tv2 extends Product2 {
	Tv2() {  super(100);	 }

	public String toString() { return "Tv"; }
}

class Computer2 extends Product2 {
	Computer2() { super(200); }
	public String toString() { return "Computer"; }
}

class Audio2 extends Product2 {
	Audio2() { super(50); }
	public String toString() { return "Audio"; }
}

class Buyer2 {			  // 고객, 물건을 사는 사람
	int money = 1000;	  // 소유금액
	int bonusPoint = 0; // 보너스점수
	Product2[] cart = new Product2[10];   // 구입한 제품을 저장하기 위한 배열
	int i =0;			  // Product배열에 사용될 카운터

	void buy(Product2 p) {
		if(money < p.price) {
			System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
			return;
		}

		money -= p.price;             // 가진 돈에서 구입한 제품의 가격을 뺀다.
		bonusPoint += p.bonusPoint;   // 제품의 보너스 점수를 추가한다.
		cart[i++] = p;                // 제품을 Product[] cart에 저장한다.
		System.out.println(p + "을/를 구입하셨습니다.");
	}
// 뒷 페이지에 계속됩니다.
	void summary() {	              // 구매한 물품에 대한 정보를 요약해서 보여 준다.
		int sum = 0;                 // 구입한 물품의 가격합계
		String itemList ="";         // 구입한 물품목록

		// 반복문을 이용해서 구입한 물품의 총 가격과 목록을 만든다.
		for(int i=0; i<cart.length;i++) {
			if(cart[i]==null) break;
			sum += cart[i].price;
			itemList += cart[i] + ", ";
		}
		System.out.println("구입하신 물품의 총금액은 " + sum + "만원입니다.");
		System.out.println("구입하신 제품은 " + itemList + "입니다.");
	}
}

class Ex7_9 {
	public static void main(String args[]) {
		Buyer2 b = new Buyer2();

		b.buy(new Tv2());
		b.buy(new Computer2());
		b.buy(new Audio2());
		b.summary();
	}
}

💻 출력
Tv을/를 구입하셨습니다.
Computer을/를 구입하셨습니다.
Audio을/를 구입하셨습니다.
구입하신 물품의 총금액은 350만원입니다.
구입하신 제품은 Tv, Computer, Audio, 입니다.


📖 31. 추상 클래스(abstract class)

-> 새로운 클래스를 작성하는데 있어서 바탕이 되는 조상 클래스로서 중요한 의미를 갖는다.


📖 32. 추상 메서드(abstract method)


📖 33. 추상클래스의 작성


📖 34. 추상클래스의 작성 예제

<예제 7-10 >

✍️ 입력

public class Ex7_10 {
	public static void main(String[] args) {
		Unit[] group = { new Marine(), new Tank(), new Dropship() };

		for (int i = 0; i < group.length; i++)
			group[i].move(100, 200);
	}
}

abstract class Unit {
	int x, y;
	abstract void move(int x, int y);
	void stop() { /* 현재 위치에 정지 */ }
}

class Marine extends Unit { // 보병
	void move(int x, int y) {
		System.out.println("Marine[x=" + x + ",y=" + y + "]");
	}
	void stimPack() { /* 스팀팩을 사용한다. */ }
}

class Tank extends Unit { // 탱크
	void move(int x, int y) {
		System.out.println("Tank[x=" + x + ",y=" + y + "]");
	}
	void changeMode() { /* 공격모드를 변환한다. */ }
}

class Dropship extends Unit { // 수송선
	void move(int x, int y) {
		System.out.println("Dropship[x=" + x + ",y=" + y + "]");
	}
	void load()   { /* 선택된 대상을 태운다. */ }
	void unload() { /* 선택된 대상을 내린다. */ }
}

💻 출력
Marine[x=100,y=200]
Tank[x=100,y=200]
Dropship[x=100,y=200]

if) Unit을 Object로 바꾼다면?
-> Object클래스에 move메서드가 선어되어 있지 않으므로 오류가 날 것이다.
-> 리모콘에 버튼이 없는 거랑 마찬가지임!


📖 35. 인터페이스(interface)


📖 36. 인터페이스의 상속

  1. 인터페이스는 인터페이스로부터만 상속 받을 수 있다.
  2. 다중상속을 허용한다.
    -> why? 다중상속의 문제점은 구현부의 충돌이다. 그러나 인터페이스는 선언만 하기 때문에 충돌 날 일이 없음!

📖 37. 인터페이스의 구현

-> 만일 클래스가 인터페이스의 메소드를 모두 구체화하지 않았다면 클래스를 추상화시켜줘야 한다. (abstract class)
-> 메소드 구체화는 곧 오버라이딩이기 때문에 접근제어자를 public으로 해주어야 한다! why? 인터페이스는 무조건 public이기 때문이다. (오버라이딩 할 때 자식은 부모의 접근제어자보다 좁지 않아야 한다는 조건!)


📖 38. 인터페이스를 이용한 다형성

-> 암기!
1. 인터페이스를 매개변수로 하고 있다면?
-> 인터페이스를 구현한 클래스의 인스턴스를 넣어줘야 한다.
2. 인터페이스를 반환하는 메서드가 있다면?
-> 인퍼테이스를 구현하고 있는 클래스의 인스턴스를 반환해야 한다.


📖 39. 인터페이스의 장점

-> 껍데기 부분과 알맹이 부분을 분리하면 수정을 줄일 수 있다.


📖 40. 디폴트 메서드와 static메서드

-> 외우기 귀찮다면 그냥 필요한거 오버라이딩 해버리면 그만임!


📖 41. 디폴트 메서드와 static메서드 예외

<예제 7-11 >

✍️ 입력

class Ex7_11 {
	public static void main(String[] args) {
		Child3 c = new Child3();
		c.method1();
		c.method2();
		MyInterface.staticMethod(); 
		MyInterface2.staticMethod();
	}
}

class Child3 extends Parent3 implements MyInterface, MyInterface2 {
	public void method1() {	
		System.out.println("method1() in Child3"); // 오버라이딩
	}			
}

class Parent3 {
	public void method2() {	
		System.out.println("method2() in Parent3");
	}
}

interface MyInterface {
	default void method1() { 
		System.out.println("method1() in MyInterface");
	}

	default void method2() { 
		System.out.println("method2() in MyInterface");
	}

	static void staticMethod() { 
		System.out.println("staticMethod() in MyInterface");
	}
}

interface MyInterface2 {
	default void method1() { 
		System.out.println("method1() in MyInterface2");
	}

	static void staticMethod() { 
		System.out.println("staticMethod() in MyInterface2");
	}
}

💻 출력
method1() in Child3
method2() in Parent3
staticMethod() in MyInterface
staticMethod() in MyInterface2


📖 42. 내부 클래스(inner class) && 43. 내부 클래스의 종류와 특징 && 44. 내부 클래스의 선언 && 45. 내부 클래스의 제어자와 접근성


📖 46. 내부 클래스의 제어자와 접근성 예제 1

<예제 7-12 >

✍️ 입력

class Ex7_12 { 
	class InstanceInner { 
		int iv = 100; 
//		static int cv = 100;            // 에러! static변수를 선언할 수 없다. 
		final static int CONST = 100;   // final static은 상수이므로 허용
	} 

   static class StaticInner { 
		int iv = 200; 
		static int cv = 200;    // static클래스만 static멤버를 정의할 수 있다. 
	} 

	void myMethod() { 
		class LocalInner { 
			int iv = 300; 
//			static int cv = 300;             // 에러! static변수를 선언할 수 없다. 
			final static int CONST = 300;    // final static은 상수이므로 허용 
		} 
	} 

	public static void main(String args[]) { 
		System.out.println(InstanceInner.CONST); 
		System.out.println(StaticInner.cv); 
	} 
}

💻 출력
100
200

-> 내부 클래스 중에서 스태틱 클래스만 static멤버를 가질 수 있다. 드문 경우지만 내부 클래스에 static변수를 선언해야 한다면 스태틱 클래스로 선언해야 한다.

-> why? 클래스 멤버를 사용할 때 객체생성을 안해줘도 되는데 내부클래스가 스테틱클래스가 아니라면 객체를 생성하고 클래스 멤버를 사용해야 하기 때문임!

-> 다만 final과 static이 동시에 붙은 변수는 상수(constant)이므로 모든 내부 클래스에서 정의가 가능하다.


📖 47. 내부 클래스의 제어자와 접근성 예제 2

<예제 7-13 >

✍️ 입력

class Ex7_13 {
	class InstanceInner {}
	static class StaticInner {}

	// 인스턴스멤버 간에는 서로 직접 접근이 가능하다.
	InstanceInner iv = new InstanceInner();
	// static 멤버 간에는 서로 직접 접근이 가능하다.
	static StaticInner cv = new StaticInner();

	static void staticMethod() {
      // static멤버는 인스턴스멤버에 직접 접근할 수 없다.
//		InstanceInner obj1 = new InstanceInner();	
		StaticInner obj2 = new StaticInner();

      // 굳이 접근하려면 아래와 같이 객체를 생성해야 한다.
      // 인스턴스클래스는 외부 클래스를 먼저 생성해야만 생성할 수 있다.
		Ex7_13 outer = new Ex7_13();
		InstanceInner obj1 = outer.new InstanceInner();
	}

	void instanceMethod() {
      // 인스턴스메서드에서는 인스턴스멤버와 static멤버 모두 접근 가능하다.
		InstanceInner obj1 = new InstanceInner();
		StaticInner obj2 = new StaticInner();
		// 메서드 내에 지역적으로 선언된 내부 클래스는 외부에서 접근할 수 없다.
//		LocalInner lv = new LocalInner();
	}

	void myMethod() {
		class LocalInner {}
		LocalInner lv = new LocalInner();
	}
}

💻 출력
없음.


📖 48. 내부 클래스의 제어자와 접근성 예제 3

<예제 7-14 >

✍️ 입력

class Outer {
	private int outerIv = 0;
	static  int outerCv = 0;

	class InstanceInner {
		int iiv  = outerIv;  // 외부 클래스의 private멤버도 접근가능하다.
		int iiv2 = outerCv;
	}

	static class StaticInner {
// 스태틱 클래스는 외부 클래스의 인스턴스멤버에 접근할 수 없다.
//		int siv = outerIv;
		static int scv = outerCv;
	}

	void myMethod() {
		int lv = 0;
		final int LV = 0;  // JDK1.8부터 final 생략 가능

		class LocalInner {
			int liv  = outerIv;
			int liv2 = outerCv;
//	외부 클래스의 지역변수는 final이 붙은 변수(상수)만 접근가능하다.
//			int liv3 = lv;	// 에러!!!(JDK1.8부터 에러 아님)
			int liv4 = LV;	// OK
		}
	}
}

💻 출력
없음.

-> 지역 클래스는 final이 붙은 지역변수만 접근가능한데 그이유는 메서드가 수행을 마쳐서 지역변수가 소멸된 시점에도, 지역 클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생 할 수 있다.


📖 49. 내부 클래스의 제어자와 접근성 예제 4

<예제 7-15 >

✍️ 입력

class Outer2 {
	class InstanceInner {
		int iv = 100;
	}

	static class StaticInner {
		int iv = 200;
		static int cv = 300;
	}

	void myMethod() {
		class LocalInner {
			int iv = 400;
		}
	}
}

class Ex7_15 {
	public static void main(String[] args) {
		// 인스턴스클래스의 인스턴스를 생성하려면
		// 외부 클래스의 인스턴스를 먼저 생성해야 한다.
		Outer2 oc = new Outer2();
		Outer2.InstanceInner ii = oc.new InstanceInner();

		System.out.println("ii.iv : "+ ii.iv);
		System.out.println("Outer2.StaticInner.cv : "+Outer2.StaticInner.cv);
                                     
	   // 스태틱 내부 클래스의 인스턴스는 외부 클래스를 먼저 생성하지 않아도 된다.
		Outer2.StaticInner si = new Outer2.StaticInner();
		System.out.println("si.iv : "+ si.iv);
	}
}

💻 출력
ii.iv : 100
Outer2.StaticInner.cv : 300
si.iv : 200

-> 컴파일 시 생성되는 클래스 파일은 다음과 같다.


📖 50. 내부 클래스의 제어자와 접근성 예제 5

<예제 7-16 >

✍️ 입력

class Outer3 {
	int value = 10;	// Outer3.this.value

	class Inner {
		int value = 20;   // this.value

		void method1() {
			int value = 30;
			System.out.println("            value :" + value);
			System.out.println("       this.value :" + this.value);
			System.out.println("Outer3.this.value :" + Outer3.this.value);
		}
	} // Inner클래스의 끝
} // Outer3클래스의 끝

class Ex7_16 {
	public static void main(String args[]) {
		Outer3 outer = new Outer3();
		Outer3.Inner inner = outer.new Inner();
		inner.method1();
	}
}

💻 출력
value :30
this.value :20
Outer3.this.value :10


📖 51. 익명 클래스(anonymous class) && 52. 익명 클래스(anonymous class) 예제

-> 조상클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 사용해서 정의하기 때문에 하나의 클래스로 상속받는 동시에 인터페이스를 구현하거나 둘 이상의 인터페이스를 구현할 수 없다.





[출처] 자바의 정석 <기초편> (남궁 성 지음)

profile
멈추지 않기

0개의 댓글