본문 바로가기
WEB/Back-end

객체(상속, 다형성) (Java)

by 최새벽 2024. 5. 22.

객체(Object)

  • 다른 것과 식별 가능한 것
  • 속성과 동작(기능)으로 구성 → 속성:필드, 동작:메소드
  • OOP: Object Oriented Programming, 객체 지향 프로그래밍
    • Java는 객체지향 프로그래밍 언어
    • 호출(실행, call), 리턴(return)을 통해서 객체 사이 상호작용, 다른 객체의 기능 이용
    • 상속(Inheritance): 부모와 자식 관계, 필드와 메소드를 물려받음.
    • 캡슐화: 데이터, 동작을 하나로 묶어서 실제 구성 내용을 외부에 감추는 것. (필드, 메소드 -> 클래스) 자바 특징, 파이썬이나 JS는 잘 안 됨.
    • 다형성: 다양한 자료형을 가질 수 있는 성질,?

클래스와 인스턴스(Class, Instance)

  • 클래스와 연관 있게 호칭할 때 인스턴스
  • ex. A클래스의 인스턴스 A1객체
  • 클래스로부터 객체를 만드는 것을 인스턴스화라고 함

생성자(Constructor)

  • 객체를 생성해주며 객체의 초기화 담당
    • 클래스의 기본 생성자는 직접 정의한 생성자가 없을 때 컴파일러가 자동으로 생성시킴.
    • 기본 생성자: 매개변수 존재x
    • 클래스가 public이면 기본 생성자도 public이 붙지만 없으면 기본 생성자에도 안붙는다.
    • .java파일에는 없지만 .class로 컴파일 되면 생김(직접 확인할 수는 없다)
  • 리턴이 없어야 하며, 이름은 클래스명과 동일해야 함.

필드(field)

  • 변수와 달리 선언 위치 상관 없이 활용할 수 있음.
  • 자동으로 초기화가 됨(기본 타입은 0, 참조 타입은 null으로)
    • 지역 변수는 초기값을 제공하지 않으면 사용할 수 없음.

메서드(method)

  • 기능, 동작
//선언부, 맨윗줄 
// 리턴타입 메서드명 ([매개변수])`
double divide(int x, int y){  
return (double) x / y;  
}
-  함수(function): 단독으로 실행
-  메서드(method): 객체를 통해서 실행. 클래스 안에 만들어야 함.

매개변수의 길이가 가변 길이인 메서드


int sum(int... n) { // 그냥 배열로 처리하는게 더 일반적 int sum(int\[\] n)  
int sum = 0;  
for(int i = 0; i < n.length; i++) {  
sum += n\[i\];  
}  
return sum;  
}

this

자기 자신 객체. 클래스 내부에서 해당 클래스의 생성자 호출로도 사용할 수 있음

인스턴스(instance) - 정적(static)

  • // 이게 저장되는 공간이 다른 거던가?
  • 인스턴스 멤버: 객체에 소속된 멤버. 객체를 생성해서 접근해야 한다
  • 정적 멤버: static 표기해야 함. 객체를 생성할 필요없이 클래스 명으로 접근하여 필드를 활용할 수 있음
  • static 메서드에서 사용할 필드는 static이어야 함.
  • static 필드는 해당 클래스의 모든 객체에서 공유
    • static 변수 타 객체로 접근해서 수정하면 해당 객체 뿐만아니라 해당 클래스 변수 다 변경됨. 즉 해당 클래스의 모든 인스턴스에서 수정사항이 적용됨
  • static블록
    • MemberMain 클래스
      package ch06.sec07;
      public class MemberMain {  
      static {  
      System.out.println("MemberMain static 블록"); // static 블록이 메인 메서드보다 더 빠르다  
      }
      public static void main(String[] args) {
      System.out.println("메인 메서드");
      // 인스턴스 멤버(필드, 메서드) 사용하기 위해서 객체 생성
      Member m = new Member();
      m.name = "홍길동";
      m.print();
      // static 멤버는 객체 없이 클래스로 접근해서 사용이 가능하다
      System.out.println(Member.school);
      Member.print2();
      m2.school = "서울고등학교";
      System.out.println(m.school);
      System.out.println();
      }
      }
    • Member 클래스
package ch06.sec07;
public class Member {

Member() {
    System.out.println("생성자");
}

// static 블록 (메모리에 로드될 때 초기 한번)
static {
    System.out.println("static 블록");
}

// 인스턴스 블록 (초기화)
{
    System.out.println("instance 블록");
}

// 인스턴스 필드
String name;

// static 필드: 객체 생성 전 클래스가 메모리에 로드될 때 생성됨
static String school = "신한고등학교";

// 인스턴스 메서드
void print() {
    System.out.println(this.name + "님 안녕하세요."); // this는 인스턴스화 되었을 경우를 고려함
}

static void print2() {
    System.out.println("안녕하세요");
    // 인스턴스가 아니라서 내부에 this 사용 X
}
}

final

  • final: 마지막, 최종. 필드 선언 시 사용하면 초기화 이후 수정 불가
  • 필드, 메서드, 클래스에서 사용 가능
  • 상수 선언: static final 타입 상수명, 상수명은 대문자 표기

패키지

  • 경로를 통해 빨리 찾을 수 있음(식별)
  • 다른 클래스에서 사용하기 위해서 패키지 사용
  • 패키지 없는 클래스 사용 불가(단, 외부에서 실행은 가능)
  • import 없이 사용 가능한 클래스
    • 같은 페이지에 있는 경우
    • String, Math와 같이 java.lang 패키지에 있는 경우

접근 제한자

  • 범위(기준): 클래스, 패키지
  • public: 제한 범위 없음
  • private: 객체 내부에서만 활용 가능(ex. 클래스 내부 메서드에서 실행)
  • default: 같은 패키지에 있으면 사용 가능. 따로 정의 안해줘도 됨
  • protected: 같은 패키지 혹은 자식 객체에서 사용(다른 패키지에 있어도 상속받는 자식 객체라면 사용 가능)
  • // 파일 내에 public 하나는 있어야 접근 가능함.<<? 두 개 이상은 X

##Getter, Setter

  • VO: Value Object, 값 객체
  • DTO: Data Transfer Object, 데이터 전송 객체
    값을 저장하기 위해 위의 객체 활용
  • VO, DTO에 있는 필드는 private(~보안, 기능 설정 등의 이유)
  • 접근 및 정의에 getter, setter 사용
    • setter: 데이터 검증 후 유효 값만 데이터 필드에 저장
    • getter: 데이터가 출력하기 적절하지 않을 경우 적절한 타입으로 변환 후 리턴
  • getter/setter 메서드 자동 생성 단축키:
    alt + shift + sralt + ar

싱글톤(Singletone)

  • 하나의 객체만 생성해 놓고 사용
  • 메모리 사용을 줄임 + 속도
  • 생성자 private: 외부에서 생성자 호출이 불가능함.
  • 기능 위주의 클래스는 싱글톤 사용
  • 값을 저장하는 객체에는 사용 금지: 객체가 하나이므로 여러 값 저장 불가
  • public class Singletone{ private static Singletone singletone = new Singletone(); private Singletone(){ } public static Singletone getInstance(){ // 해당 메서드 호출해서 싱글톤 객체 얻을 수 있음 if (singletone == null) { Singletone singletone = new Singletone(); } return singletone; } }

상속

  • 자식이 부모로부터 필드 및 메서드를 물려받음
  • 물려받은 필드와 메서드는 .java파일에는 없으나 컴파일 이후의 .class파일에는 존재함
  • 상속의 장점: 재사용, 중복 코드 감소, 클래스 수정 최소화(부모 클래스 수정하면 자식 클래스에도 적용), 다형성
  • 다중 상속 불가능. extends뒤에 하나의 부모 클래스만 상속 가능
  • super: 부모 클래스 생성자 호출하는 키워드
  • java.lang.Object: 모든 클래스의 상위 클래스
  • 자식 클래스의 생성자에는 부모클래스의 생성자super();가 생략되어 있음
  • final 클래스는 상속 불가능. final 메서드도 오버라이딩이 불가능함.
  • 부모 클래스
  • public class Phone { Phone(){ System.out.println("부모 클래스 생성자"); } }
  • 자식 클래스
  • public class SmartPhone extends Phone { SmartPhone(){ // super(); super(<매개변수>); // 부모 클래스에 매개 변수가 있을 경우 반드시 매개변수를 포함하여 적어줘야함. 아니면 오류 System.out.println("자식 클래스 생성자"); } }
  • 실행 클래스
  • public class Main { public static void main(String\[\] args) { SmartPhone sp = new SmartPhone(); } }
  • 출력
  • 부모 클래스 생성자 자식 클래스 생성자

메서드 오버라이딩(method overriding)

  • 상속된 메서드를 자식 클래스에서 다시 재정의하는 것 → 부모 클래스의 메서드는 숨겨지고 자식 클래스의 메서드가 우선 시 사용됨
  • @Override어노테이션(annotation) 사용
    • 컴파일시에 오버라이딩이 제대로 되었는지 확인해 줌. 생략은 가능하나 사용 권장
  • 오버로딩(overloading)과 달리 매개변수가 다 동일해야 함.

자동 형변환(Casting)

  • 자식 타입은 부모 타입으로 자동 형변환이 가능하다.
  • long a = 1;이 가능한 것과 비슷한 원리임.
  • 부모클래스: Animal자식클래스:Cat이 있을 경우 Animal animal = new Cat();이 가능하다.
  • 단, 위의 예시에서 Cat에만 정의된 메서드는 animal에서 사용할 수 없다. animal은 Animal 타입이기 때문. (∵ 부모 타입에는 존재하지 않는 메서드)
  • 그러나 Cat에서 오버라이딩 된 메서드는 animal에서도 재정의한 형태로 사용된다.
  • 자동 형변환 예시
  • Phone 클래스
  • public class Phone { void test() { System.out.println("test"); } void work() { System.out.println("work"); } }
  • SmartPhone 클래스
  • public class SmartPhone extends Phone { @Override void test() { System.out.println("테스트"); } void study() { System.out.println("공부"); } }
  • Main 클래스(main 메서드 有)
  • public class Main { public static void main(String\[\] args) { SmartPhone sp = new SmartPhone(); sp.test(); sp.work(); sp.study(); System.out.println(); Phone p = sp; p.test(); p.work(); // p.study(); Phone 클래스에 존재하지 않는 메서드 이므로 오류 발생 } }
  • 출력
  • 테스트 work 공부 테스트 work

자동 형변환 사용 이유

  • 한 번에 다른 타입의 클래스를 상위 클래스로 묶을 수 있음.
  • 하나의 코드로 각 객체에 적합한 결과를 낼 수 있음 → ==다형성
    Phone\[\] phone = {smartPhone, watch};  
    for (Phone ph : phone){  
    ph.test()  
    }

강제 형변환

// Phone: SmartPhone의 부모 클래스, SmartPhone: Phone의 자식 클래스  
Phone p = new Phone();  
SmartPhone sp2 = (SmartPhone)p;  
sp2.study(); // → 형변환을 했기 때문에 실행 가능
  • 아래 코드는 error 발생함. (실행하면 에러. 메세지 정확하게 안나옴)
  • Phone p2 = new Phone(1); SmartPhone sp3 = (SmartPhone)p2; // 에러 발생 Object sp4 = new SmartPhone(); SmartPhone sp5 = (SmartPhone)sp4; // 가능 Object obj = new Object(); SmartPhone sp6 = (SmartPhone)obj; // 위와 동일하게 에러 발생
  • 강제 형변환 조건
    • 자식 타입의 객체가 부모 타입으로 형변환이 된 상태여야 가능
    • SmartPhone이 Phone으로부터 형변환이 된 상태라면 가능
    • 원래 부모 객체였다면 형변환 불가능함

toString 오버라이딩

@Override  
public String toString(){  
return "toString Overried 메서드";  
}
Object sp4 = new SmartPhone();  
System.out.println(sp4.toString());  
System.out.println(sp4); // 객체를 출력해도 toString이 자동으로 호출됨

다형성

  • 동일한 사용 방법에 대해 다른 결과가 나올 수 있는 성질
  • 모든 클래스는 Object를 상속받기 때문에 Object 배열에는 모든 클래스를 다 담을 수 있음.
  • Object[] obj = {sp, 1, "문장", p, smartWatch1 ....}; ← 모두 Object 타입으로 형변환이 일어나고 있음.

필드 다형성

  • 변수와 동일
    Phone phone;  
    void test() {  
    phone = new SmartPhone();  
    }

매개변수의 다형성

Phone phone;  
void test() {  
phone = new SmartPhone();  
test(phone);  
test(new Phone(1));  
test(new SmartWatch());  
}  
void test(Phone p){  
// 자동 형변환이 일어남.  
// SmartPhone, SmartWatch이 Phone을 상속받으므로 가능  
}