[Java] 객체지향 요약
코드의 재사용성 / 유지보수 / 중복된 코드의 제거에 집중해 객체지향 개념을 공부하자.
클래스 : 객체를 정의해 놓은 것. 객체를 생성하는데 사용된다. (클래스와 객체는 다르다.)
여기서 객체는 클래스에 정의된 내용대로 메모리에 생성된 것을 뜻한다. (객체는 인스턴스라고도 불린다.)
객체를 생성하기 위해서는 클래스를 먼저 정의해야 한다.
Java에서도 프로그래밍을 휘애 유용한 클래스들을 많이 제공한다.
입력받을 때 사용하는 Scanner, 문자열을 정의할 때 사용하는 String 등.. 여러 가지 클래스들이 있다.
Scanner sc = new Scanner(System.in);
위의 코드를 읽어보면,
Scanner 클래스 타입의 참조변수 sc를 선언 후 new 연산자를 통해 Scanner 인스턴스(객체)를 생성 후 Scanner 인스턴스의 주소를 참조변수 sc에 저장한다.
즉, 참조변수에는 객체의 주소값이 저장된다.
이를 보여주는 좋은 예시로 문자열을 처리할 때 사용하는 String이 있다. String 또한 클래스인데, String을 비교할 때 == 연산자를 사용하게 되면 주소 값을 비교하게 되고 문자열을 비교할 수 없다.
여기서 조금 생각하면, 아 그럼 기본형으로 지정된 타입은 주소가 아니라 값을 바로 저장하니까.. 좀 차이가 있지 않을까? 라고 생각할 수 있는데, 이 부분은 나중에 자세히 알아보자.
변수의 종류
지역변수와 인스턴스변수 클래스변수가 있다.
지역변수의 경우, 메서드 안에 있는 변수라고 생각하면 된다.
코드를 작성할 때 for 문 안이나 if문 안에서 변수를 선언하게 되면 문장 바깥에서는 그 변수를 사용할 수 없는데, 문장 안에 선언된 변수는 지역변수로 취급되기 때문이다. (지역변수는 초기화가 꼭 필요하다.)
static 키워드를 사용해 클래스 변수를 선언할 수 있다. 인스턴스변수 앞에 static을 붙여 클래스변수를 선언할 수 있는데, static은 공통의 의미를 가진다. 즉, 한 클래스의 모든 인스턴스들이 공통값을 가진다면 클래스변수로 선언하는게 좋다.
클래스변수는 인스턴스변수와 달리 객체를 생성하지 않고도 바로 쓸 수 있다.
메서드
int result(int a, int b) {
return a+b;
}
위는 간단한 메서드의 예시이다.
수학에서 함수가 있듯, 자바에서는 메서드를 사용해 복잡한 연산을 처리하게 할 수 있다.
반환타입 메서드이름 (타입 변수명) { 수행될 코드 } 형식으로 작성된다.
static을 사용해 클래스 메서드를 사용할 수 있는데, 이 메서드 역시 객체를 생성하지 않고 바로 사용할 수 있다.
(클래스명.메서드/변수명 으로 사용.)
(반환타입이 꼭 기본형일 필요는 없다.)
위의 return; 은 현재 실행중인 메서드를 종료하고 호출한 메서드로 되돌아가는 역할을 한다.
타입이 void 여도 추가해야 하며, 만약 메인메서드에서 return을 만나면 메서드를 종료한다.
객체를 생성하고 그 객체의 메서드나 변수를 사용할 때는 참조변수.메서드/변수명 으로 사용할 수 있다.
static은 인스턴스변수와 관련이 없을 경우 붙이는 걸 고려해 보자.
같은 클래스에 속한 멤버끼리는 객체를 만들지 않고 서로 사용할 수 있는데, 클래스멤버가 인스턴스멤버를 사용하려고 할 때는 객체를 만들어야 한다. (클래스멤버가 존재하지만 인스턴스멤버가 존재하지 않을 가능성 때문. 이해하기.)
오버로딩
한 클래스에서 이름이 같은 메서드를 매개변수의 개수와 타입을 다르게 지정해 중복으로 사용하는걸 말한다.
생성자
인스턴스가 생성될 때 호출되는 인스턴스를 초기화하는 메서드이다. 모든 클래스에 반드시 하나 이상의 생성자가 정의된다.
classname() {
}
위와 같이 클래스명 (매개변수) { 수행할 동작 } 형식으로 작성된다.
생성자에서 다른 생성자를 호출할 때 this()를 사용할 수 있다. (첫 줄에서만 호출 가능)
this와 this()는 다른데, this는 생성자의 매개변수로 정의된 지역변수와 인스턴스변수의 이름을 구별할 때 사용한다.
왜 이런 짓을???? 이라고 생각할 수 있는데, 코드의 재사용성, 중복된 코드의 제거 측면에서 생각하자. 생성자는 간결한 코드 작성에 많은 도움이 된다.
상속
기존의 클래스를 재사용해 새로운 클래스를 작성하는 걸 의미한다.
class classname extends josang {
}
위처럼 extends 를 사용해 상속받는다.
그냥 객체 생성해서 쓰면 안되나... 싶기도 한데... 상속을 통해 코드를 훨씬 간결하게 짤 수 있는 등 상속이 가지는 여러 장점이 있다.
그럼 언제 객체화해서 사용하고 언제 상속을 사용할까?
~은 ~이다 처럼 is-a 관계로 설명하는 게 합리적일 경우에는 상속 관계를,
~는 ~를 가지고 있다 처럼 has-a 관계로 설명하는 게 합리적일 경우에는 포함 관계를 맺어 주자.
실제로 Java가 제공하는 유용한 클래스들도 상속을 통해 작성됐다.
모든 클래스의 조상은 Object 클래스이다. 우리가 작성하는 모든 class들도 컴파일 시 extends Object 코드를 추가해서 컴파일한다. (다중상속이 아닐 시)
오버라이딩
상속을 통해 전달받은 메서드를 변경할 때 오버라이딩을 사용한다.
오버로딩과 헷갈리지 말자.
this를 통해 매개변수와 인스턴스변수를 구분할 수있듯 super를 통해 상속받은 멤버와 자신의 멤버를 구분할 수 있다.
super()를 통해 조상 클래스의 생성자를 호출할 수 있다.
조상의 멤버가 먼저 초기화돼어야 하기 때문에 생성자의 첫 줄에서 super()를 작성해 줘야 한다.
여러 가지 제어자
static : 공통의 final : 상수의, 변경될 수 없는 abstract : 추상의 (추상클래스에서 사용)
접근제어자는 아래 표를 참고하자.
데이터를 보호하기 위해 접근제어자를 사용한다.
다형성
조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 하는걸 의미.
Pen p = new Pen();
Pencilcase pc = new Pencilcase();
Pencilcase pc = new pen();
위와 같이 코드를 작성할 수 있다.
참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 다르다.
자손타입의 참조변수로 조상타입의 객체를 참조하는 건 불가능한데, 이건 형변환과 연관돼있다.
자손타입에서 조상타입으로의 형변환은 생략할 수 있고, (Up-casting)
조상타입에서 자손타입으로의 형변환은 생략할 수 없다. (Down-casting)
상속 관계의 클래스들끼리만 형변환을 할 수 있다.
추상클래스
추상메서드를 포함한 클래스를 추상클래스라고 한다.
추상클래스로 틀을 제공하고 상속받는 클래스가 틀을 바탕을 구체화한다.
인터페이스
클래스와 비슷하다. 그냥 이름만 바꾼거..
인터페이스는 다중상속이 가능하다. (implements를 통해 상속받는다.)
메서드의 리턴타입을 인터페이스로 지정하는 경우가 있는데, 해당 메서드가 그 인터페이스를 구현한 클래스의 인스턴스를 반환한다는걸 의미한다.
인터페이스를 사용해 여러 가지 장점을 얻을 수 있으니.. 지금은 잘 모르겠지만 그런갑다 하고 넘어가자. 실무에서 많이 쓰이나보다.
'Programming Language > Java' 카테고리의 다른 글
[Java] 래퍼 클래스 (Wrapper) (0) | 2021.10.29 |
---|---|
[Java] 예외처리 (0) | 2021.10.29 |
[Java] 스트림 (Stream) (0) | 2021.10.25 |
[Java] 람다식 (Lambda expression) (0) | 2021.10.25 |
[Java] 컬렉션 프레임웍 (Collections Framework) (0) | 2021.10.19 |
댓글
이 글 공유하기
다른 글
-
[Java] 래퍼 클래스 (Wrapper)
[Java] 래퍼 클래스 (Wrapper)
2021.10.29 -
[Java] 예외처리
[Java] 예외처리
2021.10.29 -
[Java] 스트림 (Stream)
[Java] 스트림 (Stream)
2021.10.25 -
[Java] 람다식 (Lambda expression)
[Java] 람다식 (Lambda expression)
2021.10.25