[JAVA 개념정리] 객체지향 Part2

Doyeon·2023년 1월 22일
0

JAVA 개념정리

목록 보기
11/13
post-thumbnail
post-custom-banner

상속

  • 기존의 클래스를 재사용하여 새로운 클래스 작성 → 코드 추가 및 변경 쉬워짐
  • 두 클래스를 부모 자식으로 관계 맺는다. (extends 키워드 사용)

상속의 조건

  • 자손 클래스는 조상 클래스의 모든 멤버(변수, 메서드)를 상속받는다.
    • 생성자, 초기화 블럭은 상속 제외
  • 자손 클래스의 멤버 개수 ≥ 조상 클래스의 멤버 개수
  • 조상의 변경은 자손에게 영향을 미치고, 자손의 변경은 조상에게 영향을 미치지 않는다.
// Tv - 조상 클래스
class Tv {
    boolean power;
    int channel;
}

// SmartTv - 자손 클래스
class SmartTv **extends Tv** {
    String text;
}

포함관계

  • 한 클래스의 멤버변수로 다른 클래스 타입의 참조변수 선언 → 재사용성 Good
  • 작은 단위의 클래스를 만들고, 이를 조합해서 클래스를 만든다.
class Point {
	int x;
	int y;
}

clas Circle {
	Point c = new Point();
	int r;
}

상속? 포함? 클래스 간 관계 결정하기

  • 상속관계 : ~은 ~이다.(is-a)
    • 스포츠카 다.
      class SportsCar extends Car {
      			//...
      }
  • 포함관계 : ~은 ~을 가지고 있다.(has-a)
    • 을 가지고 있다.
      class Point {
      	int x;
      	int y;
      }
      
      clas Circle {
      	Point c = new Point();
      	int r;
      }

단일 상속(single inheritance)

  • java는 단일 상속만 허용(C++은 다중 상속 가능)
  • 클래스 간 관계 명확, 코드 신뢰성 Good!
    • 다중 상속은 서로 다른 클래스로부터 상속받은 멤버 이름이 같은 경우 구별 불가 → Diamond Problem

Object클래스 - 모든 클래스의 조상

  • 모든 클래스의 최상위에 있는 조상 클래스
  • 다른 클래스로부터 상속 받지 않는 클래스는 컴파일러가 extends Object 를 자동으로 추가해준다.
  • 다른 클래스로부터 상속 받는다고(이 경우는 컴파일러가 자동 추가 안해준다) 하더라도 조상클래스의 조상클래스로 올라가다보면 결국 최상위는 Object 클래스이다.
  • 주요 메서드 : toString() , equals(Object o)

오버라이딩(overriding)

  • 조상 클래스로부터 상속받은 메서드의 내용을 변경하는 것
    • 메서드 선언부는 그대로, 메서드 내용만 변경 가능

오버라이딩의 조건

  1. 선언부가 조상 클래스의 메서드와 일치해야 한다. (리턴타입, 메서드 이름, 매개변수)
  2. 접근 제어자는 조상 클래스의 메서드보다 넓거나 같아야 한다. 좁은 범위로 변경할 수 없다.
    • public > protected > (default) > private
  3. 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다. 조상 클래스의 예외가 더 많아야 한다.
class Point {
    int x;
    int y;
    
    String getLocation() {
        return "x :" + x + ", y:" + y;
    }
}

class Point3D extends Point {
    int z;
    
    String getLocation() {
        return "x :" + x + ", y :" + y + ", z :" + z; 
    }
}

오버로딩(overloading) vs. 오버라이딩(overriding)

  • 오버로딩 : 기존에 없는 새로운 메서드를 정의(new)
  • 오버라이딩 : 상속받은 메서드의 내용을 변경(change, modify)
class Parent {
    void parentMethod() {}
}

class Child extends Parent {
    void parentMethod() {}      // 오버라이딩
    void parentMethod(int i) {} // 오버로딩
    
    void childMethod() {}
    void childMethod(int i) {}  // 오버로딩
    void childMethod() {}       // Error! 중복 정의
}

super 와 super()

super - 참조변수

  • 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는 참조변수
  • 상속받은 멤버와 자신의 멤버 이름이 같을 때 super 를 붙여 구별
  • 모든 인스턴스 메서드(생성자 포함)에는 thissuper 가 지역변수로 존재 →자신이 속한 인스턴스의 주소가 자동 저장

super() - 조상의 생성자

  • 조상의 생성자를 호출한다. → 생성자의 첫 줄에 반드시 호출
    • 첫 줄에 호출 하지 않으면, 컴파일러가 생성자 첫 줄에 super(); 자동 삽입
  • 조상 클래스에 선언된 변수는, 자손 클래스에서 사용될 경우, 조상 클래스 생성자가 초기화를 하도록 작성하는 것이 좋다.
  • 생성자는 상속되지 않는다.
class Point {
    int x, y;
    
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

class Point3D extends Point {
    int z;
    
    Point3D(int x, int y, int z) {
        super(x, y);   // Point(int x, int y) 생성자 호출
        this.z = z;
    }
}

package와 import

package

  • 서로 관련된 클래스의 묶음(하나의 폴더)
  • 클래스의 실제 이름은 패키지를 포함한다. (ex. java.lang.String)

package 선언

  • 소스파일 첫 번째 문장, 단 한번 선언
  • 같은 소스 파일의 클래스는 같은 패키지에 속한다.
  • 패키지 선언이 없으면 default 패키지에 속한다.

클래스 패스(classpath)

  • 클래스 파일(.class)의 위치를 알려준느 경로
  • classpath(환경변수)로 관리
  • 경로간의 구분자는 ; 사용
  • classpath에 패키지 루트를 등록해야 한다.

import

  • 클래스를 사용할 때 패키지 이름 생략할 수 있게 해준다.
  • 컴파일러에게 클래스가 속한 패키지를 알려준다.
  • java.lang 패키지는 중요한 클래스들이 모여있기 때문에 import를 생략할 수 있다.
    • ex) String, Object, System
  • 선언방법 : import 패키지명.클래스명;

static import문

  • import : 클래스의 패키지명 생략 가능
  • static import : static 멤버 호출 시, 클래스 이름 생략 가능
    • 특정 클래스의 static 멤버를 자주 사용할 때 편리. 코드 간결
import static java.lang.Integer.*;   // Integer 클래스의 모든 static 메서드
import static java.lang.Math.random; // Math.random()만. 괄호 안붙인다
import static java.lang.System.out;  // System.out을 out만으로 참조 가능

Class Ex7_6 {
    public static void main(String[]args){
        // System.out.prntln(Math.random());
        out.println(random());
        
        // System.out.println("Math.PI :" + Math.PI);
        out.println("Math.PI :" + PI)
    }    
}

접근 제어자

제어자(modifier)

  • 클래스와 클래스의 멤버(변수, 메서드)에 부가적 의미 부여
    • 접근 제어자 : public, protected, (default), private
    • 그 외 : static, final, abstract 등
  • 하나의 대상(클래스, 멤버변수, 메서드)에 여러 제어자 조합 가능
    • 단, 접근 제어자는 네 가지 중 하나만 선택 가능

static - 클래스의, 공통적인

  • static이 사용될 수 있는 곳 - 멤버변수, 메서드, 초기화 블럭
  • 클래스 변수(static 멤버변수)는 인스턴스 관계없이 같은 값을 가진다. → 하나의 변수가 모든 인스턴스 공유
  • static 멤버변수, 메서드 모두 인스턴스 생성 없이 사용 가능
  • 메서드 내에서 인스턴스 멤버를 사용하는가?
    • YES! - 인스턴스 메서드
    • NO! - static 메서드

final - 마지막의, 변경될 수 없는

  • final이 사용될 수 있는 곳 - 클래스, 메서드, 멤버변수, 지역변수
  • fianl 클래스 : 상속 불가. 조상이 될 수 없다. 자손을 만들 수 없다.
    • ex) String, Math
  • fianl 메서드 : 오버라이딩 불가
  • fianl 멤버/지역 변수 : 상수
    • 생성자를 이용하여 final 멤버변수 초기화 가능
      class FinalTest {
          final int x;
          final int y;
          final int z;
      
          public FinalTest(int x, int y, int z) {
              this.x = x;
              this.y = y;
              this.z = z;
          }
      }

abstract - 추상의, 미완성의

  • abstract 가 사용될 수 있는 곳 - 클래스, 메서드
  • abstract(추상) 메서드 : 선언부만 작성되어 있고 실제 수행내용은 없다.
  • abstract(추상) 클래스 : 추상 메서드를 가진 클래스
    • 추상 클래스는 인스턴스를 생성할 수 없다. → 추상 클래스를 상속받은 클래스에서 추상 메서드 내용 작성

접근 제어자(access modifier)

  • 접근 제어자 가 사용될 수 있는 곳 - 클래스, 멤버변수, 메서드, 생성자
  • private : 같은 클래스 내에서만 접근 가능
  • (default) : 같은 패키지 내에서만 접근 가능
  • protected : 같은 패키지 + 다른 패키지 자손 클래스 접근 가능
  • public : 접근 제한 없음
  • 사용 이유 → 캡슐화(encapsulation)
    • 클래스 내부에 선언된 데이터를 외부로부터 보호 ← 외부에서 함부로 변경하지 못하도록 접근을 제한
    • 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감춘다. → 복잡성 Down

접근 제어자 조합 주의!

  • 클래스 : public, (default), final, abstract
  • 메서드 : 모든 접근제어자, final, abstract, static
  • 멤버변수 : 모든 접근제어자, final, static
  • 지역변수 : final
  • 클래스 접근제어자는 public, (default) 만 가능하다!
    • 다른 class에서 접근할 수 있어야 객체지향 개념을 사용할 수 있다.
    • inner, nested 클래스에서는 private, protected를 클래스에 사용할 수는 있다.
  • 메서드에 static , abstract 동시 사용 불가
    • static 메서드는 몸통이 있는 메서드에만 사용할 수 있다.
  • 클래스에 abstract, final 동시 사용 불가
    • fianl - 클래스를 확장할 수 없다. 상속할 수 없다.
    • abstract - 상속을 통해 완성되어야 한다.
  • abstract 메서드의 접근 제어자 private 불가
    • abstract 메서드는 자손 클래스에서 구현하기 위해 접근 가능해야 한다.
  • 메서드에 private, final 동시 사용할 필요 없음
    • 둘 다 오버라이딩할 수 없기 때문에 하나만 사용해도 의미 충분

캡슐화(encapsulation)

  • 객체의 속성(data fields)과 행위(method)를 하나로 묶고, 실제 구현 내용 일부를 내부에 감추어 은닉한다.
  • 외부적으로 데이터를 보호
  • 내부적으로만 사용되는 것을 외부로 노출시키지 않고 감춘다.
  • ex) 멤버변수를 private or protected 로 제한하고, getter / setterpublic 메서드로 제공

다형성(polymorphism)

  • 여러 가지 형태를 가질 수 있는 능력
  • 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있다.
    • 같은 타입의 인스턴스여도 참조변수 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다.
  • but, 자손클래스 타입의 참조변수로 조상타입의 인스턴스를 참조할 순 없다.
class Tv {
    boolean power;
    int channel;
}

class SmartTv extends Tv {
    String text;
}

class Exercise {
    public static void main(String[] args) {
        SmartTv s = new SmartTv();  // 참조 변수와 인스턴스 타입 일치
        Tv t = new SmartTv();       // 타입 불일치. 조상 타입의 참조변수로 자손 타입 인스턴스 참조
        // s와 t의 인스턴스 타입은 SmartTv로 같지만,
        // t는 Tv클래스의 멤버들(power, channel)만 사용할 수 있다.

        SmartTv x = new Tv();       // Error! 허용 안 됨
    }
}

참조변수의 형변환

  • 사용할 수 있는 멤버의 개수 조절
  • 서로 상속관계에 있는 클래스 사이에서만 참조변수 형변환이 가능하다.
    • 자손타입 참조변수 ↔  조상타입 참조변수
  • 조상의 조상으로도 형변환 가능 → 모든 참조변수는 Object 클래스 타입으로 형변환 가능
  • 참조변수가 가리키는 인스턴스의 자손타입으로 형변환 불가 → 참조변수가 가리키는 인스턴스 타입을 먼저 확인해야한다.
class Car {
    String color;
    int door;

    void drive() {
        System.out.println("drive!");
    }

    void stop() {
        System.out.println("stop!");
    }
}

class FireEngine extends Car {
    void water() {
        System.out.println("water!");
    }
}
class Example1 {
    public static void main(String[] args) {
        Car car = null;
        FireEngine fe = new FireEngine();
        FireEngine fe2 = null;

        fe.water();
        car = fe;       // 조상타입 <- 자손타입. car = (Car)fe; 에서 형변환 생략
        car.water();    // Error!
        fe2 = (FireEngine)car; // 자손타입 <- 조상타입. 형변환(생략불가)
        fe2.water();
    }
}
  • car = ~~(Car)~~fe;
    • FireEngine 타입의 fe → 조상인 Car 타입으로 형변환
    • fe의 값을 car에 저장
    • 조상 타입으로 형변환하면 다룰 수 있는 멤버의 개수가 줄어들어 항상 안전하므로, 형변환을 생략할 수 있다.
    • fe가 가리키던 인스턴스의 타입은 FireEngine 이었다. → Car 가 조상타입이어서 형변환 가능
  • car.water();
    • car는 Car 타입의 참조변수이므로, Car 에 있는 멤버만 접근 가능하다.
    • water() 메서드는 Car 클래스에 없으므로 사용할 수 없다.
  • fe2 = (FireEngine)c;
    • Car 타입의 car → 자손인 FireEngine 타입으로 형변환
    • car의 값을 fe2에 저장
    • 자손 타입으로 형변환하면 멤버 개수가 늘어나므로 형변환을 반드시 써줘야 한다.(생략불가)
    • car가 가리키는 인스턴스의 타입은 FireEngine 이다. car = fe → Car car = new FireEngine();
  • fe2.water();
    • fe2는 FireEngine 타입의 참조변수이므로, FirEEngine 에 있는 멤버에 접근 가능하다.
    • water() 메서드는 FireEngine 클래스에 있으므로 사용할 수 있다.
class Example2 {
    public static void main(String[] args) {
        Car car = new Car();
        Car car2 = null;
        FireEngine fe = null;

        car.drive();
        fe = (FireEngine)car;   // 런타임 에러!!
        fe.drive();
    }
}
  • fe = (FireEngine)car;
    • Car 타입의 car → 자손인 FireEngine 타입으로 형변환 시도
      • but, 런타임 에러 발생!
    • car 가 가리키던 인스턴스 타입은 Car 였다. 자손타입 x = new 조상타입();(조상타입의 인스턴스를 자손타입의 참조변수로 참조)은 불가하다.(다형성)참조변수가 가리키는 인스턴스의 자손타입으로 형변환 허용 불가
    • Car car = new Car();Car car = new FireEngine(); 으로 변경한다면 OK!
  • [참고]

32) 참조변수의 형변환

[ JAVA ] 다형성 - 참조변수의 형변환

A(객체) instanceof B(클래스) 연산자

  • A 객체가 B 클래스로부터 상속을 받았는지 확인
  • 참조변수 instanceof 타입(클래스명) → true : 형변환 가능
  • 형변환 전에 반드시 instanceof로 확인해야 한다.
  • 참조변수 값이 null 이면 false
void doWork(Car c) {
    if (c instanceof FireEngine) {      // 1. 형변환이 가능한지 확인
        FireEngine fe = (FireEngine)c;  // 2. 형변환
        ...
    }
}

매개변수의 다형성

  • 매개변수가 클래스 타입의 참조변수라면, 클래스 자손 타입의 참조변수면 어느 것이나 매개변수로 받아들일 수 있다.
  • 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘길 수 있다.
  • 메서드의 구현부에서 매개변수 클래스의 인스턴스 변수를 사용할 수 있다.
class Product {
    int price;
    int bonusPoint;
}
class Tv extends Product { }
class Computer extends Product { }

class Buyer {
    int money = 1000;
    int bonusPoint = 0;

    void buy(Product p) {   // Product 클래스의 자손타입 참조변수 모두 매개변수 가능
        money -= p.price;
        bonusPoint += p.bonusPoint;
    }
}

class Example {
    public static void main(String[] args) {
        Buyer b = new Buyer();
        Tv t = new Tv();
        Computer c = new Computer();
        b.buy(t);
        b.buy(c);
    }
}

여러 종류의 객체를 배열로 다루기

  • Vector 클래스 : 동적으로 크기가 관리되는 객체 배열

추상 클래스(abstract class)

  • 미완성 메서드(추상 메서드)를 포함하고 있는 미완성된 클래스
  • 인스턴스 생성이 불가하다.
  • abstract(추상) 메서드 : 선언부만 작성되어 있고 실제 수행내용은 없다.
    • 주석을 덧붙여 어떤 기능을 수행할 목적인지 알려주고, 실제 내용은 상속받는 클래스에서 구현하도록 비워둔다.
    • 몸통 { } 블럭이 없다.
      /* 주석을 통해 어떤 기능을 수행할 목적으로 작성하였는지 설명한다. */
      abstract 리턴타입 메서드이름();
  • abstract(추상) 클래스 : 추상 메서드를 가진 클래스
    • 추상 클래스는 인스턴스를 생성할 수 없다. → 추상 클래스를 상속받은 클래스에서 추상 메서드 내용 작성
    • 상속받은 클래스는, 추상 클래스 안에 있는 모든 추상 메서드를 구현해야 한다.
    • 상속받은 추상메서드 중 하나라도 구현하지 않는다면, 자손클래스도 추상 클래스로 지정해야 한다.
  • 추상화 - 기존 클래스의 공통부분을 뽑아 조상 클래스를 만든다.(상속과 반대 개념)
    class Example {
        public static void main(String[] args) {
            Unit[] group = { new Marine(), new Tank(), new Dropship() };
            
            for (int i = 0; i < group.length; i++)
                group[i].move(100, 200);
        }
    }
    
    abstract class Unit {
        int x, y;
        abstract void move(int x, int y);
    }
    
    class Marine extends Unit {
        void move(int x, int y) { }
    }
    
    class Tank extends Unit {
        void move(int x, int y) { }
    }
    
    class Dropship extends Unit {
        void move(int x, int y) { }
    }
    • 공통조상 Unit 클래스 타입의 객체 배열을 통해, 서로 다른 종류의 인스턴스를 묶을 수 있다.
    • Unit 클래스 타입의 참조변수(group)로 move 메서드 호출 가능
    • 모든 클래스의 조상인 Object 클래스 타입의 배열로 묶을 수도 있지만, Object 클래스에는 move 메서드가 정의되어 있지 않다.

인터페이스(interface)

  • 일종의 추상클래스. 추상 메서드의 집합
  • 오직 추상 메서드와 상수만을 멤버로 가진다.
  • 모든 멤버변수는 public static final 이어야 하며, 생략 가능하다.
  • 모든 메서드는 public abstact 이어야 하며, 생략 가능하다.
    • 단, static메서드와 디폴트 메서드는 예외로 추가할 수 있다.

인터페이스의 상속

  • 인터페이스의 조상은 인터페이스만 가능(Object가 최고 조상 아님)
  • 클래스와 달리 다중상속이 가능 ← 추상 메서드는 상속 받으면서 구현부 작성하기 때문에 충돌해도 상관 없음

인터페이스의 구현

  • 인터페이스를 구현할 클래스는, 인터페이스에 정의된 추상메서드를 모두 구현해야 한다.
    • 일부만 구현한다면 abstract 를 붙여 추상클래스로 선언해야 한다.
  • 상속과 구현을 동시에 할 수도 있다.
interface 인터페이스이름 {
    public static final 타입 상수이름 =;  // 상수
    public abstract 메서드이름(매개변수목록);  // 추상메서드
}
class 클래스이름 implements 인터페이스이름 {
    // 인터페이스에 정의된 추상메서드를 모두 구현해야 한다.
}
class Fighter implements Fightable {
    public void move(int x, int y) { ... }
    public void attack(Unit u) { ... }
}

abstract class Fighter implements Fightable {
    public void move(int x, int y) { ...}
}

class Fighter extends Unit implements Fightable { ... }

인터페이스를 이용한 다형성

  • 인터페이스 타입의 참조변수 -(참조)→ 인터페이스를 구현한 클래스의 인스턴스
  • 인터페이스 타입으로 형변환도 가능
  • 인터페이스를 메서드의 매개변수 타입으로도 사용 가능 → 메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공
  • 메서드의 리턴타입으로 인터페이스 지정 가능 → 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 리턴
abstract class Unit {
    int x, y;
    abstract void move(int x, int y);
}

interface Fightable {
    // ...
}

// Fighter 클래스 -> 인터페이스 Fightable을 구현한 클래스
class Fighter extends Unit implements Fightable {
    public void move(int x, int y) { /* ... */ }
    public void attack(Fightable f) { /* ... */ } // 메서드 매개변수 타입으로 인터페이스 사용 가능
}

class Example1 {
    public static void main(String[] args) {
        Fighter fighter = new Fighter();
				// attack 메서드 매개변수로 Fightable인터페이스를 구현한 Fighter클래스의 인스턴스 넘겨준다.
        fighter.attack(new Fighter()); 
    }
}

class Example2 {
    public static void main(String[] args) {
				// Fightable타입 참조변수 -(참조)-> Fighter 인스턴스
        Fightable f = (Fightable)new Fighter(); 
        Fightable f2 = new Fighter();        
    }

    Fightable method() {  // method 리턴타입이 Fightable 인터페이스
        Fighter ff = new Fighter();
        return ff;   // return new Fighter(); 가능. 
                     // Fightable인터페이스를 구현한 Fighter클래스의 인스턴스 주소 반환
    }
}

인터페이스 장점

두 객체 간 중간 다리 역할
선언(설계)과 구현 분리

  • 개발시간 단축
    • 메서드 호출하는 쪽, 인터페이스 구현하는 쪽, 나누어 동시에 개발 진행
  • 표준화 가능
    • 기본 틀을 인터페이스로 작성 → 개발자들에게 인터페이스를 구현하여 프로그램 작성하도록 함 → 일관되고 정형화된 프로그램 개발
  • 서로 관계없는 클래스들의 관계 맺음 가능
    • 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계 맺음
  • 독립적 프로그래밍 가능
    • 클래스의 선언과 구현 분리
    • 한 클래스의 변경이 관련된 다른 클래스에 영향을 미치지 않는 독립적 프로그래밍 가능

디폴트 메서드와 static 메서드

  • 인터페이스에 추상 메서드만 선언 가능하지만, 디폴트 메서드static 메서드 는 예외적으로 추가할 수 있다.
  • static 메서드 : 인스턴스와 관계 없는 독립적인 메서드라 인터페이스에 추가해도 상관은 없다.
  • 디폴트 메서드 : 추상 메서드의 기본적인 구현을 제공하는 메서드이나, 추상 메서드가 아니기 때문에 인터페이스에 새로 추가되어도 해당 인터페이스를 구현한 클래스를 변경하지 않아도 된다.
    • default 키워드를 붙인다. (접근제어자는 생략 가능)

    • 추상 메서드와 달리 { } 가 있어야 한다.

      interface MyInterface {
          void method();
          void newMethod();              // 추상 메서드
          default void newMethod2(){};   // default 메서드
      }
  • 디폴트 메서드와 기존 메서드 이름이 중복되어 충돌한다면?
    1. 여러 인터페이스의 디폴트 메서드 간 충돌

      • 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩
    2. 디폴트 메서드와 조상 클래스의 메서드 간 충돌
      - 조상 클래스의 메서드 상속, 디폴트 메서드 무시

      → 그냥 필요한 쪽 메서드와 같은 내용으로 오버라이딩

내부 클래스(inner class)

  • 클래스 내에 선언된 클래스(두 클래스 밀접한 관계일 때 사용)
  • 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있다.
  • 코드의 복잡성을 줄일 수 있다.(캡슐화)
  • 종류
    • 인스턴스 클래스(instance class)
    • 스태틱 클래스(static class)
    • 지역 클래스(local class)
    • 익명 클래스(anonymout class) : 클래스 선언 + 객체 생성 동시에 하는 이름없는 클래스(일회용)
      new 조상클래스이름() {
          // 멤버 선언
      }
      
      new 구현인터페이스이름() {
          // 멤버 선언
      }
      class Ex7_19 {
          public static void main(String[] args) {
              Button b = new Button("Start");
              b.addActionListener(**new ActionListener() {
                  @Override
                  public void actionPerformed(ActionEvent e) {
                      System.out.println("ActionEvent occurred!!");
                  }
                }** // 익명 클래스의 끝
              );
          } // main의 끝
      }

[참고] <Java의 정석 - 기초편>

profile
🔥
post-custom-banner

0개의 댓글