1. 참조 자료형
앞에서 배운 기본 자료형을 제외한 나머지 타입은 모두 참조 자료형입니다. 기본 자료형과 참조 자료형의 가장 큰 차이는 new를 사용해서 객체를 생성하는지 차이입니다. 단, String은 new 없이도 객체를 생성할 수 있습니다.
'+'는 참조 자료형 중에서 String 클래스만 사용 가능합니다. for, while, if문에서는 메소드에서 boolean 타입의 리턴값을 제공하면 사용할 수 있고, null인지 체크하는 경우는 이러한 조건문이나 반복문에 사용할 수 있습니다.
2. 생성자
객체를 생성하기 위해서는 이 생성자를 이용해서 만들어야합니다. 자바는 생성자를 만들지 않아도 자동으로 만들어지는 기본 생성자가 있습니다. 생성자의 이름은 클래스의 이름과 같습니다.
1
2
3
4
5
6
7
|
public class ReferenceTypes{
public static void main(String []args) {
ReferenceTypes reference = new ReferenceTypes();
}
}
|
|
아무런 매개 변수가 없는 ReferenceTypes()라는 생성자는 다른 생성자가 없을 경우 기본으로 컴파일 할 때 만들어 집니다. 하지만 다른 생성자가 있으면 자동으로 만들어지지 않습니다. 또한 생성자를 작성할 때에는 인스턴스 변수들을 선언한 후에 생성자를 위치 시키고, 필요한 메소드들을 위치시키는 것이 좋습니다.
1
2
3
4
5
6
7
8
9
10
11
|
public class ReferenceTypes{
public ReferenceTypes(String str) {
}
public static void main(String []args) {
ReferenceTypes reference = new ReferenceTypes("test");
}
}
|
|
클래스의 객체를 보다 간편하게 만들기 위해서 여러 가지 매개 변수를 갖는 생성자를 가질 수 있습니다. 생성자의 수는 100개가 되도 상관이 없습니다.
자바 패턴 중에서 DTO(Data Transfer Object)라는 것이 있습니다. 어떤 속성을 갖는 클래스를 만들고, 그 속성들을 쉽게 전달하기 위해서 DTO라는 것을 만듭니다. 비슷한 클래스로 VO(Value Object)라는 것이 있습니다. DTO와 형태는 동일하지만 VO는 데이터를 담아 두기 위한 목적으로 사용되며 DTO는 데이터를 다른 서버로 전달하기 위한 것이 주 목적 입니다. DTO가 VO를 포함한다고 볼 수 있기 때문에 대부분 DTO라는 명칭을 선호합니다.
예를 들어 name, phone, email이라는 인스턴스 변수를 갖는 MemberDTO를 만들어 봅시다.
1
2
3
4
5
|
public class MemberDTO {
public String name;
public String phone;
public String email;
}
|
|
이렇게 DTO를 만들어 놓으면 메소드의 리턴 타입에 MemberDTO로 선언하고, 그 객체를 리턴해 줌으로써 복합적인 데이터를 처리할 수 있습니다. 이렇게 만든 DTO에 여러가지 생성자를 만들어 둠으로써 객체를 활용할 수 있습니다.
3. 메소드 overloading
클래스의 생성자는 매개 변수들을 서로 다르게하여 선언할 수 있습니다. 메소드도 이렇게 이름은 같게 하고 매개 변수들을 다르게 하여 만들 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class MemberDTO {
public void print(int data) {
}
public void print(String data) {
}
public void print(int intData, String stringData) {
}
public void print(String stringData, int intData){
}
}
|
|
이와 같이 개수가 같아도 타입의 순서가 다르면 다른 메소드 처럼 인식됩니다. 여기서 중요한 것은 매개 변수의 이름이 아니라 매개 변수의 타입입니다. 이처럼 매개 변수만을 다르게 하는 것을 바로 오버로딩이라고 합니다.
overload라는 단어를 사전에서 찾아보면 "과적하다, 너무 많이 부하를 주다"라는 의미가 있습니다. 하나의 메소드 이름으로 많은 부하를 준다고 볼 수 있습니다.
오버로딩을 제공하는 이유는 만약 int형을 넘기거나 long형을 넘겨서 출력하려고 할 때 각각의 메소드 이름이 달라야 한다면 얼마나 불편하겠습니까? 메소드 오버로딩은 "같은 역할은 같은 메소드 이름을 가져야 한다"는 모토로 사용하는 것이라고 기억하면 됩니다.
(Tip) 메소드 작성시 void인 메소드에서 return 뒤에 아무 것도 없이 바로 세미콜론을 적어 주면, "메소드 수행을 종료해라"라고 인식합니다.
4. static 메소드와 일반 메소드의 차이
지금까지 main()메소드에서 자신의 클래스나 다른 클래스에 있는 메소드를 호출하려면 반드시 객체를 생성해 왔는데, System.out.println() 메소드는 객체를 생성하지 않고 사용함을 볼 수 있었습니다. 그 이유는 바로 static이라는 예약어 때문입니다. static은 객체를 생성하지 않아도 메소드를 호출할 수 있는 마법의 메소드 입니다.
1
2
3
4
5
6
7
|
public class MemberDTO {
public static void staticMethod() {
System.out.println("This is a static method.");
}
}
|
|
이렇게 MemberDTO 클래스에 static 메소드를 만들어 봅시다.
1
2
3
4
5
6
7
|
public class Main{
public static void main(String[] args) {
MemberDTO.staticMethod();
}
}
|
|
"This is a static method." 라는 출력결과를 확인할 수 있습니다. 이 static 메소드는 클래스 변수만 사용할 수 있다는 단점이 있습니다. 변수 앞에 static이 붙어있지 않은 인스턴스 변수를 static method안에서 사용하게되면 컴파일시 에러메시지가 출력됩니다.
만약 여러분이 인스턴스 변수를 static으로 선언하게 되면 이 변수는 인스턴스 변수가 아니라 클래스 변수가 됩니다. 아무 생각 없이 인스턴스 변수에 static을 붙이면 예상치 못한 상황이 발생하게 됩니다. 왜냐하면 클래스 변수가 되면 모든 객체에서 하나의 값을 바라보기 때문입니다.
5. static 블록
static을 특이하게 사용하는 방법에 대해서 알아봅시다. 어떤 클래스의 객체가 생성되면서 딱 한번만 불려야 하는 코드가 있다고 생각해 봅시다. 객체는 여러 개를 생성하지만, 한 번만 호출되어야 하는 코드가 있다면 "static 블록"을 사용하면 됩니다. 다음과 같은 방식으로 static 블록을 선언하여 사용합니다.
1
2
3
|
static{
//딱 한번만 수행되는
}
|
|
static 블록은 객체가 생성되기 전에 한 번만 호출되고, 그 이후에는 호출하려고 해도 호출할 수가 없습니다. 그리고 클래스 내에 선언되어 있어야 하며, 메소드 내에서는 선언할 수가 없습니다. 즉, 인스턴스 변수나 클래스 변수와 같이 어떤 메소드나 생성자에 속해 있으면 안됩니다.
다음 코드를 봅시다. static 블록은 이처럼 여러 개를 선언할 수 있습니다. 선언되어 있는 순서는 매우 중요합니다. 왜냐하면 선언된 순서대로 블록들이 차례로 호출되기 때문입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class StaticBlock {
static int data = 1;
public StaticBlock() {
System.out.println("StaticBlock Constructor.");
}
static {
System.out.println("*** First static block. ***");
data = 3;
}
static {
System.out.println("*** Second static block. ***");
}
public static int getData() {
return data;
}
}
|
|
이 StaticBlock 클래스를 실행하기 위해서 ReferenceTypes 클래스에 다음과 같은 메소드를 하나 만들어 봅시다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class ReferenceTypes{
public void makeStaticBlockObject() {
System.out.println("Creating block1");
StaticBlock block1 = new StaticBlock();
System.out.println("Created block1");
System.out.println("Creating block2");
StaticBlock block2 = new StaticBlock();
System.out.println("Created block2");
}
public static void main(String[] args) {
ReferenceTypes referType = new ReferenceTypes();
referType.makeStaticBlockObject();
}
}
|
|
실행 결과는 다음과 같습니다.
두 개의 StaticBlock 객체를 만들었지만, static 블록들은 단지 한 번씩만 호출되었습니다. 게다가 생성자가 호출되기 전에 static 블록들이 호출된 것을 볼 수 있습니다. 이와 같이 static 블록은 클래스를 초기화할 때 꼭 수행되어야하는 작업이 있을 경우 유용하게 사용될 수 있습니다.
static 블록을 사용하는 다음과 같은 예시를 볼 수 있었습니다. 미리 정의된 ENUM 클래스로부터 값을 받아와 static 인스턴스를 초기화해주는 예제 코드 입니다.
private static Map<String, String> map = new HashMap<String, String>();
static {
map.put(Enum.TYPE1, "type1");
map.put(Enum.TYPE2, "type2");
}
이처럼 static 블록은 생성자가 불리지 않더라도, 클래스에 대한 참조가 발생하자마자 호출되는 것을 알 수 있습니다. static 블록을 쓸 일은 많지 않지만, 가끔 사용 할 수도 있으니 꼭 기억하고 있어야 합니다.
6. 매개 변수를 지정하는 특이한 방법
지금까지는 매개 변수의 개수가 정확히 정해져 있는 경우만 알아보았습니다. 하지만, 매개 변수가 몇 개가 될지, 호출할 때마다 바뀌는 경우에는 어떻게 해야할까요? 가장 쉬운 방법은 배열을 넘겨 주는 방법일 것입니다. 하지만 배열을 사용해도 되지만, 매개 변수로 넘겨 줄 때 계산할 숫자들을 모두 배열로 만들 후 넘겨주어야 한다는 단점이 존재합니다.
그래서 자바에서는 임의 개수의 매개 변수를 넘겨 줄 수 있는 방법을 제공합니다.
1
2
3
4
5
6
|
public class ReferenceTypes{
public void calculateNumbers(int... numbers) {
//내용 생략
}
}
|
|
위의 코드와 같이 배열이 아닌 int 값들을 받을 수 있는 calculateNumbers()라는 메소드를 선언할 수 있습니다. "타입... 변수명"으로 선언해 주면, numbers는 배열로 인식하고, 그 값은 다음과 같이 처리할 수 있습니다. 여기서 조심해야할 것은 ...을 적을 때에 점 사이에 공백이 있으면 안된다는 것 입니다.
1
2
3
4
5
6
7
8
9
10
|
public class ReferenceTypes{
public void calculateNumbers(int... numbers) {
int total = 0;
for(int number: numbers) {
total+=number;
}
System.out.println("Total="+total);
}
}
|
|
이렇게 사용하면 numbers[]라는 배열을 받은 것과 다름없이 사용할 수 있습니다. 이와 같이 필요에 따라서 매개 변수 수를 정하기 애매한 경우 타입과 변수명 사이에 점 세개를 연달아 입력해주면 됩니다.
한가지 명심해야 할 점은 이 방법을 사용할 때에는 하나의 메소드에서는 한 번만 사용 가능하고, 여러 매개 변수가 있다면, 가장 마지막에 선언해야만 한다는 것입니다.
1
2
3
4
5
6
7
|
public class ReferenceTypes{
public void arbitrary(String message, int... numbers) {
//내용 생략
}
}
|
|
밑의 코드 처럼은 사용하면 안됩니다.
1
2
3
4
5
6
7
|
public class ReferenceTypes{
public void arbitrary(int... numbers, String message) {
//내용 생략
}
}
|
|
'Java' 카테고리의 다른 글
[Java] 9.패키지 (0) | 2019.03.10 |
---|---|
[Java] 8. Pass by Value, Pass by reference (0) | 2019.03.03 |
[Java] 6. 배열 (0) | 2019.03.01 |
[Java] 5. switch문 (0) | 2019.03.01 |
[Java] 4. 자바에서의 연산 순서 (0) | 2019.02.25 |