-
014. 클래스와 인스턴스 실습, 생성자(Constructor)SsY/Class 2023. 3. 2. 01:13728x90
2023.02.13 (월)
클래스와 인스턴스
- 실습- Test072
- 클래스와 인스턴스
더보기/*============================================= ■■■ 클래스와 인스턴스 ■■■ ==============================================*/ // 사용자로부터 임의의 정수를 입력받아 // 1 부터 입력받은 수 까지의 합을 연산하여 // 결과값을 출력하는 프로그램을 구현한다. // 단, 지금까지처럼 main()메소드에 모든 기능을 적용하는 것이 아니라 // 클래스와 인스턴스의 개념을 활용하여 처리할 수 있도록 한다. // (→Hap 클래스 설계) // 또한, 데이터 입력 처리 과정에서 BufferedReader 의 readLine() 을 사용하며, // 입력 데이터가 1보다 작거나 1000보다 큰 경우 // 다시 입력받을 수 있는 처리를 포함하여 프로그램을 구현할 수 있도록 한다. // 실행 예) // 임의의 정수 입력(1 ~ 1000) : 1050 // 임의의 정수 입력(1 ~ 1000) : -45 // 임의의 정수 입력(1 ~ 1000) : 100 // >> 1 ~ 100 까지의 합 : 5050 // 계속하려면 아무 키나 누르세요... import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; class Hap { int n, a, s; // 임의의 정수, 1부터 증가해나갈 값, 합계를 담을 변수 void input() throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); do { System.out.print("임의의 정수 입력(1~1000) : "); n = Integer.parseInt(br.readLine()); } while (n<1 || n>1000); } int cal() { s = 0; for (a=1; a<=n; a++) s += a; return s; } void print(int sum) { System.out.printf(">> 1 ~ %d 까지의 합 : %d\n", n, sum); } }// Hap class end public class Test072 { public static void main(String[] args) throws IOException { Hap h = new Hap(); h.input(); int ans = h.cal(); h.print(ans); }//main end }//class end // 실행 결과 /* 임의의 정수 입력(1~1000) : 1050 임의의 정수 입력(1~1000) : -50 임의의 정수 입력(1~1000) : 54 >> 1 ~ 54 까지의 합 : 1485 계속하려면 아무 키나 누르십시오 . . . */
- Test073
- 클래스와 인스턴스
더보기/*============================================= ■■■ 클래스와 인스턴스 ■■■ ==============================================*/ // 사용자로부터 임의의 두 정수와 연산자를 입력받아 // 해당 연산을 수행하는 프로그램을 구현한다. // 단, 클래스와 인스턴스의 개념을 활용하여 작성할 수 있도록 한다. // (→ Calculate 클래스 설계) // 실행 예) // 임의의 두 정수 입력 (공백 구분) : 10 5 // 임의의 연산자 [+ - * /] : + // 10 + 5 = 15 // 계속하려면 아무 키나 누르세요... import java.util.Scanner; import java.io.IOException; class Calculate { // 주요 변수 선언 int su1, su2; // 사용자로부터 입력받은 두 정수를 담아낼 변수 char op; // 사용자로부터 입력받은 연산자를 담아낼 변수 // 메소드 정의 (기능 : 입력) void input() throws IOException { Scanner sc = new Scanner(System.in); System.out.print("임의의 두 정수 입력(공백 구분) : "); su1 = sc.nextInt(); su2 = sc.nextInt(); System.out.print("임의의 연산자 [+ - * /] : "); op = (char)System.in.read(); } // 메소드 정의 (기능 : 연산) // → 나눗셈 연산을 실수 기반으로 처리 → 반환 자료형 → double //int cal() //{ //} // → 나눗셈 연산을 정수 기반으로 처리 → 반환 자료형 → int double cal() { double result = -1; switch (op) { case '+': result = su1 + su2; break; case '-': result = su1 - su2; break; case '*': result = su1 * su2; break; case '/': result = (double)su1 / su2; break; //default : result = -1 // result 값이 초기화 되어있기 때문에 생략 가능 } return result; } // 메소드 정의 (기능 : 출력) void print(double s) { System.out.printf(">> %d %c %d = %.2f\n", su1, op, su2, s); } }// Calculate class end public class Test073 { public static void main(String[] args) throws IOException { Calculate cal = new Calculate(); cal.input(); // 생성한 인스턴스를 통한 입력 메소드 호출 double r = cal.cal(); // 생성한 인스턴스를 통한 연산 메소드 호출 cal.print(r); // 생성한 인스턴스를 통한 출력 메소드 호출 } } // 실행결과 /* 임의의 두 정수 입력 (공백 구분) : 50 3 임의의 연산자 [+ - * /] : + 50 + 3 = 53.0 계속하려면 아무 키나 누르십시오 . . . */ /* 임의의 두 정수 입력 (공백 구분) : 30 8 임의의 연산자 [+ - * /] : - 30 - 8 = 22.0 계속하려면 아무 키나 누르십시오 . . . */ /* 임의의 두 정수 입력 (공백 구분) : 31 132 임의의 연산자 [+ - * /] : * 31 * 132 = 4092.0 계속하려면 아무 키나 누르십시오 . . . */ /* 임의의 두 정수 입력 (공백 구분) : 654 54 임의의 연산자 [+ - * /] : / 654 / 54 = 12.1 계속하려면 아무 키나 누르십시오 . . . */
클래스와 인스턴스
- 생성자 (Constructor)- 생성자를 사용하는 이유
※ 서로 다른 인스턴스의 생성은, 인스턴스 변수의 초기화라는 문제를 고민하게 한다.
더보기지금까지 작성해 왔던 방식으로 인스턴스 생성 후 변수나 메소드에 접근하는 방식을 이용한다면,
▶ 변수의 개수가 많아질수록 매우 비합리적인 행위를 반복해야만 한다.
→ 그렇다면, 사과장수의 속성값(변수)를 원하는 형태로 초기화 하는 메소드를 만들면?▶ 속성을 한번에 초기화 하는 기능을 사용하여 비교적 구문이 간단해지긴 했으나, 바람직하지 않다!
▶ why?1) 사실은 이 과정 역시 비합리적으로 생성과 동시에 초기화를 할 수 있음
- 생성자의 필요성2) 판매가격 등 변경이 되면 안되는 중요한 변수의 경우 값을 final 로 상수화 시켜야할 필요성이 있음
- final이 붙은 변수는 상수가 되었기 때문에 인스턴스 생성 하여 값을 초기화시킬 수 없음.
(문번 10번, 19번 참조)→ 생성자를 사용하는 법!
※ 생성자의 이름은 항상 예외없이 클래스의 이름과 동일해야 하며
필요할 경우 인수를 받아들이는 것도 가능하고,
같은 이름의 메소드를 정의하는 중복정의(오버로딩)가 가능하지만,
리턴값(반환값)은 가질 수 없다.
// ※ 생성자는 다른 일반 메소드처럼 호출될 수 없고,
// 『new』연산자를 이용하여 객체를 생성하기 위해 호출되며,
// 각 클래스의 인스턴스를 생성한 후에
// 생성된 객체의 멤버를 초기화 시키는 작업을 수행하게 된다.○ 생성자(Constructor)의 역할
1. 인스턴스 생성 → 메모리 할당
2. 초기화
○ 생성자(Constructor)의 특징
1. 생성자는 메소드이지만, 일반적인 메소드처럼 호출될 수 없으며, 반환 자료형을 가질 수 없다.
(『void』조차 가질 수 없으며, 값을 반환할 수도 없다.)
+
생성자가 반환자료형을 가지지 않는 특성으로 아무 것도 붙이지 않는 문법을 선점해갔기 때문에,
메소드에서 값을 반환하지 않을 때 붙이는 자료형을 void(공허의) 를 붙이게 됨.
2. 생성자는 클래스와 동일한 이름을 가져야 한다.
(대소문자 명확히 구분 → 클래스의 명명법과 같은 규칙 적용)
3. 생성자는 객체를 생성하는 과정에서 『new 생성자();』의 형태로 호출된다.
(인스턴스 생성 시 단 한 번만 호출) → final 변수(상수화된 변수) 초기화 가능
- Test074
- 생성자 (Constructor) 관찰
더보기/*============================================= ■■■ 클래스와 인스턴스 ■■■ - 생성자 (Constructor) ==============================================*/ class NumberTest { int num; // ※ 클래스에... 사용자 정의 생성자를 정의하지 않았다면... // 컴파일 과정에서 디폴트(default) 생성자가 자동으로 삽입된다. // 즉, 클래스에... 사용자 정의 생성자가 정의되어 있다면... // 컴파일 과정에서 디폴트(default) 생성자는 자동으로 삽입되지 않는다. // 디폴트(default) 생성자 // NumberTest() //{ // 텅 비어있는 상태 //} // ※ 사용자 정의 생성자 // 사용자가 직접 정의하고 사용하게 되는 생성자 NumberTest() { // 아래와 같이 내용을 채울 수도 있고, 비워서 만들어두어도 사용자 정의 생성자이다. num = 10; System.out.println("사용자 정의 생성자 호출~"); } int getNum() { return num; } } public class Test074 { public static void main(String[] args) { // NumberTest 클래스 기반의 인스턴스 생성 NumberTest nt1 = new NumberTest(); //--==>> 사용자 정의 생성자 호출~ //-- 인스턴스가 생성되는 시점에서 // 이와 동시에 선택의 여지 없이 생성자 호출이 이루어진다. // ----------- NumberTest(); /* // 사용자 정의 생성자 주석처리 후 확인 int result = nt1.getNum(); // -------------- 생성자를 따로 메소드 정의하지 않았는데 에러가 안남! // 다른 클래스에서 이미 정의 되어있기 때문에 실행 됨 - default 생성자 때문! System.out.println("result : " + result); */ //nt1.action(); //--==>> 에러 발생(컴파일 에러) // can not find symbol // NumberTest 클래스에 action이라는 메소드 존재X //nt1.NumberTest(); //--==>> 에러 발생(컴파일 에러) // can not find symbol // 생성자는 인스턴스 생성시 단 한 번만 호출 되기 때문! //int num1 = nt1.getNum(); //System.out.println(num1); System.out.println(nt1.getNum()); // 상기 두 문장을 하나로 만들 수 있음 //--==>> 10 nt1.num = 200; System.out.println(nt1.getNum()); //--==>> 200 NumberTest nt2 = new NumberTest(); //--==>> 사용자 정의 생성자 호출~ System.out.println(nt2.num); //--==>> 10 } } // 실행 결과 /* 사용자 정의 생성자 호출~ 10 200 사용자 정의 생성자 호출~ 10 계속하려면 아무 키나 누르십시오 . . . */
- Test075
- 생성자 (Constructor) 관찰
더보기/*============================================= ■■■ 클래스와 인스턴스 ■■■ - 생성자 (Constructor) ==============================================*/ class NumberTest2 { int num; // default 생성자 /* NumberTest2() { } */ // ※ 사용자 정의 생성자가 정의되어 있으므로 // default 생성자가 자동으로 삽입되지 않음~ // 생성자 → 사용자 정의 생성자 NumberTest2(int n) { num = n; System.out.println("생성자 호출 시 매개변수 전달 : " + n); } int getNum() { return num; } } public class Test075 { public static void main(String[] args) { // NumberTest2 클래스 기반의 인스턴스 생성 //NumberTest2 nt1 = new NumberTest2(); //--==>> 에러 발생 (컴파일 에러) //--NumberTest2 클래스에는 // 사용자 정의 생성자가 존재하고 있는 상황이기 때문에 // 『default 생성자』가 자동으로 삽입되지 않으며 // 사용자가 정의한 생성자는 매개변수를 갖는 형태이기 때문에 // 위와 같이 매개변수 없는 생성자를 호출하는 형태의 구문은 // 문제를 발생시키게 된다. NumberTest2 nt1 = new NumberTest2(10); //--==>> 생성자 호출 시 매개변수 전달 : 10 System.out.println("메소드 반환 값 : " + nt1.getNum()); //--==>> 메소드 반환 값 : 10 System.out.println("nt1.num : " + nt1.num); //--==>> nt1.num : 10 NumberTest2 nt2 = new NumberTest2(3654); //--==>> 생성자 호출 시 매개변수 전달 : 3654 System.out.println("메소드 반환 값 : " + nt2.getNum()); System.out.println("nt2.num : " + nt2.num); //--==>> 메소드 반환 값 : 3654 // nt2.num : 3654 } }
- Test076
- 생성자 (Constructor)
- this 키워드
더보기/*============================================= ■■■ 클래스와 인스턴스 ■■■ - 생성자 (Constructor) ==============================================*/ public class Test076 { int x; // 생성자 → 사용자 정의 생성자 → 매개변수 없는 생성자 Test076() { // ※ 생성자 내부에서 다른 생성자 호출하는 것은 가능하다. 다른 메소드들 처럼... // 하지만, 생성자 내부에서 가장 먼저 실행되어야 한다. check! this(100); x = 10; // this.x = 10; System.out.println("인자 없는 생성자"); System.out.println("Test076이 갖고있는 x : " + x); //Test076(100); //this(100); //--==>> 에러발생(컴파일 에러) // call to this must be first statement in constructor } // 생성자 → 사용자 정의 생성자 → 정수형 매개변수를 넘겨받는 생성자 Test076(int x) { //x = num; //x = x; //-- 둘 다 지역변수 x // 『this』 키워드~!!! this.x = x; System.out.println("인자가 하나인 생성자"); System.out.println("Test076이 갖고있는 x : " + this.x); } public static void main(String[] args) { // Test076 클래스 기반의 인스턴스 생성 Test076 ob1 = new Test076(); //--==>> 인자 없는 생성자 //--==>> 인자가 하나인 생성자 // Test076이 갖고있는 x : 100 // 인자 없는 생성자 // Test076이 갖고있는 x : 10 System.out.println(); // Test076 클래스 기반의 인스턴스 생성 Test076 ob2 = new Test076(100); //--==>> 인자가 하나인 생성자 // Test076이 갖고있는 x : 100 System.out.println(); System.out.println("main 에서 ob1.x : " +ob1.x); System.out.println("main 에서 ob2.x : " +ob2.x); //--==>> main 에서 ob1.x : 10 // main 에서 ob2.x : 100 } } // 실행결과 /* 인자가 하나인 생성자 Test076이 갖고있는 x : 100 인자 없는 생성자 Test076이 갖고있는 x : 10 인자가 하나인 생성자 Test076이 갖고있는 x : 100 main 에서 ob1.x : 10 main 에서 ob2.x : 100 계속하려면 아무 키나 누르십시오 . . . */
※ this 와 this( )
1) this는 객체 자신을 가리키는 레퍼런스 변수로, 자신의 객체에 접근할 때 사용된다.
- 주로 멤버변수와 매개변수의 이름이 동일할 때, 이를 구분하기 위해 사용
2) this( )는 같은 클래스에서 생성자가 다른 생성자를 호출할 때 사용된다.
- 주로 코드의 중복을 줄일 목적으로 사용됨
- this( )는 생성자 코드에서만 사용할 수 있음
- this( )는 생성자 코드안에서 사용될 때 가장 먼저 실행되어야 하므로 가장 윗줄에 위치한다.
* 클래스명.메소드명(또는 매개변수) 는 다른 문법에서 선점하였기 때문에 사용할 수 없다.
- Test077
- 생성자 (Constructor)
- 오버 로딩
더보기/*============================================= ■■■ 클래스와 인스턴스 ■■■ - 생성자 (Constructor) ==============================================*/ public class Test077 { int val1; double val2; Test077() { val1=0; val2=0; System.out.println("매개변수 없는 생성자..."); } Test077(int x) { val1=x; val2=0; System.out.println("int형 데이터를 매개변수로 받는 생성자..."); } Test077(double y) { val1=0; val2=y; System.out.println("double형 데이터를 매개변수로 받는 생성자..."); } Test077(int x, double y) { val1=x; val2=y; System.out.println("int형 변수와 double형 변수를 매개변수로 받는 생성자..."); } public static void main(String[] args) { Test077 ob1 = new Test077(); //--==>> 매개변수 없는 생성자... System.out.println(ob1.val1 + "," + ob1.val2); //--==>> 0,0.0 Test077 ob2 = new Test077(4); //--==>> int형 데이터를 매개변수로 받는 생성자... System.out.println(ob2.val1 + "," + ob2.val2); //--==>> 4,0.0 Test077 ob3 = new Test077(7.0); //--==>> double형 데이터를 매개변수로 받는 생성자... System.out.println(ob3.val1 + "," + ob3.val2); //--==>> 0,7.0 Test077 ob4 = new Test077(4, 7.0); //--==>> int형 변수와 double형 변수를 매개변수로 받는 생성자... System.out.println(ob4.val1 + "," + ob4.val2); //--==>> 4,7.0 } } // 실행 결과 /* 매개변수 없는 생성자... 0,0.0 int형 데이터를 매개변수로 받는 생성자... 4,0.0 double형 데이터를 매개변수로 받는 생성자... 0,7.0 int형 변수와 double형 변수를 매개변수로 받는 생성자... 4,7.0 계속하려면 아무 키나 누르십시오 . . . */
※ 오버로딩(또는 중복적용) (간략한 개념만)
- 클래스 내부에서 메소드는 "식별자" 역할 → 동일 클래스 내에 중복되는 이름은 없어야함
그러나 메소드에 넘겨주는 매개변수의 개수나 매개변수의 타입이 다르면 동일한 이름을 사용할 수 있다.
- 허용하는 이유는 동일한 기능을 가진 메소드를 만드는데 매번 다른 이름을 만들려면 너무 힘들기 때문
허용하지 않는다면 아래와 같이 선긋는 메소드를 만들때 번호를 붙여 1번은 점선 2번은 두줄 등.. 생성해야
하고 이 모든 기능의 번호 외워 사용하기가 힘들기 때문.
ex) 선긋기( ) { System.out.println("----------------");}
선긋기2( ) { System.out.println("===========");}
이렇게 하는 대신에
ex) 선긋기() {System.out.println("----------------"); }
선긋기(int n) {
for (int i=0; i<n ; i++ )
System.out.println("----------------"); }
이런 식으로 사용할 수 있게 해주는 것.
- Test078
- 생성자 (Constructor)와 초기화 블럭(Initialized Block)
※ 초기화 블럭 (Initialized Block)
- 선언과 동시에 초기화 하지 않았을 때,
즉, 전역변수를 선언만 해두었을때 (-전역변수는 선언만 할 경우 자바에서 자동으로 초기화 하는 값이 담김)
다시 다른 값으로 대입해서 전역변수의 값을 덮어쓰려고 할 때 사용하는 것.
- 대입연산만 있으면 오류가 나기 때문에 블레이스 안에 넣어둔 것 뿐.
- 초기화 블럭보다 생성자가 우선순위가 높다
초기화 블럭을 생성자 위에 놓든, 아래에 놓든 초기화 블럭이 먼저 실행 된 후 생성자가 실행됨
→ 초기화 블럭이 어디에 위치하든 먼저 생성 된 후 생성자가 생성되면,
초기화 블럭이 대입해둔 값이 생성자의 값에 의해서 덮어씌워지면서 사라지게 됨
→ 초기화 블럭이 일한게 의미가 없음
→ 즉, 생성자가 더 중요함!더보기/*===================================================== ■■■ 클래스와 인스턴스 ■■■ - 생성자 (Constructor)와 초기화 블럭(Initialized Block) ======================================================*/ public class Test078 { // 수행할 수 없음 /* int n; // 선언 int m; // 선언 n = 100; // 대입 연산 // 선언은 문제가 없으나 대입연산은 불가능 함. m = 200; // 대입 연산 // 초기화 개념 check! */ // 수행 가능 /* int n = 100; // 선언과 동시에 초기화 int m = 200; // 선언과 동시에 초기화 */ int n; int m; // 생성자 (Constructor) Test078() { n = 100; m = 200; System.out.println("생성자 실행..."); } // 초기화 블럭(Initialized Block) // 생성자보다 하위에 있음. { n = 10; m = 20; System.out.println("초기화 블럭 실행..."); } // 생성자(Constructor) Test078(int n, int m) { this.n = n; this.m = m; System.out.println("매개변수 있는 생성자 실행..."); } // 멤버 출력 메소드 정의 void write() { System.out.println("n:" + n + ", m:" + m); } public static void main(String[] args) { //Test078 인스턴스 생성 Test078 ob1 = new Test078(); //--==>> 초기화 블럭 실행... // 생성자 실행... ob1.write(); //--==>> n:10, m:20 //--==>> n:100, m:200 // Test078 인스턴스 생성 Test078 ob2 = new Test078(1234, 2345); //--==>> 초기화 블럭 실행... // 매개변수 있는 생성자 실행... ob2.write(); //--==>> n:1234, m:2345 } } // 실행결과 /* 초기화 블럭 실행... 생성자 실행... n:100, m:200 초기화 블럭 실행... 매개변수 있는 생성자 실행... n:1234, m:2345 계속하려면 아무 키나 누르십시오 . . . */
// 개인적 감상
더보기클래스와 인스턴스의 개념을 이해하면서,
BufferedReader 나 Scanner 등 인스턴스 생성한다고 써왔던 부분을 실제로 어떤 방법으로 사용하는지 알게되었다.
이를 복습하면서도, 중요한 개념임에도 불구하고 정리가 잘 되어있지 않아서 강의를 들으면서도 긴가민가 하면서 쓰던 부분들을 다시 확인할 수 있었다.쉬운 듯 쉽지않았던 개념이라, 어떻게하면 조금 더 쉽게 이해할 수 있을까 구체적으로 정리해보면서 강의의 흐름과 인스턴스 사용법을 이해할 수 있었다.
728x90'SsY > Class' 카테고리의 다른 글
016. 배열의 배열(다차원 배열)실습, 배열의 난수(Random 클래스) (2) 2023.03.05 015. 배열의 선언과 초기화, 배열 중첩 (배열의 배열) (0) 2023.03.03 013. 클래스와 인스턴스( 지역변수, 전역변수, 메소드와 참조변수, 매개변수, default pakage) (1) 2023.02.28 012. 실행 흐름의 컨트롤(제어문) for문 중첩(별 찍기), break, continue, skip,return 실습, 변수와 메소드의 스코프 (0) 2023.02.26 011. 실행 흐름의 컨트롤(반복문) while, do~while, for문 실습 (0) 2023.02.24 - Test072