본문 바로가기
아카이브/자바의 정석

6장 객체지향프로그래밍(2) 20200919

by nineteen 2020. 9. 19.
반응형

클래스메소드와 인스턴스메소드

 

클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것 이 있으면 static을 붙여준다

작성한 메소드 중에서 인스턴스 변수나 인스턴스 메소드를 사용하지 않는 메소드에 static을 붙일 것을 고려한다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class MyMath2 {
    long a, b;
    
    // 인스턴스 메소드
    long add() { return a+b; }
    long subtract() { return a-b; }
    long multiply() { return a*b; }
    long divide() { return a/b; }
    
    // 클래스 메소드
    static long add(long a, long b) { return a+b; }
    static long subtract(long a, long b) { return a-b; }
    static long multiply(long a, long b) { return a*b; }
    static long divide(long a, long b) { return a/b; }
}
 
public class MyMathTest {
    public static void main(String[] args) {
        // 클래스 메소드 사용
        System.out.println(MyMath2.add(200L, 100L));
        System.out.println(MyMath2.subtract(200L, 100L));
        System.out.println(MyMath2.multiply(200L, 100L));
        System.out.println(MyMath2.divide(200L, 100L));
        
        // 인스턴스 생성
        MyMath2 mm2 = new MyMath2();
        mm2.a = 200L; 
        mm2.b = 100L;
        
        // 인스턴스 메소드 사용
        System.out.println(mm2.add());
        System.out.println(mm2.subtract());
        System.out.println(mm2.multiply());
        System.out.println(mm2.divide());
 
    }
 
}
 
cs

 

 

클래스 멤버와 인스턴스 멤버간의 참조와 호출

 

 

클래스 멤버가 인스턴스 멤버를 참조 또는 호출하고자하면 인스턴스를 생성해야한다

 

이유는, 인스턴스 멤버가 존재하는 시점에 클래스 멤버는 존재하지만, 클래스 멤버가 존재하는 시점에 인스턴스 멤버가 존재하지 않을 수 있기 때문

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class MemberCall {
    // 변수구성
    int iv = 10;
    static int cv = 20;
    
    int iv2 = cv;
    // static int cv2 = iv; --> 클래스변수는 인스턴스변수 사용불가
    
    // 메소드
    static void staticMethod1() {
        // 클래스변수
        System.out.println(cv);
        // 인스턴스 생성해야 인스턴스변수 참조가능
        // System.out.println(iv); --> 에러
        MemberCall c = new MemberCall();
        System.out.println(c.iv); 
    }
    
    void instanceMethod1() {
        System.out.println(cv);
        System.out.println(iv); // 인스턴스메소드에서는 인스턴스변수 바로참조가능
    }
    
    static void staticMethod2() {
        staticMethod1();
        // instanceMethod1(); --> 에러
        MemberCall c = new MemberCall();
        c.instanceMethod1();
    }
    
    void instanceMethod2() {
        staticMethod1();
        instanceMethod1();
    }
    
    public static void main(String[] args) {
        MemberCall c = new MemberCall();
        
        MemberCall.staticMethod1();        
        MemberCall.staticMethod2();
        System.out.println();
        c.instanceMethod1();
        c.instanceMethod2();
    }
 
}
 
cs

 

 

 

 

 

오버로딩

 

한 클래스 내에 같은 이름의 메소드를 여러 개 정의하는 것

 

 

오버로딩 조건을 충족시키려면 2가지 조건을 만족시켜야 함

1. 메소드 이름이 같아야 한다

2. 매개변수의 개수 또는 타입이 달라야 한다

 

 

 

오버로딩의 장점으로는

메소드의 이름만 보고 '이 메소드들은 이름이 같으니 같은 기능을 하겠구나' 식으로 예측이 가능하다

또, 메소드의 이름을 절약할 수 있다. 하나의 이름으로 여러 개의 메소드를 정의 할 수 있어 메소드 이름을 짓는데 고민을 덜 할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class MyMath3 {
    int add(int a, int b) {
        System.out.print("int add(int a, int b) - ");
        return a+b;
    }
    
    long add(int a, long b) {
        System.out.print("long add(int a, long b) - ");
        return a+b;
    }
    
    long add(long a, int b) {
        System.out.print("long add(long a, int b) - ");
        return a+b;
    }
    
    long add(long a, long b) {
        System.out.print("long add(long a, long b) - ");
        return a+b;
    }
    
    int add(int[] a) {
        System.out.print("int add(int[] a) - ");
        int result = 0;
        for(int i : a) {
            result += i;
        }
        return result;
    }
}
 
public class OverloadingTest {
    public static void main(String[] args) {
        // MyMath3클래스의 메소드 사용위해, 인스턴스 생성
        // 메소드 실행
        // 변수 a=3, b=3
        // 배열 {100,200,300}
        
        MyMath3 mm = new MyMath3(); // 인스턴스 생성
        System.out.println(mm.add(33));
        System.out.println(mm.add(3, 3L));
        System.out.println(mm.add(3L, 3));
        System.out.println(mm.add(3L, 3L));
        
        int[] a = {100,200,300};
        System.out.println(mm.add(a));
 
    }
 
}
 
cs

 

 

 

가변인자와 오버로딩

 

기존에는 메소드의 매개변수가 고정적이었지만 JDK 1.5부터 동적으로 지정해 줄 수 있게 됐는데,

이 기능을 가변인자라고 한다

 

'타입... 변수명' 형식으로 선언

가변인자는 매개변수 중에서 가장 마지막에 선언해야 함

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class VarArgsEx {
    
    static String concatenate(String delim, String... args) {
        String result = "";
        
        for(String str : args) {
            result += str + delim;
        }
        
        return result;
        
    }
    public static void main(String[] args) {
        String[] strArr = {"100","200","300"};
        
        System.out.println(concatenate("""100""200""300"));
        System.out.println(concatenate("-", strArr));
        System.out.println(concatenate(","new String[] {"1","2","3"}));
        System.out.println();
 
    }
 
}
 
cs

 

 

 

 

생성자

 

생성자는 인스턴스가 생성될 때 호출되는 '인스턴스 초기화 메소드'이다

인스턴스 변수의 초기화 작업에 주로 사용됨

 

 

생성자의 조건

1. 생성자의 이름은 클래스의 이름과 같아야 한다

2. 생성자는 리턴 값이 없다

 

 

생성자 예시

 

Card c = new Card();

 

1, 연산자 new에 의해 메모리(heap)에 Card클래스의 인스턴스 생성

2. 생성자 Card()가 호출되어 수행

3. 연산자 new의 결과로, 생성된 Card인스턴스의 주소가 반환되어 참조변수 c에 저장

 

 

생성자가 클래스에 따로 작성되어 있지 않다면, 컴파일러가 기본생성자를 추가해줌

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class Car {
    // 색상, 기어타입, 문개수
    // 생성자
    // 아무옵션 안주면 (흰색, 오토, 문4개)를 기본옵션으로
    // 색상옵션만 주면 (색상, 오토, 문4개)
    // 색상, 기어타입, 문개수옵션주면  그에맞게 변경
    
    // 변수구성
    String color; 
    String gearType;
    int door;
    
    // 생성자
    Car() {
        // Car(String color, String gearType, int door) 호출
        this("White""auto"4);
    }
    
    Car(String color) {
        // Car(String color, String gearType, int door) 호출
        this(color, "auto"4);
    }
    
    Car(String color, String gearType, int door) {
        this.color = color;
        this.gearType = gearType;
        this.door = door;
    }
}
 
public class CarTest2 {
    public static void main(String[] args) {
        // 아무옵션 안준 차
        // 색 옵션만 준 차
        // 세가지 옵션 다 준 차
        
        Car c1 = new Car();
        Car c2 = new Car("Blue");
        Car c3 = new Car("Black""auto"2);
        
        System.out.println("c1의 color : " + c1.color + ", gearType : " + c1.gearType + 
                ", door : " + c1.door);
        System.out.println("c2의 color : " + c2.color + ", gearType : " + c2.gearType + 
                ", door : " + c2.door);
        System.out.println("c3의 color : " + c3.color + ", gearType : " + c3.gearType + 
                ", door : " + c3.door);
    }
 
}
 
 
cs

this - 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있음

this(), this(매개변수) - 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용

 

 

 

 

 

생성자를 이용해 인스턴스 복사

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Car {
    // 변수구성
    String color; 
    String gearType;
    int door;
    
    // 생성자
    Car() {
        this("White""auto"4);
    }
    
    // 매개변수로 받은 Car클래스의 참조변수의 color, gearType, door값을 복사
    Car(Car c) {
        color = c.color;
        gearType = c.gearType;
        door = c.door;
    }
    
    Car(String color, String gearType, int door) {
        this.color = color;
        this.gearType = gearType;
        this.door = door;
    }
}
 
 
public class CarTest3 {
 
    public static void main(String[] args) {
        Car c1 = new Car();
        Car c2 = new Car(c1); // c1을 복사
        
        System.out.println("c1의 color : " + c1.color + ", gearType : " + c1.gearType + 
                ", door : " + c1.door);
        System.out.println("c2의 color : " + c2.color + ", gearType : " + c2.gearType + 
                ", door : " + c2.door);
        
        c1.door = 2;
        System.out.println("c1.door = 2 수행후!");
        System.out.println("c1의 color : " + c1.color + ", gearType : " + c1.gearType + 
                ", door : " + c1.door);
        System.out.println("c2의 color : " + c2.color + ", gearType : " + c2.gearType + 
                ", door : " + c2.door);
 
    }
 
}
 
cs

 

c2는 c1을 복사해 같은 상태를 갖지만, 서로 독립적으로 메모리 공간에 존재하는 인스턴스이므로 c1값이 변경되어도 

c2는 영향을 받지 않는다

 

 

 

정리하며

인스턴스를 생성할 때는 다음의 2가지 사항을 결정해야 한다.

 

1. 클래스 - 어떤 클래스의 인스턴스를 생성할 것인가?

2. 생성자 - 선택한 클래스의 어떤 생성자로 인스턴스를 생성할 것인가?

 

 

 

 

 

 

 

변수의 초기화

 

멤버변수(클래스/인스턴스 변수)와 배열의 초기화는 선택적이지만,

지역변수의 초기화는 실수적이다.

 

지역변수는 사용하기 전에 반드시 초기화해야 한다.

 

 

멤버변수의 초기화 방법

1. 명시적 초기화

2. 생성자

3. 초기화 블럭

 

 

명시적 초기화

변수를 선언과 동시에 초기화하는 것

 

 

초기화 블럭

 - 인스턴스 초기화 블럭 : 인스턴스 변수를 초기화 하는데 사용

 - 클래스 초기화 블럭 : 클래스 변수를 초기화 하는데 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class BlockTest {
    // 클래스 초기화 블럭
    static {
        System.out.println("static { } 클래스 초기화 블럭");
    }
    
    // 인스턴스 초기화 블럭
    {
        System.out.println("{ } 인스턴스 초기화 블럭");
    }
    
    // 생성자
    public BlockTest() {
        System.out.println("생성자");
    }
    
    public static void main(String[] args) {
 
        System.out.println("BlockTest bt = new BlockTest();");
        BlockTest bt = new BlockTest();
        
        System.out.println("BlockTest bt2 = new BlockTest();");
        BlockTest bt2 = new BlockTest();
 
    }
 
}
 
cs

출력

static { } 클래스 초기화 블럭
BlockTest bt = new BlockTest();
{ } 인스턴스 초기화 블럭
생성자
BlockTest bt2 = new BlockTest();
{ } 인스턴스 초기화 블럭
생성자

 

 

 

클래스변수의 초기화 시점 - 클래스가 처음 로딩될 때 단 한번 초기화 된다

인스턴스변수의 초기화 시점 - 인스턴스가 생성될 때마다 각 인스턴스별로 초기화가 이루어진다

 

클래스변수의 초기화 순서 - 기본값 --> 명시적 초기화 --> 클래스 초기화 블럭

인스턴스변수의 초기화 순서 - 기본값 --> 명시적 초기화 --> 인스턴스 초기화 블럭 --> 생성자

'아카이브 > 자바의 정석' 카테고리의 다른 글

7장 20200924  (0) 2020.09.24
7장 상속 20200921  (0) 2020.09.21
6장 객체지향프로그래밍 20200918  (0) 2020.09.18
5장 배열 20200917  (0) 2020.09.17
JAVA 배열 20200916  (0) 2020.09.16