Java basic #3

어떤다람쥐·2023년 11월 2일
1

Java basic

목록 보기
3/3
post-thumbnail

상속 (Inheritance)

  • 기존의 클래스로 새로운 클래스를 작성하는 것 (코드의 재사용)
  • 두 클래스를 부모와 자식으로 관계를 맺어주는 것
  • 자손은 조상(부모의 부모까지)의 모든 멤버를 상속 받음 (생성자, 초기화블럭은 제외)
  • 자손의 멤버 개수는 조상보다 적을 수 없음 (같거나 많다)
  • 키워드 extends
class 자식클래스 extends 부모클래스 {
	// ...
}

class Parent {	// 멤버 1개
	int age;
}

class Child extends Parent {	// 부모로 받은 멤버 1개
}
  • 자손의 변경은 조상에 영향을 미치지 않음
class Parent {	// 멤버 1개
	int age;
}

class Child extends Parent {	// 멤버 2개 (자신 멤버 1개, 상속 받은 멤버 1개)
	void play() {	// 자식에게 새로운 멤버가 추가 되었지만 부모는 영향 받지 않음
		System.out.println("놀자~");
	}
}
  • 상속을 받고 안 받고의 차이점
class Point {
	int x;
	int y;
}

class Point3D {	// Point 클래스와 관계가 없고 영향을 안 받음
	int x;
	int y;
	int z;
}

class Point3D extends Point {	// Point 클래스에 영향을 받음
								// 부모 멤버 개수가 줄거나 늘면 영향을 받음
	int z;
}

포함 관계

  • 포함(composite)이란? 클래스의 멤버로 참조변수를 선언하는 것을 말함
  • 작은 단위의 클래스를 만들고, 이들을 조합해서 클래스를 만든다
  • 클래스의 관계는 크게 상속과 포함으로 구분됨
class Point {
	int x;
	int y;
}

class Circle {
	int x;
	int y;
	int r;
}
class Circle2 {	// Circle클래스가 Point클래스를 포함(composite)하고 있음
	Point c = new Point(); 	
	int r;
}

class Ex {
	public static void main(String[] args) {
		Circle c = new Circle();	// c.x
		Circle c2 = new Circle2();	// c.c.x
	}
}

클래스 간의 관계 결정하기

  • 상속 관계 : ~은 ~이다 (is -a)
  • 포함 관계 : ~은 ~을 가지고 있다 (has -a) (90%)

원은 점이다 - Circle is a Point
원은 점을 가지고 있다. - Circle has a Point

class MyPoint {
	int x;
	int y;
}

class Circle {
	MyPoint p = new MyPoint();
	int r;
}

class Circle2 extends MyPoint {	// 상속
	int r;
}

class InheritanceTest {
	public static void main(String[] args) {
		Circle c = new Circle();	// 참조변수 c에 주소값이 저장되어 있음
		c.p.x = 1;	// 참조변수  c.p에 주소값이 저장되어 있음
		c.p.y = 1;
		c.r = 2;
	
		Circle2 c2 = new Circle2();
		c.x = 1;
		c.y = 2;
		c.r = 3;
	}
}

단일 상속(Single Inheritance)

  • Java는 단일상속만을 허용함 (C++은 다중상속 허용)
class Tv {
	void power { // A로직 실행}
}
class DVD {
	void power { // B로직 실행}
}

class TvDVD extends Tv, DVD {	// 에러. 자바는 조상을 하나만 허용함
	// 이유: power() 메소드를 호출 시 두 부모의 power() 메소드가 충돌이 발생
}
  • 다중 상속처럼 사용하기 : 비중이 높은 클래스 하나만 상속 관계로, 나머지는 포함관계로 한다
class Tv {
	boolean power;
	int channel;
	
	void power() { power = !power;}
	void channelUp() { ++channel; }
	void channelDown() { --chanel; }
}

class DVD {
	boolean power;
	
	void power() { power = !power; }
	void play() { /* 내용 생략 */ }
	void stop() { /* 내용 생략 */ }
	void rew() { /* 내용 생략 */ }
	void ff() { /* 내용 생략 */ }
}

class TvDVD extends Tv {	// 비중이 높은 놈을 상속 받음
	DVD dvd = new DVD();	// 포함관계로 사용
	
	void play() {	// dvd의 객체를 사용하여 dvd의 메소드를 호출
		dvd.play();
	}
	void stop() {
		dvd.stop();
	}
	void rew() {
		dvd.rew();
	}
	void ff() {
		dvd.ff();
	}
}

Object 클래스 (모든 클래스의 조상)

  • 부모가 없는 클래스는 자동적으로 Object클래스를 상속 받게 된다
  • 모든 클래스는 Object클래스에 정의된 11개의 메서드를 상속받는다
    toString(), equals(Object ojb), hashCode(), ... 등등
class Tv { }
// Tv클래스에 부모를 선언하지 않으면 컴파일러가 자동으로 추가
// class Tv extends Object {}

class SmartTv extends Tv {}
// 부모가 있는 경우는 Object 클래스를 추가하지 않음
// 상속 계층도 : SmartTv => Tv => Object (하위 => 상위 순)
// 고로, SmartTv도 Object클래스를 상속 받는다

메서드 오버라이딩 (Overriding)

  • 상속 받은 조상의 메서드를 자신에 맞게 변경하는 것
class Point extends Object {
	int x;
	int y;
	String getLocation() {
		return "x:" + x + ", y:" + y;
	}

	public String toString() {	// Object클래스의 toString()을 오버라이딩 함
		return "x:" + x + ", y:" + y;
	}
}

class Point3D extends Point {
	int z;
	
	String getLocation() {	// 조상의 getLocation()을 오버라이딩
    	// 내용만 변경가능 (선언부는 변경 불가)
		return "x:" + x + ", y:" + y + ", z:" + z;
	}
}

public class OverrideTest {
	public static void main(String[] args) {
		Point3D p3 = new Point3D();
		p3.x = 3;
		p3.y = 4;
		p3.z = 5;
		System.out.println(p.getLocation());	// x:3, y:4, z:5
		
		Point p = new Point();
		p.x = 1;
		p.y = 2;
		System.out.println(p.toString);	// x:1, y:2
		System.out.println(p);	// x:1, y:2
	}
}

오버라이딩(Overring)의 조건

  • 선언부가 조상 클래스의 메서드와 일치해야 함 (반환 타입, 메서드 이름, 매개변수 목록)
  • 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없음
    public, protected, (default), private
  • 예외(Exception)는 조상 클래스의 메서드보다 많이 선언할 수 없음
class Parent {
	void parentMethod() throws IOException, SQLException {	// 조상 메서드의 Exception 2개
		// ...
	}
}

class Child extends Parent {
	void parentMethod() throws IOException {	// 자식은 조상보다 작거나 같아야 함
		// ...
	}
}

오버로딩 vs 오버라이딩 (둘은 관계가 없다)

  • 오버로딩(overloading) : 기존에 없는 새로운 메서드를 정의하는 것(new)
  • 오버라이딩(overriding) : 상속 받은 메서드의 내용을 변경하는 것 (change, modify)
class Parent {
	void parentMethod() {}
}

class Child extends Parent {
	void parentMethod() {}	// 오버라이딩
	void parentMethod(int i) {}	// 오버로딩
	
	void childMethod() {}	// 메소드 정의
	void childMethod(int i) {}	// 오버로딩
	void childMethod() {}	// 중복 정의
}

참조변수 super

  • super란? 객체 자신을 가리키는 참조변수
  • 인스턴스 메서드(생성자)내에만 존재 (static 메서드에서는 사용불가)
  • 조상의 멤버를 자신의 멤버와 구별할 때 사용
class Ex {
	public static void main(String[] args) {
		Child c = new Child();
		c.method();
	}
}

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

class Child extends Parent {
	int x = 20;	// this.x
	
	void method() {
		System.out.println("x=" + x);	// x=20
		System.out.println("this.x=" + this.x);	// this.x=20
		System.out.println("super.x=" + super.x);	// super.x=10;
	}
}
class Ex2 {
	public static void main(String[] args) {
		Child2 c = new Child2();
		c.method();
	}
}

class Parent2 { int x = 10; /* super.x */ }

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

super() 조상의 생성자

  • 조상의 생성자를 호출할 때 사용
  • 조상의 멤버는 조상의 생성자를 호출해서 초기화
  • 상속 시 조상의 생성자와 초기화 블럭은 상속불가, 그래서 super로 호출해야 함
  • super()와 super는 다름
class Point {
	int x, y;

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

class Point3D extends Point {
	int z;
	Point3D(int x, int y, int z) {
		this.x = x;	// 조상의 멤버를 초기화
		this.y = y;	// 조상의 멤버를 초기화
		// 위 방법으로 사용할 수 있지만 조상의 멤버는 조상 생성자가 초기화 하는 것이 좋음
		
		super(x, y);	// 조상클래스의 생성자 Point(int x, int y)를 호출
		this.z = z;	// 자신의 멤버를 초기화
	}
}
  • 모든 생성자의 첫 줄에는 반드시 다른 생성자를 호출해야 한다
  • 그렇지 않으면 컴파일러가 생성자의 첫 줄에 super()를 삽입한다
class Point extends Object {
	int x;
	int y;

	Point() {
		this(0,0);	// ok
	}
	
	Point(int x, int y) {
		// 첫 줄에 생성자가 없어서 컴파일러가 자동으로 super() 추가함
        // super(); <= Object() 기본 생성자를 호출하게 됨
        
		this.x = x;
		this.y = y;
	}
}

제어자 (modifier)

  • 클래스와 클래스의 멤버(멤버 변수, 메서드)에 부가적인 의미 부여
  • 접근 제어자 : public, protected, (defalut), 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 - 클래스의, 공통적인

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;	// 클래스 메서드 안에서 iv사용 못함
        						// instance메서드 사용 못함
	}
    // static 변수, 메서드는 객체 생성 없이 사용해야 함
}

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

final class FinalTest {	// 조상이 될 수 없는 클래스 (String클래스, Math클래스 등등)
						// 자식을 가질 수 없으며, 상속계층도에서 최하위에 위치함
	final int MAX_SIZE = 10;	// 값을 변경할 수 없는 멤버변수(상수)
    
    final void getMaxSize() {	// 오버라이딩할 수 없는 메서드 (변경불가)
    	final int LV = MAX_SIZE;	// 값을 변경할 수 없는 지역변수(상수)
        return MAX_SIZE;
    }
}

abstact - 추상의, 미완성의 (추상화)

abstract class AbstractTest {	// 추상클래스(추상 메서드를 포함한 클래스)
	abstract void move();		// 추상 메서드(구현부가 없는 메서드)
    // 미완성 클래스 - 미완성 설계도 - 제품 생성 불가
}

AbstractTest a = new AbstractTest();	// 에러. 추상클래스의 인스턴스 생성불가
// 추상(미완성)클래스를 상속 받아서 구상(완전한)클래스를 만든 후에 객체생성이 가능함

접근 제어자(access modifier)

  • private : 같은 클래스 내에서만 접근 가능
  • (default) : 같은 패키지 내에서만 접근 가능
  • protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근 가능
  • public : 모든 곳에서 접근 가능

public (전체) > protected (같은 패키지+자손) > (default) (같은 패키지) > private(같은 클래스)

[public | (default)] class AccessModifierTest {	// 클래스는 public, (default)만 가능
	// 멤버(iv, cv, im)는 4개 모두 가능
	[public | protected | (default) | private] int iv;
	[public | protected | (default) | private] static int cv;
    [public | protected | (default) | private] void method() {}
}
package pkg1;
public class MyParent {
	private int prv;
    (default) int dft;
    protected int prt;
    public int pub;
    
    public void printMembers() {
    	System.out.println(prv);	// ok.
        System.out.println(dft);	// ok.
        System.out.println(prt);	// ok.
        System.out.println(pub);	// ok.
    }
}

class MyParentTest {	// 접근 제어자  (default)
	public static void main(String[] args) {
    	MyParent p = new MyParent();
        System.out.println(p.prv);	// 에러. 같은 클래스가 아니라서 사용불가
        System.out.println(p.dft);	// ok. 같은패키지안에 있어서 사용가능
        System.out.println(p.prt);	// ok. 같은패키지(+자손)안에 있어서 사용가능
        System.out.println(p.pub);	// ok. 모든 곳에서 접근가능
    }
}

package pkg2;
import pkg1.MyParent;

class MyChild extends MyParent {
	public void printMembers() {
    	System.out.println(prv);	// 에러. 같은 클래스가 아니라서 사용불가
        System.out.println(dft);	// 에러. 같은 패키지가 아니라서 사용불가
        System.out.println(prt);	// ok. 자손클래스에서 접근해서 사용가능
        System.out.println(pub);	// ok. 모든 곳에서 사용가능
	}
}

public class MyParentTest2 {
	public static void main(String[] args) {
    	MyParent p = new MyParent();
        System.out.println(p.prv);	// 에러. 같은 클래스가 아니라서 사용불가
        System.out.println(p.dft);	// 에러. 같은 패키지가 아니라서 사용불가
        System.out.println(p.prt);	// 에러. 같은패키지+자손클래스가 아니라서 사용불가
        System.out.println(p.pub);	// ok. 모든 곳에서 사용가능
    }
}

출처 : 남궁성의 정석코딩

profile
쳇바퀴도 바퀴다! 존나게 뛰자!!

0개의 댓글