[JAVA] 개념 메모

merci·2023년 1월 2일
2

JAVA

목록 보기
1/10


본 포스팅은 개인적으로 메모한 내용입니다.

메모리의 저장공간단위는 얼마인가 ?

  • 과거 통신을 할때 아스키코드(프로토콜)를 전송해야하니 전송 단위를 8bit로 정함
    (데이터는 바이트 스트림으로 들어오고 받는 입장에서 끊어서 저장)
    직렬화와 역직렬화를 통해서 영문자 -> 유니코드 -> 비트 -> 유니코드 -> 영문자
    메모리는 문자하나씩 저장해야 하기 때문에 기본 저장 단위는 8bit


레퍼런스 자료형의 특징은 ?

  • 레퍼런스 자료형 (래퍼클래스를 포함한 클래스 객체)은 포인터 (주소를 가리키는)를 이용.
    레퍼런스 자료형은 번지를 가지면서 4바이트를 할당받고 (포인터가) 힙에 저장됨.
    힙 영역에 저장되면 런타임시 크기가 결정된다 (동적 할당)
    반대로 스택영역은 컴파일시 크기가 결정된다 (정적 할당)


메모리의 구조는 ?

  • static 공간은 클래스별로 분류, static멤버는 해당 클래스 공간에 존재함.

  • 스택에는 로컬변수(레퍼런스 주소를 가지는 변수도), 매개변수, 메소드 내용이 들어간다
    스택에 존재하는 변수들을 스택변수라고 한다.
    로컬 변수 재사용하기 위해서는 리턴하던지 힙에 넣어야 한다.

  • 힙에는 생성자로 만들어진 객체와 객체의 속성(필드,메소드이름)이 있다.
    main 메소드 안에서 객체가 생성된다면 포인터를 가지고있는 객체의 변수는 main스택에 있고 실제 객체는 힙에 존재한다


메소드란 ?

  • 메소드를 한마디로 표현하자면 객체의 상태를 변경하는것.

  • 자바에서는 메소드를 정의하기 위해 클래스가 필요하다.
    다른 언어에서는 클래스 필요없이 메소드를 정의하는데 이러한 메소드를 함수라고 표현한다.

  • 메소드 코드블록은 스택에 생성된다. 메소드 내부에 또다른 코드블록이 생긴다면 ( if, for...같은 코드블록 )
    메소드 스택 내부에 또 다른 스택이 생성된다.

  • 메소드를 만들면 재사용하기 좋아지므로 여러 코드를 메소드로 만들면 모듈화가 되어서 필요한것만 가져다 쓰기 좋아진다.
    ( ++ 패턴 파악 (알고리즘) -> 메소드로 만들고 (모듈화) -> 리팩토링 )

  • 이전 버전에서 1급 객체는 클래스뿐이었지만 JAVA8 버전에서 메소드도 1급객체가 되었다. (변수에 저장 가능)
    1급객체인 메소드는 메모리에 로딩이 가능하다.

  • 메소드는 어떤 일을 할지 이름으로 알수 있어야 한다. ( 코드블록은 부연설명을 하는것 )
    print() 나 random() 을 떠올려보면 이름으로 명확히 의도를 알 수가 있다.
    주석을 달지 않아도 다른 사람이 코드분석을 할수 있게 명확하게 이름을 붙이는 습관을 가지자.

  • 자바에서 클래스, 메소드는 단일 책임의 원칙을 지켜라 (기능을 분리 시켜라)
    ( 자바 라이브러리가 하나의 기능만 가진 메소드로 이루어졌듯이 )

  • 객체지향의 변수는 행위로 변경하자 --> private 접근제한자를 붙이고
    setter로만 접근가능하게 바꾸면 행위(메소드)로 변수를 변경하게 된다.


클래스, 인스턴스, 오브젝트의 차이는 ?

  • 클래스 -> 설계

  • 인스턴스 -> new생성자로 만들어서 heap에 존재하는것

  • 오브젝트(객체) -> 존재 할수 있는가? ex) 고양이, 토끼
    ( 오브젝트 - 언제든지 만들어질 수 있는것들 )
    반대로 동물은 객체가 아니다 (추상화 된것, 존재 불가)

  • new 가 가능해지거나 구상화가 되면 오브젝트, 개발자가 구현하면 그건 오브젝트가 된다.
    abstract(추상)가 아니면 모든 클래스는 오브젝트다 (heap에 갈 가능성이 있는 모든것)


상속 + 업캐스팅 + 오버라이딩 = 다형성

  • 오버로딩 -> 다양한 타입을 하나의 메소드 이름으로 사용할수 있으니 편하지만 ex out.print()
    매개변수의 종류가 다양해지면 오버로딩을 해야할 메소드가 기하급수적으로 늘어나는 단점이 있다.
    이를 오버라이딩을 통해서 해결해보자.

  • 업캐스팅은 < 부모타입 변수 = new 자식객체 > 구조
    호출할 메소드의 매개변수가 부모타입일때 자식객체를 넣으면 매개변수 자리에서도 업캐스팅이 된다.

  • 상속 + 업캐스팅으로 자식객체를 생성하면 변수의 포인터는 명시적으로 생성된 자식객체를 가리킨다.
    자식 생성자 첫줄은 부모의 생성자이기 때문에 heap에 부모의 인스턴스가 먼저 생성되고 자식이 생성된다.
    < 부모타입 = 자식객체 > 구조에서 부모의 멤버를 호출할수 있는 이유는 부모의 인스턴스가 힙에 존재하기 때문이다.
    마찬가지로 매개변수가 부모타임인 메소드에 자식객체를 넣으면 동시에 힙에 부모 객체도 생성된다.

  • 오버라이딩을 하면 부모의 메소드는 무효화가 된다. -> 자식클래스에 오버라이딩을 하고 부모메소드 호출시 부모메소드는 무효화되고 자식의 메소드가 호출됨 ( 동적 바인딩 )
    힙에 부모와 자식의 인스턴스가 존재하면 오버라이딩이 적용된다.

  • 바인딩 -> 메소드의 호출을 실제 메소드와 연결
    오버로딩은 컴파일시 다형성을 지원 -> 정적바인딩
    오버라이딩은 런타임시 다형성을 지원 -> 동적바인딩

  • 동적 바인딩
    런타임시 변수가 참조하는 객체의 실제 타입을 보고 메소드를 호출
    다형성을 사용하여 메소드를 호출하면 구현되어 있는 메소드를 호출하게 된다.

  • 부모의 메소드가 static이면 업캐스팅 구조에서 부모메소드를 호출시 재정의된 자식 메소드가 호출되지 않는다.

  • 추상메소드에 abstract 를 붙이면 자식클래스에서 반드시 재정의 해야하므로 협업시에 좋을것 같다.

  • 상속하는 자식 클래스에서 필드를 추가하면 필드에 접근할수 있는 메소드를 만들어서 개발코드에서 호출하면 자식필드를 사용할 수 있다.


상속의 목적은 ?

  • 상속의 근본적인 목적은 추상화에 있다. ( 공통적인 특징을 추상화로 모은다 )

  • 상속은 강한 결합을 가져 유연함이 떨어지는 단점이 있다 -> 만약 부모가 수정되면 자식의 구조가 모조리 깨져버린다.

  • 확장이 가능하고 종속성을 줄이고 더 유연한( 결합도가 낮아 수정시 영향이 적은) Composition을 사용하여 단점을 보완한다.

  • 조합(composition) -> 다른 클래스의 인스턴스를 가져서 그 클래스의 멤버에 접근할 수 있다.
    외부에서 객체를 생성하고 객체의 주소를 필드에 대입한다 -> 의존성을 주입한다고 표현

  • 결합도가 높으면 생성된 인스턴스가 가진 특성이 변화되었을때 대처하기가 힘들다.

  • composition을 이용하면 객체는 캡슐화 상태가 유지된다.

  • 제네릭도 다형성에 포함이 된다 -> 다형성은 하나의 코드로 다양한 타입의 객체를 처리



자바에서 의존이란 ?

  • 내부에 다른 객체를 생성하거나 메소드를 호출하면 그 객체에 의존한다고 한다.
    파라미터를 전달받으면 파라미터에 의존한다고 함. (파라미터에 따라 결과가 달라짐)

  • 즉, 의존하는 무언가가 변경되면 의존하고 있는 자신도 변경될 가능성이 있다. (영향을 미친다)

  • 자주 변하는것을 의존 하면 유연하지 못한 프로그래밍이 되고 유지보수가 어렵다.

  • 객체 지향의 프로그래밍은 구현객체를 변경해도 개발코드에 아무런 영향이 없어야 유지보수가 편하다.
    이러한 영향은 캡슐화를 통해서 최소화 한다. ( 캡슐속의 로직만 변경될 뿐 )


인터페이스

  • 개발코드와 객체사이에서 강제성을 부여해 객체사용방법을 정의함 ( 구현을 강제 )
    이름을 통일하고 가독성을 높여 유지보수를 향상시킨다.

  • 추상메소드는 내용을 가질 수 없다 (static, default 메소드 제외) -> 다이아몬드 문제가 없다.

  • 인터페이스를 이용하면 결합도를 낮춘(종속성을 낮춘) 유연한 개발을 할 수 있다.
    (상속은 강한 결합을 가진다 -> 부모를 수정하면 자식에 영향을 미친다. )

  • 인터페이스는 필드를 가질수 없다 -> 필드가 필요하면 추상클래스 이용

  • 상속과 다르게 < 인터페이스타입 변수 = new 구현객체 > 구조일때 변수로 구현객체의 필드에 접근할 수 없다.

  • 인터페이스는 관련없는 것들의 공통된 동작을 표현할때 사용. ( 객체들이 공통된 특성을 가지면 추상클래스로 )

  • 개방폐쇄원칙(OCP)을 이용한다.
    확장에 열려있다 -> 다양한 구현객체를 생성해서 기능을 추가할 수 있다.
    변화에 닫혀있다 -> ex) JDBC는 중간에 DB가 변경되더라도 영향을 받지 않는다 (수정이 필요없다).
    ---> 변하는 부분을 추상화하여 기능을 변경, 확장할 수 있으면서 그 기능을 사용하는 코드는 수정하지 않는다

  • 의존성역전원칙(DIP)을 이용한다.
    고수준 모듈에 의존해야한다. (인터페이스)
    추상화된 것을 의존하면 확장이 쉬워진다 -> 구현된 객체를 변경하기 쉽다
    ---> 자신보다 변하기 쉬운것에 의존하지 마라, 추상화(인터페이스)에 의존해라

  • 이러한 원칙들로 인해 인터페이스는 유연성(다양한 요구사항에 대응)을 가지고 , 재사용성이 높고, 유지보수에 편하다



객체 지향을 간단하게 말하자면 ?

  • 객체는 상태와 동작을 가지고, 객체를 통해 코드를 구성한다

  • 객체를 사용 -> 모듈화를 이용해 재사용성, 유지보수를 쉽게한다

  • 단점 ! 객체의 의존관계에 의해 속도가 느리고 모듈의 관계를 구현해야 해서 복잡하다

  • 응집도(Cohesion)를 높이고 결합도(Coupling)를 낮추는 방식으로(독립성이 좋아짐) 코드를 작성해보자
    (응집 - 모듈 내부에서 처리 요소들이 서로 관련되어 있음)
    (결합 - 예를들어 다른 모듈을 의존하면 결합이 되었다고 말함)

  • 모듈화 - 목적에 맞는 하나의 기능만 있으면 좋은 모듈이다 -> 책임이 분리되면 유지보수에 편하다 - 단일책임의원칙(SRP) 준수


profile
작은것부터

2개의 댓글

comment-user-thumbnail
2023년 1월 7일

다시 또 읽어봐야지! 굿굿!!

답글 달기
comment-user-thumbnail
2023년 1월 8일

여기 정리 맛집이네요..!!!! 출퇴근 지하철에서 보기 딱임 ㅎㅎ

답글 달기