티스토리 뷰

반응형

Do it! 자바 프로그래밍 입문을 보면서 익힌 객체 지향 기본 개념들을 보기 쉽게 정리

 

생성자

  • 인스턴스를 생성할 때 초기화시키는 함수 (생성자를 메서드라고 부르진 않음)
  • 생성자의 이름은 해당 클래스와 동일하게
  • 파라메터만 다르게 해서 여러 개의 생성자를 만들 수 있음(오버로딩)
  • 클래스 내에 생성자가 하나라도 없으면 JVM이 프리 컴파일 단계에서 알아서 만들어서 넣어줌
public class Student {
	String name;
	int grade;
	public Student() {} //default 생성자
	
	//오버라이딩해서 새로만든 생성자
	public Student(String name,int grade) {
		this.name = name;
		this.grade = grade;
	}
}​

*this는 해당 객체 자기 자신의 주소를 가리키는 변수임. 자바 코딩에선 이런 스타일로 많이 코딩한다

 

this의 사용처

1. 생성자로 멤버 변수에 값을 넣을 때 ex) this.name = name;

2. 생성자에서 다른 생성자를 호출할 때

public class Student {
	String name;
	int grade;
	public Student() {
		this("홍길동",2); //밑 생성자를 호출할 때
	} 
	
	//오버라이딩해서 새로만든 생성자
	public Student(String name,int grade) {
		this.name = name;
		this.grade = grade;
	}
}

*이때 this("홍길동",2) 기준 앞 라인은 꼭 비워놓아야 한다

 

3. 인스턴스의 주소 값을 리턴해주는 메서드를 만들 때

	public Student getAddressSelf() {
		return this; //반환값은 클래스명으로
	}

 

static 키워드

  변수 메서드
설명 공용으로 접근하는 변수
(자바의 전역변수) 
인스턴스 생성 없이도 접근할 수 있는 메서드 (클래스 이름으로 접근)
언제 사용하는 가? 전역 변수를 사용하고 싶을 때 유틸리티 메서드를 만들 때
(ex. 최대값을 구하는 메서드)
  • static 메서드 구현부에 인스턴스 변수 사용불가 (멤버 변수는 new예약어로 객체가 생성될 때 같이 생성되는데 static 메서드는 객체 없이 클래스명으로 접근이 가능하기 때문에 생성되지도 않은 객체의 멤버 변수를 접근할 수 있는 위험도가 존재하기 때문에 사전에 방지하는 것)
  • static 변수는 private 으로 선언하고 get 메서드로 접근하는 것이 좋음

 

singleton 패턴

public class Korea {
	private Korea korea = new Korea(); //하나의 객체만 해당 클래스에서 생성
	private Korea() {} //생성을 다른 클래스에서 못하도록 잠근다
	
	public Korea getKorea() {
		return korea;
	}
	
}
  • 오직 하나의 객체만 존재했음 할 때 사용하는 디자인 패턴
  • 위와 같이 생성자를 private으로 잠그고 해당 클래스에서 객체를 하나 생성한다
  • 다중 스레드에서 여러 객체가 생성되는 문제가 발생할 수 있는데, 이땐 생성 코드에 static을 붙여주면 된다

 

배열

		int[] arr = new int[3];
		int arr[] = new int[3];
		int[] arr = new int[] {1,2,3}; //초기화
		int[] arr = {1,2,3}; //초기화2 근데 자바에서 이렇게 잘 안함
		String[] arr = new String[] {"hi","hello"};
  • 배열 객체를 생성하는 개념으로 선언
  • 배열 생성 시 자동 초기화 (int는 0, char는 공백)
  • 배열 이름. length()를 통해서 배열의 길이를 구할 수 있음
  • 배열의 요소를 모두 순환하는 for문을 작성하고 싶을 때, 다음과 같이 작성할 수 있음(향상된 for문이라고 함)
		int count = 0;
		for (int n : arr) {
			count++;
		}

 

상속

  • 해당 클래스에서 좀 더 구체적인 클래스를 만들고 싶을 때 사용하는 행위 ex) 부모 클래스:컴퓨터 ->(상속)->자식 클래스:노트북
  • 주의할 점은, 클래스 합성과 혼동하면 안 됨!! (상속 : 일반화 대상을 좀 더 구체적으로)
class Computer {
	String keyboard;

	void print(int keyboard) {
		System.out.println(keyboard);
	}
}

public class Notebook extends Computer {
	public static void main(String[] args) {
		Notebook myNewNotebook = new Notebook();
		myNewNotebook.keyboard = "my keyboard";
	}
}
  • 자식 클래스의 객체를 생성할 땐, 부모 클래스의 객체를 생성해 놓고(힙 메모리에) 생성함 (그 이유는 자식클래스 인스턴스가 부모클래스의 변수, 메서드에 접근할 수 있어야 하기 때문)
  • super() : this는 자기 자신을 가리킨다면, super는 부모 클래스의 생성자를 가리킨다. 호출 시 생성자의 파라미터와 동일하게 설정해 주어야 함(프리 컴파일 단계에서 자바 컴파일러가 default 생성자와 마찬가지로 없으면 감지해서 넣어줌. 또한, this와 마찬가지로 코드 맨 앞줄에 위치해야 함)
class Computer {
	String keyboard;

	Computer(){
		System.out.println("컴퓨터 생성!");
	}
	
	Computer(String type){
		System.out.println(type+" 컴퓨터 생성!");
	}
	
	void print(int keyboard) {
		System.out.println(keyboard);
	}
}

public class Notebook extends Computer {
	public Notebook() {
		super("슈퍼"); //이 라인 앞에는 어떤 코드도 오면 안된다
		System.out.println("노트북 생성!");
	}
	
	public static void main(String[] args) {
		Notebook myNewNotebook = new Notebook();
	}
}

출력 값은 "슈퍼 컴퓨터 생성!" -> "노트북 생성!" 순으로 출력된다.

 

상속의 특징, 기억하면 좋은 것들

  • 모든 클래스의 부모 클래스는 Object라는 클래스 (최상위 클래스 = java.lang.Object)
  • 부모 클래스의 메서드를 자식 클래스로 가져와서 재정의하여 사용하는 행위를 '메서드 오버라이딩'이라고 한다
  • 자바는 다중 상속 지원X (상속받는 부모 클래스는 오직 하나)

 

 

클래스간의 접근성

접근제어자 private default (무선언) protected public
접근 가능 범위 해당 클래스 내부 같은 패키지 내부  상속 받은 자식만 모두
  • protected는 다른 패키지에서 부모를 상속 받았어도 접근 가능
  • public은 다른 패키지에서도 접근 가능 (단, import 해야함)

 

 

업캐스팅 / 다운캐스팅

  • 업캐스팅 : 객체의 타입을 부모 클래스 타입으로 설정하는 것 // Animal myCat = new Cat();
  • 다운캐스팅 : 업캐스팅된 객체의 타입을 다시 자기자신 클래스 타입으로 맞추는 것 // Cat myCat = (Cat) myCat;
  • instanceof 연산자 : 객체의 타입을 반환한다 (C의 typeof 와 동일)

왜 사용하는가 ? 

업캐스팅을 통해서 특정 메서드를 간략화 할 수 있다(다형성에 영향을 미침) 만약 업캐스팅없이 각 개체의 경우에 따라서 메서드의 기능을 다르게 할려면 구현부에 엄청많은 if문이 들어갈 것이다.

 

다형성

  • 하나의 메서드가 상황에 맞게 여러 기능을 수행하도록 하는 것
  • 객체 지향 프로그래밍의 특징. 상속을 통해 구현함
class Shapes {
	void printType() {
		System.out.println("모양 입니다");
	}
}

class Circle extends Shapes{
	void printType() {
		System.out.println("원 입니다");
	}
}

class Square extends Shapes{
	void printType() {
		System.out.println("사각형 입니다");
	}
}

class Triangle extends Shapes{
	void printType() {
		System.out.println("삼각형 입니다");
	}
}

public class PolyTest{
	void printFigure(Shapes type) {
		type.printType(); //printType을 한번만 호출
	}
	public static void main(String[] args) {
		PolyTest n = new PolyTest();
		n.printFigure(new Circle());
		n.printFigure(new Square());
		n.printFigure(new Triangle());
		//어떤 객체가 들어오냐에 따라서 출력값이 달라짐
	}
}
  • 오버라이딩의 대상이 되는 메서드를 가상 메서드라고 부른다 (모든 메서드는 오버라이딩 가능하므로 모든 메서드 = 가상 메서드)
  • 재정의한 메서드를 호출하면 자식 클래스의 오버라이딩된 메서드가 호출된다

 

IS-A vs HAS-A

클래스간의 관계 IS-A (상속) HAS-A (합성)
설명 부모 클래스 : 추상적인
자식 클래스 : 구체적인
다른 클래스를 사용하는 것
ex) 학생 클래스가 과목 클래스를 내포

 

 

추상 클래스

목적 : 상속 받은 자식 클래스에게 일종의 가이드라인을 제공하기 위함 (이 개념은 인터페이스와 이어진다)

  • 메서드의 이름, 파라미터, 리턴타입만 명시되고 구현부는 없는 메서를 '추상 메서드'라고 함 (C언어의 함수 프로토타입 선언과 비슷)
  • 추상 클래스란? 추상 메서드가 적어도 한 개 이상 존재하는 클래스. 아래 그림과 같이 사용한다
public class Cat extends Animal{

	@Override //wizard로 추상 클래스 메서드를 불러오면 이게 붙는다
	void move() {
		System.out.println("움직였다");
	}

	@Override
	void eat() {
		System.out.println("먹었다");
	}

	public static void main(String[] args) {
		Cat myCat = new Cat();
		myCat.move();
	}
}

abstract class Animal {
	abstract void move();
	abstract void eat(); 
	void run(){} //추상 메서드가 아님. 구현부가 존재하는 것(다만 아무 내용이 없는 경우)
}
  • 추상 클래스는 객체를 생성할 수 없다. (상속용 클래스)
  • 추상 클래스를 상속 받으면 추상 메서드들은 무조건 오버라이딩해서 새로 구현해야함

 

final 키워드

  • 무언가를 제한할 때 사용하는 수식어. 사용법은 다음과 같다
  변수 메서드 객체 클래스
제한 사항 값을 고정(변경 불가)
or 한번만 값을 입력
오버라이딩 불가 객체 변수에 새로운 객체를 담을 수 없음 상속 불가
언제 사용하는가? 상수값 설정 구현부 변경을
원치 않을때
객체 변수 고정 상수값을 모아놓은
클래스를 만들 때
  • final 수식어가 붙은 메서드를 '템플릿 메서드'라고 부른다 (프레임워크에서 많이 사용)
		final Client VIP = new Client();
		//VIP = new GoldClient(); 불가능
		
		VIP.name = "김길동"; //필드 접근은 가능

*final 객체 사용 예시

 

 

인터페이스

  • 인터페이스란? 추상 클래스보다 더 추상적인 변수, 메서드를 설정하여 구현의 가이드라인을 제공함
  • 인터페이스는 클래스로 선언하지 않고 interface 키워드를 사용해서 선언
  • 인터페이스를 상속받으려면 extends가 아닌 implements를 사용
  • 인터페이스에 선언된 모든 변수는 프리컴파일 단계에서 public static final이 붙는다 (상수 취급)
  • 인터페이스에 선언된 모든 메서드는 프리컴파일 단계에서 public abstract가 붙는다 (추상 메서드 취급)
  • 인터페이스는 다중상속이 가능하다!

클래스는 다중상속이 불가능한데 왜 인터페이스는 다중상속이 가능한가?

  • 일반적인 클래스에서 다중상속을 받을경우 발생하는 문제를 '다이아몬드 문제'라고 한다

다중상속, 다이아몬드 문제

위 그림처럼 Child 클래스의 work 메서드는 엄마한테 받을지, 아빠한테 받을지 모호하다. 그래서 일반 클래스에서는 다중상속을 할 수 없다.

하지만, 추상 메서드라면? 구현부가 존재하지 않기 때문에 누구한테서 상속을 받던 상관이 없다. 그래서 인터페이스는 다중상속이 가능하다

반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크