• Java 객체 지향 프로그래밍 개념 :: 마이구미
    Java 2017. 2. 14. 21:54
    반응형

    이번 글은 원본 글을 번역하여 객체 지향 프로그래밍(OOP) 에 대한 기본 개념을 다뤄본다.


    예제들과 함께 JAVA의 OOP의 개념에 대해 이해하는 데 도움이 될 것이다.

    OOP의 특징들에 대해 알아보자.


    OOP의 작성은 클래스를 만들고, 생성된 클래스를 객체로 만들고, 이 객체를 사용하여 독립형 실행 프로그램인 응용 프로그램을 만드는 것이 포함된다.


    클래스는 객체의 데이터 필드와 메소드가 무엇인지 정의하는 template, blueprint, contract 를 의미한다.

    객체는 클래스의 인스턴스이고, 클래스는 많은 수의 인스턴스를 생성할 수 있다.


    여기서 클래스, 객체, 인스턴스를 짚고 가자.


    // Person 클래스

    class Person {

    // ......

    }


    Person p; // Person 타입의 객체

    p = new Person(); // 인스턴스화


    간단하게 보면 클래스는 틀이고, 객체는 선언, 인스턴스는 실체화라고 보면 된다.

    객체는 선언 당시, 인스턴스는 그 객체가 메모리에 할당되어 실제로 사용될 때를 인스턴스라고 본다.


    클래스는 데이터 필드와 메소드를 정의하기 위해 변수들을 사용한다.

    또한, 새로운 객체를 생성하기 위해 수반되는 특별한 형식인 생성자라 불리는 메소드를 제공한다.

    생성자는 객체의 데이터 필드의 초기화와 같은 초기화 작업들을 수행하기 위해 설계되어있다.


    클래스 객체 구조


    객체들은 속성과 메소드로 구성되어진다.

    속성이란 객체를 정의하는 특성이다.

    속성에 포함된 값을 통해 같은 클래스로 생성된 객체들과 구분된다.

    이것을 이해하기 위해서는 Mobile 객체에 대한 아래 예제를 보면 더 좋을 것이다.


    Mobile 클래스는 모델, 제조사, 비용, 운영체제 등과 같은 특성을 가진다.

    만약 우리는 'Samsung' 객체, 'IPhone' 객체를 만든다면, 특성들을 통해 구분할 수 있다.

    객체의 속성 값은 객체의 상태라고도 불린다.


    OOP의 주요 4가지 특징


    1. 캡슐화 (Encapsulation)

    2. 상속 (Inheritance)

    3. 다형성 (Polymorphism)

    4. 추상화 (Abstraction)


    이러한 특징을 자세히 살펴보자.


    캡슐화(Encapsulation)


    캡슐화는 모든 변수들과 메소드들을 클래스라고 불리는 단위에 모으는 것을 의미한다.

    또한 객체 안에 데이터와 메소드를 숨기는 것을 의미한다.

    캡슐화는 의도치 않은 변화에서 데이터와 메소드의 안전을 유지하는 보안을 제공한다.

    프로그래머들은 때때로 블랙 박스 또는 내부 메커니즘에 관계없이 사용할 수 있는 장치라고 부른다.


    프로그래머는 블랙 박스 안에 포함된 데이터와 메소드를 사용하거나 접근할 수 있다.

    하지만 변경할 수는 없다.

    아래 예제를 보면, 생성자를 통해 객체를 생성하고, 속성은 public 접근 제어자를 가진 getXXX() 메소드로 접근하는 것을 볼 수 있다.


    public class Mobile {

    private String manufacturer; private String operating_system; public String model; private int cost; // 생성자를 통해 객체의 속성/특성 저장 Mobile(String man, String o,String m, int c){ this.manufacturer = man; this.operating_system=o; this.model=m; this.cost=c; } // 객체의 모델 속성에 접근해서 가져오는 메소드 public String getModel(){ return this.model; } // 다른 메소드를 추가하여 다른 속성들을 접근하여 가져올 수 있다. }


    상속(Inheritance)


    상속은 OOP의 중요한 특징이다.

    존재하는 클래스의 속성들과 메소드들을 공유하는 클래스들을 생성할 수 있다.

    상속은 주로 코드의 재사용성에 사용된다.

    우리는 이미 작성된 클래스를 확장하여 사용하고 있기 때문이다.

    이 말은 존재하는 클래스로부터 새로운 클래스를 파생된다는 의미이다.

    이것이 상속이다.


    보다 정확한 이해를 위해 Mobile 클래스를 확장한 안드로이드와 블랙베리와 같은 특정 클래스를 활용한 예제를 보자.


    public class Android extends Mobile{ Android(String man, String o,String m, int c){ super(man, o, m, c); } //Method to get access Model property of Object public String getModel(){ return "This is Android Mobile- " + model; } } public class Blackberry extends Mobile{ Blackberry(String man, String o,String m, int c){ super(man, o, m, c); } public String getModel(){ return "This is Blackberry-"+ model; } }


    다형성(Polymorphism)


    다형성은 이해하기 쉬운 개념 중 하나이다.

    언어의 특징을 통해 정의를 하면

    문맥에 따라 다른 상황에서 같은 단어나 기호를 올바른 해석하기 위한 기능이다.


    영어를 예로 들어보겠다.

    run 이라는 단어의 의미는 다들 알고 있다.

    "달리다" 하지만 다른 단어와 함께 사용하면 의미가 달라질 수 있다.

    "a footrace", "business", "a computer" 와 같이 run은 같은 단어이지만 다른 의미로 사용된다.


    OOP는 같은 이름을 가진 메소드가 다른 상황에서는 다르게 동작한다.

    이것이 다형성이고, 2가지 방법을 제공하고 있다.


    정적 다형성(Static Polymorphism) - complie time polymorphism / Method Overloading


    동일한 이름을 가진 메소드에 대해 전달 인자를 변경함으로써, 다른 메소드 구현이 가능한 기능을 메소드 오버로딩이라고 불린다.

    아래 코드는 3가지의 인자가 다른 print 메소드가 존재한다.

    이런 경우 적절히 오버로딩만 한다면, 인자 리스트에 맞는 메소드를 호출할 수 있다.


    class Overloadsample { public void print(String s){ System.out.println("First Method with only String- "+ s); } public void print (int i){ System.out.println("Second Method with only int- "+ i); } public void print (String s, int i){ System.out.println("Third Method with both- "+ s + "--" + i); } } public class PolymDemo { public static void main(String[] args) { Overloadsample obj = new Overloadsample(); obj.print(10); obj.print("Amit"); obj.print("Hello", 100); } }


    // Second Method with only int- 10

    // First Method with only String- Amit

    // Third Method with both- Hello -- 100


    동적 다형성(Dynamic Polymorphism) - run time polymorphism / Method Overriding


    서브클래스가 존재하는 클래스를 확장함으로써 생성할 때, 새로운 서브클래스는 슈퍼클래스에서 정의된 데이터와 메소드를 포함하고 있다.

    다른 말로는 자식 클래스는 부모 클래스의 모든 속성을 물러받는다.

    하지만 때론 서브클래스는 데이터 필드와 메소드를 슈퍼클래스로부터 물려받고 싶지 않을 경우가 있다.

    이런 경우 우리는 부모클래스의 관련된 멤버함수를 오버라이딩(재정의) 해야한다.

    관련 코드를 보자.


    * 슈퍼클래스(최상위 클래스) - 부모클래스가 될 수도 있지만 같지는 않다. 조상클래스라고도 불림.

    * 오버라이딩 - 자식클래스에서 부모클래스의 멤버함수를 재정의


    public class OverridingDemo { public static void main(String[] args) { Mobile m = new Mobile("Nokia", "Win8", "Lumia",10000); System.out.println(m.getModel()); Android a = new Android(); System.out.println(a.getModel()); Blackberry b = new Blackberry("BlackB", "RIM", "Curve",20000); System.out.println(b.getModel()); } }


    추상화(Abstraction)


    모든 프로그래밍 언어에서 추상화를 제공한다.

    우리가 해결할 수 있는 문제의 복잡성은 추상화의 질과 종류에 직접적인 관계가 있다.
    OOP에서 추상화는 핵심 요소이다.

    사람들은 추상화를 통해 복잡성을 관리한다.


    정비사가 아닌 이상 차를 운전할 때 차의 내부 작동을 걱정하지 않는다.

    오로지 우리는 브레이크, 가속기, 바퀴와 같은 인터페이스를 통해 차와 상호작용에 대해 걱정한다.

    차의 다양한 제조사는 작동되는 구현이 다르지만 기본적인 인터페이스는 변하지 않는다. 

    (바퀴, 브레이크, 가속기 등과 같은 우리가 상호작용하는 것들)

    그러므로 우리가 차에 대한 지식은 추상적이다.


    추상화를 관리하는 파워풀한 방식은 계층적인 분류의 사용하는 것이다.

    이를 통해 우리는 복잡한 시스템의 의미를 계층화하여 관리하기 쉬운 부분으로 분리할 수 있다.

    겉으로는 자동차는 하나의 대상이고, 내부로는 몇몇의 서브시스템으로 구성하고 있다.

    (바퀴, 브레이크, 사운드 시스템, 안전 벨트 등등)

    차례대로, 이러한 각 서브시스템은 많은 전문화된 단위로 만들어져있다.

    예를 들면, 사운드 시스템은 라디오, CD 플레이어 등으로 구성되어있다.

    요점은 계층적 추상화를 통해 차의 복잡성을 관리할 수 있다는 것이다.


    추상 클래스는 불완전한 클래스이고, 인스턴스화 할 수 없다.

    만약 사용하고 싶다면 다른 클래스에 추상 클래스를 확장하여 구체화하여야한다.

    구체화란 추상 클래스는 선언만 하고 구현 내용이 없는 클래스이기 때문에 구현을 나타낸다.


    이해가 쉽게 예제를 통해 알아보자.


    public abstract class VehicleAbstract { public abstract void start(); public void stop(){ System.out.println("Stopping Vehicle in abstract class"); } } class TwoWheeler extends VehicleAbstract{ @Override public void start() { System.out.println("Starting Two Wheeler"); } } class FourWheeler extends VehicleAbstract{ @Override public void start() { System.out.println("Starting Four Wheeler"); } } public class VehicleTesting { public static void main(String[] args) { VehicleAbstract my2Wheeler = new TwoWheeler(); VehicleAbstract my4Wheeler = new FourWheeler(); my2Wheeler.start(); my2Wheeler.stop(); my4Wheeler.start(); my4Wheeler.stop(); } }


    // Starting Two Wheeler

    // Stopping Vehicle in abstract class

    // Starting Four Wheeler

    // Stopping Vehicle in abstract class


    이와 같이 경우에서 추상화의 이점은 볼 수 있다.

    새로운 타입의 차량이 도입된다면 차량 추상 클래스를 확장하고 관련 특정 메소드가 구현된 클래스를 추가하면 된다.

    재사용성에도 크게 도움이 되는 것을 볼 수 있다.


    추상 클래스와 인터페이스를 헷갈린다면 다음을 참고하길 바란다.

    추상 클래스 vs 인터페이스 

    반응형

    댓글 0

Designed by Tistory.