티스토리 뷰
반응형
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 메서드는 엄마한테 받을지, 아빠한테 받을지 모호하다. 그래서 일반 클래스에서는 다중상속을 할 수 없다.
하지만, 추상 메서드라면? 구현부가 존재하지 않기 때문에 누구한테서 상속을 받던 상관이 없다. 그래서 인터페이스는 다중상속이 가능하다
반응형