no image
🖌️ GC(Garbage Collection) - 쓰레기통 파해치기
GC(Garbage Collection)는 Java에서 자동으로 메모리를 관리해 주는 메커니즘이다. 프로그래머가 메모리를 관리하지 않아도 사용되지 않는 객체(Garbage)를 JVM이 알아서 제거하기 때문에 메모리 누수를 사전에 방지할 수 있고 애플리케이션이 안정적으로 동작하도록 해준다.📍 GC의 동작 방식Java에서 객체가 생성되면, Heap Memory Area에 할당된다. 하지만 객체가 생성된 뒤로 메모리 관리를 해주지 않게 되면 애플리케이션에 문제가 발생 할 수 있다. 그리고 만약 이 작업을 개발자가 하게 된다면 매우 번거로운 작업이 된다.  하지만 GC(Garbage Collection)는 이 작업을 대신 해준다. GC(Garbage Collection)는 참조되지 않는 객체들을 자동으로 탐지..
2024.09.19
no image
[디자인 패턴]GoF 디자인 패턴
💡 1995년 GoF(Gang of Four)라고 불리는 Erich Gamma, Richard Helm, Ralph Johnson, John Vissides가 처음으로 디자인 패턴을 구체화하였다.GoF의 디자인 패턴은 소프트웨어 공학에서 가장 많이 사용되는 디자인 패턴이다.목적에 따라 분류할 시 생성 패턴 5개, 구조패턴 7개, 행위 패턴 11개 총 23개의 패턴으로 구성된다. 🤷‍♂️GoF 디자인 패턴 GoF디자인 패턴을 분류하는 기준은 두 가지이다. 목적에 따라 분류하면 생성 ,구조, 행동 3가지로 나눌 수 있다. 각각의 패턴이 어떤 일을 하기 위한 것인지에 관한 것이다. 생성 패턴은 객체의 생성 과정에 관여, 구조 패턴은 객체의 합성에 관여, 행동 패턴은 객체가 상호 작용하는 방법이나 관심사를 분리..
2022.03.15
no image
[JAVA]반복문 안에서 List 요소 삭제
for Loop를 이용해서 List 순회 중에 , 어떤 요소를 삭제하면 EXCEPTION이 발생하거나 요소를 탐색하지 못하는 문제가 발생할 수 있다. 문제점 CooncurrentModificationException 발생 가능성 반복문에서 순회 중, 일부 요소가 탐색에서 누락될 수 있는 가능성 반복문 순회 중, 일부 요소가 탐색에서 누락될 수 있는 가능성아래 코드처럼 for loop에서 list의 특정 요소를 삭제하게 되면 ConcurrentModificationException이 발생할 수 있다. 순회 중에 리스트의 요소을 삭제 했을 때, 다음에 참조하는 요소의 인덱스가 list의 범위를 벗어 나게 된다. 이 상황에서 예외가 발생한다. 🏴문제점 1 : ConcurrentModificationExcept..
2022.03.04
no image
[Code] Refactoring , 리펙토링
리펙토링이란 일련의 리펙토링을 적용하여 겉으로 보이는 동작의 변화없이 소프트 웨어 구조를 바꾸는 것이다. 리펙토링은 외부 동작을 바꾸지 않고 내부 구조를 개선하는 방법이기도하고 , 코드가 작성된 후 디자인을 개선하기도 한다. 리펙토링은 처음부터 좋은 방법을 생각하기 보다 개발해가면서 지속적으로 좋은 디자인을 찾는것이 좋다. 🔓리펙토링의 목적 소프트 웨어를 보다 이해하기 쉽고, 수정하기 쉽도록 만드는 것이고 리펙토링은 겉으로 보이는 소프트웨어의 기능은 변경하지 않는 것이다. 🔓리펙토링을 하는 이유 코드의 구조가 망가지면 당시에는 괜찮을 수 있으나 망가진 구조의 효과는 계속 누적된다. 코드의 디자인을 유지하도록 해주고 불필요한 중복을 제거함으로써 각각의 작업에 대한 코드가 한 곳에만 있게 할 수 있다. 소프..
2022.02.28
no image
[Design Pattern] 빌더 패턴(Builder Pattern)
🛠 Builder Pattern 이란 객체의 생성 단계들을 캡슐화하여 객체의 생성을 유연하게 해주는 패턴입니다. 그래서 빌더 패턴은 생성자에 들어갈 매개 변수가 많든 적든 차례대로 매개 변수를 받아들이고 모든 매개 변수를 받은 뒤에 이 변수들을 통합해서 한 번에 사용합니다. 🛠 Builder Pattern Builder Pattern의 장점에 대한 예시를 알아보자. Builder Pattern의 장점은 다음과 같은 것들이 있다. 가독성을 높일 수 있다. 불변성을 확보할 수 있다. 필요한 데이터만 설정이 가능하다. 이제 예시를 차근차근 보자 🛠첫번째로 어떤 측면에서 가독성을 높여주는지 알아보자. public class User { private Long id; private String email; pri..
2021.12.02
no image
[JAVA]Optional이란?
➡️Optional이란? Java8에서 Optional클래스를 사용해 NPE(NullPointException)을 방지할 수 있도록 도와준다.Optional는 null이 올 수 있는 값을 감싸는 Wrapper 클래스로, 참조하더라도 NPE가 발생하지 않도록 도와준다. Optional 클래스는 value에 값을 저장하기 때문에 value가 null이어도 NPE를 발생시키기 않는다. ➡️NPE(NullPointException) 우리가 개발을 할때 가장 많이 발생하고 힘들게하는 예외 중 하나가 NPE(NullPointException)이다. NPE(NullPointException)를 발생시키지 않을려면 null을 검증하는 로직을 추가 해야 하는데 , null을 검증해야하는 변수가 많으면 많을수록 코드가 지..
2021.06.17
no image
[JAVA]상속(Inheritance)
👉상속이란? 새로운 클래스를 정의 할 때 이미 구현된 클래스를 상속(inheritance) 받아서 속성이나 기능을 확장하여 클래스를 구현함 이미 구현된 클래스보다 더 구체적인 기능을 가진 클래스를 구현해야 할때 기존 클래스를 상속함 상속하는 클래스 : 상위 클래스, parent class, base class, super class 상속받는 클래스 : 하위 클래스, child class, derived class, subclass 👉상속 문법 class b extends a{ //a가 b를 상속한다 } 👉상속을 구현하는 경우 상위 클래스는 하위 클래스 보다 더 일반적인 개념과 기능을 가진다. 하위 클래스는 상위 클래스 보다 더 구체적인 개념과 기능을 가진다. 하위 클래스가 상위 클래스의 속성과 기능을 확..
2021.06.16
no image
[JAVA]삼항연산자(Ternary Operator)
👉삼항연산자란? 3개의 피연산자를 필요로 하는 연산자이다. 👉문법 문법은 어려운 편은 아니다. true/false를 판단할 수 있는 변수 또는 조건식을 작성한 후에 연산결과인 true/false에 실행되는 표현식을 작성하면 된다. 조건식의 결과가 false이면 식2가 결과가 되고 true이면 식 1이 결과가 된다. 1 2 3 int b1 = (5>4) ? 50 : 40; //조건식이 true이므로 결과값은 50이 나온다.​ cs 🙉가장 기본적인 예제이다. 1 2 3 4 5 6 7 8 //(조건식1) ? true : (조건식2) ? true : false //조건식1이 false이면 조건식2를 수행한다.조건식2는 일반 삼항 연산자처럼 실행된다. //삼항연산자를 중첩해서 사용하면 if문 대신에 사용할 수 있..
2021.06.15
728x90

GC(Garbage Collection)는 Java에서 자동으로 메모리를 관리해 주는 메커니즘이다. 프로그래머가 메모리를 관리하지 않아도 사용되지 않는 객체(Garbage)를 JVM이 알아서 제거하기 때문에 메모리 누수를 사전에 방지할 수 있고 애플리케이션이 안정적으로 동작하도록 해준다.

📍 GC의 동작 방식

Java에서 객체가 생성되면, Heap Memory Area에 할당된다. 하지만 객체가 생성된 뒤로 메모리 관리를 해주지 않게 되면 애플리케이션에 문제가 발생 할 수 있다. 그리고 만약 이 작업을 개발자가 하게 된다면 매우 번거로운 작업이 된다. 

 

하지만 GC(Garbage Collection)는 이 작업을 대신 해준다. GC(Garbage Collection)는 참조되지 않는 객체들을 자동으로 탐지하여 제거해준다.

 

자바 개발자라면 크게 신경 쓰지 않았을 것이다. GC(Garbage Collector)가 뒤에서 열심히 객체 메모리 관리 작업을 해주고 있다는 것만 알아두자( 가끔 모니터를 보고 GC야 고마워라고 작게 말하는 것도 좋을 것 같다.)

 

 GC(Garbage Collection)의 단계

📍 Mark

Mark 단계는 GC가 Heap Memory에서 어떤 객체가 여전히 사용 중인지 확인하는 단계

📍 Sweep

마크되지 않은(미사용 객체) 객체들을 실제로 메모리에서 제거하는 과정이다. 미사용 객체를 제거해서 메모리 공간을 확보한다.

📍 Compact

GC가 수행하는 최적화 작업 중 하나, 메모리 단편화 방지를 위해 살아있는 객체들은 Heap Memory 한쪽으로 이동시켜 연속된 메모리 공간을 확보한다. 파편화된 메모리를 한 곳에 모아 최적화된 메모리를 제공할 수 있다.

📍 Evacaution

Evacuation 단계는 Generational GC에서 주로 사용되며, Young Generation에서 Old Generation으로 객체를 이동시키는 과정이다. 

젊은 객체들은 Young Generation에서 빠르게 수거되지만, 오랫동안 살아남은 객체들은 Old Generation으로 이동되어 장기적으로 관리된다. 

이 작업으로 인해 Old Generation이 Young Generation 자리를 불필요하게 점유하는 것을 방지할 수 있다.

📍 Concurrent

Concurrent 단계ZGC, Shenandoah, CMS와 같은 GC에서 사용되며, 대부분의 작업을 애플리케이션과 동시에 수행하는 단계이다.

해당 단계는 애플리케이션 실행과 GC 작업을 병렬로 진행하여 Stop-the-World 시간을 최소화

 

실제로 GC가 어떻게 동작하는지 한번 예제를 보자 

import java.util.ArrayList;
import java.util.List;

public class EX_GC {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        
        for (int i = 0; i < 1000000; i++) {
            list.add(new Object()); // 객체를 계속 생성하여 메모리를 채움
            if (i % 10000 == 0) {
                list.clear(); // 일정 주기마다 리스트를 비워서 GC 대상 객체로 만듦
            }
        }
       
    }
}

우선 EX_GC라는 파일을 생성했다. 위 코드를 보면 객체가 무분별하게 생성된다. GC를 실행시키기 위한 임의의 코드이다.

javac EX_GC.java

우선 텍스트 파일을 컴파일한다.

java -Xms16M -Xmx16M '-Xlog:gc*:file=gc.log:time' EX_GC

 

이제 힙 메모리 공간을 설정하고 GC 로그를 활성화한 다음 Java를 실행시키면 GC가 동작하는 걸 볼 수 있다.

 

 

GC가 동작하면 위 그림처럼 로그가 발생한다. 만약에 메모리가 부족해서 java 실행이 실패하면 로그에

이런 식으로 로그가 남을 것이다. 이제 로그를 몇 개만 까보자 

Heap region size: 1M

 힙 메모리는 1MB 크기의 여러 영역(region)으로 나뉘어 관리되고 있다.

Using G1

JVM이 G1 GC를 사용하고 있음을 나타낸다.

Heap address, size: 16MB

힙 메모리의 주소와 크기 정보이다.

GC(0) Pause Young (Normal) (G1 Evacuation Pause)

이 로그는 첫 번째 GC 이벤트를 의미한다.

GC(0) Pause Young (Normal) (G1 Evacuation Pause) 7M->0M(16M) 0.520ms

첫 번째 GC 후, 힙 메모리 사용량이 7MB에서 0MB로 줄어들었고, 전체 힙 크기는 16MB이다. GC 이벤트는 0.520ms의 짧은 시간 동안 발생했다.

Heap

GC 후 힙 메모리 상태를 보여줍니다. 총 16MB의 힙에서 현재 1.772MB가 사용 중이며, GC 후 Eden 영역에서 살아남은 객체가 3개의 Young 영역에 위치해 있습니다.

(로그는 하나하나 설명하면 루즈해질 것 같아서 몇 개 빼곤 생략했다. 모르는 게 있으면 얼마든지 댓글로 남겨주시면 감사하겠습니다.)

 


이제 GC의 기본적인 동작은 모두 봤으니 GC의 종류를 한번 보자 (이번글의 핵심이기도 하다)

 

📍 GC의 종류

Java에서는 다양한 GC 알고리즘이 제공되며, 각 알고리즘은 서로 다른 성능 특성과 목적을 가지고 있다.

 

1. Serial GC

Java 1.2에 도입되었고 단일 스레드로 GC를 처리한다.

작은 애플리케이션에서 적합하며, Stop-the-World 시간이 길 수 있다.

-XX:+UseSerialGC 옵션으로 사용.

 

2. Parallel GC

Java 1.4에 도입되었고  여러 스레드로 동시에 GC를 처리하여 병렬로 수행된다.

대규모 애플리케이션에서 힙 메모리 관리에 효과적이다.

-XX:+UseParallelGC 옵션으로 사용.

 

3. CMS (Concurrent Mark-Sweep) GC

Java 1.5에 도입되었고응답 시간이 중요한 애플리케이션에서 사용됩니다.

마킹과 스윕 단계를 애플리케이션과 병렬로 수행하여 Stop-the-World 시간을 줄입니다.

-XX:+UseConcMarkSweepGC 옵션으로 사용.

 

4. G1 GC (Garbage First)

Java 1.7부터 시범운영을 하고 Java 9부터 기본 GC로 사용되며, 대규모 애플리케이션에서 성능을 최적화하기 위해 설계되었습니다.

힙 메모리를 여러 개의 작은 영역으로 나누고, 우선적으로 가비지가 많은 영역을 먼저 정리합니다.

-XX:+UseG1 GC 옵션으로 사용.

 

5. ZGC (Z Garbage Collector)

Java 11에 도입된 최신 GC로, 대용량 힙에서도 매우 짧은 Stop-the-World 시간을 보장한다(10ms 이하).

초대형 메모리 시스템을 위해 설계되었으며, 거의 실시간에 가까운 GC 처리가 가능하다.

하지만 ZGC는 기본 GC가 아니고 시범운영만 했지만 java 15부터는 기본 기능으로 사용이 가능하다.

작업 병렬화: 대부분의 GC 작업을 애플리케이션과 병렬로 수행한다. Stop-the-World 시간이 매우 짧고, 큰 힙 메모리에서도 10ms 이하의 지연 시간을 유지할 수 있다.

컬러드 포인터(Colored Pointers): ZGC는 “컬러드 포인터”라는 기술을 사용해 객체 참조를 추적하고, 객체가 이동할 때도 애플리케이션이 중단되지 않도록 한다. 이로 인해 매우 빠른 GC 작업이 가능하다.

대용량 힙에 적합: 수백 GB에서 몇 TB의 힙 메모리에서도 효율적으로 작동하며, 메모리 사용량이 매우 큰 애플리케이션에 적합하다.

-XX:+UseZGC 옵션으로 사용.

 

6. Shenandoah GC

CMS와 비슷하지만 더욱 짧은 Stop-the-World 시간을 제공하며, 대규모 멀티스레드 환경에 적합하다.

병렬 및 동시성: Shenandoah는 거의 모든 GC 작업을 애플리케이션과 동시에 수행한다. 힙 메모리가 매우 크더라도 지연 시간을 최소화하며, 대규모 멀티코어 환경에서 효율적으로 동작한다.

동시 압축(concurrent compaction): Shenandoah는 힙 메모리의 조각화를 방지하기 위해, 객체 이동 및 압축 작업도 애플리케이션과 동시에 수행할 수 있다.

동시 마킹과 스윕: 객체의 생존 여부를 확인하는 마킹 단계와 메모리 해제 작업을 동시에 처리하여 성능을 향상한다.

-XX:+UseShenandoahGC 옵션으로 사용.

 

자 이런 변천사를 봤는데 공통적인 포인트가 있다. Stop-the-World (멈춰! 그 세계)가 공통적으로 들어있다. 점점 루즈해지니 빨리 설명하겠다.

 

Stop-the-World란?

Stop-the-World는 GC가 실행되는 동안 JVM이 모든 애플리케이션 스레드를 일시 중지하고, GC 작업에 필요한 메모리 정리를 완료할 때까지 기다리는 시간을 의미한다. GC는 힙 메모리에서 객체를 수집할 때, 애플리케이션이 메모리를 사용할 수 없도록 하기 위해 이런 일시 중단을 발생시킨다.

 

Stop-the-World가 발생하는 이유

메모리 관리 작업은 매우 중요한 작업으로, 메모리의 일관성을 유지하기 위해 GC는 애플리케이션의 스레드가 메모리 객체를 동시에 변경하지 않도록 모든 스레드를 멈추게 한다. 이것이 Stop-the-World 이벤트이다.

 

  • Serial GC는 단일 스레드라 Heap Memory가 커질수록 Stop-the-World가 길어진다.
  • Parallel GC는 병렬 스레드긴 하지만 Stop-the-World 시간이 상대적으로 길고, 애플리케이션 성능에 영향을 미칠 수 있다.
  • CMS, G1 GC는 Stop-the-World 시간을 줄이려는 목표를 가지고 있으며, 애플리케이션과 병렬로 GC 작업을 수행한다.
  • ZGC와 Shenandoah는 가장 짧은 Stop-the-World 시간을 목표로 하며, 대부분의 GC 작업을 애플리케이션과 동시에 처리하여, 매우 짧은 지연 시간(10ms 이하)을 유지한다.

성능영향? 멈춘다? 개발자들은 알레르기 반응이 슬슬 올라올 거다. 하지만 자바 8 이상이라면 두 눈 뜨고 실제로 보긴 힘들 거다.(그 이하버전을 쓰신다면 유감입니다.) 

GC가 메모리 정리를 효율적으로 마칠 때까지 모든 애플리케이션 스레드는 멈추게 된다. 그러나 Stop-the-World 시간이 너무 길어지면 애플리케이션 성능에 큰 영향을 미칠 수 있다. 이를 최소화하는 것이 GC의 주요 목표 중 하나이다.  

 

개념적인 내용은 끝이 났다. GC를 이렇게 글로 다룬 이유는 갑자기 개발을 하다가 GC를 파보고 싶어서 파 봤는데 내가 그냥 GC? 그거 메모리 비워주고 관리해 주는 거 아니야?라고 생각했던 나 자신 반성하도록,,,,,,개인적으로 재밌었다. 다음 성능개선점을 찾을 때 이게 도움이 될지는 모르지만 뭔가 언젠간 분명 이게 차별점이 될 거라 믿는다.


아 그리고 ZGC는 따로 한번 더 다뤄볼 예정이다.

 


📍 참고자료

https://coderstea.in/post/java/get-ready-to-deep-dive-java-memory-management-garbage-collector/

https://www.geeksforgeeks.org/garbage-collection-java/

https://d2.naver.com/helloworld/1329

728x90

'Dev > JAVA' 카테고리의 다른 글

[디자인 패턴]GoF 디자인 패턴  (0) 2022.03.15
[JAVA]반복문 안에서 List 요소 삭제  (0) 2022.03.04
[Code] Refactoring , 리펙토링  (0) 2022.02.28
[Design Pattern] 빌더 패턴(Builder Pattern)  (0) 2021.12.02
[JAVA]Optional이란?  (0) 2021.06.17
728x90
💡 1995년 GoF(Gang of Four)라고 불리는 Erich Gamma, Richard Helm, Ralph Johnson, John Vissides가 처음으로 디자인 패턴을 구체화하였다.GoF의 디자인 패턴은 소프트웨어 공학에서 가장 많이 사용되는 디자인 패턴이다.목적에 따라 분류할 시 생성 패턴 5개, 구조패턴 7개, 행위 패턴 11개 총 23개의 패턴으로 구성된다.

🤷‍♂️GoF 디자인 패턴

GoF디자인 패턴을 분류하는 기준은 두 가지이다.

  1. 목적에 따라 분류하면 생성 ,구조, 행동 3가지로 나눌 수 있다. 각각의 패턴이 어떤 일을 하기 위한 것인지에 관한 것이다. 생성 패턴은 객체의 생성 과정에 관여, 구조 패턴은 객체의 합성에 관여, 행동 패턴은 객체가 상호 작용하는 방법이나 관심사를 분리하는 방법이다.
  2. 범위에 따라 분류도 가능하다. 패턴을 주로 클래스에 적용하는지, 객체에 적용하는 지 구분하는 것이다. 클래스 패턴은 클래스와 서브 클래스 간의 관령성을 다룬다. 주로 상속을 통해 관련되며, 컴파일 타임에 정적으로 결정된다. 객체 패턴은 객체 간의 관련성을 다루고, 런타임에 변경될 수 있는 동적인 성격을 가진다.

 

🔨생성 패턴

생성 패턴은 객체의 생성과 관련된 패턴이다. 객체의 인스턴스 과정을 추상화하는 방법이다. 객체의 생성과 참조 과정을 캡슐화하며 객체가 생성되거나 변경되어도 프로그램 구조에 영향을 받지 않도록 하여 프로그램에 유연성을 더해준다.생성 클래스 패턴은 객체를 생성하는 일부를 서브 클래스가 담당하도록 하며, 생성 객체 패턴은 객체 생성을 다른 객체에게 위임한다.

추상 팩토리(Abstract Factory) 구체적인 클래스를 지정하지 않고 인터페이스를 통해 서로 연관되는 객체들을 그룹으로 표현함
빌더(Builder) 복합 객체의 생성과 표현을 분리하여 동일한 생성 절차에서도 다른 표현 결과를 만들어낼 수 있음
팩토리 메소드(Factory Method) 객체 생성을 서브클래스로 위임하여 캡슐화함
프로토타입(Prototype) 원본 객체를 복사함으로써 객체를 생성함
싱글톤(Singleton) 어떤 클래스의 인스턴스는 하나임을 보장하고 어디서든 참조할 수 있도록 함

 

🔨구조 패턴

구조 패턴은 클래스나 객체들을 조합해 더 큰 구조로 만들 수 있게 해주는 패턴이다. 구조 클래스 패턴은 상속을 통해 클래스나 인터페이스를 합성하고, 구조 객체 패턴은 객체를 합성하는 방법을 정의한다.

어댑터(Adapter) 클래스의 인터페이스를 다른 인터페이스로 변환하여 다른 클래스가 이용할 수 있도록 함
브리지(Bridge) 구현부에서 추상층을 분리하여 각자 독립적으로 확장할 수 있게 함
컴포지트(Composite) 객체들의 관계를 트리 구조로 구성하여 복합 객체와 단일 객체를 구분없이 다룸
데코레이터(Decorator) 주어진 상황 및 용도에 따라 어떤 객체에 다른 객체를 덧붙이는 방식
퍼싸드(Facade) 서브시스템에 있는 인터페이스 집합에 대해 하나의 통합된 인터페이스(Wrapper) 제공
플라이웨이트(Flyweight) 크기가 작은 여러 개의 객체를 매번 생성하지 않고 가능한 한 공유할 수 있도록 하여 메모리를 절약함
프록시(Proxy) 접근이 어려운 객체로의 접근을 제어하기 위해 객체의 Surrogate나 Placeholder를 제공

 

🔨행위 패턴

행위 패턴은 클래스나 객체들이 서로 상호작용하는 방법이나 어떤 태스크, 어떤 알고리즘을 어떤 객체에 할당하는 것이 좋을지를 정의하는 패턴이다. 즉, 객체나 클래스의 교류 방법에 대해 정의하는 것이다. 행위 패턴은 하나의 객체로 수행할 수 없는 작업을 여러 객체로 분배하면서 그들 간의 결합도를 최소화 할 수 있도록 도와준다. 행위 클래스 패턴 은 상속을 통해 알고리즘과 제어 흐름을 기술하고, 행위 객체 해턴 은 하나의 작업을 수행하기 위해 객체 집합이 어떻게 협력하는지를 기술한다.

책임 연쇄(Chain of Responsibility) 요청을 받는 객체를 연쇄적으로 묶어 요청을 처리하는 객체를 만날 때까지 객체 Chain을 따라 요청을 전달함
커맨드(Command) 요청을 객체의 형태로 캡슐화하여 재사용하거나 취소할 수 있도록 저장함
인터프리터(Interpreter) 특정 언어의 문법 표현을 정의함
반복자(Iterator) 내부를 노출하지 않고 접근이 잦은 어떤 객체의 원소를 순차적으로 접근할 수 있는 동일한 인터페이스 제공
중재자(Mediator) 한 집합에 속해있는 객체들의 상호작용을 캡슐화하여 새로운 객체로 정의
메멘토(Memento) 객체가 특정 상태로 다시 되돌아올 수 있도록 내부 상태를 실체화
옵서버(Observer) 객체 상태가 변할 때 관련 객체들이 그 변화를 통지받고 자동으로 갱신될 수 있게 함
상태(State) 객체의 상태에 따라 동일한 동작을 다르게 처리해야할 때 사용
전략(Strategy) 동일 계열의 알고리즘군을 정의하고 캡슐화하여 상호교환이 가능하도록 함
템플릿 메소드(Template Method) 상위클래스는 알고리즘의 골격만을 작성하고 구체적인 처리는 서브클래스로 위임함
방문자(Visitor) 객체의 원소에 대해 수행할 연산을 분리하여 별도의 클래스로 구성함
728x90
728x90

for Loop를 이용해서 List 순회 중에 , 어떤 요소를 삭제하면 EXCEPTION이 발생하거나 요소를 탐색하지 못하는 문제가 발생할 수 있다.

  • 문제점
    • CooncurrentModificationException 발생 가능성
    • 반복문에서 순회 중, 일부 요소가 탐색에서 누락될 수 있는 가능성
    • 반복문 순회 중, 일부 요소가 탐색에서 누락될 수 있는 가능성아래 코드처럼 for loop에서 list의 특정 요소를 삭제하게 되면 ConcurrentModificationException이 발생할 수 있다. 순회 중에 리스트의 요소을 삭제 했을 때, 다음에 참조하는 요소의 인덱스가 list의 범위를 벗어 나게 된다. 이 상황에서 예외가 발생한다.

 

 

🏴문제점 1 : ConcurrentModificationException 가능성

public class RemoveIteratorSol4 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");

        for (String item : list) {
            if (item.equals("2")) {
                list.remove(item);
            }
        }
    }
}

output :

 

 

🏴문제점 2 : 반복문 순회 중 , 일부 요소가 탐색에서 누락될 수 있는 가능성

  • 문제점 1 처럼 ConcurrentModificationException 이 발생하지 않아도, 낮은 index에서 높은 index로 탐색하면서 요소를 삭제하면 탐색에서 제외되는 아이템이 발생할 수 도 있다.
public class RemoveIterator2 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");

        for (int i = 0; i < list.size(); i++) {
            String item = list.get(i);
            System.out.println("Iterating: " + item);
            if (item.equals("1") || item.equals("2")) {
                list.remove(item);
            }
        }

        System.out.println(list);
    }
}

Output :

 

🏴SOL 1 : List의 높은 인덱스에서 낮은 인덱스 방향으로 순회

List의 높은 Index에서 낮은 Index 방향으로 순회하면, for loop에서 요소를 안전하게 삭제 할 수 있다. 요소삭제가 탐색할 요소의인덱스에 영향을 주지 않는다.

 

public class RemoveIteratorSol1 {

    public static void main(String[] args) {

        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");

        for (int i = (list.size() - 1); i > -1; i--) {
            String item = list.get(i);
            System.out.println("Iterating: " + item);
            if (item.equals("2")) {
                list.remove(item);
            }
        }

        System.out.println("Result: " + list);
    }
}

output :

 

 

🏴SOL 2 : Collection.removeIf()

Collection.removeIf()는 인자로 함수형 인터페이스 Predicate를 전달하고, 요소를 안전하게 삭제한다.

 

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

        List<String> list = new ArrayList<>();
        list.add("apple");
        list.add("kiwi");
        list.add("melon");
        list.add("banana");

        list.removeIf(item -> item.equals("kiwi"));

        System.out.println("Result: " + list);
    }
}

output :

 

 

 

🏴 SOL 3 : Iterator

Iterator는 자바 컬랙션 프레임워크에서 컬랙션에 저장되어 있는 요소들을 읽어오는 방법을 표준화 한 것이다.

Iterator를 통해 리스트를 순회하고, 특정 요소를 안전하게 삭제할 수 있다.

 

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

        List<String> list = new ArrayList<>();
        list.add("apple");
        list.add("kiwi");
        list.add("melon");
        list.add("banana");

        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String item = it.next();
            System.out.println("Iterating: " + item);
            if (item.equals("kiwi")) {
                it.remove();
            }
        }

        System.out.println("Result: " + list);
    }

output :

 

 

https://github.com/ryudongjae/blog-ex

 

GitHub - ryudongjae/blog-ex: 📁블로그 예제 코드

📁블로그 예제 코드 . Contribute to ryudongjae/blog-ex development by creating an account on GitHub.

github.com


REFERENCE
https://codechacha.com/ko/java-remove-from-list-while-iterating/

 

728x90
728x90

리펙토링이란 일련의 리펙토링을 적용하여 겉으로 보이는 동작의 변화없이 소프트 웨어 구조를 바꾸는 것이다.

리펙토링은 외부 동작을 바꾸지 않고 내부 구조를 개선하는 방법이기도하고 , 코드가 작성된 후 디자인을 개선하기도 한다.

리펙토링은 처음부터 좋은 방법을 생각하기 보다 개발해가면서 지속적으로 좋은 디자인을 찾는것이 좋다.

🔓리펙토링의 목적

소프트 웨어를 보다 이해하기 쉽고, 수정하기 쉽도록 만드는 것이고 리펙토링은 겉으로 보이는 소프트웨어의 기능은 변경하지 않는 것이다.

🔓리펙토링을 하는 이유

  • 코드의 구조가 망가지면 당시에는 괜찮을 수 있으나 망가진 구조의 효과는 계속 누적된다.
  • 코드의 디자인을 유지하도록 해주고 불필요한 중복을 제거함으로써 각각의 작업에 대한 코드가 한 곳에만 있게 할 수 있다.
  • 소프트웨어의 디자인을 개선시켜주고 더 이해하기 쉽게 해준다.
  • 디버깅을 하기 편리해진다.

🔓리펙토링을 해야하는 시기

  • 3번의 중복/ 3번의 동일한 행위하면 리펙토링을 한다.
  • 기능을 추가할 때 되도록이면 리펙토링을 하는 것이 좋다. 기능을 추가할 때 객체 지향의 특징을 살리려면 switch-case문은 지양하는 것이 좋다.
  • 버그를 수정 해야할 때 리펙토링을 한다.

🔓리펙토링 단계

  • Naming
    • 컴퓨터가 이해하는 코드는 개발에서 당연한 것이다. 좋은 프로그래머는 사람도 이해하기 쉽게 작성해야 한다.
  • 클래스의 메소드는 클래스의 변수를 사용한다.
    • 클래스 정보를 사용하고 있지 않다면 사용하고 있는 쪽으로 움직여야 한다.
  • 임시 변수 제거
    • 임시 변수는 종종 불필요한 파라미터를 많이 만들게 된다. 임시 변수는 하나의 메소드로 구현하여 리펙토링 하는게 좋다.
  • 다른 객체의 속성을 기반으로한 switch문
    • switch문을 함수로 추출하여 자신의 데이터를 사용하는 것으로 리펙토링 해야한다.
  • 메소드에서 두개의 클래스를 변수로 사용한다면 변화하기 쉬운쪽으로 메소드를 이동시켜 변화의 폭을 최대한 작게 만들어야 한다.
  • 기능이 한쪽으로 모여진 클래스를 추상화하여 상속관계로 표현할 수 있다.
  • 추후 리펙토링 → 테스트 → 리펙토링 → 테스트를 반복한다.

🔓리펙토링 예제

  1. 함수,변수명 변경
//before
public int getOrderPrice(int arg1, int arg2){
        return arg1 * arg2;
    }

//after
public int getOrderTotalPrice(int price , int quantity){
        return price * quantity;
}

첫번째 리펙토링 예제는 함수명을 직관적으로 바꾸고 , 변수명을 의미에 맞게 수정한 것이다.

  1. 메소드 추출을 통해 코드를 간소화 한다.
//before
public int getOrderTotalPrice1(int price, int quantity,double discount){
     return (int) ((price * quantity) * (discount/100));
}

----------------------------------------------------

//after
public int getOrderTotalPrice2(int price, int quantity,double discount){
    return (int) calculationOrderTotalPrice(price,quantity,discount);
}

private double calculationOrderTotalPrice(int price, int quantity, double discount) {
     return ((price * quantity) * (discount/100));
}

기능을 가지고 있는 메서드는 외부에서 건들지 못하도록 private 선언을 해준다.

🛠클린 코드와 리펙토링

클린 코드와 리펙토링은 큰 의미로 보면 비슷하다. 그러나 클린코드보다 리펙토링이 더 큰 의미를 가지고 있다.

클린코드는 단순히 가독성을 높이기 위한 작업으로 이루어 지지만 리펙토림은 클린 코드를 포함한 유지보수를 위한 코드 개선이 이루어 진다.클린 코드와 같은 부분은 설계부터 잘 설계된느 것이 중요하고 리펙토링은 추후에 개선해 나가는 것이 바람직 하다.

 

https://github.com/ryudongjae/blog-ex

 

GitHub - ryudongjae/blog-ex: 📁블로그 예제 코드

📁블로그 예제 코드 . Contribute to ryudongjae/blog-ex development by creating an account on GitHub.

github.com


REFERENCE

https://tasddc.tistory.com/85

728x90

'Dev > JAVA' 카테고리의 다른 글

[디자인 패턴]GoF 디자인 패턴  (0) 2022.03.15
[JAVA]반복문 안에서 List 요소 삭제  (0) 2022.03.04
[Design Pattern] 빌더 패턴(Builder Pattern)  (0) 2021.12.02
[JAVA]Optional이란?  (0) 2021.06.17
[JAVA]상속(Inheritance)  (0) 2021.06.16
728x90

🛠 Builder Pattern 이란

객체의 생성 단계들을 캡슐화하여 객체의 생성을 유연하게 해주는 패턴입니다. 그래서 빌더 패턴은 생성자에 들어갈 매개 변수가 많든 적든 차례대로 매개 변수를 받아들이고 모든 매개 변수를 받은 뒤에  이 변수들을 통합해서 한 번에 사용합니다.

 

🛠 Builder Pattern

Builder Pattern의 장점에 대한 예시를 알아보자. Builder Pattern의 장점은 다음과 같은 것들이 있다.

  • 가독성을 높일 수 있다.
  • 불변성을 확보할 수 있다.
  • 필요한 데이터만 설정이 가능하다.

이제 예시를 차근차근 보자

 

🛠첫번째로 어떤 측면에서 가독성을 높여주는지 알아보자.

public class User {

    private Long id;
    private String email;
    private String name;
    private String password;
    private int age;

    public User(Long id, String email, String name, String password, int age) {
        this.id = id;
        this.email = email;
        this.name = name;
        this.password = password;
        this.age = age;
    }
}

우선 기본적인 생성자로 넘기는 방법이다. 

User user = new User(1L,"rrr11@naver.com","KK","l12313123",14);

 

모든 데이터를 생성자로 넘기면 위처럼 작성하다 보면 인자가 많아지면  순서를 바꿔 넣을 수도 있고 직관적으로 한눈에 알아보기 어렵다는 단점이 존재한다. 이제 이 문제를 점차 해결해보자.

 

  @Builder
    public User(Long id, String email, String name, String password, int age) {
        this.id = id;
        this.email = email;
        this.name = name;
        this.password = password;
        this.age = age;
    }

 

생성자를 위처럼 빌더 패턴으로 넘기면 값을 설정할 때 

	User user = User.builder()
                .id(1L)
                .email("rrr11@naver.com")
                .name("KK")
                .password("l12313123")
                .age(14)
                .build();

 

이런식으로 한눈에 직관적으로 보이게 값을 삽입할 수 있다.


🛠두번째로 불변성을 확보하는 예시를 보자 

 

자바 빈 패턴으로 @Setter로 값을 삽입할 수 있는데 이 방식은 가독성도 생성자 패턴보다 좋아지고 객체를 생성하기에도 편해졌지만, 함수 호출 한 번으로 객체를 생성할 수 없고  객체 일관성이 일시적으로 깨질 수 있다.

 

@Setter
public class User {

    private Long id;
    private String email;
    private String name;
    private String password;
    private int age;
    
  }
  
  
   User user = new User();
        user.setId(1L);
        user.setEmail("rrr11@naver.com");
        user.setName("KK");
        user.setPassword("l12313123");
        user.setAge(23);

위처럼 @Setter를 열어두는 것은 불필요하게 확장 가능성을 열어두는 것이기 때문에 Open-Close 법칙에도 위배가 되고, 불필요한 코드 리딩을 유발한다.

 


🛠세번째로 필요한 데이터를 설정하는 예시를 보자.

 

우선 데이터를 전송할 때 그 작업에 필요한 데이터만 넘길 수 있다. 필요한 데이터만 넘기게 되면 유저 정보의 패스워드 등을 노출하지 않을 수 있기 때문에 보안적으로 이점을 가진다.

일단 패스워드와 아이디는 넘기면 안된다고 가정을 해보자.

기본적인 생성자로 넘기면  우선 모든 데이터가 넘어간다. 이 문제를 생성자로 해결해보자.

public class User {

    private Long id;
    private String email;
    private String name;
    private String password;
    private int age;

    public User(String email, String name, int age) {
        this.email = email;
        this.name = name;
        this.age = age;
    }

    public User(Long id, String password) {
        this.id = id;
        this.password = password;
    }
}

이러한 방식으로 분리해서 하면 아이디와 패스워드를 빼고 넘길 수 있다. 이런 식으로 분리하면 코드가 지저분 해지고 가독성이 떨어진다.

빌더 패턴을 사용해보자 

    @Builder
    public User(Long id, String email, String name, String password, int age) {
        this.id = id;
        this.email = email;
        this.name = name;
        this.password = password;
        this.age = age;
    }
	User user = User.builder()
                .email("rrr11@naver.com")
                .name("KK")
                .age(14)
                .build();

 

이런식으로 필요한 데이터만 설정할 수 있다. 그러므로 불필요한 코드를 줄여준다. 이러한 방법으로 작업마다 필요한 데이터를 엔티티객체 또는 도메인 객체로부터 DTO로 만들어 넘겨줄 수 있다. 

 

 

DTO 예시

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
public class UserDto {
    
    private String email;
    private String name;
    private int age;
}

이런식으로 DTO를 만들 수 있다.


그러나 빌더 패턴에 장점만 존재하는 것이 아니다. 

우선 객체를 사용하려면 빌더 객체를 생성해야 하고, 다른 패턴보다 많은 코드를 요구하기 때문에 인자가 충분히 많아진 상황에서 이용할 필요가 있다.

 

GITHUB 소스코드 : https://github.com/ryudongjae/blog-ex

 

GitHub - ryudongjae/blog-ex

Contribute to ryudongjae/blog-ex development by creating an account on GitHub.

github.com


REPERENCE

728x90

'Dev > JAVA' 카테고리의 다른 글

[JAVA]반복문 안에서 List 요소 삭제  (0) 2022.03.04
[Code] Refactoring , 리펙토링  (0) 2022.02.28
[JAVA]Optional이란?  (0) 2021.06.17
[JAVA]상속(Inheritance)  (0) 2021.06.16
[JAVA]삼항연산자(Ternary Operator)  (0) 2021.06.15

[JAVA]Optional이란?

ryudjae
|2021. 6. 17. 14:30
728x90

➡️Optional이란?

  • Java8에서 Optional<T>클래스를 사용해  NPE(NullPointException)을 방지할 수 있도록 도와준다.Optional<T>는 null이 올 수 있는 값을 감싸는 Wrapper 클래스로, 참조하더라도 NPE가 발생하지 않도록 도와준다. Optional 클래스는 value에 값을 저장하기 때문에  value가 null이어도 NPE를 발생시키기 않는다.

 


➡️NPE(NullPointException)

 우리가 개발을 할때 가장 많이 발생하고 힘들게하는 예외 중 하나가 NPE(NullPointException)이다. NPE(NullPointException)를 발생시키지 않을려면 null을 검증하는 로직을 추가 해야 하는데 , null을 검증해야하는 변수가 많으면 많을수록 코드가 지저분해지고 로직이 번거로워진다.그래서 null대신 초기값을 사용하기를 권장하기도 한다.

 

➡️Optional  객체 생성

>Optional.of : value가 null인 경우 NPE예외를 던진다. 반드시 값이 있어야 하는 객체인 경우 해당 메서드를 사용하면 된다.

>Optional.ofNullable : value가 null 인 경우 비어있는 Optional을 반환한다. 값이 null일수도 있는 것은 해당 메서드를 사용하면 된다.

 

>Optional.empty : 비어있는 Optional객체를 생성한다. 조건에 따라 분기를 태워야하고 반환할 값이 없는 경우에도 사용된다.

 

➡️Optional 중간처리 

:Optional 객체를 생성 한 후 사용가능한 메서드이다. 해당 메서드들은 다시 옵셔널을 반환하므로 메서드 체이닝을 통해 원하는 로직을 반복 삽입할 수 있습니다.

 

>filter

:predicate(반환값) 값이 참이면 해당 필터를 통과시키고 거짓이면 통과를 하지 못한다.

1
2
3
4
5
6
// 메서드 시그니처
public Optional<T> filter(Predicate<super T> predicate);
// 예제
Optional.of("True").filter((val) -> "True".eqauls(val)).orElse("NO DATA"); // "True"
Optional.of("False").filter((val) -> "True".eqauls(val)).orElse("NO DATA"); // "NO DATA"
 
cs

 

>map

: mapper 함수를 통해 입력값을 다른 값으로 변환하는 메서드이다.

1
2
3
public<U> Optional<U> map(Function<super T, ? extends U> mapper);
// 예제
Integer test = Optional.of("1").map(Integer::valueOf).orElseThrow(NoSuchElementException::new); // string to integer
cs

 

>flatMap

:mapper 함수를 통해 입력값을 다른 값으로 변환하는 메서드이다. map()메서드와 다른점은 메서드 시그니처의 매개변수입니다.

1
2
3
4
5
6
7
// 메서드 시그니처
public<U> Optional<U> flatMap(Function<super T, Optional<U>> mapper);
// 예제
String result = Optional.of("result")
        .flatMap((val) -> Optional.of("good"))
        .get();
System.out.println(result); // print 'good'
cs
 

 

➡️Optional 종단처리

>.ifPresent

최종적으로 연산을 끝낸 후 값이 비어있지 않다면 입력값으로 주어진다. 이 값을 가지고 원하는 작업을 수행하면 된다. 하지만 중간 연산을 하다 비어있는 옵셔널 객체를 받게 되면 .ifPresent() 메서드의 내용을 수행하지 않는다.

1
2
3
4
5
6
7
8
9
10
// 메서드 시그니처
public void ifPresent(Consumer<super T>; consumer);
// 예제1
Optional.of("test").ifPresent((value) ->; {
    // something to do
});
// 예제2 (ifPresent 미수행)
Optional.ofNullable(null).ifPresent((value) ->; {
    // nothing to do
});
cs

 

 

>.isPresent

최종적으로 연산을 끝낸 후 객체가 존재하는지 여부를 판별한다.

1
2
3
4
5
// 메서드 시그니처
public boolean isPresent();
// 예제
Optional.ofNullable("test").isPresent(); // true
Optional.ofNullable("test").filter((val) ->"result".eqauls(val)).isPresent(); // false
cs

 

>.get

: 최종적으로 연산을 끝낸 후 객체가 존재하는지 여부를 판별한다. 없으면 예외를 던진다.

1
2
3
4
5
// 메서드 시그니처
public T get();
// 예제
Optional.of("test").get(); // 'test'
Optional.ofNullable(null).get(); // NoSuchElementException
cs

 

>.orElse

: 최종적으로 연산을 끝낸 후에도 Optional객체가 비어있다면 기본값으로 제공할 객체를 지정한다.

1
2
3
4
5
/ 메서드 시그니처
public T orElse(T other);
// 예제
String result = Optional.ofNullable(null).orElse("default");
System.out.println(result); // print 'default'
cs

 

>.orElseGet

: 최종적으로 연산을 끝낸 후에도 옵셔널 객체가 비어있다면 기본값으로 제공할 공급자 함수를 지정합니다.

1
2
3
4
5
// 메서드 시그니처
public T orElseGet(Supplier<extends T> other);
// 예제
String result = Optional.ofNullable("input").filter("test"::equals).orElseGet(() ->"default");
System.out.println(result); // print 'default'
cs

 

 

>.orElseThrow

최종적으로 연산을 끝낸 후에도 Optional객체가 비어있다면 예외 공급자 함수를 통해 예외를 발생시킨다.

1
2
3
4
// 메서드 시그니처
public <extends Throwable> T orElseThrow(Supplier<extends X> exceptionSupplier) throws X;
// 예제
Optional.ofNullable("input").filter("test"::equals).orElseThrow(NoSuchElementException::new);
cs

 

 

orElse, orElseGet 중 무엇을 사용할까?

orElse 메서드는 옵셔널 객체가 비어있든 비어있지 않든 반드시 실행 한다. orElseGet 메서드는 옵셔널 객체가 비어있으면 실행합니다. 따라서 기본값을 주고자 할때에 기본값을 구하는 과정이 오래 걸린다면 orElseGet을 사용하는게 좋다.

 

 

 

👉다음에는 JAVA9,JAVA10 에 추가된 메서드를 추가해볼 예정이다.

 


Reference

728x90

'Dev > JAVA' 카테고리의 다른 글

[Code] Refactoring , 리펙토링  (0) 2022.02.28
[Design Pattern] 빌더 패턴(Builder Pattern)  (0) 2021.12.02
[JAVA]상속(Inheritance)  (0) 2021.06.16
[JAVA]삼항연산자(Ternary Operator)  (0) 2021.06.15
[JAVA]Primitive type과 Reference type  (0) 2021.04.07

[JAVA]상속(Inheritance)

ryudjae
|2021. 6. 16. 17:56
728x90

👉상속이란?

  • 새로운 클래스를 정의 할 때 이미 구현된 클래스를 상속(inheritance) 받아서 속성이나 기능을 확장하여 클래스를 구현함
  • 이미 구현된 클래스보다 더 구체적인 기능을 가진 클래스를 구현해야 할때 기존 클래스를 상속함

상속하는 클래스 : 상위 클래스, parent class, base class, super class
상속받는 클래스 : 하위 클래스, child class, derived class, subclass

👉상속 문법

class b extends a{
//a가 b를 상속한다
}

👉상속을 구현하는 경우

  • 상위 클래스는 하위 클래스 보다 더 일반적인 개념과 기능을 가진다.
  • 하위 클래스는 상위 클래스 보다 더 구체적인 개념과 기능을 가진다.
  • 하위 클래스가 상위 클래스의 속성과 기능을 확장 (extends)한다는 의미이다.

👉예제로 동물을 상위클래스로 두고 상속 받는 다른클래스를 만들어보자

상위클래스인 동물 클래스를 만든다.

1
2
3
4
5
6
7
public class Animal {
    String name;
 
    public void setName(String name) {
        this.name = name;
    }
}
cs

 

Dog라는 animal하위클래스를 하나 만든다.

 

1
2
3
4
5
6
7
8
9
public class Dog extends Animal {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("poppy");
        System.out.println(dog.name);
    }
}
 
 
cs

 

실행해보면 "poppy"라는  문자열이 출력된다.

1
2
3
4
5
6
7
8
9
10
11
12
public class Dog extends Animal {
    public void sleep() {
        System.out.println(this.name+" zzz");
    }
 
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("poppy");
        System.out.println(dog.name);
        dog.sleep();
    }
}
cs

Dog클래스에 sleep이라는 메소드를 추가하였다.

이제 Dog 클래스는 Animal 클래스보다 좀 더 많은 기능(sleep메소드가 추가되었다.)을 가지게 되었다. 이렇듯 보통 부모 클래스를 상속받은 자식 클래스는 부모 클래스의 기능에 더하여 좀 더 많은 기능을 갖도록 설계한다.

 

👉IS-A 관계

Dog클래스는 Animal클래스를 상속받았다. 즉, Dog는 Animal의 하위 개념이라고 할 수 있겠다. 이런 경우 Dog는 Animal에 포함되기 때문에 "개는 동물이다"라고 표현할 수 있다. 

자바는 이러한 관계를 IS-A 관계라고 표현한다. 즉 "Dog is a Animal" 과 같이 말할 수 있는 관계를 IS-A 관계라고 한다.

그러나 부모 클래스로 만들어진 객체를 자식 클래스의 자료형으로는 사용할 수 없다.

Dog dog = new Animal();  

이렇게 사용하면 컴파일 오류가 발생한다.

 

👉메소드 오버라이딩 (Method overriding) ->상위 클래스가 가지고 있는 메서드를 하위 클래스가 재정의해서 사용

메소드 오버라이딩이란?

 

  • 오버라이딩(overriding)이란 상속 관계에 있는 부모 클래스에서 이미 정의된 메소드를 자식 클래스에서 같은 시그니쳐를 갖는 메소드로 다시 정의하는 것이라고 할 수 있다.
  • 자바에서 자식 클래스는 부모 클래스의 private 멤버를 제외한 모든 메소드를 상속받는다.
  • 이렇게 상속받은 메소드는 그대로 사용해도 되고, 필요한 동작을 위해 재정의하여 사용할 수도 있다.
  • 즉, 메소드 오버라이딩이란 상속받은 부모 클래스의 메소드를 재정의하여 사용하는 것을 의미한다.

오버라이딩의 조건

  • 오버라이딩이란 메소드의 동작만을 재정의하는 것이므로, 메소드의 선언부는 기존 메소드와 완전히 같아야 합니다.
  • 하지만 메소드의 반환 타입은 부모 클래스의 반환 타입으로 타입 변환할 수 있는 타입이라면 변경할 수 있습니다.
  • 부모 클래스의 메소드보다 접근 제어자를 더 좁은 범위로 변경할 수 없습니다
  • 부모 클래스의 메소드보다 더 큰 범위의 예외를 선언할 수 없습니다.

👉메소드 오버로딩 (Method overloading) ->같은 이름의 메서드 여러개를 가지면서 매개변수의 유형과 개수가 다르도록 하는 기술

   메소드 오버로딩이란 ?

  • 메소드 오버로딩(overloading)이란 같은 이름의 메소드를 중복하여 정의하는 것을 의미한다.
  • 자바에서는 원래 한 클래스 내에 같은 이름의 메소드를 둘 이상 가질 수 없다.
  • 하지만 매개변수의 개수나 타입을 다르게 하면, 하나의 이름으로 메소드를 작성할 수 있다.
  • 즉, 메소드 오버로딩은 서로 다른 시그니처를 갖는 여러 메소드를 같은 이름으로 정의하는 것이라고 할 수 있다.
  • 이러한 메소드 오버로딩을 사용함으로써 메소드에 사용되는 이름을 절약할 수 있다.
  • 또한, 메소드를 호출할 때 전달해야 할 매개변수의 타입이나 개수에 대해 크게 신경을 쓰지 않고 호출할 수 있게 된다.
  • 메소드 오버로딩은 객체 지향 프로그래밍의 특징 중 하나인 다형성(polymorphism)을 구현하는 방법 중 하나이다.

 메소드 오버로딩의 조건

  • 메소드의 이름이 같아야 한다.
  • 메소드의 시그니처, 즉 매개변수의 개수 또는 타입이 달라야 한다.

 

 

Reference

 

 

728x90

'Dev > JAVA' 카테고리의 다른 글

[Code] Refactoring , 리펙토링  (0) 2022.02.28
[Design Pattern] 빌더 패턴(Builder Pattern)  (0) 2021.12.02
[JAVA]Optional이란?  (0) 2021.06.17
[JAVA]삼항연산자(Ternary Operator)  (0) 2021.06.15
[JAVA]Primitive type과 Reference type  (0) 2021.04.07
728x90

👉삼항연산자란?

  • 3개의 피연산자를 필요로 하는 연산자이다.

👉문법

사진 출처:https://cremazer.github.io/java-Types-of-Operators/

  • 문법은 어려운 편은 아니다. true/false를 판단할 수 있는 변수 또는 조건식을 작성한 후에 연산결과인 true/false에 실행되는 표현식을 작성하면 된다.
  • 조건식의 결과가 false이면 식2가 결과가 되고 true이면 식 1이 결과가 된다.
1
2
3
  int b1 = (5>4) ? 50 : 40;
  
  //조건식이 true이므로 결과값은 50이 나온다.​
cs

 

  • 🙉가장 기본적인 예제이다.
1
2
3
4
5
6
7
8
//(조건식1) ? true : (조건식2) ? true : false
//조건식1이 false이면 조건식2를 수행한다.조건식2는 일반 삼항 연산자처럼 실행된다.
//삼항연산자를 중첩해서 사용하면 if문 대신에 사용할 수 있다.
 
int a = 10
int b = 10
 
System.out.println((a &gt; b) ? "a는 b보다 크다" : (a &lt; b) ? "b는 a보다 크다" : "a와 b는 같다.");
cs

🙉이 예제는 삼항연산자를 중첩해서 사용하는 코드이다.

728x90

'Dev > JAVA' 카테고리의 다른 글

[Code] Refactoring , 리펙토링  (0) 2022.02.28
[Design Pattern] 빌더 패턴(Builder Pattern)  (0) 2021.12.02
[JAVA]Optional이란?  (0) 2021.06.17
[JAVA]상속(Inheritance)  (0) 2021.06.16
[JAVA]Primitive type과 Reference type  (0) 2021.04.07