U E D R , A S I H C RSS

한자공/시즌3/20140721


1. 일시

  • 오후 12 : 10 ~ 오후 1 : 50

2. 참가자

유재범 참석
최다인 불참
이지수 참석
김용준 참석
김정민 참석

3. 진행 상황

  • 유재범 학우의 발표
    • JAVA의 정석 7-5~

3.1. 발표 내용

  • 클래스 중첩 : 여러 클래스를 관리 할 때 클래스 안에 다시 클래스를 선언하여 중첩시키는 것.

Outer 객체1 = new Outer(); //Outer 클래스 객체 생성 방법
Outer.Inner 객체2 = 객체1.new Inner(); //Inner 클래스 객체 생성 방법
  • 컴파일러를 돌리고 윈도우 탐색기를 이용하면 Outer$Inner.class 라는 파일도 있을 것이다. 이 파일이 바로 중첩된 클래스를 나타내는 것이다.
  • Inner 클래스에서는 Outer 클래스의 멤버를 이용할 수 있다. 하지만 Outer 클래스에서 Inner 클래스의 멤버를 이용하려면 객체를 직접 선언해야 한다.
    • Outer 내부에서 Inner의 멤버를 사용하기 위해 객체를 선언하려면 현재 클래스의 객체를 대변하는 this가 있어야 한다.
      • static 메서드 내부에서는 일반 중첩 클래스의 객체가 선언 될 수 없다는 것
      • 또 Inner 내부에 static과 관련된 멤버를 선언하는 것도 컴파일 에러를 발생시킨다
  • 정적 중첩 클래스 : 중첩 클래스 내부에서 static과 관련된 멤버를 선언할 수 있는 클래스
    • 일반 중첩 클래스 내부에는 static과 관련된 멤버를 선언할 수 없다. 그러나 Outer 클래스의 멤버를 단지 이용만 할 때에는 static이든 아니든 관계 없이 이용 할 수 있다.

class Outer{
	static class Inner{
		..........
	}
}
  • 정적 중첩의 클래스는 static의 특성상 객체를 독립적으로 만들 수 있다.
    • Outer.Inner 객체 = new Outer.Inner();
  • Outer 클래스의 객체가 없어도 Inner 클래스의 객체를 만들 수 있다.
  • 또한 static 멤버를 선언 할 수 있고 static 메서드도 만들어 사용 할 수 있다.
    • 그래서 Inner 클래스 내부에 static을 선언하여 사용하고 싶다면 정적 중첩 클래스를 사용해야 한다. 객체 선언 방식은 위와 같은 방식으로만 발생시킬 수 있따.
    • Outer 클래스의 멤버는 static일 경우에만 사용할 수 있다. 이것은 마치 일반 멤버를 static 메서드 내부에서 사용할 수 없는것과 유사하다

public class Round12_Ex04 {
	public static class Inner3{
		public static void main(String[] ar){
			System.out.println("Inner 클래스 내부의 main 메서드");
		}
	}
}
  • 위와 같은 경우 java Round12_Ex04로 실행하면 main() 메서드가 Inner 클래스 내부에 있기 때문에 찾을 수 없어 JVM이 main()을 찾을 수 없다는 에러가 뜬다. 그래서 실행 시킬때에는 java Round12_Ex04$Inner3으로 실행을 해야 한다.
    • 이것은 실제 메서드가 있는 곳을 지칭하는 것이다.
  • 지역 중첩 클래스 : 특정 메서드에 한정적인 용도로 사용할 클래스로 등장
    • 일반적으로 보통 클래스와 동일하나 접근 제한자와 지정 예약어를 사용할 수 없다는 형태이다.
    • 만일 일반 중첩 클래스처럼 main() 메서드의 멤버를 사용하려면 그 멤버는 반드시 final로 선언되어 있어야만 한다.
    • 컴파일을 하면 Round12_Ex06.class 외에 Round12_Ex06$1Inner5.class라는 클래스가 생성된다.
    • 일반 중첩 클래스와 유사하가 static 멤버를 선언하지 못한다.
  • 익명 중첩 클래스 : class라는 예약어와 클래스 명을 가지지 않고 단지 instance의 생성과 내용부의 정의만 가지고 있는 클래스
    • 지역 중첩 클래스의 변형된 형태
    • 다만 여기에 사용되는 중첩 클래스는 이미 기존에 존재 하는 것이어야 한다.
    • 또한 이 내에서 사용 할 수 있는 외부 데이터도 final로 선언되어 있어야 한다.
    • 내용부가 서로 다른 특정 메서드의 실행을 주관 하기 위해서 사용
      • 접근 제한자의 사용에 주의해야 한다. 자기 자신의 멤버일지라도 정의되는 영역이 다르기 때문이다.

class Inner6{
	int y = 200;
	public Inner6(){
		this.disp();
	}
	public void disp(){}
}
public class Round12_Ex07 {
	public static void main(String[] ar){
		final int x = 100;
		new Inner6(){
			public void disp(){
				System.out.println("Default 생성자");
				System.out.println("x = " + x);
				System.out.println("y = " + y);
			}
		};
	}
}
  • 위 예시를 컴파일 후 탐색기로 클래스 파일을 찾아보면 Inner6.class, Round12_Ex07.class, Round12_Ex07$1.class. 이렇게 3개가 생성이 된다.
    • 이 중 마지막이 익명 중첩 클래스인다 이름에서 알 수 있듯이 익명이기에 숫자로 그 클래스를 표시한다.
    • 만약 main() 메서드 내부에 다른 익명 중첩 클래스가 있다면 이 클래스는 Round12_Ex07$2.class가 될 것이다.
  • 익명 중첩 클래스는 내부에 생성자를 작성할 수 없다.
    • 만약 작성하면 invalid 메서드 declaration 이렇게 뜰 것이다.
  • 다형성 : 여러개의 개별적 클래스를 하나의 부모 클래스 객체로 통합하여 관리하여 그 효율성을 높인 것
    • 예 : 배열
    • 다형성의 표현

A ap = new A();
A bp = new B();
A cp = new C();
  • 여기서 중요한 것은 자신의 클래스 객체가 아니지만 자신의 부모 클래스라면 인스턴스를 부모 객체에 담을 수 있다는 것이다.

class A3{
	public String toString(){
		return "A3 클래스";
	}
}
class B3{
	public String toString(){
		return "B3 클래스";
	}
}
public class Round13_Ex01 {
	public static void main(String[] ar){
		A3 ap = new A3();
		B3 bp = new B3();
		System.out.println("ap = " + ap);
		System.out.println("bp = " + bp);
	}
}
  • 위 클래스 A3, B3는 언뜻 보면 연관이 되어 있지 않지만 사실 다형적인 표현을 사용할 수 있다.
    • 왜냐하면 모두 Object를 부모로 두기 때문이다. 그래서 이를 아래와 같이 사용 할 수도 있다.

public class Round13_Ex01 {
	public static void main(String[] ar){
		Object[] obj = new Object[2];
		obj[0] = new A3();
		obj[1] = new B3();
		for(int a = 0; a<obj.length; a++){
			System.out.println("abj[" + a + "] = " + obj[a]);
		}
	}
}
  • 다형적인 표현에서 멤버에 대한 접근 규정
    • 부모 클래스가 가지고 있는 모든 멤버들에 접근할 수 있다.
      • 단, 자식 클래스에서 메서드 오버라이딩을 했다면 오버라이딩이 된 자식의 멤버에 접근이 된다.
    • 멤버 필드의 경우 부모 클래스의 멤버 필드에만 접근 할 수 있다.
      • 자식 클래스의 멤버 필드는 오버라이딩이 된 자식 클래스의 메서드에 의해서만 접근 할 수 있다.
  • 다형성에서 멤버 필드로의 접근
    • 필드는 다형성으로 표현 되었을 때는 객체를 통해 부모 클래스의 멤버 필드에만 접근 할 수 있다.
    • 상위 하위 모두 동일한 이름의 필드라 하더라도 상위 클래스의 멤버 필드의 것만 접근 할 수 있다.
  • 다형성에서 메서드로의 접근
    • 우선은 상위 클래스의 메서드에 접근 할 수 있고 하위 클래스의 메서드에는 접근 할 수 없다.
    • 하지만 상위와 하위에 동시에 있는 오버라이딩이 된 메서드에 대해서는 하위의 멤버를 실행 할 수 있다.

class A6{
	public void aaa(){
		System.out.println("aaa");
	}
	public void bbb(){
		System.out.println("bbb");
	}
}
class B6 extends A6{
	public void bbb(){
		System.out.println("bbb1");
	}
	public void ccc(){
		System.out.println("ccc");
	}
}
public class Round13_Ex11 {
	public static void main(String[] ar){
		A6 ap = new B6();
		ap.aaa();//상위 클래스의 메서드에 접근
		ap.bbb();//오버라이딩 된 하위 클래스에 접근
		//ap.ccc();//하위 클래스의 메서드에 접근
	}
}
  • 다형성은 어떤 값이 올지 예상을 하면 어렵지 않다고 한다.

class A{ ...}
class B extends A{...}
public class C{
	public static void main(String[]ar){
		A ap = new B();
		B bp = ap;
	}
}
  • 위와 같은 경우 에러가 발생한다. 에러를 발생하지 않게 하기 위해서는 B bp = (B)ap로 명시적으로 캐스팅을 해야 한다.
  • 하지만 아직 문제는 있다. 만약 A ap = new A();라는 문맥이었다면 Exception in thread "main" java.lang.ClassCastException:A라는런타임 에러가 발생한다. 이럴 때 instanceof라는 예약어가 참으로 유용하다.
    • instanceof 연산자 : 참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용
      • 이항 연산자이며 피연산자는 참조형 변수와 타입, 연산 결과는 true, false이다.
      • instanceof의 연산 결과가 true이면 해당 타입으로 형변환이 가능하다.

class A{}
class B extends A{}
public class Test{
	public static void main(String[] ar){
		A ap = new B();
		B bp = null;
		if(ap instanceof B){//형식 : 객체 instanceof 변환할 클래스
			bp = (B)ap;
			System.out.println("형 변환이 가능하다.");
		}
		else{
			System.out.println("형 변환이 불가능 하다");
		}
	}
}

  • abstract(추상, 추상 메서드, 추상 클래스) : 부모클래스를 직접 사용하지 않고 자식을 통해서만 사용할 목적으로 혹은 단지 묶어 주기만 할 목적으로 클래스를 만들 때 추상 클래스를 사용한다.
    • 접근_제한자 abstract class 클래스명 extends 상위_클래스 implements 상위_인터페이스{...}
    • 추상 클래스는 일반 클래스의 모든 기능을 할 수 있다. 다만 그 자신의 객체만큼은 발생시키지 못한다.
      • 이것은 주로 다형성을 표현할 목적으로 많이 사용하는데 이런 것을 "디자인 목적"이라고 한다. 쉽게 하나의 제품을 만들 때 참고하는 디자인 혹은 모델이라고 생각해두자.
      • 만약 추상 클래스가 추상 메서드를 가지고 있다면 그것은 반드시 오버라이딩 되어야 한다.
    • 추상 클래스는 일반 클래스의 멤버 이외에 추상 메서드를 가질 수 있다.
      • 접근_제한자 abstract 결과형_리턴값 메서드명(매개_변수들) throws 예외 클래스들;
        • 여기서 중요한 것은 마지막에 세미클론으로 끝난다는 것이다. 즉, 내용부를 가지지 않고 이름만 있는 메서드이다.
          • 이런 이유는 다형성의 표현에서 오버라이딩이 되었음을 의미하는 것인데 이것은 반드시 오버라이딩이 되어야만 한다.
    • 추상메서드를 만드는 이유는 상속받는 하위 클래스에게 디자인이 되어 있는 메서드를 재정의 하라고 명령을 내리기 위해서다.
    • 추상클래스를 통해 인스턴스를 발생시키려고 하면 에러가 발생한다.

  • 인터페이스 : 단일 상속의 제약을 보완하기 위해 자바에서 제안한 새로운 개념의 클래스. 이를 통하 자바는 다중 상속을 할 수 있게 되었다.
    • 접근_제한자 interface 인터페이스 명 extends 상위_인터페이스{ 내용부 }
      IMG_20140721_034348.jpg
      [JPG image (1.51 MB)]

    • 인터페이스는 다중 상속이 가능하다는 특징이 강하게 나타난다.
    • 인터페이스의 정의
      • 1. 다중 상속을 위한 클래스의 대안
      • 2. 다형성에 의한 클래스 제어
    • 인터페이스의 내부에 포함 될 수 있는 멤버들은 일반 클래스와 조금 차이난다.
    • 인터페이스 포함 멤버
      • 필드 : 무조건 public static final 멤버 필드이다. 모두 기재하든 static만 기재하든 기재를 하지 않든 모두 public static final로 인식한다.
      • 메서드 : 무조건 public abstract 멤버 메서드다. 고로 정의부를 가질 수 없다. 인터페이스도 다형성이 목절이므로 자동으로 모든 메서드가 abstract가 된다.
      • 정적 중첩 클래스 : 인터페이스가 가지는 중첩 클래스에는 자동적으로 static이 붙어 정적 중첩 클래스만 가질 수 있다는 개념이 되어버린다. 물론 중첩 클래스 내부에는 일반 클래스처럼 할수 있다.(생성자 생성, 정의부가 있는 메서드 생성 등)
    • 인터페이스에는 생성자 조차 없다. 어떤 의미로는 제한적인 클래스라고 생각 할 수도 있다.
    • 추상 메서드를 포함 하고 있고 생성자도 없어 객체를 발생 시킬 수 없다.
      • 필드 : 인터페이스에서 필드를 사용하려면 직접 값을 할당하는 방식으로 한다.

interface A1{
	int w = 10;
	static int x = 20;
	final int y = 30;
	public static final int z = 40;
}
public class Round14_Ex01 {
	public static void main(String[] ar){
		//A1 ap = new A1();
		//A1.w = 100;
		System.out.println("w = " + A1.w);
		System.out.println("x = " + A1.y);
		System.out.println("y = " + A1.x);
		System.out.println("z = " + A1.z);
	}
}
  • 메서드 : 무조건 public abstract이기 때문에 무조건 하위 클래스에 의해 오버라이딩이 되어야 한다.
    • 그리고 public 접근자가 생략되어 있으므로 오버라이딩 시에는 반드시 접근자를 public으로 해야 한다.

interface A2{
	void aaa();
	public abstract void bbb();
}
class B2 implements A2{
	void aaa(){
		System.out.println("aaa 메서드");
	}
	public void bbb(){
		System.out.println("bbb 메서드");
	}
}
public class Round14_Ex02 {
	public static void main(String[] ar){
		B2 bp = new B2();
		bp.aaa();
		bp.bbb();
	}
}
  • 정적 중첩 클래스 : 인터페이스에 마지막으로 있을 수 있는 멤버는 정적 중첩 클래스와 중첩 인터페이스이다. 클래스가 중첩 될 경우 무조건 public, static이기에 정적 중첩 클래스가 되는 것이다.
    • 따라서 외부에서 그 클래스에 대한 객체를 발생시킬 때에는 정적 중첩 클래스 객체 생성 방식을 따르게 된다.

interface T3{
	int x = 100;
	class B3{
		private int y;
		public B3(){
			this.y = 200;
		}
		public void disp(){
			System.out.println("x = " + x);//A.x
			System.out.println("y = " + y);//this.y
		}
	}
}
public class Round14_Ex03 {
	public static void main(String[]ar){
		T3.B3 bp = new T3.B3();
		bp.disp();
	}
}
  • int x 역시 public static final 이기 때문에 disp() 메서드에서 사용할 수 있는 것이다.
  • abstract와 인터페이스
    • 공통점
      • 1. 디자인의 개념으로 다형성을 표현하기에 아주 적당한 형태이다.
      • 2. 객체를 발생 시킬 수 없다.
      • 3. 추상 메서드를 포함하고 있고, 그 메서드를 오버라이딩을 해야만 하위 클래스의 객체가 발생한다.
      • 4. 표현의 방식에서 효율성을 고려하여 다형적인 표현을 주목적으로 한다.
    • 차이점

  • 만약 단지 하위클래스들을 통합 관리하기 위한 목적만 있고 상위 클래스로서 아무런 역할도 할 필요 없다면 abstract보다는 인터페이스가 더 효율적이다.

4. 다음 진행

  • 이지수
    • 8단원 예외처리
  • 24일은 그린팩토리(그으리인팩토으리) 견학으로 스터디를 쉬고 28일날 진행합니다.

5. 과제

  • 그 동안 배운 개념(상속, 다형성 등)을 활용해서 도서 관리 프로그램 만들기
  • 적어도 지정한 기능을 구현해서 프로그램이 동작하도록 하게 하면 된다.
  • 조건
    • 도서관리 클래스를 다형성을 통해서 코딩하기
    • 상속 이용할 것

   도서관리 프로그램_v1.0
========= 데이터 구조 =========
회원 - 이름
    - 생년월일
    - 전화번호
    - 대출내역

도서 - 제목
    - 저자
    - 출판사
    - 고유코드
    - 현재 비치수

========= 구현해 기능 =========
회원 - 등록
    - 수정
    - 도서 대출 가능 확인(대출제한 건수, 기한, 연속 대출)
    - 탈퇴
 
도서 - 대출
    - 반납
    - 책 상태 (대출가능 여부)
    - 책 정보 확인

5.1. 유재범

package hanjagonghomework;
import hanjagonghomework.Active.Book2;
import hanjagonghomework.Active.Member2;

import java.io.*;
interface Active{
	public class Member implements Active{
		public Member(){};
		int arrcount = 0;
		String name = "유재범";
		String birth = "1995년 12월 17일";
		String phnum = "01068267677";
		public String saveMemberData[][] = {{name, birth, phnum}};
		public int rentcount = 0;
	}
	
	public class Member2 extends Member implements Active{
		private static BufferedReader in;
		static{
			in = new BufferedReader(new InputStreamReader(System.in));
		}
		Member2(){};
		public void getname(String name) throws IOException{
			System.out.print("이름을 입력해 주십시오 : ");
			name = in.readLine();
			saveMemberData[arrcount][0] = name;
		}
		public void getbirth(String birth) throws IOException{
			int year = 0;
			int month = 0;
			int date = 0;
			boolean booly = false;
			do{
				booly = false;
				try{
					System.out.print("태어난 연도는? ");
					year = Integer.parseInt(in.readLine());
					
				}catch(NumberFormatException nfe){
					System.out.println("잘못된 연도입니다.");
					booly = true;
				}
			}while(booly);
			
			do{
				booly = false;
				try{
					System.out.print("태어난 달은? ");
					month = Integer.parseInt(in.readLine());
					
				}catch(NumberFormatException nfe){
					System.out.println("잘못된 달입니다.");
					booly = true;
				}
			}while(booly);
			
			do{
				booly = false;
				try{
					System.out.print("태어난 날짜는? ");
					date = Integer.parseInt(in.readLine());
					
				}catch(NumberFormatException nfe){
					System.out.println("잘못된 날짜입니다.");
					booly = true;
				}
			}while(booly);
			birth = year + "년 " + month + "월 " + date + "일";
			saveMemberData[arrcount][1] = birth;
		}
		
		public void getphnum(String phnum) throws IOException{
			System.out.print("전화번호를 입력해주세요 : ");
			phnum = in.readLine();
			saveMemberData[arrcount][2] = phnum;
		}
		
		public String setname(){
			return name;
		}
		
		public String setbirth(){
			return birth;
		}
		
		public String setphnum(){
			return phnum;
		}
		public void Addmem() throws IOException{
			Member2 admem = new Member2();
			arrcount++;
			admem.getname(name);
			admem.getbirth(birth);
			admem.getphnum(phnum);
		}
		public void Watchmem(){
			for(int pp=0; pp<arrcount; pp++){
				System.out.println("회원 이름 : " + saveMemberData[pp][0]);
				System.out.println("생년월일 : " + saveMemberData[pp][1]);
				System.out.println("핸드폰번호 : " + saveMemberData[pp][2]);
				System.out.println();
				System.out.println();
			}
		}
	}
	
	public class Book implements Active{
		String book = "푸른 지붕의 앤";
		String writer = "Lucy Maud Montgomery";
		String bocom = "NEXUS";
		public String [][] saveBookData = {{"푸른 지붕의 앤", "Lucy Maud Montgomery", "NEXUS", "", ""}};
		public int bookarrcount = 0;
		int  bocode = 1234;
		int bocount = 2;
		int rentcode = 0;
	}
	
	public class Book2 extends Book implements Active{
		private static BufferedReader in;
		static{
			in = new BufferedReader(new InputStreamReader(System.in));
		}
		Book2(){};
		int count=0;
		public void getbook(String book) throws IOException{
			System.out.print("책 이름을 등록해주세요 : ");
			book = in.readLine();
			saveBookData[bookarrcount][0] = book;
		}
		
		public void getwriter(String writer) throws IOException{
			System.out.print("저자를 등록해주세요 : ");
			writer = in.readLine();
			saveBookData[bookarrcount][1] = writer;
		}
		
		public void getbocom(String bocom) throws IOException{
			System.out.print("출판사를 등록해주세요 : ");
			bocom = in.readLine();
			saveBookData[bookarrcount][2] = bocom;
		}
		
		public String setbook(){
			return book;
		}
		
		public String setwriter(){
			return writer;
		}
		
		public String setbocom(){
			return bocom;
		}
		public int setbocode(){
			return (bocode+count);
		}
		public int setbocount(){
			return bocount;
		}
		public void bookRent(){
			if(bocount <= 0){
				System.out.println("책을 대여하실 수 없으십니다.");
			}
			else{
				bocount--;
				rentcode ++;
			}
		}
		public void bookReturn(){
			if(bocount >= 2){
				System.out.println("반납하실 책이 없읏비니다.");
			}
			else{
				rentcode --;
				bocount++;
			}
		}
		
		public void WatchBookInfo() throws IOException{
			Book2 watbok = new Book2();
			watbok.getwriter(writer);
			watbok.getbook(book);
			watbok.getbocom(bocom);
			count++;
		}
		public void setBookInfo(){
			System.out.println("책 제목 : " + book);
			System.out.println("저자 : " + writer);
			System.out.println("출판사 : " + bocom);
			System.out.println("고유 코드 : " + bocode+count);
			System.out.println("잔여 도서량 : " + bocount);
		}
	}
}

public class Library {
	public static void main(String[] args) throws IOException{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		Member2 memmenu = new Member2();
		Book2 bookmenu = new Book2();
		while(true){
			boolean boolmenu = false;
			int menunum = 0;
			System.out.print("무엇을 하시겠습니까?"
					+ "(1.회원증 생성     "
					+ "2.회원 정보 확인      "
					+ "3.책 정보 입력     "
					+ "4.책 정보 확인     "
					+ "5.책 대여     "
					+ "6.책 반납) : ");
			do{
				boolmenu = false;
			}while(boolmenu);
			try{
				menunum = Integer.parseInt(in.readLine());
				if(menunum > 6 || menunum <= 0){
					System.out.println("잘못된 숫자입니다.");
					boolmenu = true;
				}
			}catch(NumberFormatException nfe){
				System.out.println("잘못된 숫자입니다.");
				boolmenu = true;
			}
			
			if(menunum == 1){
				memmenu.Addmem();
				continue;
			}
			
			else if(menunum == 2){
				memmenu.Watchmem();
				continue;
			}

			else if(menunum == 3){
				bookmenu.WatchBookInfo();
				continue;
			}

			else if(menunum == 4){
				bookmenu.setBookInfo();
				continue;
			}

			else if(menunum == 5){
				bookmenu.bookRent();
				continue;
			}

			else if(menunum == 6){
				bookmenu.bookReturn();
				continue;
			}
		}
		
	}
}

  • 반복을 넣긴 했는데 책을 등록할 때, 회원 등록 할 때 그걸 저장해서 나중에 불러오고 싶었으나 어떻게 할 줄 몰라 실패
  • 회원 정보나 책 정보를 넣으면 들어가기는 하는데 나중에 뽑을 때 초기 값으로 나온다. 왜이러지?
  • 기타 필요 없거나 하나로 통일 될 수 있는 기능은 통일했습니다. 쓸데없이 여러가지 같은거 넣을 필요는 없을거 같았습니다.
  • 생각해보니 다형성 쓸 필요가 없었습니다.
  • 인터페이스를 main 클래스에서 받아서 쓰려니까 오류가 났는데 질문을 할 수도 없고 해서 그냥 import로 받았는데 이거 왜이러는지 아시는분 답변좀요.
  • 하면 재밌는데 하기 전에 진짜 죽어도 하기 싫어서 큰일 날뻔했습니다.
  • 다른 사람은 몰라도 김용준 과제 안하면 간식 사와라...

  • 고쳐왔는데 결국 저장이 되도 계속 날라가네... 이 이상을 다른 선배님들께 물어봐도 내 코드가 잘못됬다는데 누구 코드좀 봐줄 사람 없으신가?

5.2. 최다인

5.3. 이지수

5.4. 김용준

5.5. 김정민

6. 후기

  • 주말에 과제만 하면 되겠군... - 유재범
  • 금요일날 일찍 고향에 내려와야 되서 불참합니다. - 김용준
    • 이번주 목요일은 그린팩토리로 없을거고 다음주 월요일이 불참인건가? - 유재범
    • 아 금요일날 안하는구나. 착각함 ㅋㅋㅋㅋ - 김용준

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:31:31
Processing time 0.0447 sec