ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자바의 정석] 6장 객체지향 언어 1. 4~6 변수의 초기화
    카테고리 없음 2023. 3. 12. 16:42
    728x90

    아래 내용은 자바의 정석 강의&책을 보면서 정리한 내용입니다.

    들어가기 전에

    자바의 정석 6장 내용 리스트 

    이번 시간에는 아래 내용 중 오버로딩~변수의 초기화 부분을 정리하겠습니다. 

     

    4. 오버로딩

    4.1 오버로딩이란?

    오버로딩? 한 클래스 내에 같은 이름의 메서드를 여러 개 정의하는 것

     

    4.2 오버로딩 조건

    ⭐  1. 메서드 이름이 같다.
          2. 매개변수의 개수 또는 타입이 다르다.
          주의! 반환 타입은 오버로딩 구현 시 아무런 영향을 주지 못함

     

     

    4.3 오버로딩의 예

    가장 대표적인 것은 println 메서드이다. 아래와 같이 매개변수 타입에 따라서 오버로딩 되어 있다.

     

    1) 리턴 타입만 다른 경우 - 오버로딩이 아님

    아래 add() 메서드에서 리턴값만 다른 경우 아래와 같은 에러가 발생한다. 이는 오버로딩이 아니다!!

    class Math{
        int add(int a, int b) {return a + b;}
        long add(int a, int b){return long(a + b);}
    }
    
    

     

    2) 매개변수 타입 순서만 다른 경우 - 오버로딩

    아래는 두 메서드 모두 int형과 long형 매개변수가 하나씩 선언되어 있지만 서로 순서가 다른 경우이다. 이 경우 구분하여 호출이 가능하므로 오버로딩으로 간주한다. 하지만 이렇게 선언하는 것은 순서를 외워야 하기 때문에 단점이 된다.

    아래 m.add(1, 2)와 같은 호출은 불가능하다. 왜냐하면 어떤 메서드를 호출해야할지 알 수가 없다. 따라서 java: reference to add is ambiguous라는 컴파일 에러가 발생한다.

    class Math{
        long add(int a, long b) {return a + b;}
        long add(long a, int b){return a + b;}
    }
    
    public class Test {
        public static void main(String[] args) {
            Math m = new Math();
            System.out.println(m.add(1, 2L));
            System.out.println(m.add(1, 2));    // 에러 발생:reference to add is ambiguous
        }
    }
    

     

    4.4 오버로딩의 장점

    ⭐  모두 근본적으로 같은 기능을 하는 메서드지만 서로 다른 이름을 가져야하면 이름 짓기도 어렵고 메서드를 사용하는 쪽에서 이름을 일일이 구분해서 기억해야 한다. 하지만 오버로딩을 하면 한 개만 기억하면 되고 메서드 명만 보고도 예측이 쉽다.
    • 오버로딩을 사용 안하는 경우, 아래와 같이 정의해야 한다.

     

    4.5 가변인자와 오버로딩

    매개변수 개수가 고정이 아닌 동적으로 지정할 수 있다. 가변 인자 선언을 진행하면 가능하다.

    • 가변인자 선언 방식: 타입… 변수명
    • 주의: 가변인자는 마지막에 선언

     

    1) 가변인자 vs 배열 차이점

    • 배열을 매개변수로 하는 경우, 아래와 같이 빈 값으로 넣을 수 없고 반드시 null을 넣어줘야 한다.

    2) 가변인자 오버로딩 시, 주의점

    아래 예시를 보면 concatenate 메서드를 오버로딩했다. delim이 없는 경우를 오버로딩하였지만, 실제 컴퓨터는 이 두 메서드를 구분할 수 없기 때문에 에러가 발생한다. 따라서 가변인자 메서드는 오버로딩하지 않는 것을 추천한다.

    public class Test {
        static String concatenate(String delim, String ... args){
            String result = "";
    
            for(String str: args){
                result += str + delim;
            }
            return result;
        }
        // 아래 오버로딩 시, 에러 발생!!
        static String concatenate(String ... args){
            return concatenate("", args);
        }
        public static void main(String[] args) {
            String[] strArr = {"100", "200", "300", "400"};
            System.out.println(concatenate("", "100", "200", "300", "400"));           // 100200300400
            System.out.println(concatenate("-", strArr));                                    // 100-200-300-400-
            System.out.println(concatenate(",", new String[]{"100", "200", "300", "400"}));  // 100,200,300,400,
            System.out.println("[" + concatenate(",", new String[0]) + "]");                 // []
            System.out.println("[" + concatenate(",") +  "]");                               // []
        }
    }

     

    5. 생성자

    5.1 생성자란?

    ⭐  생성자란? 인스턴스가 생성될 때 호출되는 인스턴스(iv) 초기화 메서드이다. 따라서 인스턴스 변수의 초기화 작업에 주로 사용되며, 인스턴스 생성 시에 실행되어야 할 작업을 위해서 사용된다. ⇒ 주의! 생성자는 인스턴스를 생성하는 것은 아님!

    생성자 조건

    1. 생성자의 이름은 클래스의 이름과 같다.
    2. 생성자는 리턴값이 없다. ⇒ void 생략

     

    특징

    • 오버로딩이 가능하여 하나의 클래스에 여러 개의 생성자 존재

     

    인스턴스 생성 코드 순서

    Card c = new Card();
    
    1. 연산자 new에 의하여 메모리(heap)에 Card 클래스의 인스턴스가 생성된다.
    2. 생성자 Card()가 호출되어 수행된다.
    3. 연산자 new의 결과로 생성된 Card인스턴스의 주소가 반환되어 참조변수 c에 저장된다.

     

    5.2 기본 생성자

    ⭐ 기본 생성자란? 컴파일러가 자동으로 생성해 주는 매개변수가 없고 아무런 내용 없는 생성자
    주의: 기본 생성자는 생성자가 하나도 없을 때 컴파일러가 자동으로 생성되는 것!!

    아래 예제를 통해 주의: 기본 생성자는 생성자가 하나도 없을 때 자동으로 생성되는 것!! 을 알 수 있다.

    Data2 클래스는 매개변수가 있는 생성자를 정의하였다. 그러면 컴파일러는 자동으로 기본 생성자를 추가하지 않는다.

    class Data1{
        int val;
    }
    
    class Data2{
        int val;
        // 매개변수가 존재하는 생성자 정의 
        Data2(int x){
            val = x;
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Data1 d1 = new Data1();
            Data2 d2 = new Data2();  // 컴파일 에러!!
            
        }
    }
    

     

    5.3 매개변수가 있는 생성자 - 초기화

    생성자도 메서드와 같이 매개변수를 선언하여 호출 시 인스턴스의 초기화 작업을 사용할 수 있다.

    class Car{
        String color; 
        String gearType;
        int door;
        
        Car(){}
        Car(String c, String g, int d){
            color = c;
            gearType = g;
            door = d;
        }
    }
    public class Test {
        public static void main(String[] args) {
            // 인스턴스 초기화 방법 1. 직접 
            Car c1 = new Car();
            c1.color = "white";
            c1.gearType = "auto";
            c1.door = 4;
    
            // 인스턴스 초기화 방법 2. 생성자 사용  
            Car c2 = new Car("white", "auto", 4);
        }
    }
    

     

    5.4 생성자에서 다른 생성자 호출하기 - this(), this

    ⭐  this: 인스턴스 자신을 가리키는 참조변수. 인스턴스 주소가 저장되어 있다.
                    모든 인스턴스메서드에 지역변수로 숨겨진 채 존재.
        this(), this(매개변수): 생성자. 같은 클래스의 다른 생성자 호출 시 사용
            - 생성자의 이름으로 클래스 이름 대신 this를 사용한다.
            - 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서만 호출이 가능하다.

    주의: this는 static 메서드(클래스 메서드)에서 사용할 수 없다. this는 인스턴스를 의미하기 때문!: this는 static 메서드(클래스 메서드)에서 사용할 수 없다. this는 인스턴스를 의미하기 때문!
    • 첫 줄에서만 호출이 가능한 이유?
      • 다른 생성자 호출하기 이전 초기화 작업이 무의미해질 수 있다. → 7장에서 자세히 배움!
    • 결과적으로 아래 예시는 에러가 발생한다.
    class Car{
        String color;
        String gearType;
        int door;
    
        Car(){
            this("white", "auto", 4);
        }
        Car(String color){
            door = 5;              // this가 첫번째줄에 존재하지 않음! 
            Car(color, "auto", 4); // this로 생성자를 호출해야한다. 
        }
        Car(String c, String g, int d){
            color = c;
            gearType = g;
            door = d;
        }
    }
    
    • 수정된 올바른 예시
    class Car{
        String color;
        String gearType;
        int door;
    
        Car(){
            this("white", "auto", 4);   // 아무것도 지정 안하는 경우, default값 설정 
        }
        Car(String color){
            this(color, "auto", 4);
        }
        Car(String c, String g, int d){
            color = c;
            gearType = g;
            door = d;
        }
    }
    public class Test {
        public static void main(String[] args) {
            // 인스턴스 초기화 방법 1. 직접
            Car c1 = new Car();
            c1.color = "white";
            c1.gearType = "auto";
            c1.door = 4;
    
            // 인스턴스 초기화 방법 2. 생성자 사용
            Car c2 = new Car("white", "auto", 4);
        }
    }
    
    • this.인스턴스 사용
      • 아래와 같이 this.인스턴스로 적어야 인스턴스와 매개변수 구분이 가능하다.
    class Car{
        String color;
        String gearType;
        int door;
    
        Car(){
            this("white", "auto", 4);
        }
        Car(String color){
            this(color, "auto", 4);
        }
        Car(String color, String gearType, int door){
            this.color = color;
            this.gearType = gearType;
            this.door = door;
        }
    }
    

    5.5 생성자를 이용한 인스턴스의 복사

    • 아래 Car(Car c)를 통해 인스턴스를 복사하여 사용한 예시이다. c1.door = 100;로 값을 변경했지만 c2.door는 변경되지 않음을 알 수 있다.
    • this()를 호출하여 인스턴스 복사를 하였다.
    class Car{
        String color;
        String gearType;
        int door;
    
        Car(){
            this("white", "auto", 4);
        }
        Car(Car c){
            this(c.color, c.gearType, c.door);   //this를 활용하여 복사 
        }
        Car(String color, String gearType, int door){
            this.color = color;
            this.gearType = gearType;
            this.door = door;
        }
    }
    public class Test {
        public static void main(String[] args) {
            // 인스턴스 초기화 방법 1. 직접
            Car c1 = new Car();
            Car c2 = new Car(c1);
            System.out.println("c1: " + c1.color + " " + c1.gearType + " " + c1.door);    // c1: white auto 4
            System.out.println("c2: " + c2.color + " " + c2.gearType + " " + c2.door);    // c2: white auto 4
            c1.door = 100;
            System.out.println("c1: " + c1.color + " " + c1.gearType + " " + c1.door);    // c1: white auto 100
            System.out.println("c2: " + c2.color + " " + c2.gearType + " " + c2.door);    // c2: white auto 4
        }
    }
    

     

     

    6. 변수의 초기화

    6.1 변수의 초기화

    ⭐ 멤버변수(클래스변수와 인스턴스변수)와 배열의 초기화: 선택적 ⇒ 기본값으로 자동 초기화됨 (대부분 0으로 초기화)
     지역변수의 초기화: 필수

    멤버변수(cv, iv) 초기화 방법

    1. 자동 초기화: 0으로 기본 초기화
    2. 간단 초기화(=명시적 초기화) : =
    3. 복잡 초기화
      1. 생성자
      2. 초기화 블럭
      • 인스턴스 초기화 블럭: 인스턴스변수를 초기화 하는데 사용
      • 클래스 초기화 블럭: 클래스변수를 초기화 하는데 사용

     

    6.2 멤버변수 초기화 방식 1. 명시적 초기화

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

    class Car {
    	int door = 4;             // 기본형 초기화 
    	Engine e = new Engine();  // 참조형 초기화. null이 아닌 객체 주소를 넣기 
    
    }
    

     

    6.3 멤버변수 초기화 방식 2. 초기화 블럭

    ⭐ - 클래스 초기화 블럭: 클래스변수의 복잡한 초기화에 사용된다.
        -  인스턴스 초기화 블럭: 인스턴스변수의 복잡한 초기화에 사용된다. 거의 사용 안 함!!

     

    클래스 초기화 인스턴스 초기화 (거의 사용 안 함)→ 생성자 사용

    방법 static { /* 클래스 초기화블럭 */} {/* 인스턴스 초기화블럭 */}
    수행 시기 클래스가 메모리에 처음 로딩될 때 한 번 - 인스턴스 생성할 때 마다 수행

     

    인스턴스 초기화 사용 목적 예시

    Car 생성자 수행 시 count ++; serialNo = count; 해당 부분은 중복이 된다.

    Car(){
            count ++;           // 중복 
            serialNo = count;   // 중복 
            color = "White";
            gearType = "Auto";
        }
        
        Car(String color, String gearType){
            count ++;          // 중복 
            serialNo = count;  // 중복 
            this.color = color;
            this.gearType = gearType;
        }
    

    아래와 같이 초기화 블럭으로 초기화 수행을 하면 중복을 제거할 수 있다.

    { count ++; serialNo = count; } 초기화 블럭을 추가하여 중복을 제거할 수 있다.

    Car(){
            color = "White";
            gearType = "Auto";
        }
    
        Car(String color, String gearType){
            this.color = color;
            this.gearType = gearType;
        }
        {
            count ++;
            serialNo = count;
        }
    

    클래스 초기화, 인스턴스 초기화 사용 예시

    아래예시는 초기화 블럭 호출 시기를 알 수 있다.

    class BlockTest {
        static {
            System.out.println("static {}");   // 클래스 초기화. 1번 호출. BlockTest가 메모리에 로딩 시 가장 먼저 수행
        }
    
        {
            System.out.println("{ }");        //  인스턴스 초기화. 3번 호출. 객체 생성 시 인스턴스 초기화 블록 수행
        }
    
        public BlockTest(){
            System.out.println("생성자");       // 4번 호출. 인스턴스 초기화 -> 생성자 호출 
        }
        public static void main(String[] args) {
            System.out.println("BlockTest bt = new BlockTest();");  // 2번 호출
            BlockTest bt = new BlockTest();
            System.out.println("BlockTest bt2 = new BlockTest();");
            BlockTest bt2 = new BlockTest();
        }
    }
    
    • 결과
    static {}
    BlockTest bt = new BlockTest();
    { }
    생성자
    BlockTest bt2 = new BlockTest();
    { }
    생성자
    

    6.4 멤버변수의 초기화 시기와 순서

      클래스 변수  인스턴스 변수
    초기화 시점 클래스가 처음 로딩될 때 한번 인스턴스가 생성될 때마다 각 인스턴스별로 초기화
    초기화 순서 기본값 → 명시적초기화 → 클래스 초기화 블럭 기본값 → 명시적초기화 → 인스턴스 초기화 블럭 → 생성자

     

    초기화 순서 예시

    class InitTest {
     // 명시적 초기화 (간단 초기화) 
    	static int cv = 1;
    	int iv = 1;
    
    	static {cv = 2;}   // 클래스 초기화 블럭 
    	{iv = 2;}          // 인스턴스 초기화 블럭 
    
    	InitTest() {       // 생성자 
    		iv = 3;
    	}
    
    }
    

    위 예시의 순서는 아래와 같이 이뤄진다.

    • cv 초기화 → iv 초기화 진행
    • 자동(0으로 초기화) → 간단(=) → 복잡 초기화(static {}, 생성자)

    사용 예시

    아래 예시는 초기화 사용 예시다.

    예를 들어 공장에서 제품 생산 시 생산일련번호(serialNo)를 제품마다 부여한다. 이때 {} 블럭(초기화 블럭)을 사용한다.

     

    class Product {
        static int count = 0;  // 인스턴스 수 저장
        int serialNo;
    
        {
            ++count;
            serialNo = count;
        }
        public Product(){}
    }
    public class Test {
        public static void main(String[] args) {
            Product p1 = new Product();
            Product p2 = new Product();
            Product p3 = new Product();
    
            System.out.println("p1: " + p1.serialNo );       // p1: 1
            System.out.println("p2: " + p2.serialNo );       // p2: 2
            System.out.println("p3: " + p3.serialNo );       // p3: 3
            System.out.println("count: " + Product.count );  // count: 3
        }
    }

     

    다음 시간에는 자바의 정석 7장 객체지향 언어 2에 대해서 정리하겠습니다. 😀

     

    댓글

Designed by Tistory.