빌리 관리 도구란?

프로젝트에서 필요한 xml, properties, jar 파일들을 자동으로 인식하여 빌드해주는 도구 

소스 코드를 컴파일, 테스트, 정적분석 등을 하여 실행가능한 앱으로 빌드해줌

프로젝트 정보 관리, 테스트 빌드, 배포 등의 작업을 진행해줌

외부 라이브러리를 참조하여 자동으로 다운로드 및 업데이트의 관리해줌 

 

자바의 대표적인 빌드도구 : Ant, Maven, Gradle

 

 

메이븐 (Maven) 이란?

자바의 대표적인 관리 도구였던 Ant를 대체하기 위해 개발됨

프로젝트의 외부 라이브러리를 쉽게 참조할 수 있게 pom.xml 파일로 명시하여 관리 

참조한 외부 라이브러리에 연관된 다른 라이브러리도 자동으로 관리됨

 

메이븐을 사용하는 이유 

기존에 사용하던 Ant는 빌드의 기능만 가지고 있음

자동으로 라이브러리를 관리해주는 기능이 추가된 Maven을 사용

다운받아 사용하던 라이브러리에 변동 사항이 있으면 자동으로 업데이트 하여 적용됨

 

Ant

  • XML 기반의 빌드 스크립트
  • 자유로운 빌드 단위 지정
  • 간단하고 사용하기 쉬움
  • 대규모 프로젝트에서 복잡해지는 경향이 있음
  • 라이프 사이클이 없음

 

Maven

  • XML 기반의 빌드 스크립트
  • 라이프 사이클 도입
  • pom.xml로 편하게 Dependency 관리
  • 대규모 프로젝트에서 복잡해지는 경향이 있음
더보기

pom.xml의 역할

- 프로젝트 정보 관리

- 해당 프로젝트에서 사용하는 외부 라이브러리 관리

- 해당 프로젝트의 빌드 관련 설정

 

Maven의 대표 태그 설명

  • modelVersion : maven의 버전을 의미
  • groupId : 프로젝트 그룹 id를 뜻하며, 일반적으로 대표하는 사이트 도메인을 역순으로 적어 사용
  • artifactId : groupId외에 다른 프로젝트와는 구분될 수 있는 프로젝트의 id를 작성
  • version : 프로젝트의 버전을 의미하며 개발 단계에 따라 구분하여 작성
  • name : 프로젝트의 이름
  • description : 해당 프로젝트의 간략한 설명을 작성
  • properties : pom.xml 파일 내에서 빈번하게 사용되는 중복 상수를 정의하는 영역 해당 영역의 상수를 사용하기 위해서는 ${태그명} 의 형태로 사용한다.
  • dependendies : 해당 프로젝트에서 의존성을 가지고 사용하는 라이브러리를 정의하는 영역 각 라이브러리마다 <dependency> 태그를 사용하여 구분
  • build : 프로젝트 빌드와 관련된 정보를 설정하는 영역

 

Gradle 이란?

Groovy 스크립트를 활용한 빌드 관리 도구

안드로이드 프로젝트의 표준 빌드 시스템으로 채택

멀티 프로젝트(Multi-Project)의 빌드에 최적화 하여 설계됨

Maven에 비해 더 빠른 처리속도를 가지고 있음

Maven에 비해 더 간결한 구성이 가능함

 

Gradle과 Maven 비교

  • Gradle에 비해 Maven이 점유율이 더 높은 상황(점차 Gradle 점유율이 오르는 중)
  • Gradle에 비해 Maven 성능이 떨어짐
  • Maven에 비해 Gradle이 대규모 프로젝트에서의 성능이 좋음
  • Mavne : pom.xml  Gradle : build.gradle
  • Gradle은 설치 없이 사용할 수 있다. 

Gradle 대표 용어 설명

  • repositories : 라이브러리가 저장된 위치 등 설정
  • mavenCentral : 기본 Maven Repository
  • dependencies : 라이브러리 사용을 위한 의존성 설정

'Back-End > Spring Boot + Kotlin' 카테고리의 다른 글

REST 와 RESTful  (0) 2024.02.07
Swagger  (1) 2023.11.08
Post API  (0) 2023.11.02
Spring Boot 기초  (0) 2023.11.01
REST API  (2) 2023.10.30

자바스크립트에서 객체는 상태를 나타내는 프로퍼티와 동작을 나타내는 메서드를 하나의 논리적인 단위로 묶은 복합접인 자료구조다.

 

동작을 나타내는 메서드는 자신이 속한 객체의 상태, 즉 프로퍼티를 참조하고 변경할 수 있어야 한다. 이때 메서드가 자신이 속한 객체의 프로퍼티를 참조하려면 먼저 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 한다.

 

이를 위해 자바스크립트는 this라는 특수한 식별자를 제공한다.

 

this 는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수(self-referencing variable)다. this 를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있다.

 

this는 자바스크립트 엔진에 의해 암묵적으로 생성되며, 코드 어디서든 참조할 수 있다. 함수를 호출하면 arguments 객체와 this가 암묵적으로 함수 내부에 전달된다. this는 지역 변수처럼 사용할 수 있다.

단, this가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.

더보기

this 바인딩 

- 바인딩이란 식별자와 값을 연결하는 과정을 의미한다. 예를 들어, 변수 선언은 변수 이름(식별자)과 확보된 메모리 공간의 주소를 바인딩하는 것이다. this 바인딩은 this(키워드로 분류되지만 식별자 역할을 한다)와 this가 가리킬 객체를 바인딩하는 것이다.

// 객체 리터럴
const circle = {
	radius: 5,
    getDiameter() {
    	// this는 메서드를 호출한 객체를 가리킨다.
        return 2 * this.radius;
    }
};

console.log(circle.getDiameter()); // 10

객체 리터럴의 메서드 내부에서의 this는 메서드를 호출한 객체, 즉 circle을 가리킨다.

 

this는 코드 어디에서든 참조 가능하다. 전역에서도 함수 내부에서도 참조할 수 있다.

 

// this는 어디서든 참조 가능하다.
// 전역에서 this는 전역 객체 window를 가리킨다.
console.log(this); // window

function square(number) {
	// 일반 함수 내부에서 this는 전역 객체 window를 가리킨다.
    console.log(this); // window
}

const person = {
	name: 'Lee',
    getName() {
    	// 메서드 내부에서 this는 메서드를 호출할 객체를 가리킨다.
        console.log(this); // {name: "Lee", getName: f}
        return this.name;
    }
};

 

기본적으로 this에는 전역 객체(global object)가 바인딩된다.

// var 키워드로 선언한 변수 value는 전역 객체의 프로퍼티다.
var value = 1;
// const 키워드로 선언한 전역 변수 value는 전역 객체의 프로퍼티가 아니다.
//const value = 1;

const obj = {
	value : 100,
    foo() {
    	console.log("foo's this: ", this); // {value : 100, foo : f}
        console.log("foo's this.value: ", this.value); // 100
        
        // 메서드 내에서 정의한 중첩 함수
        function bar() {
        	console.log("bar's this: ", this); // window
            console.log("bar's this.value: ", this.value); // 1
        }
    }
};

위처럼 일반 함수로 호출된 모든 함수(중첩 함수, 콜백 함수 포함) 내부의 this에는 전역 객체가 바인딩된다.

 

메서드 내부의 중첩 함수나 콜백 함수의 this 바인딩을 메서드의 this 바인딩과 일치시키는 방법은 다음과 같다.

var value = 1;

const obj = {
	value : 100,
    foo() {
    	// this 바인딩(obj)을 변수 that에 할당한다.
        const that = this;
        
        // 콜백 함수 내부에서 this 대신 that을 참조한다.
        setTimeout(funtion() {
        	console.log(that.value); // 100
        }, 100);
    }
};

자바에서는 대표적으로 문자열을 처리하는 클래스로 String, StringBuilder, StringBuffer 라는 3가지 클래스를 제공한다.

3가지로 구분되는 이유는 무엇이며 무엇이 다른지 정리해보자.

 

가장 먼저 String 과 다른 클래스의 차이점은 String 은 immutable(불변), 다른 두 클래스는 mutable(가변)의 차이점이다.

 

String 자료형만으로도 + 연산이나 concat() 메소드로 문자열을 이어붙일 수 있다. 하지만 덧셈(+) 연산자를 이용해

String 인스턴스의 문자열을 결합하면, 내용이 합쳐진 새로운 String 인스턴스를 생성하게 되어 문자열을 많이 결합하면 할수록

공간의 낭비가 생기고 속도 또한 매우 느려지게 된다. 왜냐하면 초기 공간과 다른 값에 대한 연산에서 많은 시간과 자원을 사용하게 되기

때문이다.

 

String 으로 할당했을때 메모리 사용을 살펴보자

 

 

그래서 자바에서는 이러한 문자열 연산의 낭비를 막기 위해 문자열 전용 자료형을 제공해주는데 StringBuffer 이다.

StringBuffer 클래스는 내부적으로 Buffer 라고 하는 독립적인 공간을 가지게 되어, 문자열을 바로 추가할 수 있어 공간의

낭비도 없으며 문자열 연산 속도도 매우 빠르다는 특징이 있다.

 

StringBuffer sb = new StringBuffer(); // StringBuffer 객체 생성

sb.append("Hello");
sb.append(" "):
sb.append("Java");
String result = sb.toString();

System.out.println(result); // Hello Java

StringBuilder는 StringBuffer와 거의 비슷한 자료형인데 둘의 차이점은 

StringBuffer 는 멀티 스레드 환경에서 안전하다는 장점이 있고, StringBuilder 는 문자열 파싱 성능이 가장 우수하다는 장점이 있다.

 

정리하자면 

  • String은 짧은 문자열을 더할 경우 사용한다.
  • StringBuffer는 스레드에 안전한 프로그램을 개발할때, 개발 중인 시스템이 스레드에 안전한지 모를 경우 사용한다.
  • StringBuilder 는 스레드의 안전 여부가 상관 없는 프로그램을 개발할 때 사용하면 좋다.

 

StringBuffer 의 버퍼(데이터 공간)의 크기의 기본값은 16개의 문자열을 저장할 수 있는 크기이며, 생성자를 통해 그 크기를 

별도로 설정할 수도 있다. 

만약 문자열 연산중 할당된 버퍼의 크기를 넘겨도 상관없다. 자동으로 버퍼를 증가시켜 주기 때문이다.

 

메서드 설명
StringBuffer() 버퍼의 길이를 지정하지 않으면 크기가 16인 버퍼를 생성한다.
StringBuffer(int length) length 길이를 가진 StringBuffer 클래스의 인스턴스(buffer)를 생성
StringBuffer(String str) 지정한 문자열 (str)의 길이보다 16 만큼 더 큰 버퍼를 생성
StringBuffer append() 매개변수로 입력된 값을 문자열로 변환하여 StringBuffer 인스턴스가 저장하고 있는 
문자열의 뒤에 덧붙임
int capacity() StringBuffer 인스턴스의 버퍼크기 반환
int length() StringBuffer 인스턴스에 저장된 문자열의 길이 반환
char charAt(int index) 지정된 위치(index) 에 있는 문자를 반환
StringBuffer delete(int short, int end) 시작위치(start) 부터 끝 위치(end) 사이에 있는 문자를 제거, 단 end 위치의 문자는 제외
StringBuffer deleteCharAt(int index) 지정된 위치(index)의 문자를 제거
StringBuffer insert(int pos, boolean b)
StringBuffer insert(int pos, String str) 

등등
두 번째 매개변수로 받은 값을 문자열로 변황하여 지정된 위치(pos)에 추가 
StringBuffer replace(int start, int end, String str) 지정된 범위 (start ~ end) 의 문자들을 주어진 문자열로 변경
String toString() StringBuffer 인스턴스의 문자열을 String 으로 변환
void setLength(int newLength) 지정된 길이로 문자열의 길이를 변경 
길이를 늘리는 경우에는 나머지 빈공간들을 널문자(\u000)로 채운다.
String subString(int start) 지정된 밤위 내의 문자열을 String 으로 뽑아서 반환

StringBuffer 클래스의 메서드와 StringBuilder 클래스 메서드 사용법은 동일하다.

 

StringBuffer / StringBuilder 의 메모리공간을 살펴보자

따라서 값이 변경될 때마다 새롭게 객체를 만드는 String 보다는 문자열의 추가,수정,삭제가 빈번하게 발생한다면

StringBuffer / StringBuilder 를 사용하는것이 좋다.

 

간단하지만 이해하기 쉬운 예제로 for문을 돌면서 *을 추가하는 예제를 들 수 있다.

String str = "*";

for (int i = 1; i < 10; i++) {
	str += "*";
}
StringBuffer sb = new StringBuffer("*");

for(int i = 1; i < 10; i++) {
	sb.append("*");
}

String 객체일 경우 매번 * 문자열이 업데이트 될때마다 계속해서 메모리 블럭이 추가되게 되고, 일회용으로 사용된 이 매모리들은 후에 

Garbage Collector (GC)의 제거 대상이 되어 빈번하게 Minor GC를 일으켜 Full GC(Major GC)를 일으킬 수 있는 원인이 된다.

'Back-End > Java' 카테고리의 다른 글

스레드  (1) 2024.07.05
프로세스  (0) 2024.07.04
Java HTTP 통신  (4) 2024.06.12
Exception과 Transaction  (1) 2024.02.05
스프링이란 무엇일까?  (0) 2023.09.16

인덱스 수직적 탐색

정렬된 인덱스 레코드 중 조건을 만족하는 첫 번째 레코드를 찾는 과정이다. 즉, 인덱스 스캔 시작점을 찾는 과정이다.

 

인덱스 수직적 탐색은 루트(Root) 블록에서부터 시작한다. 루트를 포함해 브랜치(Branch) 블록에 저장된 각 인덱스 레코드는 하위 블록에 대한 주소값을 갖는다. 루트에서 시작하여 리프(Leaf) 블록까지 수직적 탐색이 가능한 이유다.

 

수직적 탐색 과정에 찾고자 하는 값보다 크거나 같은 값을 만나면, 바로 직전 레코드가 가리키는 하위 블록으로 이동한다.

여기서 중요한 것은 수직적 탐색은 조건을 만족하는 레코드를 찾는 과정이 아니라 조건을 만족하는 첫 번째 레코드를 찾는 과정임을 반드시 기억해야 한다.

 

 

인덱스 수평적 탐색 

수직적 탐색을 통해 스캔 시작점을 찾았다면, 찾고자 하는 데이터가 더 안 나타날 때까지 인덱스 리프 블록을 수평적으로 스캔한다. 인덱스에서 본격적으로 데이터를 찾는 과정이다. 인덱스 리프 블록끼리는 서로 앞뒤 블록에 대한 주소값을 갖는다. 즉, 양방향 연결 리스트(double linked list) 구조다. 좌에서 우로, 또는 우에서 좌로 수평적 탐색이 가능한 이유다.

 

인덱스를 수평적으로 탐색하는 이유는 첫째, 조건절을 만족하는 데이터를 모두 찾기 위해서고 둘째, ROWID를 얻기 위해서다. 필요한 컬럼을 인덱스가 모두 갖고 있어 인덱스만 스캔하고 끝나는 경우도 있지만, 일반적으로 인덱스를 스캔하고서 테이블도 액세스 한다. 이때 ROWID가 필요하다.

 

 

인덱스는 WHERE 절에 자주 등장하는 컬럼에 지정하거나, ORDER BY에 자주 사용되는 컬럼에 사용해주면 좋다.

 

선택도가 낮은 컬럼을 앞쪽에 두고 결합인덱스를 생성해야 검사 횟수를 줄일 수  있어 성능에 유리하다.

'Back-End > DB' 카테고리의 다른 글

SQL 파싱과 최적화  (3) 2024.07.25
Lock 과 트랜잭션 동시성 제어 (Oracle)  (3) 2024.07.23
인덱스의 기본  (3) 2023.10.11
인덱스를 사용하는 이유  (0) 2023.09.14
DB 설계를 잘못하면 생기는 일  (1) 2023.09.13

데이터베이스 테이블에서 데이터를 찾는 방법은 무엇이 있을까?

  • 테이블 전체를 스캔한다.
  • 인덱스를 이용한다.

위 두 가지 방법이 있다. 

 

테이블 전체 스캔과 관련해서는 튜닝 요소가 많지 않지만, 인덱스와 관련해서는 튜닝 요소가 매우 많고 기법도 다양하여 SQL을 공부할때 가장 먼저 다루어야 한다.

 

인덱스 튜닝의 두 가지 핵심요소

인덱스는 큰 테이블에서 소량 데이터를 검색할때 사용한다. 여러 가지 방법이 있지만, 핵심요소는 크게 두 가지로 나뉜다. 

 

첫 번째는 인덱스 스캔 과정에서 발생하는 비효율을 줄이는 것이다. 즉, 인덱스 스캔 효율화 튜닝이다.

 

인덱스 튜닝의 두 번째 핵심요소는 테이블 엑세스 횟수를 줄이는 것이다. 인덱스 스캔 후 테이블 레코드를 액세스할 때 랜덤 I/O 방식을 사용하므로 이를 랜덤 액세스 최소화 튜닝이라고 한다.                                                                                                                                                                                                                                                                                                    

인덱스 스캔 효율화 튜닝과 랜덤 액세스 튜닝 둘 다 중요하지만, 더 중요한 하나를 고른다면 랜덤 액세스 최소화 튜닝이다. 성능에 미치는 여향이 더 크기 때문이다.

 

SQL 튜닝은 랜덤 I/O와의 전쟁

데이터베이스 성능이 느린 이유는 디스크 I/O 때문이다. 읽어야 할 데이터량이 많고, 그 과정에서 디스크 I/O가 많이 발생할 때 느리다.

 

인덱스의 구조에 대해서 알아보자

 

인덱스 구조

인덱스는 대용량 테이블에서 필요한 데이터만 빠르게 효율적으로 액세스하기 위해 사용하는 오브젝트다. 모든 책 뒤쪽에 있는 색인과 같은 역할을 한다.

데이터베이스에서 인덱스 없이 데이터를 검색하려면, 테이블을 처음부터 끝까지 모두 읽어야 한다. 반면, 인덱스를 이용하면 일부만 읽고 멈출 수 있다. 즉, 범위 스캔(Range Scan이 가능하다. 범위 스캔이 가능한 이유는 인덱스가 정렬돼 있기 때문이다.

 

DBMS는 일반적으로 B*Tree 인덱스를 사용한다. 

나무(Tree)를 거꾸로 뒤집은 모양이여서 뿌리(Root)가 위쪽에 있고, 가지(Branch)를 거쳐 맨 아래에 잎사귀(Leaf)가 있다.

 

인덱스의 탐색 과정은 수직적 탐색과 수평적 탐색으로 나눌 수 있다.

  • 수직적 탐색 : 인덱스 스캔 시작지점을 찾는 과정
  • 수평적 탐색 : 데이터를 찾는 과정

 

 

                                                                       

'Back-End > DB' 카테고리의 다른 글

SQL 파싱과 최적화  (3) 2024.07.25
Lock 과 트랜잭션 동시성 제어 (Oracle)  (3) 2024.07.23
인덱스의 기본 (2)  (0) 2023.10.12
인덱스를 사용하는 이유  (0) 2023.09.14
DB 설계를 잘못하면 생기는 일  (1) 2023.09.13

자바스크립트 객체는 다음과 같이 크게 3개의 객체로 분류할 수 있다.

  • 표준 빌트인 객체(standard built-in objects/native objects/global objects) : 표준 빌트인 객체는 ECMAScript 사양에 정의된 객체를 말하며, 애플리케이션 전역의 공통 기능을 제공한다. 실행 환경과 관계없이 언제나 사용할 수 있다. 또 전역 객체의 프로퍼티로서 제공된다. 따라서 별도의 선언 없이 전역 변수처럼 언제나 참조할 수 있다.
  • 호스트 객체 (host objects) : 호스트 객체는 ECMAScript 사양에 정의되어 있지 않지만 자바스크립트 실행 환경에서 추가로 제공하는 객체를 말한다. 
  • 사용자 정의 객체(user-defined objects) : 사용자 정의 객체는 표준 빌트인 객체와 호스트 객체처럼 기본 제공되는 객체가 아닌 사용자가 직접 정의한 객체를 말한다.

 

표준 빌트인 객체

자바스크립트는 40여 개의 표준 빌트인 객체를 제공한다.

 

// String 생성자 함수에 의한 String 객체 생성
const strOjb = new String('Lee'); // String {"Lee"}
console.log(typeof strObj); // object

// Number 생성자 함수에 의한 String 객체 생성
const numOjb = new Number(123); // Number {123}
console.log(typeof numObj); // object

// RegExp 생성자 함수에 의한 RegExp 객체(정규 표현식) 생성
const regExp = new RegExp(/ab+c/i); // /ab+c/i
console.log(typeof regExp); // object
  • 무명의 리터럴로 생성할 수 있다. 즉, 런타임에 생성이 가능하다
  • 변수나 자료구조(객체, 배열 등)에 저장할 수 있다
  • 함수의 매개변수에 전달할 수 있다
  • 함수의 반환값으로 사용할 수 있다

위의 조건을 만족하는 객체를 일급 객체라 한다. 자바스크립트의 함수는 위의 조건을 모두 만족하기 때문에 일급 객체다.

 

// 함수는 무명의 리터럴로 생성할 수 있다.
// 함수는 변수에 저장할 수 있다.
// 런타임(할당 단계)에 함수 리터럴이 평가되어 함수 객체가 생성되고 변수에 할당된다.
const increase = function (num) {
	return ++num;
};

const decrease = funtion(num) {
	return --num;
};

// 함수는 객체에 저장할 수 있다
const predicates = { increase, decrease };

// 함수의 매개변수에 전당할 수 있다
function makeCounter(predicate) {
	let num = 0;
    
    return function() {
    	num = predicate(num);
        return num;
    };
}

// 함수는 매개변수에게 함수를 전달할 수 있다.
const increaser = makeCounter(predicates.increase);

일급 객체로서 함수가 가지는 가장 큰 특징은 일반 객체와 같이 함수의 매개변수에 전달할 수 있으며, 함수의 반환값으로 사용할 수도 있다는 것이다. 이는 함수형 프로그래밍을 가능케 하는 자바스크립트의 장점이다.

 

 

함수 객체의 프로퍼티

함수는 객체이기 때문에 함수도 프로퍼티를 가질 수 있다. 

함수 객체의 프로퍼티

square 함수의 모든 프로퍼티의 프로퍼티 어트리뷰트를 Object.getOwnPropertyDescriptors 메서드로 확인해 보면 다음과 같다.

function square(number) {
	return number * number;
}

console.log(Object.getOwnPropertyDescriptors(square));

/*
	{
    	length: {value:1, writable: false, enumerable: false, configurable: true},
        name: {value: "square", writable: false, enumerable: false, configurable: true},
        arguments: {value: null, writable: false, enumerable: false, configurable: false},
    	caller: {value: null, writable: false, enumerable: false, configurable: false},
        prototype: {value: {....}, writable: true, enumerable: false, configurable: false}
    }
*/

// __proto__는 square 함수의 프로퍼티가 아니다.
console.log(Object.getOwnPropertyDescriptor(square, '__proto__')); // undefined

// __proto__는 Object.prototype 객체의 접근자 프로퍼티다.
/ square 함수는 Object.prototype 객체로부터 __proto__ 접근자 프로퍼티를 상속받는다.
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));
// {get: f, set: f, enumerable: false, configurable: true}

 

length 프로퍼티

함수 객체의 length 프로퍼티는 함수를 정의할 때 선언한 매개변수의 개수를 가리킨다.

function foo() {}
console.log(foo.length); // 0

function bar(x) {
	return x;
}
console.log(bar.length); // 1

 

name 프로퍼티

함수 객체의 name 프로퍼티는 함수 이름을 나타낸다. 

// 기명 함수 표현식
var namedFunc = function foo() {};
console.log(namedFunc.name); // foo

// 익명 함수 표현식
var anonymousFunc = function() {};
console.log(anonymousFunc.name); // anonymousFunc

// 함수 선언문
function bar() {}
console.log(bar.name); // bar

 

__proto__ 접근자 프로퍼티

모든 객체는 [[Prototype]] 이라는 내부 슬롯을 갖는다. __proto__ 프로퍼티는 [[Prototype]] 내부 슬롯이 가리키는 프로토타입 객체에 접근하기 위해 사용하는 접근자 프로퍼티다.

const obj = { a: 1 };

console.log(obj.__proto__ === Object.prototype);

// 객체 리터럴 방식으로 생성한 객체는 프로토타입 객체인 Object.prototype의 프로퍼티를 상속받는다.
// hasOwnProperty 메서드는 Object.prototype의 메서드다.
console.log(obj.hasOwnProperty('a')); // true
console.log(obj.hasOwnProperty('__proto__')); // false

 

prototype 프로퍼티

prototype 프로퍼티는 생성자 함수로 호출할 수 있는 객체, 즉 constructor만이 소유하는 프로퍼티다.

일반 객체와 생성자 함수로 호출할 수 없는 non-constructor에는 prototype 프로퍼티가 없다.

// 함수 객체는 prototype 프로퍼티를 소유한다.
(function () {}).hasOwnProperty('prototype'); // true

// 일반 객체는 prototype 프로퍼티를 소유하지 않는다.
({}).hasOwnProperty('prototype'); // false

시간 복잡도(time complex)

시간 복잡도란 어느 코드를 실행했을 때 실행 시간이 어느정도일지 표현해 보는 것이다.

여기서 실행시간이랑 함수/알고리즘 수행에 필요한 스텝(step) 수 이다.

int[] multiply(int[] inputs, int multiplier) {
	int[] nums = new int[inputs.length];
    
    for(int i = 0; i < inputs.length; i++) }
    	nums[i] = inputs[i] * multiplier;
    }
    return nums;
}

위와 같은 코드가 있을 때 각각 라인이 실행되는 스텝은 상수로 표시된다. 따라서 각 라인의 스텝수와 실행시간은 아래와 같이 정리할 수 있다.

cost times
c1 1
c2 N+1
(for 문을 돌고 빠져나올때 한번 더 실행되기 때문에)
c3 N
c4 1

이렇게 정리된 것을 수식으로 정리하면

 

T(N) = c1 + c2 * (N+1) + c3 * N + 1

         = (c2 + c3) * N + c1 + c2 + 1 

         = a * N + b (위의 식을 치환하였다) 여기서 N 은 input의 Size 에 해당한다.

 

위의 식을 정리하면 

  • 여기서 더 정확한 계산은 어렵다
  • N이 작을땐 실행 시간이 의미가 없다

그럼 여기서 N -> 무한대일 때 실행 시간은 어떻게 될까?

  • N이 커질수록 덜 중요한 것은 제거된다
  • 최고차항만 의미있다.
  • 최고차항의 계수는 의미가 없다. (위의 식에서 a 부분)

라는 사실을 알게된다. 이를 점근적 분석이라고 하며, 임의의 함수가 N -> 무한대일 때 어떤 함수 형태에 근접하는지 분석하는 것이다.

 

다시 정리해

 

시간 복잡도는 함수의 실행 시간을 표현하는 것이고, 주로 점근적 분석을 통해 실행 시간을 단순하게 표현하며 이때 점근적 표기법으로 표현한다.

 

boolean exists(int[] inputs, int target) {
	for (int i = 0; i < inputs.length; i++) {
    	if(inputs[i] == target) {
        	return true;
        }
    }
    
    return false;
}

위와 같은 코드가 있을 때 함수의 파라미터 데이터에 따라 실행시간이 조금씩 달라지게 된다. 만약 target 이 앞쪽에 있다면 실행 시간이 짧게 걸리고, 뒤에 있다면 길게 걸릴 것이다. 이런 경우  case 정리가 필요하다

case when times
best 0번째에 존재 1
worst 마지막에 존재 or 존재하지 않음 N

따라서

함수의 실행 시간은 아무리 빨라도 상수 시간 이상 or 함수 실행 시간은 아무리 오래 걸려도 N에 비례하는 정도 이하

이기 때문에 

O(N) 점근 표기법으로 표현할 수 있다.

 

 

 

'자료구조&알고리즘' 카테고리의 다른 글

순환 (Recursion)  (3) 2024.07.16
Array에서 Index는 왜 0부터 시작할까?  (2) 2023.09.15
List 와 Set  (1) 2023.09.12
Array List 와 Linked List  (1) 2023.09.08
Array 와 List 의 차이  (1) 2023.09.08
  • 스프링은 프레임워크다.
  • 스프링은 오픈소스다.
  • 스프링은 IOC 컨테이너를 가진다.
  • 스프링은 DI를 지원한다.
  • 스프링은 엄청나게 많은 필터를 가지고 있다.
  • 스프링은 MessageContertor를  가지고 있다. 기본값은 현재 Json이다.
  • 스프링은 BufferedReader 와 BufferedWriter를 쉽게 사용가능하다.\

 

스프링은 프레임워크다

framework 를 살펴보면 frame : 틀 + work : 동작하다 이다. 

풀이를 해보면 어떤 틀에서 동작하는 것이다. 틀을 제공해주고 여기에 맞춰서 개발을 하면 누구나 좋은 프로그램을 만들 수 있기 때문에 사용한다.

 

 

IOC(Inversion Of Controll)

뜻을 해석해 보면 역전의 제어이다 즉 주도권이 스프링에게 있다는 것이다.

 

우선 class, object, instance 에 대해 알아야 한다.

  • class : 설계도
  • object : 실체화가 가능한 어떤 것
  • instance : 실체과 된 것

만약 가구가 있다고 해보자 가구는 추상적이다. 가구에 해당하는 의자, 침대, 책상이 있다고 하면 의자, 침대, 책상은 object에 해당한다. 이 object들이 실체화가 되면 그게 instance가 되는 것이다.

 

그렇다면 IOC 는 무엇일까? 

만약 오브젝트를 만들어 본다고 하면 

 

의자 chair = new 의자();

위의 chair 는 힙 메모리에 저장되어 사용 가능하게 된다. IOC는 이러한 수많은 object 들을 읽어서 직접 사용가능하게 해주는 것이다.

 

 

DI(Dependencies Injection)

위 단어를 해석해 보면 의존성 주입이라는 뜻이다. 

스프링이 내가 만든 class 들을 관리하는데 내가 원하는 다른 곳에서 사용(공유)할 수 있게 해주는 것이 DI이다.

위에 있는 IOC와 연관이 되어 있다.

 

'Back-End > Java' 카테고리의 다른 글

스레드  (1) 2024.07.05
프로세스  (0) 2024.07.04
Java HTTP 통신  (4) 2024.06.12
Exception과 Transaction  (1) 2024.02.05
String, StringBuilder, StringBuffer 의 차이점  (1) 2023.10.26

Array는 두 가지 요소로 표현할 수 있다.

  1. Array의 시작 주소
  2. 각 item의 Size(byte)

c언어에서 int 배열을 하나 만들었다고 해보자

 

int nums[5] = {1,2,3,4,5}

 

배열의 시작을 가리키는 시작주소가 1000 이라고 했을 때 다음 item 의 시작 주소는 1000 + 4 로 설정되고, 다음은 1000 + 4 + 4 계속 이런 식으로 반복하게 된다.

 

여기서 4는 item int 의 크기 4byte를 뜻한다.

 

1000 + 4 === 1000 + 4 x 0 과 같다. 그렇기 때문에 쉽게 계산하기 위해서 0부터 시작하는 것이다. 

 

여기서 Array의 장점을 알 수 있다. 

Array의 size가 아무리 커도 똑같은 속도로 각 위치의 item 을 가져올 수 있다는 것이다.

'자료구조&알고리즘' 카테고리의 다른 글

순환 (Recursion)  (3) 2024.07.16
시간복잡도  (0) 2023.09.19
List 와 Set  (1) 2023.09.12
Array List 와 Linked List  (1) 2023.09.08
Array 와 List 의 차이  (1) 2023.09.08

+ Recent posts