객체 지향

Java/이론 정리 / / 2021. 1. 19. 18:20

절차 지향 프로그래밍:일련의 동작을 순서에 맞추어 단계적으로 실행하도록 명령어를 나열
객체 지향 프로그래밍: 현실 세계의 개념을 객체 단위로 프로그래밍을 함

객체

소프트웨어 객체: 현실 세계의 객체를 필드와 메서드로 모델링 한 것
필드(변수): 소프트웨어 객체의 상태

메서드(함수): 소프트웨어의 동작


객체 지향 언어의 특징

  • 기존의 프로그래밍과 크게 다르지 않음
  • 코드의 재사용성이 높다.
    • 새로운 코드를 작성할 때 기존의 코드를 이용해서 쉽게 작성한다.
  • 코드의 관리가 쉽다.
    • 코드간의 관계가 있다.
  • 신뢰성이 높은 프로그램의 개발을 가능케 한다.
    • 제어자와 메서드를 통해 데이터를 보호한다.
    • 코드의 중복을 제거하여 코드의 불일치를 방지

클래스와 객체

public 클래스는 한 프로그램에 단 하나만 존재한다.

그 클래스의 이름은 소스 파일 이름과 동일해야한다.

클래스: 객체를 정의 해 놓은 것
객체: 실제로 존재하는 것
클래스를 선언을 해두고 자체만으로 사용이 불가하다.
객체를 만들어서 이를 통해 클래스의 메서드를 사용이 가능하다.

  • 특징
    • 캡슐화(정보 은닉)
      • 관련된 필드와 메서드를 하나로 묶어 관리하고 세부 내용을 외부에서 알 수 없도록 감춘다.
      • 외부에서는 메서드를 통하여 접근을 한다.
    • 상속: 상위 객체를 상속받은 하위 객체가 상위 객체의 메서드와 필드를 사용하는 것
      • 개발된 객체를 재사용하는 방법 중 하나이다.

상속

  • 관계
    • has-a관계(소유 관계)
        class Engine{}
        class Car{
            Engine engine;
        }
      • Car라는 class는 engine이라는 객체를 가지고 있다.
    • is-a 관계(상속 관계)
        class Person{}
        class Student extends parent{}
      • 학생은 사람이다.
      • 학생이라는 클래스는 사람이라는 클래스이다를 표현하였다.
      • extends라는 키워드를 통해 상속한다.
        • java에서는 다중 상속을 지원하지 않는다.
  • 상속 정리
    • 기존의 클래스를 재사용해서 새로운 클래스를 작성하는 것
    • 두 클래스의 관계를 맺어주는 것
    • 자손은 조상의 모든 멤버를 상속받는다.
      • 생성자와 초기화블럭은 제외
    • 자손의 멤버개수는 조상보다 같거나 많다.
    • 모든 클래스는 반드시 상속을 한다.
      • 기본적으로 상속이 안되어있는 클래스는 없다.
      • 최상위 클래스는 Object class이다.
      • Object class: 자바에서 가장 기본이 되는 class
  • 다향성: 대임되는 객체에 따라 메서드를 다르게 동작하도록 하는 기술
      class Animal{
          void move(){}
      }
      class Eagles extends Animal{
          void move{
              fly();
          }
      }
      class Dogs extends Animal{
          void move{
              run();
          }
      }
      class Fishes extends Animal{
          void move{
              swim();
          }
      }
    • 같은 move에 대해 다른 동작들이 구현되었다.
  • 추상화
    • 일종의 모델링 기법
    • 현실 세계의 객체에서 불필요한 속성을 제거하고 중요한 정보만 클래스로 표현한다.
      class Person{
        hands();
        legs();
        heads();
        etc..
      }

JVM 메모리 구조

JVM: 자바 가상 머신

  • 메서드 영역 (코드 내용)
    • 클래스 정보와 클래스 변수가 저장되는 곳
  • 호출 스택 (함수들의 동작)
    • 메서드의 작업 공간
    • 메서드가 호출되면 메서드 수행에 필요한 메모리 공간을 할당
    • 메서드가 종료되면 사용하던 메모리를 반환
  • 힙 영역 (동적 메모리)
    • 인스턴스가 생성되는 공간
    • new 연산자에 의해서 생성되는 배열과 객체는 모두 여기에서 생성

생성자

  • 특징

    • 객체 생성 시점 호출
    • 일반적으로 공개, 아닐 수도 있음
    • 오버로딩이 가능하다.
    • 기본 생성자
    • 생성자 호출은 가장 위에 있어야 한다.
  • this와 this(): 자기 자신의 주소

      class Circle{
      private double radius;
      private String color;
          public Circle(double radius, String color){
              this.radius = radius;
              this.color = color;
          }
          public Circle(double radius){
              this(radius, "파랑");
          }
          public Circle(String color){
              this(10.0, color);
          }
          public Circle(){
              this(10.0, "빨강");
          }
      }
  • 연속 호출

      Person person = new Person();
      person.setName("민국");
      person.setAge(21);
      person.setHello();
    
      person.setName("민국").setAge(21).sayHello();
    • 만일 각각의 메서드 반환형식이 this이면, 마지막 한줄로 간단하게 쓸 수 있다.

정적 멤버

정적 변수는 클래스 로더가 클래스를 메서드 영역에 적재할 때 생성

  • 정적 메서드 유의사항

    • 객체와 관련된 인스턴스 변수를 사용할 수 없다.

    • 객체와 관련된 인스턴스 메서드를 호출할 수 없다.

    • 객체 자신을 가리키는 this 키워드를 사용할 수 없다.

      class A{
        int instanceField = 1; // 인스턴스 필드
        static int staticField = 1; // 정적 필드
      
        public void instanceMethod(){ // 인스턴스 메소드
            this.instanceField = 1; // this 사용 가능
            instanceField = 1; // 인스턴스 필드 사용 가능
            staticField = 1; // 정적 필드 사용 가능
        }
      
        public static void staticMethod(){ // 정적 메소드
        //    this.instanceField = 5; this 사용 불가(컴파일 에러)
        //    instanceField = 1; // 인스턴스 필드 사용 불가(컴파일 에러)
        //  instanceMethod(); // 인스턴스 메서드 사용 불가 (컴파일 에러)   
            staticField = 1; // 정적 필드 사용 가능
        }
      }
  • 사용방법

    • 클래스명.정적변수이름
    • 클래스명.정적메서드이름
  • 정적 멤버는 전체 클래스가 공유하는 멤버이다.

    메서드 오버라이딩

    메서드 오버라이딩: 물려받은 메서드를 자식에게 맞도록 수정하는 것
    <-> 오버로딩: 매개변수가 다른 경우를 생각해서 구현한 것

  • 규칙

    • 부모 클래스의 메서드와 동일한 이름 동일한 반환 타입이어야 한다.
    • 부모 클래스의 메서드보다 접근범위를 더 좁게 수정할 수 없다.
      • public -> priave으로 불가하다.
    • 추가적인 예외가 발생할 수 있음을 나타낼 수 없다.
    • 오버라이드된 함수 위에 @override를 표시해준다.
      • 오버라이드가 되었음을 알려줌 / 필수는 아니다.
    • 불가 항목
      • private 메서드: 부모 전용이므로 자식에게 상속 안됨
      • 정적 메서드
      • final 메서드: 더이상 수정 불가
  • 오버라이드된 메서드

    • 부모 클래스의 메서드 접근
    • 자식 클래스가 메서드를 오버라이딩하면 자식 객체는 부모의 메서드를 숨김
    • 메서드를 호출하려면 super 키워드를 사용한다.
      • super: 현재 객체에서 부모 클래스의 참조를 의미

        메서드 오버라이딩 VS 메서드 오버로딩

  • 메서드 오버라이딩

    • 메서드 이름: same
    • 매개 변수: same
    • 반환 타입: same
    • 상속 관계: need
    • 예외와 접근 범위: have a limit
    • 바인딩: 실행 중 결정하는 동적 바인딩
  • 메서드 오버로딩

    • 메서드 이름: same
    • 매개 변수: differ
    • 반환 타입: no-matter
    • 상속 관계: don't need
    • 예외와 접근 범위: no limit
    • 바인딩: 컴파일 할 때 결정하는 정적 바인딩

패키지

파일 시스템의 폴더를 이용하며 클래스 파일을 묶어서 관리하기 위한 수단

  • 장점
    • 패키지마다 별도의 namespace가 생기기 때문에 클래스 이름의 유일성 보장
    • 클래스 패키지 단위로도 제어할 수 있기 때문에 세밀하게 점근 제어가 가능
  • 대표적 패키지
    • java.lang: 자동으로 import, 자바 기본 클래스를 모아 둔 것
    • java.awt , java.io
  • 패키지의 선언
    • 주석문을 제외하고 반드시 첫 라인에 위치
    • 패키지 명은 모두 소문자
      • 패키지 이름이 중복되지 않도록
      • 회사의 도메인 이름을 역순으로 사용
        • com.naver.www
    • 명령어: javac -d ./inha/test.java
      • javac: 컴파일 명령어
      • -d: 패키지 폴더 생성 옵션
      • ./inha/test.java: 현재 폴더의 inha폴더에 test.java 파일을 컴파일
  • 패키지 사용
    • 다른 패키지에 있는 공개된 클래스를 사용하려면 패키지 경로를 컴파일러에게 알려주어야한다.
    • 직접 사용
      • com.usa.people.Lincoln man = new com.usa.people.Lincoln();
    • import 사용
      • import 패키지명.클래스;
        • 패키지 안에 있는 클래스를 사용하겠다.
      • import 패키지명.*;
        • 패키지 안에 있는 모든 클래스를 사용하겠다.
      • import 사용은 package문과 처음 class 사이에 위치

        자식 클래스와 부모생성자

        자식을 생성하면 부모 생성자를 자동 호출 (c++과 동일)
        자식 생성자에서 인위적*으로 부모 생성자를 *호출 할 경우 첫 행에 호출해야 한다.
  • 주의할 점
      class Animal{
          public Animal(int n){
              System.out.Print(n);
          }
      }
      class Mammal extends Animal{
          public Mammal(){
              System.out.Print("포유류");
          }
      }
      class Birds extends Animal{
          public Birds(){
              super(10);
              System.out.Print("포유류");
          }
      }
    • 부모 클래스의 생성자에선 매개변수가 있다.
    • 자식 클래스 Mammal은 부모 생성자를 임의로 생성하지 않았다.
      • 컴파일러가 부모의 디폴트 생성자를 호출한다.
      • 하지만 부모의 생성자는 매개변수가 있어야 하므로 컴파일 에러를 발생한다.
    • 자식 클래스 Birds처럼 super로 부모 생성자를 임의로 호출해야 한다.
  • super == std::

상속과 접근 제어

private > default > protected > public
동일 class > 동일 패키지 > 자식 클래스 > 모든 클래스
뒤로 갈 수록 앞에 있는 것까지 다 사용이 가능하다.

  • 접근 지정자 주의사항
    • private 멤버는 자식 클래스에 상속 안됨
    • 클래스 멤버는 모두 사용이 가능하나, 클래스는 protected와 private 사용 불가
    • 메서드 오버라이딩 할 때 부모클래스의 메서드보다 접근 범위를 좁게 할 수 없다.

타입 변환과 다향성

객체의 타입 변환(c++에서 참조자 할당과 동일)

  • 부모 <- 자식

    public class Person{
      String name = "사람";
    
      void whami(){
          System.out.println("나는 사람이다.");
      }
    }
    public class Student extends Person{
      int num = 7;
    
      void work(){
          System.out.println("나는 공부한다.");
      }
    }
    public static void main(String[] args){
      Student s = new Stduent();
      Person p = s; //자동으로 타입 변환을 한다.
      //p = (Person)s와 동일
    
      //아래 두 명령은 실행할 수 없다. 아래 설명 참고 A part
      //p.number = 1;
      //p.work();
    

}

p = s를 통해 p = (Person)s로 되었다.    
p는 s의 메모리를 가지게 되는데 위 A part 에서는 p객체가 Student 클래스의 멤버에 점근을 하려한다.    
하지만 p 객체는 결국 Person 클래스의 객체이므로 Student의 멤버들은 사용이 불가하다.
* 자식 <- 부모
```java
//B part
Person p = new Person();
Student S = (Student) p;

//C part
Student s1 = new Student();
Person p = s1;
Student s2 = (Student) p;

B part에서는 부모의 메모리 영역을 자식 객체에 할당해 주는데 이는 오류를 발생시킨다. 기존에 있는 메모리 영역을 강제로 확장시켜야 하므로 에러를 발생시킨다.


C part에서는 자식 객체를 부모객체에 할당하고 다시 부모 객체를 자식 객체에 할당을 하는데 이는 가능하다. 애초에 자식 객체 크기의 메모리를 할당해 주었기 때문에 메모리를 강제로 확장시킬 필요가 없기 때문이다.

타입 변환된 객체의 구별

객체를 참조하는 변수 instanceof 클래스 이름 혹은 인터페이스 이름
위 명령은 타입 변환이 가능한지 bool형식으로 반환해 준다.

타입 변환을 이용한 다형성

```java
class Animal{
    String name = "동물";
    void move(){}
    static void hello(){}
}
class Dogs extends Animal{
    String name = "개";
    void move{
        run();
    }
    static void hello(){}
}
public class Source{
    public static void main(String[] args){
        Animal v = new Dogs();
        System.out.print(v.name);
        v.move();
        v.hello();
    }
}
```

여기서 v.name은 Animal로 호출되었으므로 Animal의 name을 호출한다.

하지만 v.move는 자식 클래스 메모리를 참조했기 때문에 오버라이딩이 되었다. 따라서, Dogs의 move메서드를 호출한다.

v.hello는 정적 메서드이므로 오버라이딩이 안된다. 즉, Animal의 hello를 호출한다.


추상 클래스

c++이랑 같음
추상 메서드: 메서드 본체를 완성하지 못한 메서드
선언은 가능하나 정의는 할 수 없음
추상 클래스: 보통 하나 이상의 추상 메서드를 포함하지만 없을 수도 있음
주로 상속 계층에서 자식 멤버의 이름을 통일하기위 사용

  • 추상클래스는 인스턴스를생성하지 못한다.

  • 추상 클래스 선언

    • abstract class 클래스명{

      }

  • 추상 메서드 선언

    • abstract Type 메서드 이름();
    • 정의가 없다.
    • 상속을 받고 오버라이딩이 필수

Interface

  • interface 장점

    • 다양한 형태로 새로운 클래스를 개발 가능
    • 클래스는 다중 상속을 지원하지 않음. 하지만, 인터페이스는 다중 상속이 가능함
  • 특징

    • 정의된 메서드는 포함이 불가하다.
    • 인스턴스 변수도 포함 불가
    • 디폴트 메서드는 선언이 가능
      • 단 Interface에서는 default라고 명시해주어야 함
    • 생성자와 main() 당연히 선언이 불가능하다
    • interface의 부모는 interface밖에 되지 않는다.
    • 자신의 모든 멤버를 공개한다.
  • 상속

      interface Child_interface extends Parent_interface{
          //extends 예약어
      }
      class Child_class implements Parent_interface{
          //implements 예약어
      }
    • interface는 다중상속이 가능하므로 다음과 같이 사용할 수 있다.
      interface Child_interface extends Parent_interface1, Parent_interface2{
        //extends 예약어
      }
      class Child_class extends Parent_class implements Parent_interface1, Parent_interface2{
        //implements 예약어
      }
  • interface의 다향성

    • interface도 하나의 타입이므로 변수를 인터페이스 타입으로 선언가능하다

      • 인터페이스타입 변수 = 구현 객체
      • 구현 객체는 이 인터페이스의 자식이므로 자동 형변환이 이루어진다.
      • 이렇게 선언된 변수는 해당 객체의 사용이 가능하다.
    • interface 구현

      public interface Controllable {
        default void repair() {
            System.out.println  ("장비를 수리한다.");
        }
        static void reset() {
            System.out.println  ("장비를 초기화한다.");
        }
      
        void turnOn();
        void turnOff();
      }
      • class 상속

        public class Tv implements Controllable {
        
        @Override
        public void turnOn() {
          // TODO Auto-generated  method stub
          System.out.println  ("TV를 켠다.");
        }
        
        @Override
        public void turnOff() {
          // TODO Auto-generated  method stub
          System.out.println  ("TV를 끈다.");
        }
        

      }
      public class Computer implements Controllable {

      @Override
      public void turnOn() {

        // TODO Auto-generated  method stub
        System.out.println  ("컴퓨터를 켠다.");

      }

      @Override
      public void turnOff() {

        // TODO Auto-generated  method stub
        System.out.println  ("컴퓨터를 끈다.");

      }

      }

      ```

    • 실제 사용

      public class Source4 {
      
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Controllable[] controllable = {new Tv(),new Computer()};
      
            for(Controllable c : controllable) {
                c.turnOn();
                c.turnOff();
                c.repair();
            }
            Controllable.reset();
      
        }
      
      }

'Java > 이론 정리' 카테고리의 다른 글

예외처리와 제네릭  (0) 2021.01.19
배열  (0) 2021.01.19
Java 기본 문법  (0) 2021.01.19
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기