수평적 설계
ex) 개(먹다, 이름, 나이, ..), 고양이(먹다, 이름, 나이,..)
수직적 설계(계층화, 상속구조)
// 모든 클래스는 Object 클래스를 기본으로 상속 받음
public clss Animal extends Object {
public String name;
public int age;
public String part;
public void eat() {
System.out.println("?"); // 포괄적, 추상적
}
public Animal() {
super();
}
}
public class Dog extends Animal {
public void eat() {
System.out.prinln("게 처럼 먹다.");
}
public Dog() {
super(); // new Animal(); 실행, 생략해도 컴파일러가 자동으로 넣어 줌
// 객체는 부모가 만들어 지고 자식이 만들어져야 함
}
}
public class Cat extends Animal {
public void eat() {
System.out.prinln("고양이 처럼 먹다.");
}
public Cat() {
super(); // new Animal(); 실행
}
}
상속받은 하위 클래스가 상위 클래스의 동작을 수정하는 것
동적바인딩 : 호출될 메서드가 실행 시점에 결정되는 바인딩
ex) animal의 eat() 메서드 / Dog의 eat()메서드 => Dog꺼
자동형변환 : 부모 = 자식(하위 클래스의 타입이 상위 클래스에 들어가는 것, 프로모션, object casting)
// Dog의 모든 동작을 알고있을 때
Dog d = new Dog();
d.eat();
// Dog 클래스의 동작을 모를 때, 부모 클래스로 생성해서 호출
Animal d = new Dog(); // upcasting(자식 타입을 부모가 받는 것)
// 부모 클래스는 하위 클래스가 재정의한지 찾아보고 재정의한 메서드를 참조하게 되어있음
// Dog의 기능을 모르더라도 부모의 타입으로 Dog가 가지고 있는 eat()를 실행시킬 수 있음
// 실행할 때 메서드 찾아감(동적 바인딩)
d.eat();
public class Dog extends Animal {
public void eat() {
System.out.printlm("개처럼 먹다.");
}
}
public class Cat extends Animal {
public void eat() {
System.out.printlm("고양이처럼 먹다.");
}
}
Animal ani = new Dog();
ani.eat(); // "개처럼 먹다"로 출력됨
ani = new Cat();
ani.eat(); // "고양이 처럼 먹다"로 출력됨
Animal d = new Dog(); // 간접
Dog d = new Dog(); // 직접, super(); 생략되어있음
public class Main {
public static void main(String[] args) {
Animal a = new Dog(); // upcasting
a.eat(); // "456" 출력, Animal 갔다가, Dog에 오버라이드 메서드 있어서 자식으로 실행(동적 바인딩)
Animal c = new Cat();
((Cat) c).night(); // downcasting, Animal에 있는 메서드가 아닌 Cat의 고유 기능이므로, 접근 불가능 하니 다운캐스팅 필요
// "." 연산자가 캐스팅연산자 보다 우선순위가 높아서 괄호 처리 해야함
}
}
class Animal (extends Object){
public void eat() {
System.out.println("123");
}
// (기본 생성자)
public Animal() {
super(); // new Object();
}
}
class Dog extends Animal {
// @Override시 부모 클래스로 해당 함수를 검색하는데
// 부모클레스에 해당 함수 이름이 없으면 에러
@Override
public void eat() {
System.out.println("456");
}
// 기본 생성자
public Dog() {
super(); // new Animal();
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("789");
}
public void night() {
System.out.println("밤에 눈에서 빛이난다.");
}
}
Object Casting(객체 형변환) : 상속관계에 있는 클래스들 간의 형(DataType)을 바꾸는 것
Animal r = new Dog();
r = new Cat();
Dog g = (Dog) r;
Cat c = (Cat) r;
Animal r = new Cat();
Cat c = (Cat)r; // downcasting
c.night();
다형성 : 상위 클래스가 하위 클래스에게 동일한 메세지로 서로 다르게 동작시키는 원리
Dog d = new Dog();
display(d);
Cat c = new Cat();
display(c);
// display 메서드를 하나로 만들기 위해 상위클래스를 받는 메서드 구현
// 만일 따로 만들면 Cat, Dog 받는 2개의 메서드 정의 필요
// 동물이 더 많아지면 메서드도 많아져야 하는 불편함
public static void display(Animal r) {
// Animal r : 다형성 인수(하위 클래스를 받을 수 있다)
// 업캐스팅
r.eat();
// instanceof 메서드로 다운캐스팅 할 때를 지정 가능
if(r instanceof Cat) {
((Cat)r).night();
}
}
Animal[ ] r = new Animal[2];
r[0] = new Dog();
r[1] = new Cat();
// 오버라이드 되어있어서 다운 캐스팅 없이도 갈 수 있음
r[0].eat();
r[1].eat();
((Cat)r[1]).night(); // 오버라이딩 안된 메서드는 형변환을 통해 하위 클래스 메서드 사용 가능
public void eat() {
System.out.println("?");
}
// 추상 메서드 -> 구현부가 없음
// 추상 메서드를 하나라도 가지면 추상 클래스라 함
// 불완전한 메서드
public abstract void eat();
추상클래스(불완전한 객체) : 추상 메서드 + 구현 메서드(없을 수도 있음)
public abstract class Animal {
public abstract void eat(); // 추상메서드
public void move() { // 구현메서드
System.out.println("무리를 지어서 이동한다.");
}
}
추상 메서드는 하위 클래스가 반드시 재정의 해야한다.
추상 클래스는 부모 역할 가능 -> 다형성 보장 가능
public abstract class Animal {
// 추상 메서드...
}
public class Dog extends Animal {
// 추상 메서드를 반드시 구현
}
public class Cat extends Animal {
// 추상 메서드를 반드시 구현
}
Animal r1 = new Dog();
r1.eat(); // 재정의가 반드시 되어있으니 동작 가능
Animal r2 = new Cat();
r2.eat(); // 재정의가 반드시 되어있으니 동작 가능
서로 기능이 비슷한 클래스를 묶음 -> 자연스럽게 추상 클래스가 많이 등장하게 됨
부모에게 있는 구현 메서드는 자식에서 재정의 하지 않아도 사용 가능
인터페이스 : 서로 기능이 다른 클래스를 묶을때 사용하는 클래스
인터페이스 : 100% 추상메서드만 가능, 구현된 메서드를 가질 수 없다.
public interface RemoCon {
// 인터페이스에 변수 넣으면 자동으로 상수 취급
// 괄호 부분을 안적어도 동일
public (static final) int MAXCH = 100;
public abstract void chUp();
public void chDown();
public abstract void internet();
// 구현 메서드 가질 수 x
public void internet() {
System.out.println("123");
}
}
public class TV implements RemoCon {
public void chUp() {
System.out.println("TV 채널이 올라간다.");
}
public void chDown() {
System.out.println("TV 채널이 내려간다.");
}
public void internet() {
System.out.println("인터넷이 된다.");
}
}
public class Radio implements RemoCon {
public void chUp() {
System.out.println("Radio 채널이 올라간다.");
}
public void chDown() {
System.out.println("Radio 채널이 내려간다.");
}
public void internet() {
System.out.println("인터넷이 지원되지 않는다.");
}
}
RemoCon r1 = new TV();
r1.chUP();
r1.chDown();
r1.internet();
RemoCon r2 = new Radio();
r2.chUp();
r2.chDown();
r2.internet();
인터페이스의 동작 방식을 알면 실제 핵심 클래스를 몰라도 동작시킬 수 있음
단독적 객체 생성 불가
추상 클래스
인터페이스
public class TV implements RemoCon {
int curCh = 1;
public void chUp() {
// 인터페이스에 정의된 static 변수 사용 가능
if(curCh < Remocon.MAXCH) {
curCh++;
System.out.println("TV 채널이 올라간다.");
}
}
public void chDown() {
System.out.println("TV 채널이 내려간다.");
}
public void internet() {
System.out.println("인터넷이 된다.");
}
}
Remocon.MAXCH
public interface Connection {
// 접속동작
getConnection(String url, String userm String passwd);
}
// 예시, 실제로는 구현 내용을 드라이버 클래스를 받아야 함
public class MySQL implements Connection {
@Override
public String getConnection(String url, String userm String passwd) {
return "연결되었습니다";
}
public interface A {
public void m();
}
public interface B extends A{
public void z();
}
// 두개를 구현해야 함
public class X implements B {
public void m() {
}
public void z() {
}
}
public class Dog extends Animai implements Pet, Robots{
}
(import java.lang.*;) // 기본적으로 생략
public class A (extends Object) {
// 기본 생성자 생략
(
public A() {
super();
}
)
// Object에서 display 출력 불가
// 다운 캐스팅을 통해 출력 기능
public void display() {
System.out.println("나는 A이다.");
}
// Object로 toString 출력하면 출력 가능(Object 클래스 내 toSting메서드를 재정의 했기 때문)
@Override
public String toString() {
System.out.println("재정의 메서드입니다.");
}
}public class ObjectTest {
public static void main(String args) {
display(new A());
display(new B());
}
// A와 B 클래스 각각 go라는 메서드 있다고 할 때
// 각각의 매개변수 A, B 2개로 만들 수 있지만 하나로 합칠 수 있음
public void display(Object o) {
// 사용할 때는 downcasting 해야한다.
if(o instanceOf A) {
((A)o).go();
}
else {
((B)o).go();
}
}
}
// Heap Area에 객체 생성 메모리 영역에 "APPLE" 생성
// str1변수와 str2의 주소 번지는 달라짐(new 키워드로 각각의 객체를 생성했기에)
// new 키워드 하면 Heap Area에 생성됨
String str1 = new String("APPLE");
String str2 = new String("APPLE");
// no가 출력됨
if(str1==str2) {
System.out.println("yes");
}
else {
System.out.println("no");
}
// yes가 출력됨
if(str1.equals(str2)) {
System.out.println("yes");
}
else {
System.out.println("no");
}
// Literal Pool : 문자열 상수(객체)가 생성되는 메모리 영역(재활용)
String str3 = "APPLE";
// 이미 만들어 진 "APPLE"을 가르킴
// 하나를 공통으로 가르킴
String str4 = "APPLE";
// yes가 출력됨
if(str3==str4) {
System.out.println("yes");
}
else {
System.out.println("no");
}
public class BasicArray {
public static void main(String[] args) {
int[] a = new int[3];
a[0] = 10;
a[1] = 20;
a[2] = 30;
int v = a[1];
int len = a.length;
for(int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
}
public class IntArray {
private int count;
private int[] arr;
// 매개변수 없으면, 디폴트 생정자 호출
// 기본 사이즈 10
public IntArray() {
this(10); // 자기 자신을 가르키는 또다른 생성자 호출
}
// 배열 생성 동작
public IntArray(int init) {
arr = new int[init];
}
// 추가 동작
public void add(int data) {
arr[count++] = data;
}
// 얻는 동작
public int get(int index) {
return arr[index];
}
// 배열크기
public int size() {
return count;
}
}
// 배열처럼 동작하는 API 적용
public class BasicArray {
public static void main(String[] args) {
IntArray arr = new IntArray(3);
arr.add(10);
arr.add(20);
arr.add(30);
for(int i = 0; i<arr.size(); i++) {
System.out.println(arr.get(i));
}
}
}
Object 형태로만 변경하면 됨
실제 ArrayList에서는 배열의 size가 넘치면 size를 증가시켜주는 등의 동작을 함
하지만 이미 인터페이스에 구현되어 있으므로, 따라하는 정도로만 하기 위해 배열의 크기를 늘리는 방식은 구현하지 않았음
public class ObjectArray {
private int count;
private Object[] arr;
// 매개변수 없으면, 디폴트 생정자 호출
// 기본 사이즈 10
public ObjectArray() {
this(10); // 자기 자신을 가르키는 또다른 생성자 호출
}
// 배열 생성 동작
public ObjectArray(int init) {
arr = new Object[init];
}
// 추가 동작
public void add(Object data) {
arr[count++] = data;
}
// 얻는 동작
public Object get(int index) {
return arr[index];
}
// 배열크기
public int size() {
return count;
}
}
// 배열처럼 동작하는 API 적용
public class TPC37 {
public static void main(String[] args) {
ObjectArray arr = new ObjectArray(3);
arr.add(new A());
arr.add(new B());
arr.add(new A());
for(int i = 0; i<arr.size(); i++) {
// 배열에 넣을 때 upcasting
// 나올때도 upcasting 이니깐 타입 검사 필요
Object o = arr.get(i);
if(o instanceof A) {
((A)o).go();
}else {
((B)o).go();
}
}
}
}
제네릭으로 타입 지정할 수도 있음
import java.util.*;
// 사이즈 1이여도 자동으로 증가하므로 들어갈 수 있음
List list = new ArrayList(1);
list.add(new BookDTO(123));
list.add(new BookDTO(234));
list.add(new BookDTO(5123));
for(int i = 0; i<list.size(); i++) {
Object o = list.get(i);
BookDTO vo = (BookDTO)o;
System.out.println(123123213);
}
위 처럼만 사용하면 리스트에 어떤 타입이든 넣을 수 있음
하지만 보통 하나의 타입만 넣는것이 일반적
제네릭으로 지정 할 수 있음
배열에 들어갈 때 upcasting이 일어나지 않음
꺼낼 때 downcasting이 필요없음
import java.util.*;
// 사이즈 1이여도 자동으로 증가하므로 들어갈 수 있음
// Object[] -> BookDTO[]로 지정 가능
// upcasting이 일어나지 않음
List<BookDTO> list = new ArrayList<BookDTO>(1);
list.add(new BookDTO(123));
list.add(new BookDTO(234));
list.add(new BookDTO(5123));
for(int i = 0; i<list.size(); i++) {
// Object o = list.get(i);
// downcasting이 필요없음
BookDTO vo = list.get(i);
System.out.println(123123213);
}
| 기본자료형 | 객체자료형 | 사용 예 |
|---|---|---|
| int | Integer | 1, new Integer(1) |
| float | Float | 23.4f, new Float(23.4f) |
| char | Character | 'A', new Character('A') |
| boolean | Boolean | true, new Boolean(true) |
int a = 1;
Integer b = new Integer(1); // 객체
int v = b.intValue(); // 포장을 벗긴다
박싱 / 언박싱 : 컴파일러가 자동으로 해준다.
기본자료형을 Object[] 배열에 저장할 경우? Integer 클래스 활용하여 객체형태로 저장
Object[] obj = new Object[3];
// obj[0] = 1;도 에러가 나지 않음
// 오토 박싱이 되기에 에러가 나지 않지만 아래 코드가 정확
obj[0] = new Integer(1);
obj[1] = new Integer(2);
obj[2] = new Integer(3);
int v1 = 100;
String.valueOf(v1); // v1을 String

part2도 거의 아는 내용이였지만, 세세하게 메모리 부분을 알 수 있어 좋았다.
String에서 String a = "abc"; 형태가 literal pool에 생겨서 == 로 대등 비교해도 된다는 것을 처음 안 것 같다.(아닌가 들어봤나..? 무튼)
뭔가 깊은 부분의 내용을 좀 더 알 수 있던 3일간의 연휴동안 쭉쭉 달려왔다.
자바 클래스, 상속 등 개념 부분이 확실하지 않은 사람들이 보기에 좋은 강의일 것 같다!
17시간 44분이라니..! 고생했다!
강의 출처남기면 블로그 작성해도 된다고 하셨지만, 상세 실습코드는 작성하지 않았습니다. 강의를 통해 확인하세요!