프로그래밍/Java 정리

Java 10일차 - 추상,내부 클래스

윤도ri 2021. 11. 30. 00:32

>접근 권한 제어자

:다른 패키지 혹은 다른 클래스에서 해당 필드에 접근할 수 있는 권한을 제어해주는, 설정해주는 키워드들 

-종류 


      (default) :다른 패키지에서 접근 불가

        when? 확실하게 같은 패키지에서만 이용할 때, 귀찮을 때 
      public :모든 곳에서 접근 가능

        when? 모든곳에서 자유롭게 접근이 가능해야하는 필드들
                (데이터를 처리하고 기능을 담당하는 메소드들)
      private :다른 클래스, 다른 패키지에서 접근 불가 

        when? 데이터를 담는 변수들 (게시글 제목,회원 아이디,...)
      protected :다른 패키지에서 접근 불가/  단 자식은 자신의 필드처럼 접근 가능

        when? 상속이 목적(자식 클래스들이 오버라이딩 해서 써야하는 메소드)

 

 **private 필드는 직접 접근할 방법이 하나도 없기 때문에 무조건 public 메소드를 통해서 간접적으로 접근하다.

     (값을 사용하는 경우: getter / 수정하는 경우: setter)

 

사용할때 obj.getData3(), obj.setData3(300); 이런식으로 호출하기 (obj는 객체이름)

 

 

------------------------------------------------------------------------------------------------------------------

>추상 클래스(불완전한 클래스)

:추상적인 내용만 정의하고 있는 클래스로, 구체적인 내용은 존재하지 않는 클래스 이며 상속받은 하위 클래스에서 그 내용들을 구현하도록 설계된 클래스이다.

:추상 클래스(부모)는 클래스들(자식)의 공통 요소들을 추상적으로 가상화 시켜놓기 때문에 객체화시 자식에서 재정의를 통한 구현을 하고 그 자식타입으로 객체화를 진행해서 사용한다. 부모 추상 클래스의 역할은 단지 자식 클래스를 만들 때 틀로 존재해서 도와주는 역할을 수행한다. 그렇기 때문에 자식 클래스에서 재정의 해야되는 메소드의 이름과 형태만
가지고 있다. 즉 메소드에 {}(바디)가 없다. 이러한 메소드를 추상 메소드라고 하며, abstract 라는 키워드가 리턴타입 앞에 붙는다.추상 메소드가 하나라도 포함되어 있다면 그 클래스는 추상 클래스로 만들어야 한다.

 

* 추상메소드를 만드는 이유 

:자식들이 움직임 행동을 하기 때문에 추상 클래스쪽을 간결하게 사용해서 구조를 간결하게 만들기 위함이다.

 

ex)포유류중에 원숭이랑 코끼리만 울릴것이다.

1. 일단 포유류는 동물이다 그러므로 class를 하나만들어서 공통적인 속성을 넣어둔다. 

   int age; 

   String name;

2. 생각해보니 원숭이랑 코끼리가 울긴 우는데 우는 방법이 다르겠지? 그럼 생각해보면 메소드의 이름은 같으나 내용이 다르다는것을 알수있다. 그러므로 추상적인 클래스로 만들어주고 자식클래스에서 재정의를 해주면 될것이다.

  abstract void makeCry ();     <--- 바디가 없으며 추상적으로 존재(틀로 존재)

3. 그다음 원숭이랑 코끼리 클래스를 만들어서 거기서 재정의를 해주자. 

  Monkey extends Animal 

  void makeCry(){

  System.out.println(name+"(이)가 또르르륵 우는중..")

 };

 

 

>추상 메소드 선언

         abstract class 추상클래스명{
               abstract 리턴타입 추상메소드명();    }

:추상 메소드는 자식 클래스에서 강제적으로 반드시 재정의 해야한다. 일반 메소드도 추상 클래스 내부에 존재할 수 있다.

예제 1. 산이랑(삼각형) 모니터(사각형) 으로 객체화하여 각각 넓이를 구하여라

1.일단 산과 모니터 모두 변의갯수 넓이,폭 길이 다 같으므로 변수로 묶는다. 2.생성자 만들어준다 3. 재정의되어야하는 넓이구하는 메소드는 abstract로 만들어준다 4. 재정의 되고싶지않은 메소드는 final메소드를 써준다!!
5.재정의 하기위해서 shape을 상속시킨다 6.생성자 가지고 온다 7. 메소드 오버라이딩 시킨후 내용적어주고 그 값을 리턴시킨다
위와 똑같이 재정의 해준다(이때는 삼각형이므로 2로 나눠주기만 하면 끗!

 

board가 메인 클래스라고 보면 된다. 여기서 출력을 하게 된다. 8.마지막으로 try,square클래스타입으로&amp;nbsp; 산과 모니터를 객체화시켜준다 9. 그후 각각의 메소드를 불러와서 출력해주면 끗!&amp;nbsp; 여기서 init은 final메소드로서 재정의가 안되었기 때문에 mt든 monitor든 다 같게 출력이 된다.

위 예제를 보면 추상클래스를 사용하는 방법과 추상클래스가 어떤의미를 갖고 있는지 알게될 수 있다.

 

 

>인터페이스

1.추상 클래스를 고도화시킨 문법이며, 반드시 추상메소드와 상수만 선언해야 한다.다른 클래스에서 인터페이스를 지정받을 때에는 implements 라는 키워드를 사용한다.  지정받은 클래스는 인터페이스가 가지고 있는 추상 메소드를 반드시 재정의 해야한다. 

 

예제2. ferrari roma라는 차의 시동을 켜라  (implements , interface, abstract를 사용한다)

1.부모 클래스인 카에 변수인 가격,색깔을 넣어준다.
3.페라리를 interface 로 만들어준다 4. 브랜드가 페라리 하나이므로 상수로 선언한다 5.시동키고 끄는 방법이 페라리 시리즈별로 다를수있기때문에 추상 메소드로 선언을 시켜둔다(abstract 붙이기)
2.페라리 로마는 차이자 페라리이다 그러나 다중상속이 불가능하므로 interface가 필요하다. 5.인터페이스로 페라리를 만들었으므로 구현하기 위해서 implements 를 써준다 6.메소드를 오버라이딩 시켜준다. (이때 brand는 상수이므로 this.brand로 써줄 필요가 없다&amp;nbsp; &amp;nbsp;
로드는 메인이므로 여기서 출력을 해준다 7.페라리 로마의 클래스 타입으로 mycar를 객체화 시킨다 8. 원하는 객체에 값을 넣어주거나 메소드를 호출할 수 있다.

예제3. 마커 인터페이스 

1.1)movie 의 변수를 정한다 2)기본생성자랑 이름을 받을수있는 생성자를 만든다 3) 기본메소드를 만들어준다.
5. 마블영화만 보고싶을때 마블이라는 이름으로 인터페이스를 지정하고 이터널즈, 베놈를 마블로 묶어준다(implements)&amp;nbsp;

 

6.각각 영화들을 객체화해주는데 계속 반복되므로 배열로 만들어준다7. 영화중에 마블인경우에만 상영하도록 if문과 instanceof 를 써준다
2.자식클래스 dune 을 상속시킨다 (기본생성자, 이름담는 생성자)

 

3.자식클래스 Eternals 을 상속시킨다 (기본생성자, 이름담는 생성자)
4.자식클래스 venom 을 상속시킨다 (기본생성자, 이름담는 생성자)

2.jdk 8버전 이후로부터는 인터페이스에 default 메소드를 선언할 수 있다. 따라서 사실상의 다중상속을 지원하게 된다.
인터페이스 끼리나 다른 클래스와의 메소드 모호성이 발생한다면(같은 이름의 메소드끼리 충돌이 발생한다면)

상속받은 클래스에서 명시적으로 작성(오버라이딩)해 주어 모호성을 해결해 주어야 한다. 내부에서는 
                       인터페이스명.super.메소드()
로 지정받은 인터페이스에 있는 메소드를 호출할 수 있고 이는 다중 상속을 받을 수 있다는 것을 의미한다.

원래는 추상메소드만 올수있는데 dafault 키워드를 통해 일반 메소드를 부모메소드처럼 선언할 수 있다 (다중 상속이 가능하다는 의미)
위 예제와 마찬가지이다

 

C는 메인 클래스이다.
D는 C의 자식클래스이며 A와 B라는 인터페이스를 구현한다라는 의미 . 근데 보니까 메소드 이름이 f()으로 다 같다. 그러므로 인터페이스의 메소드를 호출할때는 인터페이스명.super.메소드명(); 으로 호출해야한다.

--> 인터페이스는 추상메소드(부모)이므로 자식 클래스에서 무조건 재정의 해주어야 한다. 그래서 자식클래스의 메소드에서 인터페이스의 메소드를 호출한 것이다.

 

>내부 클래스(inner class)

:클래스 내부에 클래스를 선언하며 외부클래스의 필드에 용이하게 접근하기 위해서 사용한다.내부 클래스의 필드를 사용하기 위해서는 먼저 외부 클래스의 객체를 만들고 그 객체를 통해 내부 클래스까지 접근해서 객체화를 해야한다.
외부 클래스의 필드에서는 자신이랑 같이 올라와 있는 내부 클래스를 바로 객체화 할 수 있다. 보통은 어떤 메소드의 호출 결과로 내부 객체를 부여받아서 사용하는 방식으로 설계된다.  

      외부 클래스명 객체명 = new 외부클래스생성자(); <---1.외부클래스의 객체를 만든다(객체화하기전엔 내부클래스 
      외부클래스명.내부클래스명 객체명 = 외부클래스명.new 내부클래스생성자();            존재하지 않는다)

          ↑2.내부클래스 생성자로 외부클래스 안에 있는 내부클래스를 객체화 시킨다.

>내부클래스를 사용하는 이유

1. 상속처럼 이용
  외부 클래스의 필드를 마치 내것처럼 접근하여 사용하기 위함
2. 캡슐화 
  외부클래스의 객체가 없다면 내부 클래스도 존재할 수 없기 때문에  다른 클래스에서 접근하지 못하도록 내부 클래스를 숨기기 위함

 

IF가정 :B클래스의 b() 메소드가 자주 쓰이고 이 작업은 A클래스의 데이터가 필요하다.  만약 다른 곳에서는 b()메소드가 전혀 안쓰이거나 , B클래스를 외부에 노출시키고 싶지  않거나, B 클래스의 객체가 있기 전에 필수적으로 A클래스의 객체가 있어야 한다면  설계를 내부 클래스 형태로 만들어서 사용한다.

In 클래스를 import했기때문에 Out.In 을 쓰지않아도&amp;nbsp; In in = out. new In();

 

외부 클래스의 필드에서는 자신이랑 같이 올라와 있는 내부 클래스를 바로&amp;nbsp; 객체화 할 수 있다(같은 위치에 있기때문에)