배열(Array)의 각 인자에는 Primitive Type
(원시타입)과 Class Type
(클래스 타입) 두 가지 타입이 올 수 있다.
자바 서비스단 구현 시 서비스 메서드명에는 몇가지 규칙이 있다. 꼭 정해진 규칙은 아니나 지켜진 경우 훨씬 가독성이 좋다.
- 조회 메서드는 getObject와 같이 get으로 시작한다. 전체를 조회하는 경우 getAllObjec 또는 getObjects와 같이 작성한다.
- 검색 메서드의 경우 search나 find로 시작한다. 검색 조건등이 있는 경우 뒤에 ByParameter를 붙여 구분한다.
평소 서비스 메서드 작성할 때 DAO 이름을 따라가거나 대충 짓는 경우가 많았는데 앞으로 위 규칙을 따라 깔끔하게 작성해야겠다.
메서드 오버로딩(Method Overloading)
하는 일은 같지만 처리해야하는 데이터나 메서드마다 로직이 다를 때 쓰는 기법이다. 예를 들어, 검색이란 기능은 동일하나 검색 조건이나 범위등이 달라질 때 구현 시 사용된다.
- 메서드명은 동일하다.
- 메서드 인자(순서, 데이터 타입, 수 등)는 반드시 달라야한다.
- 메서드 리턴 타입은 같거나 다르거나 상관없다.
메서드 오버라이딩(Method Overriding)
같은 기능이나 상속받는 클래스마다 그 로직이 달라질 때 사용한다. 부모 클래스에서 이미 정의된 메서드를 자식 클래스에서 같은 시그니쳐를 갖는 메서드로 다시 정의하는 것이다. 자바에서 자식 클래스는 부모 클래스의 private 멤버를 제외한 모든 메서드를 상속받는다.
- 메서드의 선언부는 동일하다. 반환 타입은 부모 클래스의 반환 타입으로 타입 변환할 수 있는 타입이라면 변경할 수 있다.
- 구현부는 상속받은 클래스마다 달라진다.
- 부모 클래스의 메서드보다 접근 제어자를 더 좁은 범위로 변경할 수 있다.
- 부모 클래스의 메서드보다 더 큰 범위의 예외를 선언할 수 있다.
상속(Inheritance)
부모 클래스의 멤버(필드와 메서드)를 물려받음과 동시에 자식은 자식만의 멤버를 갖을 때를 의미한다. 모든 클래스의 근원은 Object 클래스
이며 모든 클래스는 Object 클래스를 상속받는다.
[Java Object Docs] https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html
Object 클래스가 물려주는 중요한 메서드에는 두 가지가 있다
- equals()
객체가 같은지 다른지 주소값을 비교하여 boolean값을 리턴한다.
String 객체의 경우 주소값이 아닌 실제 객체 내 값이 같은지 아닌지 비교하여 리턴한다. 이러한 이유는 각 객체에 맞게 해당 메서드를 오버라이딩하여 사용하기 때문이다. - toString()
사실 모든 객체 뒤에는 .toString()이 숨겨져있다. 객체를 콘솔에 찍어보면 주소값이 적히는 걸 확인할 수 있는데, toString() 메서드는 메모리에 현존하는 객체의 주소값을 String으로 리턴하여준다.
이 또한 필요 시 객체 내 필드값을 리턴하는 메서드로 오버라이딩하여 사용할 수 있다.
추상화(Abstraction)
관련성 없는 모듈 사이에서 공통적으로 포함된 성질들을 찾아 그 성질들을 일반적인 필드로 갖는 모듈 하나로 상정하는 것이다.
추상화한 객체는 부모 클래스(Parent Class, Super Class)이고 상속받은 객체들은 자식 클래스(Child Class, Sub Class)라고 한다.
아래 세 직업군의 필드 중 name, birthday, salary 필드는 공통으로 들어가는 필드들이다. 이런 공통점들을 모아 Employee라는 객체를 만들었다. 이 과정을 추상화
라고하며 Employee 객체를 가지고 Manager, Engineer, Teacher 라는 객체를 구현하는 것을 구체화
또는 실체화
라고 한다.
extends
키워드는 대표적인 상속
키워드로 부모 클래스의 메서드를 그대로 이용하거나 오버라이딩(재정의)할 수 있다. 말 그대로 부모 클래스를 확장하는 것이다.
그 외에도
implements
와abstract
키워드,interface
등이 있는데 추후 추가할 예정!
this
키워드는 객체 자신을 의미한다. 객체 자신의 정보를 담고 있다.
생성자 작성 시 동일한 이름의 로컬 변수와 필드명을 구분하고자 사용하거나 생성자 안에서 또 다른 생성자를 호출을 위해 사용한다.
아래 name, birthday, salary 세 필드를 갖는 객체 Employee가 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Employee{
private String name;
private Date birthday;
private double salary;
public Employee() {} //명시적 생성자있을 경우 기본 생성자 필수
public Employee(String name, Date birthday, double salary){
this.name = name;
this.birthday = birthday;
this.salary = salary;
}
}
만약 salary에 값이 입력되지 않은 경우 기본값으로 세팅 후 객체를 생성하고 싶다면 모든 인자를 받는 생성자를 이용하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Employee{
private String name;
private Date birthday;
private double salary;
private static final double BASIC_SALARY = 0.0;
public Employee() {} //명시적 생성자있을 경우 기본 생성자 필수
public Employee(String name, Date birthday, double salary){
this.name = name;
this.birthday = birthday;
this.salary = salary;
}
public Employee(String name, Date birthday){
this(name, birthday, BASIC_SALARY); //salary = 0.0
}
}
비어있는 salary 대신 0.0으로 초기화된 상수 BASIC_SALARY를 인자로 전달하여 객체를 생성한다.
The field ~~ is not visible.
만약 자식 클래스에서 부모 클래스의 멤버 필드 접근하려 하면 위와 같은 에러 메시지가 뜬다. 자식 클래스 생성자 작성 시 부모 클래스의 멤버변수는 직접 초기화하지 못한다. 이때 사용하는 것이 super
키워드이다.
this
가 객체 자신을 가리키는 것처럼 super
는 부모 클래스를 의미한다.
1
2
3
4
5
public Child(String f1, int f2..) extends Parent{
super(); // Parent()
this.f1 = f1;
this.f2 = f2;
}
클래스 작성 시 자동생성으로 생성자를 작성하면 super();
구문이 자동으로 작성되는데 이것이 바로 부모 클래스 생성자 호출이다.
만약 자식 클래스에서 부모 클래스의 멤버 필드까지 초기화하여 생성자를 작성하고 싶다면 아래와 같이 활용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
// 부모 클래스
class Parent {
private String p1;
private int p2;
public Parent(){};
public Parent(String p1, int p2){
this.p1 = p1;
this.p2 = p2;
}
}
1
2
3
4
5
6
7
8
9
10
// 자식 클래스
class Child extends Parent{
private double f1;
public Child(){};
public Child(String p1, int p2, double f1){
super(p1, p2); // Parent(p1, p2);
this.f1 = f1;
}
}
비슷하게 toString()
을 객체 주소가 아닌 필드 정보를 리턴하도록 재정의한 경우, 부모 클래스의 필드도 함께 출력할 수 있다.
1
2
3
public String toString(){
return super.toString() + ...; // 부모 클래스 toString() 호출
}
부모 클래스를 extends
한 자식 클래스 생성 시 메모리 구조는 새로 할당이 아닌 말 그대로 확장 이다.
자식 객체 생성 시(생성자 호출 시) 부모 클래스의 생성자가 반드시 먼저 호출된다.
- Stack에 Child를 위한 공간이 생긴다.
- Heap에 Child 생성 전, 부모 클래스인 Parent가 먼저 생긴다. 그리고 값이 기본값으로 초기화(묵시적 초기화)된다.
- Heap에 Chid가 새로 생성되는 것이 아니라 Parent 클래스에 Child만의 필드들이 추가되어 Child로 확장된다. 추가된 필드들도 기본값으로 초기화된다.
- 이 공간에 주소가 라벨링되고 Stack에 해당 주소값이 저장된다.