생성자를 이용한 초기화와 설정자를 이용한 초기화 비교
public class Application {
public static void main(String[] args) {
/* 생성자를 이용한 초기화(constructor)와 설정자를 이용한 초기화 비교 */
/* 생성자를 이용한 초기화와 설정자(setter)를 이용한 초기화는 각각의 장단점이 존재한다.
*
*
* 1. 생성자를 이용한 초기화
* 장점 : setter메소드를 여러 번 호출해서 사용하지 않고 단 한번의 호출로
* 인스턴스를 생성 및 초기화 할 수 있다.
* 단점 : 필드를 초기화 할 매개변수의 갯수를 경우의 수 별로 모두 만들어두어야 한다.
* 호출시 인자가 많아지는 경우 어떤 값이 어떤 필드를 의미하는지 한 눈으로
* 보기 힘들다.
*
*
* 2. 설정자를 이용한 초기화
* 장점 : 필드를 초기화 하는 각각의 값들이 어떤 필드를 초기화 하는지 명확하게 볼 수 있다.
* 단점 : 하나의 인스턴스를 생성할때 한번의 호출로 끝나지 않는다.
*
*
* */
/* 생성자를 이용한 초기화 */
UserDTO user1 = new UserDTO("greedy", "greedy", "greedy", new java.util.Date());
System.out.println(user1.getInformation());
// 콘솔
// User DTO [id=greedy, name=greedy, pwd=greedy, enrollDate=Thu Dec 30 09:37:57 KST 2021]
/* 기본 생성자와 설정자를 이용한 초기화 */
UserDTO user2 = new UserDTO();
user2.setId("greedy");
user2.setPwd("greedy");
user2.setName("greedy");
user2.setEnrollDate(new java.util.Date());
System.out.println(user2.getInformation());
// 콘솔
//User DTO [id=greedy, name=greedy, pwd=greedy, enrollDate=Thu Dec 30 09:37:57 KST 2021]
}
}
public class UserDTO {
/* 일반적으로 DTO(Data Transfer Object) 목적으로
* 설계된 클래스는 명사 뒤에 DTO를 붙인다. */
/* UserDTO, MemberDTO, BoardDTO 등...
* 참고) VO(Value Object) 라는 용어와 혼용해서 사용하기도 함
* 값을 담고있는 객체라고 받아 들여라
*
* */
/* 모든 필드를 private 접근제한으로 선언 */
private String id;
private String pwd;
private String name;
private java.util.Date enrollDate;
/* 필드 아래엔 생성자 작성
* 기본생성자 명시적으로 작성
* 매개변수 있는 생성자를 선택적으로 추가할 수 있도록 기본생성자를
* 명시한다.
* 명시하지 않고 추후 매개 변수 생성자를 추가할 시
* 에러발생가능성이 있기 때문*/
public UserDTO() {}
/* 매개 변수 있는 생성자는 선택 사항이다.
* 필요에 따라 만들지만 일반적으로 가장 많이 가용 되는 생성자는
* 모든 필드를 초기화 하는 생성자이다.
*
* */
public UserDTO(String id, String pwd, String name, java.util.Date enrollDate) {
this.id = id;
this.pwd = pwd;
this.name = name;
this.enrollDate = enrollDate;
}
/* 설정자(Setter)와 접근자(Getter) */
/* 설정자(setter) */
public void setId(String id) {
this.id = id;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public void setName(String name) {
this.name = name;
}
public void setEnrollDate(java.util.Date enrollDate) {
this.enrollDate = enrollDate;
}
/* 접근자 (getter) */
public String getId() {
return id;
}
public String getPwd() {
return pwd;
}
public String getName() {
return name;
}
public java.util.Date getEnrollDate() {
return enrollDate;
}
/* 접근자로 하나씩 필드 값을 확인해보기 번거롭기 때문에
* 모든 필드의 값을 하나의 문자열로 반환하는 메소드를
* 필드값 확인 용으로 많이 사용한다. */
public String getInformation() {
return "User DTO [id=" + this.id +", name="+
this.name +", pwd="+ this.pwd +", enrollDate="+ this.enrollDate + "]";
}
}
오버로딩
오버로딩(Overloading)이란?
- 동일한 메소드명으로 다양한 종류의 매개변수에 따라 다르게 처리해야하는 것을 관리하기
위해 사용하는 기술 - 동일한 메소드명의 매개변수의 타입, 개수, 순서를 다르게 작성
- 즉 메소드의 시그니처(Signature)가 다르지만 메소드 명은 같게 함
오버로딩 테스트
public class OverloadingTest {
/* 생성자 작성시 매개변수 부분의 타입, 갯수, 순서를 다르게 작성하면
* 서로 다른 생성자로 인식해서 동일한 이름이지만 여러 개 작성할 수 있었다.
* => 오버로딩(overloading)
*
* 오버로딩의 사용이유
* 동일한 기능의 메소드를 매개변수에 따라 다르게 이름을 정의하면
* 복잡하고 관리하기가 어려워진다. 따라서 동일한 이름으로 다양한 종류의
* 매개변수에 따라 처리해야 하는 여러 메소드를 동일한 이름으로 관리하기 위해서 사용한다.
*
*
* 오버로딩의 조건
* 동일한 이름을 가진 메소드의 파라미터 선언부에 매개변수의 타입, 갯수,
순서를 다르게 작성하며
* 한 클래스 내에 동일한 이름의 메소드를 여러개 작성할 수 있도록 한다.
* 메소드의 시그니처가 다르면 다른 메소드로 인식하기 때문이다.
* 즉, 시그니처 중 메소드 이름은 동일해야 하기 때문에 파라미터 선언부가
다르게 작성 되어야 오버로딩이 성립된다.
*
*
* 메소드의 시그니처?
* public void method(int num) {}
* (오버로딩과 무관) (시그니처)
* 메소드의 메소드 명과 파라미터 선언부 부분을 시그니처 라고 부른다.
* method (int num) 이 부분이 시그니처이다.
* 즉, 접근제한자나 반환형은 오버로딩 성립 요건에 해당하지 않는다.
*
*
* */
/* 오버로딩을 이용한 메소드 작성 테스트를 위한 기준이 되는 메소드 */
public void test() {}
/* 메소드 시그니처가 동일한 경우 컴파일 에러를 발생시킨다. */
// public void test() {}
/* 접근 제한자에 따른 오버로딩 성립 확인
* -> 접근 제한자는 메소드 시그니처에 해당하지 않는다. */
//private void test() {}
/* 반환형에 따른 오버로딩 성립 확인
* -> 바환형은 메소드 시그니처에 해당하지 않는다. */
// publc int test() {return 0;}
/* 매개변수 유무에 따른 오버로딩 성립 확인
* -> 파라미터 선언부는 메소드 시그니처에 해당한다. */
public void test(int num) {}
/* 매개 변수의 이름은 메소드 시그니처에 영향을 주지 않는다. */
// public void test(int num2) {}
/* 매개변수 갯수에 따른 오버로딩 성립 확인 */
public void test(int num, int num2) {}
/* 매개변수 타입 변화에 따른 오버로딩 성립 확인 */
public void test (int num, String name) {}
/* 매개변수 순서에 따른 오버로딩 성립 확인 */
public void test (String name, int num) {}
}
파라미터
메소드의 파라미터 선언부에는 다양한 종류의 값을 인자로 전달하여 호출 가능
* 가변인자 : 인자가 넘어가는 갯수가 가변적이 되도록 설정할 수도 있다.
class Application
public class Application {
public static void main(String[] args) {
/* 메소드의 파라미터 선언부에는 다양한 종류의 값을 인자로 전달하여 호출할 수 있다.
*
* 매개변수(parameter) 로 사용 가능한 자료형
* 1. 기본자료형
* 2. 기본자료형 배열
* 3. 클래스자료형
* 4. 클래스자료형 배열
* 5. 가변인자
*
* */
ParameterTest pt = new ParameterTest();
// 컴파일 오류시 클래스 생성
/* 1. 기본자료형을 매개변수로 전달 받는 메소드 호출 확인 */
/* 기본자료형 8가지 모두 가능하다. */
int num = 20;
pt.testPrimaryTypeParameter(num);
System.out.println("메소드 호출 후 num :" + num);
// 콘솔 // 매개변수로 전달받은 값 : 20
// 인자로 전달하는 값 : [I@3830f1c0
// 매개변수로 전달받은 값 : [I@3830f1c0
/* 2. 기본자료형 배열을 매개변수로 전달 받는 메소드 호출 확인 */
int[] iarr = new int[] {1,2,3,4,5};
System.out.println("인자로 전달하는 값 : " + iarr);
pt.testPrimaryTypeArrayParameter(iarr); // 메소드로 생성
/* 메소드 호출 후 값 변경 확인 */
System.out.print("배열의 값 출력 :");
for (int i = 0; i < iarr.length; i++) {
System.out.print(iarr[i] + " ");
}
System.out.println();
// 콘솔
// 배열의 값 출력 :1 2 3 4 5
// 배열의 값 출력 :99 2 3 4 5
// 배열의 값 출력 :99 2 3 4 5
/* 3. 클래스 자료형 */
/* 사각형의 가로, 세로 길이를 저장할 RectAngle 이라는 클래스를 하나 추가해 보자 */
RectAngle r1 = new RectAngle(12.5, 22.5);
// 마우스 오버해서 클래스 생성
System.out.println("인자로 전달하는 값 :" + r1);
pt.testClassTypeParameter(r1); //메소드 생성
// 인자로 전달하는 값 :com.greedy.section05.parameter.RectAngle@71dac704
/* 메소드 호출 후 값 변경 확인 */
System.out.println("메소드 호출 후 사각형의 넓이와 둘레 ==========");
r1.clacArea();
r1.clacRound();
// 메소드 호출 후 사각형의 넓이와 둘레 ==========
// 이 사각형의 넓이는 10000.0입니다.
// 이 사각형의 둘레는 400.0입니다.
// 매개변수에서 클래스를 자료형으로 사용하는 것은 값 변경을 하는 것이다.
/* 4. 클래스 자료형 배열은 뒤에서 학습 */
/* 5. 가변인자 */
/* 인자로 전달하는 값의 갯수가 정해지지 ㅇ낳은 경우 가변배열을 활용할 수 있다. */
//pt.testVariableLengthArrayParameter();
// 인자가 아무것도 없는 경우 name이 전달되지않아 에러
pt.testVariableLengthArrayParameter("홍길동");
// name에 해당하는 것은 전달해야하지만 ...hobby인 가변인자는 하나도 전달되지않아도 괜찮다.
// 이름 : 홍길동
// 취미의 갯수 : 0
// 취미 :
pt.testVariableLengthArrayParameter("유관순", "축구", "농구", "배구");
// 이름 : 유관순
// 취미의 갯수 : 3
// 취미 : 축구 농구 배구
pt.testVariableLengthArrayParameter("신사임당", new String[] {"테니스","서예"});
// 배열도 전달 가능
// 이름 : 신사임당
// 취미의 갯수 : 2
// 취미 : 테니스 서예
/* 가변배열을 매개변수로 이용한 메소드는 모호성으로 인해 오버로딩 하지 않는 것이 좋다. */
}
}
class ParameterTest
public class ParameterTest {
public void testPrimaryTypeParameter(int iarr) {
System.out.println("매개변수로 전달받은 값 : " + iarr);
}
public void testPrimaryTypeArrayParameter(int[] iarr) {
/* 배열의 주소가 전달된다.
* 즉 인자로 전달하는 배열과 매개변수로 전달받은
* 배열은 서로 동일한 배열을 가리킨다.(얕은 복사)
*
* */
System.out.println("매개변수로 전달받은 값 : " + iarr);
/* 배열의 값 출력 */
System.out.print("배열의 값 출력 :");
for (int i = 0; i < iarr.length; i++) {
System.out.print(iarr[i] + " ");
}
System.out.println();
/* 배열의 0번 인덱스 값 변경 */
iarr[0] = 99;
/*값 변경 후 배열의 값 출력*/
System.out.print("배열의 값 출력 :");
for (int i = 0; i < iarr.length; i++) {
System.out.print(iarr[i] + " ");
}
System.out.println();
}
public void testClassTypeParameter(RectAngle rectAngle) {
/* 인스턴스도 주소가 전달된다.
* 즉, 인자로 전달하는 인스턴스와 매개변수로 전달받은 인스턴스는 서로
* 동일한 인스턴스를 가리킨다. (얕은 복사) */
System.out.println("매개변수로 전달 받은 값 : " + rectAngle);
//인자로 전달하는 값 :com.greedy.section05.parameter.RectAngle@71dac704
//매개변수로 전달 받은 값 : com.greedy.section05.parameter.RectAngle@71dac704
System.out.println("변경 전 사각형의 넓이와 둘레 ==========");
rectAngle.clacArea();
rectAngle.clacRound();
/* 사각형의 너비와 높이를 변경 */
rectAngle.setWidth(100);
rectAngle.setHeight(100);
System.out.println("변경 후 사각형의 넓이와 둘레 ==========");
rectAngle.clacArea();
rectAngle.clacRound();
// 변경 전 사각형의 넓이와 둘레 ==========
// 이 사각형의 넓이는 281.25입니다.
// 이 사각형의 둘레는 70.0입니다.
// 변경 후 사각형의 넓이와 둘레 ==========
// 이 사각형의 넓이는 10000.0입니다.
// 이 사각형의 둘레는 400.0입니다.
}
public void testVariableLengthArrayParameter(String name, String... hobby) {
// 값의 갯수가 여러개일 수 있는데 그것을 hobby 로 받겠다는 의미
// 이때 hobby와 name의 순서가 바뀐다면 컴파일 에러가 뜬다.
// ("name", "hobby1", "hobby2"); 가변인자를 선언할땐 반드시 마지막에 선언해야한다.
/* 가변 길이의 배열은 몇 개가 매개변수로 전달될지 모르는 상황이기에
* 이름과구분하기 위해 뒤쪽에 작성해야 한다.
* 앞쪽에 작성하는 경우 에러가 발생한다. */
System.out.println("이름 : " + name);
System.out.println("취미의 갯수 : " + hobby.length);
//length 전달시 취미를 몇개 전달했는지 알 수 있음
System.out.print("취미 : ");
for (int i= 0; i < hobby.length; i++) {
System.out.print(hobby[i] + " ");
}
System.out.println();
}
//오버로딩 // name만 뺐다.
// public void testVariableLengthArrayParameter(String... hobby) {
//
// System.out.println("취미의 갯수 : " + hobby.length);
// //length 전달시 취미를 몇개 전달했는지 알 수 있음
// System.out.print("취미 : ");
// for (int i= 0; i < hobby.length; i++) {
// System.out.print(hobby[i] + " ");
// }
//
// System.out.println();
//
// }
// 이렇게 작성한 상태에서 어플리케이션에 가보면 컴파일 오류가 나 있다.
// 전부 스트링 타입이므로, 호출시 굉장한 모호성이 발생할 수 있다.
}
RectAngle
public class RectAngle {
private double width;
private double height;
/* 기본 생성자로 객체 생성을 막고, 모든 필드를 초기화하는 생성자를 추가하여
* 초기값을 입력해서 인스턴스를 생성하도록 제한 */
// 기본생성자 막음
public RectAngle(double width, double height) {
this.width = width;
this.height = height;
}
/* 생성자와 접근자 */
public void setWidth (double width) {
this.width = width;
}
public void setHeight (double height) {
this.height = height;
}
public double getWidth () {
return width;
}
public double getHeight () {
return height;
}
/* 사각형의 넓이를 구하는 메소드 */
public void clacArea() {
double area = width * height;
System.out.println("이 사각형의 넓이는 " + area + "입니다.");
}
/* 사각형의 둘레를 구하는 메소드 */
public void clacRound() {
double round = (width + height) *2;
System.out.println("이 사각형의 둘레는 "+ round + "입니다.");
}
}
static
static이란?
- 정적 메모리 영역에 프로그램이 start될 시 할당 하고자 할 때 사용하는 키워드
- static 필드나 메소드는 인스턴스 생성 없이 사용 가능
- 여러 인스턴스가 공유해서 사용할 목적으로 만드는 것
heap은 동적인 영역이라고 한다. 프로그램 진행에 따라 생성이 되었다가,
더이상의 사용이없으면 지워진다.
static은 정적인 영역이라고 한다. 프로그램 시작시 생성되었다가
프로그램이 종료되는 사라진다.
공간의 사용이 다르고 특성이 다르다.
stack은 객체 생성시 할당되는 영역이 아니다.
인스턴스는 각각의 공간이 형성되지만,
스태틱은 프로그램 시작시 생성되는 하나의 영역에 형성된다.
여러인스턴스가 공유해서 사용할 목적으로 사용
final
final이란?
- 변경 불가의 의미를 담고 있는 키워드
- 메소드에서는 종단의 의미를 지님
- 클래스 필드의 final 변수는 선언과 동시에 초기화 하거나 생성자를 통한 초기화를 해야 함 (그렇지않으면 0.0으로 초기화되는 문제가 발생한다.)
StaticFieldTest 메인 메소드
public class Application {
public static void main(String[] args) {
/* static : 정적 메모리 영역에 프로그램이 시작될 시에 할당을 하는 키워드이다.
* 인스턴스를 생성하지 않고도 사용할 클래스의 멤버(필드, 메소드)에
* 지정할 수 있다.
* 여러 인스턴스가 공유해서 사용할 목적의 공간이다.
* 하지만 static 키워드의 남발은 유지보수와 추적이 힘든 코드를
* 작성하는 방식으로, 명확한 목적이 존재하지 않는이상 static 키워드
* 사용은 자제
* => 의도적으로 static키워드를 사용하는 대표적인 예는
* singleton 객체를 생성할때
*
*
* */
/* static 키워드를 필드에서 사용할 때 */
StaticFieldTest sft1 = new StaticFieldTest();
// 클래스 생성
/* 현재 두 필드가 가지고 있는 값 확인 */
System.out.println("non-static field : " + sft1.getNonStaticCount());
System.out.println("static field : " + sft1.getStaticCount());
// non-static field : 0
// static field : 0
/* 두 필드의 값 1씩 증가 후 다시 값 확인 */
sft1.increaseNonStaticCount();
sft1.increaseStaticCount();
System.out.println("non-static field : " + sft1.getNonStaticCount());
System.out.println("static field : " + sft1.getStaticCount());
// non-static field : 1
// static field : 1
/* 새로운 StaticFieldTest 인스턴스 생성 */
StaticFieldTest sft2 = new StaticFieldTest();
System.out.println("non-static field : " + sft2.getNonStaticCount());
System.out.println("static field : " + sft2.getStaticCount());
// non-static field : 0
// static field : 1
/* 인스턴스 변수의 경우에는 sft1과 sft2 두개의 인스턴스가
* 서로 값을 공유하지못하고 인스턴스를 생성할 때마다 0으로 초기화 되었다.
* 하지만 static 필드의 경우에는 클래스 변수 자체가
* 프로그램을 종료할 때까지 유지되고 있기 때문에
* 값을 유지하고 있다.
* => 여러개의 인스턴스가 같은 공간을 공유할 목적으로
* 필드에 static 키워드를 사용한다. */
/* static 키워드를 method에 작성 */
StaticMethodTest smt = new StaticMethodTest();
smt.nonStaticMethod();
/* 클래스명.메소드명으로 인스턴스를 생성하지않고 호출할 수 있다.
* 예: Math클래스의 메소드들
* */
StaticMethodTest.staticMethod();
//이미 프로그램시작시 생성됐던 공간에서 호출가능
/* static메소드의 경우 인스턴스를 생성하지 않고
* '호출하는 방식'으로 사용해야 한다. */
smt.staticMethod();
//경고문구가 뜬다. 권장되는 방식이 아니기 때문이다.
}
}
StaticFieldTest 클래스
public class StaticFieldTest {
/* non-static 필드와 static 필드 선언 */
private int nonStaticCount; //인스턴스 변수
private static int staticCount; // 스태틱 변수
public StaticFieldTest() {}
/* 두 필드에 대한 값을 확인 */
public int getNonStaticCount() {
return this.nonStaticCount;
}
public int getStaticCount() {
/* static 필드에 접근하기 위해서는 클래스명.필드명으로 접근한다. */
return StaticFieldTest.staticCount;
// 어떤객체의 주소값이 this
}
/* 두 필드 값을 1씩 증가시키기 위한 용도의 메소드 */
public void increaseNonStaticCount() {
this.nonStaticCount++;
}
public void increaseStaticCount() {
StaticFieldTest.staticCount++;
}
}
StaticMethodTest
public class StaticMethodTest {
/*필드*/
private int count;
public void nonStaticMethod() {
this.count++;
// 인스턴스 생성 후 사용가능한 메소드이기 때문에 this에는 주소가 들어있을 것이다.
System.out.println("nonStaticMethod 호출됨...");
}
public static void staticMethod() {
// this.count++;
// 컴파일 에러남. Cannot use this in a static context
// this 는 객체의 주소값이다. 즉, 인스턴스를 생성했을때의 값
// 인스턴스를 생성하지않고 사용하는 메소드이기 때문에 this에는 주소가 들어갈 수 없다.
System.out.println("staticMethod 호출됨...");
}
}
FinalFieldTest
public class FinalFieldTest {
/* non-static field에 final 사용 */
/* final은 변경 불가의 의미를 가진다.
* 따라서 초기 인스턴스가 생성되고 나면 기본값 0이 필드에 들어가게 되는게
* 그 초기화 이후 값을 변경할 수 없기 때문에 선언하면서 바로 초기화를 해주어야한다.
* 그렇지 않으면 컴파일 에러가 발생한다.
* The blank final field nonStaticNum may not have been initialized
* */
// private final int nonStaticNum;
// 에러발생 0으로 초기화되어 이후 변경 불가능
/* 1. 선언과 동시에 초기화 한다. */
private final int NON_STATIC_NUM =1;
// 상수는 대문자로 표현하는 것이 관례이므로 언더바로 구분한다.
/* 2. 생성자를 이용해서 초기화 함 */
private final String NON_STATIC_NAME;
public FinalFieldTest(String nonStaticName) {
this.NON_STATIC_NAME = nonStaticName;
}
/* static field에 final 사용 */
/* static 에서도 자바에서 지정한 기본값이 초기에 대입되기 때문에
* final키워드 사용시 초기화를 하지않으면 에러가 발생한다. */
// private static final int STATIC_NUM;
// 에러발생 0으로 초기화 되기 때문에 이후 변경 불가능
// 접근제한자와 자료형 사이에 static 과 final 위치
// 정적메모리영역도 기본값으로 초기화
private static final int STATIC_NUM = 1;
/* 생성자를 이용한 초기화는 불가능하다. */
/* 생성자는 인스턴스가 생성되는 시점에 호출이 되기 때문에 그 전에는 초기화가
* 일어나지 못한다. 하지만 static은 프로그램이 시작될 때 할당되기 때문에 초기화가
* 되지않은 상태로 선언된 것과 동일하다.
* */
//// private static final double STATIC_DOUBLE;
//
//// public FinalFieldTest(double staticDouble) {
//// FinalFieldTest.STATIC_DOUBLE = staticDouble;
}
singleton
싱글톤 패턴(singleton pattern)이란?
- 클래스의 인스턴스 사용시 메모리 공간에 있는 하나의 인스턴스를 공유해서 사용하는 디자인 패턴
(생성 된 하나의 인스턴스만을 사용) ex: 법인카드를 공유해서 전팀이 사용하는 것
Singleton 메인 메소드
public class Application {
public static void main(String[] args) {
/* static을 이용한 싱글톤 패턴 */
/* singleton 패턴이란?
* : 애플리케이션이 시작될 때 어떤 클래스가 최초 한 번만 메모리를 할당하고
* 그 메모리에 인스턴스를 만들어서 하나의 인스턴스를 공유해서 사용하여 메모리 낭비를
* 방지할 수 있게 함(매번 인스턴스를 생성하지 않음)
*
*
* 장점
* 1. 첫 번째 이용 시에는 인스턴스를 생성해야 하므로 속도 차이가 나지 않지만
* 두 번째 이용시에는 인스턴스 생성시간 없이 사용할 수 있다.
* 2. 인스턴스가 절대적으로 한개만 존재하는 것을 보증할 수 있다.
*
*
* 단점
* 1. 싱글톤 인스턴스가 너무 많은 일을 하거나 많은 데이터를 공유하면 결합도가 높아진다.
* (유지보수와 테스트에 문제점이 있음)
* 2. 동시성 문제를 고려해서 설계해야 하기 때문에 난이도가 있다.
*
* */
/* 싱글톤 구현방법
* 1. 이른 초기화 (Eager Initialization)
* 2. 게으른 초기화 (Lazy Initialization)
*
*
* */
/* 1. 이른 초기화 */
EagerSingleton eager1 = EagerSingleton.getInstance();
EagerSingleton eager2 = EagerSingleton.getInstance();
/* 두 인스턴스의 해쉬코드가 같은 것을 알 수 있다.
* 즉, 동일한 인스턴스이다. */
System.out.println("eager1의 hashCode" + eager1.hashCode());
System.out.println("eager2의 hashCode" + eager2.hashCode());
/* 반드시 하나의 객체에서, 인스턴스에서 가져오도록 싱글톤으로 보증했으니
* 하나의 주소만 나와야 한다. */
// eager1의 hashCode1227229563
// eager2의 hashCode1227229563
/* 게으른 초기화 */
LazySingleton lazy1 = LazySingleton.getInstance();
LazySingleton lazy2 = LazySingleton.getInstance();
/* 두 인스턴스의 hashCode가 동일함 */
System.out.println("lazy1의 hashCode : " + lazy1.hashCode());
System.out.println("lazy2의 hashCode : " + lazy2.hashCode());
// lazy1의 hashCode : 1910163204
// lazy2의 hashCode : 1910163204
}
/* 이른 초기화를 사용하면 클래스를 로드하는 속도가 느려지지만
* 처음 인스턴스 반환 요청에서는 속도가 빠르다는 장점을 가진다.
*
* 게으른 초기화를 사용하면 클래스를 로드하는 속도는 빠르지만
* 첫번째 요청에 대한 속도가 두번째 요청에 대한 속도보다 느려진다는
* 특징을 가지고 있다.
*
* */
}
EagerSingleton
public class EagerSingleton {
/* 클래스가 초기화 되는 시점에서 인스턴스를 생성한다. */
private static EagerSingleton eager = new EagerSingleton();
/* 싱글톤 패턴은 생성자 호출을 통해 외부에서 인스턴스를 생성하는 것을 제한한다. */
private EagerSingleton() {}
// 접근을 못하므로 객체 생성을 못함
/* 만들어놓은 인스턴스를 반환한다. */
public static EagerSingleton getInstance() {
return eager;
}
// 단하나 생성되는 인스턴스를 퍼블릭으로 반환
// new 생성이 아니어도 호출 가능 (static)
}
LazySingleton
public class LazySingleton {
/* 클래스가 초기화되는 시점에는 정적 필드를 선언해두고 null로 초기화된다. */
private static LazySingleton Lazy;
// 참조 변수이므로 null로 초기화
/* 싱글톤 패턴은 생성자 호출을 통해 외부에서 인스턴스를 생성하는 것을 제한한다. */
private LazySingleton() {}
/* 인스턴스를 생성한 적이 없는 경우 인스턴스를 생성해서 반환하고
* 생성한 인스턴스가 있는 경우 만들어둔 인스턴스를 반환한다.
* */
public static LazySingleton getInstance() {
if(Lazy == null) {
/* 인스턴스를 생성한 적이 없는 경우 새로운 인스턴스 생성 */
Lazy = new LazySingleton();
}
return Lazy;
}
// 이른초기화는 필드선언과 동시에
// 게으른 초기화는 필드선언시에는 반환하지않고 호출시에 인스턴스 반환
// 생성되는 시기에만 차이가 있는 방법일뿐 의도는 동일하다.
}
클래스에서의 변수
변수의 종류
- 클래스에서의 변수는 아래와 같이 구분한다.
- 클래스 변수 : static 키워드를 가지고 필드에 선언하는 변수, 메모리의 static영역 사용
- 멤버 변수(인스턴스 변수) : static 키워드 없이 필드에 선언하는 변수, 메모리의 heap영역 사용
- 지역 변수 : 메소드, 생성자, 초기화 블록 내부에서 선언하는 변수
'Programming > JAVA' 카테고리의 다른 글
상속 (0) | 2022.01.04 |
---|---|
객체 배열 (0) | 2022.01.03 |
클래스와 객체(2) (0) | 2021.12.29 |
배열, 클래스와 객체 (0) | 2021.12.28 |
배열 (0) | 2021.12.27 |