오늘 부터 상속을 공부하는데,
상속은 조금 나누어서 공부를 할 것이다.

완전한 이해가 필요하기 때문이다.

상속은 무엇일까?
-> 상속은 기존에 정의했던 클래스의 메소드, 변수들을 이어 받는 개념이다.

먼저 오늘은 상속의 문법, 사용법에 관해 공부했다.

상속
: 기존에 정의된 클래스에 메소드와 변수를 추가하여 새로운 클래스를 정의 하는 것.

표현으로는 상위 클래스, 하위 클래스가 있다.
* 상위클래스
: 기초 클래스라고도 한다. ( super class, base class )
: 원판이라고 생각하면 된다. 이제 이 클래스로 확장시켜 새로운 클래스를 만들 것이다.
: 상속할 대상의 클래스이다.

* 하위클래스
: 유도 클래스라고도 한다. ( sub class, derived class )
: 상속 받은 클래스이다. 상위 클래스의 메소드, 변수들을 이 하위클래스로 가져와 사용한다.

- 상위, 하위라고해서 헷갈린다면
  base class, derived class 라고 생각해도 된다.

사용법은
하위 클래스 선언시 상위 클래스를 언급해주면 된다.
예로 들면,
class sub extends super
{
...
}

이렇게 sub (하위클래스)를 선언할 때 extends super(상위클래스)를 적어주면된다.
여기서 sub, super는 클래스 이름이다.!!

그렇다면 상속을 할 때 초기화는 어떻게 될까?
초기화? 음 다시말하면 생성자는 어떻게 호출 될까?
-> 하위클래스의 생성자 속에 상위 클래스위 생성자를 부른다.
(그렇다고 생성자를 상속 받았다. 라는 의미는 아니다.)

부르는 방법은
super(전달 변수);
이렇게 전달한다.

예시로 문제를 적어보았다.
문제 14-1



(상속 예시)


문제를 풀고 작성한 코드인데,

여기서 Car -> HybridCar -> HybridWaterCar 이렇게 상속되었다.
보면 super() 를 통해 전달변수를 전달하여 각 상위클래스의 생성자를 호출하였다.



(실행 화면)


* 상위클래스의 생성자를 호출해야한다.
super를 이용해 상위클래스를 생성해야하는데 만약 super가 없다면
컴파일할때 자동으로 빈 super() 가 삽입된다.

* 상속과 접근제어 지시자
전에 접근제어 지시자 공부할 때 protected는 변수는 상속받은 클래스에서 까지 사용가능하다고 공부했었다. (다른 패키지에 존재할 지라도 상속관계에 놓이면 접근을 허용하는 접근제어 지시자 이다.)

* private 멤버는 간접적으로 접근해야한다.
-> 이 말의 뜻은 private 로 선언된 멤버는 직접 접근이 아니라 그 클래스의 호출을 통해 접근을 해야된다는 뜻이다. private으로 선언해 프로그램의 안전성을 높이는 것이 좋고 이 점을 생각하고 있어야한다.

(* 참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)



3단계로 업그레이드 과정이다.

필요 조건은
그 전 단계버전까지는 데이터가 관리 되지 않았다.
이번 단계의 핵심은 배열로 전화번호 데이터들을 관리하는 것이다.

이렇게 관리되는 데이터들을 이름으로 검색할 수 있고,
또 필요에 따라 삭제 할 수 있는 기능을 추가해야한다.

점점 쓸만한 프로그램이 되가는 느낌이 들어서 좋다. :)

먼저,
main 코드를 중심으로 필요한 메소드와 클래스를 생각해보았다.

아무래도 전화번호들을 관리하는데 인스턴스가 필요해 보였다. 왜냐하면 데이터를 입력받고 검색하고 삭제하고 기능들의 메소드를 메인 클래스에 꾸겨 넣자니 모양새가 안좋았다.

manager라는 인스턴스(객체)를 생성하여 이 놈이 관리하도록
관리자를 만들어야겠다는 생각이 들었다.
또 이 클래스 안에
입력, 검색, 메뉴출력, 삭제 등의 메소드들을 포함시킬 생각이다.

코드를 작성하고 컴파일 도중 에러를 만났다..!


(마주친 에러)


1. reached end of file while parsing 에러

-> 처음에 이게 어떤 오류인지 이해가 안갔다.
내용은 파싱(구문해석)하는 동안에 파일의 끝에 닿았다.
코드를 보니 아직 끝날때가 안됐는데 이미 파일의 끝에 가버렸다는 말이다.
이게 무슨말인지.. 했더니

보통 { }를 잘 안닫아서 생기는 오류였다.
하나하나 검사해보니 } 하나 빠져있었다... ㅜ

수정 후 다시 컴파일을 하였다.


(마주친 에러2)


2. non-static variable registPhone cannot be referenced from a static context 에러
이 에러로 고민을 많이했다..
이유가.. 도통 뭔지 모르겠어서..

내용을 읽어보면 static으로 선언되지 않은 변수는 참조할 수 없다고 설명되있다.
!! ..
전에 내용을 내가 잊고있었다..
다시 책을 뒤져보니..!!!!!
static 메소드에서는 인스턴스 변수에 접근하지 못한다..
static 메소드 내에서는 static 변수나 static 메소드가 아닌 인스턴스 변수나 인스턴스 메소드의 접근이 불가능하다...
이유는 인스턴스는 여러개 생성될 수 있지만 static으로 선언하면 하나를 같이 공유하는 개념이기 때문이다.



(문제 코드.!)


static 메소드가 인스턴스 변수인 registPhone에 접근하려 했다..
-> 내가 static을 쓴 이유는 메뉴를 보이고 데이터 입력 등 이런 메소드를 manager 인스턴스를 안만들고 바로 쓰고 싶어서 static으로 선언했는데,
사실 생각해보면 manager 인스턴스를 한번만 만들고 그 인스턴스로 사용하기 때문에 상관없는 거였다.

registPhonestatic을 선언할 것인가 static을 메소드에서 제거할 것인가 고민 후 static 선언을 지웠다.

그 후 출력



(만족스러운 화면)


아주~ 잘됬다.!! :)

3단계까지 업그레이드에 성공하였다 :)

작성 풀 코드

----------------------------------------------------------------------------------------------

// 단계별 프로젝트 03
// 전화번호 관리 프로그램

import java.util.Scanner;

class PhoneInfo
{
 String name;
 String phoneNum;
 String birth;

 public PhoneInfo(String name, String phoneNum, String birth)
 {
    this.name = name;
    this.phoneNum = phoneNum;
    this.birth = birth;
 }
 public PhoneInfo(String name, String phoneNum)
 {
    this(name, phoneNum, null);
 }

 public void showPhoneInfo()
 {
    System.out.println("name : " + name);
    System.out.println("phone : " + phoneNum);
    if(birth == null)
  System.out.println("birthday :");
    else
  System.out.println("birthday : " + birth);
 }
}

class PhoneManager
{
 final int MAX = 100;
 PhoneInfo[] registPhone = new PhoneInfo[MAX];
 int cnt = 0;
 public static Scanner keyboard = new Scanner(System.in);

 public static void showMenu()
 {
    System.out.println("\n");  // 공백 띄우기.
    System.out.println("메뉴를 선택하세요.");
    System.out.println("1. 전화번호추가하기");
    System.out.println("2. 검색하기.");
    System.out.println("3. 삭제하기.");
    System.out.println("4. 사용종료.");
 }
 
 public void inputData()
 {
    System.out.print("이름을 입력해주세요 :");   // 개행하지 않기위해 그냥 print 메소드를 사용함.
    String name = keyboard.nextLine();           // 입력을 엔터로 종료하기 위해.
    System.out.print("전화번호를 입력해주세요 :");
    String phoneNum = keyboard.nextLine();
    System.out.print("생년월일을 입력해주세요(모른다면 그냥 넘어가도 좋습니다.) : ");
    String birth = keyboard.nextLine();
 
    registPhone[cnt] = new PhoneInfo(name, phoneNum, birth);

    System.out.println("\n\n입력된 정보를 확인해 주세요.");
    registPhone[cnt].showPhoneInfo();
    cnt++;
 }
 
 public void searchData()
 {
    System.out.println("검색을 시작합니다.");

    System.out.print("이름 : ");
    String name = keyboard.nextLine();

    int indx = search(name);    // 검색 메소드 이용.
    if(indx < 0)
    {
       System.out.println("해당 이름의 자료가 없습니다.\n");
    }
    else
    {
       registPhone[indx].showPhoneInfo();
       System.out.println("검색하였습니다.\n");
    }
 }

 public void delData()
 {
    System.out.print("삭제하실 분의 이름을 입력해 주세요 : ");
    String name = keyboard.nextLine();

    int indx = search(name);
    if(indx <0)
    {
       System.out.println("해당 이름의 자료가 없습니다.\n");
    }
    else
    {
       for(int idx = indx; idx<(cnt-1); idx++)
  registPhone[idx] = registPhone[idx+1];

       cnt--;
    }
 }

 private int search(String name)
 {
    for(int idx=0; idx<cnt; idx++)
    {
  PhoneInfo pointInfo = registPhone[idx];
  if(name.compareTo(pointInfo.name) == 0)
     return idx;
    }
    return -1;   // 못찾았을 경우
 }
}
 
class PhoneManage3
{
    
 public static void main(String[] args)
 {
    int sel;     // 선택 변수
    PhoneManager manager = new PhoneManager();   //인스턴스 생성 (번호 데이터 관리)


    while(true)            // 사용자의 종료 입력전까지 반복.
    {
  manager.showMenu();
  sel = manager.keyboard.nextInt();
  manager.keyboard.nextLine();  // 남아있는 Enter입력 버리기.

  switch(sel)
  {
     case 1 :
        manager.inputData();
        break;
     case 2:
        manager.searchData();
        break;
     case 3:
        manager.delData();
        break;
     case 4 :
        System.out.println("시스템 종료");
        return;    // 반복문 나가기
  }
    }
 }
}

----------------------------------------------------------------------------------------------


(*참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)





오늘 2단계, 3단계의 전화번호 관리 프로그램을 업그레이드 시켰다. !!

:)

먼저
2단계 업그레이드 조건은
오늘 공부한 콘솔입력을 통해
사용자로부터 데이터를 입력받아 전화번호 관리 데이터들을 만드는 것이다.

먼저 main 메소드를 중심으로 내용들을 설계해 보았고
필요한 메소드가 무엇인지 체크하면서 시작했다.

흐름은
크게 while(true)으로 진행 할 것이다.
사용자가 종료하기 전까지 반복문으로 돌릴 생각이다.

while 안에서
1. 메뉴출력을 한다.
2. 선택을 입력 받는다.
3. 입력에 따라 모드를 바꾼다. (switch 이용)
-> 즉 switch이용할 것이므로  flag용으로 선택변수가 필요하다. 나는 int sel로 설정하였다.
    그러면 sel에 입력받을것이다.
필요 메소드
-> 메뉴 출력,  데이터 입력.

(전화번호 정보 클래스는 1단계에서 만든 것을 사용할 것이다.)

메뉴 출력 메소드는 println으로 작성했다.

데이터 입력 메소드는 각각의 정보입력에 따라 문자열을 생성하여 그 곳으로 집어 넣고
이 정보들로 전화번호 정보 클래스로 인스턴스를 만든다.


(작성코드.)


윗부분에는 전에 작성했던 전화번호 정보 클래스가 있다.

실행 결과



(결과)


여기에 조금 추가한것은..
왠지 생년월일 입력해주세요에 강요가 묻어나는 것 같았다.
몰라도 입력이 가능하게 만들어 놨으니
생년월일을 안써도 된다는 문구만 더 추가했다.


(추가 수정 코드)


(만족 스러운 2단계 업그레이드 버전)


모를때 그냥 엔터로 입력을 넘겨도 정보가 저장되는 것을 확인 할 수 있다.

2단계까지 업그레이드를 성공시켰다.

작성 풀 코드

---------------------------------------------------------------------------------------------

// 단계별 프로젝트 02
// 전화번호 관리 프로그램

import java.util.Scanner;

class PhoneInfo
{
 String name;
 String phoneNum;
 String birth;

 public PhoneInfo(String name, String phoneNum, String birth)
 {
    this.name = name;
    this.phoneNum = phoneNum;
    this.birth = birth;
 }
 public PhoneInfo(String name, String phoneNum)
 {
    this(name, phoneNum, null);
 }

 public void showPhoneInfo()
 {
    System.out.println("name : " + name);
    System.out.println("phone : " + phoneNum);
    if(birth == null)
  System.out.println("birthday :");
    else
  System.out.println("birthday : " + birth);
 }
}

class PhoneManage2
{
 static Scanner keyboard = new Scanner(System.in);

 public static void showMenu()
 {
    System.out.println("\n");  // 공백 띄우기.
    System.out.println("메뉴를 선택하세요.");
    System.out.println("1. 전화번호추가하기");
    System.out.println("2. 사용종료.");
 }

 public static void inputData()
 {
    System.out.print("이름을 입력해주세요 :");   // 개행하지 않기위해 그냥 print 메소드를 사용함.
    String name = keyboard.nextLine();           // 입력을 엔터로 종료하기 위해.
    System.out.print("전화번호를 입력해주세요 :");
    String phoneNum = keyboard.nextLine();
    System.out.print("생년월일을 입력해주세요(모른다면 그냥 넘어가도 좋습니다.) : ");
    String birth = keyboard.nextLine();
 
    PhoneInfo newInfo = new PhoneInfo(name, phoneNum, birth);
    System.out.println("\n\n입력된 정보를 확인해 주세요.");
    newInfo.showPhoneInfo();
 }
   
 public static void main(String[] args)
 {
    int sel;     // 선택 변수

    while(true)            // 사용자의 종료 입력전까지 반복.
    {
  showMenu();
  sel = keyboard.nextInt();
  keyboard.nextLine();  // 남아있는 Enter입력 버리기.

  switch(sel)
  {
     case 1 :
        inputData();
        break;
     case 2 :
        System.out.println("시스템 종료");
        return;    // 반복문 나가기
  }
    }
 }
}

-----------------------------------------------------------------------------------------------


(* 참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)



오늘 공부는 JAVA에서 입력과 출력이다.
오늘 공부로서
이제 프로그램 콘솔창에서 직접 입력을 넣을 수 있게 됬다.

먼저 콘솔 출력부터 살펴보면,
우리가 전까지 쓰던


System.out.println(" ");

으로 사용했는데 이 것과 .print 둘 다 가능하다.
println은 문자열을 출력하고 개행(다음행으로 넘어감)처리가 된다.
print는 문자열을 출력하고 개행되지 않는다.

+ 문자열 조합 출력

System.out.printf("%d", 12);

12가 출력되는 문장이다. 이 구성은 C와 같다. C에서의 printf의 기능과 같다.

콘솔의 입력!
입력은 자바에서 원래 복잡한 기능이었으나,
자바 버전 5.0 이후로 이에 대한 대안이 나왔다. :)

바로 Scanner 클래스를 이용한 것인데, 먼저 방법은

Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt();

위 코드는 사용자에게 입력을 받은 정수를 num1 에 저장하는 문장이다.
먼저 sc는 참조 변수이다. scanner 인스턴스를 만들어 입력을 받고
인스턴스의 nextInt 메소드를 이용하여 num1로 넘긴다.

Scanner의 주요 메소드들이다.
- public boolean nextBoolean()
- public byte nextByte()
- public short nextShort()
- public int nextInt()
-public long nextLong()
- public float nextFloat()
- public double nextDouble()
- public String nextLine()
-> nextLine()은 문자열의 끝을 enter입력을 통해서 종료를 표시한다.
나머지는 자료형의 입력에 따라 나누어진다.

(콘솔 입력 코드)


(결과화면)


위 결과를 보면 콘솔 입력이 구분되는 기준을 이해할 수 있다.
보면 처음에 1 엔터 2 엔터 3 입력하였을 때, 1, 2, 3 이 입력되었고
엔터도, 스페이스바도 치지 않았을 때 123 이 입력,
엔터후 2 입력했을 때 2, 스페이스바 후 3입력했을 때 3...

입력 콘솔에서 모든 공백이 데이터를 구분하는 기준이 된다.

그 다음으로서는 배열을 공부했다. 전에 학교 자료구조수업때 배열을 공부했었는데
내용은 그와 같다. C에서의 배열과 같다는 이야기다.
자바에서 배열의 특징은
배열도 인스턴스라는 것이다.
즉,!
배열을 생성할 때
다른 인스턴스를 생성하던 것처럼 new 를 포함해 생성해야된다는 점이다.
(하지만 꼭 new를 안써도 { } 중괄호를 이용해 생성할 수 도 잇다.)
선언은


int[] ref = new int[5];


이렇게 선언된 배열은 정수형 크기는 5인 배열을 선언한 것이다. 그렇게 되면 메모리 상에 정수형 크기 5인 배열의 공간이 확보된다. 그리고 ref에는 그 주소값이 들어가게 되는것이다. 즉 ref는 여기서 참조 변수이다.

문제 13-1
사용자로부터 입력 받은 수 중에 최대값과 최소값을 구하는 프로그램을 작성하세요.


------------------------------------------------------------------------------------------------

import java.util.Scanner;

class Problem131
{
 public static int[] insertData()
 {
    Scanner keyboard = new Scanner(System.in);
 
    int[] arr = new int[10];     // 들어올 변수 선언

    for(int i=0; i<arr.length; i++)
    {
  System.out.printf("정수를 입력해 주세요.(%d개)", arr.length-i);
  arr[i] = keyboard.nextInt();
    }
    return arr;
 }


 public static int minValue(int[] arr)
 {
    int min = arr[0];

    for(int i = 1; i<arr.length; i++)
    {
  if(min>arr[i])
     min = arr[i];
    }
    return min;
 }

 public static int maxValue(int[] arr)
 {
    int max = arr[0];

    for(int i =1; i<arr.length; i++)
    {
  if(max<arr[i])
     max = arr[i];
    }
    return max;
 }

 public static void main(String[] args)
 {
    int[] arr = new int[10];

    System.out.println("10개의 정수 중 최대,최소값 구하기 프로그램 시작");
    arr = insertData();
   
    System.out.println("최대값은 : " + maxValue(arr));
    System.out.println("최소값은 : " + minValue(arr));
 }
}

------------------------------------------------------------------------------------------------


작성한 코드이다.

클래스를 하나로 만들었고, main 메소드로 실행을 한다.
그리고 동작에 필요한 3개의 메소드들을 작성하였다.
(입력, 최대값구하기, 최소값구하기)

동작 확인

(문제13-1 결과)


배열은 10개로 지정했으므로 10개의 정수를 입력 받게 시작했다. 그리고 출력에서 몇개 남았는지 헷갈릴것 같아서 () 안에 몇개를 더 입력해야하는지 출력하였다.

최대 , 최소값 나온 것을 확인 할 수 있다. :)

for-each문
-> 자바 버전 5.0 이후부터 추가된것이다.

배열의 모든 값들에 대해 반복할 때 사용된다.
예를 들면 어떤 배열의 값들에 모두 1을 더한다든지 이런 데 사용된다.

예)


for(int e : arr)

        e++;


위와 같이 작성하면 모든 배열에 1을 더할 수 있다.

여기서 arr은 배열 이름이다. e는 모든 요소들을 지칭하는 변수로 나타내어진다.
(*그러나 이 구문이 끝나고 나면 변경 결과는 적용되지 않는다. 다시말하면 저 문장이 끝나고 다른 곳에서 저 배열을 확인하면 1이 증가되있지 않다.)

그러므로 배열의 내용을 바꾸지 못하지만  탐색같은 것을 할 때 더 유용하게 활용 될 수 있다.


(* 참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)







이번 단원부터
단계별 프로젝트를 시작했다.!!

:)

전화번호를 관리하는 프로그램을 만들건데,

먼저 지금까지 배운 내용으로
전화번호 정보들을 저장할 class를 설계할 것이고,

이 정보들을 출력할 수 있는 메소드도 만들 것이다.



(처음 설계한 전화번호정보 class)


처음 설계한 전화번호 정보 class이다.
설명을 하자면
PhoneInfo의 생성자는 오버로딩으로 작성하였다.
이유는 생년월일을 모를경우도 입력이 가능하도록. 이라는 조건이 있었기에
생년월일을 입력하지 않아도 출력되도록 코딩했다.

또 this 라는 것은 자기 본인의 생성자를 다시 호출하는 것이다. 여기서 this.name이라고 하면 자기 자신의 name을 뜻한다.
아래의 this도 같다.
다른 생성자의 this에서는
this(); 이런식으로 작성하였는데
바로 위의 생성자를 호출하여 마지막 생년월일부분은 모르니 0으로 입력하였다.

아래 main 메소드가 포함된 클래스는 다음과 같이 작성하였다.


class PhoneManage1
{
 public static void main(String[] args)
 {
    PhoneInfo data1 = new PhoneInfo("김똑똑", "323-4432", "95-10-18");
    PhoneInfo data2 = new PhoneInfo("김멍청", "323-2231");
 
    data1.showPhoneInfo();
    data2.showPhoneInfo();
 }
}  



그리고 실행했다.!!


(에러 화면..)


this() 구문에서 0이 잘못된것 같다.
아.!
문자열 String이니까 0 정수가 아니라 null?을 넣어야하나?


(null 로 변경)


null 로 바꾸고 실행했다.



(출력 화면)


오케이! 돌아갔다.!
근데.. 왜 전화번호는 null로 뜨는거지?...
(phoneNum에 오타가 있었고,, 처음 생성자에서 phoneNum도 this로 바꾸어 보았다.)
(사실 phoneNum은 this로 사용하지 않았던 이유는 오류가 날까봐 책의 다른 예제와 비슷하게 해보려고 했었던 것이다.


(수정한 사진.)


(결과 사진)


됬다.!
정상적으로 출력이 되었다. :)

마지막으로..
왠지..
생년월일의 null이 거슬렸다.
내용이 없으면 빈 공백으로 나오게 하고 싶어서 코드를 다시 조금 수정했다.


(null 없애기 코드)


(만족스러운 결과)


결과가 만족스럽게 나왔다.

지금까지 배운 것으로 단계별로 진행할 것인데,

오늘은 여기까지 만들어 보았다.

:)

(*참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)



오늘은 JAVA에서 클래스, 인스턴스 변수들을 안전하게 사용하기 위한 접근 제어를 공부했다.

정보은닉이란?
-> 외부에서 인스턴스의 변수에 직접적인 접근을 막는 것이다.

방법은 변수 앞에 private을 선언하는 것이다. 그렇게 되면 그 변수는 그 인스턴스 안의 메소드를 이용해서만 접근 할 수 있다.
* 프로그램의 안전성을 높이기 위해 인스턴스 변수는 가급적 private으로 선언하자.
 
이러한 정보은닉은 접근제어 지시자를 통해 이루어진다.
접근제어 지시자는 private, public, protected, default 가 있다.

private는 위에서 말한 것처럼 외부에서 건들지 못하게 하는 것이고
public은 아무데서나 사용할 수 있도록 한다. 그래서 메소드에는 public을 많이 쓴다.
default는 변수 앞에 아무것도 적지 않았을 때인데 동일 패키지 내에서의 접근까지 허용한다.
 
protected 개념은 상속 개념을 이해해야하는데,
상속받은 클래스안의 변수를 이어받을 수 있다. private으로 선언된 변수가 있는 클래스를 상속 받았다면 그 속에 있는 그 변수는 사용하지 못하는 것이다. 하지만 protected로 선언된 변수는 상속 받고 난 후도 사용할 수 있다. 물론 외부에서 접근은 허용하지 않는다.
 
그렇다면 class에는 public? default? private? 어떤걸 사용할까??

상식적으로 private를 사용해 class를 선언한다면 왜 선언하는 걸까? 외부에서 접근을 못하므로 외부에서 인스턴스 생성을 허용하지 않는다. 사용하지 못하는 class가 될 뿐이다. 즉 class에서 private는 사용하지 않는다.

public으로 선언하면 어디서든 인스턴스 생성이 가능하다. 하지만 조건이 있다.

1. 하나의 소스파일에는 하나의 클래스만 public으로 선언해야한다.
2. public 클래스의 이름과 소스파일의 이름은 완전히 일치해야 한다.

-> 보통 외부로 노출시키고 싶은 classpublic을 붙인다.(라이브러리생성시)
    
캡슐화
-> class로 감싸는 것을 의미한다. 이 캡슐화는 정답이란 것이 없고 필요한 상황에 맞게 class 안에 필요한 메소드나 변수들을 구성하는 것이다.
 
문제 9-2
원을 의미하는 클래스를 정의하고 Circle 클래스 좌표 정보와 반지름길이 정보를 저장할 수 있게 한다. Ring 클래스도 정의한다. Ring 클래스는 내부원 외부원으로 구성된다.
public static void main(String[] args)
{
Ring ring=new Ring(1, 1, 4, 2, 2, 9);
ring.showRingInfo();
}
main 메소드를 이용해 링의 정보를 출력한다.

먼저 각 클래스 Circle, 클래스 Ring을 설계하고 위 main 메소드에 맞추어 설계하였다.

작성한 코드는 아래와 같다.


---------------------------------------------------------------------------------------------

class Point
{
 int xPos, yPos;

 public Point(int x, int y)
 {
    xPos = x;
    yPos = y;
 }
 public void showPointInfo() { System.out.println("["+xPos+", "+yPos+"]");}
}

class Circle
{
 Point posit;
 int r;

 public Circle(int xi, int yi, int ri)
 {
    posit = new Point(xi, yi);
    r = ri;
 }

 public void showCircleInfo()
 {
    System.out.println("radius : " + r);
    posit.showPointInfo();
 }   
}

class Ring
{
 Circle inner;
 Circle outter;

 public Ring(int x1, int y1, int r1, int x2, int y2, int r2)
 {
    inner = new Circle(x1, y1, r1);
    outter = new Circle(x2, y2, r2);
 }

 public void showRingInfo()
 {
    System.out.println("Inner Circle Info...");
    inner.showCircleInfo();
    System.out.println("Outter Circle Info...");
    outter.showCircleInfo();
 }
}

class Problem92
{
 public static void main(String[] args)
 {
    Ring ring = new Ring(1, 1, 4, 2, 2, 9);
    ring.showRingInfo();
 }
}

---------------------------------------------------------------------------------------------


위 코드의 결과로


(결과 화면)


아래와 같이 나왔다.
외부 원과 내부 원의 정보를 화면에 출력하였다.

클래스 변수, 클래스 메소드

static 선언이란?
-> static으로 선언된 변수는 변수가 선언된 클래스의 모든 인스턴스가 공유하는 변수다.
, static은 딱 하나만 존재하는 변수다.
모두 여기에 접근을 해서 사용하는 것이다.
 
그렇다면 접근 방법은 어떻게 할까??
방법은 3가지가 있다.

1. 내부에서 접근 : 다른 변수와 똑같이 다룬다.
2. 참조변수를 통한 접근 : 참조변수.변수
3. 클래스 이름을 통한 접근 : 클래스이름.변수
 
static 변수는 언제 초기화 될까?
-> static변수는 인스턴스를 생성하기도 전에 이미 메모리에 올라가 있다. 자바 가상머신에 올라가면서 static 변수는 초기화된다.
* static변수가 초기화되는 시점은 JVM에 의해서 클래스가 메모리 공간에 올라가는 순간이다.
* “그래서 static변수를 생성자를 통해서 초기화하는 실수를 범하면 안된다."
 
static을 메소드에 적용하게 되면??
인스턴스를 생성하지 않아도 static 메소드를 호출 할 수 있다.
static은 클래스가 메모리에 올라가는 순간 시작 되므로
인스턴스를 생성하지 않아도 바로 쓸수 있다.
보통 쓴다면 외부에서 쓰기 때문에
public과 같이 쓴다.

메소드 오버로딩은 무엇일가?
메소드 오버로딩이란


class Example
{
       void isItOk(int n) {};
       void isItOk(int n, int m) {};
       void isItOk(int n, double m) {};
}

위와 같이 메소드 이름이 같게 사용하는 것이다.
결론은 메소드 이름이 같아도 괜찮다.
다만, 메소드 이름이 같더라도 매개변수는 달라야한다.
매개변수가 다르다면
메소드 오버로딩으로 이름이 같아도 괜찮다.

(*생성자도 오버로딩이 가능하다.)
오버로딩의 중요성은 여기에 있다.
생성자도 오버로딩이 가능하다는 것이다.

그렇게 되면 이
생성자의 오버로딩으로 선언된 하나의 클래스로 다양한 형태의 인스턴스 생성이 가능하다.

생성된 오버로딩의 중복되는 내용은 this 라는 키워드를 사용해 해결한다.
(이와 관련된 예시는 단계별 프로젝트에서 진행하였다.)

String 클래스
-> 문자열 클래스다.
다만 C언어와 다른점은 String 클래스의 문자열은 바꿀수 없다..
또 같은 문자열이라면 기존에 있던 문자열을 같이 사용한다.
다시말하면 문자열은 상수형이다 처음 입력되는 값이 유지된다고 생각하면 된다.

* "문자열이 동일한 경우에는 하나의 String 인스턴스만 생성해서 공유하도록 한다"

문자열을 조금 유연하게 다루고 싶다면
StringBuilder 혹은 StringBuffer 클래스를 이용하는 것이 좋다.

문자열을 복사하는 법 (자바에서)

String str1 = "Testing";
String str2 = new String(str1);

인스턴스를 새로 생성하여 만들면 된다.
(하지만 자바에서는 문자열을 직접 복사할 필요를 못 느낄만큼 다른 것들을 많이 지원해 주고 있다.)

(문자열에 관한 예시도 다음 단계별 프로젝트에서 같이 진행하겠다.)



(* 참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)





오늘 친구랑 걸으면서
(그 친구는 JAVA 학교에서 수업을 듣는다.)
JAVA이야기를 했는데 벌써 상속까지 나간것 같았다.
몇 주 안된거 같은데..!

음.. 독학하면 속도가 느려진다 그래서 더 많은 시간을 투자해야겠다.!!
오늘은 클래스 패스와 패키지까지 공부했다.
(클래스 개념하고 패키지 개념을 이해하느라 오래걸렸다..)

클래스 패스란?
-> 클래스의 경로를 의미한다.
cmd 명령창을 열고 실행하면 그 위치의 디렉토리에서 .class를 찾아서 실행한다.


(예시)


위 예시는 .class가 부족하다. AAA와 BBB class는 mysubclass파일에 옮겨 놓았다.
이 경우는 저 디렉토리에서 cmd를 열고 java ClassPath를 실행하면 어떻게 될까?


(오류 메세지)


해당 디렉토리에 필요한 class를 찾을 수 없다는 에러 메세지가 뜬다.

클래스 패스를 잘 설정해주어야 한다.

제어판 들어가서 환경변수 설정을 할 수도 있지만 위와 같이 cmd명령창으로 환경 변수를 설정해 줄 수 있다.
set classpath=.;.\mysubclass;
cmd 명령창에 위와 같이 입력해주면 된다.
. 은 현재 해당 디렉토리이고, ; 은 끊어주는 것이다.
.\mysubclass 에도 클래스 패스를 설정해 주었다.


(클래스 패스 설정화면 후 오류없이 결과가 나오는 화면)


위 화면을 보면 오류없이 결과가 나온 것을 확인 할 수 있다.

패키지는 서로 다른 클래스들을 관리하기 위해 만든다.
많은 개발자들이 함께 만드는 과정에서 같은 클래스 이름이 사용 될 수도 있다. 만약 패키지가 없다면
같이 만든 클래스들이 서로 충돌할 것이다.
이 때 이 클래스들을 잘 모아주는 것이 패키지이다.

이 패키지는 단순한 디렉터리를 나누는 것을 의미하지 않는다. 패키지는 디렉터리를 나누고 패키지 선언라는 것도 별도로 해야한다.

패키지를 사용할 때 클래스 패스
그 상위 폴더가 클래스 패스에 포함되어야 한다.
예로 들면,
AAA폴더 안에 BBB, CCC가 있고 BBB안에 Circle.class, CCC안에 Circle.class 있다.
이 때
BBB.Circle c1 = new BBB.Circle();
CCC.Circle c2 = new CCC.Circle();
위와 같이 선언 하게 되면 BBB와 CCC가 패키지 이름이된다. 그래서 BBB와 CCC는 패키지 이름으로 선언이 되있어야한다.
클래스 패스는 AAA디렉터리가 클래스 패스에 포함되야 한다.

다른 예로 위와 같은 폴더에
AAA.BBB.Circle c1 = new AAA.BBB.Circle();
AAA.CCC.Circle c2 = new AAA.CCC.Circle();
위와 같이 쓴다면 AAA.BBB와 AAA.CCC가 패키지 이름이다.
이 때 클래스 패스는 AAA의 상위 폴더가 클래스 패스에 포함되어야한다. 동시에 AAA.BBB와 AAA.CCC가 패키지 이름으로 선언되야한다.
패키지 선언은 바로 위의 경우
package AAA.BBB;
이렇게 선언하면 된다.

import 선언
-> 패키지로 묶여있는 클래스의 인스턴스 생성을 간편하게 하기 위하여 사용한다.
예로,
import orange.area.Circle; 과 같이 쓴다면
그 아래부터는 orange.area를 생략하고 Circle만 사용해도 된다.

패키지안에 여러 클래스가 있는데 그 클래스들을 전부 import하고 싶을 때는
import orange.area.* 로 선언하면 그 안에 있는 클래스들이 전부 import된다.

하지만 import로 쓰면 Circle만 써도 된다고 했는데 다른 클래스에 Circle이 있을 경우 충돌할 수 있게된다. 그러므로 그런 경우는 주의해서 사용해야한다.
클래스 마다 import하는 것이 가장 좋은 방법이다.

문제 8-1 2번문제
이 문제를 하면서 배치 파일을 직접 만들어 보았다.


javac -d . *.java

java FruitSalesPackageMain


위는 배치파일 내용이다.

(prob.bat 파일)


이 파일을 실행하면

(결과)


위와 같이 경로의 파일을 일일이 만들고 컴파일 하지 않아도 되는
-d . *.java 코드를 넣어서 각각의 폴더가 만들어 진 것을 확인 할 수 있다.
또 그 파일 안에 필요한 class 파일들이 들어가 있다.


(실행 결과)


위는 문제의 코드를 실행한 결과이다.

(참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)




오늘 공부한 내용은 클래스와 인스턴스다.
이전 C언어와 두드러진 특징 중 하나가 자바는 객체지향언어라는 점이다.

이 객체에 대한 개념을 이해하는 것이 중요하다.
* 객체지향 프로그래밍은 현실에 존재하는 사물과 대상, 그리고 그에 따른 행동을 있는 그대로 실체화시키는 형태의 프로그래밍이다.

객체를 생성하려면 class가 필요하다.
class를 먼저 설계하고 선언해두고,
이를 이용해 객체를 생성하는 것이다.

* 전에 javac 컴파일을 하면 class 이름으로 .java 파일이 만들어진다고 했었는데 그럼 클래스가 여러개이면 어떻게 될까? -> 클래스의 수만큼 .java 파일이 생성된다.

(class를 선언했다고 객체가 생성되는 것은 아니다.)
객체를 공부하다 보니 C와 비슷한 놈이 떠올랐다.
구조체다.
수업시간에 교수님이 C언어에서 구조체를 잘 사용하면 객체지향 프로그래밍을 할 수 있다고 얘기해 주신 것이 떠올랐다.
아..!!
:)

객체를 생성할 때
ex)
FruitSeller seller = new FruitSeller();
이런 식으로 생성하는데 맨 왼쪽의 FruitSeller는 자료형이다. 객체를 표현하는 자료형이다.
seller는 객체 변수이름이다.
new는 FruitSeller라는 객체를 생성하고 그 주소를 반환한다.
* 주소를 반환하기 때문에 seller라는 객체 변수에 주소값이 저장된다.
이 내용을 쉽게 받아들이기 위해서
메소드에서 객체를 호출하는 경우를 생각해보면 된다.
객체를 호출할 때 객체를 복사해서 전달 할까?
아니면 같은 객체를 공유하면서 사용할까?



(메소드에서 객체 호출)


(객체 호출 결과)


이 화면을 보면 알 수 있다. 객체는 같은 것을 사용하고 있다.
위에서 말했듯이 객체의 주소를 가지고 객체 이름변수에 저장했기 때문에,
객체 이름변수를 넘겨주면 그 주소를 넘겨주는 것이고 같은 객체에 접근하는 것이다.

생성자
-> 생성자는 메소드 호출 후 딱 한번만 실행되는 메소드이다.
목적은 인스턴스(객체) 변수의 초기화이다.

생성자를 이용하면 인스턴스 변수의 초기화를 쉽게 할 수 있다.

문제 7-1 2번 문제

(문제 class 설계)

-> Child라는 클래스를 만들고

생성자로 초기화

win 메소드, 추가로 작성하다보니 lose 메소드도 필요하여 추가하였다.

print 메소드 를 사용하였다.


(문제 해결 코드)


(결과 화면)


(참조 - 난 정말 JAVA를 공부한 적이 없다구요. , 윤성우)


오늘은 자바의 메소드를 공부했다.

드디어 C와는 구별되는 메소드이다.

흠, 그런데
공부하면서 보니 C언어의 함수 와 같았다.
쓰임도 같고, 모양새도 같고, 어디선가 익숙한 듯한 형식이다.

그래서 조금 더 쉽게 받아들일 수 있었다.
JAVA는 객체지향 언어로써 메소드를 잘 이용해야 자바를 쓰는 의미가 있다.
그러면 메소드를 잘 쓰는 연습을 시작해야겠다.

메소드

메소드 형식
public static void main(String[] args)
: 이 전까지 우리가 써왔던 메소드 선언이다.
void -> 반환할 값을 표시함. 정수형을 반환하면 int를 쓰면 된다.
main -> 메소드의 이름이다. (자바 프로그램의 시작은 main이라는 이름의 메소드를 실행하는 데서부터 시작한다.)
(String[] args) -> 전달받을 변수이다. 여기서 아직 String[] args 의 의미는 모르겠지만,
예로 (int a) 라고 받으면 받은 메소드 안에서 정수형 a 변수에 값을 입력받아 전달받는다.

아직 public, static, String[] args 의 의미는 잘 모르지만 뒷부분에서 더 배우기로 한다.

메소드 예시

코드


메소드 사용이다.  결과는

결과


+ 메소드에 둘 이상의 값을 전달할 수는 있어도, 메소드는 오직 하나의 값만을 반환할 수 있다.
 
+ 메소드 중간에 return 문을 만나면 나머지는 실행하지 않고 바로 메소드를 빠져나간다. (return; 만 쓸 경우)
 
+ 변수 scope -> 변수의 범위다. 변수는 { } 중괄호 안에서 선언됬다면 그 안에서만 사용가능하다.

메소드  문제
문제 6-1 1번
두 개의 정수를 전달받아서, 두 수의 사칙연산 결과를 출력하는 메소드와 이 메소드를 호출하는 main 메소드를 정의해보자. 단 나눗셈은 몫과 나머지를 각각 출력해야한다.



작성한 코드이다.  메소드의 반환을 이용하지 않고 그냥 void로 선언하여
그 메소드 안에서 계산 값들을 출력하였다.



재귀함수 -> recursive function
재귀 호출 메소드 -> recursive한 형태의 메소드를 의미한다.
메소드 안에서 자기 본인을 다시 호출하는 형태이다.
 
쉽게 이해하자면 , 팩토리얼을 예로 들수 있다.
5! = 5*4!
    
재귀 호출 문제
문제 6-3 1번
정수 N을 전달받아서, 2N승을 계산하여 반환하는 메소드를 재귀의 형태로 정의하고, 이의 테스트를 위한 main 메소드도 함께 정의하자.



재귀메소드를 이용하여 N승을 계산하였다.


2의 5승은 32입니다. 결과


메소드는 이전 C에서 해왔던
함수와 같은 기능을 하고 있었다.

(참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)

 

어제 집내려갔다가
오늘 올라왔는데, 바로 잘까하다가..
JAVA공부 조오금만 하고 정리하고 자야겠다라는 생각이 들어서
책을 펼쳤다. (의지..!)

chap 5 실행흐름의 컨트롤 부분이였는데,
C 언어와 상당히 비슷했다. (그만큼 빨리 넘어갈 수 있었다.)

조금 놓치고 있었던 부분에 대해 정리해 두려고 한다.

Switch 문.

 

위의 경우 n = 2일 때,
실행내용(2), 실행내용(3)이 실행된다.
n이 1이면
실행내용 1,2,3 전부 실행된다.

(엥?. ) n이 2면 2만 실행되는거 아닌가?..

C 언어에서 배울때 관습적으로 case : 실행내용 적고 break;를 추가했었다.
바로 이게 실행내용을 이어서 하지 못하게 끊어주었던 것이다.

 

이렇게 되면 n=1 일때, 실행내용 1만 실행되게 된다.

추가로
* break;     는 가장 가까운 반복문을 탈출하는 역할을 한다.
(가장 가까운 한개의! 반복문을  탈출하는 역할을 해준다.)

* continue;     는 break;  와 헷갈리지 않게 잘 이해해야한다.
break; 는 가장 가까운 반복문 하나를 벗어나게 한다. continue;는 continue를 만나면 그 아래 반복 실행코드를 무시하고 다시 반복문조건으로 돌아간다.
(+그러므로 반복문의 조건항에 반복문을 수렴하게하는 문장이 포함되야한다. ex) n++)

오늘 공부 중 실수
문제 : 1000이하의 자연수 중에서 2의 배수이면서 7의 배수인 숫자를 출력하고, 그 출력된 숫자들의 합을 구하는 프로그램을 while문을 이용해서 작성해보자.

문제 5-43번문제 풀다가

 

(첫 작성 코드)

 

(에러)

 

 

오류가 났다. 다시 코드를 확인해 보니,
비교문에서 ==을 써야하는데 =을 사용했다.
= 은 대입연산자이다..

 

(수정)

 

(실행)

 

물론 이런 실수는 오류 메세지로 코드를 다시 확인하면 쉽게 발견할 수 있는 오류지만
첫 작성시 주의할 필요가 있겠다.

 

+ Recent posts