기존의 클래스를 재사용 하는것
상속 그림 표시
자식클래스에서 부모클래스로 화살표가 표시돼있다.
다이어그램
class Circle {
int x;
int y;
int r;
}
코드를
class Circle {
Point c = new Point();
int r;
}
로 바꾸면 간결하고 코드 관리가 쉽다.
클래스를 포함
할것인지 상속
할것인지 헷갈릴때가있다.
- 상속 (a는 b다.)
원
은점
이다.스포츠카
는자동차
다.- 포함 (a는 b를 가지고있다.)
원
은점
을 가지고 있다.스포츠카
는자동차
를 가지고 있다.
구조짤때 이렇게 문장을 만들어서 생각하면 쉽다.
c++
은 다중상속
이 가능한데 자바
는 하나
만 가능하다.
이름
, 매개변수
, 리턴타입
이 같아야한다.접근제어자
는 조상 클래스보다 범위가 넓어야한다.예외
는 조상 클래스보다 많이 쓸 수 없다. (넓은 범위로 쓸 수 없다.)예외
도 조상순으로 조건을 맞춰야한다.IOException
을 쓰면 자식에는 Exception
을 못쓴다.같은 클래스는 this
로 썼다면 상속 받은 멤버는 super
로 쓴다.
this()
는 같은 클래스 생성자 호출
super()
는 상속 클래스 생성자 호출
super();
코드를 생성한다.클래스의 묶음
package
예약어로 선언해야한다.package 패키지명;
파일 최상단에 선언해야한다.
패키지를 선언하지 않으면 자동으로 이름 없는 패키지에 속한다.
javac -d PackageTest.java
package 패키지명
을 통해 알아서 폴더를 만들어준다.클래스패스
에 포함해야 클래스파일을 읽는다.;
로 구분한다..
은 현재 경로 추가클래스패스 : c:\a
클래스파일 : c:\a\b\c\Test.class
명령어 : java b.c.Test
Test.class 실행됨
임시로 클래스패스 지정하기 -cp
명령어
ex) java -cp c:\~~임시클래스패스경로 b.c.Test
import 패키지명.클래스명
을 붙혀서 선언할 수 있다.
import문은 프로그램에 성능에 영향을 안끼친다. 다만 컴파일시간이 더 걸린다.
코드에 import를 선언하면 컴파일러는 해당 코드안에 있는 모든클래스 앞에 패키지를 붙혀준다.
ex )
import java.util.Date
Date d = new Date(); // java.util.Date d = new java.util.Date();
순으로 작성한다.
import 패키지명.클래스명
import 패키지명.*
*을 붙히면 해당 패키지명에 있는 모든 클래스를 import한다.
import java.*;
으로 import해도 아래 포함된 클래스들은 import 안된다.
import java.util.*;
import java.text.*;
대신 java안에 클래스가 있다면 java.클래스
들은 import된다.
import java.lang.*
은 자동 import가 된다.
접근제어자
와 그외의 제어자
로 나뉜다.
사용되는곳 : 멤버변수, 메서드, 초기화 블럭
인스턴스변수는 생성자에서 초기화할 수 있다.
클래스에 사용 : 추상메서드가 있음을 의미
메서드에 사용 : 선언만 작성, 구현은 없음
abstract
를 선언 가능한데 이럴 이유는 없다.접근 제한 역할
같은클래스
내에서만 접근같은패키지
내에서만 접근같은패키지
, 다른패키지 자손
에서 접근가능접근제한없음
java파일 안에서는 하나의 public class만 존재가능
class Singleton {
// 인스턴스 생성
private static Singleton s = new Singleton();
// 외부에서는 인스턴스 생성을 못한다.
private Singleton();
// 인스턴스 생성없이 호출가능
public static Singleton getInstance() {
return s;
}
}
Singleton.getInstance();
를 하면 Singleton 인스턴스를 생성하고 객체를 가져온다.
static
과 abstract
는 동시에 사용 못한다.클래스.메서드
를 쓰면 사용이 되야하는데 abstract
는 구현이 없다.abstract
와 final
을 동시에 사용 못한다.abstract
는 상속받는용도, final
은 상속불가능abstract
메서드의 접근제어자는 private
일 수 없다.abstract
는 구현해야하는데 private
를 쓰면 접근을 못한다.private
와 final
은 같이 쓸 필요 없다.여러 가지 형태를 가질 수 있는 능력
조상클래스 타입
의 참조변수
-> 자손클래스
의 인스턴스
를 참조
class TV {
boolean power;
int channel;
void power() {power=!power;}
}
class CpationTV extends TV {
String text;
void caption() {};
}
CaptionTV c = new CaptionTV();
Tv t = new CaptionTV();
CaptionTV ct = new Tv(); // 에러
용어
Tv t = new CaptionTV();
타입
인스턴스
설명
1. c는 CaptionTV
+ TV
클래스 멤버 사용가능
2. t는 TV
멤버만 사용가능
3. ct는 TV
가 쓰려는 멤버보다 CaptionTV
의 멤버가 더많아서 안된다.
4. Tv를 기준으로 멤버를 쓸수있다.
참조변수타입에 따라 사용할 수 있는 멤버가 다르다.
모든 참조변수는 4byte 주소값을 가진다.
조상타입의 참조변수로 자손타입의 인스턴스 참조가능
Tv t = new Caption();
이 반대는안된다.
기본형처럼 참조형도 형변환이 가능하다.
단 상속관계만가능
자동차 = (자동차) 스포츠카
스포츠카 = (스포츠카) 자동차
public class Main {
public static void main(String[] args) {
FireEngine f;
Ambulance a;
// a = (Ambulance)f; // 에러
// f = (FireEngine)a; // 에러
Car car = null;
FireEngine fe = new FireEngine();
FireEngine fe2 = null;
car = (Car) fe; // (Car) 생략가능, 조상 <- 자손
fe2 = (FireEngine) car;// 생략불가능, 자손 <- 조상
fe2.color = "RED";
}
}
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 Ambulance extends Car {
void siren() {
System.out.println("siren~");
}
}
Car car = null;
if (car instanceof FireEngine) {
FireEngine fe = (FireEngine) car;
fe.water();
} else if (car instanceof FireEngine) {
FireEngine fe = (FireEngine) car;
fe.water();
}
Parent p = new Child();
Child c = new Child();
// 메서드 오버라이딩으로 둘에 결과는 같다.
p.method();
c.method();
System.out.println(p.x);
System.out.println(c.x);
메서드 : 둘다 Child의 method가 호출된다.
변수 : 각각의 변수가 호출된다.
method()
는 실제 인스턴스
를 바라본다.public class Main {
public static void main(String[] args) {
Buyer b = new Buyer();
Tv tv = new Tv(); // #1
Computer com = new Computer(); // #4
b.buy(tv); // #7
b.buy(com); // #10
System.out.println("남은돈:" + b.money);
System.out.println("보너스:" + b.bonusPoint);
}
}
class Product {
int price;
int bonusPoint;
// #3 #6
public Product(int price) {
this.price = price;
bonusPoint = (int)(price/10.0);
}
}
class Tv extends Product {
Tv() {
super(100); // #2
}
// #9
@Override
public String toString() {
return "TV";
}
}
class Computer extends Product {
public Computer() {
super(200); // #5
}
// #12
@Override
public String toString() {
return "Computer";
}
}
class Buyer {
int money = 1000;
int bonusPoint = 0;
// #8 #11
// 업캐스팅
void buy(Product p) {
if(money < p.price) {
System.out.println("잔액부족");
return;
}
money -= p.price;
bonusPoint += p.bonusPoint;
System.out.println(p + "를 구입");
}
}
Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();
공통의 조상으로 배열을 다뤄야한다.
public class Main {
public static void main(String[] args) {
Buyer b = new Buyer();
Tv tv = new Tv();
Computer com = new Computer();
Audio audio = new Audio();
b.buy(tv);
b.buy(com);
b.buy(audio);
b.summary();
System.out.println();
b.refund(com);
b.summary();
}
}
class Product {
int price;
int bonusPoint;
public Product(int price) {
this.price = price;
bonusPoint = (int)(price/10.0);
}
}
class Tv extends Product {
Tv() {super(100);}
@Override
public String toString() {return "TV";}
}
class Computer extends Product {
public Computer() {super(200); }
@Override
public String toString() {return "Computer";}
}
class Audio extends Product {
public Audio() {super(50); }
@Override
public String toString() {return "Computer";}
}
class Buyer {
int money = 1000;
int bonusPoint = 0;
Vector item = new Vector();
void buy(Product p) {
if(money < p.price) {
System.out.println("잔액부족");
return;
}
money -= p.price;
bonusPoint += p.bonusPoint;
System.out.println(p + "를 구입");
item.add(p);
}
void refund(Product p) {
if(item.remove(p)) {
money += p.price;
bonusPoint -= p.bonusPoint;
System.out.println(p + "를 반품");
} else {
System.out.println("제품없음");
}
}
void summary() {
int sum = 0;
String itemList = "";
if(item.isEmpty()) {
System.out.println("구입상품없음");
}
for(int i = 0; i < item.size(); i++) {
Product p = (Product) item.get(i);
sum += p.price;
itemList += (i==0) ? "" + p : ", " + p;
}
System.out.println("총 " + sum + "원");
System.out.println("구입제품 " + itemList + "임");
}
}
TV, 오디오, 컴퓨터를 객체에 저장해서 구매자가 지정된 액션을 하는 예제
객체지향의 완벽한 예제인것같다.
abstract class Player {
abstract void play(int pos);
abstract void stop();
}
class AudioPlayer extends Player {
@Override
void play(int pos) { }
@Override
void stop() { }
}
abstract class AbstractPlayer extends Player { }
구현부분만큼이나 메서드이름, 매개변수 , 타입도 중요
해서 추상메서드를 쓰는거다.
기존의 클래스에서 공통부분을 뽑아서 조상클래스를 만드는것.
상속은 위와 반대다.
abstract class Player {
boolean pause;
int currentPos;
// 생성자
Player() {
pause = false;
currentPos = 0;
}
// 추상메서드, 필수로입력해야함
abstract void play(int pos);
abstract void stop();
void play() {
play(currentPos);
}
// 일반메서드
void pause() {
if(pause) {
pause= false;
play(currentPos);
} else {
pause = true;
stop();
}
}
}
class CDPlayer extends Player {
@Override
void play(int pos) {}
@Override
void stop() { }
int currentTrack;
void nextTrack() { currentTrack ++;}
void preTrack() {
if(currentTrack > 1) {
currentTrack --;
}
}
}
play
와 stop
은 필수로 작성해야한다.
// 스타크래프트 유닛 클래스
abstract class Unit {
int x, y;
// 공중과 지상 공통 move이름
// 공중과 지상이 움직임이 달라서 abstract로 한다.
abstract void move(int x, int y);
// 예제는 일반메서드지만
// 공중은 멈출때 가속도가 붙어서 abstract로 한다.
abstract void stop();
}
class Marine extends Unit {
void move(int x, int y) { }
// 추상 메서드가 일반메서드였다면 오버라이딩된다.
void stop() { } // 즉시 stop
}
class Dropship extends Unit {
void move(int x, int y) { }
void stop() { } // 가속도붙은 stop
void load() { }
void unload() { }
}
추상클래스 예제
추상메서드
와 상수
만 허용interface 인터페이스이름 {
public static final 타입 상수이름 = 값;
public abstract 메서드이름();
}
모든 메서드
는 public abstract
다. (생략가능)모든 타입
은 public static final
이다. (생략가능)implements
키워드사용최고조상(Object)
이 없다. abstract class Fighter implements Fightable {
public void move(){}
}
위처럼 구현도 할수 있다.
인터페이스 이름은
~을 할 수있다.
의미인able
로 쓴다.
구현
이라는 용어를 쓴다.public
만 써야한다.static final변수
라 충돌이 피해진다.구현부가 없는 메서드
라 충돌이 피해진다.자손클래스의 인스턴스를 조상타입의 변수로 참조가 가능하다.
Fightable f = (Fightable) new Fighter();
Fightable f = new Fighter();
void attack(Fighter f) {}
매개변수로도 가능하다.
public class Main {
public static void main(String[] args) {
Parseable parser = ParseManager.getParser("XML");
parser.parse("doc.xml");
parser = ParseManager.getParser("HTML");
parser.parse("doc2.html");
}
}
interface Parseable {
void parse(String fileName);
}
class XMLParser implements Parseable {
@Override
public void parse(String fileName) {
System.out.println(fileName + "- XML parsing");
}
}
class HTMLParser implements Parseable {
@Override
public void parse(String fileName) {
System.out.println(fileName + "- HTML parsing");
}
}
class ParseManager {
public static Parseable getParser(String type) {
if(type.equals("XML")) {
return new XMLParser();
} else {
Parseable p = new HTMLParser();
return p;
}
}
}
위와같은 코드에서 XMLParser->NewXMLParser로 변경되는게아닌 JSON형식이 추가된다면 Json클래스생성과 ParseManager클래스에 조건문으 하나 더 추가할지 설계가 잘못된건지 의문이다.
클래스<->클래스
가 아닌 클래스->인터페이스<-클래스
관계다.위 코드에서 건물까지 합쳐진 코드를 나중에 직접 짜봐야겠다.
클래스를 사용하는쪽
, 클래스를 제공하는쪽
이 있음사용하는쪽 : user
사용하려는 메서드 : provider
public class Main {
public static void main(String[] args) {
A a = new A();
a.a(new B());
}
}
class A {
public void a(B b) {
b.b();
}
}
class B {
public void b() {
System.out.println("call");
}
}
위코드는 A-B가 직접적인 관계가있다.
B(provider)
가 변경되면 A(user)
도 변경되야한다.B(provider)
를 변경해야한다.public class Main {
public static void main(String[] args) {
A a = new A();
a.a(new B());
}
}
class A {
public void a(I i) {
i.b();
}
}
class B implements I{
public void b() {
System.out.println("call");
}
}
interface I {
void b();
}
C, D, E가 추가되서 A에 선언 후 C, D, E가 변경되도 A는 변경을 안해도된다.
public class Main {
public static void main(String[] args) {
A a = new A();
a.a();
}
}
interface I {
void b();
}
class A {
public void a() {
I i = InstanceManager.getInstance();
i.b();
}
}
class B implements I{
public void b() {
System.out.println("call");
}
}
class InstanceManager {
public static I getInstance() {
return new B();
}
}
위 코드에서 매개변수 대신 instance를 바로 얻어서 사용한다.
JDBC의 DriverManager클래스가 위처럼 생겼다.
정리
상속할때 팁
- 상속 (a는 b다.)
- 포함 (a는 b를 가지고있다.)
object클래스 - 모든 클래스의 조상
형변환은 상속관계에서 양방향으로 수행
추상화 : 클래스간의 공통조상
추상클래스보다 인터페이스가 더 추상적이다.
인터페이스는 선언부만 알고 내용은 몰라도 된다.