본문 바로가기
☕ Java 웹 프로그래밍/Java

[프로그래머스] Java(자바) 입문 | Part 6. 클래스 다듬기

by 일단연 2023. 5. 3.

 생성자 

  • 모든 클래스는 인스턴스화될 때 생성자를 사용
    • 예: Car c1 = new Car( ); 에서 Car( )가 생성자

생성자의 특징

  • 생성자는 리턴타입이 없음
  • 생성자를 프로그래머가 만들지 않으면, 컴파일할 때 매개변수가 없는 생성자가 자동으로 만들어짐
    • 컴파일 시에 만들기 때문에 코드로 나타나진 않음
  • 매개변수가 없는 생성자를 기본생성자라고 함
  • 생성자를 하나라도 프로그래머가 만들었다면 기본생성자는 자동으로 만들어지지 않음

 

생성자의 역할

  • 생성자가 하는 일은 클래스가 객체가 될(인스턴스화) 때 필드를 초기화하는 역할을 수행
  • Car가 객체가 될 때 반드시 이름을 가지도록 하려면, Car클래스에 다음과 같은 생성자를 만들어야 함
    • 이름을 받아들일 수 있는 매개변수를 하나 받아서, 그때 받은 매개변수를 name필드에 넣어줌
    • Car객체가 생성되면 name이 초기화될 것
public class Car{
  String name;
  int number;

  public Car(String n){  //이름을 받아들일 수 있는 매개변수를 하나 받고
    name = n;            //그때 받은 매개변수를 name필드에 넣어줌
  }                      //Car객체가 생성되면 name이 초기화될 것
}
  • 위에서 매개변수 n로 정의한 생성자를 만들었기 때문에 Car클래스는 기본 생성자를 가지지 않음 >기본생성자로 Car 객체를 생성할 수 없음
    • 매개변수 n로 정의한 생성자를 만들자마자, CarExam 클래스의 기본생성자에 오류 발생
  • 위의 Car 클래스를 이용하여 Car 인스턴스를 생성하는 방법
    • 정의한 생성자는 값을 받아와야 함 (생성자의 매개변수 데이터타입에 맞춰서)
    • Car 객체를 생성할 때 필드 값이 생성자에 적은 값으로 초기화됨
public class CarExam2{
  public static void main(String args[]){

    Car c1 = new Car("소방차");
    Car c2 = new Car("구급차");
    *//Car c3 = new Car();          //컴파일 오류 발생*
    System.out.println(c1.name);   //Car 객체를 생성할 때 필드 값이 "소방차"로 초기화됨
    System.out.println(c2.name);   //Car 객체를 생성할 때 필드 값이 "구급차"로 초기화됨
  }
}

 

실습

  • Person클래스
class Person{
  int age;
    
  public Person(int a){
    age = a;
  }
}
  • PersonExam클래스
//실행을 위한 코드입니다.
public class PersonExam {
  public static void main(String[] args) {
    //Person클래스에서 int형 변수를 매개변수로 받는 생성자를 호출합니다.
    Person person = new Person(25);
  }
}


 

 this 

객체 자신을 참조하는 키워드

 

this 의 사용

public class Car{
  String name;
  int number;

  public Car(String n){
    name = n;
  }
}
  • Car클래스의 생성자 매개변수의 이름이 n
    • n 이라는 변수명은 무엇을 의미하는지 쉽게 알 수 없음
    • n 보다는 name으로 사용하는 게 좋음
public Car(String name){
  name = name;  //필드 = 매개변수
}
  • 'name=name' 이라고 코드를 바꾸면, 컴파일러는 가깝게 선언된 변수를 우선 사용
    • 매개변수 name의 값을 매개변수 name에 대입하라는 의미로 변질됨
      • 생성자에 인자를 넣었을 때 String클래스로 선언한 필드의 결과는 null이 되고, int 데이터타입으로 선언한 필드의 결과는 0이 됨
      • 필드를 매개변수에 들어오는 인자로 바꾸려는 건데 위처럼 되면, 필드는 바뀌지 않음
  • 이런 경우 필드라는 것을 컴파일러와 JVM에게 알려주기 위해 this키워드를 사용해야 함
public Car(String name){
  this.name = name;
}
  • 앞의 this.name은 필드 name을 말하고 =(이퀄) 뒤의 name은 매개변수를 의미
  • 즉 매개변수의 값(인자)을 필드에 대입하라는 의미가 됨

 

클래스 안에서 this를 사용하는 경우

  • 자기 자신이 갖고 있는 필드에 매개변수의 값을 대입할 때: this.필드명 = 매개변수명;
    • 예: this.name = name;
  • 자기 자신이 갖고 있는 메소드를 사용할 때: this.메소드명( )
  • 자기 자신의 생성자를 호출할 때: this.생성자
    • 예: this(”이름없음”, 0);

 

실습

  • Person클래스
class Person {
  String name;
  int age;
  public Person(String name, int age) {
    // 매개변수로 받은 name과 age를 각각 name, age 필드에 저장하세요.
    this.name = name;
    this.age = age;
  }
}
  • PersonExam클래스
// 실행을 위한 코드입니다.
public class PersonExam {
  public static void main(String[] args) {
    // Person클래스에서 String과 int를 매개변수로 받는 생성자를 호출합니다.
    Person person = new Person("사람", 25);
  }
}


 

 메소드 오버로딩 

매개변수의 데이터타입이나 개수가 다른 경우, 같은 이름의 메소드를 여러 개 정의할 수 있게 하는 기술

 

메소드 오버로딩

  • 이름은 같지만 매개변수가 다른 메소드

class MyClass2{
  public int plus(int x, int y){
    return x + y;
  }

  public int plus(int x, int y, int z){
    return x + y + z;
  }

  public String plus(String x, String y){
    return x + y;
  }
}
  • 메소드 오버로딩은 매개변수 부분이 반드시 달라야 함
public int plus(int i, int f){
  return i+f;  //오류
}
  • 위처럼 변수명이 다르다고 해서 메소드 오버로딩을 사용할 순 없음 (메소드 오버로딩 조건을 충족하지 못함)
    • 매개변수의 타입과 개수가 동일하기 때문에 동일한 메소드를 또 정의할 수 X

 

오버로딩된 메소드 이용하기

  • 메소드의 인자에 어떤 값이 쓰이는지에 따라 각기 다른 메소드가 호출됨
public MethodOverloadExam{
  public static void main(String args[]){
    MyClass2 m = new MyClass2();
    System.out.println(m.plus(5,10));
    System.out.println(m.plus(5,10,15));
    System.out.println(m.plus("hello" + " world"));
  }
}

 

실습

  • Car클래스
class Car {
  void run() {
    System.out.println("차가 달립니다.");        
  }
  // 정수 하나를 매개변수로 받는 메소드, run을 추가해 보세요.
  public void run(int x){
        
  }
    
}
  • CarExam클래스
// 실행을 위한 코드입니다.
public class CarExam {
  public static void main(String[] args) {
    // Person클래스에서 String과 int를 매개변수로 받는 생성자를 호출합니다.
    Car car = new Car();
        
    car.run();
    // int형 매개변수를 받는 run을 호출합니다.
    car.run(100);
  }
}


 

 메소드 오버로딩과 this 

생성자 오버로딩

  • 생성자의 매개변수의 유형과 개수가 다르게 해서 같은 이름의 생성자를 여러 개 가질 수 있음
    • 생성자도 메소드와 마찬가지로 여러 개를 선언할 수 있음
    • 매개변수의 수와 타입이 다르다면 여러개의 생성자를 선언할 수 있음
public class Car{
  String name;
  int number;
  
  //기본생성자로 Car객체를 만들고 싶다면 Car클래스에 기본생성자를 정의해두면 됨
  **public Car(){ 

  }**

  public Car(String name){
    this.name = name;
  }

  public Car(String name, int number){
    this.name = name;
    this.number = number;
  }
}
  • 매개변수가 있는 생성자가 있을 경우, 기본생성자로 객체를 정의하면 오류 발생
    • 클래스에 기본생성자를 정의해두면 오류가 해결됨

 

오버로딩된 생성자 이용하기

    public class CarExam4{
        public static void main(String args[]){
            Car c1 = new Car();
            Car c2 = new Car("소방차");
            Car c3 = new Car("구급차", 1234);
        }
    }

 

자기 생성자 호출하는 this( )

  • 기본생성자를 호출했을 때 name을 "이름없음" , 숫자를 0으로 초기화하기
public Car(){
  this.name = "이름없음";
  this.number = 0;       //밑의 코드와 중복됨
}

public Car(String name, int number){
  this.name = name;
  this.number = number;
}
  • 위처럼 작성했을 경우 기본생성자와 매개변수가 있는 생성자에서 코드 중복이 발생
  • 자신이 가지고 있는 다른 생성자를 이용할 수 있음
public Car(){
  //this.name = "이름없음";
  //this.number = 0; 
  
  this("이름없음", 0); //이렇게 쓰면 중복을 피할 수 있음
}
  • this( ): 자신의 생성자를 호출하는 것
    • 자기 자신의 생성자를 호출함으로써 비슷한 코드가 중복돼서 나오는 것을 방지할 수 있음

 

실습

  • Car클래스
public class Car {
  String name;
  int number;

  public Car(){
    this("이름없음", 0);
  }
    
  public Car(String name){
    this(name, 0);
  }
    
  public Car(String name, int number){
    this.name = name;
    this.number = number;
  }
    
}
  • CarExam클래스
// 실행을 위한 코드입니다.
public class CarExam {
  public static void main(String[] args) {
    Car car1 = new Car();
    Car car2 = new Car("자동차");
    Car car3 = new Car("자동차", 1234);
  }
}


 

 패키지 

  • 서로 관련이 있는 클래스 또는 인터페이스들을 묶어놓은 묶음
  • 패키지를 사용함으로써 클래스들이 필요할 때만 사용될 수 있게 함
  • 클래스를 패키지 이름과 함께 계층적인 형태로 사용
    • 다른 그룹에 속한 클래스와의 관계에서 생길 수 있는 클래스 이름 간의 충돌을 방지하므로 클래스의 관리를 편하게 해줌

 

패키지 정의 방법

  • package이름은 보통 도메인 이름을 거꾸로 적은 후, 그 뒤에 프로젝트 이름을 붙여서 만듦
    • 물론, 프로젝트 이름 뒤에 또 다른 이름이 나올 수도 있음
    • 도메인으로 사용하는 이유는 패키지가 중복되는 것을 방지하기 위함이므로, 반드시 존재하는 도메인이 아니라도 상관없음
  • package이름은 ‘ 폴더명.폴더명.폴더명 ‘ 과 같은 형식으로 만들어짐
    • 각각의 폴더명은 숫자로 시작할 수 없음
  • 예시
    • com.eightcruz.javastudy.Hello로 패키지를 지정
      • 도메인명: 8cruz.com, 프로젝트명: javastudy, 클래스명: Hello
      • 도메인이 숫자로 시작되는데 패키지명은 첫 글자에 숫자를 사용할 수 없으므로 eightcruz처럼 적절하게 수정

 

이클립스에서 패키지 생성하기

  1. src폴더를 선택한 후 우측버튼을 클릭하여 패키지 생성을 선택
  2. 패키지 이름에 com.eightcruz.javastudy를 입력
  3. 해당 패키지를 선택하고 Hello클래스 생성
    • 작성된 클래스 파일의 첫 줄에 package com.eightcruz.javastudy; 생성된 것을 볼 수 있음
    • 패키지를 생성하는 예약어는 package

 

패키지에 생성된 클래스 사용하기 (import)

  • java.lang패키지를 제외하고는 다른 패키지에 있는 클래스를 사용하려면 import라는 구문을 적어줘야 함
    • import com.eightcruz.javastudy.Hello;
    • 위의 코드는 com.eightcruz.javastudy패키지 아래의 Hello클래스를 사용한다고 컴파일러와 JVM에게 알리는 것 (import문을 쓰지 않으면 컴파일 오류 발생)
    • 클래스 이름 대신에 * 를 적어도 됨 (패키지 전체를 import하겠다는 뜻)
      • import com.eightcruz.javastudy.*;
  • * import 단축키: Ctrl + Shift + O
    • 객체를 생성한 후에 누르면 자동으로 해당 패키지의 클래스가 import됨
package javaStudy.part6;

import com.eightcruz.javastudy.Hello; //2. 자동으로 패키지의 클래스가 import됨
                                      //Hello 클래스명 대신 *를 사용해도 됨

public class HelloExam {

  public static void main(String[] args) {
    Hello hello = new Hello(); //1. 이렇게 객체 생성 후 **Ctrl + Shift + O 누르면**
	}
}

 

import하지 않고 사용하는 방법

  • 만약 import를 하기 싫거나, 각기 다른 패키지에 존재하는 같은 이름의 클래스 파일을 사용해야 한다면 클래스 경로 전체를 객체로 생성해 사용
    • com.eightcruz.javastudy.Hello hello = new com.eightcruz.javastudy.Hello();
    • 클래스를 쓸 때마다 패키지명을 전부 써줘야 함