JAVA SPRING/java

JAVA_008) 클래스와 객체, 클래스의 내부 구성요소(생성자, this키워드, this()메서드)

오동순이 2023. 4. 25. 17:40

클래스의 개념 알아보기

객체는 사용할 수 있는 실체를 의미, 클래스는 객체를 만들기 위한 설계도

      자바의 시작점
변수 배열 구조체 클래스
int score1 = 80;
int score2 = 75;
...
double avg = 78.5;
int[] scores = {80,75,...,85};
double avg = 78.2;
struct Score {
   int[] scores = {80,75,...,85};
   double avg = 78.5;
}
class Score {
   int[] scores = {80,75,...,85};
   double avg = 78.5;

   void printAvg() {
     System.out.println(avg);
   }
   void printScores() {
     for(int k : socres) {
         System.out.println(k);
      }
   }
}

 

 

절차지향형(기능 중심 프로그래밍) ? 순서에 맞춰 단계적으로 실행하도록 명령어를 나열하는 방식                      

객체지향형(객체 중심 프로그래밍) ? 객체를 구성하고 객체 단위로 프로그래밍(필드/메서드)

Do it 자바 _ 클래스와 객체

 

객체의 생성과 활용

 

1 객체 생성하기

클래스명 참조변수명 = new 생성자();

ex) A a = new A();

 

2 객체 활용하기

참조변수명.필드명

참조변수명.메서드명()

ex) A a = new A();

      System.out.println(a.m); // 필드 활용

      a.print();                          // 메서드 활용

 

// 클래스의 구성과 객체의 생성 및 활용
class A {
    int m = 3;
    void print() {
        System.out.println("객체 생성 및 활용");
    }
}

public class CreateObjectAndUsageOfMembers {
    public static void main(String[] args) {
        // 클래스로 객체 생성
        A a = new A();

        // 클래스 멤버 활용
        // @필드 활용 : 필드에 값을 읽기/쓰기
        a.m = 5;
        System.out.println(a.m);

        // @메서드 활용 : 메서드 호출
        a.print();
        
    }
}

 

클래스의 내부 구성요소

 

필드(클래스에 포함된 변수)와 지역변수(메서드에 포함된 변수) 구분

// 클래스 생성
class A {
    int m = 3; // 필드
    int n = 4; // 필드

    void work1() {
        int k = 5;  // 지역 변수
        System.out.println(k);
        work2(3);
    }

    void work2(int i) { // 인수를 변수 i에 대입해 입력 매개변수로 활용
        int j = 4;  // 지역 변수
        System.out.println(i + j);
    }
}

public class Class_Ex01 {
    public static void main(String[] args) {
        // 클래스로 객체 생성
        A a = new A();

        // 필드값 출력
        System.out.println(a.m);
        System.out.println(a.n);

        // 메서드 호출
        a.work1();
    }
}

 

필드와 지역변수의 초기값

// 클래스 생성(정의)
class A {
    boolean m1;
    int m2;
    double m3;
    String m4;

    void printFieldValue() {
        System.out.println(m1); // 필드는 초기화하지 않아도 값이 강제 초기화돼 출력 가능
        System.out.println(m2);
        System.out.println(m3);
        System.out.println(m4);
    }

    void printLocalVariable() {
        // int k;
        // System.out.println(k); // 지역변수는 초기화하지 않으면 오류 발생
    }
}

public class InitialValueOfFieldAndLocalVariable {
    public static void main(String[] args) {
        // 클래스를 활용해 객체 생성
        A a = new A();
        a.printFieldValue();
    }
}

 

메서드

메서드 정의하기

 

자바제어자 리턴(반환)타입 메서드명(입력매개변수) {

     메서드 내용

}

ex)

public static int sum(int a, int b) {

    // 메서드 내용

}


 

리턴 타입의 메서드

리턴 타입이 void(리턴타입이 없다)이고, 입력매개변수가 없는 메서드
void print () {
    System.out.println("안녕")
}
리턴 타입이 void일 때 return 키워드의 의미 (메서드를 종료하라)
void printMonth(int m){
   if(m < 0 || m > 12) {
      System.out.println("잘못된 입력!");
      return; // 메서드 종료
   }
  System.out.println( m +"월 입니다.");
}

 

리턴 타입이 int이고, 입력매개변수가 없는 메서드
int data() {
   return 3;
}

 

리턴 타입이 double이고, 입력매개변수가 2개인 메서드
double sum(int a, double b) {
   return a + b ;
}

 


클래스 외부에서 메서드 호출하기

 :  클래스 외부에서 메서드를 사용하려면 먼저 객체를 생성해야함.

// 클래스 정의
class A {
    // 리턴 타입 void, 입력매개변수 없음.
    void print() {
        System.out.println("안녕");
    }
    // 리턴 타입 int, 입력매개변수 없음.
    int data() {
        return 3;
    }
    // 리턴 타입 double, 입력매개변수 2개
    double sum(int a, double b) {
        return a + b;
    }
    // 리턴 타입 void, 내부에 리턴 포함(함수를 종료함)
    void printMonth(int m) {
        if(m < 0 || m >12) {
            System.out.println("잘못된 입력");
            return ;
        }
        System.out.println(m +"월 입니다.");
    }   
}

public class ExternalCallMethods {
    public static void main(String[] args) {
        // 객체 생성
        A a = new A();
        // 메서드 호출(멤버 활용)
        a.print();
        int k = a.data();
        a.data();
        System.out.println(k);
        double result = a.sum(3, 5.2);
        System.out.println(result);
        a.printMonth(5);
        a.printMonth(15);
    }
}

 

클래스 내부에서 메서드 호출하기

 : 클래스 내부에 있는 메서드끼리는 객체를 생성하지 않고 서로를 호출할 수 있다.

 단, 메서드 앞에 static*(자바제어자)이 붙어있을 때는 static이 붙은 필드 또는 메서드만 호출할 수 있다.

 '같은 멤버끼리는 클래스 내부에서 객체를 생성하지 않고 서로 호출가능'

public class InternalCallMethods {
    public static void main(String[] args) {
        // 같은 클래스 안에 있는 내부 메서드 호출
        print();

        int a = twice(3);
        System.out.println(a);

        double b = sum(a, 5.8);
        System.out.println(b);

    }
    public static void print() {
        System.out.println("Hello");
    }

    public static int twice(int k) {
        return k * 2;
    }  

    public static double sum(int m, double n) {
        return m + n;
    }

}

 

 

입력매개변수가 배열인 메서드 호출하기

import java.util.Arrays;

public class ArrayArgumentMethod {
    public static void main(String[] args) {
        // 배열을 입력매개변수로 하는 메서드 호출
        int[] a = new int[] {1,2,3};
        printArray(a);                  // 방법1
        printArray(new int[] {1,2,3});  // 방법2

        // printArray({1,2,3}); // 오류발생

    }
    public static void printArray(int[] a) {
        System.out.println(Arrays.toString(a));
    }
}

 

기본자료형 입력매개변수와 참조자료형 입력매개변수의 차이

 : 배열과 같은 참조자료형이 입력매개변수로 넘겨질때 실제객체가 전달X, 객체의 위치값이 전달O!

 - 기본 자료형 입력매개변수값의  변화

public class EffectOfPrimaryDataArgument {
    public static void main(String[] args) {
        int a = 3;              // main 의 지역변수 a
        int result1 = twice(3);
        System.out.println(result1); // 결과 6
        
        int result2 = twice(a); // main 의 지역변수 a
        System.out.println(result2); // 결과 6

        System.out.println(a);  // main 의 지역변수 a
                                    // 결과 3
        
    }

    public static int twice(int a) { // twice() 메서드의 지역변수 a
        a = a*2;    // twice() 메서드의 지역변수 a
        return a;   // twice() 메서드의 지역변수 a
    }
}

 

 - 참조 자료형 매개변수값의 변화

import java.util.Arrays;

public class EffectOfReferenceDataArgument {
    // 참조 자료형 매개변수 값의 변화
    public static void main(String[] args) {
        int[] array = new int[] {1,2,3}; // 객체 선언
        modifyData(array); // 값이 변경되고
        printArray(array); // 변경된 값으로 프린트메서드 실행
    }

    public static void modifyData(int[] a) { // 수정 메서드
        a[0] = 4;
        a[1] = 5;
        a[2] = 6;
    }

    public static void printArray(int[] a) { // 프린트 메서드
        System.out.println(Arrays.toString(a));
    }
}

 

오버로딩된 메서드

 

메서드 오버로딩

(ex. abc.jpg, abc.png, abc.bmp를 동일한 폴더에 저장가능하다. 파일명은 동일하지만 확장자가 다르기 때문)

리턴타입 메서드명(자료형 변수명, 자료형 변수명, ...) {

    }

ex) 메서드 시그니처(메서드를 구분하는 기준 역할)

int sum (int a, int b) {

return 3;

}

public class MethodOverloading {
    public static void main(String[] args) {
        print();
        print(3);
        print(5.8);
        print(2, 5);        
        
    }

    public static void print() {
        System.out.println("데이터가 없습니다.");
    }
    public static void print(int a) {
        System.out.println(a);
    }
    public static void print(double a) {
        System.out.println(a);
    }

    // public static void print(double b) { // double a 와 중복으로 오버로딩 되지 않음
    //     System.out.println(b);
    // }

    public static void print(int a, int b) {
        System.out.println("a : "+ a + ", b : "+ b);
    }

    // public static void print(int a, int b) { // int a, int b 와 중복으로 오버로딩 되지 않음
    //     System.out.println("a : "+ a + " b : "+ b);
    //     return a+b;
    // }

}

 

 - 가변 길이(...) 배열 입력매개변수를 활용한 메서드의 호출 예

가변 길이 배열 입력매개변수
리턴타입 메서드명 (자료형... 참조변수명) {

}
public class FlexibleSizeArrayArgument {
    public static void main(String[] args) {
        // method1(int...values)
        method1(1,2);
        method1(1,2,3);
        method1();

        // method2(String...values)
        method2("안녕","Hello");
        method2("감사","thanks","고마워");
        method2();
    }

    public static void method1(int...values) {
        System.out.println("배열의 길이 : "+values.length);
        for(int k : values) {
            System.out.print(k + " ");
        }
        System.out.println();
    }

    public static void method2(String...values) {
        System.out.println("배열의 길이 : "+values.length);
        for(int i=0; i<values.length; i++) {
            System.out.print(values[i] + " ");
        }
        System.out.println();
    }
}
배열의 길이 : 2
1 2
배열의 길이 : 3
1 2 3
배열의 길이 : 0

배열의 길이 : 2
안녕 Hello
배열의 길이 : 3
감사 thanks 고마워
배열의 길이 : 0

 

 

생성자

생성자는 객체를 생성하는 역할을 지닌 클래스의 내부 구성 요소다.

생성자의 특징 : 반드시 클래스명과 동일한 이름, 리턴 타입이 없음(void와 다름).

생성자를 만들지 않아도 작동했던 이유는 컴파일러가 기본 생성자를 추가해줬기 때문

    (기본생성자 = 입력매개변수가 없는 생성자)

생성자를 포함시키지 않은 클래스 컴파일러로 기본 생성자가
자동으로 추가된 클래스
기본생성자가 아닌
생성자를 포함하고 있는 클래스
class A {
   int m;
   void work() {
   
   }
}
class A {
   int m;
   void work() {   }
   A() { 
         //컴파일러가 자동으로 기본생성자 추가
   
   }
}
class A {
   int m;
   void work() {   }
   A(int k) {
   m = k; 

             //생성자가 있으므로, 기본생성자는 추가되지 않음.
   
   }
}
class A {
    int m;
    void work() {
        System.out.println(m);
    }
    /* 생성자를 포함하지 않으면 컴파일러가 기본 생성자를 자동으로 추가
    A() {

    }
     */
}

class B {
    int m;
    void work() {
        System.out.println(m);
    }
    B() {

    } // 기본생성자 직접 정의
}

class C {
    int m;
    void work() {
        System.out.println(m);
    }
    C(int a) { // 입력매개변수를 포함하고 있는 생성자 정의
        m =a;  // 입력매개변수로 전달된 값으로 필드 초기화
    }
}

public class DefaultConstructor {
    public static void main(String[] args) {
        // 클래스 객체 생서
        A a = new A(); // 컴파일러가 자동으로 추가한 기본 생성자
        B b = new B(); // 직접 정의한 기본 생성자

        // C c = new C();  // 기본생성자 호출 불가
        
        C c = new C(3); // 직접 정의한 생성자를 호출해 객체 생성
    
        // 메서드 호출
        a.work();  // 0 출력
        b.work();  // 0 출력
        c.work();  // 3 출력
    }
}

 

this 키워드와 this() 메서드

 - 내부객체 참조변수명인 this 키워드

   (인스턴스 메서드 내부에서 this를 사용할 수 있지만, static 메서드 내부에서는 사용할 수 없다.)

 // 클래스 내부에서 필드, 메서드 앞에 자동으로 붙는 this 키워드
class A { 
    int m;
    int n;
    void init(int a, int b) {
        int c;
        c = 3;
        this.m = a; // this.을 생략했을 때 자동으로 추가
        this.n = b; // this.을 생략했을 때 자동으로 추가
    }
    void work() {
        this.init(2, 3); // this.을 생략했을 때 자동으로 추가
    }
}

public class ThisKeyword {
    public static void main(String[] args) {
        // 클래스 객체 생성
        A a =new A();

        // 메서드 호출 / 필드 값 활용
        a.work();
        System.out.println(a.m); // 출력 2
        System.out.println(a.n); // 출력 3

    }     
}

 

- 명시적 this 키워드 추가

class AA{
    int m;
    int n;
    void init(int m, int n) {
        m = m;
        n = n;
    }
}

class BB {
    int m;
    int n;
    void init(int m, int n) {
        this.m = m ;
        this.n = n;
    }
}

public class ThisKeyword_2 {
    public static void main(String[] args) {
        // 필드명과 지역변수명이 같고, this 키워드를 사용하지 않음.
        AA aa = new AA();
        aa.init(2, 3);
        System.out.println(aa.m); // 0 출력
        System.out.println(aa.n); // 0 출력

        // 필드명과 지역변수명이 같고, this 키워드를 사용함.
        BB bb = new BB();
        bb.init(2, 3);
        System.out.println(bb.m); // 2 출력
        System.out.println(bb.n); // 3 출력
    }
}

 

클래스 내 다른 생성자를 호출하는 this() 메서드

 : this() 메서드 (this 키워드와 다름!) - 자신이 속한 클래스 내부의 다른 생성자를 호출

   생성자의 내부에서만 사용가능O, 생성자의 첫 줄에 위치해야함.

 

- this() 메서드의 문법적 특징과 의미

// 클래스의 정의
class AAA {
    AAA() {
        System.out.println("첫 번째 생성자");
    }
    AAA(int a){
        this(); // 반드시 생성자의 첫 줄에 위치해야 함.
        System.out.println("두 번째 생성자");
    }
    /*
    void abc() { // 메서드에서는 this() 메서드 사용 불가능
        this();
    }
    */
}

public class ThisMethod_1 {
    public static void main(String[] args) {
        // 객체 생성
        AAA a1 = new AAA(); // 첫번째 생성자 호출
        System.out.println();
        AAA a2 = new AAA(3); // 두번째 생성자 호출(생성자 내부의 첫번째 생성자 호출)

    }
}

 

 - this(생성자 입력매개변수) 활용

class AAAA {
    int m1, m2, m3, m4;
    AAAA() {
        m1 = 1;
        m2 = 2;
        m3 = 3;
        m4 = 4;
    }
    AAAA(int a) {
        m1 = a;
        m2 = 2;
        m3 = 3;
        m4 = 4;
    }
    AAAA(int a, int b) {
        m1 = a;
        m2 = b;
        m3 = 3;
        m4 = 4;
    }
    void print() {
        System.out.print(m1 + " ");
        System.out.print(m2 + " ");
        System.out.print(m3 + " ");
        System.out.print(m4);
        System.out.println();
    }
}

class BBBB {
    int m1, m2, m3, m4;
    BBBB() {
        m1 = 1;
        m2 = 2;
        m3 = 3;
        m4 = 4;
    }
    BBBB(int a) {
        this(); // BBBB() 생성자 호출
        m1 = a;
    }
    BBBB(int a, int b) {
        this(a); // BBBB(int a) 생성자 호출
        m2 = b;
    }
    /*
    BBBB(int a, int b) { // BBBB() 생성자를 호출, 두 필드 값을 한번에 수정 가능
        this();
        m1 = a;
        m2 =b;
    }
    */
    void print() {
        System.out.print(m1 + " ");
        System.out.print(m2 + " ");
        System.out.print(m3 + " ");
        System.out.print(m4 + " ");
        System.out.println();
    }
}

public class ThisMethod_2 {
    public static void main(String[] args) {
        // 3가지 객체 생성( this() 미사용 )
        AAAA a1 = new AAAA();
        AAAA a2 = new AAAA(10);
        AAAA a3 = new AAAA(10, 20);
        a1.print();
        a2.print();
        a3.print();
        System.out.println();

        // 3가지 객체 생성( this() 사용 )
        BBBB b1 = new BBBB();
        BBBB b2 = new BBBB(11);
        BBBB b3 = new BBBB(11, 22);
        b1.print();
        b2.print();
        b3.print();
    }
}

 출력

1 2 3 4
10 2 3 4
10 20 3 4

1 2 3 4 
11 2 3 4
11 22 3 4