Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 인플레이션
- XLF
- 오버라이딩
- FCF
- 미국주식
- 다형성
- 제태크
- 무디스
- etf
- mco
- StringBuffer
- javascript
- object
- 잉여현금흐름
- 자바
- 알고리즘
- 금리인하
- 객체지향
- Java
- 그리디 알고리즘
- 프로그래머스
- 금리인상
- 주린이
- 현금흐름표
- S&P500
- 접근제어자
- 백준
- 기업분석
- 배당성장
- 주식
Archives
- Today
- Total
오늘의하루
[JAVA] 객체지향 추상클래스 인터페이스 내부클래스 본문
반응형
1. 추상 클래스(abstract class)
- 아직 사용할 수 없는 미완성된 클래스
- 인스턴스 생성 불가능하다.
- 추상 메서드를 포함하고 있는 클래스
- 선언 부만 작성된 메서드
- 꼭 필요하지만 자식마다 다르게 구현될 것으로 예상되는 경우에 사용
- 정상적인 메서드는 추상 메서드를 호출할 수 있다.
- 호출할 때 필요한 건 선언 부이기 때문이다.
- 다른 클래스가 상속을 통해 추상 메서드를 완성해서 사용할 수 있게 도움을 주는 목적으로 작성한다.
- 사용 목적은 여러 클래스에 공통적으로 사용될 수 있는 부분을 뽑아서 추상 클래스로 만든다.
abstract class player{ // 추상 클래스
int x;
player(){ // 추상 클래스도 생성자는 있어야 한다.
x = 0;
}
abstract void play(int a); // 추상메서드
abstract void stop(); // 추상메서드
void play(){
play(this.x); // 일반 메서드가 추상 메서드 사용
}
}
// 추상클래스를 상속받은 클래스는 추상 메서드를 완성해서 사용할 수 있다.
class Audio extends player {
void play(int a){
// 구현부 완성!
}
void stop(){
// 구현부 완성!
}
}
// Error! 추상메서드를 상속받고 사용할때는 모든 추상메서드를 완성해야한다.
// 모든 추상메서드를 완성하지 않으면 그 class도 추상메서드가 된다.
abstract class Error extends player{
void play(int a){
// 구현부 완성
}
}
1-1. 추상 클래스를 사용하는 실전 예제
// ⭐추상 클래스 사용 전
class Marine{
int x, y;
void move(int x, int y){}
void stop(){}
void stimpack(){}
}
class Tank{
int x, y;
void move(int x, int y){}
void stop(){}
void changeMode(){}
}
class Dropship{
int x, y;
void move(int x, int y){}
void stop(){}
void load(){}
void unload(){}
}
// ⭐추상 클래스 사용
abstract class Unit{
int x, y;
abstract void move(int x, int y);
void stop(){}
}
class Marine extends Unit{
void move(int x, int y){}
void stimpack(){}
}
class Tacnk extends Unit{
void move(int x, int y){}
void changeMode(){}
}
class Dropship extends Unit{
void move(int x, int y){}
void load(){}
void unload(){}
}
2. 인터페이스(interface) - 껍데기
- 추상 메서드와 상수만을 멤버로 가질 수 있다.
- 추상 클래스보다 추상화 정도가 높다.
- 인스턴스를 생성할 수 없고 클래스 작성에 도움을 줄 목적으로 사용된다.
interface Interface_name{
public static final int x = 1; // 상수
public abstract String method(); // 추상 메서드
}
- 인터페이스의 모든 멤버 변수는 public static final 이기 때문에 생략이 가능하다.
- 인터페이스의 모든 메서드는 public abstract 이기 때문에 생략이 가능하다.
interface Interface_name{
public static final int x = 1; // 상수
static final int y = 2;
final int z = 3;
int r = 4;
public abstract String method(); // 추상 메서드
abstract int method2();
String method3(int[] T);
}
2-1. 인터페이스의 상속
- 인터페이스도 클래스처럼 상속이 가능하며, 다중 상속도 허용된다.
- 인터페이스는 Object 클래스와 같은 최고 조상이 없다.
클래스에서는 다중 상속이 불가능한 건 메서드의 구현부가 충돌하기 때문인데 인터페이스의 경우 선언 부만 존재하기 때문에 가능하다.
interface I{
void move(int x, int y);
}
interface II{
void attack(Unit u);
}
interface III extends I, II{ }
2-2. 인터페이스 구현
- 인터페이스를 구현하기 위해서는 implements로 클래스에서 상속을 받아야 한다.
- 인터페이스에 정의된 모든 추상 메서드를 구현해야 한다.
- 모두 구현하지 않으면 추상 클래스가 된다.
- 다른 클래스의 상속과 인터페이스의 구현이 동시에 가능하다.
- 클래스 상속 먼저 그 이후 인터페이스 구현
interface Movable {
void move(int x, int y);
}
interface Attackable {
void attack(Unit u);
}
interface Fightable extends Movable, Attackable{ }
class Unit{
int hp;
int mp;
}
class Fighter extends Unit implements Fightable{
public void move(int x, int y){/* 구현부 작성 */}
public void attack(Unit u){/* 구현부 작성 */}
}
// 추상 메서드를 모두 구현못했기 때문에 추상 클래스가 된다.
abstract class Fighter2 implements Fightable{
public void move(int x, int y){/* 구현부 작성 */}
}
2-3. 인터페이스를 이용한 다형성
- 인터페이스 타입의 변수로 인터페이스를 구현한 클래스의 인스턴스를 참조할 수 있다.
- 인터페이스를 메서드의 매개변수 타입으로 지정할 수 있다.
- 인터페이스를 메서드의 리턴 타입으로 지정할 수 있다.
public static void main(String args[]) {
Fighter f = new Fighter(1,1);
Fightable ff = new Fighter(2,2);
f.attack(ff);
Fightable Test = f.method();
// System.out.println(Test.hp); Fightable 타입에서는 hp 멤버 변수가 없다.
// hp에 접근하기 위해 형변환을 시켜준다.
Fighter Test2 = null; // Fighter 타입의 참조변수 Test2에 null을 저장해 둔다.
Test2 = (Fighter) Test; // 형변환
System.out.println(Test2.hp); // 100
}
interface Movable {
void move(int x, int y);
}
interface Attackable {
void attack(Unit u);
}
interface Fightable extends Movable, Attackable{ } // 인터페이스 다중 상속
class Unit{
int hp;
int mp;
Unit(int x, int y){ // 생성자
hp = x;
mp = y;
}
}
class Fighter extends Unit implements Fightable{ // 클래스 상속과 인터페이스 구현 (동시)
public void move(int x, int y){/* 구현부 작성 */}
public void attack(Unit u){/* 구현부 작성 */}
Fighter(int x, int y){ // 생성자
super(x,y);
}
void attack(Fightable f){ // 매개변수로 인터페이스 타입으로 지정했다.
System.out.println("T class attack method");
}
Fightable method(){ // 리턴 타입을 인터페이스로 지정했다.
System.out.println("method class Fightable Type");
// Fighter 클래스는 인터페이스를 모두 구현했기때문에 다형성을 사용할 수 있다.
return new Fighter(100,100); // 생성된 객체의 주소를 반환
}
}
- 인터페이스의 장점
- 개발 시간을 단축시킬 수 있다.
- 표준화가 가능하다.
- 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
- 하나의 인터페이스를 공통적으로 구현함으로써 관계를 맺는다.
- 독립적인 프로그래밍이 가능하다.
인터페이스의 장점을 살려 중간 점검 코드를 작성하였습니다.
public static void main(String args[]) {
Tank t = new Tank(100); // 부모타입 : GroundUnit
Dropship d = new Dropship(80); // 부모타입 : AirUnit
Marine m = new Marine(40); // 부모타입 : GroundUnit
SCV s = new SCV(40); // 부모타입 : GroundUnit
System.out.println(t.getname() + "의 MAX_HP = " + t.MAX_HP + " 공격력 = " + t.hitpoint);
System.out.println(d.getname() + "의 MAX_HP = " + d.MAX_HP + " 공격력 = " + d.hitpoint);
System.out.println(m.getname() + "의 MAX_HP = " + m.MAX_HP + " 공격력 = " + m.hitpoint);
System.out.println(s.getname() + "의 MAX_HP = " + s.MAX_HP + " 공격력 = " + s.hitpoint);
s.powerful_evolution(t); // 가능
s.powerful_evolution(d); // 가능
// powerful_evolution(m); Error : Repariable 인터페이스를 구현하지 않았다.
s.powerful_evolution(s); // 가능
System.out.println("진화 후 "+t.getname() + "의 MAX_HP = " + t.MAX_HP + " 공격력 = " + t.hitpoint);
System.out.println("진화 후 "+d.getname() + "의 MAX_HP = " + d.MAX_HP + " 공격력 = " + d.hitpoint);
System.out.println("진화 후 "+s.getname() + "의 MAX_HP = " + s.MAX_HP + " 공격력 = " + s.hitpoint);
}
}
//서로 다른 클래스의 관계를 맺어주지 위한 인터페이스
interface evolution {}
class Unit{
int hitpoint;
final int MAX_HP;
Unit(int x){
MAX_HP = x;
}
}
class GroundUnit extends Unit{
GroundUnit(int x){
super(x);
}
}
class AirUnit extends Unit{
AirUnit(int x){
super(x);
}
}
class Tank extends GroundUnit implements evolution{
Tank(int x){
super(x);
hitpoint = MAX_HP/2;
}
public String getname(){
return "Tank";
}
}
class Dropship extends AirUnit implements evolution{
Dropship(int x){
super(x);
}
public String getname(){
return "Drop ship";
}
}
class Marine extends GroundUnit{
Marine(int x){
super(x);
hitpoint = MAX_HP/10;
}
public String getname(){
return "Marine";
}
}
class SCV extends GroundUnit implements evolution{
SCV(int x){
super(x);
hitpoint = MAX_HP/20;
}
void powerful_evolution(evolution r){ // 매개변수로 인터페이스 타입을 지정해줬다.
if(r instanceof Unit){ // Unit이 참조변수 r의 부모가 맞는지 확인
Unit u = (Unit)r; // Unit의 멤버를 사용할 수 있도록 형변환
while(u.hitpoint < 100){ // 100은 조건 성립이 되지 않아 while문을 빠져나오지만 hitpont는 100이 된다.
u.hitpoint++; // 공격력을 100까지 증가시켜준다.
}
}
}
public String getname(){
return "SCV";
}
}
2-4. 인터페이스의 이해
- 인터페이스는 두 객체 간의 연결을 돕는 중간 역할을 한다.
- 선언과 구현을 분리시키는 것이 가능하다.
class B{public void method(){System.out.println("methodInB");}}
// 위에 있는 클래스의 메서드를 선언부와 구현부로 나눠서 아래 처럼작성이 가능하다.
interface I{public void metdhod();}
class B implements I{public void method(){System.out.println("methodInB");}}
- 클래스를 사용하는 쪽(User)과 클래스를 제공하는 쪽(Provider)이 있다.
- 메서드를 호출하는 쪽(User)에서는 사용하려면 메서드의 선언 부만 알면 된다.
- 직접적인 관계를 인터페이스를 사용하여 간접적인 관계로 만들어 줄 수 있다.
// 예제 1번
// 직접적인 관계 ( A -> B )
// A에서 B를 직접 접근한다.
class A {
public void methodA(B b){
b.methodB();
}
}
class B {
public void methodB(){
System.out.println("methodB()");
}
}
// 간접적인 관계 ( A -> interface -> B )
// A에서 interface를 통해 B에 접근한다.
class A {
public void methodA(I i){
i.methodB();
}
}
interface I {
void methodB();
}
class B implements I {
public void methodB(){
System.out.println("methodB()");
}
}
public static void main(String args[]) {
Time t = new Time();
t.setHour(4);
t.setMinute(75);
t.setSecond(35);
System.out.println(t.getHour() + " : " + t.getMinute() + " : " + t.getSecond());
}
interface TimeIntf{
int getHour();
void setHour(int h);
int getMinute();
void setMinute(int m);
int getSecond();
void setSecond(int s);
}
class Time implements TimeIntf{
private int hour;
private int minute;
private int second;
public void setHour(int h){
if (h < 0 || h > 23){
System.out.println("You entered the wrong hour.");
return;
}
hour = h;
}
public int getHour(){
return hour;
}
public void setMinute(int m){
if (m < 0 || m > 59){
System.out.println("You entered the wrong minute.");
return;
}
minute = m;
}
public int getMinute(){
return minute;
}
public void setSecond(int s){
if (s < 0 || s > 59){
System.out.println("You entered the wrong seconds.");
return;
}
second = s;
}
public int getSecond(){
return second;
}
}
2-5. 디폴트 메서드
- JDK 1.8 이후 인터페이스에 디폴트 메서드, static 메서드를 추가할 수 있는 변경되었다.
- 디폴트 메서드는 인터페이스에 추가된 일반 메서드를 말한다.
interface a{
int a = 1; // 상수
void method(); // 추상 메서드
default void method2(){ // 디폴트 메서드
System.out.println("응애 나 디폴트메서드~");
}
}
- 디폴트 메서드가 기존의 메서드와 충돌하는 경우 아래와 같이 해결할 수 있다.
- 여러 인터페이스의 디폴트 메서드 간의 충돌
- 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버 라이딩해야 한다.
- 디폴트 메서드와 부모 클래스의 메서드 간의 충돌
- 부모 클래스의 메서드가 상속되고 디폴트 메서드는 무시된다.
- 여러 인터페이스의 디폴트 메서드 간의 충돌
3. 내부 클래스
- 클래스 안에 선언된 클래스를 말한다.
- 특정 클래스 내에서만 사용되는 클래스를 내부 클래스로 선언한다.
- 내부 클래스를 쓰는 이유
- 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있다.
- 코드의 복잡성을 줄일 수 있다.( 캡슐화 )
- 내부 클래스의 종류는 변수의 선언 위치에 따른 종류와 유효 범위가 동일하다.
- 인스턴스 내부 클래스
- 외부 클래스의 멤버 변수 선언 위치에 선언하며 외부 클래스의 인스턴스 멤버처럼 사용된다.
- 주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용된다.
- 스태틱 내부 클래스
- 외부 클래스의 멤버 변수 선언 위치에 선언하며 외부 클래스의 static 멤버처럼 사용된다.
- 특히 static 메서드에서 사용될 목적으로 선언된다.
- 지역 내부 클래스
- 외부 클래스의 메서드나 초기화 블록 안에 선언되며 선언된 블록이 유효 범위이다.
- 익명 내부 클래스
- 클래스의 선언과 객체의 생서울 동시에 하는 이름 없는 1회용 클래스이다.
- 인스턴스 내부 클래스
- 내부 클래스의 접근제어자는 변수에 사용할 수 있는 접근제어자와 동일하다.
class Outer{
class InstanceInner{}
static class StaticInner{}
private class PrivateInstanceInner{}
protected static class ProtectedStaticInner{}
void Mymethod(){
class LocalInner{} // 지역변수는 접근제어자가 불가능하다.
}
protected void Mymethod2(){
class LocalInner2{} // 지역변수는 접근제어자가 불가능하다.
}
}
반응형
'JAVA' 카테고리의 다른 글
[JAVA] Object Class 1편 equals hashCode toString clone 메서드 (0) | 2022.08.04 |
---|---|
[JAVA] 예외처리 (0) | 2022.08.03 |
[JAVA] 객체지향 2편 제어자 다형성 (0) | 2022.08.02 |
[JAVA] 객체지향 2편 (0) | 2022.08.01 |
[JAVA 공부 6일차] static, final, abstract, 접근 제어자 알아보기 (0) | 2022.07.27 |
Comments