[2023.10.05] 개발자 교육 10일 차 : 강의-복습, 클래스 쪼개기, 생성자, 증감연산자 [구디 아카데미/김승수 강사님]

DaramGee·2023년 10월 5일
0

오늘 정리

클래스 사이의 관계를 파악하여 필요한 곳에 인스턴스화를 할 수 있어야 한다.

인스턴스화의 위치에 따라 NullPointException 발생할 수 있다는 것을 설명하고, 해결할 수 있어야 한다.

static 대신 생성자 호출을 통해 객체 주입을 받아내는 코드를 작성할 수 있어야 한다.

복습

  • 클래스 나누기
    package com.step4;
    class M{ //변수
    	int tot;        
    	double avg;
    }
    class M1{//메소드
    	void hap() {
    		System.out.println("hap()");
    	}
    	void hap(int n1) {
    		int n2 = 2;            
    		System.out.println("hap(int n1)");
    		System.out.println("hap(int n2)" + n2); //지변은 초기화 생략x
    	}
    	void hap(M1 m1) {   //목적지!
    		System.out.println("hap(M1 m1)" + m1);
    	}
    }
    public class MMain {
    
    	public static void main(String[] args) {
    		int n1 = 70;
    		int n2 = 80;
    		int n3 = 90;
    		M1 m1 = null;    
    		System.out.println(m1);  //주소x, NullPointerException 발생
    		//나누는 순간 공백, 시점의 문제 발생
    		m1 = new M1();
    		System.out.println(m1); //주소o
    		m1.hap(m1);               //선언은 클래가 들어가지만, 호출하는 자리에는 변수가 들어감 
    		//지변이더라도 파라미터를 통해 원본을 넘기면 다른 메소드에서도 사용이 가능함.
    	}
    }

강의 내용

  • 클래스 구성 : 생성자, 선언부, 내부 클래스, 변수, 메소드(파라미터-참조형, 리턴타입, 오버로딩/오버라이딩)
    • 생성자 : 클래스 간 관계를 통해 시너지 生, 리턴타입X(리턴타입이 들어가면 JVM이 메소드로 인식)
    • 메소드 오버로딩 : 같은 이름의 메소드 사용 가능, but 파라미터 타입이나 갯수 달라야 함.
    • 클래스 나눔 이유 : 클래스 간 관계 인터페이스 처리를 위해 나눔.(참조형 사용 多)
  • Frame work
    • DIJ(Dependet Injection) : 제어권이 넘어감?
  • java의 배열
    • Table이 가로(row) → 클래스, 세로(colum)로 구성되어 있다면?
      idagename …
    • 배열 : 값이 들어갈 방 만들기
    • 생성자 : 생성자 파라미터 자리에 메소드 오버로딩 규칙 들어감?
    • 1차 배열(table)
      • 세로 방향이라 같은 타입만 담기는 한계 있음.(데이터 간의 관계 확인x)

      • 생성자를 통해 사이즈가 결정되면 변경 x

        • 변수.length로 길이 넣기도 함.
      • 데이터 끼워넣기 x

        	public static void main(String[] args) {
        		int com[]   = new int[3];
        		for(int i=0;i<3;i++) {
        			System.out.println("com ["+i+"]"+com[i]);
        		}
        	}
    • 2차 배열
  • 향상된 for문
    • 가진 전부를 처리할 때 사용
      public static void main(String[] args) {
      		int my[]     = {1, 2, 3};
      		//가진 전부를 처리할 땐 개선된  for 문 사용
      		for(int i:my) {
      			System.out.print(i); // 1, 2, 3  출력
      		}
      		System.out.println();
      		int other[]  = new int[] {1,2,3};
      		for(int i:other) {
      			System.out.println(i);
      		}
      	}
  • 생성자
    • 생성자를 통해 (캡슐화 된) 전역변수의 재정의, 초기화를 해줄 수 있다.
      • 이때, 생성자 내부에서는 반드시 전변과 파라미터 값 동기화 필요
    • 생성자 안에서도 메소드를 호출할 수 있다.
      • 이 때, 호출 순서를 정할 수 있어야 한다.(선처리, 후처리)
    • 메소드 오버로딩은 같은 이름의 메소드나 생성자를 중복해서 선언할 수 있다.
    • 파라미터값으로 지역변수와 전역변수의 동기화 가능(재정의, 초기화)
    • 단 파라미터 갯수 또는 타입은 달라야만 한다.
      class F2{
      	//생성자
      	F2(){}
      	F2(int i){	}
      //	F2(int j){	} //타입, 갯수 같음
      	F2(boolean isOk){System.out.println(isOk);}
      	F2(String s, int i){	}
      	F2(int i, int j){System.out.println(i+","+j);}
      }
      
      public class Fmain2 {
      
      	public static void main(String[] args) {
      		F2 f = new F2(1,2);
      		System.out.println(f);
      		f = new F2(true);      //객체 배열, 자료구조, 웹 or 하이브리드, JSON
      		System.out.println(f); //다른 주소번지를 갖는다.
      	}
      }
  • this
    • 현재 스래드가 관리하는 클래스, 원본 나 자신임.(따라서 참조하여 생성하면 주소번지는 같음)
    • 현재 메모리에 활성화(언제든 사용 가능) 되어있는 원본의 객체를 참조하고 있다.
      class GLogic{
      	int i = 1;
      	public GLogic(GView gv) {  //null
      		System.out.println(gv);
      	}
      }
      public class GView {
      	//디폴트 생성자만 생략 가능함!
      	GView() {
      		GLogic gl = new GLogic(this);          //this는 현재 스레드가 관리하는 클래스이고 원본 나 자신
      		//원본인지 확인하는 법? 전역변수로 확인 가능??
      	}
      	public static void main(String[] args) {
      		//static 안에서는 this나 supper(부모클래스 수정자?) 사용 불가 -> 생성자에서는 가능하다
      		GView gv = new GView();
      		System.out.println(gv);
      	}
      }
  • private 변수
    • 캡슐레이션(캡슐화) 그 사물을 정의하는 중요한 고유명사를 만들어 임의로 위변조 x
    • getters and setters로 사용 가능 → 전역변수를 바라보고 있음.
    • 생성자를 통해서 전역변수 초기화, 인터셉트 사용 가능 → 인스턴스변수.set변수(초기화값);
      class Dept{
      	//전변은 초기화를 생략할 수 있다. 생성자가 대신 해준다.
      	public Dept() {}
      	private int deptno;     //부서번호
      	private String dname; //부서명
      	private String loc;      //지역
      	public Dept(int deptno, String dname, String loc) {
      		//지역변수와 전역변수의 동기화! (생성자의 파라미터값으로 재정의, 초기화)
      		this.deptno  = deptno; 
      		this.dname  = dname;
      		this.loc       = loc;
      	}
      	public int getDeptno() {
      		return deptno;
      	}
      	public void setDeptno(int deptno) {
      		this.deptno = deptno;
      	}
      	public String getDname() {
      		return dname;
      	}
      	public void setDname(String dname) {
      		this.dname = dname;
      	}
      	public String getLoc() {
      		return loc;
      	}
      	public void setLoc(String loc) {
      		this.loc = loc;
      	}
      }
      public class DeptMain {
      
      	public static void main(String[] args) {
      		//인스턴스화를 해도 안된다. -> 캡슐레이션(캡슐화) 그 사물을 정의하는 중요한 고유명사 만들기 private
      		Dept dept   = new Dept();                                //기본값
      		Dept dept1 = new Dept(10, "개발1팀", "부산");    //10 새로운 객체 생성 
      		System.out.println(dept.getDeptno());                 //0
      		dept1.setDeptno(100);                                     //10->100 초기화 by 생성자의 인터셉트
      		System.out.println(dept1.getDeptno());               //10
      		dept1 = null;                                                 //캔디데이트 상태 -> 너는 앞으로 쓰레기 값이 됨 
      						                                                   //- > dept1 = new dept1();  실행되면 앞의 38번에서 생성된 객체는 사라짐 
      //		dept1.setDeptno(100);                                     //NullPointerException 발생
      		dept1 = new Dept();
      		dept1.setDeptno(100);                                     //10->100 초기화 by 생성자의 인터셉트
      		dept1.setDname("운영1팀");
      		dept1.setLoc("제주");
      		System.out.println(dept1.getDeptno()+", "+dept1.getDname()+", "+dept1.getLoc());
      		System.out.println(dept.getDeptno()+", "+dept.getDname()+", "+dept.getLoc());
      	}
      }
      /*
      Dept 클래스에 Getter Setter를 두는 것은 결국 전역변수를 사용하기 위함이다. 
      web서비스 - 동기화 가능
      150명 사용 -> 인스턴스를 갖는다 ->하나임 ->싱글톤
      */
  • 증감연산자
    • 대입이 먼저? 증감이 먼저?
    • 변수 앞에 연산자가 있으면 증감이 먼저 진행되고, 뒤에 있을 땐 대입이 먼저 진행됨.
      int i = 1;
      int j = i++;  //j=1, i=2
      
      int a = 1;
      int b = ++a;  //b=2, a=2
  • 연산자 || , &&, &
    • ||(파이프 연산자) → or
      • 이거나 비교일 때는 첫번째 조건이 참이면 두번째 조건은 따질 필요 없음. 어차피 실행(예 : 아이디 중복검사)
    • &&(엔퍼센트 연산자) → and
      • 둘 다 참일 때 실행(예 : 아이디, 비번 동시 검사)
      • 일의 양이 줄어들기 때문에 많이 사용
  • do while문(예 : baseballgame)
    • do..while문 조건 검사를 나중에 하므로 무조건 한 번은 실행
      public class Oper4 {
      
      	public static void main(String[] args) {
      		int i = 1;
      		int j = 10;
      		do {
      			System.out.println("나는 do문과 함께 무조건 실행된다. "+i+", "+j);
      		    if( i>j )  break;
      		    System.out.println("if문의 조건 만족하면 나는 못 본다."+i+", "+j);
      		     j--;
      		}while( ++i < 5 );
      		System.out.println("i는 "+i+", j는 "+j);
      	}
      }
      /*
      나는 do문과 함께 무조건 실행된다. 1, 10
      if문의 조건 만족하면 나는 못 본다.1, 10
      나는 do문과 함께 무조건 실행된다. 2, 9
      if문의 조건 만족하면 나는 못 본다.2, 9
      나는 do문과 함께 무조건 실행된다. 3, 8
      if문의 조건 만족하면 나는 못 본다.3, 8
      나는 do문과 함께 무조건 실행된다. 4, 7
      if문의 조건 만족하면 나는 못 본다.4, 7
      i는 5, j는 6
      */
      public void ranCom() {
      		Random r = new Random();
      		com[0] = r.nextInt(10); //0~9 사이 숫자 채번
      		//do..while문 조건검사를 나중에 하므로 무조건 한 번은 실행되고, while문은 먼저 조건검사를 하니 한번도 실행이 안될 수 있음. 
      		do { 
      			com[1] = r.nextInt(10);
      		}while(com[0] == com[1]);
      		do { 
      			com[2] = r.nextInt(10);
      		}while(com[0] == com[1] || com[1] == com[2]);  
      	}
  • 메소드 단위 테스트(unit test)
    • 클래스 실행에 있어 각 메소드가 작동을 잘 하는지 별도의 테스트 클래스를 만들어서 작동확인
    • 회차에 for문의 i를 넣으면 변경되는 부분이 많음. → cnt와 같은 다른 변수를 만들어 회차를 표시하는 것이 좋음.
      public class UnitTest {
      
      	public static void main(String[] args) {
      		BaseballGame bbg = new BaseballGame();
      
      		
      		String hint = null;
      		int cnt = 0;
      		for(int i=0;i<3;i++) {
      			hint = bbg.account(++cnt +"회차 : "+"25"+ ++i);
      			System.out.println(hint);
      		}
  • 이중 for문
    public String account(String user) {
    		System.out.println("사용자가 입력한 숫자는 "+user);
    		if(user.length()!=3) {
    			return "세자리 숫자를 입력하세요.";
    		}
    		//사용자가 jtf_user에 입력한 숫자는 보기에는 숫자 처럼 보여도 알맹이는 문자열로 
    		//인식을 합니다. 그래서 형전환을 한 후 my[]배열에 담아야 함니다.
    		//문자열 "256"을 숫자로 담을 변수 선언
    		int temp 	= 0;
    		int strike 	= 0;//힌트로 사용될 스트라이크를 담을 변수 선언
    		int ball 	= 0;//볼을 담을 변수 선언
    		//strike와ball을 지역변수로 해야 하는건 매 회차 마다 값이 변해야 하기 때문이다.
    		try {
    			temp = Integer.parseInt(user);
    		} catch (NumberFormatException e) {
    			return "숫자만 입력하세요.";
    		}
    		my[0] = temp/100;         //2.56 -> int 2만 담김(백의자리)
    		my[1] = (temp%100)/10; //5.6   -> int 5만 담김(십의자리)
    		my[2] = temp%10;         //6     -> int 6만 담김(일의자리)
    		System.out.println(my[0]+""+my[1]+""+my[2]);
    		for(int i=0;i<3;i++) {
    			for(int j=0;j<3;j++) {
    				if(com[i] == my[j]) {          //숫자 같니?
    					if(i == j) {      //위치 같니?
    						strike++;
    					}else {
    						ball++;
    					}
    				}
    			}
    		}
    		return strike+"스  "+ball+"볼";
    	}

강의 마무리

0개의 댓글