Dev/Java

[java] 생성자, instance블럭, static블럭, 재귀함수, Call By Reference

창문닦이 2019. 1. 24. 19:13

생성자

1.메모리를 할당 받을 때 사용

2.변수 초기화 목적

클래스의 이름과 동일

리턴값이 없기 때문에 property가 없다. 생성자냐 메소드냐 둘중에 하나.

property가 있다면 무조건 메소드

오버로딩이 가능함. (오버로딩 : 메소드중복정의. 하나의 클래스 안에서 이름은 같지만 데이터 자료형,매개변수 갯수 상이함.)

코딩의 첫째줄에서 한번만 호출 가능 <- 상속에서 추가설명

public class Test1 {

//instance 변수와 초기화 메소드는 세트라고 생각. 없으면 초기값 설정할 수 없음.

private int x;  //instance변수

//생성자코딩. 변수선언한 끝에 있음. void, int 등 리턴값 없음.

public Test1(){ //기본생성자. 무조건 작성되어지고 표기가 생략되어 있음. 중복정의(오버로딩) 할거 아니라면 생략

this(100); //오버로딩된 생성자를 호출. 사용하려면 맨앞줄에 한번만 써줘야 오류안남

System.out.println("기본생성자(인수가 없는 생성자)");

x=10; //생성자를 통한 변수초기화

System.out.println("x: "+ x);

}

/*

public Test1(){}

기본생성자를 지워버리면 무조건 오버로딩된 생성자로 생성.

Database활용시 기본생성자에 저장경로를 세팅해놔서 객체생성과 동시에 위치 설정을 하면 손쉽게 관리 가능

반드시 필요한 변수값 설정시 사용

*/

public Test1(int x){//필요에 의해 만드는 오버로딩된 생성자

//this(); // 오버로딩된 생성자에서 기본생성자 호출가능. 지금은 기본생성자 호출. 사용하려면 맨앞줄에 한번만 써줘야 오류안남

System.out.println("중복정의된 생성자");

this.x = x;

System.out.println("x: "+ x);

}

public void set(int x){ //초기화메소드

this.x = x;

}

//생성자를 통한 변수초기화 : public Test1() 가

//초기화메소드: set() 를 이용한 초기화보다 빠르다!

public static void main(String[] args) {

Test1 ob1 = new Test1(); //객체 생성을 통해 메모리를 할당받고 public Test1()로 가서 실행해줌. 기본생성자 호출

ob1.set(10);

System.out.println("main ob1.x: " + ob1.x);

Test1 ob2 = new Test1(20); //오버로딩된 생성자 호출. 객체 생성과 동시에 초기화 진행

//오버로딩된 생성자를 사용하기 위해서는 반드시 기본생성자도 같이 정의해줘야 함

//이 때, 기본생성자를 정의하지 않는다면 사용이 불가능.

//중복정의해서 사용하는 게 자주 있진 않지만, 필요할 수 있으니 기억.

}

}


private 변수 초기화 방법은 두가지. 초기화메소드 이용, 생성자 이용

class Rect{

private int w;

private int h;

public Rect(){//기본생성자

}

public Rect(int w, int h){//오버로딩된 생성자

this.w = w;

this.h = h;

}

public void set(int w, int h){//초기화 메소드

this.w = w;

this.h = h;

}

public int area(){

return w*h;

}

public int length(){

return 2*(w+h);

}

public void print(int a, int l){

System.out.println("가로: "+ w);

System.out.println("세로: "+ h);

System.out.println("넓이: "+ a);

System.out.println("둘레: "+ l);

}

public void print(int a){ //메소드 오버로딩(중복정의)

System.out.println("가로: "+ w);

System.out.println("세로: "+ h);

System.out.println("넓이: "+ a);

}

}

public class Test2 {

public static void main(String[] args) {

Rect ob1 = new Rect(); //기본생성자 + 초기화메소드 사용

ob1.set(10, 20);

int area = ob1.area();

int length = ob1.length();

ob1.print(area);

ob1.print(area, length);

System.out.println("-------------------");

Rect ob2 = new Rect(100,200); //오버로딩된 생성자를 통해 객체 생성시 초기화 바로 진행. spring에서 '의존성 주입'이라고 함

area = ob2.area();

length = ob2.length();

ob2.print(area);

ob2.print(area, length);

}

}


객체가 생성되면 바로 실행되는 instance 블럭

public class Test3 {

int a=5; //instance변수

{//초기화 블럭. 메소드로 호출하진 않는데 형식은 갖춰야 함. instance. 객체를 생성해야 볼 수 있음

System.out.println("초기화 블럭 a -> " + a);

a=10;

System.out.println("초기화 블럭 a -> " + a);

}

static int b; //클래스변수. 메모리 할당 되어 있음.

static{//static 블럭

b = 20;

System.out.println("static 블럭 b -> " + b);

}

final int C; //final변수 = 상수. 항상 변하지 않는 수. 대문자로 작성함. 프로그램이 끝날 때 까지 값을 바꿀 수 없음

//은행에서의 변동하지 않는 고정이자율. 원주율(파이)와 같은 변수 설정시 사용한다.

//상수에 값을 설정 안해두면 에러. 초기값 반드시 설정해야 함. 메모리에 올라가야만 초기화 가능.

//일반 메소드에서 초기화 시킬 수 없음

public Test3(){

System.out.println("생성자...");

C = 100;

System.out.println("C:"+ C);

}//이런 경우에 가장 마지막에 생성되는 것은 생성자.

public static void main(String[] args) {

Test3 ob = new Test3(); //객체생성. static블록이 제일 먼저 생성됨

Test3 ob1 = new Test3(); //객체 두개 생성시 static은 객체를 여러번 만들어도 한번만 만들어진다. 메모리를 같이 쓰니까

final int k = 10;

}

}


되부름 함수(재귀함수)

장점 : 소스가 간단해짐. 소스가 짧음

단점 : 처리속도가 느림(stack에 저장했다가 출력하기 때문에)

비정형인수 예제

public class Test4 {

public void print(int n){

if(n!=1){

print(n-1); //되부름함수, 메소드안에서 함수호출시 자기 자신을 부름

}

System.out.printf("%5d",n);

}

public int sum(int n){

//1-10까지의 합

return n>1 ? n+sum(n-1) : n;

}

public int pow(int a , int b){

return b>=1 ? a*pow(a,b-1) : 1;//메소드안에서 자기자신 호출 = 되부름함수

}

//비정형인수

int sum(int...args){

int sum=0;

/*

for(int i=0;i<args.length;i++){

sum+=args[i];

}

*/

for(int su: args){ //확장for문으로도 사용가능

sum += su;

}

return sum;

}

public static void main(String[] args) {

Test4 ob = new Test4();

ob.print(5);

System.out.println();

int s = ob.sum(100);

System.out.println(s);

System.out.println("pow(2,10): " + ob.pow(2,10));

//비정형인수

int result;

result = ob.sum(2,4,6,8,10); //배열 설정시에는 크기를 지정해야 되는데 비정형인수는 정해져 있지않아도 배열처럼 연산가능

System.out.println(result);

result = ob.sum(1,3,5,7,9,11,13,15,17);

System.out.println(result);

}

}


클래스를 활용하여 객체 생성 후 계산기 만들기

import java.io.IOException;

import java.util.Scanner;

class Calc{

private int num1, num2;

private char oper;

public boolean input() throws IOException{

Scanner sc = new Scanner(System.in);

System.out.print("두개의 수?");//10 20

num1 = sc.nextInt();

num2 = sc.nextInt();

System.out.println("연산자?");//+,-,*,/

oper = (char)System.in.read();

if(oper!='+' && oper!='-' && oper!='/' && oper!='*'){

return false;

}

return true;

}

public int result(){

int r = 0;

switch(oper){

case '+':

r = num1 + num2; break;

case '-':

r = num1 - num2; break;

case '/':

r = num1 / num2; break;

case '*':

r = num1 * num2; break;

}

return r;

}

public void print(int r){

System.out.printf("%d %c %d = %d\n",num1, oper, num2, r);

}

}

public class Test5 {

public static void main(String[] args) throws IOException {

Calc ob = new Calc();

boolean b = false;

int r = 0 ;

/*

b = ob.input(); //예외처리를 main문에서도 써줘야 함

if(b==true){

r = ob.result();

ob.print(r);

}

System.out.println("연산자 오류!!");

*/

//boolean이므로 True나 False값이 나옴. 일반적으로 중괄호 바깥을 정상실행의 경우로 작성. 소스코드가 길어서

if(!ob.input()){

System.out.println("연산자 오류!!");

return;

}

r = ob.result();

ob.print(r);

}

}


Call By Value.

동일 변수값을 가진다. stack 영역의 데이터가 Heap영역으로 데이터 자체가 넘어감

Call By Reference

Heap영역에 있는 데이터를 복사할때 데이터자체가 복사되는게 아니라 주소가 복사되는 것. static과 같은 역할을 함

동일 주소를 가진다. 주소를 서로 나누어 가짐. 이미 만들어진 것을 가져다 쓸 때 사용

class Test{

public int x= 10;

public void sub(int a){

x += a; //x=x+a

}

}

public class Test6 {

public static void main(String[] args) {

Test ob = new Test();

int a = 10;

System.out.println("sub메소드 실행전 :" + ob.x);

ob.sub(a);// Call by value

System.out.println("sub메소드 실행후 :" + ob.x);

Test ob1;

ob1 = ob; //Call by reference. ob의 주소값을 ob1에 넣어라. 주소값을 복사해서 같은 곳을 가리키므로 동일값 나옴

System.out.println("ob.x:" + ob.x ); //20

System.out.println("ob1.x:" + ob1.x ); //20

//똑같은 위치인 걸 어떻게 아느냐. 값을 변경해서 다시 조회해보면 됨

ob1.x = 100;

System.out.println("ob.x:" + ob.x ); //100

System.out.println("ob1.x:" + ob1.x ); //100

}

}


상속(부모가 자식한테 주는 것)

1. 부모꺼는 내거다

2. private 로 선언한 것은 상속이 불가능

3. protected 로 선언한 것은 상속이 가능. 같은 패키지안에서라면 사용 가능

4. 내꺼는 내거다. 부모가 가져다가 쓸 순 없음. 이순신의 특징은 이순신만 사용 가능!

5. 부모도 가지고 있고 나도 가지고 있으면 내꺼 쓴다.

class SuperClass{

private String title;

private int area;

public void set(String title, int area){

this.area=area;

this.title = title;

}

public void print(){

System.out.println(title + ":" + area);

}

}

class SubClass extends SuperClass{ //다중상속이 안되기 때문에 하나만 쓸수있음(단일상속)

private int w;

private int h;

public SubClass(int w, int h){ //생성자 초기화

this.w = w;

this.h = h;

}

public void rectArea(){

int a = w*h;

//area = w*h; 바로 area에 입력할 수 없음. private이기 때문 //2.private로 선언한 것은 상속이 불가능

set("사각형", a); //1.부모꺼는 내거다

}

}

public class Test7 {

public static void main(String[] args) {

SubClass ob = new SubClass(10,20);

ob.rectArea();

ob.print();//1.부모꺼는 내거다

}

}


상속(부모가 자식한테 주는 것)

1. 부모꺼는 내거다(자식도 그대로 쓸 수 있음)

2. private 로 선언한 것은 상속이 불가능

3. protected 로 선언한 것은 상속이 가능

4. 내꺼는 내거다. 부모가 가져다가 쓸 순 없음

5. 부모도 가지고 있고 나도 가지고 있으면 내꺼 쓴다.

class SuperClassA{

private String title;

protected int area; // 자식도 사용가능하도록 접근제어자 변경

public void set(String title){

this.title = title;

}

public void print(){

System.out.println(title + ":" + area);

}

}

class SubClassA extends SuperClassA{ //다중상속이 안되기 때문에 하나만 쓸수있음(단일상속)

private int w;

private int h;

public SubClassA(int w, int h){ //생성자 초기화

this.w = w;

this.h = h;

}

public void rectArea(){

//int a = w*h;

area = w*h; //3. protected 로 선언한 것은 상속이 가능

set("사각형"); //1.부모꺼는 내거다

}

}

public class Test8 {

public static void main(String[] args) {

SubClassA ob = new SubClassA(100,200);

ob.rectArea();

ob.print();//1.부모꺼는 내거다

ob.area = 10; //protected 일때는 접근 가능

System.out.println("area : "+ ob.area);

}

}