20230405 TIL

박우현 (Joshua)·2023년 4월 6일

항해99_TIL

목록 보기
3/20

20230404 TIL
오늘은 자바 클래스에 관해서 배웠다.

📋 클래스(설계도)


📌 객체지향 프로그램

객체
1. 세상에 존재하는 물체를 뜻하며 식별이 가능한 것.
2. 속성(필드), 행위(메서드)로 구성되어있다.

객체간의 협력

위에 처럼 행위를 정의하는 Java의 메서드를 통해 이루어진다
예시로

  • 사람 객체는 gasPedal(50); 이렇게 메서드 괄호 안에 50의 매개값을 넣어 호출합니다.
    • 그러면 자동차 객체는 해당하는 50의 데이터를 전달 받아 자동차 객체의 속성인 속도의 값을 50으로 만듭니다.
    • 또한 자동차 객체는 gasPedal(50); 메서드에서 속도를 바꾸는 작업을 수행한 후 사람 객체에게 실행 결과인 속도의 값을 반환할 수 있습니다. 이때 반환되는 값을 ‘리턴값’ 이라 표현합니다.

객체간의 관계

  • 사용 관계

    객체 Person은 객체 Car을 사용
  • 포함 관계

    타이어 객체, 차문 객체, 핸들 객체는 자동차 객체에 포함되어있다.
  • 상속 관계

    자동차와 기차 객체는 하나의 공통된 기계시스템 객체를 토대로 만들어진다면 자동차 객체와 기차 객체는 기계시스템 객체를 상속 받는 상속 관계가 됩니다.

객체지향 프로그래밍의 특징

  • 캡슐화 : 속성(필드)와 행위(메서드)를 하나로 묶어 객체로 만든 후 실제 내부 구현 내용은 외부에서 알 수 없게 감추는 것
  • 상속 : 부모 객체가 가지고 있는 필드와 메서드를 자식 객체에 물려주어 자식 객체가 이를 사용할 수 있도록 만드는 것
  • 다형성 : 객체가 연산을 수행할 때 하나의 행위에 대해 각 객체가 가지고 있는 고유한 특성에 따라 다른 여러가지 형태로 재구성되는 것
  • 추상화 : 객체에서 공통된 부분들을 모아 상위 개념으로 새롭게 선언하는 것

객체와 클래스
클래스 = 설계도
객체 = 설계도를 배경으로 만들어진것
클래스를 토대로 생성된 객체를 해당 클래스의 ‘인스턴스’라고 부르며 이 과정을 ‘인스턴스화’라고 부릅니다.
동일한 클래스로 여러 개의 인스턴스를 만들 수 있다.


📌 클래스 설계

1. 클래스 선언 : 만들려 하는 설계도를 선언
2. 클래스의 필드 정의 : 객체가 가지고 있어야할 속성(필드)을 정의
3. 클래스의 생성자 정의 : 객체를 생성하는 방식을 정의
4. 클래스의 메서드 정의 : 객체가 가지고 있어야할 행위(메서드)를 정의

//클래스 선언
public class Car {
	//클래스 필드 정의
	String company; // 자동차 회사
    String model; // 자동차 모델
    String color; // 자동차 색상
    double price; // 자동차 가격
    double speed;  // 자동차 속도 , km/h
    char gear; // 기어의 상태, P,R,N,D
    boolean lights; // 자동차 조명의 상태
	
    // 기본 생성자
	public Car() {} 
    
	//클래스의 메서드 정의
	double gasPedal(double kmh) {
        speed = kmh;
        return speed;
    }
    double brakePedal() {
        speed = 0;
        return speed;
    }
		char changeGear(char type) {
        gear = type;
        return gear;
    }
    boolean onOffLights() {
        lights = !lights;
        return lights;
    }
	void horn() {
        System.out.println("빵빵");
    }
}

📌 객체 생성과 참조형 변수

객체 생성
객체 생성 연산자인 ‘new’를 사용해서 생성
new 연산자 뒤에는 해당 클래스의 생성자 호출 코드를 작성한다.
new Car(); // Car클래스 객체 생성

참조형 변수
new 연산자를 통해서 객체가 생성되면 해당 인스턴스의 주소가 반환되어서 해당 클래스의 참조형 변수를 사용하여 받아준다.

Car car1 = new Car(); // Car클래스의 객체인 car1 인스턴스 생성
Car car2 = new Car(); // Car클래스의 객체인 car2 인스턴스 생성

객체 배열
객체는 참조형 변수와 동일하게 취급되기 때문에 배열 또는 컬렉션에도 저장하여 관리할 수 있다.

public class Main {
    public static void main(String[] args) {
        Car[] carArray = new Car[3];
        //Instance 1
        Car car1 = new Car();
        car1.changeGear('P');
        carArray[0] = car1; 
        //Instance 2
        Car car2 = new Car();
        car2.changeGear('N');
        carArray[1] = car2;
        //Instance 3
         Car car3 = new Car();
        car3.changeGear('D');
        carArray[2] = car3;
        for (Car car : carArray) {
            System.out.println("car.gear = " + car.gear);
        }
    }
}
// 출력
//car.gear = P
//car.gear = N
//car.gear = D

📌 객체의 속성 : 필드

필드
객체의 데이터를 저장하는 역할
고유 데이터 (변하지 않는), 상태 데이터 (바뀌는), 객체 데이터(하위 객체)로 분류

필드의 초기값과 초기화
정의하여 선언한 클래스의 필드들은 기본적으로 초기값을 제공하지 않을 경우 객체가 생성될 때 자동으로 기본값으로 초기화된다.

  • 초기값을 제공하는 방법은 필드타입 필드명 = 값;

필드 사용방법
객체를 생성한 후에 필드를 사용할 수 있다.

  • 외부 접근 : 객체를 생성했다면 우리는 참조변수 car를 이용하여 외부에서 객체 내부의 필드에 접근하여 사용할 수 있습니다. 이때 객체의 내부 필드에 접근하는 방법은 도트(.) 연산자를 사용하면 됩니다.
    Car car = new Car();
    car.color = "blue";
  • 내부 접근 : 객체 내부 메서드에서도 내부 필드에 접근할 수 있다.
double brakePedal() {
    speed = 0;
    return speed;
}

📌 객체의 행위 : 메서드

메서드는 객체의 행위를 뜻하며 객체간의 협력을 위해 사용된다.

  • 메서드의 행위를 정의하는 방법은 블록{ } 내부에 실행할 행위를 정의하면된다.

메서드 선언

리턴타입 메서드명(매개변수, ...) {
			 실행할 코드 작성
}
  • 매개변수
    - 메서드를 호출할 때 메서드로 전달하려는 값을 받기 위해 사용되는 변수
    - 가변길이의 매개변수도 선언할 수 있습니다.
void carSpeeds(double ... speeds) {
    for (double v : speeds) {
        System.out.println("v = " + v);
    }
}
//호출
carSpeeds(100, 80);
carSpeeds(110, 120, 150);

메서드 호출방법
객체를 생성한 후에 메서드를 사용할 수 있다.

  • 외부 접근 :
    1. 객체의 내부 메서드에 접근하는 방법은 도트(.) 연산자를 사용하면 된다.
    car.brakePedal();
    2. 또한 메서드가 매개변수를 가지고 있다면 반드시 호출할 때 매개변수의 순서와 타입에 맞게 매개값을 넣어줘야 한다.
    car.gasPedal(100, 'D');
  • 내부 접근 :
    객체의 내부 메서드에 접근하는 방법은 바로 호출 하면 된다.
  double gasPedal(double kmh, char type) {
 		changeGear(type);
        speed = kmh;
        return speed;
}
  • 반환값 저장
    메서드의 리턴타입을 선언하여 반환할 값이 있다면 변수를 사용하여 받아줄 수 있다.
    이때, 반드시 리턴타입과 변수의 타입이 동일하거나 자동 타입 변환될 수 있어야한다

메서드 오버로딩
함수가 하나의 기능만을 구현하는것이 아니라 하나의 메서드 이름으로 여러 기능을 구현하도록 하는 Java의 기능
한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메서드가 있더라도, 매개변수의 개수 또는 타입, 순서가 다르면 동일한 이름을 사용해서 메서드를 정의할 수 있다.

  • 메서드의 이름이 같고, 매개변수의 개수, 타입, 순서가 달라야 합니다.
  • 오버로딩은 매개변수의 차이로만 구현할 수 있습니다
public void println() {
	newLine();
}
public void println(char x) {
	if (getClass() == PrintStream.class) {
		writeln(String.valueOf(x));
	} else {
		synchronized (this) {
			print(x);
			newLine();
		}
	}
}
public void println(int x) {
	if (getClass() == PrintStream.class) {
		writeln(String.valueOf(x));
	} else {
		synchronized (this) {
			print(x);
			newLine();
		}
	}
}
...

기본형 & 참조형 매개변수

  • 기본형 : 값 자체가 복사되어 넘어가기 때문에 매개값으로 지정된 변수의 원본 값이 변경되지 않는다.
  • 참조형 : 값이 저장된 곳의 원본 주소를 알 수 있기 때문에 값을 읽어 오는 것은 물론 값을 변경하는 것도 가능하다.
public class Main {
    public static void main(String[] args) {
        Car car = new Car(); // 객체 생성
        // 기본형 매개변수
        char type = 'D';
        car.brakePedal(type);
        // 메서드 실행 완료 후 전달할 매개값으로 지정된 type 값 확인
        System.out.println("type = " + type); 
        // 기존에 선언한 값 'D' 출력, 원본 값 변경되지 않음
        // 메서드 실행 완료 후 반환된 car 인스턴스의 gear 타입 확인
        System.out.println("gear = " + car.gear); 
        // 객체 내부에서 type을 변경하여 수정했기 때문에 'P' 출력
//--------------------------------
        // 참조형 매개변수
        Tire tire = new Tire();
        tire.company = "금호"; // 금호 타이어 객체 생성
        // 차 객체의 타이어를 등록하는 메서드 호출한 후 반환값으로 차 객체의 타이어 객체 반환
        Tire carInstanceTire = car.setTire(tire);
        // 메서드 실행 완료 후 전달할 매개값으로 지정된 참조형 변수 tire의 company 값 확인
        System.out.println("tire.company = " + tire.company); // "KIA" 출력
        // 전달할 매개값으로 지정된 tire 인스턴스의 주소값이 전달되었기 때문에 
        // 호출된 메서드에 의해 값이 변경됨.
        // 메서드 실행 완료 후 반환된 car 인스턴스의 tire 객체 값이 반환되어 저장된 
        //참조형 변수 carInstanceTire의 company 값 확인
        // "KIA" 출력
        System.out.println("carInstanceTire.company = " + carInstanceTire.company); 
    }
}

📌 인스턴스 멤버와 클래스 멤버

멤버 = 필드 + 메서드

  • 인스턴스 멤버 = 인스턴스 필드 + 인스턴스 메서드
  • 클래스 멤버 = 클래스 필드 + 클래스 메서드

인스턴스 멤버
인스턴스 멤버는 객체 생성 후에 사용할 수 있고 클래스 멤버는 객체 생성 없이도 사용할 수 있다
객체의 인스턴스 필드는 각각의 인스턴스 마다 고유하게 값을 가질 수 있다.
메서드는 메서드 영역에 두고서 모든 인스턴스들이 공유해서 사용합니다.

클래스 멤버
Java의 클래스 로더에 의해 메서드 영역에 저장되고 사용된다.
메서드 영역의 클래스와 같은 위치에 고정적으로 위치하고 있는 멤버를 의미한다.
따라서 클래스 멤버는 객체의 생성 필요없이 바로 사용이 가능합니다.

  • 선언 : 필드 타입 앞에 static 키워드를 추가하여 선언한다.
  • 사용 : 클래스의 이름과 함께 도트(.) 연산자를 사용하면 된다.

지역 변수

  • 메서드 내부에 선언한 변수를 의미한다.
  • 메서드가 실행될 때마다 독립적인 값을 저장하고 관리하게된다.
  • 지역 변수는 메서드 내부에서 정의될때 생성되어 메서드가 종료될 때까지만 유지된다.

final 필드와 상수
final 필드는 초기값이 저장되면 해당값을 프로그램이 실행하는 도중에는 절대로 수정할 수 없다.
또한 final 필드는 반드시 초기값을 지정해야 한다.

  • 선언 : 필드 타입 앞에 final 키워드를 추가하여 final 필드를 선언한다.
  • 상수 : final 앞에 static 키워드를 추가하여 모든 인스턴스가 공유할 수 있는 값이 한개이며 불변인 상수를 선언할 수 있다.

📌 생성자

생성자는 객체가 생성될 때 호출되며 객체를 초기화하는 역할을 수행

생성자 선언과 호출

  • 생성자는 반환 타입이 없고 이름은 클래스의 이름과 동일합니다.
  • new 연산자에 의해 객체가 생성되면서 Car(); 즉, 생성자가 호출됩니다.
public Car() {} // 선언
Car car = new Car(); // 호출

기본 생성자
기본 생성자는 선언할 때 괄호( ) 안에 아무것도 넣지않는 생성자를 의미한다.

  • 모든 클래스는 반드시 생성자가 하나 이상 존재
  • 만약 클래스에 생성자를 하나도 선언하지 않았다면 컴파일러는 해당 클래스의 접근 제어자를 따르는 기본 생성자를 바이트코드 파일에 자동으로 추가한다. 따라서 이러한 경우는 기본 생성자 생략이 가능
  • 반대로, 단 하나라도 생성자가 선언되어있다면 컴파일러는 기본 생성자를 추가하지 않는다.

필드 초기화와 생성자 오버로딩

  • 필드 초기화 : 객체를 만들때 인스턴스마다 다른 값을 가져야 한다면 생성자를 통해서 필드를 초기화 (초기 값을 대입) 할 수 있다.
    생성자를 통해 필드 값을 초기화 하고 기본 생성자를 작성하지 않았는데 기본 생성자를 호출하면 에러
public Car(String modelName, String colorName, double priceValue) {
    model = modelName;
    color = colorName;
    price = priceValue;
}
...
Car car = new Car(); // 오류 발생
  • 생성자 오버로딩 : 생성자를 통해 필드를 초기화 할 때 오버로딩을 적용할 수 있다.
    오버로딩을 할 때 개수, 타입, 순서가 동일한데 매개변수명만 다르게 하는 경우는 오버로딩 규칙에 위배되기 때문에 오류가 발생

📌 this 와 this()

this
객체 즉, 인스턴스 자신을 표현하는 키워드
객체 내부 생성자 및 메서드에서 객체 내부 멤버에 접근하기 위해 사용된다.
this 키워드를 통해 변수명에 해당하는 객체의 필드에 접근하여 받아온 매개변수의 매개값을 객체의 필드에 대입하여 저장할 수 있다.

public Car(String model, String color, double price) {
    this.model = model;
    this.color = color;
    this.price = price;
}

this()
객체 즉, 인스턴스 자신의 생성자를 호출하는 키워드
객체 내부 생성자 및 메서드에서 해당 객체의 생성자를 호출하기 위해 사용된다.
생성자를 통해 객체의 필드를 초기화할 때 중복되는 코드를 줄여준다.
this() 키워드를 사용해서 다른 생성자를 호출할 때는 반드시 해당 생성자의 첫 줄에 작성되어야 한다.

public Car(String model) {
    this(model, "Blue", 50000000);
}
public Car(String model, String color) {
    this(model, color, 100000000);
}
public Car(String model, String color, double price) {
    this.model = model;
    this.color = color;
    this.price = price;
}

📌 접근 제어자

제어자는 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미를 부여한다.

  • 접근 제어자 : public, protected, default, private
  • 그 외 제어자 : static, final, abstract

하나의 대상에 여러 개의 제어자를 조합해서 사용할 수 있으나, 접근 제어자는 단 하나만 사용할 수 있다.

접근 제어자
멤버 또는 클래스에 사용, 외부에서 접근하지 못하도록 제한

  • 클래스, 멤버변수, 메서드, 생성자에 사용되고, 지정되어 있지 않다면 default
    • public : 접근 제한 X.
    • protected : 같은 패키지 내에서, 다른 패키지의 자손클래스에서 접근이 가능
    • default : 같은 패키지 내에서만 접근이 가능
    • private : 같은 클래스 내에서만 접근이 가능
  • 사용가능한 접근 제어자
    • 클래스 : public, default
    • 메서드 & 멤버변수 : public, protected, default, private
    • 지역변수 : 없음
  • 접근 제어자를 이용한 캡슐화 (은닉성)
    • 접근제어자는 클래스 내부에 선언된 데이터를 보호하기 위해서 사용
    • 유효한 값을 유지하도록, 함부로 변경하지 못하도록 접근을 제한하는 것이 필요하다.
  • 생성자의 접근 제어자
    • 생성자에 접근 제어자를 사용함으로 인스턴스의 생성을 제한할 수 있다.
    • 일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 일치

Getter 와 Setter
객체의 private 필드를 읽어오거나 저장하고 싶을 때 사용

  • Getter : 외부에서 객체의 private 한 필드를 읽을 필요가 있을 때 Getter 메서드를 사용
  • Setter : 객체의 private 한 필드를 저장/수정할 때 Setter 메서드를 사용
//Getter
public String getModel() {
    return model;
}
public String getColor() {
    return color;
}
public double getPrice() {
    return price;
}
//Setter
public void setModel(String model) {
    this.model = model;
}
public void setColor(String color) {
    this.color = color;
}
public void setPrice(double price) {
    this.price = price;
}

제어자의 조합

  • 사용가능한 제어자
    • 클래스 : public, default, final, abstract
    • 메서드 : public, protected, default, private, final, abstract, static
    • 멤버변수 : public, protected, default, private, final, static
    • 지역변수 : final
  • 제어자 사용시 주의 사항
    • 메서드에 staticabstract를 함께 사용할 수 없다.
    • 클래스에 abstractfinal을 동시에 사용할 수 없다.
    • abstract메서드의 접근 제어자가 private일 수 없다.
    • 메서드에 privatefinal을 같이 사용할 필요는 없다.

📌 package와 import 이해하기

패키지란?
클래스의 일부분이면서 클래스를 식별해 주는 용도

  • 패키지는 상위 패키지와 하위 패키지를 도트(.)로 구분합니다.
  • package 상위패키지.하위패키지; 이렇게 선언한다.
package oop.main;
public class Main {
    public static void main(String[] args) {
    	//패키지
        oop.pk1.Car car = new oop.pk1.Car();
        car.horn(); // pk1 빵빵
        oop.pk2.Car car2 = new oop.pk2.Car();
        car2.horn(); // pk2 빵빵
    }
}

import란?
다른 패키지에 있는 클래스를 사용하기 위해 명시하는 키워드
패키지를 import로 명시
서로 다른 패키지에 있는 같은 이름의 클래스를 동시에 사용하려면 해당 클래스에 패키지 명을 전부 명시해야 한다.

package oop.main;
//import 
import oop.pk1.Car;
public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.horn(); // pk1 빵빵
        oop.pk2.Car car2 = new oop.pk2.Car();
        car2.horn(); // pk2 빵빵
    }
}

📓 오늘 느낀 점 한줄 요약

"객체와 클래스!" ✔

20230405 TIL

profile
매일 매일 성장하자

0개의 댓글