⭐String 과 StringBuffer

String 클래스
문자열을 표현하는데 사용된다.

💀불변 immutable 이다.
한 번 설정하면 변경할 수 없다.

 

String 클래스를 통해 문자열을 저장하는 방식엔 2가지가 있다.


리터럴 방식
String str1 = "Hello";
Heap 안에 존재하는 특정한 영역
String Constant Poll에 저장돼 재사용된다.

new 연산자 사용
String str1 = new String("Hello");
Heap 메모리에 객체로서 올라간다.

String 클래스의 특성으로 인해
문자열을 자주 변경한다면
메모리 낭비가 심해질 수 있다.

 

상수풀에 문자열을 저장한 뒤
이를 참조해서 재사용하면 메모리를 아낄 수 있다.

 

⭐StringBuffer

 

String 클래스의 불변성으로 인해
문자열을 자주 변경할 때 메모리 낭비가 발생할 수 있다.

 

StringBuffer를 사용하면

객체를 계속해서 생성시키지 않고 문자열을 변경 가능하다.

 

 

예제) String 클래스의 객체 선언 방식

 

package _string;
/**
 * 4.24
 * String 연습
 */
public class StringTest1 {

    //변수
    //생성자
    //메서드

    //main
    public static void main(String[] args) {

        String str1 = "문자열"; //Heap => StringPool에 저장

        String str2 = new String("abc"); //Heap에 저장
        String str3 = new String("abc");
        //Heap에 올라가면 주소값이 생성된다.
        /*
        참조 비교
        주소 == 주소
        각각 객체의 주소값을 비교한다.
         */
        System.out.println("str2 == str3: " + (str2 == str3));

        //문자열을 리터럴 방식으로 만들어보자
        String str4 = "abc";
        String str5 = "abc";
        String str6 = "abc";

        System.out.println("str4 == str5: " + (str4 == str5));
        /*
        문자열은 아주 많이 사용되는 데이터 타입이다.
        모든 문자열이 객체로 저장된다면
        메모리 효율이 떨어지게 된다.

        상수풀에 문자열을 저장한 뒤
        이를 참조해서 재사용하면 메모리를 아낄 수 있다.

        그래서 str1 = "abc" = str4,str5 인 것이다.
         */

        String str7 = str6 + " 안녕"; //"abc 안녕"이라는 새로운 녀석이 상수풀에 올라갔다.
        System.out.println(str7);

    }//end of main
}//end of class

String은 리터럴 방식, 객체 방식으로 선언하면 저장방식의 차이로 인해 주소값이 달라질 수 있다.

str2, str3은 객체로

str4, str4는 리터럴로 선언됐다.

 

예제2)

String은 불면한다

 

💀String 객체는 불변 immutable 이다.

원래 객체 주소가 생성됐고
내부 변수 값이 변경된다면
String 클래스는 수정되지 않고 불변이다.

⭐ 만약 수정을 하게되면
새로운 String 객체를 만드는 동작이 실행된다.

package _string;
/**
 * 4.24
 * String 연습
 */
public class StringTest2 {

    //main
    public static void main(String[] args) {

        //객체
        String str1 = new String("Hello");
        String str2 = new String("World");

        /*
        String 객체는 불변 immutable 이다.

        원래 객체 주소가 생성됐고
        내부 변수 값이 변경된다면
        String 클래스는 수정되지 않고 불변이다.

        만약 수정을 하게되면
        새로운 String 객체를 만드는 동작이 실행된다.
         */

        System.out.println("고유주소확인: " + System.identityHashCode(str1));

        //문자열 연결 기능 호출
        str1 = str1.concat(str2);

        System.out.println("수정주소확인: " + System.identityHashCode(str1));

    }//end of main
}//end of class

str1의 문자열 값을 변경하자 sir1의 주소값도 자동으로 변경됐다.

 

예제3)

String 클래스에 포함된 다양한 메서드를 사용해봤다.

 

⭐replace 메서드
문자열 내 특정 문자열을
다른 문자나 문자열로 교체할 때 사용한다
ex 비속어

⭐ substring 메서드
문자열 일부분을 추출하여
새로운 문자열로 반환한다.

두가지 오버로딩 메서드를 제공한다.
startindex~
startindex~ endIndex
index는 0부터 시작한다.

package _string;
/**
 * 4.24
 * String 연습
 */
public class StringTest3 {

    //main
    public static void main(String[] args) {

        String str1 = "ABCD";
        int countStr1 = str1.length(); //문자열 길이
        System.out.println("countStr1: " + countStr1);

        /*
        replace 메서드는
        문자열 내 특정 문자열을
        다른 문자나 문자열로 교체할 때 사용한다
        ex 비속어

        World 를 Java로 대체해보자
         */
        String str2 = "HelloWorld";
        String str3 = str2.replace("World", "Java");

        System.out.println("str2: " + str2); // HelloWorld
        System.out.println("str3: " + str3); // HelloJava

        /*
        substring 메서드는
        문자열 일부분을 추출하여
        새로운 문자열로 반환한다.

        두가지 오버로딩 메서드를 제공한다.
        startindex~
        startindex~ endIndex
        index는 0부터 시작한다.
         */
        String result1 = str2.substring(0, 5);
        System.out.println("HelloWorld의 1~5번째 글자: " + result1);

    }//end of main
}//end of class

 

예제4)

StringBuffer 활용

package _string;
/**
 * 4.24
 * String Buffer 연습
 */
public class StringBufferTest1 {

    //main
    public static void main(String[] args) {

    String str1 = new String("Hello");
    String str2 = new String("World");

    //새로 배우는 데이터 타입 StringBuffer
    StringBuffer buffer1 = new StringBuffer(str1);

        System.out.println(buffer1);
        System.out.println("수정전 해시코드: " + System.identityHashCode(buffer1));

    //buffer1 값을 수정해보자 Replace
    buffer1.append(str2); //문자열 합치기
    buffer1.append("111");
    buffer1.append("222");

        System.out.println(buffer1);
        System.out.println("수정후 해시코드: " + System.identityHashCode(buffer1));

        /*
        hashCode()
        API7에서는 객체의 유일성 보장하는 정수값
        API8부터는 buffer1.toString() 해야 값을 확인 가능

        StringBuffer 데이터 타입을 String으로 형변환 하려면 toString()하면 됨
         */
        String result1 = buffer1.toString();
        System.out.println(result1);

    }//end of main
}//end of class

StringBuffer 구문을 통해 주소값 변경없이(객체생성 없이) 문자열을 변경한 모습

 

⭐java API 문서

자바 개발자들은 자바 API를 이용한다.

이를 위해 API 목록과 사용법을 정리한 문서가 있다.

API
Application - 응용프로그램
Programming - 프로그래밍
Iterface - 인터페이스: 서로 연결해주는 접접(표준, 규약)

 

⭐ 자바를 통해 어떤 문제를 해결하려면
자신이 필요한 로직이 담긴 API  패키지를 찾아야 한다.

👍 한 사람이 모든 API를 외울 수는 없다.
그때 그때 문서에서 필요한 것을 찾아 쓰는 연습을 해야 한다.

 

많이 쓰는 자바 패키지 4가지


java.lang - 기본 패키지와 클래스
java.util - 프로그램 제어, 데이터 저장
java.io - 주변기기와 파일 제어
java.net - 통신

 

👍API문서를 볼때의 실무팁
계층구조를 먼저 보고
필드를 보면 좋다

 

인터넷 이용이 제한된 업무환경도 존재한다.

API문서를 보는 연습을 하는 편이 좋다.


final 변수 = 상수
final 메서드 = 재정의가 안됨

final 클래스 = 상속이 안됨
자바 기능과 관련된 민감한 클래스이니 건들지 마라는 뜻

오라클에서 제공하는 자바8 버전의 API문서

⭐오브젝트 클래스
Object Class

Object 클래스는 모든 클래스의 최상위 클래스다.

자바는 Object 클래스를 제외하고 하나의 상속만을 제공한다.


java.lang 패키지 안에 존재하며

import java.lang.*; 임포트 하지 않아도 자동으로 가져와준다.

이를 통해 많은 마더 메서드를 상속받아 쓸 수 있다.

대표적으로는 toString(), equals(), hashCode() 등이 있다.

 


⭐toString()
객체의 주소값을 호출
재정의: 모든 객체에 공통 메서드를 만들어주고 싶을때

⭐ equals()
두 객체의 동등성 == 비교
재정의: 서로 다른 객체가 논리적으로 동등하도록 만들고 싶을때

⭐ hashCode()
객체의 고유한 정수값을 만들어서 독립성을 보장
빠른 검색과 분류 저장을 가능하게 한다. ex)도서관
재정의: 동일 상품에 같은 고유값을 주고 싶을때

 

오브젝트 클래스는 모든 클래스의 최상위 클래스다

 

오브젝트 클래스를 직접 호출할 수도 있지만 그럴 필요는 없다.

자동으로 상속되기 때문이다.

java.lang.*; 를 입력해 lang에 있는 모든 메서드를 호출할 수 있다.
이처럼 오브젝트 클래스에 정의된 메서드를 상속받아 편리하게 쓸 수 있다.

 

예제)

내용이 같은 객체라고 하더라도

서로 다른 주소값을 가지고 있으면 다른 객체다.

 

하지만 상점의 상품이나 도서관의 책처럼

논리적으로는 같은 객체로 바라봐야할 때도 생긴다.

 

오브젝트 클래스의

equals() 메서드를 오버라이드(덮어쓰기)로 재정의해

책 제목과 저자가 같으면 논리적으로 같게 처리하는 방법을 연습해봤다.

package _object;
/**
 * 4.24
 * Object 최상위 클래스 이해
 *
 * 클래스를 만들면
 * 기본적으로 Object 클래스를 상속받도록 돼 있다.
 *
 * Object 클래스는 모든 클래스의 최상위 클래스다.
 *
 * 자바는 Object 클래스를 제외하고
 * 단일 상속만을 제공한다.
 *
 * import java.lang.Object;
 * import java.lang.*;
 * 패키지도 자동으로 넣어준다
 */
//import java.lang.Object;
//import java.lang.*;

public class Book { //컴파일러가 'extends Object'를 자동으로 꽂아준다.

    private int bookTypeId;

    private String title;
    private String author;

    public Book(int bookTypeId, String title, String author) {
        this.bookTypeId = bookTypeId;
        this.title = title;
        this.author = author;
    }

    @Override
    public boolean equals(Object obj) { //equals 메서드 재정의

        if (obj instanceof Book) {
            //Book 타입이 맞고, 제목도 같다면 같은 책으로 판별해보자
            //this.title == title && 저자 == 저자
            if (this.title.equals(((Book) obj).title) && this.author.equals(((Book) obj).author)) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
   }
    /*
    equals 메서드를 재정의 할때는 haseCode 메서드를 재정의 해줘야
    의도하지 않은 동작을 막을 수 있다.

    hashCode
    이 객체의 고유한 정수값을 만들어서 독립성을 보장하는 정수 값이다.
     */

    @Override
    public int hashCode() {
        return bookTypeId;
    }

    //method - showInfo 대신 toString을 써보자
//    @Override
//    public String toString() {
//
//        return "title:" + title + ", author:" + author;
//    }

    //main - 테스트 코드
    public static void main(String[] args) {
        /*
        book1, boo2처럼
        물리적 객체 주소값은 다르지만
        equals 메서드를 재정의해서..

        논리적으로 책 이름과 저자 이름이 같다면
        같은 녀석으로 바라보도록
        프로그램을 짤 수는 없을까?
         */

        //object
        Book book1 = new Book(1, "데미안", "헤르만 헤세");
        Book book2 = new Book(1, "데미안", "헤르만 헤세");
        Book book3 = new Book(2, "자바", "홍길동");
        Book book4 = new Book(1, "데미안", "파울로코엘료");
        //두 객체는 내용은 같지만 주소값이 달라

        String stri1 = new String("데미안");

        System.out.println(book1.toString()); // toString: 객체의 주소값을 반환
        System.out.println(book2.toString());

        boolean result1 = book1.equals(book2);
        boolean result2 = book1.equals(stri1);
        boolean result3 = book1.equals(book3);
        boolean result4 = book1.equals(book4);

        System.out.println("result1: " + result1);
        System.out.println("result2: " + result2);
        System.out.println("result3: " + result3);
        System.out.println("result4: " + result4);

    }//end of main
}//end of class

 

내용이 같더라도 다른 객체들의 주소값은 모두 다르다.

 

소프트웨어 형상 관리
SCM
SW Config Mgt

버전관리시스템
VCS
Ver Ctr Sys

VCS에는 Git과 SVN 등이 있다. 

⭐Git 분산형 저장 시스템
⭐ SVN 중앙 집중형 저장 시스템

💀SVN은 안정성 문제.. 싹 날아갈 위험이 존재

 

👍그래서 원격지에 저장해 안정성을 높인 Git이 등장하게 됐다.

 

git은 데이터를 논리적인 3가지 상태로 분류한다.

working directory => staging area => repository ===> remote

저장소 안에 또 저장소를 쓸 수 없다.

 

git clone 주소
(git에 있는 코드들을 오프라인 폴더로 가져온다.)

⭐빈 공간에만 쓸 수 있다.

 

git init
(git 폴더 만들어짐)

git status

(폴더 상태 확인)

git -M main

(현 버전을 메인 브렌치로 설정)

 

branch
○ - ○ - ○
  └ ○ - ○


git add .
(요소들이 staging area에 옮겨짐)

git commit -m'버전명'

(요소들이 repository에 옮겨짐)

git push origin main

(요소들이 remote에 옮겨짐)

q

리셋


IDE인 인텔리제이는 Git 터미널을 제공하고 있다.

터미널 기능을 통해 코드를 작성하면서 바로바로 Git과 상호작용할 수 있다.

 

 

5번째 버전까지 누적된 모습

1.first commit 2.object class 3.string and stringbuffer 4.exception handling 5.thread...

 

4번째 버전으로 돌아가려면: 깃 체크아웃 헤드 캐럿

git checkout HEAD^

 

1번째 버전으로 돌아가려면:깃 체크아운 헤드 캐럿캐럿캐럿캐럿

git checkout HEAd^^^^

 

최신버전으로 돌아오려면

git checkout main

⭐인터페이스

Interface

객체의 동작을 정의하는 추상타입으로
클래스가 구현할 메서드의 설계도를 제공한다.

👍다형성
👍 유연성
👍 코드재사용성을 높일 수 있다.

 

예제 1)

인터페이스(동물 )

클래스(새,개)

설계를 통해 인터페이스 사용법을 알아봤다.

 

public interface Animal { //인터페이스

}

public class Bird implements Animal { //구현클래스

}

public class Dog implements Animal {  //구현클래스

}

package com.interface_.animal;
/**
 * 4.23 인터페이스
 *
 * How
 * Interface를 선언하면 된다.
 * 여기 안에 선언된 메서드는
 * 모두 추상메서드가 돼야 한다.
 *
 * Why?
 */
public interface Animal {

    //추상메서드 선언
    public abstract void eat(); // 메서드 선언부만 있고 바디가 없다.

    public void move(); // abstract 생략 가능

}//end of Animal
package com.interface_.animal;
/**
 * 4.23 인터페이스
 */
public class Bird implements Animal{

    @Override
    public void eat() {
        System.out.println("새가 모이를 먹는다");
    }

    @Override
    public void move() {
        System.out.println("새가 하늘을 난다");
    }
    
}//end of Bird
package com.interface_.animal;
/**
 * 4.23 인터페이스
 * <p>
 * 인터페이스는 상속이 아니라 구현받다, 구현하다 라고 말한다.
 * <p>
 * Animal 인터페이스를 구현받았다.
 */
public class Dog implements Animal {

    //추상메서드를 구현메서드로 재정의 해야 한다.
    @Override
    public void eat() {
        System.out.println("강아지가 먹이를 먹는다");
    }

    @Override
    public void move() {
        System.out.println("강아지가 달린다");
    }

    //main
    public static void main(String[] args) {

        //다형성 적용
        Animal dog = new Dog(); //업캐스팅 됐다
        Animal bird = new Bird();

        dog.eat();
        dog.move();
        System.out.println();
        bird.eat();
        bird.move();

    }//end of main

}//end of dog

 

예제 2)

인터페이스(리모콘,음향)

추상클래스(가전)

구현클래스(티비,냉장고,로봇,)

설계를 통해 인터페이스 사용법을 알아봤다.

 

⭐바텀업!

먼저 티비, 냉장고, 로봇 클래스를 만든 뒤

공통된 부분을 추상클래스로

동작 부분은 인터페이스로 선언해간다.

 

public interface RemoteController { //인터페이스

}

public interface SoundEffect { //인터페이스

}

 

public abstract class HomeAppliances { //추상클래스

}

 

public class TV extends HomeAppliances //추상클래스 상속

implements RemoteController, SoundEffect { //인터페이스 구현

}

public class Refrigerator extends HomeAppliances //추상클래스 상속

implements RemoteController , SoundEffect { //인터페이스 구현

}

public class Refrigerator implements Animal, SoundEffect { //인터페이스 구현

 

2-1.TV 클래스

package com.interface_.appliance;
/**
 * 4.23 인터페이스 2강
 */
public class Television extends HomeAppliances implements RemoteController {

//    //member
//    int width;
//    int height;
//    String color;
//
//    //method
//    public void turnOn() {
//        System.out.println("TV전원을 켠다");
//    }
//    public void turnOff() {
//        System.out.println("TV전원을 끈다");
//    }

    @Override
    public void turnOn() {
        System.out.println("티비 전원을 켠다");
    }

    @Override
    public void turnOff() {
        System.out.println("티비 전원을 끈다");
    }
    
}//end of TV

 

2-2.냉장고

package com.interface_.appliance;
/**
 * 4.23 인터페이스 2강
 */
public class Refrigerator extends HomeAppliances
        implements RemoteController, SoundEffect { // 인터페이스는 다중 구현이 가능하다.

    @Override
    public void turnOn() {
        System.out.println("냉장고 전원을 켠다");
    }

    @Override
    public void turnOff() {
        System.out.println("냉장고 전원을 끈다");
    }

    @Override
    public void soundOn() {
        System.out.println("냉장고 문이 열렸다고 경고한다");
    }
}//end of Refrige

 

2-3.장난감로봇

package com.interface_.appliance;
/**
 * 4.23 인터페이스 2강
 *
 * 지금처럼 장난감 로봇이 가전을 상속받는다면 혼동이 올 수 있다.
 *
 * 추상클래스보다
 * 더 유연한 설계기법이 필요하다.
 *
 * 그것이 인터페이스 Interface 다.
 */
public class ToyRobot implements RemoteController, SoundEffect {

    String name;

    @Override
    public void turnOn() {
        System.out.println("장난감 로봇을 켠다");
    }

    @Override
    public void turnOff() {
        System.out.println("장난감 로봇을 끈다");
    }

    @Override
    public void soundOn() {
        System.out.println("장난감 로봇이 소리를 낸다");
    }
    
}//end of TR

 

2-4.가전 (추상클래스)

package com.interface_.appliance;
/**
 * 4.23 인터페이스 2강
 */
public abstract class HomeAppliances implements RemoteController {

    //member
    int width;
    int height;
    String color;

//    //method
//    public void turnOn() {
//        System.out.println("전원을 켠다");
//    }
//    public void turnOff() {
//        System.out.println("전원을 끈다");
//    }

}//end of HA

 

2-5. 리모콘 (인터페이스)

package com.interface_.appliance;
/**
 * 4.23 인터페이스 2강
 *
 * 인터페이스 개념정리
 */
public interface RemoteController {

    /*
    ⭐인터페이스란

    구현된 것이 아무것도 없는
    밑 그림만 있는 기본 설계도다.

    모든 변수는 상수가 된다.
    public static final int N;

    모든 메서드는 추상메서드가 된다.
    심지어 abstract 키워드도 필요 없다.

    추상클래스보다 추상화 수준이 더 높다.

    ⭐Why
    인터페이스는
    동작 중심의 클래스를 선언해야 할 때 사용한다.

    인터페이스는 동작 중심이다.

    인터페이스는 표준이다.

    또는 강제성 있는 규약이다.
     */

    //오직 static final 상수만을 가질 수 있다.
    public static final int SERIAL_NUMBER = 100;

    //오직 abstract 추상 메서드만을 가질 수 있다.
    public abstract void turnOn();
    public void turnOff();

}//end of RemoteController

 

2-6. 음향(인터페이스)

package com.interface_.appliance;
/**
 * 4.23 인터페이스 2강
 */
public interface SoundEffect {

    //추상메서드
    public abstract void soundOn();

}//end of SE

 

2-7. 코드 실행부

package com.interface_.appliance;
/**
 * 4.23 인터페이스 2강
 */
public class MainTest1 {
    //main
    public static void main(String[] args) {
        /*
        인터페이스를 사용하면
        유연한 코드를 설계할 수 있다.
         */
        RemoteController[] remoteControllers = new RemoteController[3];

        remoteControllers[0] = new Television(); //다형성
        remoteControllers[1] = new Refrigerator();
        remoteControllers[2] = new ToyRobot();

        /*
        인터페이스는 표준이다.
        또는 강제성 있는 규약이다.
         */
        for (int i = 0; i < remoteControllers.length; i++) {
            remoteControllers[i].turnOn(); //한번에 모든 전원을 켰다.
        }

    }//end of main
}

 

예제 3)

다음 코드다이어그램(uml) 구현

 

 

Calc, 인터페이스로 작성

 

 

 

 

Claclator, 추상클래스로 작성

 

 

 

 

CompleteCalc, 구현클래스로 작성

 

 

 

⭐코드설계가 이미 완성돼 있다면

탑다운으로 작성하더라도 문제가 없다.

 

3-1.Calc(인터페이스) 작성

package com.interface_;
/**
 * 4.23 인터페이스 3강
 */
public interface Calc { //인터페이스 선언

    //인터페이스는 public abstract 생략 가능
    void add(int n1, int n2);
    void sub(int n1, int n2);
    void multi(int n1, int n2);
    void divide(int n1, int n2);

}//end of Calc

 

3-2. Calculator(추상클래스) 작성

package com.interface_;
/**
 * 4.23 인터페이스 3강
 */
public abstract class Calculator implements Calc {

}//end of Calculator

 

3-3. CompleteCalc(구현클래스) 작성

F2를 누르면 구현메서드를 딸깍하고 만들 수 있다.

package com.interface_;
/**
 * 4.23 인터페이스 3강
 */
public class CompleteCalc extends Calculator{

    @Override
    public void add(int n1, int n2) {

    }

    @Override
    public void sub(int n1, int n2) {

    }

    @Override
    public void multi(int n1, int n2) {

    }

    @Override
    public void divide(int n1, int n2) {

    }

}//end of CompleteCalc

 

 

 

⭐추상 클래스

abstract class

추상 메서드를 포함한 클래스

상속에서 사용되는 개념으로

객체로 만들기는 좀 애매할때 사용한다.

class 앞에 abstract가 붙으면 된다.


⭐추상 메서드

선언부만 있고 바디가 없는 형태

예 int add(int x, int y);

void 앞에 abstract가 붙으면 된다.

 

추상클래스를 (동물 - 인간, 호랑이) 관계를 통해 이해해봤다.

package com.abstract_.animal;
/**
 * 4.22 5교시 추상클래스
 * <p>
 * 추상클래스
 * abstract class
 * <p>
 * 하나 이상의 추상 메서드를 포함한 클래스
 * class 앞에 abstract가 뭍으면 추상클래스다.
 *
 * 강제적으로 타입으로만 설계하는 기법이다.
 *
 * abstract - 강제성
 */
public abstract class Animal { //추상클래스로 선언됐다.

    String name;

    public void move() {
        System.out.println("동물이 이동한다");
    }

    //추상메서드를 만들어보자
    public abstract void hunt();
    /*
    클래스 안에
    단 하나라도 추상 메서드를 가지고 있다면
    그 클래스는 반드시 추상 클래스가 돼야 한다.
     */

}//end of Animal

 

2. 자식클래스 호랑이

추상클래스를 상속받으면, 이렇게 오류가 발생한다. 해결방법은 1.자식클래스도 추상클래스로 변경 2.추상메서드를 구현메서드로 오버라이드 하는 방법이다.

package com.abstract_.animal;
/**
 * 4.22 5교시 추상클래스
 *
 * 추상클래스를 사용하는 이유
 *
 * 단 하나라도 추상메서드가 있으면 추상클래스다.
 */
public class Tiger extends Animal {

    @Override //오버라이드 하자 오류가 없어졌다
    public void hunt() {
        System.out.println("호랑이가 사냥을 한다");
    }

    @Override
    public void move() {
        System.out.println("호랑이가 살금살금 이동한다");
    }

}//end of Tiger

 

3.자식클래스이자 추상클래스인 인간을 설계해봤다.

package com.abstract_.animal;
/**
 * 4.22 5교시 추상클래스
 */
public abstract class Human extends Animal{


    @Override
    public void move() {
        System.out.println("사람이 두 발로 걷는다");
    }
}//end of Human

 

4. 인간 클래스의 자식클래스인 사람 클래스를 설계했다.

package com.abstract_.animal;
/**
 * 4.22 5교시 추상클래스
 */
public class Person extends Human{

    //구현 메서드로 만들어주면 된다.
    @Override
    public void hunt() {
        System.out.println("총으로 동물을 사냥한다");
    }
}//end of Person

 

5. 코드 실행부

추상클래스인 Animal, Human을 인스턴스화 하려고 하자 오류가 발생했다.

추상클래스를 객체 선언할 수 없다.

package com.abstract_.animal;
/**
 * 4.22 5교시 추상클래스
 */
public class MainTest1 {
    //main
    public static void main(String[] args) {
        /*
        객체지향 개념으로
        Animal이라는 클래스를 인스턴스화하면 좀 이상하다
         */
//        animal = new Animal(); // 오류발생

        /*
        Animal 클래스는
        abstract 키워드를 사용해
        추상 클래스로 설계됐다.

        추상 클래스는
        new 키워드 생성자를 활용해서
        독립적으로 메모리에 올릴 수 없다.

        개발자가 객체를 생성시킬 때
        다른 사용자가 마음대로 객체를 생성시키지 못하도록
        강제성을 줄 수 있다.
         */
//        Human human = new Human(); //오류 발생

    }//end of main
}//end of class

 

 

예제)

컴퓨터 - 데스크탑, 노트북 - 내노트북

상속관계와 추상클래스 처리 방법을 연습했다. 

 

1. 컴퓨터 클래스

package com.abstract_.computer;
/**
 * 4.22 5_1교시 추상클래스
 *
 * 추상클래스 상속
 * 메서드 오버라이드
 *
 * Computer
 * 부모클래스
 * 추상클래스
 */
public abstract class Computer {

    abstract void display();
    abstract void typing();

    void turnOn() { System.out.println("컴퓨터를 켭니다"); }
    void turnOff() { System.out.println("컴퓨터를 끕니다"); }

}//end of Computer

 

2-1. 데스크탑 클래스

구현클래스로 설계했다(완)

package com.abstract_.computer;
/**
 * 4.22 5_1교시 추상클래스
 * 구현클래스
 * Computer의 자식클래스
 */
public class DeskTop extends Computer {

    void display() { System.out.println("데스크탑 화면을 띄웁니다"); }
    void typing() { System.out.println("데스크탑에 문자를 입력합니다"); }

}//end of DeskTop

 

2-2. 노트북 클래스

추상클래스로 설계했다.

package com.abstract_.computer;
/**
 * 4.22 5_1교시 추상클래스
 * 추상클래스
 * Computer의 자식클래스
 */
public abstract class NoteBook extends Computer {

    void typing() { System.out.println("노트북에 글자를 입력합니다"); }

}//end of NoteBook

 

3. 내노트북 클래스

구현클래스로 설계했다(완)

package com.abstract_.computer;
/**
 * 4.22 5_1교시 추상클래스
 * 구현클래스
 * NoteBook의 자식클래스
 */
public class MyNoteBook extends NoteBook {

    void display() { System.out.println("내 노트북 화면을 띄웁니다"); }

}//end of MyNoteBook

 

4. 코드 실행부

데스크탑과 내노트북 클래스로 객체선언이 정상적으로 되는 것을 확인했다.

package com.abstract_.computer;
/**
 * 4.22 5_1교시 추상클래스
 * 코드 실행부
 */
public class ComperMainTest1 {
    //main
    public static void main(String[] args) {

        Computer computer1 = new DeskTop(); //다형성
        Computer computer2 = new MyNoteBook();

    }//end of main
}//end of class

 

⭐다형성
Polymorphism

하나의 데이터 타입을 다양한 형태로 바라볼 수 있다는 개념

한 요소가 여러 형태를 가질 수 있다는 가능성을 가리킨다.

⭐ 다형성의 장점은

부모 타입으로 자식 클래스를 인스턴스화 할 수 있다는 점이다.
이는 자바의 굉장한 기능이다.

다형성을 이해한다면
유연한 코드를 작성할 수 있다.

 

 

예제) 동물 클래스를 인간, 호랑이 클래스가 상속하게 하자

package com.polymorphism;
/**
 * 4.22 3교시 다형성
 */
public class Animal {

    public void move() {
        System.out.println("동물이 움직인다");
    }
    public void eat() {
        System.out.println("동물이 먹는다");
    }

}//end of Animal class

class Human extends Animal { // 상속 관계로 설정... 다형성

    @Override
    public void move() {
        System.out.println("사람이 걷는다");
    }
    @Override
    public void eat() {
        System.out.println("사람이 식사한다");
    }
    public void read() {
        System.out.println("사람이 읽는다");
    }

}//end of Human class

class Tiger extends Animal {

    @Override
    public void move() {
        System.out.println("호랑이가 활보한다");
    }
    public void hunt() {
        System.out.println("호랑이가 사냥한다");
    }

}//end of Tiger class

 

코드 테스트

package com.polymorphism;
/**
 * 4.22 3교시 다형성
 *
 * 다형성
 * 하나의 데이터 타입을 다양한 형태로 바라보는 것
 *
 * 한 메서드(클래스)가 여러 형태를 가질 수 있다.
 * 상속관계를 통해 다형성을 살펴본다.
 */
public class AnimalTest1 {
    //main
    public static void main(String[] args) {

        Animal animal1 = new Animal();
        animal1.move();
        animal1.eat();
        System.out.println();
        /*
        다형성의 장점

        부모 타입으로 자식 클래스를 인스턴스화 할 수 있다.

        이는 자바의 굉장한 기능
         */
        Animal animal2 = new Tiger(); //? 다형성.. 업캐스팅
        animal2.move();
        animal2.eat();
        System.out.println();
        /*
        코드를 작성하는 컴파일 시점
        프로그램을 실행하는 런타임 시점
         */
        Animal animal3 = new Human();
        animal3.move();
        animal3.eat();

    }//end of main
}//end of class

 

코드테스트2

package com.polymorphism;
/**
 * 4.22 3교시 다형성
 */
public class AnimalTest2 {

    //main
    public static void main(String[] args) {

        /*
        다형성
        하나의 메서드가
        여러 형태를 가질 수 있는 능력

        move()

        배열
        하나의 변수에 통으로 데이터를 관리하고 싶다면
         */
        Animal[] animals = new Animal[3];

        animals[0] = new Animal();
        animals[1] = new Tiger();
        animals[2] = new Human();

        for (int i = 0; i < animals.length; i++) {
            animals[i].move();
        }

    }//end of main
}//end of class



⭐업캐스팅 / 다운캐스팅

업캐스팅

부모클래스의 데이터타입으로
자식클래스의 객체를 대입하는 것을 말한다.

이는 자동으로 이뤄진다.

다운캐스팅

부모클래스의 참조변수를
자식클래스의 객체로 

((Banana) fruits[i]).saleBanana();

이 객체가 특정 클래스에 종속됐는지 확인하는 구문

if (fruits[i] instanceof Banana) {}

 

예제)

복숭아, 바나나 클래스를 만들고

부모클래스인 과일 클래스를 만들어보자

 

1. 복숭아 클래스

package com.polymorphism.fruits;
/**
 * 4.22 3_1교시 다형성
 *
 * 과일을 통해
 * 상속
 * 바텀업
 * 업캐스팅
 * 다운캐스팅 이해
 */
public class Peach extends Fruit {

//    String name;
//    int price;

    public Peach() {
        name = "춘식이복숭아";
        price = 5000;

    }

}//end of Peach

 

2. 바나나 클래스

바나나 클래스에는 고유의 멤버변수와 메서드를 넣었다.

package com.polymorphism.fruits;
/**
 * 4.22 3_1교시 다형성
 */
public class Banana extends Fruit {

    String ogrin; // Banana만의 멤버변수

        public Banana() {
            name = "델몬트바나나";
            price = 3000;
            ogrin = "필리핀";
        }

    public void saleBanana() {
        System.out.println("지금은 할인 기간입니다");
        System.out.println("이 방송이 나간 뒤(메서드호출) 바나나 가격을 천원 할인");
        price -= 1000;
    }

}//end of Banana

 

3. 부모클래스인 과일 클래스 설계

package com.polymorphism.fruits;
/**
 * 4.22 3_1교시 다형성
 */
public class Fruit {

    String name;
    int price;

    public Fruit() {
        name = "춘식이복숭아";
        price = 5000;

    }
    public void showInfo() {
        System.out.print("상품명: ");
        System.out.print(name + " ");
        System.out.print("가격: ");
        System.out.println(price + "원");
    }
}//end of Fruits

 

4. 코드 실행부

package com.polymorphism.fruits;
/**
 * 4.22 3_1교시 다형성
 *
 * 업캐스팅
 * 다운캐스팅
 */
public class FruitTest1 {
    //main
    public static void main(String[] args) {

        Fruit fruit1 = new Peach(); //업캐스팅된 상태
        Fruit fruit2 = new Banana();

        fruit1.showInfo();
        fruit2.showInfo();

        System.out.println();
        /*
        바나나의 원산지 정보를 출력하시오

        이 문제는
        컴파일 시점과 런타임 시점을 이해해야 한다.

        업캐스팅된 상태에서는
        컴파일 시점에 부모에 있는 변수나 메서드만 이해 가능
         */
        //fruit2.orign

        String reultOrigin = ((Banana)fruit2).ogrin; // 다운캐스팅
        System.out.println("바나나 원산지: " + reultOrigin);

        System.out.println();
        /*
        인스턴스오브 연산자
        instanceof
        ↳예약어

        다운캐스팅 관련 활용가능한 기능
         */

        if (fruit2 instanceof Banana) { // true
            System.out.println("바나나인가? true");
        }
        if (fruit2 instanceof Peach) { // false
            System.out.println("복숭아인가? true");
        }

        System.out.println();
        /*
        fruit2에 saleBanana() 메서드를 호출하시오
         */

        ((Banana)fruit2).saleBanana(); //다운캐스팅
        fruit2.showInfo();

    }//end of main
}//end of class

 

5. 다운캐스팅 연습을 위한 심화문제

package com.polymorphism.fruits;
/**
 * 4.22 3_1교시 다형성
 *
 * 업캐스팅
 * 다운캐스팅
 */
public class EMart {
    //main
    public static void main(String[] args) {

        Banana banana1 = new Banana();
        Banana banana2 = new Banana();
        /*
        배열
        배열을 사용할 때는
        반드시 크기를 먼저 지정한다.

        배열의 길이와
        요소의 길이는 항상 동일한 것은 아니다.
         */
        Banana[] bananas = new Banana[10];
        bananas[0] = banana1;
        bananas[1] = banana2;

        Peach[] peaches = new Peach[3];
        peaches[0] = new Peach();
        peaches[1] = new Peach();

        System.out.println();
        /*
        다형성
        다형성을 이해한다면
        유연한 코드를 작성할 수 있다.
         */
        Fruit[] fruits = new Fruit[5];
        fruits[0] = new Banana();
        fruits[1] = new Peach();
        fruits[2] = new Banana();
        fruits[3] = new Peach();
        /*
        문제
        배열 안에 들어있는 각각의 객체 showInfo 호출

        데이터타입이 바나나면
        원산지 정보와 세일 메서드를 호출하라
         */
        for (int i = 0; i < fruits.length; i++) {

            if (fruits[i] != null) {

                if (fruits[i] instanceof Banana) {
                    System.out.print((i + 1) + "번 ");
                    fruits[i].showInfo();
                    System.out.println("원산지: " + ((Banana) fruits[i]).ogrin);
                    ((Banana) fruits[i]).saleBanana();
                    System.out.println("===== ===== =====");
                } else {
                    System.out.print((i + 1) + "번 ");
                    fruits[i].showInfo();
                    System.out.println("===== ===== =====");
                }//end of if

            }//defensive

        }//end of for

    }//end of main

}//end of class

⭐연관관계
Association

두 클래스가 독립적으로 존재하면서 서로를 참조하거나 협력하는 관계

클래스 간의 느슨한 결합
두 객체의 생명주기는 종속되지 않는다. (생명주기 = 선언~GC)

 

ex)

학생과 과목

선수와 팀

이는 폭넓은 개념인데
포함관계도 연관관계의 일부다.
⭐ 내부에서 객체가 생성될 때 따로 포함관계라고 한다

1. 학생 클래스 설계

package com.association;
/**
 * 4.22 2교시 연관관계
 * 
 * 학생과 과목 클래스의 연관관계를 만들어본다
 */
public class Student {
    //member
    private String name;

    private Course course; //연관관계

    //constructor
    public Student(String name) {
        this.name = name;
        course = null; //수강 없음
    }

    //method
    /*
    1.강의를 듣는 메서드를 만든다.
    과목에 대한 정보는 Course에 있다.

    2.학생의 현재 수강상태를 보여주는 기능

    3.수강 종료 기능을 만들어보시오
     */

//    public void takeCourse(Course course) {
//        System.out.println(this.name + "의 수강 과목");
//        course.display();
//    }

    public void enroll(Course course) {
        this.course = course;
        System.out.println(name + ", " + course.getName() + " 과목 등록" );
    }

    public void showCourse() {
        if (this.course != null) {
            System.out.println(this.course.getName() + " 과목을 수강중입니다.");
        } else {
            System.out.println("수강중인 과목 없음");
        }
    }

    public void end(Course course) {
        if (course == null) {
            System.out.println("수강중이 아닙니다");
        } else {
            System.out.println(course.getName() + " 수강 취소");
            this.course = null;
        }
    }

}//end of Student

 

2. 과목 클래스 설계

package com.association;
/**
 * 4.22 2교시 연관관계
 *
 * 학생과 과목 클래스의 연관관계를 만들어본다
 */
public class Course {
    //member
    private String name;

    //constructor
    public Course(String name) {
        this.name = name;
    }

    //getter
    public String getName() {
        return name;
    }

    public void display() {
        System.out.println(name + "강의");
    }

}//end of Course

 

3. 코드 실행부

package com.association;
/**
 * 4.22 2교시 연관관계
 */
public class MainTest1 {
    //main
    public static void main(String[] args) {

        Student student = new Student("홍길동");

        Course java = new Course("자바");
        Course db = new Course("데이터베이스");

        student.showCourse(); //상태
        System.out.println();

        student.enroll(java); //강의등록
        student.showCourse(); //상태
        System.out.println();

        student.end(java); //수강취소
        student.showCourse(); //상태

    }//end of main
}//end of class

 

다음으로 선수와 팀을 만들어 연관관계를 만들어봤다.

 

1.선수 클래스 설계

package com.association;
/**
 * 4.22 2_2교시 연관관계
 */
public class Player {
    
    //member
    private String name;

    private Team team;

    //constructor
    public Player(String name) {
        this.name = name;
    }

    //getter
    public String getName() {
        return name;
    }

    //method - 입단
    public void join(Team team) {
        this.team = team;
        System.out.println(name + " " + team.getName() + " 입단");
    }

    //method - 탈단
    public void leave(Team team) {
        System.out.println(name + " " + team.getName() + " 탈단");
        this.team = null;
    }

    //method - 현황
    public void showRoster() {
        System.out.print(name + " 팀 현황: ");
        if (this.team != null) {
            System.out.println(this.team.getName());
        } else {
            System.out.println("소속 팀 없음");
        }
    }

}//end of Player

 

2.팀 클래스 설계

package com.association;
/**
 * 4.22 2_2교시 연관관계
 */
public class Team {

    //member
    private String name;

    private Player player; //연관관계

    //constructor
    public Team(String name) {
        this.name = name;
    }

    //getter
    public String getName() {
        return name;
    }

    //method - 영입
    public void recruit(Player player) {
        this.player = player;
        System.out.println(name + " " + player.getName() + " 선수 영입");
    }

    //method - 방출
    public void release(Player player) {
        System.out.println(name + " " + player.getName() + " 선수 방출");
        this.player = null;
    }

    //method - 현황
    public void showRoster() {
        System.out.print(name + " 선수 현황: ");
        if (this.player != null) {
            System.out.println(this.player.getName());
        } else {
            System.out.println("등록 선수 없음");
        }
    }

}//end of Team

 

3. 코드 실행부

package com.association;
/**
 * 4.22 2_2교시 연관관계
 */
public class MainTest2 {
    //main
    public static void main(String[] args) {
        Team team1 = new Team("롯데");
        Player player1 = new Player("장원준");

        team1.showRoster();
        System.out.println();

        team1.recruit(player1);
        team1.showRoster();
        System.out.println();

        team1.release(player1);
        team1.showRoster();
        System.out.println();

        player1.showRoster();
        System.out.println();

        player1.join(team1);
        player1.showRoster();
        System.out.println();
        
        player1.leave(team1);
        player1.showRoster();

    }//end of main
}//end of class

⭐접근제어지시자

 

+ public
  default
- private
# protected

 

# protected
접근제어지시자의 한 종류
자식클래스에서만 접근 가능하게 해준다.

package com.inheritance.animal;
/**
 * 4.22 1교시 상속 심화
 * xxx.java 파일에는 public을 가진 클래스는 오직 하나만 존재할 수 있다.
 */
//부모 클래스
class Animal {
    /*
    protected
    접근제어지시자의 한 종류
    자식클래스에서만 접근 가능하게 된다.
     */
    protected String name;

    void bark() {
        System.out.println(name + " 짖는 중");
    }

    void eat() {
        System.out.println(name + " 먹이 먹는 중");
    }
}//end of Animal

//자식 클래스1
class Dog extends Animal {

//    void bark() {
//        System.out.println(name + " 멍멍 짖는 중");
//    }

    @Override // 어노테이션 = 주석+힌트 : 부모클래스의 메서드 eat 오버라이드
    void eat() {
        // super.eat(); 기존 필드.. 필요하다면 사용
        // 강아지 전용 코드 작성
        System.out.println(name + "사료 먹는 중");
    }
}//end of Dog

//자식 클래스2
class Cat extends Animal {

//    void bark() {
//        System.out.println(name + " 야옹 하는 중");
//    }

    @Override
    void eat() {
        // super.eat();
        //고양이 먹는 모습 구현
    }
}//end of Cat

public class Main1 {
    //main
    public static void main(String[] args) {

        Dog dog = new Dog();
        dog.name = "바둑이";

        dog.eat(); // 부모클래스 메서드 호출
        dog.bark(); // 자식클래스 메서드 호출

    }//end of main
}//end of class

/**
 * 보다 일반적인 개념이 부모클래스가 된다. 동물 <= 개
 */

package com.inheritance.animal;
/**
 * 4.22 1교시 상속 심화
 */
public class AnimalTest {
    //main
    public static void main(String[] args) {

        Dog dog = new Dog();
        dog.name = "멍멍이";
        dog.bark();

        Cat cat = new Cat();
        cat.name = "야옹이";
        cat.bark();

    }//end of main
}//end of class

 

⭐상속 실무팁

탑 다운(부모 => 자식)으로 접근하면 문제가 발생할 가능성이 높아진다.
바텀 업(자식 => 부모)으로 접근하는 것이 안전

또한 강한의존성은 문제를 키울 위험이 있다.
따라서 유연하게 묶는 것이 안전

⭐포함관계
Compositon

한 클래스가 다른 클래스를 포함하는 관계다.

"has a"

⭐ 강한 연관성(필수적)

단, 상속과는 다르다

 

 

포함관계를 이해하기 위해

 

차와 엔진을 코드로 간략히 구현해봤다.

 

차와 엔진은 강한 연관성(필수적)을 가지고 있다.

 

1. 엔진

package com.composition;
/**
 * 4.21 포함개념 8
 */
public class Engine {

    //멤버변수설계
    String name;
    int price;

    //메서드
    void start() {
        System.out.println("start() 엔진을 구동합니다.");
    }

    void stop() {
        System.out.println("stop() 엔진을 정지합니다.");
    }

}// end of Engine

/**
객체지향 패러다임 고민

Q 차와 엔진을 상속관계에 둬도 될까?

A 안된다 💀
 */

 

2. 차

차가 움직이려면 먼저 엔진이 가동해야 한다.

package com.composition;
/**
 * 4.21 포함개념 8
 */
public class Car {

    //멤버변수설계
    String name;
    int price;
    /*
    ⭐Car 클래스는 Engine 객체를 포함한다.
    포함관계(Compositoion)
     */
    Engine engine;

    //생성자
    public Car(String name, int price) {
        this.name = name;
        this.price = price;

        /*
        자동차 객체가 생성될 때 엔진 객체도 함께 생성된다.
        포함관계
        ⭐강한의존성
         */
        engine = new Engine();
    }

    //메서드
    void startCar() {

        //car 객체를 통해 engine의 start(); 메서드를 호출한다
        engine.start();
        System.out.println("startCar() 자동차가 움직입니다.");
    }

    void stopCar() {

        engine.stop();
        System.out.println("stopCar() 자동차가 멈춥니다.");
    }
//테스트코드작성
    public static void main(String[] args) {

        /*
        ⭐컴포지션 관계란

        자동차 클래스 내부에서
        엔진 객체를 생성시켜야 컴포지션 관계다
         */

        Car car = new Car("소나타", 1000);
        car.startCar(); // 시동걸기

        System.out.println();
        car.stopCar(); // 시동끄기

    }//main

} // end of Car

 

또 다른 포함관계 예제

 

PC와 CPU 역시 강한 연관성(필수적)을 가지고 있다.

 

1.CPU

package com.composition;
/**
 * 4.21 포함개념 8_1
 */
public class CPU {

    //멤버변수
    private String name;
    private int id;

    //메서드

    void startCPU() {
        System.out.println(this.name + "CPU 가동");
    }

    void stopCPU() {
        System.out.println(this.name + "CPU 정지");
    }

}//end of CPU

 

2. PC

package com.composition;
/**
 * 4.21 포함개념 8_1
 */
public class PC {

    //멤버변수
    private String name;
    private int id;

    //CPU 객체 선언
    CPU cpu;

    //생성자
    PC(String name, int id) {
        this.name = name;
        this.id = id;

        cpu = new CPU();
    }

    //메서드
    void startPC() {
        cpu.startCPU();
        System.out.println(this.name + " PC 가동");
    }
    void stopPC() {
        cpu.stopCPU();
        System.out.println(this.name + "PC 정지");
    }

    //main
    public static void main(String[] args) {

        PC pc1 = new PC("삼보", 1113);
        PC pc2 = new PC("현대", 4321);

        pc1.startPC();
        pc1.stopPC();

        System.out.println();

        pc2.startPC();
        pc2.stopPC();

    }//end of main

}//end of PC

 

다른 형태의 포함관계를 생각해보자.

 

집과 방도 강한 연관성(필수적)을 가지고 있다.

 

1. 방

package com.composition;
/**
 * 4.21 포함개념 8_2
 */
public class Room {

    private String type;

    public Room(String type) {
        this.type = type;
    }

    void descrive() {
        System.out.println(this.type + " 입니다.");
    }
}// end of Room

 

2. 집

 

집은 여러개의 방으로 구성돼 있다.

 

반복되는 부분이 있는 점을 고려해

 

배열과 반복문을 응용해서 넣어봤다.

package com.composition;
/**
 * 4.21 포함개념 8_2
 */
public class House {

    private String address;
    Room[] rooms;

    public House(String address) {
        this.address = address;

        this.rooms = new Room[3];

        rooms[0] = new Room("1.거실");
        rooms[1] = new Room("2.침실");
        rooms[2] = new Room("3.주방");

        //속성으로 선언되고
        //내붸서 객체생성
        //컴포지션이다.
        //room = new Room(type:"안방");
    }

    void showRoom() {
        System.out.println(address+ "에 있는 한 주택의 방 목록: " );
        for (int i = 0; i < rooms.length; i++) {
            if (rooms[i] != null) {
                rooms[i].descrive();
            }
        }
    }

    //테스트
    public static void main(String[] args) {
        House house = new House("부산시진구");
        house.showRoom();

        //house 객체가 소멸이 되면 rooms 도 Room 객체도 소멸
        //GC에 의해 소멸
        house = null;
    }//end of main

}//end of House

+ Recent posts