chapter 7 객체지향 2

JMG·2022년 1월 16일
0

자바의 정석

목록 보기
10/13

📖 상속(Inheritance)

상속이란 기존의 클래스로 새로운 클래스를 작성하는 것을 의미합니다.(코드의 재사용)
두 클래스를 부모와 자식으로 관계를 맺어줍니다.

class 자식클래스 extends 부모클래스 {
	//...
}
  • 자손은 조상의 모든멤버를 상속받는다. (생성자, 초기화블럭 제외)
  • 자손의 멤버개수는 조상보다 적을 수 없다.(같거나 많다.)

 class Parent { 
	int age;
}
class Child extends Parent { } 
//아무것도 안적었지만 Parent클래스의 age변수를 상속받고 있다.
  • 자손의 변경은 조상에 영향을 미치지 않는다.
class Parent {
	int age;
}

class Child extends Parent {
	void play() { //부모 클래스에 영향이 없다.
		System.out.println("play");
	}
}

예제)

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

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

//SmartTv는 Tv에 캡션(자막)을 보여주는 기능을 추가
//SmartTv의 멤버변수는 부모클래스의Tv까지 전부 상속받았다.
class SmartTv extends Tv { 
	boolean caption; // 캡션상태(on/off)
	void displayCaption(String text) {
		if(caption) {
			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");

	}
}

📖 포함 관계(composite)

포함(composite)이란 클래스의 멤버로 참조변수를 선언하는 것을 의미합니다.
작은 단위의 클래스를 만들고, 이들을 조합해서 클래스를 만듭니다.

class Circle {
	Point c = new Point(); //  포함관계
	int r;
}

class Point {
	int x;
	int y;
}

📌 클래스 간의 관계 결정하기

상속관계
~은 ~이다.(is-a)
포함관계
~은 ~을 가지고 있다(has-a) ->대부분 포함관계인경우가 많다.

📖 단일 상속(Single Inheritance)

Java는 단일 상속만을 허용합니다.
비중이 높은 클래스 하나만 상속관계로, 나머지는 포함관계로 설계합니다.

📌 다중상속의 문제점

만약 두 부모에 동명의 메서드가 있는경우(충돌문제)

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

  • Object클래스는 상속계층에서 최상층에 있는 클래스입니다.

  • 부모가 없는 클래스는 자동적으로 Object클래스를 상속받게 됩니다.

  • 모든 클래스는 Object클래스에 정의된 11개의 메서드를 상속받습니다.
    toString()(중요), equals(Object obj), hashCode(), ....(9장에서 자세히...)

  • toString() - '클래스명@객체의 메모리주소값' 형태로 출력됩니다.
    그냥 참조변수를 출력해도 toString()을 호출해서 출력합니다.

📖 오버라이딩(overriding)

오버라이딩은 상속받은 조상의 메서드를 자신에 맞게 변경하는 것을 의미합니다.

예제)

class Point {
	int x;
	int y;
	
	String getLocation() {
		return "x: "+x+", y: "+y;
	}
}

class Point3D extends Point {

	int z;
	//선언부는 변경불가
	//내용(구현부{})만 변경가능
	String getLocation() {
		return "x: "+x+", y: "+y+", z: "+z;
	}
}

📌 오버라이딩의 조건

  1. 선언부가 조상클래스의 메서드와 일치해야한다.
    선언부 : 반환타입, 메서드이름, 매개변수 목록
  2. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
  3. 예외는 조상클래스의 메서드보다 많이 선언할 수 없다.

📌 오버로딩 vs 오버라이딩

오버로딩(overloading) - 이름은 같으나 기존의 없는 새로운 메서드를 정의하는것
오버라이딩(overriding) - 상속받은 메서드의 내용을 변경하는 것

📖 참조변수 super

조상 클래스를 가리키는 참조변수. 인스턴스 메서드(생성자)내에만 존재합니다.
조상의 멤버를 자신의 멤버와 구별할 때 사용됩니다.

예제)

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

//super.x
class Parent { int x = 10; }

class Child extends Parent {
	int x = 20;

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

📖 super() - 조상의 생성자

조상의 생성자를 호출할 때 사용됩니다.
조상의 멤버는 조상의 생성자를 호출해서 초기화됩니다.

예제)

class Point { 

	int x, y;

	Point(int x, int y) {
		this.x = x;
		this.y = y;
	}

}

class Point3D extends Point {

	Point3D(int x, int y, int z) {
		super(x, y); // 조상의 생성자를 호출
		this.z = z;
	}

}

📌 super()의 특징

생성자의 첫줄에 반드시 생성자를 호출해야 합니다.
그렇지 않으면 컴파일러가 생성자의 첫 줄에 super();를 자동으로 삽입하게 됩니다.
만약 상속받은 클래스가 없다면 Object()의 super()를 실행하게 됩니다.

만약 상속받은 클래스의 생성자에 기본생성자가 없고 매개변수가 있다면 반드시 매개변수를 넣은 super(매개변수1, 매개변수2, ....)를 사용해야합니다.

예제)

class Point {

	int x;
	int y;
	
    	//Point() {}
	Point(int x, int y) {
		this.x = x;
		this.y = y;
	}

}

class Point3D extends Point {

	int z;

	Point3D(int x, int y, int x) {
		super(x, y);//작성안할시 에러발생
		this.z = z;
	}
}

📖 패키지(package)

패키지란 서로 관련된 클래스의 묶음을 의미합니다.
실제로 컴퓨터에서 클래스는 클래스파일(*.class), 패키지는 폴더로 구성되어 있습니다.(하위 패키지는 하위 폴더로 구성)
클래스의 실제 이름(full name)은 패키지를 포함하고 있는 형태입니다.(java.lang.String)
rt.jar는 클래스들을 압축한 파일을 의미합니다.(JDK설치경로 \jre\lib에 위치)

📌 패키지의 선언

패키지는 소스파일의 첫 번째 문장으로 단 한번만 선언해야 합니다.
같은 소스 파일의 클래스들은 모두 같은 패키지에 속하게 됩니다.
패키지 선언이 없으면 이름없는(unnamed)패키지에 속하게 됩니다.


package com.codechobo.book;

public class PackageTest {
	public static void main(String[] args) {
		System.out.println();
	}
}

📖 import문

import문을 이용하면 클래스를 사용할 때 패키지이름을 생략할 수 있습니다.

//원래는 아래와같이 작성해야한다.
class ImportTest {
	java.util.Date today = new java.util.Date();
	//....
}

//import문을 이용하면 아래와같이 패키지를 생략할 수 있다.
import java.util.Date;

class ImportTest {
	Date today = new Date();
}

📌 java.lang패키지

java.lang패키지의 클래스는 import하지 않고도 사용할 수 있습니다.
String, Object, System, Thread ....

📌 java.lang.*패키지

import문을 선언하는 방법은 다음과 같습니다.

//패키지의 특정클래스 가져오기
import 패키지명.클래스명;
//패키지의 모든 클래스 가져오기
import 패키지명.*;

import문은 패키지문과 클래스선언의 사이에 선언합니다.

예제)

package com.codechobo.book;

import java.text.SimpleDateFormat;
import java.util.*;

public class PackageTest {
	public static void main(String[] args) {
		Date today = new Date();
		SimpleDateFormat date = new SimpleDateFormat("yyyy/MM/dd");
	}
}

import문은 컴파일 시에 처리되므로 프로그램의 성능에 영향없습니다.
그러므로 모든클래스를 가져오는 import 패키지명.*;을 써도 무방합니다.

📌 import java.util.;과 import java.;의 차이점

import java.util.*;

  • java.util패키지의 모든 클래스포함

import java.*;

  • java패키지의 모든클래스포함
  • 패키지는 포함이 안된다.(util패키지등..)

📌 static import문

클래스 이름을 생략할 수 있게 해줍니다.
꼭 필요할때만 사용하는 것이 좋습니다.

import static java.lang.Math.random; //Math.random()만
import static java.lang.System.out; //System.out을 out만으로 참조가능

//System.out.println(Math.random());
out.println(random());

📖 제어자(modifier)

클래스와 클래스의 멤버(멤버변수, 메서드)에 부가적인 의미 부여하는 역할을 합니다.

접근제어자

public, protected, (default), private

그 외

static, final, abstract, native, transient, synchronized, volatile,strictfp

📌 하나의 대상에 여러 제어자를 같이 사용가능(접근제어자는 하나만)

public class ModifierTest {
	public static final int WIDTH = 200;

	public static void main(String[] args) {
		System.out.println("WIDTH = "+WIDTH);
	}
}

📌 static - 클래스의, 공통적인

멤버변수

  • 모든 인스턴스에 공통적으로 사용되는 클래스 변수가 된다.
  • 클래스 변수는 인스턴스(객체)를 생성하지 않고도 사용가능하다.
  • 클래스가 메모리에 로드될 때 생성된다.

메서드

  • 인스턴스를 생성하지 않고도 호출이 가능한 static메서드가 된다.
  • static메서드내에서는 인스턴스 멤버들을 직접 사용할 수 없다.

예제)

class StaticTest {

	static int width = 200; //클래스 변수(static 변수)
	static int height = 120;  //클래스 변수(static 변수)

	static { //클래스 초기화 블럭
		//static변수의 복잡한 초기화 수행
	}

	static int max(int a, int b) { //클래스 메서드(static메서드)
		return a > b ? a : b;
	}
}

📌 final - 마지막의, 변경될 수 없는

클래스

  • 변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다.
    그래서 final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다.

메서드

  • 변경 될 수 없는 메서드, final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다.

멤버변수, 지역변수

  • 변수 앞에 final이 붙으면, 값을 변경할 수 없는 상수가 된다.

예제)

final class FinalTest { //조상이 될수 없는 클래스
	final int MAX_SIZE  = 10; // 값을 변경할 수 없는 멤버변수(상수)

	final void getMaxSize() { // 오버라이딩할 수 없는 메서드(변경불가)
		final int LV = MAX_SIZE; //값을 변경할 수 없는 지역변수(상수)
		return MAX_SIZE;
	}
}

📌 abstract 추상의, 미완성의

클래스

  • 클래스내에 추상 메서드가 선언되어 있음을 의미한다.

메서드

  • 선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 의미한다.
abstract class AbstractTest {	// 추상 클래스(추상 메서드를 포함한 클래스)
	abstract void move(); // 추상 메서드(구현부가 없는 메서드)
}

AbstractTest a = new AbstractTest(); // 에러!! 추상클래스의 인스턴스는 생성할 수 없다.

추상클래스를 상속받아서 완전한 클래스를 만든후에 객체생성이 가능하다(차후 강의 예정)

📖 접근제어자(access modifier)

4개중 1개만 사용이 가능합니다.

  1. private
    같은 클래스 내에서만 접근이 가능하다.
  2. (defualt)->아무것도 안적은 경우
    같은 패키지 내에서만 접근이 가능하다.
  3. protected
    같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근이 가능하다.
  4. public
    접근 제한이 전혀 없다.
제어자같은 클래스(파일)같은 패키지(폴더)자손클래스(다른폴더)전체
publicoooo
protectedooo
(default)oo
privateo

클래스

  • public, (default) 이 2가지만 클래스앞에 사용이 가능하다
  • public 클래스의 클래스명으로 파일명을 설정해줘야한다.

멤버변수

  • 4가지 전부 사용이 가능하다.

📖 캡슐화와 접근 제어자

📌 접근 제어자를 사용하는 이유

  • 외부로부터 데이터를 보호하기 위해서
  • 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해

예제)

class Time {
	
	//접근 제어자를 private으로 하여
	//외부에서 직접 접근하지 못하도록 한다.
	private int hour;
	private int minute;
	private int second;

	public int getHour() { return hour; }
	//함수를 통해 데이터를 정제할 수 있다.
	public void setHour(int hour) {
		if (hour < 0 || hour > 23) {
			return;
		}
		this.hour = hour;
	}

	public int getHour() { 
		return hour; 
	}

}

public class TimeTest {
	public static void main(String[] args) {
		//위와같이 코드를 작성하면 다음과같은 코드를 막을 수 있다.
		Time t = new Time();
		t.hour = 52; // 에러발생!
	}
}

📖 다형성(polymorphism)

여러 가지 형태를 가질 수 있는 능력을 의미하고
java에서의 정확한 의미는 조상 타입 참조 변수로 자손 타입 객체를 다루는 것을 의미합니다.
조상타입의 맴버변수만 제한적으로 사용할 때 주로 이용합니다.

예제)

class Tv {
	boolean power;
	int channel;

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

class SmartTv extends Tv {
	String text;
	void caption() { //.....}
}

public class Polymorphism {
	public static void main(String [] args) {
		Tv tv = new SmartTv(); //조상타입 참조변수 = new 자손타입();
	}
}

📌객체와 참조변수의 타입이 일치할 때 와 일치하지 않을 때의 차이

//일치(조상, 자손 멤버 전부사용가능)
SmartTv s = new SmartTv(); // 참조변수와 인스턴스의 타입이 일치

//불일치(변수 전부사용불가 조상의 멤버만 사용가능)
Tv t = new SmartTv(); // 조상타입 참조변수로 자손 타입 인스턴스 참조

반대로 자손타입의 참조변수로 조상타입의 객체를 가리킬수 없습니다.

SmartTv s = new Tv(); //에러! 허용안됨
//이유: 조상타입에 없는 멤버를 자손측에서 호출하게 되면서 에러가 발생하게 됩니다.
profile
초보개발 블로그입니다~

0개의 댓글