클래스 (Class) part.2
1. 접근제어 명시자 (Access Modifier)
- 변수, 메서드, 클래스 어디에나 사용이 가능하다.
- 클래스와 클래스들은 기본적으로 서로가 쉽게 접근 할 수 없다.
클래스는 누구는 접근 할 수 있도록 하고,
누구는 접근하지 못하게 할 수 있다.
클래스의 보안 기능을 살펴보자.
1) 종류
<접근허가>
1. default
- 접근제어명시자가 생략된 형태. 접근할 수 있도록 허가, 같은 폴더 안에 있는 class 안에서만 사용가능)
- 같은 파일 안에서는 public을 안붙여도 된다.
- 한 파일에 하나의 클래스만 있는 것이 원칙이다.
2. public
- 다른 폴더나 같은 폴더나 어디서나 접근할 수 있는 허가권
<접근불가>
1. private
- 가장 강력한 접근거부
- 같은 클래스에서만 사용 가능
2. protected (class part3에서 다룸)
- defult와 성격이 비슷
<예제 1>
class EmpManager{
public String name;
int no;
double pay;
}
public class AccessModifierTest {
public static void main(String[] args) {
// TODO 접근제어명시자 테스트
EmpManager kim = new EmpManager();
kim.name = "김유신";
kim.no = 12;
kim.pay=1000000;
System.out.println(kim.name + " : " + kim.no + " : " + kim.pay);
}
}
※결과값
김유신 : 12 : 1000000.0
여기서 pay값을 못 보게 하고 싶다면 private를 사용한다.
<예제2>
class EmpManager{
public String name;
int no;
// 클래스 안에서만 작동하기 때문에 오류가 생긴다.
private double pay;
}
public class AccessModifierTest {
public static void main(String[] args) {
// TODO 접근제어명시자 테스트
EmpManager kim = new EmpManager();
kim.name = "김유신";
kim.no = 12;
kim.pay=1000000;
System.out.println(kim.name + " : " + kim.no + " : " + kim.pay);
}
}
※결과값
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The field EmpManager.pay is not visible
The field EmpManager.pay is not visible
at AccessModifierTest.main(AccessModifierTest.java:17)
문제는 이렇게 되면 EmpManager라는 클래스가 쓸모없어진다.
그렇다면 어떻게 하면 pay를 못보게 하면서 클래스를 사용할 수 있을까?
이럴 때는 메서드를 만들어주면 된다.
class EmpManager{
public String name;
int no;
private double pay;
//private 변수를 수정하고 저장 할 수 있는 메서드 (쓰고 저장하는 기능)
//setter 메서드
//이런 setter 메서드는 앞에 변수 이름을 set이라고 쓴다.
// 값을 받아서 private 변수에 넣어준다.
void setPay(int p) {
//값에 대한 검증
pay = p;
}
// getter 메서드
// 값을 가져다가 읽어올 수 있게 해준다. (읽기 기능)
// 이런 setter 메서드는 앞에 변수 이름을 get이라고 쓴다.
double getPay() {
return pay;
}
}
public class AccessModifierTest {
public static void main(String[] args) {
// TODO 접근제어명시자 테스트
EmpManager kim = new EmpManager();
kim.name = "김유신";
kim.no = 12;
//kim.pay=1000000;
kim.setPay(1000000);
System.out.println(kim.name + " : " + kim.no + " : " + kim.getPay());
}
}
※ 결과값
김유신 : 12 : 1000000.0
2) setter메서드, getter 메서드
위에 예시에서 보듯이
prive으로 선언될 때는 클래스 내부 기능을
사용하기 위해서 반드시 메서드가 달려있다.
private 변수하나에 반드시 두 개의 메서드가 따라 다녀야 한다.
이 두 변수 이름을 getter 와 setter 메서드 라고 한다.
① setter 메서드
private 변수를 수정하고 저장 할 수 있는 메서드 (쓰고 저장하는 기능)
이런 setter 메서드는 앞에 변수 이름을 set이라고 쓴다.
값을 받아서 private 변수에 넣어준다.
② getter 메서드
값을 가져다가 읽어올 수 있게 해준다. (읽기 기능)
이런 setter 메서드는 앞에 변수 이름을 get이라고 쓴다.
지금까지 배운 내용을 바탕으로 메인 메서드를 다시 살펴보자.
public static void main(String[] args)
public 자바 가상머신이 어디에든 실행 할 수 있도록 한다.
void 리턴값이 없다. (가상머신이 main찾는데 가상머신에게 리턴하지 않는다.)
main 메서드도 시스템이 찾는 콜백메서드이다.
static (앞으로 배워야 할 것)
(String[] args) 명령행 인자를 위한 매개변수이다.
2. 메서드
- 메서드 때문에 클래스의 특징이 결정된다.
- 변수 값을 임시저장 할 뿐이다. 정말 중요한건 메서드가 한다.
1) 인자 전달 방식
메서드를 호출했을 때 인자를 전달하는 방법이 크게 두가지가 있다.
1. 직접 값을 줄 것인가?
2. 주소를 통해 전달해 줄 것인가?
메서드의 인자전달방식
① 값에 의한 전달 (call by value)
- 지금까지 했던 모든 전달방식은 값에 의한 전달방식이었다.
a. 소량의 데이터
b. 잠깐 사용할 데이터
② 주소(참조)에 의한 전달(call by reference)
a. 대량의 데이터
b. 오랫동안 사용할 데이터
<인자 전달 방식>
public class CallByTest1 {
void display(int a, int b, int c, int d, int e) {
System.out.println(a + ", " + b + ", " + c);
}
public static void main(String[] args) {
// TODO 값에 의한 인자 전달 방식
// 일반변수는 stack을 사용하기 때문에 주소값을 저장할 수 없다.
// hip에 저장을 해야 안전하게 쓸 수 있다.
// 어떻하면 이 데이터를 안전하게 보관할 수 있을까? 답은 배열이다.
int a=4, b=7, c=15, d=80, e=9;
CallByTest1 call = new CallByTest1();
call.display(a, b, c, d, e);
}
}
※ 결과값
4, 7, 15
<주소(참조)에 의한 전달>
1.값이 많아 져도 괜찮다.
2.안전한 저장이 가능하다.
인자와 매개변수는 타입이 똑같아야한다.
주소(참조)에 의한 전달 방법은 두 가지가 있다.
첫 번째, 배열로 묶어서 전달한다.
두 번째, 인스턴스 변수를 선언하여 주소에 저장한다.
첫번째, 배열로 묶어서 전달하는 방법
public class CallByTest1 {
void display(int [] arr) {
System.out.println(arr[0] + ", " + arr[1] + ", " + arr[2]);
}
public static void main(String[] args) {
// TODO 값에 의한 인자 전달 방식
// 배열로 주소에 의함 참조 방식을 쓴다. 값이 많아져도 된찮다.
// 값이 많아 져도 괜찮다. 안전한 저장이 가능하다.
//지역변수를 인스턴스 변수로 선언
int [] arr = {4, 7, 15, 80, 9};
CallByTest1 call = new CallByTest1();
call.display(arr);
}
}
※ 결과값
4, 7, 15
두번째, 인스턴스 변수를 선언하여 주소에 저장하는 방법
public class CallByTest1 {
//인스턴스변수를 선언하여 주소에 저장한다.
int a =4, b=7, c=15, d=80, e=9;
void display() {
System.out.println(a + ", " + b + ", " + c);
}
public static void main(String[] args) {
// TODO 참조에 의한 전달 방식 2
int a=4, b=7, c=15, d=80, e=9;
CallByTest1 call = new CallByTest1();
call.display();
}
}
※ 결과값
4, 7, 15
여기서 Stack 구조에 대해 잠깐 알아보자.
<Stack 구조>
LiFO 구조이다.
lest in first out 구조
마지막에 나온 것이 먼저 나온다.
Stack 구조를 이용해 여러가지의 데이터타입을 인스턴스 변수로 빼 줄 수 있다.
public class CallByTest1 {
int i = 4;
double d = 3.14;
char c = '가';
boolean b = true;
String s = "문자열";
void display() {
System.out.println(i + ", " + d + ", " + c);
}
public static void main(String[] args) {
// TODO 참조에 의한 인자 전달 방식
CallByTest1 call = new CallByTest1();
call.display();
}
}
※ 결과값
4, 3.14, 가
아래와 같이 클래스를 따로 뺀다면 코드가 깔끔해진다.
class Data{
int i = 4;
double d = 3.14;
char c = '가';
boolean b = true;
String s = "문자열";
}
public class CallByTest1 {
void display(Data da) {
System.out.println(da.i + ", " + da.d + ", " + da.c);
}
public static void main(String[] args) {
// TODO 참조에 의한 인자 전달 방식
CallByTest1 call = new CallByTest1();
Data data = new Data();
call.display(data);
}
}
※ 결과값
4, 3.14, 가
★ 알고리즘과 디자인패턴 ★
어느정도 익숙해지면 알고리즘 공부를 해야한다.
디자인 패턴
- 똑같은 재료를 어떻게 쓸것인가?
- 같은 재료를 가지고 다양한 기능을 수행
- 개발자들의 시행 착오, 다양하게 쓰던 방법을 모아두었다.
- 짧은 시간에 비법을 알 수 있는 비급서
DTO패턴 (Data Object)
- DO(Data Object) VO(value Objec) DTO (Data To Object) 라고 함
Data Object 따로 따로 흩어진 다양한 변수로 묶어서
쓰기 편하도록 하나의 클래스로 만들어주는 방법
위 예제와 같은 예문을 DTO 패턴이라고 한다.
반드시 주소(참조)에 의한 전달을 써야하는 경우는 어떻게 될까?
내가 원하는 위치에서 값이 바뀔 수 있는 방법.
배열로 전달한다.
public class CallByTest2 {
void swap(int[] n) {
int temp = n[0];
n[0] = n[1];
n[1] = temp;
}
public static void main(String[] args) {
// TODO 반드시 참조에 의한 전달을 사용해야하는 경우
// 내가 원하는 위치에서 값이 바뀔 수 있도록 한다.
// num1과 num2의 주소값을 전달한다.
int[]num = {5,10};
CallByTest2 call = new CallByTest2();
call.swap(num);
System.out.println("교환 후 ...");
System.out.println(num[0] + ", " + num[1]);
}
}
※결과값
교환 후 ...
10, 5
public class CallByTest2 {
int num1=5, num2=10;
void swap() {
int temp = num1;
num1 = num2;
num2 = temp;
}
public static void main(String[] args) {
// TODO 반드시 참조에 의한 전달을 사용해야하는 경우
// 내가 원하는 위치에서 값이 바뀔 수 있도록 한다.
// num1과 num2의 주소값을 전달한다.
CallByTest2 call = new CallByTest2();
call.swap();
System.out.println("교환 후 ...");
System.out.println(call.num1 + ", " + call.num2);
}
}
※ 결과값
교환 후 ...
10, 5
같은 클래스지만 main 클래스에서 메소드를 쓰려면 생성자를 써야하는데
이는 static 때문이다. static은 나중에 별도로 설명한다.
3. 데이터 저장방법
1)변수의 단점
- 값을 1개만 저장해야한다.
2) 배열의 단점
- 같은 데이터 타입만 사용 가능
- 크기를 지정해야해서 남는 메모리나 더 큰 메모리가 될 수도 있다.
- 데이터 중간에 삽입/삭제 가 매우 불편하다.
- 배열은 데이터를 한번 저장하고 보관하는 것이 가장 적절하다.
3) 클래스
- 배열의 단점을 해결하기 위한 방법으로도 클래스가 사용된다.
- 서로 다른 데이터를 묶을 수 있다. (배열의 불편함 중에 이 부분만 해결 가능)
★ 연결리스트(Linked List) 알고리즘
- 배열의 크기 지정해야하는 문제나 데이터 삽입/삭제 문제를 해결해준다.
- 알고리즘을 공부하면 배울 수 있다.
- 자바에서 클래스로 제공해준다.
우선 이클립스에서 privite 을 사용할 때
getter setter와 생성자를 쉽게 만드는 방법을 알아보자.
★ getter setter 쉽게 만들기
★ 생성자 쉽게 만들기
그럼 학점 관리 프로그램을 만들어보자.
public class Sunjuk_v3 {
public static void main(String[] args) {
// TODO 클래스를 이용한 성적표
//이는 인스턴스가 3개 만들어진 것이 아니라 인스턴스의 주소를 저장 할 참조변수가 3개 만들어 진 것이다.
//new만들어갔다고 인스턴스가 생성된 것이 아니라는 점을 생각하자.
Student students[] = new Student[3];
//생성자가 호출되어야 인스턴스가 생성되기 때문에 생성자를 생성.
students[0] = new Student("홍길동", 1, 98, 90);
students[1] = new Student("임꺽정", 2, 76, 55);
students[2] = new Student("신돌석", 3, 85, 73);
// 총점 구하기
for (int i = 0; i < students.length; i++) {
students[i].setTot(students[i].getKor()
+ students[i].getEng());
}
// 평균구하기
for (int i = 0; i < students.length; i++) {
students[i].setAvg(students[i].getTot()/2 );
}
// 학점 구하기
for (int i = 0; i < students.length; i++) {
if (students[i].getAvg() >= 90)
students[i].setGrade('A');
else if (students[i].getAvg() >= 80)
students[i].setGrade('B');
else if (students[i].getAvg() >= 70)
students[i].setGrade('C');
else if (students[i].getAvg() >= 60)
students[i].setGrade('D');
else
students[i].setGrade('F');
}
// 등수 구하기
System.out.println("***성적결과***");
System.out.println("학번\t국어\t영어\t총점\t평균\t학점\t순위");
System.out.println("---------------------------------------------");
for (int i = 0; i < students.length; i++) {
System.out.println(students[i].getNo() + "\t" +
students[i].getKor() + "\t" +
students[i].getEng() + "\t " +
students[i].getTot() + "\t" +
students[i].getRank() + "\t" +
students[i].getGrade() + "\t" +
students[i].getAvg());
}
System.out.println("정렬 후.......");
for (int row = 0; row < students.length-1; row++) {
for (int col = row+1; col < students.length; col++) {
if (students[row].getAvg() < students[col].getAvg()) {
Student temp = students[row];
students[row] = students[col];
students[col] = temp;
}
}
}
System.out.println("***성적결과***");
System.out.println("학번\t국어\t영어\t총점\t평균\t학점\t순위");
System.out.println("---------------------------------------------");
for (int i = 0; i < students.length; i++) {
System.out.println(students[i].getNo() + "\t" +
students[i].getKor() + "\t" +
students[i].getEng() + "\t " +
students[i].getTot() + "\t" +
students[i].getRank() + "\t" +
students[i].getGrade() + "\t" +
students[i].getAvg());
}
}//main end
}//class end
//따로만든 Student 클래스
public class Student {
//항상 클래스에 있는 변수는 private로 선언
private String name;
private int no;
private int kor;
private int eng;
private int tot;
private int avg;
private int rank;
private char grade;
//생성자를 만들어준다.
public Student(String name, int no, int kor, int eng) {
this.name = name;
this.no = no;
this.kor = kor;
this.eng = eng;
}
//getter와 setter를 만들어 준다.
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public int getKor() {
return kor;
}
public void setKor(int kor) {
this.kor = kor;
}
public int getEng() {
return eng;
}
public void setEng(int eng) {
this.eng = eng;
}
public int getTot() {
return tot;
}
public void setTot(int tot) {
this.tot = tot;
}
public int getAvg() {
return avg;
}
public void setAvg(int avg) {
this.avg = avg;
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
public char getGrade() {
return grade;
}
public void setGrade(char grade) {
this.grade = grade;
}
}
//Student[] students = new Student[5];
//이렇게 배열로 만들면 크기를 지정해줘야해서 메모리 공간이 낭비될 수 있다.
//class를 배열처럼 다루자.
//이렇게 하는 것이 DTO 패턴이다.
※ 결과값
***성적결과***
학번 국어 영어 총점 평균 학점 순위
---------------------------------------------
1 98 90 188 0 A 94
2 76 55 131 0 D 65
3 85 73 158 0 C 79
정렬 후.......
***성적결과***
학번 국어 영어 총점 평균 학점 순위
---------------------------------------------
1 98 90 188 0 A 94
3 85 73 158 0 C 79
2 76 55 131 0 D 65
4. 재귀호출 (Recursive Call)
void func(){
func();
}
-> func();
스스로를 호출하는 메소드 반복문과 같은 효과이다.
그러나 반복문 보다는 효과가 매우 떨어진다.
메소드이기 때문에 스택에 계속 임시저장을 하기 때문에 메모리를 엄청 사용한다.
그래서 재귀호출은 흐름상 반복을 돌려야 할 때를 제외하고는 쓰지 않는다.
재귀호출은 알고리즘을 배울 때 정리해두면 좋다.
5. static
1) 인스턴스와는 상관없이 따로 만들어지는 별도의 메모리
- 별도로 hip에 만들어지는 메모리
- 인스턴스는 클래스와 상관이 없다.
- 클래스의 소속이 아니기 때문에 인스턴스를 안만들어도 되지만
어느 클래스에 있는 변수인지 소속을 알려줘야한다.
- 변수 뿐만일 아니라 메서드도 마찬가지이다.
2) 여러 인스턴스들이 공유할 수 있는 메모리
- 인스턴스가 공통적으로 사용하는 메모리 (프로그램 실행하면 자동으로 만들어짐)
3) this 가 없다.
- this란 인스턴스의 주소값.
- this를 인스턴스를 구별하기 위해 만든 것이다.
- static은 인스턴스가 없기 때문에 인스턴스의 주소값이 없다.
4) 클래스 변수
- static 변수는 반드시 클래스 안에서만 선언할 수 있다.
- 메서드 안에서는 선언 할 수 없다.
- 커뮤니케이션 오해가 없기 위해 클래스 변수라는 표현보다 static 변수라고 부르자.
5) static block
- static 변수만을 모아서 초기화
- 깔끔하게 관리할 수 있다.
예시)
static int i;
static double d;
static{
i = 10;
d = 3.14;
}
public static void main(String[] args)
public 자바 가상머신이 어디에든 실행 할 수 있도록 한다.
static main이 쉽게 호출 할 수 있도록 인스턴스를 생성하지 않고 어디서나 사용할 수 있는 static사용
void 리턴값이 없다. (가상머신이 main찾는데 가상머신에게 리턴하지 않는다.)
main 메서드도 시스템이 찾는 콜백메서드이다.
(String[] args) 명령행 인자를 위한 매개변수이다.
static 사용 사례를 확인해보자.
class StaticDemo1{
int a;
int b;
static int c;
}
//하지만 static의 소속은 해당클래스에 있기 때문에 접근제한자 private의 영향을 받는다.
public class StaticTest1 {
//변수 static을 사용하면 어디서나 쓸 수 있다.
static int d;
//변수 뿐 아니라 메서드도 static이 붙으면 클래스와는 별도로 사용할 수 있다.
static void method1() {
System.out.println("난 메서드야...");
}
//main에 static을 만든 이유는 가상머신이 일일히 인스턴스를 생성해
// main을 호출하여 프로그램을 실행하기 어렵기 때문이다.
public static void main(String[] args) {
// TODO static이란 무엇인가?
StaticDemo1.c = 100;
//static은 인스턴스를 넣어도 쓸 수있지만 없어도 할 수 있다.
StaticDemo1 demo1 = new StaticDemo1();
StaticDemo1 demo2 = new StaticDemo1();
System.out.println(demo1.c);
System.out.println(demo2.c);
demo2.c = 200;
System.out.println(demo2.c);
//static이 붙은건 인스턴스를 만들지 않는다.
//StaticTest1.d 이지만 같은 클래스에 있기 때문에 생략해주었다.
d = 300;
}
}
※ 결과값
100
100
참고로, 인스턴스와 객체는 거의 비슷한 개념으로 보아도 좋다.
//스테틱과 인스턴스, 누가 더 빠를까?
public class StaticTest2 {
StaticTest2(){
System.out.println("생성자 호출됨 : 인스턴스 생성");
}
static double d1, d2;
static {
System.out.println("static 생성");
//Math.은 수학계산을 도와주는 메서드이다.
d1 = Math.sqrt(4.0);
d2 = Math.sqrt(8.0);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new StaticTest2();
System.out.println(d1 + "," + d2);
}
}
※ 결과값
static 생성
생성자 호출됨 : 인스턴스 생성
2.0,2.8284271247461903
static이 인스턴스생성보다 더 빠르다.
이를 통해 static은 인스턴스와 상관없이 움직인다는 것을 알 수 있다.
6. 중첩클래스
- 클래스도 반복문처럼 중첩을 할 수 있다.
- 전용으로 써야할 클래스가 있는 경우 중첩클래스를 사용하면 편하다.
- 클래스가 내부에 있으면(중첩하면) private에 접근할 수 있다.
1) 일반클래스
- 바깥에 있는 클래스의 인스턴스가 먼저 만들어 져야하고
내부 클래스의 인스턴스가 또 생성이 되어야한다.
바깥 클래스의 메모리 영역이 결정되어야
내부 클래스의 메로리를 쓸 수 있기 때문이다.
- 안에있는 클래스는 바깥에 있는 클래스를 모두 쓸 수 있다. (변수, 메소드)
- 바깥에 있는 클래스는 안에 있는 클래스를 접근 할 수 없다.
2) static 클래스
- static 클래스는 내부클래스가 되었을 때
클래스 안에 있지만 바깥에 클래스와는 상관 없다.
그렇기 때문에 인스턴스를 따로 생성해도 상관없다.
- static 클래스의 경우 일반 클래스와 다르게
별개의 메모리를 가지고 있기 때문에
사용하기 위해서는 인스턴스를 매번 생성해야한다.
그래서 중첩클래스는 대부분 일반클래스를 사용한다.
<static클래스의 경우>
public class OuterClass {
private int outer;
//클래스가 내부에 있으면(중첩하면) private에 접근할 수 있다.
static class InnerClass{
private int inner;
void innerMethod() {
System.out.println(inner);
OuterClass obj2 = new OuterClass();
obj2.outer = 200;
System.out.println("outer=" + obj2.outer);
}
}
public static void main(String[] args) {
// TODO 중첩클래스 (내부클래스가 static일 경우)
InnerClass obj1 = new InnerClass();
obj1.innerMethod();
}
}
※ 결과값
0
outer=200
<일반클래스의 경우>
public class OuterClass {
//안에있는 클래스는 바깥에 있는 클래스를 모두 쓸 수 있다. (변수, 메소드)
//바깥에 있는 클래스는 안에 있는 클래스를 접근 할 수 없다.
private int outer;
//클래스가 내부에 있으면(중첩하면) private에 접근할 수 있다.
class InnerClass{
private int inner;
void innerMethod() {
System.out.println(inner);
OuterClass obj2 = new OuterClass();
obj2.outer = 200;
System.out.println("outer=" + obj2.outer);
}
}
public static void main(String[] args) {
// TODO 중첩클래스 (내부클래스가 일반클래스일 경우)
//일반클래스는 바깥에 있는 클래스의 인스턴스가 먼저만들어져야 내부 클래스를 쓸 수 있다.
//OuterClass out = new OuterClass();
//InnerClass obj1 = out.new InnerClass();
//같은 클래스에 있기 때문에 .OuterClass을 생략해도 되지만 바깥에서 불러올 때는
//바깥 클래스의 인스턴스를 먼저 생성해야하기 때문에 OuterClass.을 반드시 써야한다.
OuterClass.InnerClass obj1 = new OuterClass().new InnerClass();
obj1.inner = 100;
obj1.innerMethod();
}
}
※ 결과값
0
outer=200
지금까지 배운 내용을 종합하여 디자인패턴을 하나 배워보자.
**Singleton
- 인스턴스를 단 하나만 쓸 수 있는 디자인패턴
- 하나만 있어도 충분한 인스턴스를 계속 만들어 메모리를 낭비하는 경우를 사전에 방지한다.
- private 은 class 앞에 못 쓴다.
- 기본 생성자에 private을 붙힌다.
- new가 있다고 해서 다 인스턴스가 만들어진다고 생각하지 말아라.
- 메서드만가지고 인스턴스가 만들어지는 경우는 모두 싱글턴이다.
싱글턴 패턴을 만들기 위해 필요한 것
- 재료 : 생성자, static, private
- 방법
①외부에서 절대를 인스턴스를 생성할 수 없게 한다.
②내부에서 단 하나의 인스턴스를 생성한다.
③그렇게 만들어진 인스턴스를 외부에서 사용 할 수 있게 한다.
class SingletonDemo{
private int i;
// 인스턴스를 하나 만들어준다.
// 보호할 수 있도록 private 처리를 한다.
// 단 하나만 만들어 질 수 있도록 static을 놓는다.
private static SingletonDemo instance = new SingletonDemo();
// 기본생성자에 private을 붙여서 인스턴스를 하나만 생성하도록 한다.
private SingletonDemo() {
}
//외부에서 쓸 수 있도록 메서드를 사용한다.
//리턴값이 SingletonDemo이기 때문에 void 자리에 클레스 타입을 쓴다.
//인스턴스 없어도 호출할 수 있도록 static을 쓴다.
public static SingletonDemo getInstance() {
return instance;
}
}
public class SingletonTest {
public static void main(String[] args) {
// TODO Singeton Patten
/*
SingletonDemo obj1 = new SingletonDemo();
SingletonDemo obj1 = new SingletonDemo();
*/
SingletonDemo obj1 = SingletonDemo.getInstance();
SingletonDemo obj2 = SingletonDemo.getInstance();
SingletonDemo obj3 = SingletonDemo.getInstance();
System.out.println("주소 비교 : " + (obj1==obj2));
System.out.println("주소 비교 : " + (obj2==obj3));
}
}
※결과값
주소 비교 : true
주소 비교 : true
'개발 > Java' 카테고리의 다른 글
[java] 패키지 package (0) | 2017.10.25 |
---|---|
[java] 클래스 (Class) part.3 : 상속 (Inheritance ) (0) | 2017.10.24 |
[java] 배열 (Array) (0) | 2017.10.19 |
[java] 클래스 (Class) part.1 (0) | 2017.10.18 |
[java] 제어문(Control Statement) : 조건문과 반복문 (0) | 2017.10.18 |