[Java] 클래스와 데이터, 기본형과 참조형, 생성자

클래스와 데이터

1. 클래스

  • 클래스 : 객체를 생성하기 위한 설계도로 객체가 가져야 할 속성(변수)과 기능(메서드)를 정의한다.

      public class ClassStart3 {
          public static void main(String[] args) {
              Student student1;
              student1 = new Student();
              student1.name = "학생1";
              student1.age = 15;
              student1.grade = 90;
        
              Student student2 = new Student();
              student2.name = "학생2";
              student2.age = 16;
              student2.grade = 80;
          }
      }
    
    • 사용자가 원하는 종류의 데이터 타입을 마음껏 정의할 수 있다.
    • 객체(Object) : 클래스를 사용해서 실제 메모리에 만들어진 실체
      • 서로 독립적인 상태를 가진다.
    • 인스턴스(Instance) : 특정 클래스로부터 생성된 객체
      • 주로 객체가 어떤 클래스에 속해있는 지 강조할 때 사용한다.
      • 예) student1 객체는 Student 클래스의 인스턴스이다.
    • 멤버 변수(Member Variable) : 특정 클래스에 소속된 변수
    • 필드(Field) : 특정 클래스에 소속된 변수
      • 멤버 변수와 필드는 같은 뜻이다.
    • 클래스는 관례상 대문자로 시작하고, 낙타 표기법을 사용한다.
      • 예) Student, User, MemberService
  • 변수 선언 → 객체 생성 → 참조값 보관

    • Student student1 : Student 타입을 받을 수 있는 변수를 선언한다.
    • student1 = new Student() : Student 클래스 정보를 기반으로 새로운 객체인 student1을 생성한다.
    • student1 변수는 메모리에 존재하는 실제 Student 객체의 참조값(x001)을 보관한다.
      • 객체에 접근하기 위해 객체 생성 시 반환되는 참조값을 보관해두어야 한다.

    image

2. 객체 사용

  • 객체에 접근하기 이해 . 을 사용한다.

      student1.name = "학생1";
      student1.age = 15;
      student1.grade = 90;
    
  • 객체 값을 읽을 때도 . 을 통해 참조값을 사용해서 객체에 접근한 다음 원하는 작업을 하면 된다.

      //1. 객체 값 읽기
      System.out.println("이름:" + student1.name);
      //2. 변수에 있는 참조값을 통해 실제 객체에 접근하고, name 멤버 변수에 접근한다.
      System.out.println("이름:" + x001.name);
      //3. 객체의 멤버 변수의 값을 읽어옴
      System.out.println("이름:" + "학생1");
    

3. 배열 도입

  • 배열 사용시 특정 타입을 연속한 데이터 구조로 묶어서 편리하게 관리할 수 있다.

      public class ClassStart4 {
          public static void main(String[] args) {
              Student student1 = new Student();
              student1.name = "학생1";
              student1.age = 15;
              student1.grade = 90;
        
              Student student2 = new Student();
              student2.name = "학생2";
              student2.age = 16;
              student2.grade = 80;
        
              **Student[] students = new Student[2];**
              students[0] = student1;
              students[1] = student2;
          }
      }
    
  • Student[] students = new Student[2]
    • Student 배열의 각 항목은 Student 타입의 참조값을 보관한다.
    • 아직 참조값을 대입하지 않아서 null 값으로 초기화된다.

    image

  • 배열에 들어있는 객체 사용
    • 먼저 배열에 접근 → 객체에 접근
  • 배열 선언 최적화

      // 방법 1
      Student[] students = new Student[]{student1, student2};
        
      // 방법 2
      Student[] students = {student1, student2};
    

기본형과 참조형

1. 기본형 vs 참조형

  • 기본형(Primitive Type) : int, long, double, boolean처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입
  • 참조형(Reference Type): Student student1, int[] students와 같이 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입
  • 기본형을 제외한 나머지는 모두 참조형이다.
    • 기본형은 소문자로 시작한다.
    • 클래스는 대문자로 시작한다. → 참조형
    • String은 클래스로 참조형이지만, 기본형처럼 문자 값을 바로 대입할 수 있다. 문자는 매우 자주 다뤄 자바에서 특별히 편의 기능을 제공한다.

2. 변수 대입

  • 기본형 : 실제 사용하는 값이 변수에 들어있어서 해당 값만 복사해서 대입한다.
  • 참조형 : 실제 사용하는 객체가 아니라 객체의 위치를 가리키는 참조값만 복사된다.
    • 예시 : dataA에 들어있는 참조값 x001을 복사해서 dataB에 대입한다.

    image.png

      Data dataA = new Data();
      dataA.value = 10;
      Data dataB = dataA;
        
      System.out.println("dataA 참조값=" + dataA); // ref.Data@x001
      System.out.println("dataB 참조값=" + dataB); // ref.Data@x001
      System.out.println("dataA.value = " + dataA.value); // 10
      System.out.println("dataB.value = " + dataB.value); // 10
    

3. 메서드 호출

  • 기본형 : 메서드로 기본형 데이터 전달시, 해당 값이 복사되어 전달된다.
    • 이 경우, 메서드 내부에서 매개변수의 값을 변경해도, 호출자의 변수 값에는 영향이 없다.
  • 참조형 : 메서드로 참조형 데이터를 전달하면, 참조값이 복사되어 전달된다.
    • 이 경우, 메서드 내부에서 매개변수로 전달된 객체의 멤버 변수를 변경하면, 호출자의 객체도 변경된다.
    • 예시 : dataA와 dataX는 같은 참조값이 x001을 가지게 되어 dataX를 통해서 x001에 있는 Data 인스턴스에 접근할 수 있다.

        public static void main(String[] args) {
        		Data dataA = new Data();
        		dataA.value = 10;
        		System.out.println("메서드 호출 전: dataA.value = " + dataA.value); // 10
              		
        		changeReference(dataA);
        		System.out.println("메서드 호출 후: dataA.value = " + dataA.value); // 20
        }
              
        static void changeReference(Data dataX) {
        		dataX.value = 20;
        }
      

4. 변수와 초기화

  • 변수의 종류
    • 멤버 변수(필드) : 클래스에 선언
    • 지역 변수 : 메서드에 선언, 매개 변수도 지역 변수의 한 종류이다.
  • 변수의 값 초기화
    • 멤버 변수 : 인스턴스 생성 시 자동 초기화된다.
      • int = 0, boolean = false, 참조형 = null
      • null은 아직 값이 존재하지 않는다는 것
    • 지역 변수 : 항상 직접 초기화 해야한다.
  • 가비지 컬렉션(GC) : 아무도 참조하지 않는 인스턴스가 있으면 GC가 더이상 사용하지 않는 인스턴스라 판단하고 해당 인스턴스를 자동으로 메모리에서 제거해준다.
    • 아무도 참조하지 않는 인스턴스는 사용되지 않고 메모리 용량만 차지한다.
  • NullPointerException
    • null에 . 을 찍었을 때, 참조할 주소가 존재하지 않기 때문에 발생하는 예외

객체 지향 프로그래밍

1. 절차 지향 프로그래밍 vs 객체 지향 프로그래밍

  • 절차 지향 프로그래밍
    • 프로그램의 흐름을 순차적으로 따르면 처리한다.
    • “어떻게”를 중심으로 프로그래밍한다.
    • 데이터와 해당 데이터에 대한 처리 방식이 분리되어 있다. → 유지보수하기 불편하다.
  • 객체 지향 프로그래밍
    • 실제 세계의 사물이나 사건을 객체로 복, 이러한 객체들 간의 상호작용을 중심으로 프로그래밍한다.
    • “무엇을” 중심으로 프로그래밍한다.
    • 데이터(속성)와 그 데이터에 대한 행동(메서드)이 하나의 ‘객체’안에 함께 포함되어 있다.
    • 예시 : 데이터인 value와 해당 데이터를 사용하는 add() 메서드를 함께 클래스에 정의

        public class ValueObject {
        		int value;
              		
        		void add() {
        				value++;
        				System.out.println("숫자 증가 value=" + value);
        		}
        }
      
        public class ValueObjectMain {
        		public static void main(String[] args) {
        				ValueObject valueObject = new ValueObject();
        				valueObject.add();
        				valueObject.add();
        				valueObject.add();
        				System.out.println("최종 숫자=" + valueObject.value);
        		}
        }
      
  • 캡슐화
    • 속성과 기능을 하나로 묶어서 필요한 기능을 메서드를 통해 외부에 제공하는 것
    • 객체 내부 코드가 변하는 경우, 다른 코드는 변경하지 않아도 된다.

생성자

1. 생성자가 필요한 이유

  • 아래 코드에서는 초기값을 설정하는 부분이 계속 반복된다.

      public static void main(String[] args) {
      		MemberInit member1 = new MemberInit();
      		member1.name = "user1";
      		member1.age = 15;
      		member1.grade = 90;
        		
      		MemberInit member2 = new MemberInit();
      		member2.name = "user2";
      		member2.age = 16;
      		member2.grade = 80;
        		
      		MemberInit[] members = {member1, member2};
      }
    
  • 메서드를 사용해서 초기값 설정하는 부분의 반복을 제거해보자.

    • 객체 지향 프로그래밍에서는 속성과 기능을 한 곳에 두는 것이 더 나은 방법이다. —> MemberInit이 초기값을 설정하는 기능을 제공하는 것이 바람직!
      public static void main(String[] args) {
      		MemberInit member1 = new MemberInit();
      		initMember(member1, "user1", 15, 90);
        		
      		MemberInit member2 = new MemberInit();
      		initMember(member2, "user2", 16, 80);
        		
      		MemberInit[] members = {member1, member2};
      		for (MemberInit s : members) {
      				System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" +s.grade);
      		}
      }
        
      static void initMeber(MemberInit member, String name, int age, int grade) {
      		member.name = name;
      		member.age = age;
      		member.grade = grade;
      }
    

2. this

  • 멤버 변수와 메서드의 매개 변수가 이름이 동일하면, 매개변수가 우선순위를 가진다.
  • 멤버 변수에 접근하려면 this. 으로 인스턴스 자신의 참조값을 가리켜주어야 한다.

      public class MemberInit {
      		String name;
      		int age;
      		int grade;//추가
        		
      		void initMember(String name, int age, int grade) {
      				**this**.name = name;
      				**this**.age = age;
      				**this**.grade = grade;
      		}
      }
    
  • 필드 이름과 매개변수 이름이 다르다면, this를 생략해도 된다.
    • name = name → 필드 이름과 매개변수 이름이 같을 때, name은 둘 다 매개변수를 가르킨다.

3. 생성자 도입

  • 객체 지향 언어는 객체를 생성하자마자 즉시 초기값을 할당할 수 있도록 생성자라는 기능을 제공한다.
    • 생성자의 이름은 클래스 이름과 같아야 하며, 첫 글자는 대문자로 시작한다.
    • 생성자는 반환 타입이 없다.

        public class MemberConstruct {
        		String name;
        		int age;
        		int grade;
              		
        		**MemberConstruct(String name, int age, int grade) {
        				this.name = name;
        				this.age = age;
        				this.grade = grade;
        		}**
        }
      
  • 생성자는 인스턴스를 생성하고 나서 즉시 호출된다.
    • new 명령어 다음에 생성자 이름과 매개변수에 맞추어 인수를 전달하면 된다.

              
        public static void main(String[] args) {
        		MemberConstruct member1 = **new MemberConstruct("user1", 15, 90);**
        		MemberConstruct member2 = **new MemberConstruct("user2", 16, 80);**
        		}
        }
      
  • 생성자 특징
    • 중복 호출 제거
    • 제약 - 생성자 호출 필수
      • 생성자가 없으면 프로그램은 작동하지만, 데이터가 없는 상태로 동작하게 된다.
    • 직접 정의한 생성자의 경우 반드시 호출되어야 하며, 호출되지 않으면 컴파일 오류가 발생한다.
    • 생성자를 사용하면 필수값 입력을 보장할 수 있다.

4. 기본 생성자

  • 기본 생성자 : 매개변수가 없는 생성자
  • 클래스에 생성자가 없으면 자바 컴파일러는 매개변수가 없고, 작동하는 코드가 없는 기본 생성자를 자동으로 만들어준다.
  • 생성자가 하나라도 있으면 자바는 기본 생성자를 만들지 않는다.

      public class MemberDefault {
      		String name;
      }
        
      public class MemberDefaultMain {
      		public static void main(String[] args) {
      				MemberDefault memberDefault = new MemberDefault();
      		}
      }
    
    • 위의 경우 자바가 다음과 같은 기본 생성자를 만들어준다.
      public class MemberDefault {
      		String name;
        		
      		**//기본 생성자
      		public MemberDefault() {
      		}**
      }
    

5. 오버로딩과 this()

  • 생성자는 메서드 오버로딩처럼 매개변수만 다르게 해서 여러 생성자를 제공할 수 있다.
    • grade가 꼭 필요한 경우 grade가 있는 생성자를 호출하고, 그렇지 않은 경우에는 grade가 없는 생성자를 호출하면 된다.
      public class MemberConstruct {
      		String name;
      		int age;
      		int grade;
        		
      		//추가
      		MemberConstruct(String name, int age) {
      				this.name = name;
      				this.age = age;
      				this.grade = 50;
      		}
        		
      		MemberConstruct(String name, int age, int grade) {
      				this.name = name;
      				this.age = age;
      				this.grade = grade;
      		}
      }
        
      public class ConstructMain2 {
      		public static void main(String[] args) {
      				MemberConstruct member1 = new MemberConstruct("user1", 15, 90);
      				MemberConstruct member2 = new MemberConstruct("user2", 16);
        				
      				MemberConstruct[] members = {member1, member2};
      				}
      		}
      }
    
  • this() 를 사용하여 생성자 내부에서 자신의 생성자를 호출할 수 있다.
    • 생성자 2개

        public class MemberConstruct {
        		String name;
        		int age;
        		int grade;
              		
        		MemberConstruct(String name, int age) {
        				**this(name, age, 50); //변경**
        		}
              		
        		MemberConstruct(String name, int age, int grade) {
        				this.name = name;
        				this.age = age;
        				this.grade = grade;
        		}
        }
      




김영한의 실전 자바 기본편을 참고하였습니다

© 2021. All rights reserved.

yaejinkong의 블로그