추상클래스 개념

추상(abstract) : " 여러 가지 사물이나 개념에서 공통되는 특성이나 속성 따위를 추출하여 파악하는 작용."

 

추상 클래스 : 클래스 선언 시 앞에 abstract,

  • 추상클래스 = 필드 + 일반 메서드 + 추상 메서드
  • 메서드 선언 시 본문을 구현하지 않으면 abstract로 선언(abstract 선언 메서드는 본문X)
  • 추상 메서드를 포함하는 클래스는 선언부에 abstract 명시(추상메서드를 하나라도 포함하면 추상클래스)
  • 실체 클래스(객체를 직접 생성할 수 있는 클래스)들의 공통되는 필드와 메서드 정의한 클래스(부모 클래스 역할 : 단독 객체 X) 
  • 기능이 무엇인지만을 정의하고 어떻게 구현되는지는 정의 하지 않는다.(메소드가 미완성이므로 추상클래스로는 객체(인스턴스)를 생성할 수 없다.)
  • 그래서 하나의 추상클래스에 정의된 기능을 여러 개의 하위클래스에서 서로 다른 형태로 구현하여 사용할 수 있다.(반드시 재정의 해 주어야 한다.)
  • 설계와 구현을 분리한다.(슈퍼 클래스에서는 개념 정의, 각 서브 클래스에서 구체적 행위 구현)
  • 계층적 상속 관계를 갖는 클래스 구조를 만들 때

[접근제어자 abstract class 클래스이름{

        접근제어자 abstract 반환형 추상메서드명();

}]

용도

  • 실체클래스의 공통된 필드와 메소드의 이름 동일할 목적
  • 실체 클래스를 작성할 때 시간 절약(추가적인 필드와 메소드만 선언)
  • 실체 클래스 설계 규격을 만들고자 할 때(필드와 메소드를 추상 클래스에 미리 정의, 추상클래스를 무조건 상속 받아 작성)

추상메소드(몸체가 없어 항상 세미콜론으로 종료)와 오버라이딩 

  • 메소드 이름은 동일하지만, 실행내용이 실체 클래스마다 다른 메소드.
  • 선언되어 있으나 구현되어 있지 않은 메소드 서브클래스에서 오버라이딩하여 구현해야함.
  • 추상클래스에는 메소드의 선언부만 작성(추상메서드)
  • 실체 클래스에서 메서드의 실행 내용 작성(오버라이딩)

추상클래스 종류

  1. 추상 메서드를 하나라도 가진 클래스 클래스 앞에 abstract
  2. 추상 메서드가 하나도 없지만 abstract로 선언된 클래스

다형성 : 동일한 부모 클래스에서 상속된 서브 클래스의 객체들을 하나의 타입으로 취급할 수 있게 해준다. 따라서 서로 다른 타입들을 받아서 하나의 코드로 처리할 수 있다. 상속관계에서는 부모 타입의 변수에 모든 자식 객체를 대입해 이용할 수 있다. 하나의 타입에 여러 객체를 대입할 수 있다는 의미.(다양한 실행 결과를 얻는 것) 다형성은 코드 구조가 향상되고 가독성을 증가시키며, 가능한 프로그램을 작성하는 객체지향의 중요한 개념 중의 하나. 메소드의 매개변수로 사용(유지보수 용이)

 

구현기술 : 상속 또는 인터페이스의 자동 타입 변환, 오버라이딩

 

#업캐스팅 

[슈퍼클래스참조변수 = new 서브클래스생성자(); ]

  • 상위클래스로 형변환
  • 컴파일러에 의해 자동으로 형변환된다.
  • 업캐스팅이 된 이후 상위 클래스형의 참조변수는 상위 클래스로부터 상속받은 멤버만 호출할 수 있다.
  • 업캐스팅이 되더라도 하위 클래스에서 재정의된 메서드는 참조할 수 있고. 상위 클래스로부터 상속받은 메서드는 은닉된다.

#다운캐스팅(강제타입변환) : 부모타입을 자식 타입으로 변환하는 것, 서브 클래스 참조 변수로 슈퍼 클래스 객체를 참조하는 것으로 본다면 컴파일 오류가 발생. //자식 타입을 부모 타입으로 자동 변환 후, 다시 자식 타입으로 변환할 때

[자식클래스참조변수 = (자식클래스)부모클래스타입; ]

  • 하위클래스 = 상위클래스
  • 하위 클래스로 형변환
  • 컴파일러에 의해 자동으로 형변환 X
  • 참조 가능한 영역이 확대되는 의리를 갖는다.

 

package practice;
class A{
	int a = 10;
	
	void b() {
		System.out.println("A");
	}
}

class AA extends A{
	int a = 20;
	@Override
	void b() {
		System.out.println("AA");
		
	}
	
	void c () {
		System.out.println("C");
	}
}

class BB extends A{
	int a = 30;
	
	@Override
	void b() {
		System.out.println("BB");
	}
	
	void d() {
		System.out.println("D");
	}
}

public class ClassTest {
	public static void main(String args[]) {
		A z = new AA(); //AA객체를 생성해서 A 타입의 레퍼런스에 할당한다. 업캐스팅(자식클래스를 부모클래스로)
		System.out.println(z.a); //슈퍼 클래스의 필드 접근
		z.b();//슈퍼 클래스의 메소드 접근. 단 서브클래스에서 메서드 오버라이딩되면 오버라이딩 메서드가 우선접근.
		//z.c(); A에는 c 메소드가 없음.
		
		((AA)z).c();//서브클래스의 메서드 접근
		System.out.println(((AA)z).a);//서브클래스의 필드 접근
		
		AA a1 = (AA)z;
		System.out.println(a1.a);//서브클래스의 필드 접근
		a1.c();
		
		z= new BB(); //업캐스팅. 슈퍼클래스참조변수= new 서브클래스의 생성자()
		System.out.println(z.a);
		z.b();
		((BB)z).d();
		System.out.println(((BB)z).a);
		
		BB b1 = (BB)z; //다운 캐스팅
		b1.d();
		System.out.println(b1.a);
		
	}

}

 

package practice;

class Shape{
	public void draw() {
		System.out.println("Shape");
	}
}

class Line extends Shape{
	@Override
	public void draw() {
		System.out.println("Line");
	}
}

public class MethodOverridingExample {
	public static void paint(Shape p) {
		p.draw();
	}
	
	public static void main(String args[]) {
		Line line = new Line();
		paint(line);//Line.draw
		
		paint(new Shape());
		paint(new Line());
		
	}

}

객체의 타입을 알아내는 방법 : 객체가 특정 클래스로부터 생성된(상속된) 객체인지를 판별하기 위해 사용할 수 있는 연산자가 instanceof. 반환값. true, false

[참조변수 instanceof 클래스명]

 


#인터페이스: 여러 프로그램네서 사용할 멤버(필드, 메서드)를 일관되게 하기 위한 기술 명세, 표준규격을 나타냄 인터페이스 변경시키려면 이 인터페이스를 구현하였던 모든 클래스가 동작하지 않게 된다. 이런 경우를 대비하여서 인터페이스도 상속을 받아서 확장시킬 수 있도록 한다.

[public interface 인터페이스명{

    ( public static final) 자료형 변수명 = 값 ;  //인터페이스에 선언된 필드는 모두 상수이기 때문에 생략가능

      (public abstract) 반환형 메서드명1();   //추상메서드만 정의할 수 있기에 생략가능

      public abstract 반환형 메서드명2();

}

접근제어자 interface 인터페이스명{

     (접근제어자 제어자 ) 자료형 변수명 = 값 ;  //인터페이스에 선언된 필드는 모두 상수이기 때문에 생략가능

      (접근제어자 제어자) 반환형 메서드명1();   //추상메서드만 정의할 수 있기에 생략가능

      public abstract 반환형 메서드명2();

}

]

  • 추상메소드와 상수(객체를 생성할 수 없는 인터페이스에서 필드를 선언한다는 것은 객체 생성과 관계없이 사용할 수 있는 static으로 선언 데이터 저장하지 않음)로 이루어짐. 상수명은 대문자로 작성.선언과 동시에 초기값 지정
  • 메서드를 미리 선언(어떻게 입력 받고 어떤 결과값을 반환할 것이라는 사용법)
  • 구현은 비워 놓은 추상 메서드로 만든다. 메서드의 헤더를 선언.
  • 인터페이스에는 필드(멤버변수) 선언불가

#구현 클래스 선언 : 메서드의 선언부가 정확히 일치 해야한다.

[public class 클래스명 implements 인터페이스명{

         반환형 추상메서드1(){//재정의

         }

         반환형 추상메서드2(){//재정의

         }

}] 

#디폴트 메소드 선언 : 인터페이스를 구현하는 클래스에 자동 상속되는 메소드, default 키워드를 반드시 붙여야한다. 기본적으로 public 접근제한

[public default 리턴타입 메서드명(매개변수,...){...}]

#정적 메서드 선언 : 인스턴스 생성과 상관없이 바로 사용할 수 있다. 인타페이스를 구현하고 있는 모든 객체에서 자주 사용하는 유용한 기능을 제공하는데 있다.

[public static 리턴타입 메서드명(매개변수, ...){...}]

#private 메소드 선언 : 외부접근 제한, default 메서드에서만 사용할 목적으로 본문을 구현

[private 리턴타입 메서드명(매개변수,...){...}]

  일반 클래스 추상 클래스 인터페이스
매서드의 재정의 선택적 강제적 강제적
상속, 구현시 예약어 extends extends implements
필드 선언 가능 여부 가능 가능 불가능
상수 선언 가능 여부 가능 가능 가능
생성자 선언 여부 가능 가능 불가능
추상 메서드 포함 여부 불포함 포함 포함
객체 생성 가능 여부 가능 불가능 불가능
다중 상속 가능 여부 불가능 불가능 가능

내부클래스: 클래스 멤버로 선언된 클래스<클래스 생성 시 바이트 코드 따로 생성>

멤버 클래스 인스턴스 멤버 클래스 class outer{
      class inner{...}                  
}
outer객체를 생성해야만 사용할 수 있는 inner 내부 클래스
멤버 클래스 정적 멤버 클래스 class outer{
  static class inner{...}
}
outer 클래스로 바로 접근할 수 있는 inner 내부 클래스
멤버 클래스 바이트코드 파일의 이름 외부 클래스명$내부클래스.class  
로컬 클래스 class outer{
  void method(){
     class inner{...}
   }
}
method()가 실행할 때만 사용할 수 있는 inner 중첩 클래스
로컬 클래스 바이트코드 파일의 이름 외부 클래스명$1내부클래스.class
  • 클래스가 여러 클래스와 관계를 맺는 경우에는 독립적으로 선언하는 것이 좋으나, 특정(하나의) 클래스와 관계를 맺을 경우에는 관계 클래스를 클래스 내부에 선언하는 것이 좋다.
  • 내부 클래스를 사용하면 두 클래스의 멤버들을 서로 쉽게 접근할 수 있다.
  • 외부에는 불필요한 관계 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있다.(하나의 장소에서만 사용되는 클래스들을 한 곳에 모을 수 있다.)

#인스턴스 멤버 클래스(non-static 내부 클래스) : 내부 클래스의 멤버들은 static이 될수 없다.

[접근제어자 class 외부클래스명{

     [public | private: 외부 클래스 내부에서 접근가능] class 내부클래스명{

      }

}]

#정적 멤버 클래스(static 내부 클래스): 내부 클래스는 외부 클래스의 일반멤버 변수는 참조할 수 없다. 정적멤버 클래스는 주로 default or public 접근 제한을 가짐

[접근제어자 class 외부클래스명{

      [public | private: 외부 클래스 내부에서 접근가능] static class 내부클래스명{

      }

 }]

지역 내부 클래스(로컬클래스): 외부 클래스의 메서드에서 사용하기 위해 메서드 내에 선언하는 내부 클래스

  • 생성자 또는 메소드 내부에 선언된 클래스를 늬미하며 생성자와 메소드가 실행될 동안에만 객체를  생성할 수 있다.
  • 보통 메소드 내부에 선언하여 사용하며, 메소드의 실행이 끝나는 순간 메소드의 모든 멤버가 사라진다.
  • 로컬 클래스 내부에는 필드, 생성자, 메서드 선언이 올 수 있으며 정적 필드와 정적 메서드는 JDK17부터 선언이 가능하다.

내부 인터페이스: 클래스 멤버로 선언된 인터페이스

#무명(익명) 클래스 : 클래스 몸체는 정의되지만 이름이 없는 클래스, 정의부와 생성부가 하나로 묶여 있는 클래스로 선언과 동시에 객체가 생성된다. 한번만 사용하며 재참조가 불가능, 하나의 객체만을 생성하는 일회용 클래스 

[new 상위클래스(일반클래스,추상클래스, 인터페이스 모두가능)명(생성자 매개변수){  }]

#명시적인 구현 클래스 작성 생략하고 바로 구현 객체를 얻는 방법(이름 없는 구현 클래스 선언과 동시에 객체 샹성)

[인터페이스 참조형 = new 인텨페이스(){

인터페이스에 선언된 추상 메서드의 실체 메서드 선언

}]

+ Recent posts