[Java] 클래스

thingzoo·2023년 6월 14일
0

Java

목록 보기
9/20
post-thumbnail

객체지향

객체

세상에 존재하는 물체를 뜻하며 식별이 가능한 것
예) 자동차, 도서관, 계산기, 강의, 배달 주문, 운동(개념또한 포함)

  • 객체는 속성과 행위로 구성
    예) 자동차
    • 속성: 회사, 모델, 색상, 가격, 속도 등
    • 행위: 가속, 브레이크, 기어변속, 조명, 경적 등

Java 에서는 이러한 속성과 행위를 필드와 메서드로 정의하여 구현한다
이처럼 현실 세계에 있는 객체를 소프트웨어의 객체로 설계하는 것을 ‘객체 모델링’이라고 부른다

객체 간의 관계

현실세계에서의 객체는 수많은 관계를 맺고 살아간다
소프트웨의 객체도 마찬가지다
자동차 객체를 통해 살펴보자

사용관계

사람이 자동차를 사용한다

포함관계

자동차에는 타이어, 차문, 핸들 등의 부품이 필요하다

상속관계

자동차와 기차 객체는 하나의 공통된 기계 시스템 객체를 토대로 만들어진다

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

캡슐화

속성(필드)와 행위(메서드)를 하나로 묶어 객체로 만든 후 실제 내부 구현 내용은 외부에서 알 수 없게 감추는 것

  • 외부 객체에서는 노출시켜 준 필드 혹은 메서드를 통해 접근
  • 캡슐화하는 이유: 외부 객체에서 해당 필드와 메서드를 잘못 사용하여 객체가 변화하지 않도록 하기 위해서

상속

기존의 객체(부모객체)를 재사용해서 새로운 객체(자식객체)를 작성하는것

[상속하는 이유]

  • 객체 간의 구조 파악 용이
  • 부모객체만 수정해도 자식객체 전부 반영이 되어 일관성 유지에 용이
  • 자식객체가 부모객체의 필드와 메서드를 물려받아 코드의 재사용성 증가

다형성

객체가 연산을 수행할 때 하나의 행위에 대해 각 객체가 가지고 있는 고유한 특성에 따라 다른 여러가지 형태로 재구성되는 것

추상화

객체에서 공통된 부분들을 모아 상위 개념으로 새롭게 선언하는 것

객체와 클래스

  • 현실세계에서 자동차를 만들기 위해 자동차 설계도가 필요한것 처럼
  • 소프트웨어에서도 객체를 만들기위해서는 설계도에 해당하는 클래스가 필요!
  • 이때 클래스를 토대로 생성된 객체를 해당 클래스의 ‘인스턴스’라고 부르며 이 과정을 ‘인스턴스화’라고 부름

클래스 설계

1. 클래스 선언

public class Car {}

2. 필드 정의

String company; // 자동차 회사
String model; // 자동차 모델
String color; // 자동차 색상
double price; // 자동차 가격
double speed;  // 자동차 속도 , km/h
char gear; // 기어의 상태, P,R,N,D
boolean lights; // 자동차 조명의 상태

3. 생성자 정의

public Car() {}

4. 메서드 정의

double gasPedal(double kmh) {
    speed = kmh;
    return speed;
}

객체 생성과 참조형 변수

객체 생성

new Car(); // Car클래스 객체 생성
  • 객체 생성 연산자인 new뒤에 클래스()를 붙여 객체 생성

참조형 변수

Car car1 = new Car(); // Car클래스의 객체인 car1 인스턴스 생성
Car car2 = new Car(); // Car클래스의 객체인 car2 인스턴스 생성
  • new 연산자를 통해서 객체가 생성되면 해당 인스턴스의 주소가 반환되기 때문에 해당 클래스의 참조형 변수를 사용

객체 배열

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

Car[] carArray = new Car[3];

객체의 속성: 필드

필드

필드는 객체의 데이터를 저장하는 역할

  • 객체의 필드는 크게 고유한 데이터, 상태 데이터, 객체 데이터로 분류

필드의 초기값과 초기화

필드들은 초기화안하면 객체 생성시 자동으로 기본값으로 초기화됨

  • 초기화: ‘필드타입 필드명 = 값;’
    • String model = "Gv80";

[필드 타입별 기본값]

데이터타입기본갑
byte, short, int0
long0L
float0.0F
double0.0
char\u0000(공백)
booleanfalse
배열, 클래스, 인터페이스null

필드 사용방법

외부 접근

  • Car car = new Car();
    • 이렇게 객체 생성후 참조변수 car를 이용하여 필드 접근 가능
    • 이때 객체의 내부 필드에 접근하는 방법은 도트(.) 연산자를 사용
      • car.color = "blue";

내부 접근

  • 내부에서는 바로 호출해서 사용 가능
double brakePedal() {
    speed = 0;
    return speed;
}

객체의 행위: 메소드

메소드 선언

리턴타입 메서드명(매개변수, ...) {
			 실행할 코드 작성
}

리턴타입

메서드가 실행된 후 호출을 한 곳으로 값을 반환할 때 해당 값의 타입

double brakePedal() {...} // double 타입 반환
char changeGear(char type) {...} // char 타입 반환
boolean onOffLights() {...} // boolean 타입 반환
void horn() {...} // 반환할 값 없음
  • 반환할 값이 있다면 리턴타입을 선언하고
  • return문을 사용해 반환!
    - return 리턴타입의 반환값;

매개변수

메서드를 호출할 때 메서드로 전달하려는 값을 받기 위해 사용되는 변수

double gasPedal(double kmh, char type) {
    speed = kmh;
    return speed;
}
  • (double kmh, char type) 요놈들이 매개변수
  • 값을 전달하려면 gasPedal(100, 'D'); 이렇게 순서와 타입에 맞게 쓰면됨
  • 생략도 가능!
  • 가변길이의 매개변수도 가능
    - (double ... speeds)
    • 개수 상관없이 적으면됨 (10, 20, 30)

메소드 호출방법

외부 접근

  • Car car = new Car();
    • 이렇게 객체 생성후 참조변수 car를 이용하여 메소드 접근 가능
    • 이때 객체의 내부 메소드에 접근하는 방법은 도트(.) 연산자를 사용
      • car.gasPedal(100, 'D');

내부 접근

  • 내부에서는 바로 호출해서 사용 가능
double gasPedal(double kmh, char type) {
    changeGear(type);
    speed = kmh;
    return speed;
}

반환값 저장

  • 메서드의 리턴타입을 선언하여 반환할 값이 있다면 변수를 사용하여 저장 가능
    • 반드시 리턴타입과 변수의 타입이 동일하거나 자동 타입 변환될 수 있어야함!
double speed = car.gasPedal(100, 'D');

메소드 오버로딩

한 클래스 내에 동일한 이름의 메소드를 매개변수의 개수, 타입, 순서를 달리하여 여러 개 정의하는 것

조건

  • 메서드의 이름이 같고, 매개변수의 개수, 타입, 순서가 다름
  • 응답값만이나 접근 제어자만 다른 것은 오버로딩 불가
  • 결론, 오버로딩은 매개변수의 차이로만 구현 가능

장점

  1. 메서드 이름 하나로 여러 정의 가능
    • 예: println()
    • 매개변수: int, double, String, boolean 등
  2. 메서드의 이름을 절약할 수 있습니다.
    • 만약 오버로딩이 안된다면 printlnInt(), printlnDouble() 처럼 메서드명이 길어지고 낭비 되었을 것

기본형 & 참조형 매개변수

기본형 매개변수

메소드를 호출할 때 전달할 매개값으로 지정한 을 메소드의 매개변수에 복사해서 전달

참조형 매개변수

메소드를 호출할 때 전달할 매개값으로 지정한 값의 주소를 매개변수에 복사해서 전달

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

📌 맴버 = 필드 + 메소드

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

인스턴스 멤버

객체를 생성해서 사용 가능

클래스 멤버

객체를 생성없이도 사용 가능

  • static 키워드 사용해서 생성
  • 공용적인 데이터나 인스턴스 필드를 사용하지 않는 메소드인 경우

지역변수

메서드 내부에 선언한 변수

  • 메서드 내부에서 정의될때 생성되어 메서드가 종료될 때까지만 유지

final 필드와 상수

final 필드

  • final 필드는 반드시 초기값 지정해야함
  • 또한 해당값을 프로그램이 실행하는 도중에는 절대로 수정 불가
final String company = "GENESIS";
Car car = new Car();
System.out.println(car.company);

상수

  • 값이 반드시 한개이며 불변의 값
  • 따라서 인스턴스마다 상수를 저장할 필요 없음
static final String COMPANY = "GENESIS";
System.out.println(Car.COMPANY);

생성자

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

생성자 선언과 호출

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

기본 생성자

선언할 때 괄호( ) 안에 아무것도 넣지않는 생성자

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

필드 초기화와 오버로딩

필드 초기화

  • 객체를 만들때 인스턴스마다 다른 값을 가져야 한다면 생성자를 통해서 필드를 초기화하고
  • 반대로 인스턴스 마다 동일한 데이터를 가지는 필드는 초기값을 대입하자

생성자 오버로딩

생성자를 통해 필드를 초기화 할 때 오버로딩을 적용 가능

🚨 주의사항
오버로딩을 할 때 개수, 타입, 순서가 동일한데 매개변수명만 다르게 하는 경우는 오버로딩 규칙에 위배되기 때문에 오류가 발생하니 주의!

this와 this()

this

this는 객체 즉, 인스턴스 자신을 표현하는 키워드

  • 객체 내부 생성자 및 메서드에서 객체 내부 멤버에 접근하기 위해 사용
  • 매개변수명과 객체의 필드명이 동일할 경우
public Car(String model, String color, double price) {
    this.model = model;
    this.color = color;
    this.price = price;
}
  • 리턴타입이 인스턴스 자신의 클래스 타입인 경우
Car returnInstance() {
    return this;
}

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;
}

🚨 주의사항
this() 키워드를 사용해서 다른 생성자를 호출할 때는 반드시 해당 생성자의 첫 줄에 작성해야함!!
this() 키워드로 다른 생성자 호출 이전에 코드가 존재하면 오류 발생

접근제어자

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

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

접근 제어자

사용가능한 접근 제어자

  • 클래스 : public, default
  • 메서드 & 멤버변수 : public, protected, default, private
  • 지역변수 : 없음

접근 제어자를 이용한 캡슐화 (은닉성)

  • 접근제어자는 클래스 내부에 선언된 데이터를 보호하기 위해서 사용
  • 유효한 값을 유지하도록, 함부로 변경하지 못하도록 접근을 제한하는 것이 필요

생성자의 접근 제어자

  • 생성자에 접근 제어자를 사용함으로 인스턴스의 생성을 제한
  • 일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 일치

Getter와 Setter

외부에서 객체의 private 필드를 읽어오거나 저장하는 메소드

Getter

외부에서 객체의 private 한 필드를 읽을 필요가 있을 때

  • 메서드 이름 규칙 : get + 필드이름(첫 글자 대문자)
public String getModel() {
    return model;
}

Setter

외부에서 객체의 private 한 필드를 저장/수정할 필요가 있을 때

  • 메서드 이름 규칙 : set + 필드이름(첫 글자 대문자)
public void setModel(String model) {
    this.model = model;
}

제어자 조합

사용가능한 제어자

  • 클래스 : 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.pk1,oop.pk2 라는 패키지가 있다고 가정

    • 두 패키지에 모두 Car 클래스가 존재하며 사용하려고 하는 경우

      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 oop.pk1.Car;, import oop.pk2.Car;
  • import oop.pk1.*;: oop.pk1 패키지 아래에 있는 모든 클래스 사용 가능
  • 다만 서로 다른 패키지에 있는 같은 이름의 클래스를 동시에 사용하려면 해당 클래스에 패키지 명을 전부 명시해야함

Reference

🔗 스파르타코딩클럽 Java 문법 종합반
🔗 자바의 정석

profile
공부한 내용은 바로바로 기록하자!

0개의 댓글