Before coding in Spring framework
오래된 Spring framework 코드를 유지보수 할 일이 생겼다.
여타 웹 애플리케이션 프레임워크가 그렇듯, http request-response를 다루니까
크게 코드를 읽는 데 불편하지는 않았다.
그러나 애플리케이션 로직이 java 문법으로 작성된 만큼
java 개발 생태계를 익혀야 할 필요성을 느껴
간략하게 상기하는 차원에서 특별한 순서 없이 작성하였음.
java에는 여러가지 에디션이 있는데
1. java SE (J2SE) : 표준 에디션
2. jakarta EE(J2EE , 구 java EE) : 서버 페이지에 특화
3. java ME (J2ME) : 임베디드 환경에 특화 / 경량
등이 있다.
프로그램을 제작할 때, 사용 환경에 따라 적합한 유형의 java를 선택하여
개발할 수 있다.
.java 소스코드의 컴파일
Class 선언
static 변수(: class attribute, class method)static 키워드가 앞에 붙어있는 변수는
객체가 아닌 클래스에 포함되므로
Heap 영역 메모리의 정적 영역에 생성된다.
또한, 객체가 아닌 클래스에 포함되므로
new로 객체를 생성하지 않아도
클래스가 JVM에 로드될 때 한 번 생성되고
생성된 객체들이 이 변수를 공유할 수 있다.
- 객체 생성 없이 사용 가능
- 전 객체에서 공유 가능
this
생성되어 실행 중인 객체의 주소를 가리키는 변수.
stack 프레임에 존재하며 객체가 없으면 존재할 수 없다.
protected는
상위 class가 가진 멤버 변수 중,
외부에는 private,
하위 class에는 public으로 사용하고 싶을 때 선언한다.
클래스 간 형변환
여타 웹 애플리케이션 프레임워크가 그렇듯, http request-response를 다루니까
크게 코드를 읽는 데 불편하지는 않았다.
그러나 애플리케이션 로직이 java 문법으로 작성된 만큼
java 개발 생태계를 익혀야 할 필요성을 느껴
간략하게 상기하는 차원에서 특별한 순서 없이 작성하였음.
===============================================================
JAVA
JAVA'S Editionsjava에는 여러가지 에디션이 있는데
1. java SE (J2SE) : 표준 에디션
2. jakarta EE(J2EE , 구 java EE) : 서버 페이지에 특화
3. java ME (J2ME) : 임베디드 환경에 특화 / 경량
등이 있다.
프로그램을 제작할 때, 사용 환경에 따라 적합한 유형의 java를 선택하여
개발할 수 있다.
JSP
HTML 페이지를 동적으로 생성하기 위한 파일.
JSP Template은 Java Servlet 코드로 변환된다.
HTML page에 Java 코드가 포함된 꼴을 띄고 있다.
최근엔 JS, JS 프레임워크에 비해 밀리는 추세.
HTML Page를 동적으로 만드는 것이 줄고 있음.
왜냐하면 현대에는 API를 사용하여
서버 자원에 접근을 하고(DB, File)
화면에 보여주는 UI는 HTML/CSS/JS를 사용한다.
따라서 client <-> server 간 통신이 필요하고
XHR, XML HttpRequest를 사용한다.
이런 프로그래밍 기법을 AJAX라함.
JSP Template은 Java Servlet 코드로 변환된다.
HTML page에 Java 코드가 포함된 꼴을 띄고 있다.
최근엔 JS, JS 프레임워크에 비해 밀리는 추세.
동적 HTML page 생성 vs AJAX
서버 사이트 스크립트 언어를 사용해서HTML Page를 동적으로 만드는 것이 줄고 있음.
왜냐하면 현대에는 API를 사용하여
서버 자원에 접근을 하고(DB, File)
화면에 보여주는 UI는 HTML/CSS/JS를 사용한다.
따라서 client <-> server 간 통신이 필요하고
XHR, XML HttpRequest를 사용한다.
이런 프로그래밍 기법을 AJAX라함.
.java 소스코드의 컴파일
프로그래머가 작성한 .java 소스 코드는
Javac 컴파일러에 의해 .class코드로 변환되고
windows / linux / mac 환경에 각각 깔린 jvm에 의해
해당 시스템의 기계어에 맞게 번역되어 실행된다.
다양한 플랫폼에서 구동가능한 이유는 jvm 덕.
일반적으로 java를 설치한다는 것은
java 컴파일러 , jvm이 설치된 다는 것을 뜻 함.
JDK : Java 라이브러리
JRE : Java 버추얼 머신
===============================================================
Javac 컴파일러에 의해 .class코드로 변환되고
windows / linux / mac 환경에 각각 깔린 jvm에 의해
해당 시스템의 기계어에 맞게 번역되어 실행된다.
다양한 플랫폼에서 구동가능한 이유는 jvm 덕.
일반적으로 java를 설치한다는 것은
java 컴파일러 , jvm이 설치된 다는 것을 뜻 함.
JDK : Java 라이브러리
JRE : Java 버추얼 머신
===============================================================
JAVA Syntax
기본 자료형 vs 참조 자료형
정적 타이핑에 정의되는 변수들은 기본 자료형을 따른다.
(byte, short, int 등...)
배열, String과 같은 경우는
기본 자료형 여러개가 순서를 가지며 존재하는 형태기 때문에
기본 자료형으로 볼 수 없다.
참조 자료형은 기본 자료형을 바탕으로 정의된
class, interface, 열거형과 같은 자료형이다.
- JDK 제공 Class
- 직접 구현한 Class 또한 포함된다.
(byte, short, int 등...)
배열, String과 같은 경우는
기본 자료형 여러개가 순서를 가지며 존재하는 형태기 때문에
기본 자료형으로 볼 수 없다.
참조 자료형은 기본 자료형을 바탕으로 정의된
class, interface, 열거형과 같은 자료형이다.
- JDK 제공 Class
- 직접 구현한 Class 또한 포함된다.
Class 선언
<접근 제어자> class <클래스 이름>
{
멤버 변수 선언,
생성자 선언,
메서드 선언
}
Static code는 곧 Instance화 되어 동적으로 메모리에 배치된다.
객체는 new 키워드를 통해 생성한다.
{
멤버 변수 선언,
생성자 선언,
메서드 선언
}
Static code는 곧 Instance화 되어 동적으로 메모리에 배치된다.
객체는 new 키워드를 통해 생성한다.
생성자 (Constructor)
생성자의 목적은 인스턴스를 생성하는 것.
객체를 생성할 때
초기화할 명령어의 집합이며
주로 멤버 변수의 초기화를 담당한다.
생성자 오버로딩
매개변수를 달리하는 생성자를
여러개 선언하는 것.
어떤 class로부터 생성자를 사용하여 객체를 생성한다고 가정하자.
우선 프로그램은 main함수로부터 시작하므로
main 함수를 위한 프레임이 stack 공간에 생기고,
지역 변수를 위한 공간이 예약된다.
위에서 언급한 new 키워드를 통해
인스턴스(객체)가 생성되면 heap 메모리에 배치되고
객체 내부의 멤버 변수들도 인스턴스화 되어 값을 가지게 된다.
stack 메모리에 공간이 예약된 지역변수는
방금 생성된 객체의 주소를 가리킨다.
위 case에서 만약 인스턴스 생성시 args를 넘겨줘야한다면
args에 해당하는 값들은 main 함수에 존재하므로
stack 메모리에 존재한다.
객체를 생성할 때
초기화할 명령어의 집합이며
주로 멤버 변수의 초기화를 담당한다.
생성자 오버로딩
매개변수를 달리하는 생성자를
여러개 선언하는 것.
어떤 class로부터 생성자를 사용하여 객체를 생성한다고 가정하자.
우선 프로그램은 main함수로부터 시작하므로
main 함수를 위한 프레임이 stack 공간에 생기고,
지역 변수를 위한 공간이 예약된다.
위에서 언급한 new 키워드를 통해
인스턴스(객체)가 생성되면 heap 메모리에 배치되고
객체 내부의 멤버 변수들도 인스턴스화 되어 값을 가지게 된다.
stack 메모리에 공간이 예약된 지역변수는
방금 생성된 객체의 주소를 가리킨다.
위 case에서 만약 인스턴스 생성시 args를 넘겨줘야한다면
args에 해당하는 값들은 main 함수에 존재하므로
stack 메모리에 존재한다.
Static , This , Method
static 변수(: class attribute, class method)
객체가 아닌 클래스에 포함되므로
Heap 영역 메모리의 정적 영역에 생성된다.
또한, 객체가 아닌 클래스에 포함되므로
new로 객체를 생성하지 않아도
클래스가 JVM에 로드될 때 한 번 생성되고
생성된 객체들이 이 변수를 공유할 수 있다.
- 객체 생성 없이 사용 가능
- 전 객체에서 공유 가능
this
생성되어 실행 중인 객체의 주소를 가리키는 변수.
stack 프레임에 존재하며 객체가 없으면 존재할 수 없다.
method의 lifecycle
메서드 코드는 코드 영역에 배치되고
실행은 Stack 영역에서 수행된다.
메서드가 호출되면 Stack 영역에
해당 메서드를 위한 frame이 할당되고
이 프레임에 메서드 안의 지역 변수, 매개변수, 리턴 값 이 담긴다.
메서드 실행이 끝나면 할당된 Stack Frame이 해제된다.
실행은 Stack 영역에서 수행된다.
메서드가 호출되면 Stack 영역에
해당 메서드를 위한 frame이 할당되고
이 프레임에 메서드 안의 지역 변수, 매개변수, 리턴 값 이 담긴다.
메서드 실행이 끝나면 할당된 Stack Frame이 해제된다.
정보 은닉
private, default, protected, public의 접근 제어자가 있으며
필드에 private 을 선언하여 정보 은닉을 구현할 수 있다.
필드에 private 을 선언하여 정보 은닉을 구현할 수 있다.
private 설정시 해당 클래스의 메서드를 통해서만
heap 데이터에 접근할 수 있다.
public이라면 외부 객체에서도 heap 주소를 타고 들어와
직접 값을 조작할 수 있다.
외부에서 값을 조작하고 싶거나, 값을 알고싶은 경우
메서드를 내부에 구현하는 형태로 구현할 수 있다.
private로 선언한 경우, 하위 클래스에 생성은 되지만
부모 클래스라도 접근은 할 수 없다.
heap 데이터에 접근할 수 있다.
public이라면 외부 객체에서도 heap 주소를 타고 들어와
직접 값을 조작할 수 있다.
외부에서 값을 조작하고 싶거나, 값을 알고싶은 경우
메서드를 내부에 구현하는 형태로 구현할 수 있다.
private로 선언한 경우, 하위 클래스에 생성은 되지만
부모 클래스라도 접근은 할 수 없다.
protected는
상위 class가 가진 멤버 변수 중,
외부에는 private,
하위 class에는 public으로 사용하고 싶을 때 선언한다.
배열
동일한 자료형을 순차적으로 관리하는 자료형이다.
기본형 자료형으로 이뤄진 배열이 있고
객체들이 나열된 배열이 있다.
기본형 자료형으로 이뤄진 배열이 있고
객체들이 나열된 배열이 있다.
현대에는 Enhanced loops 의 문법을 사용하여 순회하며
ArrayList class라는
배열 사용에 필요한 기능들을 미리 구현된 class를 사용하여
간편하게 배열을 조작할 수 있다.
ArrayList class라는
배열 사용에 필요한 기능들을 미리 구현된 class를 사용하여
간편하게 배열을 조작할 수 있다.
상속
상위 class와 하위 class는
"하위 class는 상위 class다"라는 Is-A관계를 따른다.
상위 class는 다른 표현으로
parent class, super class, base class로도 불리며
하위 class는 다른 표현으로
child class, sub class, derived class로도 불린다.
상속에서 두드러지게 나타나는 특징은
코드 재사용인데 , 이 목적만으로 쓰이지는 않는다.
"하위 class는 상위 class다"라는 Is-A관계를 따른다.
상위 class는 다른 표현으로
parent class, super class, base class로도 불리며
하위 class는 다른 표현으로
child class, sub class, derived class로도 불린다.
상속에서 두드러지게 나타나는 특징은
코드 재사용인데 , 이 목적만으로 쓰이지는 않는다.
대신 주로 일반적인 개념의 class보다
구체적인 class를 구현할 때 사용한다.
하위 class가 생성될 때, 상위 class 생성자를 먼저 호출한다.
프로그래밍 언어마다 상속의 특성이 다르다.
JAVA는 단일 상속,
C++는 Multi 상속이 가능하며 'diamond problem'을 유발한다.
한 클래스가 두 개의 클래스를 상속 받는데
그 두 상속자가 다시 하나의 부모 클래스를 공통으로 가질 때
구체적인 class를 구현할 때 사용한다.
하위 class가 생성될 때, 상위 class 생성자를 먼저 호출한다.
프로그래밍 언어마다 상속의 특성이 다르다.
JAVA는 단일 상속,
C++는 Multi 상속이 가능하며 'diamond problem'을 유발한다.
한 클래스가 두 개의 클래스를 상속 받는데
그 두 상속자가 다시 하나의 부모 클래스를 공통으로 가질 때
발생하는 문제이다.
JAVA의 설계자는 C++ 상속의 복잡성을 없애고 싶었기에
단일 상속 정책을 적용했다.
JAVA는 클래스간 다중 상속 대신
Interface를 통한 다중 구현을 지원한다.
JAVA의 설계자는 C++ 상속의 복잡성을 없애고 싶었기에
단일 상속 정책을 적용했다.
JAVA는 클래스간 다중 상속 대신
Interface를 통한 다중 구현을 지원한다.
클래스 간 형변환
상위 Class가 하위 Class의 기능을 받는 것을 형변환이라고 한다.
묵시적인 down casting은 불가능하고 (상위 -> 하위)
명시적으로 강제 형변환이 필요하다.(하위 -> 상위)
안전한 형 변환을 위해 instanceof와 같은 형 확인 로직 확보가 필요.
추상 class를 사용하면
빈번하게 사용되는 템플릿 메서드라는 설계 패턴을 구현할 수 있다.
묵시적인 down casting은 불가능하고 (상위 -> 하위)
명시적으로 강제 형변환이 필요하다.(하위 -> 상위)
안전한 형 변환을 위해 instanceof와 같은 형 확인 로직 확보가 필요.
메서드 재정의(override)
하위 클래스는 기능적으로 상위 클래스와 다른 메서드를 구현할 수 있지만
name, return type, argument list는 같아야한다.
이는 컴파일러에서 강제됨.
@override를 통해 컴파일러에게 알려준다.
이 데코레이터가 없으면 컴파일러는
기존 메서드와 다른 메서드로 인식한다.
name, return type, argument list는 같아야한다.
이는 컴파일러에서 강제됨.
@override를 통해 컴파일러에게 알려준다.
이 데코레이터가 없으면 컴파일러는
기존 메서드와 다른 메서드로 인식한다.
가상 메서드
프로그램에서 어떤 (변수)/(메서드)의 참조는 타입에 따라 이뤄진다.
그러나 가상 메서드는 타입과 상관없이
실제 생성된 인스턴스의 메서드가 호출한다.
Java의 경우 모든 메서드가 가상 메서드다.
C++의 가상함수가 메서드 호출에서는 인스턴스를 호출하고
Java의 모든 메서드(non-stastic)는
가상 메서드 이므로 인스턴스를 호출한다.
그러나 가상 메서드는 타입과 상관없이
실제 생성된 인스턴스의 메서드가 호출한다.
Java의 경우 모든 메서드가 가상 메서드다.
C++의 가상함수가 메서드 호출에서는 인스턴스를 호출하고
Java의 모든 메서드(non-stastic)는
가상 메서드 이므로 인스턴스를 호출한다.
C++, JAVA 모두 실행 시점에
vtable(가상 함수 테이블)을 활용하여 타깃 함수를 찾아간다.
c++는 컴파일 타임에 호출 주소가 결정되며
따라서 정적으로 바인딩된다.
java는 런타임에 jvm이 타입을 확인하고 메서드를 호출한다.
(참고 : JIT컴파일러가 이 부분을 최적화함)
vtable(가상 함수 테이블)을 활용하여 타깃 함수를 찾아간다.
c++는 컴파일 타임에 호출 주소가 결정되며
따라서 정적으로 바인딩된다.
java는 런타임에 jvm이 타입을 확인하고 메서드를 호출한다.
(참고 : JIT컴파일러가 이 부분을 최적화함)
다형성
가상 메서드 원리에 기반하여 구현된다.
상위 클래스 자료형으로 하위 클래스를 관리할 수 있다.
하나의 코드를 여러 자료형으로 쓸 수 있으므로
다양한 구현이 가능하다.
[다형성이 구현되는 절차]
상위 Class 대입 -> 메서드 overriding -> 가상함수에 의한 호출
상위 클래스 자료형으로 하위 클래스를 관리할 수 있다.
하나의 코드를 여러 자료형으로 쓸 수 있으므로
다양한 구현이 가능하다.
[다형성이 구현되는 절차]
상위 Class 대입 -> 메서드 overriding -> 가상함수에 의한 호출
상속 관계 vs 포함 관계
Inheritance. 상속 관계는 Is-A.
Composition. 포함 관계는 Has-A임이 엄연히 다르다.
Composition. 포함 관계는 Has-A임이 엄연히 다르다.
예약어 final
- final 변수는 값이 변경될 수 없는 상수를 지정할 때 변수 앞에 사용.
- 오직 1번만 값 할당이 가능하다.
- 하위 클래스에서 재정의 할 수 없다.
- 오직 1번만 값 할당이 가능하다.
- 하위 클래스에서 재정의 할 수 없다.
- final class의 경우 더 이상 상속이 불가능하다.
추상 Class
추상 class는 상속하기 위한 class.
아래는 그냥 제가 추상 Class를 이해하기 위한 재미없는 상황극입니다.
[ 추상 class P]
"미래의 class 여러분, 저를 상속받아서 필요한 기능을 구현하십시오.
아래는 그냥 제가 추상 Class를 이해하기 위한 재미없는 상황극입니다.
[ 추상 class P]
"미래의 class 여러분, 저를 상속받아서 필요한 기능을 구현하십시오.
여러분은 저를 상속받게되면 자동으로 구현할 책임 또한 지게 됩니다."
[ 추상 class P를 상속받아 구현된 객체 A ]
[ 추상 class P를 상속받아 구현된 객체 A ]
"너 추상 class를 본 적 있어 ? "
[ 추상 class P를 상속받아 구현된 객체 B ]
"실제로 본 적은 없어. 그냥 설계도만 있던데? "
[ 추상 class P를 상속받아 구현된 객체 A ]
"신기하군. 걔가 요구하는 기능들이 우리에겐 다 탑재되어있으니까
우리도 추상 class P 아니야?"
우리도 추상 class P 아니야?"
[ 추상 class P를 상속받아 구현된 객체 B ]
"공통된 부모를 가진 것은 맞지.
하지만 네가 하는 일과 내가 하는 일은 다르다고.
하는 일의 이름이 같더라도 다른 곳에 있는 작업을 수행하거든."
하지만 네가 하는 일과 내가 하는 일은 다르다고.
하는 일의 이름이 같더라도 다른 곳에 있는 작업을 수행하거든."
[ 추상 class P를 상속받아 구현된 객체 A ]
"흠...궁금한데, 어디 한 번 볼까..."
"흠...궁금한데, 어디 한 번 볼까..."
[ 추상 class P를 상속받아 구현된 객체 B ]
"미안하지만 보안상 그 값은 나만 쓸 수 있거든.
직접 접근하는 건 안 돼."
"미안하지만 보안상 그 값은 나만 쓸 수 있거든.
직접 접근하는 건 안 돼."
[ 추상 class P를 상속받아 구현된 객체 A ]
"추상 class P에서 final로 정의된 변수들 말고는
다른 변수들을 알 수 있는 방법이 없군, 원"
다른 변수들을 알 수 있는 방법이 없군, 원"
추상 class를 사용하면
빈번하게 사용되는 템플릿 메서드라는 설계 패턴을 구현할 수 있다.
인터페이스
인터페이스는 객체의 사용 설명서인 동시에
class가 필수적으로 구현할 수 있게 하는 규격이다.
추상 클래스로 상속받을 때는 extends를 쓰고, "A는 P의 일종이다"를 의미.
인터페이스(class)는 implements를 쓰고, "A는 p의 기능을 가진다"를 의미(p는 인터페이스)
추상 클래스를 상속받는 목적은
추상 클래스P의 기능을 물려받고 확장하는 것.
class가 필수적으로 구현할 수 있게 하는 규격이다.
추상 클래스로 상속받을 때는 extends를 쓰고, "A는 P의 일종이다"를 의미.
인터페이스(class)는 implements를 쓰고, "A는 p의 기능을 가진다"를 의미(p는 인터페이스)
추상 클래스를 상속받는 목적은
추상 클래스P의 기능을 물려받고 확장하는 것.
인터페이스의 목적은
동일한 규격의 동작을 수행함을 보장하기.
- new를 사용하여 객체를 만드는 것이 아니라 class가 필요하다.
인터페이스의 모든 메서드는 public abstract의 추상 메서드이고
인터페이스의 변수는 public static final(상수)임.
- 인터페이스 class 하나로 여러 class를 만들 수 있다.
동일한 규격의 동작을 수행함을 보장하기.
- new를 사용하여 객체를 만드는 것이 아니라 class가 필요하다.
인터페이스의 모든 메서드는 public abstract의 추상 메서드이고
인터페이스의 변수는 public static final(상수)임.
- 인터페이스 class 하나로 여러 class를 만들 수 있다.
인스턴스화 될 수 없기에 new는 사용 불가.
댓글
댓글 쓰기