반응형

출처 : 이것이 자바다

인터페이스

8.1 인터페이스의 역할

v  인터페이스란?

개발 코드와 객체가 서로 통신하는 접점

      개발 코드는 인터페이스의 메소드만 알고 있으면 OK

 

    • 인터페이스의 역할

      개발 코드가 객체에 종속되지 않게 -> 객체 교체할 수 있도록 하는 역할

      개발 코드 변경 없이 리턴값 또는 실행 내용이 다양해 질 수 있음 (다형성)

 

 

8.2 인터페이스 선언

    • 인터페이스 이름 - 자바 식별자 작성 규칙에 따라 작성
    • 소스 파일 생성

      인터페이스 이름과 대소문자가 동일한 소스 파일 생성

    • 인터페이스 선언

 

 

8.2.1인터페이스 선언

인터페이스의 구성 멤버

 

상수필드(Constant Field)

인터페이스는 객체 사용 설명서이므로 런타임 시 데이터를 저장할 수 있는 필드를 선언할 수 없다.

그러나 상수 필드는 선언이 가능하다.

상수는 인터페이스에 고정된 값으로 런타임 시에 데이터를 바꿀 수 없다.

상수를 선언할 때에는 반드시 초기값을 대입

 

추상 메소드(Abstract Method)

추상 메소드는 객체가 가지고 있는 메소드를 설명한 것

매개값이 필요하고, 리턴 타입이 무엇인지만 알려준다.

실제 실행부는 객체(구현 객체)가 가지고 있다.

 

디폴트 메소드(Default Method)

디폴트 메소드는 인터페이스에 선언되지만 사실은 객체가 가지고 있는 인스턴스 메소드라고 생각

디폴트 메소드를 허용하는 이유는 기존 인터페이스를 확장 새로운 기능 추가

 

정적 메소드(Static Method)

자바8부터 작성, 디폴트 메소드와 달리 객체가 없어도 인터페이스만으로 호출이 가능

 

8.2.2 상수 필드 선언

      인터페이스는  상수 필드만 선언 가능

 데이터 저장하지 않음

      인터페이스에 선언된 필드는 모두 public static final

자동적으로 컴파일 과정에서 붙음

      상수명은 대문자로 작성

서로 다른 단어로 구성되어 있을 경우에는 언더 바(_)로 연결

      선언과 동시에 초기값 지정

 static { } 블록 작성 불가 - static {} 으로 초기화 불가

상수 필드 선언

public interface RemoteControl {

           public int MAX_VOLUME = 10;

    public int MIN_VOLUME = 0;

}

 

8.2.3추상 메소드 선언

인터페이스 통해 호출된 메소드는 최종적으로 객체에서 실행

      인터페이스의 메소드는 기본적으로 실행 블록이 없는 추상 메소드로 선언

      public abstract를 생략하더라도 자동적으로 컴파일 과정에서 붙게 됨

 

추상메소드

(메소드 선언부)

(호출 방법만 기술)

재정의된 메소드

(실제 실행 메소드)

 
 
 

 

 

 

 

 

 

 

 

 

 

메소드 선언

public interface RemoteControl {

           public int MAX_VOLUME = 10;

    public int MIN_VOLUME = 0;

   

    //추상 메소드

    public void turnOn();                    //메소드 선언부만 작성 (추상 메소드)

    public void turnOff();           

    public void setVoulume(int volume);       

}

 

8.2.4디폴트 메소드 선언

      자바8에서 추가된 인터페이스의 새로운 멤버

 

      실행 블록을 가지고 있는 메소드

      default 키워드를 반드시 붙여야

      기본적으로 public 접근 제한

생략하더라도 컴파일 과정에서 자동 붙음

메소드 선언

public interface RemoteControl {

           public int MAX_VOLUME = 10;

    public int MIN_VOLUME = 0;

   

    //추상 메소드

    public void turnOn();                    //메소드 선언부만 작성 (추상 메소드)

    public void turnOff();           

    public void setVoulume(int volume);     

   

    //디폴트 메소드

    default void setMute(boolean mute) {        //실행 내용까지 작성

        if(mute) {

            System.out.println("무음 처리합니다.");

        } else {

            System.out.println("무음 해제합니다.");

        }

    }

}

 

8.2.5 정적 메소드 선언

      자바8에서 추가된 인터페이스의 새로운 멤버

 

 
 

 

 

 

 

 

 

 

 

 

메소드 선언

public interface RemoteControl {

           public int MAX_VOLUME = 10;

    public int MIN_VOLUME = 0;

   

    //추상 메소드

    public void turnOn();                    //메소드 선언부만 작성 (추상 메소드)

    public void turnOff();           

    public void setVoulume(int volume);     

   

    //디폴트 메소드

    default void setMute(boolean mute) {        //실행 내용까지 작성

        if(mute) {

            System.out.println("무음 처리합니다.");

        } else {

            System.out.println("무음 해제합니다.");

        }

    }

   

    //정적 메소드

    static void changeBattery() {

        System.out.println("건전지를 교환합니다.");

    }

}

 

8.3 인터페이스 구현

v  구현 객체와 구현 클래스

인터페이스의 추상 메소드 대한 실체 메소드를 가진 객체 = 구현 객체

 

구현 객체

 

 

 

 

 

 

 

 

 

    • 구현 객체를 생성하는 클래스 = 구현 클래스

 

8.3.1 구현 클래스 선언

    • 자신의 객체가 인터페이스 타입으로 사용할 수 있음

      implements 키워드로 명시

 

v  추상 메소드의 실체 메소드를 작성하는 방법

메소드의 선언부가 정확히 일치해야

인터페이스의 모든 추상 메소드를 재정의하는 실체 메소드 작성해야

      일부만 재정의할 경우, 추상 클래스로 선언 + abstract 키워드 붙임

 

구현 클래스

public class Television implements RemoteControl{

    //필드

    private int volume;

   

    @Override

    public void turnOn() {

        System.out.println("TV를 켭니다.");

    }

 

    @Override

    public void turnOff() {

        System.out.println("TV를 끕니다.");

    }

 

    @Override

    public void setVoulume(int volume) {                    //인터페이스 상수를 이용해서 volume 필드의 값을 제한

        if(volume>RemoteControl.MAX_VOLUME) {

            this.volume = RemoteControl.MAX_VOLUME;

        } else if(volume<RemoteControl.MIN_VOLUME) {

            this.volume = RemoteControl.MIN_VOLUME;

        } else {

            this.volume = volume;

        }

        System.out.println("현재 TV 볼륨: " + volume);

    }

 

}

 

구현 클래스

public class Audio implements RemoteControl{

    //필드

    private int volume;

   

    @Override

    public void turnOn() {

        System.out.println("Audio를 켭니다.");

    }

 

    @Override

    public void turnOff() {

        System.out.println("Audio를 끕니다.");

    }

 

    @Override

    public void setVoulume(int volume) {                    //인터페이스 상수를 이용해서 volume 필드의 값을 제한

        if(volume>RemoteControl.MAX_VOLUME) {

            this.volume = RemoteControl.MAX_VOLUME;

        } else if(volume<RemoteControl.MIN_VOLUME) {

            this.volume = RemoteControl.MIN_VOLUME;

        } else {

            this.volume = volume;

        }

        System.out.println("현재 Audio 볼륨: " + volume);

    }

 

}

 

인터페이스 변수에 구현 객체 타입

public class RemoteControlExample {

           public static void main(String[] args) {

                       RemoteControl rc;

                       rc = new Television();

                       rc = new Audio();

           }

}

 

8.3.2 익명 구현 객체

    • 명시적인 구현 클래스 작성 생략하고 바로 구현 객체를 얻는 방법

      이름 없는 구현 클래스 선언과 동시에 객체 생성

 

      인터페이스의 추상 메소드들을 모두 재정의하는 실체 메소드가 있어야

      추가적으로 필드와 메소드 선언 가능하나 익명 객체 안에서만 사용

      인터페이스 변수로 접근 불가

익명 구현 클래스

public class RemoteControlExample {

           public static void main(String[] args) {

                       //RemoteControl rc;

                       //rc = new Television();

                       //rc = new Audio();

                      

                       RemoteControl rc = new RemoteControl() {

                                 

                                  @Override

                                  public void turnOn() {

                                              // TODO Auto-generated method stub

                                             

                                  }

                                 

                                  @Override

                                  public void turnOff() {

                                              // TODO Auto-generated method stub

                                             

                                  }

                                 

                                  @Override

                                  public void setVoulume(int volume) {

                                              // TODO Auto-generated method stub

                                             

                                  }

                       };

           }

}

 

8.3.3다중 인터페이스 구현 클래스

 

 

 

인터페이스

public interface Searchable {

           void search(String url);

}

 

다중 인터페이스 구현 클래스

public class SmartTelevision implements RemoteControl,Searchable{

private int volume;

   

    @Override

    public void turnOn() {

        System.out.println("TV를 켭니다.");

    }

 

    @Override

    public void turnOff() {

        System.out.println("TV를 끕니다.");

    }

 

    @Override

    public void setVoulume(int volume) {                    //인터페이스 상수를 이용해서 volume 필드의 값을 제한

        if(volume>RemoteControl.MAX_VOLUME) {

            this.volume = RemoteControl.MAX_VOLUME;

        } else if(volume<RemoteControl.MIN_VOLUME) {

            this.volume = RemoteControl.MIN_VOLUME;

        } else {

            this.volume = volume;

        }

        System.out.println("현재 TV 볼륨: " + volume);

    }

   

    @Override

    public void search(String url) {

        System.out.println(url + "을 검색합니다.");

       

    }

}

 

8.4 인터페이스 사용

인터페이스에 구현 객체를 대입하는 방법

 

 

 

 

public class MyClass {

           //필드

           RemoteControl rc = new Television();

          

           //생성자

           MyClass(RemoteControl rc){

                       this.rc = rc;

           }

          

           //메소드

           void methodA() {

                       //로컬 변수

                       RemoteControl rc = new Audio();

           }

          

           void methodB(RemoteControl rc ) {}

}

 

8.4.1 추상 메소드 사용

 

 

인터페이스 사용

public class RemoteControlExample {

           public static void main(String[] args) {

          

           RemoteControl rc = null;             //인터 페이스 변수 선언

       

        rc = new Television();                //Television 객체를 인터페이스 타입에 대입

        rc.turnOn();

        rc.setMute(true);

       

        rc = new Audio();                    //Audio 객체를 인터페이스 타입에 대입

        rc.turnOn();                       

        rc.setMute(true);

           }

}

 

 

8.4.2 디폴트 메소드 사용

    • 인터페이스만으로는 사용 불가

      구현 객체가 인터페이스에 대입되어야 호출할 수 있는 인스턴스 메소드

    • 모든 구현 객체가 가지고 있는 기본 메소드로 사용

      필요에 따라 구현 클래스가 디폴트 메소드 재정의해 사용

 

구현 클래스

public class Audio implements RemoteControl{

           //필드

    private int volume;

    private boolean mute;

   

    //turnOn() 추상 메소드의 실체 메소드

    @Override

    public void turnOn() {

        System.out.println("Audio를 켭니다.");

    }

    //turnOff() 추상 메소드의 실체 메소드

    @Override

    public void turnOff() {

        System.out.println("Audio를 끕니다.");

    }

    //setVolume() 추상 메소드의 실체 메소드

    @Override

    public void setVoulume(int volume) {                    //인터페이스 상수를 이용해서 volume 필드의 값을 제한

        if(volume>RemoteControl.MAX_VOLUME) {

            this.volume = RemoteControl.MAX_VOLUME;

        } else if(volume<RemoteControl.MIN_VOLUME) {

            this.volume = RemoteControl.MIN_VOLUME;

        } else {

            this.volume = volume;

        }

        System.out.println("현재 Audio 볼륨: " + volume);

    }

   

    //디폴트 메소드 재정의

    @Override   

    public void setMute(boolean mute) {

        this.mute = mute;

        if(mute) {

            System.out.println("Audio 무음 처리합니다.");

        } else {

            System.out.println("Audio 무음 해제합니다.");

        }

    }

 

}

 

디폴트 메소드 사용

public class RemoteControlExample {

           public static void main(String[] args) {

        RemoteControl rc = null;             //인터 페이스 변수 선언

       

        rc = new Television();                //Television 객체를 인터페이스 타입에 대입

        rc.turnOn();

        rc.setMute(true);

       

        rc = new Audio();                    //Audio 객체를 인터페이스 타입에 대입

        rc.turnOn();                       

        rc.setMute(true);

           }

}

 

8.4.3 정적 메소드 사용

인터페이스로 바로 호출 가능

정적 메소드 사용

public class RemoteControlExample {

           public static void main(String[] args) {

        RemoteControl.changeBattery();

           }

}

 

8.5 타입 변환과 다형성

v  다형성 (p.362~364)

하나의 타입에 여러 가지 객체 대입해 다양한 실행 결과를 얻는 것

다형성을 구현하는 기술

      상속 또는 인터페이스의 자동 타입 변환(Promotion)

      오버라이딩(Overriding)

다형성의 효과

      다양한 실행 결과를 얻을 수 있음

      객체를 부품화시킬 수 있어 유지보수 용이 (메소드의 매개변수로 사용)

 

8.5.1 자동 타입 변환(Promotion)

 

 

 

8.5.2 필드의 다형성

 

 

 

인터페이스

public interface Tire {

           public void roll();    //roll() 메소드 호출 방법 설명

}

구현 클래스

public class HankookTire implements Tire{

    @Override

    public void roll() {

        System.out.println("한국 타이어가 굴러갑니다.");

       

    }

}

 

구현 클래스

public class KumhoTire implements Tire{

 

    @Override

    public void roll() {

        System.out.println("금호 타이어가 굴러갑니다.");

    }

 

}

 

필드 다형성

public class Car {//인터페이스 타입 필드 선언과 초기 구현 객체 대입

    Tire frontLeftTire = new HankookTire();

    Tire frontRightTire = new HankookTire();

    Tire backLeftTire = new HankookTire();

    Tire backRightTire = new HankookTire();

   

    void run() {    //인터페이스에서 설명된 roll() 메소드 호출

        frontLeftTire.roll();

        frontRightTire.roll();

        backLeftTire.roll();

        backRightTire.roll();

    }

 

}

 

필드 다형성 테스트

public class CarExample {

    public static void main(String[] args) {

        Car myCar = new Car();

       

        myCar.run();

       

        myCar.frontLeftTire = new KumhoTire();

        myCar.frontRightTire = new KumhoTire();

       

        myCar.run();

    }

}

 

8.5.3 인터페이스 배열로 구현한 객체 관리

 

 

 

 

 

 

 

 

 

 

필드 다형성

package textbook.chapter8.exam01;

 

public class Car {

           Tire[] tires = {

                   new HankookTire(),

                   new HankookTire(),

                   new HankookTire(),

                   new HankookTire()       

               };

              

            void run() {

                 for (Tire tire : tires) {

                     tire.roll();

                 }

            }

}

 

필드 사형성 테스트

package textbook.chapter8.exam01;

 

public class CarExample {

           public static void main(String[] args) {

                       Car myCar = new Car();

 

                       myCar.run();

 

                       myCar.tires[0] = new KumhoTire();

                       myCar.tires[1] = new KumhoTire();

 

                       myCar.run();

           }

}

 

8.5.4매개변수의 다형성

    • 매개 변수의 타입이 인터페이스인 경우

      어떠한 구현 객체도 매개값으로 사용 가능

      구현 객체에 따라 메소드 실행결과 달라짐

자동 타입 변환은 필드의 값을 대입할 때도 발생하지만, 주로 메소드를 호출할 때 많이 발생한다.

 

매개 변수의 인터페이스화

public class Driver {

           public void drive(Vehicle vehicle) {

                       vehicle.run();

           }

}

 

인터페이스

public interface Vehicle {

           public void run();//interface는 메소드만 작성한다.

}

 

Vehicleinterface이다.

 

구현 클래스

public class Bus implements Vehicle{

 

           @Override

           public void run() {

                       System.out.println("버스가 달립니다.");

           }

          

}

 

구현 클래스

public class Taxi implements Vehicle {

 

           @Override

           public void run() {

                       System.out.println("택시가 달립니다.");

           }

 

}

 

매개 변수의 다형성 테스트

public class DriverExample {

           public static void main(String[] args) {

                       Driver driver = new Driver();

                      

                       Bus bus = new Bus();

                       Taxi taxi = new Taxi();

                      

                       driver.drive(bus); //자동 타입 변환 Vehicle vehicle =bus;

                       driver.drive(taxi);//자동 타입 변환 Vehicle vehicle =taxi;

           }

}

 

8.5.5 강제 타입 변환(Casting)

인터페이스 타입으로 자동 타입 변환 후, 구현 클래스 타입으로 변환

      필요성: 구현 클래스 타입에 선언된 다른 멤버 사용하기 위해

 

구현클래스 변수 = (구현클래스)인터페이스변수;

인터페이스

public interface Vehicle {

           public void run();//interface는 메소드만 작성한다.

}

 

구현 클래스

public class Bus implements Vehicle{

 

           @Override

           public void run() {

                       System.out.println("버스가 달립니다.");

           }

          

           public void checkFare() {

                       System.out.println("승차요금을 체크합니다.");

           }

}

 

강제 타입 변환

public class DriverExample {

           public static void main(String[] args) {

                       Vehicle vehicle = new Bus();

                       vehicle.run();

                       //vehicle.checkFare(); //vehicle interface에는 checkFare이 없습니다.

                      

                       Bus bus = (Bus)vehicle;//강제 타입 변환

                       bus.run();

                       bus.checkFare();

                      

           }

}

 

8.5.6 객체 타입 확인(instanceof 연산자) (p.375~377)

강제 타입 변환 전 구현 클래스 타입 조사

 

객체 타입 확인

public class Driver {

           public void drive(Vehicle vehicle) {

                       if(vehicle instanceof Bus) {

                                  Bus bus=(Bus)vehicle;

                                  bus.checkFare();//Bus타입으로 강제 타입 변환을 하는 이유

                       }

                       vehicle.run();

           }

}

 

타입인지 확인 하는 것은 instanceof이다. 이것으로 확인하고 처리하는게 좋다.

 

8.6 인터페이스 상속

v  인터페이스간 상속 가능

 

    • 하위 인터페이스 구현 클래스는 아래 추상 메소드를 모두 재정의해야

      하위 인터페이스의 추상 메소드

      상위 인터페이스1의 추상 메소드

      상위 인터페이스2의 추상 메소드

 

    • 인터페이스 자동 타입 변환

      해당 타입의 인터페이스에 선언된 메소드만 호출 가능

 

 

부모 인터페이스

public interface InterfaceA {

           public void methodA();

}

 

부모 인터페이스

public interface InterfaceB {

           public void methodB();

}

 

하위 인터페이스

public interface InterfaceC extends InterfaceA,InterfaceB{

    public void methodC();

}

 

하위 인터페이스 구현

public class ImplementationC implements InterfaceC{

 

    @Override

    public void methodA() {

        System.out.println("methodA() 실행");

    }

 

    @Override

    public void methodB() {

        System.out.println("methodB() 실행");

    }

 

    @Override

    public void methodC() {

        System.out.println("methodC() 실행");

    }

 

}

 

호출 가능 메소드

public class Example {

           public static void main(String[] args) {

        ImplementationC impl = new ImplementationC();

       

        InterfaceA ia = impl;

        ia.methodA();

        System.out.println();        //InterfaceA 변수는 methodA()만 호출 가능

       

        InterfaceB ib = impl;

        ib.methodB();

        System.out.println();         //InterfaceB 변수는 methodB()만 호출 가능

       

        InterfaceC ic = impl;

        ic.methodA();

        ic.methodB();        //InterfaceC 변수는 methodA(),methodB(),methodC() 모두 호출 가능

        ic.methodC();

    }

}

 

 

8.7 디폴트 메소드와 인터페이스 확장

8.7.1 디폴트 메소드의 필요성

v  디폴트 메소드와 확장 메소드 사용하기 (p.379~382)

 

 

interface에 새로운 기능을 추가할 경우 원래의 구현한 메소드에서 오류가 난다. 그래서 이것을 해결하기 위하여 새로운 interface에 디폴트 메소드를 추가한다.

 

기존 인터페이스

public interface MyInterface {

           public void method1();

          

           public default void method2() {

        System.out.println("MyInterface-method2 실행");    //디폴트 메소드

    }

}

 

기존 구현 클래스

public class MyClassA implements MyInterface{

 

    @Override

    public void method1() {

        System.out.println("MyCalssA-method1() 실행");

    }

 

}

 

새로운 구현 클래스

public class MyClassB implements MyInterface{

 

    @Override

    public void method1() {

        System.out.println("MyCalssA-method1() 실행");

    }

    @Override

    public void method2() {

        System.out.println("MyClassB-method2() 실행");        //디폴트 메소드 재정의

    }

 

}

 

디폴트 메소드 사용

public class DefaultMethodExampl {

           public static void main(String[] args) {

                       MyInterface mi1 = new MyClassA();

                       mi1.method1();

                       mi1.method2();

 

                       MyInterface mi2 = new MyClassB();

                       mi2.method1();

                       mi2.method2();

           }

}

 

8.7.2 디폴트 메소드가 있는 인터페이스 상속

    • 부모 인터페이스의 디폴트 메소드를 자식 인터페이스에서 활용 방법

      디폴트 메소드를 단순히 상속만 받음

      디폴트 메소드를 재정의(Override)해서 실행 내용을 변경

      디폴트 메소드를 추상 메소드로 재선언

 

부모 인터페이스

public interface ParentInterface {

           public void method1();

           public default void method2() {/*실행문*/}

}

 

 

자식 인터페이스

public interface ChildInterface1  extends ParentInterface{

           public void method3();

}

 

자식 인터페이스

public interface ChildInterface2  extends ParentInterface{

           @Override

           public default void method2() {/*실행문*/};//재정의

          

           public void method3();

}

 

자식 인터페이스

public interface ChildInterface3  extends ParentInterface{

           @Override

           public void method2();//추상 메소드로 재선언

          

           public void method3();

}

 

사용법

public class ChildExample {

           public static void main(String[] args) {

                       ChildInterface1 ci1 = new ChildInterface1(){

                                  @Override

                                  public void method1() {/*실행문*/}

 

                                  @Override

                                  public void method3() {/*실행문*/}

                                 

                       };

                      

                       ci1.method1();

                       ci1.method2();//ParentInterface method2()호출

                       ci1.method3();

                      

                       ChildInterface2 ci2 = new ChildInterface2(){

                                  @Override

                                  public void method1() {/*실행문*/}//재정의

 

                                  @Override

                                  public void method3() {/*실행문*/}

                                 

                       };

                      

                       ci2.method1();

                       ci2.method2();//ChildInterface2 method2()호출

                       ci2.method3();

                      

                       ChildInterface3 ci3 = new ChildInterface3(){

                                  @Override

                                  public void method1() {/*실행문*/}

                                 

                                  @Override

                                  public void method2() {/*실행문*/}

 

                                  @Override

                                  public void method3() {/*실행문*/}

                                 

                       };

                      

                       ci3.method1();

                       ci3.method2();//ChildInterface3의 구현 객체의 method2()호출

                       ci3.method3();

           }

}

 

 

 

 

 

연습문제

1. 인터페이스에 대한 설명으로 틀린 것은 무엇입니까? (3)

 

1. 인터페이스는 객체 사용 설명서 역할을 한다.

2. 구현 클래스가 인터페이스의 추상 메소드에 대한 실체 메소드를 가지고 있지 않으면 추상 클래스가 된다.

3. 인터페이스는 인스턴스 필드를 가질 수 있다.

4. 구현 객체는 인터페이스 타입으로 자동 변환된다.

 

2. 인터페이스의 다형성과 거리가 먼 것은? (4)

 

1. 필드가 인터페이스 타입일 경우 다양한 구현 객체를 대입할 수 있다.

2. 매개 변수가 인터페이스 타입일 경우 다양한 구현 객체를 대입할 수 있다.

3. 배열이 인터페이스 타입일 경우 다양한 구현 객체를 저장할 수 있다.

4. 구현 객체를 인터페이스 타입으로 변환하려면 강제 타입 변환을 해야 한다.

 

3. 다음은 Soundable 인터페이스입니다. sound() 추상 메소드는 객체의 소리를 리턴합니다.

 

package sec7;

 

public interface Soundable {

    String sound();

}

 

package sec7;

 

public class SoundableExample {

    private static void printSound(Soundable soundable) {

        System.out.println(soundable.sound());

    }

    public static void main(String[] args) {

        printSound(new Cat());

        printSound(new Dog());

    }

}

 

package sec7;

 

public class Cat implements Soundable{

 

    @Override

    public String sound() {

        return "야옹";

    }

    

}

 

package sec7;

 

public class Dog implements Soundable{

 

    @Override

    public String sound() {

        return "멍멍";

    }

    

}

야옹

멍멍

 

4. DaoExample 클래스의 main() 메소드에서 dbWork() 메소드를 호출할 때 OracleDao MySqlDao 객체를 매개값으로 주고 호출했습니다. dbWork() 메소드는 두 객체를 모두 매개값으로 받기 위해 DateAccessObject 타입의 매개 변수를 가지고 있습니다. 실행 결과를 보고 DataAccessObject 인터페이스와 OracleDao, MySqlDao 구현 클래스를 각각 작성해보세요.

 

package sec7;

 

public class DaoExample {

    

    public static void dbWork(DataAccessObject dao) {

        dao.select();

        dao.insert();

        dao.update();

        dao.delete();

    }

    

    public static void main(String[] args) {

        dbWork(new OracleDao());

        dbWork(new MySqlDao());

    }

 

}

 

package sec7;

 

public interface DataAccessObject {

 

    public void select();

    public void insert();

    public void update();

    public void delete();

    

}

 

 

package sec7;
 
public class MySqlDao implements DataAccessObject {
 
    @Override
    public void select() {
        System.out.println("MySql DB에서 검색");
    }
 
    @Override
    public void insert() {
        System.out.println("MySql DB에서 삽입");
    }
 
    @Override
    public void update() {
        System.out.println("MySql DB에서 수정");
    }
 
    @Override
    public void delete() {
        System.out.println("MySql DB에서 삭제");
    }
}

Oracle DB에서 검색

Oracle DB에서 삽입

Oracle DB에서 수정

Oracle DB에서 삭제

MySql DB에서 검색

MySql DB에서 삽입

MySql DB에서 수정

MySql DB에서 삭제

 

5. 다음은 Action 인터페이스입니다. work() 추상 메소드는 객체의 작업을 시작시킵니다.



ActionExample 클래스의 main() 메소드에서 Action의 익명 구현 객체를 만들어 다음과 같은 실행 결과가 나올 수 있도록 박스 안에 들어갈 코드를 작성해보세요.

 

package sec8;

 

public class ActionExample {

 

    public static void main(String[] args) {

        Action action = new Action() {

            

            @Override

            public void work() {

                System.out.println("복사를 합니다.");

            }

        };

        action.work();

    }

 

}​
package sec8;

 

public interface Action {

    void work();

}

복사를 합니다.

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

10. 예외처리  (0) 2020.10.01
09. 중첩 클래스와 중첩 인터페이스  (0) 2020.10.01
07. 상속  (0) 2020.09.29
06. 클래스  (0) 2020.09.28
05. 참조 타입  (0) 2020.09.27
반응형

출처 : 이것이 자바다
상속
7.1 상속 개념
 상속(Inheritance)이란?
현실 세계:
• 부모가 자식에게 물려주는 행위
• 부모가 자식을 선택해서 물려줌
객체 지향 프로그램:
• 자식(하위, 파생) 클래스가 부모(상위) 클래스의 멤버를 물려받는 것
• 자식이 부모를 선택해 물려받음
• 상속 대상: 부모의 필드와 메소드

 상속(Inheritance) 개념의 활용
상속의 효과
• 부모 클래스 재사용해 자식 클래스 빨리 개발 가능
• 반복된 코드 중복 줄임
• 유지 보수 편리성 제공
• 객체 다형성 구현 가능
상속 대상 제한
• 부모 클래스의 private 접근 갖는 필드와 메소드 제외
• 부모 클래스가 다른 패키지에 있을 경우, default 접근 갖는 필드와 메소드도 제외
 extends 키워드
자식 클래스가 상속할 부모 클래스를 지정하는 키워드

//A로 부터 물려받은 필드와 메소드
B b = new B();
b.field1 = 10;
b.method1();

//B가 추가한 필드와 메소드
b.filed2 = "홍길동";
b.method2();

7.2 클래스 상속
현실에서 상속은 부모가 자식을 선택해서 물려주지만, 프로그램에서는 자식이 부모를 선택한다.
class 자식 클래스 extends 부모글래스{
//필드
//생성자
//메소드
}

class SportCar extends Car{
}

 자바는 단일 상속 - 부모 클래스 나열 불가

[CellPhone.java] 부모 클래스

public class CellPhone {
	//필드
    String model;
    String color;
    
    //생성자
    
    //메소드
    void powerOn() {System.out.println("전원을 켭니다.");}
    void powerOff() {System.out.println("전원을 끕니다.");}
    void bell() {System.out.println("벨이 울립니다.");}
    void sendVoice(String message) {System.out.println("자기: " + message);}
    void receiveVoice(String message) {System.out.println("상대방: " + message);}
    void hangUp() {System.out.println("전원을 끊습니다.");}
}

 

[DmbCellPhone.java] 자식 클래스

public class DmbCellPhone extends CellPhone {
	//필드
    int channel;
    
    //생성자
    DmbCellPhone(String model,String color,int channel) {
        this.model = model;     //CellPhone 으로부터 상속받은 필드
        this.color = color;        //CellPhone 으로부터 상속받은 필드
        this.channel = channel;
    }
    
    //메소드
    void turnOnDmb() {
        System.out.println("채널 " + channel + "번 DMB 방송 수신을 시작합니다.");
    }
    
    void changeChannelDmb(int channel) {
        this.channel = channel;
        System.out.println("채널 " + channel + "번으로 바꿉니다.");
    }
    
    void turnOffDmb() {
        System.out.println("DMB 방송 수신을 멈춥니다.");
    }
}

 

[DmbCellPhoneExample.java] 자식 클래스 사용

public class DmbCellPhoneExample {
	public static void main(String[] args) {
		// DmbCellPhone 객체 생성
		DmbCellPhone dmbCellPhone = new DmbCellPhone("자바폰", "검정", 10);

		// CellPhone 으로부터 상속받은 필드
		System.out.println("모델: " + dmbCellPhone.model);
		System.out.println("색상: " + dmbCellPhone.color);

		// DmbCellPhone의 필드
		System.out.println("채널: " + dmbCellPhone.channel);

		// CellPhone으로부터 상속받은 메소드 호출
		dmbCellPhone.powerOn();
		dmbCellPhone.bell();
		dmbCellPhone.sendVoice("여보세요");
		dmbCellPhone.receiveVoice("안녕하세요! 저는 홍길동인데요");
		dmbCellPhone.sendVoice("아~ 예 반갑습니다.");
		dmbCellPhone.hangUp();

		// DmbCellPhone의 메소드 호출
		dmbCellPhone.turnOnDmb();
		dmbCellPhone.changeChannelDmb(12);
		dmbCellPhone.turnOffDmb();
	}
}

7.3 부모 생성자 호출
 자식 객체 생성하면 부모 객체도 생성되는가?
부모 없는 자식 없음
• 자식 객체 생성할 때는 부모 객체부터 생성 후 자식 객체 생성
• 부모 생성자 호출 완료 후 자식 생성자 호출 완료

 명시적인 부모 생성자 호출
부모 객체 생성할 때, 부모 생성자 선택해 호출

• super(매개값,…)
매개값과 동일한 타입, 개수, 순서 맞는 부모 생성자 호출
• 부모 생성자 없다면 컴파일 오류 발생
• 반드시 자식 생성자의 첫 줄에 위치
• 부모 클래스에 기본(매개변수 없는) 생성자가 없다면 필수 작성

[People.java] 부모 클래스

public class People {
	public String name;
	public String ssn;
	
	public People(String name,String ssn) {
		this.name = name;
		this.ssn = ssn;
	}
}

 

[Student.java] 자식 클래스

public class Student extends People {
	public int studentNo;
	
	public Student(String name, String ssn,int studentNo ) {
		super(name, ssn);//부모 생성자 호출
		this.studentNo = studentNo;
	}
}

 

[StudentExample.java] 자식 객체 이용

public class StudentExample {
	public static void main(String[] args) {
		Student student = new Student("홍길동", "12345-1234567", 1);
		//부모에서 물려받은 필드 출력
		System.out.println("name :" + student.name);
		System.out.println("ssn :" + student.ssn);
		System.out.println("studentNo :" + student.studentNo);
	}
}

7.4 메소드 재정의
 메소드 재정의(@Override)
부모 클래스의 상속 메소드 수정해 자식 클래스에서 재정의하는 것
메소드 재정의 조건 (p.295~296)
• 부모 클래스의 메소드와 동일한 시그니처 가져야
• 접근 제한을 더 강하게 오버라이딩 불가
public을 default나 private으로 수정 불가
반대로 default는 public 으로 수정 가능
• 새로운 예외(Exception) throws 불가 (예외처리는 10장 참조)
부모 클래스의 모든 메소드가 자식 클래스에게 맞게 설계되어 있다면 가장 이상적인 상속이지만,
어떤 메소드는 자식 클래스가 사용하기에 적합하지 않을 수도 있다.
이 경우 상속된 일부 메소드는 자식 클래스에서 다시 수정해서 사용해야 한다.
자바는 이런 경우를 위해 메소드 오버라이딩(Overriding) 기능을 제공한다.

 

7.4.1 메소드 재정의(Override)
메소드 오버라이딩은 상속된 메소드의 내용이 자식 클래스에 맞지 않을 경우, 자식 클래스에서 동일한 메소드를 재정의하는 것을 말한다.

메소드가 오버라이딩되었다면 부모 객체의 메소드는 숨겨지기 때문에, 자식 객체에서 메소드를 호출하면 오버라이딩된 자식 메소드가 호출된다.

메소드 오버라이딩 규칙

  • 부모의 메소드와 동일한 시그니처(리턴타입,메소드 이름,매개 변수 리스트)를 가져야 한다.
  • 접근 제한을 더 강하게 오버라이딩할 수 없다.
  • 새로운 예외(Exception) 를 throws 할 수 없다(예외는 10장에서 학습한다).
    [Calculator.java] 부모 클래스

public class Calculator {
	double areaCircle(double r) {
		System.out.println("Calculator 객체의 areaCircle() 실행");
		return 3.14159 * r * r;
	}
}

[Computer.java] 자식 클래스

public class Computer extends Calculator {
	@Override
	double areaCircle(double r) {
		System.out.println("Computer 객체의 areaCircle() 실행");
		return Math.PI * r * r;
	}
}

[ComputerExample.java] 메소드 오버라이딩 클래스

public class ComputerExample {
	public static void main(String[] args) {
		int r = 10;
		Calculator calculator = new Calculator();
		System.out.println("원면적 : " + calculator.areaCircle(r));

		System.out.println();

		Computer computer = new Computer();
		System.out.println("원면적 : " + computer.areaCircle(r)); // 재정의된 메소드 호출
	}
}

  1. 자식 클래스에서 오버라이딩 메소드를 작성할 위치로 입력 커서를 옮긴다
  2. 메뉴에서 [Source Override/Implement Methods...]를 선택한다.
  3. 부모 클래스에서 오버라이딩될 메소드를 선택하고 [OK] 버튼을 클릭한다.

7.4.2 부모 클래스 호출(super)
 부모 메소드 사용(super)
메소드 재정의는 부모 메소드 숨기는 효과 !!
• 자식 클래스에서는 재정의된 메소드만 호출
자식 클래스에서 수정되기 전 부모 메소드 호출 - super 사용
• super는 부모 객체 참조(참고: this는 자신 객체 참조)

자식 클래스에서 부모 클래스의 메소드를 오버라이딩하게 되면,부모 클래스의 메소드는 숨겨지고 오버라이딩된 자식 메소드만 사용된다.
그러나 자식 클래스 내부에서 오버라이딩된 부모 클래스의 메소드를 호출해야 하는 상황이 발생한다면 명시적으로 super 키워드를 붙여서 부모 메소드를 호출할 수 있다.
super는 부모 객체를 참조하고 있기 때문에 부모 메소드에 직접 접근할 수 있다.

[Airplane.java] super변수

public class Airplane {
	public void land() {
		System.out.println("착륙합니다.");
	}
	public void fly() {
		System.out.println("일반비행합니다.");
	}
	public void takeOff() {
		System.out.println("이륙합니다.");
	}
}

[SupersonicAirplane.java] super변수

public class SupersonicAirplane extends Airplane {
	public static final int NORMAL = 1;
    public static final int SUPERSONIC = 2;
    
    public int flyMode = NORMAL;
    
    @Override
    public void fly() {
    	if(flyMode == SUPERSONIC) {
    		System.out.println("초음속비행합니다.");
    	}else {
    		//Airplane 객체의 fly() 메소드 호출
            super.fly();//부모의 함수 호출 할 경우는 super
    	}
    }
}

 

[SupersonicAirplaneExample.java] super변수

public class SupersonicAirplaneExample {
	public static void main(String[] args) {
		SupersonicAirplane sa = new SupersonicAirplane();
		sa.takeOff();
		sa.fly();
		sa.flyMode = SupersonicAirplane.SUPERSONIC;
		sa.fly();
		sa.flyMode = SupersonicAirplane.NORMAL;
		sa.fly();
		sa.land();
	}
}

자주 사용되는 고정값들은 상수를 사용함으로써 가독성을 높여준다.

 

7.5 final클래스와 final 메소드
 final 키워드의 용도
final 필드: 수정 불가 필드
final 클래스: 부모로 사용 불가한 클래스
final 메소드: 자식이 재정의할 수 없는 메소드
final 키워드는 해당 선언이 최종상태이고, 결코 수정될 수 없음을 뜻한다.
final 키워드가 클래스,필드,메소드 선언에 사용될 경우 해석이 조금씩 달라지는데
클래스와 메소드에 final이 지정되면 어떤 효과가 날까?
클래스와 메소드 선언 시에 final 키워드가 지정되면 상속과 관련이 있다.


7.5.1상속할 수 없는 final 클래스
자식 클래스 만들지 못하도록 final 클래스로 생성
public final class 클래스{...}

final 대표적인 예는 String이다.

그래서 다음과 같이 자식 클래스를 만들 수 없다.
public class NewString extends String{...}

[Member.java] 상속할 수 없는 final클래스
public final class Member {

}

[VeryVeryImportantPerson.java] 상속할 수 없는 final 클래스
//Member를 상속할 수 없음
public class VeryVeryImportantPerson extends Member {

}

7.5.2오버라이딩할 수 없는 final 메소드
자식 클래스가 재정의 못하도록 부모 클래스의 메소드를 final로 생성
public final 리턴타입 메소드([매개변수 , ...] ...) {...}

[Car.java] 재정의할 수 없는 final메소드

public class Car {
	// 필드
	public int speed;

	// 메소드
	public void speedUp() {
		speed += 1;
	}

	// final 메소드
	public final void stop() {
		System.out.println("차를 멈춤");
		speed = 0;
	}
}

 

[SportsCar.java] 재정의할 수 없는 final메소드

public class SportsCar extends Car{
    @Override
    public void speedUp() {speed += 10;}
    
    //오버라이딩을 할 수 없음
    @Override
    public void stop() {
        System.out.println("스포츠카를 멈춤");
        speed = 0;
    }
}

 

7.6 protected 접근 제한자
protected는 public과 default 접근 제한의 중간쯤에 해당한다.
같은 패키지에서는 default와 같이 접근 제한이 없지만 다른 패키지에서는 자식 클래스만 접근을 허용
 protected 접근 제한자
상속과 관련된 접근 제한자
• 같은 패키지: default와 동일
• 다른 패키지: 자식 클래스만 접근 허용

protected는 필드와 생성자 ,메소드 선언에 사용될수 있다.

[A.java] protected 접근 제한자

package textbook.chapter7.package1;

public class A {
	protected String field;
	
	protected A() {
		
	}
	
	protected void method() {
		
	}
}

 

[B.java] protected 접근 제한자

package textbook.chapter7.package1;

public class B {
    public void method() {
        A a = new A();; //(O)
        a.field = "value"; //(O)
        a.method();
    }
}

[C.java] protected 접근 제한자 테스트

package textbook.chapter7.package2;

import textbook.chapter7.package1.A;

public class C {
    public void method() {
        A a = new A();            // x
        a.field = "value";          // x
        a.method();                  // x
    }
}

[D.java] protected 접근 제한자

package textbook.chapter7.package2;

import textbook.chapter7.package1.A;

public class D extends A {
	public D() {
		super(); // o
		this.field = "value"; // o
		this.method(); // o
	}
}

7.7 타입 변환과 다형성
 다형성 (多形性, Polymorphism)
같은 타입이지만 실행 결과가 다양한 객체 대입(이용) 가능한 성질
• 부모 타입에는 모든 자식 객체가 대입 가능
자식 타입은 부모 타입으로 자동 타입 변환
• 효과: 객체 부품화 가능

public class Car{
Tire t1 = new HankookTire();
Tire t2 = new KumhoTire();
}


7.7.1 자동타입 변환(Promotion)
자동 타입 변환(Promotion) 은 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것을 말한다

 바로 위의 부모가 아니더라도 상속 계층의 상위면 자동 타입 변환 가능
• 변환 후에는 부모 클래스 멤버만 접근 가능 (p.308~310)

 

class A {}

class B extends A {}
class C extends A {}
 
class D extends B {}
class E extends C {}
 
public class PromotionExample {
    public static void main(String[] args) {
        B b = new B();
        C c = new C();
        D d = new D();
        E e = new E();
        
        A a1 = b;
        A a2 = c;
        A a3 = d;
        A a4 = e;
        
        B b1 = d;
        C c1 = e;
        
        //B b3 = e;        //컴파일 에러(상속관계에 있지 않음)
        //C c2 = d;        //컴파일 에러(상속관계에 있지 않음)
        
    }
}

 

부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근이 가능하다.
비록 변수는 자식 객체를 참조, 변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정된다.
그러나 예외가 있다
메소드가 자식 클래스에서 오버라이딩되었다면 자식 클래스의 메소드가 대신 호출된다
이것은 다형성(Polymorphism)과 관련이 있기 때문에 매우 중요한 성질

[Parent.java] 자동 타입 변환 후의 멤버 접근

public class Parent {
	public void method1() {
		System.out.println("Parent-method1()");
	}

	public void method2() {
		System.out.println("Parent-method2()");
	}
}
public class Child extends Parent {
	@Override
	public void method2() {
		System.out.println("Child-method2()"); // 재정의
	}

	public void method3() {
		System.out.println("Child-method3()");
	}
}

 

[Child.java] 자동 타입 변환 후의 멤버 접근

public class ChildExample {
	public static void main(String[] args) {
		Child child = new Child();

		Parent parent = child; // 자동 타입 변환
		parent.method1();
		parent.method2(); // 재정의된 메소드가 호출됨
		// parent.method3(); (호출 불가능)

	}
}

 

[ChildExample.java] 자동타입 변환 후의 멤버 접근
public class ChildExample {
public static void main(String[] args) {
Child child = new Child();

    Parent parent = child; // 자동 타입 변환
    parent.method1();
    parent.method2(); // 재정의된 메소드가 호출됨
    // parent.method3(); (호출 불가능)

}

}

7.7.2필드의 다형성
 다형성을 구현하는 기술적 방법
• 부모 타입으로 자동 변환
• 재정의된 메소드(오버라이딩)
다형성이란 동일한 타입을 사용하지만 다양한 결과가 나오는 성질을 말한다.

주로 필드의 값을 다양화함으로써 실행 결과가 다르게 나오도록 구현하는데, 필드의 타입은 변함이 없지만, 실행 도중에 어떤 객체를 필드로 저장하느냐에 따라 실행 결과가 달라질 수 있다.

이것이 필드의 다형성이다.
부모 클래스를 상속하는 자식 클래스는 부모가 가지고 있는 필드와 메소드를 가지고 있으니 사용 방법이 동일할 것이고, 자식 클래스는 부모의 메소드를 오버라이딩(재정의)해서 메소드의 실행내용을 변경함으로써 더 우수한 실행 결과가 나오게 할 수 있다.

class Car{
//필드
Tire frontLeftTire = new Tire();
Tire frontRightTire = new Tire();
Tire backLeftTire = new Tire();
Tire backRightTire = new Tire();
//메소드
void run(){...}
}

 

Car myCar = new Car();
myCar.frontLeftTire = new HankookTire();
myCar.backLeftTire = new KumboTire();
myCar.run();

 

void run(){
	frontLeftTire. roll();
	frontRightTire. roll();
	backLeftTire. roll();
	backRightTire.roll();

}


[Tire.java] 타이어 클래스

package textbook.chapter7.exam01;

public class Tire {
	// 필드
	public int maxRotation; // 최대 회전수(타이어 수명)
	public int accumulatedRotation; // 누적 회전수
	public String location; // 타이어의 위치

	// 생성자
	public Tire(String location, int maxRotation) {
		this.location = location;
		this.maxRotation = maxRotation;
	}

	// 메소드
	public boolean roll() {
		++accumulatedRotation; // 누적 회전수 1증가
		if (accumulatedRotation < maxRotation) {
			System.out.println(location + " Tire 수명: " + // 정상 회전
					(maxRotation - accumulatedRotation) + "회"); // (누적<최대)일 경우 실행
			return true;
		} else {
			System.out.println("*** " + location + " Tire 펑크 ***"); // 펑크(누적=최대)일 경우 실행
			return false;
		}
	}
}

 

[Car.java] Tire를 부품으로 가지는 클래스

package textbook.chapter7.exam01;

public class Car {
	//필드
    Tire frontLeftTire = new Tire("앞왼쪽",6);
    Tire frontRightTire = new Tire("앞오른쪽",2);
    Tire backLeftTire = new Tire("뒤왼쪽",3);
    Tire backRightTire = new Tire("뒤오른쪽",4);        //자동차는 4개의 타이어를 가진다.
    //생성자
    //메소드
    int run() {
        System.out.println("[자동차가 달립니다.]");
        if(frontLeftTire.roll()==false) {stop(); return 1;};        //모든 타이어를 1회 회전시키기 위해 각 Tire
        if(frontRightTire.roll()==false) {stop(); return 2;};    //객체의 roll()메소드를 호출한다.
        if(backLeftTire.roll()==false) {stop(); return 3;};        //false를 리턴하는 roll()이 있을 경우
        if(backRightTire.roll()==false) {stop(); return 4;};        //stop() 메소드를 호출하고 해당 타이어 번호를 리턴한다.
        return 0;
    }
    
    void stop() {
        System.out.println("[자동차가 멈춥니다.]");
    }
}

 

[HankookTire.java] Tire의 자식 클래스

package textbook.chapter7.exam01;

public class HankookTire extends Tire {
	   //필드
    //생성자
    public HankookTire(String location,int maxRotation) {
        super(location,maxRotation);
    }
    
    //메소드
    @Override
    public boolean roll() {
        ++accumulatedRotation;
        if(accumulatedRotation<maxRotation) {
            System.out.println(location + " HankookTire 수명: " + (maxRotation-accumulatedRotation) + "회");
        return true;
        } else {
            System.out.println("*** " + location + " HankookTire 핑크 ***");
            return false;
        }
    }
}

 

[KumhoTire.java] Tire의 자식 클래스

package textbook.chapter7.exam01;

public class KumhoTire extends Tire{
    //필드
    //생성자
    public KumhoTire(String location,int maxRotation) {
        super(location,maxRotation);
    }
    //메소드
    @Override
    public boolean roll() {
        ++accumulatedRotation;
        if(accumulatedRotation<maxRotation) {
            System.out.println(location + " KumhoTire 수명: " + (maxRotation-accumulatedRotation) + "회");
            return true;
        } else {
            System.out.println("*** " + location + " KumhoTire 펑크 ***");
            return false;
        }
    }
}

[CarExample.java] 실행 클래스

package textbook.chapter7.exam01;

public class CarExample {
	public static void main(String[] args) {
		Car car = new Car(); // Car 객체 생성

		for (int i = 1; i <= 5; i++) { // Car 객체의 run() 메소드 5번 반복 실행
			int problemLocation = car.run();

			switch (problemLocation) {
			case 1:
				System.out.println("앞왼쪽 HankookTire로 교체");
				car.frontLeftTire = new HankookTire("앞왼쪽", 15);
				break;
			case 2:
				System.out.println("앞오른쪽 KumhoTire로 교체");
				car.frontLeftTire = new KumhoTire("앞오른쪽", 13);
				break;
			case 3:
				System.out.println("뒤왼쪽 HankookTire로 교체");
				car.frontLeftTire = new HankookTire("뒤왼쪽", 14);
				break;
			case 4:
				System.out.println("뒤오른쪽 HankookTire로 교체");
				car.frontLeftTire = new HankookTire("뒤오른쪽", 17);
				break;
			}
			System.out.println("-------------------------------"); // 1회전 시 출력되는 내용을 구분
		}
	}
}


결과 =>
[자동차가 달립니다.]
앞왼쪽 Tire 수명: 5회
앞오른쪽 Tire 수명: 1회
뒤왼쪽 Tire 수명: 2회
뒤오른쪽 Tire 수명: 3회


[자동차가 달립니다.]
앞왼쪽 Tire 수명: 4회
* 앞오른쪽 Tire 펑크 *
[자동차가 멈춥니다.]
앞오른쪽 KumhoTire로 교체


[자동차가 달립니다.]
앞오른쪽 KumhoTire 수명: 12회
* 앞오른쪽 Tire 펑크 *
[자동차가 멈춥니다.]
앞오른쪽 KumhoTire로 교체


[자동차가 달립니다.]
앞오른쪽 KumhoTire 수명: 12회
* 앞오른쪽 Tire 펑크 *
[자동차가 멈춥니다.]
앞오른쪽 KumhoTire로 교체


[자동차가 달립니다.]
앞오른쪽 KumhoTire 수명: 12회
* 앞오른쪽 Tire 펑크 *
[자동차가 멈춥니다.]
앞오른쪽 KumhoTire로 교체


7.7.3 하나의 배열로 객체 관리

[Car.java] Tire를 부품으로 가지는 클래스

public class Car {
	 //필드
    Tire[] tires = {
            new Tire("앞왼쪽",6),
            new Tire("앞오른쪽",2),
            new Tire("뒤왼쪽",3),
            new Tire("뒤오른쪽",4),
    };
    
    //메소드
    int run() {
        System.out.println("[자동차가 달립니다.]");
        for(int i=0; i<tires.length;i++) {
            if(tires[i].roll()==false) {
                stop();
                return (i+1);
            }
        }
        return 0;
    }
    
    void stop() {
        System.out.println("[자동차가 멈춥니다.]");
    }
}

 

[CarExample.java] 실행 클래스

public class CarExample {
	public static void main(String[] args) {
	       Car car = new Car();
	        
	        for(int i=1;i<=5;i++) {
	            int problemLocation = car.run();
	            if(problemLocation!=0) {
	                System.out.println(car.tires[problemLocation-1].location + "HankookTire로 교체");
	                car.tires[problemLocation-1] =
	                    new HankookTire(car.tires[problemLocation-1].location,15);
	            }
	            System.out.println("----------------------------------");
	        }
	}
}

 

7.7.4 매개변수의 다형성
 매개변수가 클래스 타입일 경우
• 해당 클래스의 객체 대입이 원칙이나 자식 객체 대입하는 것도 허용
자동 타입 변환
매개변수의 다형성
자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 주로 메소드를 호출할 때 많이 발생한다.
메소드를 호출할 때에는 매개 변수의 타입과 동일한 매개값을 지정하는 것이 정석이지만, 매개값을 다양화하기 위해 매개 변수에 자식 타입 객체를 지정할 수도 있다.

Driver driver = new Driver();
Vehicle vehicle = new Vehicle();
driver.drive(vehicle);

우리는 여기서 매우 중요한 것을 하나 알게 되었다.
매개 변수의 타입이 클래스일 경우, 해당 클래스의 객채뿐만 아니라 자식 객체까지도 매개값으로 사용할 수 있다는 것이다.

[Vehicle.java] 부모 클래스
package textbook.chapter7.exam03;

public class Vehicle {
public void run() {
System.out.println("차량이 달립니다.");
}
}

[Driver.java] Vehicle을 이용하는 클래스
package textbook.chapter7.exam03;

public class Driver {
public void drive(Vehicle vehicle) {
vehicle.run();
}
}

[Bus.java] 자식 클래스
package textbook.chapter7.exam03;

public class Bus extends Vehicle {
@Override
public void run() {
System.out.println("버스가 달립니다.");
}
}

[Taxi.java] 자식 클래스

package textbook.chapter7.exam03;

public class Taxi extends Vehicle {
	@Override
	public void run() {
		System.out.println("택시가 달립니다.");
	}
}

[DriverExample.java] 실행 클래스

package textbook.chapter7.exam03;

public class DriverExample {
	public static void main(String[] args) {
		Driver driver = new Driver();

		Bus bus = new Bus();
		Taxi taxi = new Taxi();

		driver.drive(bus);
		driver.drive(taxi);
	}
}

7.7.5 강제 타입 변환(Casting)
 부모 타입을 자식 타입으로 변환하는 것

 조건
• 자식 타입을 부모 타입으로 자동 변환 후, 다시 자식 타입으로 변환할 때
 강제 타입 변환 이 필요한 경우
• 자식 타입이 부모 타입으로 자동 변환
부모 타입에 선언된 필드와 메소드만 사용 가능
• 자식 타입에 선언된 필드와 메소드를 다시 사용해야 할 경우

[Parent.java]부모 클래스

package textbook.chapter7.exam03;

public class Parent {
	public String field1;

	public void method1() {
		System.out.println("Parent-method1()");
	}

	public void method2() {
		System.out.println("Parent-method2()");
	}
}

 

[Child.java] 자식 클래스

package textbook.chapter7.exam03;

public class Child extends Parent {
	public String field2;

	public void method3() {
		System.out.println("Child-method3()");
	}

}

[ChildExample.java] 강제 타입 변환(캐스팅)

package textbook.chapter7.exam03;

public class ChildExample {
    public static void main(String[] args) {
        Parent parent = new Child();
        parent.field1 = "data1";
        parent.method1();
        parent.method2();
        /*
         parent.filed2 = "data2"; (불가능)
         parent.method3();
         */
 
        Child child = (Child) parent;
        child.field2 = "yyy"; //가능
        child.method3(); //가능
    }
}

 

7.7.6 객체 타입 변환(instanceof)
 객체 타입 확인(instanceof) (p.326~329)
부모 타입이면 모두 자식 타입으로 강제 타입 변환할 수 있는 것 아님
• ClassCastException 예외 발생 가능

 먼저 자식 타입인지 확인 후 강제 타입 실행해야 함

[Parent.java]부모 클래스
package textbook.chapter7.exam04;

public class Parent {

}

[Child.java] 자식 클래스
package textbook.chapter7.exam04;

public class Child extends Parent{

}

[InstanceofExampl.java] 객체 타입 확인

package textbook.chapter7.exam04;

public class InstanceofExampl {
	public static void method1(Parent parent) {
		if (parent instanceof Child) {
			Child child = (Child) parent;
			System.out.println("method1 - Child로 변환 성공");
		} else {
			System.out.println("method1 - Child로 변환되지 않음");
		}
	}

	public static void method2(Parent parent) {
		Child child = (Child) parent; // ClassCastException 발생할 가능성 있음
		System.out.println("method2 - Child로 변환 성공");
	}

	public static void main(String[] args) {
		Parent parentA = new Child();
		method1(parentA);
		method2(parentA);

		Parent parentB = new Parent();
		method1(parentB);
		method2(parentB); // 예외 발생
	}
}


결과=>
method1 - Child로 변환 성공
method2 - Child로 변환 성공
method1 - Child로 변환되지 않음
Exception in thread "main" java.lang.ClassCastException: textbook.chapter7.exam04.Parent cannot be cast to textbook.chapter7.exam04.Child
at textbook.chapter7.exam04.InstanceofExampl.method2(InstanceofExampl.java:14)
at textbook.chapter7.exam04.InstanceofExampl.main(InstanceofExampl.java:25)

7.8 추상 클래스
7.8.1 추상 클래스의 개념
 추상(abstract)
• 실체들 간에 공통되는 특성을 추출한 것
예1: 새, 곤충, 물고기 동물 (추상)
예2: 삼성, 현대, LG  회사 (추상)
 추상 클래스(abstract class)
• 실체 클래스들의 공통되는 필드와 메소드 정의한 클래스
• 추상 클래스는 실체 클래스의 부모 클래스 역할 (단독 객체 X)

7.8.2 추상 클래스의 용도
 실체 클래스의 공통된 필드와 메소드의 이름 통일할 목적
• 실체 클래스를 설계자가 여러 사람일 경우,
• 실체 클래스마다 필드와 메소드가 제각기 다른 이름을 가질 수 있음
 실체 클래스를 작성할 때 시간 절약
• 실체 클래스는 추가적인 필드와 메소드만 선언
 실체 클래스 설계 규격을 만들고자 할 때
• 실체 클래스가 가져야 할 필드와 메소드를 추상 클래스에 미리 정의
• 실체 클래스는 추상 클래스를 무조건 상속 받아 작성
7.8.3 추상 클래스 선언
 클래스 선언에 abstract 키워드 사용
• New 연산자로 객체 생성하지 못하고 상속 통해 자식 클래스만 생성 가능

[Phone.java] 추상 클래스

 

public class Phone {
    //필드
    public String owner;
    
    //생성자
    public Phone(String owner) {
        this.owner = owner;
    }
    
    //메소드
    public void turnOn() {
        System.out.println("폰 전원을 켭니다.");
    }
    public void turnOff() {
        System.out.println("폰 전원을 끕니다.");
    }
}

 

[SmartPhone.java] 실체 클래스

public class SmartPhone extends Phone{
    //생성자
    public SmartPhone(String owner) {
        super(owner);
    }
    
    //메소드
    public void internetSearch() {
        System.out.println("인터넷 검색을 합니다.");
    }

}

 

[PhoneExample.java] 추상 클래스

public class PhoneExample {
    public static void main(String[] args) {
      //Phone phone = new Phone();
      SmartPhone smartPhone = new SmartPhone("홍길동");

      smartPhone.turnOn();
      smartPhone.internetSearch();
      smartPhone.turnOff();

  }
}

 

7.8.4 추상 메소드와 오버라이딩(재정의)
메소드 이름 동일하지만, 실행 내용이 실체 클래스마다 다른 메소드
예: 동물은 소리를 낸다. 하지만 실체 동물들의 소리는 제각기 다르다.
구현 방법
• 추상 클래스에는 메소드의 선언부만 작성 (추상 메소드)
• 실체 클래스에서 메소드의 실행 내용 작성(오버라이딩(Overriding))

[Animal.java] 추상 메소드 선언

public abstract class Animal { //추상 클래스
  public String kind;
  public void breathe() {
      System.out.println("숨을 쉽니다.");
  }

  public abstract void sound();            //추상 메소드
}

 

추상 메소드 오버라이딩

public class Dog extends Animal{
  public Dog() {
  	this.kind = "포유류";
  }
  @Override                        //추상 메소드 재정의
  public void sound() {
      System.out.println("멍멍");
  }
}

 

추상 메소드 오버라이딩

public class Cat extends Animal{
  public Cat() {
  	this.kind = "포유류";
  }
  @Override
  public void sound() {
      System.out.println("야옹");
  }
}

 

실행 클래스

public class AnimalExample {
  public static void main(String[] args) {
      Dog dog = new Dog();
      Cat cat = new Cat();
      dog.sound();
      cat.sound();
      System.out.println("-----");
      //변수의 자동 타입 변환
      Animal animal = null;
      animal = new Dog();
      animal.sound();
      animal = new Cat();
      animal.sound();
      System.out.println("-----");
      //메소드의 다형성
      animalSound(new Dog());
      animalSound(new Cat());
  }

  public static void animalSound(Animal animal) {
      animal.sound();        //재정의된 메소드 호출
  }
}

 

연습문제

1. 자바의 상속에 대한 설명 중 틀린 것은 무엇입니까? (1)

 

1. 자바는 다중 상속을 허용한다.

2. 부모의 메소드를 자식 클래스에서 재정의(오버라이딩)할 수 있다.

3. 부모의 private 접근 제한을 갖는 필드와 메소드는 상속의 대상이 아니다.

4. final 클래스는 상속할 수 없고, final 메소드는 오버라이딩할 수 없다.

 

2. 클래스 타입 변환에 대한 설명 중 틀린 것은 무엇입니까? (2)

 

1. 자식 객체는 부모 타입으로 자동 타입 변환된다.

2. 부모 객체는 항상 자식 타입으로 강제 타입 변환된다.

3. 자동 타입 변환을 이용해서 필드와 매개 변수의 다형성을 구현한다.

4. 강제 타입 변환 전에 instanceof 연산자로 변환 가능한지 검사하는 것이 좋다.

 

3. final 키워드에 대한 설명으로 틀린 것은? (1)

 

1.final 클래스는 부모 클래스로 사용할 수 있다.

2.final 필드는 값이 저장된 후에는 변경할 수 없다.

3.final 메소드는 재정의(오버라이딩)할 수 없다.

4.static final 필드는 상수를 말한다.

 

4. 오버라이딩(Overriding)에 대한 설명으로 틀린 것은? (4)

 

1. 부모 메소드의 시그니처 (리턴 타입, 메소드명, 매개 변수)와 동일해야 한다.

2. 부모 메소드보다 좁은 접근 제한자를 붙일 수 없다. (public(부모) -> private (자식))

3. @Override 어노테이션을 사용하면 재정의가 확실한지 컴파일러가 검증한다.

4. protected 접근 제한을 갖는 메소드는 다른 패키지의 자식 클래스에서 재정의할 수 없다.

 

5. Parent 클래스를 상속해서 Child 클래스를 다음과 같이 작성했는데, Child 클래스의 생성자에서 컴파일 에러가 발생했습니다. 그 이유를 설명해보세요.

package sec7;

public class Parent {
public String name;

public Parent(String name) {
    this.name = name;
}

}
package sec7;

public class Child extends Parent{

private int studentNo;

public Child(String name, int studentNo) {
    this.name = name;
    this.studentNo = studentNo;
}

}

 

this.name = name; 부분을 super(name); (부모생성자 호출)으로 고쳐준다.

  1. Parent 클래스를 상속받아 Child 클래스를 다음과 같이 작성했습니다. ChildExample 클래스를 실행했을 때 호출되는 각 클래스의 생성자의 순서를 생각하면서 출력 결과를 작성해보세요.

package sec7;

public class Parent {
public String nation;

public Parent() {
    this("대한민국");
    System.out.println("Parent() call");
}

public Parent(String nation) {
    this.nation = nation;
    System.out.println("Parent(String nation) call");
}

}

package sec7;

public class Child extends Parent{
private String name;

public Child() {
    this("홍길동");
    System.out.println("Child() call");
}

public Child(String name) {
    this.name = name;
    System.out.println("Child(String name) call");
}

package sec7;

public class ChildExample {

public static void main(String[] args) {
    Child child = new Child();
}

Parent(String nation) call
Parent() call
Child(String name) call
Child() call

  1. Tire 클래스를 상속받아 SnowTire 클래스를 다음과 같이 작성했습니다. SnowTireExample 클래스를 실행했을 때 출력 결과는 무엇일까요?

package sec7;

public class Tire {
public void run() {
System.out.println("일반 타이어가 굴러갑니다.");
}
}

package sec7;

public class SnowTire extends Tire{
@Override
public void run() {
System.out.println("스노우 타이어가 굴러갑니다.");
}
}

package sec7;

public class SnowTireExample {

public static void main(String[] args) {
    SnowTire snowTire = new SnowTire();
    Tire tire = snowTire;

    snowTire.run();
    tire.run();
}

스노우 타이어가 굴러갑니다.
스노우 타이어가 굴러갑니다. 

  1. A,B,C,D,E,F 클래스가 다음과 같이 상속 관계에 있을 때 다음 빈칸에 들어올 수 없는 코드는? (2)

자식 객체는 부모타입에 대입 될수 있다.

  1. new B()
  2. (B) new A() //강제 타입 변환
  3. new D() //자동 타입 변환
  4. new E() //자동 타입 변환
반응형

' > 이것이 자바다' 카테고리의 다른 글

09. 중첩 클래스와 중첩 인터페이스  (0) 2020.10.01
08. 인터페이스  (0) 2020.09.30
06. 클래스  (0) 2020.09.28
05. 참조 타입  (0) 2020.09.27
04. 조건문과 반복문  (0) 2020.09.26
반응형

클래스

6.1 객체 지향 프로그래밍

객체 지향 프로그래밍

OOP: Object Oriented Programming

부품 객체를 먼저 만들고 이것들을 하나씩 조립해 완성된 프로그램을 만드는 기법

 

6.1.1 객체란?

물리적으로 존재하는 것 (자동차, , 사람)

추상적인 것(회사, 날짜) 중에서 자신의 속성과 동작을 가지는 모든 것

객체는 필드(속성) 과 메소드(동작)로 구성된 자바 객체로 모델링 가능

현실 세계의 객체를 소프트웨어 객체로 설계하는 것을 객체 모델링(.Object Modeling)이라고 한다.

 

6.1.2 객체의 상호 작용

객체들은 서로 간에 기능(동작)을 이용하고 데이터를 주고 받음

 

객체들은 각각 독립적으로 존재하고, 다른 객체와 서로 상호작용한다. 이때 상호작용의 수단은 메서드이며 객체가 다른 객체의 기능을 이용하는 것이 메서드 호출이다. 정리하자면 객체의 상호작용은 객체 간의 메서드 호출을 의미하며 매개 값과 리턴 값을 통해서 데이터를 주고받는 것이다.

 

메소드 호출

리턴값 = 전자계산기객체.메소드(매개값1, 매개값2, ..)

 

int result = Calculator.add(10 , 20);

 

6.1.3 객체 간의 관계

객체 지향 프로그램에서는 객체는 다른 객체와 관계를 맺음

 

=>관계의 종류

집합 관계: 완성품과 부품의 관계

사용 관계: 객체가 다른 객체를 사용하는 관계

상속 관계: 종류 객체와  구체적인 사물 객체 관계

 

 

6.1.4 객체 지향 프로그래밍의 특징

객체를 사용하는 프로그램을 객체 지향 프로그래밍(OOP)이라고 한다

 

=>캡슐화(Encapsulation)->노출을 방지하기 위해서

객체의 필드, 메소드를 하나로 묶고, 실제 구현 내용을 감추는 것

외부 객체는 객체 내부 구조를 알지 못하며 객체가 노출해 제공하는 필드와 메소드만 이용 가능

필드와 메소드를 캡슐화하여 보호하는 이유는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록

자바 언어는 캡슐화된 멤버를 노출시킬 것인지 숨길 것인지 결정하기 위해 접근 제한자(Access Modifier) 사용

 

 

=>상속(Inheritance)

      상위(부모) 객체의 필드와 메소드를 하위(자식) 객체에게 물려주는 행위

      하위 객체는 상위 객체를 확장해서 추가적인 필드와 메소드를 가질 수 있음

      상속 대상: 필드와 메소드

      상속의 효과

상위 객체를 재사용해서 하위 객체를 빨리 개발 가능

반복된 코드의 중복을 줄임

  유지 보수의 편리성 제공

객체의 다형성 구현

 

 

=>다형성(Polymorphism)

같은 타입이지만 실행 결과가 다양한 객체를 대입할 수 있는 성질

       부모 타입에는 모든 자식 객체가 대입

       인터페이스 타입에는 모든 구현 객체가 대입

효과

       객체를 부품화시키는 것 가능

       유지보수 용이

 

 

6.2 객체(Object)와 클래스(Class)

현실세계: 설계도 -> 객체

자바: 클래스  ->  객체

클래스에는 객체를 생성하기 위한 필드와 메소드가 정의

클래스로부터 만들어진 객체를 해당 클래스의 인스턴스(instance)

하나의 클래스로부터 여러 개의 인스턴스를 만들 수 있음

 

 

 

 

 

 

 

 

클래스를 설계 -> 설계된 클래스를 가지고 사용할 객체를 생성 ->생성된 객체를 이용하는 것

 

6.3 클래스 선언

=>클래스의 이름

자바 식별자 작성 규칙에 따라야

 

 

 

한글 이름도 가능하나, 영어 이름으로 작성

알파벳 대소문자는 서로 다른 문자로 인식

첫 글자와 연결된 다른 단어의 첫 글자는 대문자로 작성하는 것이 관례

 

 

 

 

 

=>클래스 선언과 컴파일

소스 파일 생성: 클래스이름.java (대소문자 주의)

소스 작성

 

컴파일

클래스이름.class

javac.exe

 

 

 

 

 

 

소스 파일당 하나의 클래스를 선언하는 것이 관례

두 개 이상의 클래스도 선언 가능

소스 파일 이름과 동일한 클래스만 public으로 선언 가능

선언한 개수만큼 바이트 코드 파일이 생성

 

Car.java

public class Car {

}

class Tire {

}

컴파일

Car.class

Tire.class

javac.exe

 

 

 

 

 

 

 

 

 

두개 class가 있을 경우 public는 하나만 있어야 한다.

주의할 점은 파일 이름과 동일한 이름의 클래스 선언에만 public 접근 제한자를 붙일 수 있다.

만약 파일 이름과 일치하지 않는 클래스 선언에 public 접근 제한자를 붙이면 컴파일 에러가 발생한다.

가급적이면 소스파일 하나당 동일한 이름의 클래스 하나를 선언하는 것이 좋다.

 

6.4 객체 생성과 클래스 변수

=>new 연산자

객체 생성 역할

 

 

 

클래스()는 생성자를 호출하는 코드

생성된 객체는 힙 메모리 영역에 생성

new 연산자는 객체를 생성 후, 객체 생성 번지 리턴

 

=>클래스 변수

new 연산자에 의해 리턴 된 객체의 번지 저장 (참조 타입 변수)

힙 영역의 객체를 사용하기 위해 사용

 

클래스 타입으로 선언된 변수에 new 연산자가 리턴한 객체의 주소를 저장하는 코드

 

클래스 변수 선언과 객체 생성을 한 개의 실행문으로 작성할 수도 있다.

 

 

 

 

 

new 연산자로 객체를 생성하고 리턴된 객체의 주소를 변수에 저장하면 다음 그림과 같이 변수가 객체를 참조하게 된다.

 

 

 

 

 

 

 

[ Student.java]클래스 선언

public class Student {

 

}

 

[ StudentExample.java]클래스로부터 객체 생성

public class StudentExample {

       public static void main(String[] args) {

               Student s1 = new Student();

               System.out.println("s1 변수가 Student 객체를 참조합니다.");

 

               Student s2 = new Student();

               System.out.println("s2 변수가 다른 Student 객체를 참조합니다.");

       }

}

비록 같은 클래스로 부터 생성되었지만, 각각의 Student 객체는 자신만의 고유 데이터를 가지면서 메모리에서 활동하게 된다

s1, s2가 참조하는 Student 객체는 완전히 독립된 서로 다른 객체이다.

 

 

=>클래스의 용도

라이브러리(API: Application Program Interface)

자체적으로 실행되지 않음

다른 클래스에서 이용할 목적으로 만든 클래스

 

실행용

main() 메소드를 가지고 있는 클래스로 실행할 목적으로 만든 클래스

 

 

public class Student {

           //라이브러리로서의 코드(필드 ,생성자 ,메소드)

          

           //실행하기 위한 코드

           public static void main(String[] args) {

                       Student s1 = new Student();

                       System.out.println("s1 변수가 Student 객체를 참조합니다.");

 

                       Student s2 = new Student();

                       System.out.println("s2 변수가 또 다른 Student 객체를 참조합니다.");

           }

}

대부분의 객체 지향 프로그램은 라이브러리(부품 객체 및 완성 객체)와 실행 클래스가 분리되어 있다.

 

6.5클래스의 구성 멤버

=>클래스의 구성 멤버

필드(Field)

생성자(Constructor)

메소드(Method)

 

 

 

 

 

 

6.5.1필드

필드는 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳..

선언 형태는 변수와 비슷하지만, 필드는 변수가 아니다.

변수는 생성자와 메소드 내에서만 사용되고, 생성자와 메소드가 실행 종료되면 자동 소멸된다.

하지만 필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재한다.

 

6.5.2생성자

생성자는 new연산자로 호출되는 특별한 중괄호 {} 블록이다.

생성자의 역할은 객체 생성 시 초기화를 담당한다.

필드를 초기화하거나 ,메소드를 호출해서 객체를 사용할 준비를 한다.

생성자는 메소드와 비슷하게 생겼지만, 크래스 이름으로 되어 있고 리턴 타입이 없다.

 

6.5.3 메소드

메소드는 객체의 동작에 해당하는 중괄호 {} 블록을 말한다.

중괄호 블록은 이름을 가지고 있는데, 이것이 메소드 이름이다.

메소드를 호출하게 되면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행된다.

메소드는 필드를 읽고 수정하는 역할도 하지만, 다른 객체를 다양한 기능을 수행하기도 한다.

메소드는 객체 간의 데이터 전달의 수단으로 사용한다.

외부로부터 매개값을 받을 수 있고 , 실행 후 어떤 값을 리턴할 수도 있다.

 

6.6 필드

=>필드의 내용

객체의 고유 데이터

객체가 가져야 할 부품 객체

객체의 현재 상태 데이터

 

 

 

 

6.6.1  필드 선언

필드 선언은 클래스 중괄호 {} 블록 어디서든 존재할 수 있다.

생성자 선언과 메소드 선언의 앞과 뒤 어떤 곳에서도 필드 선언이 가능하다.

생성자와 메소드 중괄호 블록 내부에 선언된 것은 모두 로컬 변수가 된다.

 

 

타입은 필드에 저장할 데이터의 종류를 결정한다.

 

 

 

 

 

 

 

 

 

=>필드의 기본 초기값

초기값 지정되지 않은 필드

객체 생성시 자동으로 기본값으로 초기화

 

 

 

 

6.6.2 필드 사용

필드 값을 읽고, 변경하는 작업을 말한다.

필드 사용 위치

객체 내부: “필드이름” 으로 바로 접근

객체 외부: “변수.필드이름”으로 접근

필드는 객체에 소속된 데이터이므로 객체가 존재하지 않으면 필드도 존재하지 않기 때문이다.

 

 

 

 

 

 

변수는 자신이 선언된 생성자 또는 메소드 블록내부에서만 사용할 수 있는 반면 필드는 생성자와 모든 메소드에서 사용이 가능하다.

Car myCar = newCar():

myCar.speed = 60; //필드값을 60으로 변경

 

[ Car.java]Car 클래스 필드 선언

public class Car {

           // 필드

           String company = "현대자동차";

           String model = "그랜저";

           String color = "검정";

           int maxSpeed = 350;

           int speed;

}

 

[ CarExample.java]외부 클래스에서 Car 필드값 읽기와 변경

public class CarExample {

           public static void main(String[] args) {

                       // 객체 생성

                       Car myCar = new Car();

 

                       // 필드 값 읽기

                       System.out.println("제작회사: " + myCar.company);

                       System.out.println("모델명: " + myCar.model);

                       System.out.println("색깔: " + myCar.color);

                       System.out.println("최고속도: " + myCar.maxSpeed);

                       System.out.println("현재속도: " + myCar.speed);

 

                       // 필드 값 변경

                       myCar.speed = 60;

                       System.out.println("수정된 속도: " + myCar.speed);

           }

}

Car클래스는 speed필드 선언 시 초기값을 주지 않았다. 그러나 출력해보면 기본값은0이 들어있는 것을 볼 수 있다.

 

[FieldInitValue.java]필드 자동 초기화

public class FieldInitValue {

           // 필드

           byte byteField;

           short shortField;

           int intField;

           long longField;

 

 

           boolean booleanField;

           char charField;

 

           float floatField;

           double doubleField;

 

           int[] arrField;

           String referenceField;

}

 

[ FieldInitValueExample.java]필드값 출력

public class FieldInitValueExample {

           public static void main(String[] args) {

                       FieldInitValue fiv = new FieldInitValue();

 

                       System.out.println("byteField: " + fiv.byteField);

                       System.out.println("shortField: " + fiv.shortField);

                       System.out.println("intField: " + fiv.intField);

                       System.out.println("longField: " + fiv.longField);

                       System.out.println("booleanField: " + fiv.booleanField);

                       System.out.println("charField: " + fiv.charField);

                       System.out.println("floatField: " + fiv.floatField);

                       System.out.println("doubleField: " + fiv.doubleField);

                       System.out.println("arrField: " + fiv.arrField);

                       System.out.println("referenceField: " + fiv.referenceField);

           }

}

 

6.7 생성자

생성자(Constructor) : new 연산자와 같이 사용되어 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당
객체 초기화 : 필드를 초기화하거나 메서드를 호출해서 객체를 사용할 준비를 하는 것

생성자의 실행 없이 객체 생성은 불가능.

new 연산자에 의해 생성자가 성공적으로 실행되면 힙(Heap)영역에 객체가 생성되고 객체의 주소가 리턴된다. 리턴된 객체의 주소는 클래스 타입 변수에 저장되어 객체에 접근할 때 이용된다. 만약 생성자가 성공적으로 실행되지 않고 예외(에러)가 발생했다면 객체는 생성되지 않는다.

 

6.7.1기본 생성자 (Default Constructor)

모든 클래스는 생성자가 반드시 존재하며 하나 이상 가질 수 있음

생성자 선언을 생략하면 컴파일러는 다음과 같은 기본 생성자 추가

 

public 없이 class로만 선언되면 기본 생성자에도 public이 붙지 않는다.

 

 

 

컴파일러는 기본 생성자를 추가하지 않는다.

 

 

 

6.7.2 생성자 선언

=>생성자 선언

디폴트 생성자 대신 개발자가 직접 선언

 

 

 

 

 

=>개발자 선언한 생성자 존재 시 컴파일러는 기본 생성자 추가하지 않음

new 연산자로 객체 생성시 개발자가 선언한 생성자 반드시 사용

 

 

클래스에 생성자가 명시적으로 선언되어 있을 경우에는 반드시 선언된 생성자를 호출해서 객체를 생성해야만 한다.

 

[ Car1.java]생성자 선언

public class Car1 {

           // 생성자

           Car1(String color, int cc) {// 검정, 3000

           }

}

 

[ CarExample1.java]생성자를 호출해서 객체 생성

public class CarExample1 {

           public static void main(String[] args) {

                       Car1 myCar = new Car1("검정", 3000);

                       // Car1 myCar = new Car1(); (X) // 기본 생성자를 호출할 수 없다.

           }

}

 

6.7.3필드 초기화

클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동 설정됩니다.

만약 다른 값으로 초기화하고 싶다면 두가지 방법이 있습니다

-필드를 선언할 때 초기값을 주는 방법

-생성자에서 초기값을 주는 방법

필드를 선언할 때 초기값을 주면 동일한 클래스로부터 생성되는 객체들은 모두 같은 데이터를 갖게 됩니다.

객체 생성 후 변경할 수 있지만 객체 생성 시점에는 필드의 값이 모두 같습니다.


:

korean 클래스에 nation필드를 선언하면서 "대한민국"으로 초기값을 준 경우 ,Korean클래스로부터 k1k2객체를 생성하면k1k2객체의 nation필드에는 모두 "대한민국"이 저장되어 있다.

  

 

객체 생성 시점에 외부에서 제공되는 다양한 값들로 초기화되어야 한다면 생성자에서 초기화를 해야 합니다.

위 코드에서 name(이름) ssn(주민번호) 필드값은 클래스를 작성할 때 초기값을 줄 수 없고 객체 생성시점에서 다양한 값을 가져야 합니다.

따라서 생성자의 매개값으로 이 값들을 받아 초기화 하는 것이 맞습니다.

 

 

생성자의 매개값으로 초기값 설정

 

 

 

 

 

[ Korean.java]생성자에서 필드 초기화

public class Korean {

           // 필드

           String nation = "대한민국";

           String name;

           String ssn;

 

           // 생성자

           public Korean(String n, String s) {

                       name = n;

                       ssn = s;

           }

}

 

[ KoreanExample.java]객체 생성 후 필드값 출력

public class KoreanExample {

           public static void main(String[] args) {

                       Korean k1 = new Korean("박자바", "011225-1234567");

                       System.out.println("k1.name : " + k1.name);

                       System.out.println("k1.ssn : " + k1.ssn);

 

                       Korean k2 = new Korean("김자바", "930525-0654321");

                       System.out.println("k2.name : " + k2.name);

                       System.out.println("k2.ssn : " + k2.ssn);

           }

}

 

매개 변수와 필드명 같은 경우 this 사용

public Korean(String name, String ssn) {

   this.name = name;

   this.ssn = ssn;

}

 

6.7.4 생성자 오버로딩(Overloaging)

=>생성자 다양화해야 하는 이유

객체 생성할 때 외부 값으로 객체를 초기화할 필요

외부 값이 어떤 타입으로 몇 개가 제공될 지 모름 - 생성자도 다양화

 

=>생성자 오버로딩(Overloading)

매개변수의 타입, 개수, 순서가 다른 생성자 여러 개 선언

 

 

 

Car클래스에서 생성자를 오버로딩한 예:

 

 

생성자 오버로딩 시 주의할 점은 매개 변수의 타입과 개수 그리고 선언된 순서가 똑같을 경우 여러 변수 이름만 바꾸는 것은 생성자 오버로딩이라고 볼 수 없다.

 

 

생성자가 오버로딩되어 있을 경우 ,new 연산자로 생성자를 호출할 때 제공되는 매개값의 타입과수에 의해 생성자가 렬정된다.

 

 

[ Car2.java]생성자의 오버로딩

public class Car2 {

           // 필드

           String company = "현대자동차";

           String model;

           String color;

           int maxSpeed;

 

           // 생성자

           Car2() { // 기본생성자이지만, 다른 생성자들도 만들었으므로, 자동으로 생성X, 그래서 이 예제에서 명시적으로 만듬

           }

 

           Car2(String model) {

                       this.model = model;

           }

 

           Car2(String model, String color) {

                       this.model = model;

                       this.color = color;

           }

 

           Car2(String model, String color, int maxSpeed) {

                       this.model = model;

                       this.color = color;

                       this.maxSpeed = maxSpeed;

           }

}

 

[CarExample2.java]객체 생성 시 생성자 선택

public class CarExample2 {

           public static void main(String[] args) {

                       Car2 car1 = new Car2();

                       System.out.println("car1.company : " + car1.company);

                       System.out.println();

 

                       Car2 car2 = new Car2("자가용"); // String model

                       System.out.println("car2.company : " + car2.company);

                       System.out.println("car2.model : " + car2.model);

                       System.out.println();

 

                       Car2 car3 = new Car2("자가용", "빨강"); // String model, String color

                       System.out.println("car3.company : " + car3.company);

                       System.out.println("car3.model : " + car3.model);

                       System.out.println("car3.color : " + car3.color);

                       System.out.println();

 

                       Car2 car4 = new Car2("택시", "검정", 200); // String model, String color, int maxSpeed

                       System.out.println("car4.company : " + car4.company);

                       System.out.println("car4.model : " + car4.model);

                       System.out.println("car4.color : " + car4.color);

                       System.out.println("car4.maxSpeed : " + car4.maxSpeed);

           }

}

 

6.7.5 다른 생성자 호출(tis())

=>다른 생성자 호출( this() )

생성자 오버로딩되면 생성자 간의 중복된 코드 발생

초기화 내용이 비슷한 생성자들에서 이러한 현상을 많이 볼 수 있음

초기화 내용을 한 생성자에 몰아 작성

다른 생성자는 초기화 내용을 작성한 생성자를 this()로 호출

 

 

this() 는 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫줄에서만 허용됩니다

this()의 매개값은 호출되는 생성자의 매개 변수 타입에 맞게 제공해야 합니다.

this()다음에는 추가적인 실행문들이 올 수 있다. 이 말은 호출되는 생성자의 실행이 끝나면 원래 생성자로 돌아와서 다음 실행문을 진행한다는 뜻이다.

 

[ Car3.java]위코드의 중복을 제거하는 예제를 보겠습니다.

public class Car3 {

           // 필드

           String company = "현대자동차";

           String model;

           String color;

           int maxSpeed;

 

           // 생성자

           Car3() {

                       this("자가용", "은색", 250); // this는 생성자의 첫줄에만 있어야한다 아니면 오류가 난다.

           }

 

           Car3(String model) {

                       this(model, "은색", 250);

           }

 

           Car3(String model, String color) {

                       this(model, color, 250);

           }

 

           Car3(String model, String color, int maxSpeed) // 공통 실행 코드, 초기화 내용을 한 생성자에 몰아서 작성한다

           {

                       this.model = model;

                       this.color = color;

                       this.maxSpeed = maxSpeed;

           }

}

 

[ CarExample3.java]다른 생성자를 호출해서 중복 코드 줄이기

public class CarExample3 {

           public static void main(String[] args) {

                       Car3 car1 = new Car3();

                       System.out.println("car1.company : " + car1.company);

                       System.out.println("car1.model : " + car1.model);

                       System.out.println("car1.color : " + car1.color);

                       System.out.println("car1.maxSpeed : " + car1.maxSpeed);

                       System.out.println();

 

                       Car3 car2 = new Car3("자가용");

                       System.out.println("car2.company : " + car2.company);

                       System.out.println("car2.model : " + car2.model);

                       System.out.println("car2.color : " + car2.color);

                       System.out.println("car2.maxSpeed : " + car2.maxSpeed);

                       System.out.println();

 

                       Car3 car3 = new Car3("자가용", "빨강");

                       System.out.println("car3.company : " + car3.company);

                       System.out.println("car3.model : " + car3.model);

                       System.out.println("car3.color : " + car3.color);

                       System.out.println("car3.maxSpeed : " + car3.maxSpeed);

 

                       System.out.println();

 

                       Car3 car4 = new Car3("택시", "검정", 200);

                       System.out.println("car4.company : " + car4.company);

                       System.out.println("car4.model : " + car4.model);

                       System.out.println("car4.color : " + car4.color);

                       System.out.println("car4.maxSpeed : " + car4.maxSpeed);

           }

}

 

 

6.8 메소드

메소드객체의 동작에 해당하는 중괄호 {} 블록

-중괄호 블록은 이름을 가지고 있는데 이것이 메소드 이름입니다

-메소드를 호출하면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행

-메소드는 필드를 읽고 수정하는 역할도 하지만, 다른 객체를 생성해서 다양한 기능을 수행하기도 합니다

-메소드는 객체 간의 데이터 전달의 수단으로 사용됩니다

-외부로부터 매개값을 받을 수도 있고 실행 후 어떤 값을 리턴할 수도 있습니다.

 

6.8.1 메소드 선언

 

 

 

 

선언부와(리턴타입, 메서드이름, 매개변수선언)와 실행 블록으로 구성.

메소드 선언부를 메서드 시그니처라고도 합니다.

객체의 동작(기능)

호출해서 실행할 수 있는 중괄호 { } 블록

메소드 호출하면 중괄호 { } 블록에 있는 모든 코드들이 일괄 실행

 

=>리턴 타입

리턴 타입은 메소드가 실행 후 리턴하는 값이 타입을 말한다.

메소드가 실행 후 결과를 호출한 곳에 넘겨줄 경우에는 리턴값이 있어야 합니다

리턴값이 없는 메소드 : 리턴타입에 void가 와야하고 ,

리턴값이 있는 메소드 : 리턴값의 타입이 와야합니다.



리턴값이 있나냐 없느냐에 따라 메소드를 호출하는 방법이 조금 다르다.

 

 

리턴 타입을 맞추어야 한다.

int result = divide(10, 20 ); //컴파일 에러

 

리턴 타입이 있다고 해서 리턴 값을 변수에 저장할 필요는 없다.

divide(10,20);

 

=>메소드 이름

메소드 이름은 자바 식별자 규칙에 맞게 작성하면 됩니다.

-숫자로 시작하면 안되고 $ , _ 를 제외한 특수문자를 사용하면 안된다.

-관례적으로 메서드명은 소문자로 작성한다.

-서로 다른 단어가 혼합된 이름이라면 뒤이어 오는 단어의 첫머리 글자는 대문자로 작성한다.

 

기능에 맞게 이름을 지어주는 것이 좋다.

 

=> 매개 변수 선언

매개변수는 메소드를 실행할 때 필요한 데이터를 외부에서 받기 위해 사용

매개변수도 필요 없을 수 있음

 

매개변수가 선언 예:

double divide(int x, int y ){...}

이렇게 선언된 divide() 메소드를 호출할 때에는 반드시 두개의 int값을 주어야 한다.

double result = divide(10,20);

잘못된 매개값을 사용해서 컴파일 오류가 발생

double result = divide(10.0 , 20.0 );//컴파일 에러

하지만 매개값의 타입과 매개 변수의 타입(int)이 달라도 byte타입은 int타임으로 자동 타입 변환되기 때문에 컴파일 오류가 생기지 않는다.

byte b1 =10;

byte b2 =20;

double result = divide(b1, b2);

 

[ Calculator.java]메소드 선언

public class Calculator {

           // 메소드

           void powerOn() {

                       System.out.println("전원을 켭니다.");

           }

 

           int plus(int x, int y) {

                       int result = x + y;

                       return result;

           }

 

           double divide(int x, int y) {

                       double result = (double) x / (double) y;

                       return result;

           }

 

           void powerOff() {

                       System.out.println("전원을 끕니다");

           }

}

 

[ CalculatorExample.java]메소드 호출

public class CalculatorExample {

           public static void main(String[] args) {

                       Calculator myCalc = new Calculator();

                       myCalc.powerOn();

 

                       int result1 = myCalc.plus(5, 6);

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

 

                       byte x = 10;

                       byte y = 4;

                       double result2 = myCalc.divide(x, y);

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

 

                       myCalc.powerOff();

           }

}

 

=>매개변수의 수를 모를 경우

메소드의 매개 변수는 이미 정해져 있는 것이 입반적이지만, 경우에 따라서느느 메소드를 선언할 때 매개변수의 개수를 알 수 없는 경우가 있다.

int sum(int[] values) { }

sum() 메소드를 호출할 때 배열을 넘겨줌으로써 배열의 항목 값들을 모두 전달할 수 있습니다배열의 항목 수는 호출할 때 결정됩니다.
int[] values = {1,2,3};

int result = sum(values);

int result = sum(new int[] = {1,2,3,4,5};

배열을 생성하지 않고 값의 리스트만 넘겨주는 방법도 있습니다. 매개 변수를 "..." 을 사용해서 선언하게 되면 메소드 호출 시 넘겨준 값의 수에 따라 자동으로 배열이 생성되고 매개값으로 사용됩니다.

 int sum2(int ... values) { }

"..." 으로 선언된 매개 변수의 값은 아래와 같이 메소드 호출 시 리스트로 나열해주면 됩니다.

int result = sum2(1,2,3);

int result = sum2(1,2,3,4,5);

"..." 으로 선언된 매개 변수는배열 타입이므로 배열을 직접 매개값으로 사용해도 됩니다.

int[] values = {1,2,3};

int result = sum2(values);

int result = sum2(new int[] = {1,2,3,4,5};

 

[ Computer.java]매개 변수의 수를 모를 경우

public class Computer {

           int sum1(int[] values) {

                       int sum = 0;

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

                                  sum += values[i];

                       }

                       return sum;

           }

 

           int sum2(int... values) {

                       int sum = 0;

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

                                  sum += values[i];

                       }

                       return sum;

           }

 

}

 

[ ComputerExample.java]매개 변수의 수를 모를 경우

public class ComputerExample {

           public static void main(String[] args) {

                       Computer myCom = new Computer();

                      

                       int[] values1 = { 1, 2, 3 };

                       int result1 = myCom.sum1(values1);

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

 

                       int result2 = myCom.sum1(new int[] { 1, 2, 3, 4, 5 });

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

 

                       int result3 = myCom.sum2(1, 2, 3);

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

 

                       int result4 = myCom.sum2(1, 2, 3, 4, 5);

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

           }

}

 

6.8.2 리턴(return)

=>메소드 실행을 중지하고 리턴값 지정하는 역할

=>리턴값이 없는 메소드

메소드 실행을 강제 종료 시키는 역할

return 결과값;

=>리턴값이 있는 메소드

반드시 리턴(return)문 사용해 리턴값 지정해야

 

 

return 문 뒤에 실행문 올 수 없음 ->Unreachable code라는 오류가 난다.

int plus(int x, int y){

           int result = x +y;

           return result;

           System.out.println(result); //Unreachable code

}

다음과 같은 경우는 컴파일 에러가 발생하지 않는다.

 

 

 

 

 

=>리턴 값이 없는 메소드(void)

return 문을 사용하면 메소드 실행을 강제 종료시킨다.

return;

아래에서는 return문을 대신해서 break 문을 사용할 수도 있습니다

만약 while문 뒤에 실행문이 추가적으로 더 있을 경우, break문을 반드시 사용해야 합니다.

return문은 즉시 메서드를 종료시키기 때문입니다.

 

 

[Car4.java]return

public class Car4 {

           // 필드

           int gas;

 

           // 생성자

 

           // 메소드

           // 리턴값이 없는 메소드로 매개값을 받아서 gas필드값을 변경

           void setGas(int gas) {

                       this.gas = gas;

           }

          

           //리턴값이 boolean인 메소드로 gas필드값이 0이면 false 0이 아니면 true로 리턴

           boolean isLeftGas() {

                       if (gas == 0) {

                                  System.out.println("gas가 없습니다.");

                                  return false;

                       }

                       System.out.println("gas가 있습니다.");

                       return true;

           }

       //리턴값이 없는 메소드로 gas필드값이 0이면 return문으로 메소드를 강제 종료

           void run() {

                       while (true) {

                                  if (gas > 0) {

                                              System.out.println("달립니다.(gas잔량:" + gas + ")");

                                              gas -= 1;

                                  } else {

                                              System.out.println("멈춥니다.(gas잔량:" + gas + ")");

                                              return;//메소드 실행 종료

                                  }

                       }

           }

}

 

[ CarExample4.java]return

public class CarExample4 {

           public static void main(String[] args) {

                       Car4 myCar = new Car4();

                       myCar.setGas(5); // Car setGas() 메소드 호출

 

                       boolean gasState = myCar.isLeftGas(); // Car isLeftGas() 메소드 호출

                       if (gasState) {

                                  System.out.println("출발합니다.");

                                  myCar.run(); // Car run() 메소드 호출

 

                       }

 

                       if (myCar.isLeftGas()) { // Car isLeftGas() 메소드 호출

                                  System.out.println("gas를 주입할 필요가 없습니다.");

                       } else {

                                  System.out.println("gas를 주입하세요.");

                       }

           }

}

 

6.8.3      메소드 호출

=>메소드는 클래스 내∙외부의 호출에 의해 실행

클래스 내부: 메소드 이름으로 호출

클래스 외부: 객체 생성 후, 참조 변수를 이용해 호출 , 그 이유는 객체가 존재해야 메소드도 존재하기 때문이다.

 

 

=>객체 내부에서 호출

 

:

public class ClassName{

           void method1(String p1, int p2){

}

void method2{}{

           method1("홍길동",100);

}

}

 

리턴값이 있는 메소드를 호출하고 리턴값을 받고 싶다면 다음과 같이 변수를 선언하고 대입하면 된다.

 

주의해야 할 점은 변수 타입은 메서드 리턴값과 동일하거나 타입 변환이 될수 있어야 합니다.

ex) int 타입은 double 타입으로 자동 변환되기 때문에 int 리턴값은 double 변수에 대입할 수 있습니다

public class ClassName {

        int method1(int x, int y){

            int result = x + y;

          return result;

          }

 

      void method2(){

        int result1 = method1(10,20);

       double result2 = method1(10,20);

    }

}

 

[ Calculator1.java]클래스 내부에서 메소드 호출

public class Calculator1 {

           int plus(int x, int y) {

                       int result = x + y;

                       return result;

           }

          

           double avg(int x, int y) {

                       double sum = plus(x,y);

                       double result = sum / 2;

                       return result;

           }

          

           void execute() {

                       double result = avg(7, 10);

                       println("실행결과 : "+result);

           }

          

           void println(String messge) {

                       System.out.println(messge);

           }

}

 

[ CalculatorExample1.java]Calculatorexecute()실행

public class CalculatorExample1 {

           public static void main(String[] args) {

                       Calculator1 myCals = new Calculator1();

                       myCals.execute();

           }

}


=>
객체 외부에서 호출

클래스 참조변수 = new 클래스(매개값,...); //객체 생성

 

객체가 생성되었다면 참조변수와 도트(.) 연산자를 사용해서 메서드를 호출할 수 있습니다

도트 연산자는 객체 접근 연산자로 객체가 가지고 있는 필드나, 메서드에 접근할 때 사용됩니다.

 

참조타입.메서드(매개값,...); //리턴값이 없거나, 있어도 리턴값을 받지 않을 경우

타입 변수 = 참조변수.메서드(매개값,...); // 리턴값이 있고, 리턴값을 받고 싶을 경우


Car myCar = new Car();

myCar.keyTurnOn();

myCar.run();

int speed = myCar.getSpeed();

[ Car5.java]클래스 외부에서 메소드 호출

public class Car5 {

           // 필드

           int speed;

 

           // 생성자

 

           // 메소드

           int getSpeed() {

                       return speed;

           }

 

           void keyTurnOn() {

                       System.out.println("키를 돌립니다.");

           }

 

           void run() {

                       for (int i = 10; i <= 50; i += 10) {

                                  speed = i;

                                  System.out.println("달립니다.(시속:" + speed + "km/h)");

                       }

           }

}

 

[CarExample5.java]글래스 외부에서 메소드 호출

public class CarExample5 {

           public static void main(String[] args) {

 

                       Car5 myCar = new Car5();

                       myCar.keyTurnOn();

                       myCar.run();

                       int speed = myCar.getSpeed();

                       System.out.println("현재 속도: " + speed + "km/h");

           }

}

 

6.8.4 메소드 오버로딩(Overloading)

클래스 내에 같은 이름의 메소드를 여러 개 선언하는 것

하나의 메소드 이름으로 다양한 매개값 받기 위해 메소드 오버로딩

오버로딩의 조건: 매개변수의 타입, 개수, 순서가 달라야

 

 

메소드 오버로딩이 필요한 이유는 매개값을 다양하게 받아 처리할 수 있도록 하기 위해서이다.

 

 

int ->double

 

 

plus()메소드 호출

plust(10,20);

plus(10.5, 20.3)

 

 

int x = 10;

double y = 20.3;

plus(x, y); =>puls(double, double)메소드가 실행된다.

자동 타입 변환

 

int divide(int x, int y ){...}

double divide(int boonja, int boonmo){...}

 

메소드 오버로딩된 println()메소드를 보여준다.

 

 

[Calculator2.java]메소드 오버로딩

public class Calculator2 {

           // 정사각형의 넓이

           double areaRectangle(double width) {

                       return width * width;

           }

 

           // 직사각형의 넓이

           double areaRectangle(double width, double height) {

                       return width * height;

           }

}

 

[ CalculatorExample2.java]메소드 오버로딩

public class CalculatorExample2 {

           public static void main(String[] args) {

                       Calculator2 myCalcu = new Calculator2();

                      

                       //정사각형의 넓이 구하기

                       double result1 = myCalcu.areaRectangle(10);

                      

                       //직사각형의 넓이 구하기

                       double result2 = myCalcu.areaRectangle(10,20);

                      

                       //결과 출력

                       System.out.println("정사각형 넓이 = "+result1);

                       System.out.println("직사각형 넓이 = "+result2);

           }

}

 

6.9   인스턴스 멤버와 this

=>인스턴스 멤버란?

객체(인스턴스) 마다 가지고 있는 필드와 메소드

이들을 각각 인스턴스 필드, 인스턴스 메소드라고 부름

인스턴스 멤버는 객체 소속된 멤버이기 때문에 객체가 없이 사용불가

 

 

 

 

 

 

인스턴스를 생성하고 참조 변수 등을 접근

 

메소드 영역

 

 

=>this ->

객체(인스턴스) 자신의 참조(번지)를 가지고 있는 키워드

객체 내부에서 인스턴스 멤버임을 명확히 하기 위해 this. 사용

매개변수와 필드명이 동일할 때 인스턴스 필드임을 명확히 하기 위해 사용

 

 

[Car6.java]인스턴스 멤버와 this

public class Car6 {

           // 필드

           String model;

           int speed;

 

           // 생성자

           Car6(String model) {

                       this.model = model;

           }

 

           // 메소드

           void setSpeed(int speed) {

                       this.speed = speed;

           }

 

           void run() {

                       for (int i = 10; i <= 50; i += 10) {

                                  this.setSpeed(i);

                                  System.out.println(this.model + "가 달립니다.(시속:" + this.speed + "km/h)");

                       }

           }

}

 

[ CarExample6.java]인스턴스 멤버와 this

public class CarExample6 {

           public static void main(String[] args) {

                       Car6 myCar = new Car6("포르쉐");

                       Car6 yourCar = new Car6("벤츠");

 

                       myCar.run();

                       yourCar.run();

           }

}

 

6.10 정적 멤버와 static

=>정적(static) 멤버란?

클래스에 고정된 필드와 메소드 - 정적 필드, 정적 메소드

정적 멤버는 클래스에 소속된 멤버

객체 내부에 존재하지 않고, 메소드 영역에 존재

정적 멤버는 객체를 생성하지 않고 클래스로 바로 접근해 사용

클래스에 소속된 멤버이기 때문에 클래스멤버라고도 합니다.

 

6.10.1 정적 멤버 선언

필드 또는 메소드 선언할 때 static 키워드 붙임

 

 

 

 

 

 

 

 

 

정적 필드와 정적 메소드는 클래스에 고정된 멤버이므로 클래스 로더가 클래스를 로딩해서 메소드 메모리 영역에 적재할 때 클래스별로 관리된다.

 

 

 

 

 

 

 

 

객체마다 가지고 있을 필요성이 없는 공용적인 데이터라면 정적 필드로 선언하는 것이 좋다.

인스턴스 멤버 선언 vs 정적 멤버 선언의 기준

§  필드

      객체 마다 가지고 있어야 할 데이터 è 인스턴스 필드

      공용적인 데이터 è 정적 필드

public class Calculator {

           String color;  // 계산기별로 색까리 다를 수 있ㄷ.

           static double pi = 3.14159; // 계산기에서 사용하는 파이 값은 동일하다.

}


인스턴스 필드를 이용해서 실행해야 한다면 인스턴스 메소드로 선언

    • 메소드

      인스턴스 필드로 작업해야 할 메소드 è 인스턴스 메소드

      인스턴스 필드로 작업하지 않는 메소드 è 정적 메소드

 

 

 

public class Calculator{

           String color; //인스턴스 메소드

           void setColor(String color){this.color = color;} //인스턴스 메소드

           static int plus(int x, int y){return x + y ;} //정적 메소드

           static int minus(int x, int y){return x - y;} //정적 메소드

}

6.10.2 정적 멤버 사용

클래스 이름과 함께 도트(.) 연산자로 접근

 

 

 

:

 

[바람직하지 못한 사용]

[바람직한 사용]

   

 

 

 

 

 

 

 

 

 

 

 

 

 

(1) 클래스 이름으로 접근해야 하지만

(2) 객체를 먼저 생성하고 참조 변수(객체 참조 변수) 접근이 가능하다. (클래스 이름으로 접근하기.. 아니면 오류 생길 수 있음)

 

==>클래스 이름으로 접근

[Calculator3]정적 멤버 사용

public class Calculator3 {

           static double pi = 3.14159;

 

           static int plus(int x, int y) {

                       return x + y;

           }

 

           static int minus(int x, int y) {

                       return x - y;

           }

}

 

[CalculatorExample3.java]정적 멤버 사용

public class CalculatorExample3 {

           public static void main(String[] args) {

                       double result1 = 10 * 10 * Calculator3.pi;

                       int result2 = Calculator3.plus(10, 5);

                       int result3 = Calculator3.minus(10, 5);

 

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

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

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

           }

}

 

 

6.10. 3 정적 초기화 블록

정적 필드는 다음과 같이 필드 선언과 동시에 초기값을 주는 것이 보통이다.

static double pi = 3.14159;

정적 필드는 필드 선언과 동시에 초기값을 주는 것이 일반적입니다.

계산이 필요한 초기화 작업이 있을 수도 있습니다

정적 필드는 객체 생성 없이 사용해야 하므로 생성자에서 초기화 작업을 할 수 없습니다

정적 필드의 복잡한 초기화 작업을 위해서 정적 블록을 제공합니다.

§  클래스가 메소드 영역으로 로딩될 때 자동으로 실행하는 블록

static {

      ......

}

정적 블록은 클래스가 메모리로 로딩될 때 자동적으로 실행된다.정적 블록은 클래스 내부에 여러개가 선언되어도 상관 없다. 클래스가 메모리로 로딩될때 선언된 순서대로 실행된다.

 

정적 필드의 복잡한 초기화 작업과 정적 메소드 호출 가능

클래스 내부에 여러 개가 선언되면 선언된 순서대로 실행

 

[Television.java]정적 초기화 블록

public class Television {

           static String company = "Samsung";

           static String model = "LCD";

           static String info;

 

           static {

                       info = company + "-" + model;

           }

}

 

[TelevisionExample.java]정적 초기화 블록

public class TelevisionExample {

           public static void main(String[] args) {

                       System.out.println(Television.info);

           }

}

 

6.10.4 정적 메소드와 정적 블록 작성시 주의할 점

객체가 없어도 실행 가능

블록 내부에 인스턴스 필드나 인스턴스 메소드 사용 불가

객체 자신의 참조인 this 사용 불가

EX)

public class ClassName{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

객체 생성하고 참조 변수로 접근해야 한다.

 

 

 

 

 

 

 

main()메서드도 동일한 규칙이 적용됩니다.

main()메서드도 정적 메서드이므로 객체 생성 없이 인스턴스 필드와 인스턴스 메서드를  

main() 메서드에서 바로 사용할 수 없습니다.

 

예제)

public class Car {

 int speed;

 

 void run() {...}

public static void main(String[] args) {

speed = 60;

run();

}

}

 

메인 메소드를 올바르개 수정하면 다음과 같다.

public static void main(String[] args) {

  Car myCar = new Car(); 

  myCar.speed = 60;

  myCar.run();

 }

}

 

[Car7.java ]정적 메소드와 블록 선언 시 주의 할 점

public class Car7 {

           int speed;

 

           void run() {

                       System.out.println(speed + "으로 달립니다.");

           }

 

 

           public static void main(String[] args) {

                       Car7 myCar = new Car7();

                       myCar.speed = 60;

                       myCar.run();

           }

}

6.10.5싱글톤(Singleton)

하나의 애플리케이션 내에서 단 하나만 생성되는 객체

=>싱글톤을 만드는 방법

외부에서 new 연산자로 생성자를 호출할 수 없도록 막기

private 접근 제한자를 생성자 앞에 붙임

클래스 자신의 타입으로 정적 필드 선언

자신의 객체를 생성해 초기화

private 접근 제한자 붙여 외부에서 필드 값 변경 불가하도록

외부에서 호출할 수 있는 정적 메소드인 getInstance() 선언

정적 필드에서 참조하고 있는 자신의 객체 리턴

public class 클래스{

           //정적 필드

           private static 클래스 singleton = new 클래스();

 

           //생성자

           private 클래스(){}

 

           //정적 메소드

           static 클래스 getInstance(){

                       return singleton;

}

}

 

=>외부에서 싱글톤 얻는 방법

 

 

 

[Singleton.java] 싱글톤

public class Singleton {

           private static Singleton singleton = new Singleton();

 

           private Singleton() {

           }

          

           static Singleton getInstance() {

                       return singleton;

           }

}

 

[SingletonExample.java] 싱글톤 객체

public class SingletonExample {

           public static void main(String[] args) {

                        /* Singleton obj1= new Singleton();//컴파일 에러  (private때문에 클래스 외부에서 new 생성자로 호출 X)

                        * Singleton obj2= new Singleton();//컴파일 에러  (싱글톤은 하나의 객체이고, 생성자를 호출한만큼 객체가 생성 되므로 X)*/

 

                       Singleton obj1 = Singleton.getInstance();

                       Singleton obj2 = Singleton.getInstance();

 

                       if (obj1 == obj2) {

                                  System.out.println("같은 Singleton 객체 입니다.");

                       } else {

                                  System.out.println("다른 Singleton 객체 입니다.");

                       }

           }

}

 

6.11 inal필드와 상수

6.11.1 final 필드

최종적인 값을 갖고 있는 필드 = 값을 변경할 수 없는 필드

final 타입 필드 = [= 초기값];

=>final 필드의 딱 한번의 초기값 지정 방법

필드 선언 시

생성자

단순 값이라면 필드 선언시에 주는 것이 제일 간단하다.

하지만 복잡한 코드가 필요하거나 객체 생성 시에 외부 데이터로 초기화해야 한다면 생성자에서 초기값을 지정해야 한다.

 

 

[Person.java] fianl 필드 선언과 초기화

public class Person {

           final String nation = "Korea";

           final String ssn;

           String name;

 

           public Person(String ssn, String name) {

                       this.ssn = ssn;

                       this.name = name;

           }

}

 

[PersonExample.java] final 필드 테스트

public class PersonExample {

           public static void main(String[] args) {

 

                       Person p1 = new Person("123456-1234567", "계백");

 

 

                       System.out.println(p1.nation);

                       System.out.println(p1.ssn);

                       System.out.println(p1.name);

 

                       // p1.nation = "Corea"; //final 필드는 수정이 불가합니다.

                       // p1.ssn = "654321-7654321";

                       p1.name = "을지문덕";

                       ;

           }

}

 

6.11.2상수(static final)

일반적으로 불변의 값을 상수라고 부른다.

=>상수 = 정적 final 필드

==>final 필드:

-객체마다 가지는 불변의 인스턴스 필드

==>상수(static final):

-객체마다 가지고 있지 않음

-메소드 영역에 클래스 별 로 관리되는 불변의 정적 필드

-공용 데이터로서 사용

일반적으로 불변의 값을 상수라고 부른다

불변의 값을 저장하는 필드를 자바에서는 상수라고 한다

final 필드를 상수라고 부르지는 않는다

상수는 static 이면서 final 이어야 함.

static final 필드는 객체마다 저장되지 않고, 클래스에만 포함

한 번 초기값이 저장되면 변경 불가.

 

 

static final 타입 상수 [= 초기값];

 

초기값이 단순 값이라면 선언 시에 주는 것이 일반적이지만

복잡한 초기화일 경우 정적 블록에서도 할 수 있습니다.

 static final 타입  상수;

  static {

    상수 = 초기값;

  }

 

상수 이름은 전부 대문자로 작성

다른 단어가 결합되면 _ 로 연결

static final double PI = 3.1459;

static final double EARTH_SURFACE_AREA;

 

[Earth.Java] 상수 선언

public class Earth {

           static final double EARTH_RADIUS = 6400;

           static final double EARTH_SURFACE_AREA;

          

           static {

                       EARTH_SURFACE_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS;

           }

}

 

[EarthExample.java] 상수 사용

public class EarthExample {

           public static void main(String[] args) {

                       System.out.println("지구의 반지름 : " + Earth.EARTH_RADIUS + "km");

                       System.out.println("지구의 표면적 : " + Earth.EARTH_SURFACE_AREA + "km^2");

           }

}

 

6.12 패키지란?

=>클래스를 기능별로 묶어서 그룹 이름을 붙여 놓은 것

==>파일들을 관리하기 위해 사용하는 폴더(디렉토리)와 비슷한 개념

==>패키지의 물리적인 형태는 파일 시스템의 폴더

=>클래스 이름의 일부

==>클래스를 유일하게 만들어주는 식별자

==>전체 클래스 이름 = 상위패키지.하위패키지.클래스

==>클래스명이 같아도 패키지명이 다르면 다른 클래스로 취급

패키지명 + 클래스명

 

패키지가 중요한 이유는 클래스만 따로 복잡해서 다른 곳으로 이동하면 클래스는 사용할 수 없기 때문이다.

 

v  패키지란?

§  클래스 선언할 때 패키지 결정

      클래스 선언할 때 포함될 패키지 선언

      클래스 파일은(~.class) 선언된 패키지와 동일한 폴더 안에서만 동작

      클래스 파일은(~.class) 다른 폴더 안에 넣으면 동작하지 않음

 

 

6.12.1 패키지 선언

클래스를 컴파일하는 과정에서 자동적으로 생성되는 폴더

컴파일러는 클래스에 포함되어 있는 패키지 선언을 보고 파일 시스템의 폴더로 자동 생성

 

패키지 선언 방법

package 상위패키지.하위패키지;

public class ClassName { ... }

 

패키지 이름은 개발자가 임의대로 지어주면 되지만 여기에도 지켜야 할 몇가지 규칙이 있습니다.

- 숫자로 시작해서는 안되고 특수문자는 $ _ 만 사용.

- java로 시작하는 패키지는 자바 표준 API에서만 사용하므로 사용해서는 안됨.

- 모두 소문자로 작성하는 것이 관례.

 

도메인은 등록 기관에서 유일한 이름이 되도록 검증되었기 떄문에 ,도메인 이름으로 패키지를 만들면 다른 회사의 패키지와 중복되는 경우가 발생하지 않는다.

com.samsung.projetname

com.hyndai.projectname

com.lg.projectname

org.apache.projectname

 

6.12.2 패키지 선언이 포함된 클래스 컴파일

javac -d . ClassName.java <- 현재 폴더 내에 생성

 

 

 

6.12.3 이클립스에서 패키지 생성과 클래스 생성

패키지 생성

프로젝트의 src폴더를 선택하고 메뉴에서 [File ->New ->Package]

마우스 오늘똑 버튼을 클릭해서 [ New->Package]를 선택해도 좋다.

 

6.12.4 import

패키지 내에 같이 포함된 클래스간 클래스 이름으로 사용 가능

=>패키지가 다른 클래스를 사용해야 할 경우

==>패키지 명 포함된 전체 클래스 이름으로 사용

 

==>Import 문으로 패키지를 지정하고 사용

 

 

import com.mycompany.*;

import com.mycompany.project.*;

 

 

다음 예제는 서로 다른 패키지에 소속된 Tire클래스를 사용:

 

[Car.java] import

package textbook.chapter6.mycompany;

 

import textbook.chapter6.hanbook.SnowTire;

import textbook.chapter6.hyndai.Engine;

import textbook.chapter6.kumbo.BigWidthTire;

 

public class Car {

 

           //필드

           Engine engine = new Engine();

           SnowTire tire1= new SnowTire();

           BigWidthTire tire2 = new BigWidthTire();

           textbook.chapter6.hanbook.Tire tire3 = new textbook.chapter6.hanbook.Tire();

           textbook.chapter6.kumbo.Tire tire4 = new textbook.chapter6.kumbo.Tire();

}

 

6.13 접근 제한자(Access Modifier)

클래스 및 클래스의 구성 멤버에 대한 접근을 제한하는 역할

      다른 패키지에서 클래스를 사용하지 못하도록 (클래스 제한)

      클래스로부터 객체를 생성하지 못하도록 (생성자 제한)

      특정 필드와 메소드를 숨김 처리 (필드와 메소드 제한)

§  접근 제한자의 종류

 

 

6.13.1 클래스의 접근 제한

 

클래스에 적용할 수 있는 접근 제한은 publicdefault단 두가지인데

//defautl접근 제한

class 클래스 {...}

 

//public 접근 제한

public class 클래스

 

=>default

클래스 선언할 때 public 생략한 경우

다른 패키지에서는 사용 불가

 

=>public

다른 개발자가 사용할 수 있도록 라이브러리 클래스로 만들 때 유용

제한 없이 사용할 수 있다.

인터넷으로 배포되는 라이브러리 클래스들도 모두 public 접근 제한을 가지고 있다.

 

 

 

[A.java] 클래스의 접근 제한

package textbook.chapter6.exam01_class_acess.package1;

 

class A {} //default 접근 제한

 

 

[B.java] 클래스의 접근 제한

package textbook.chapter6.exam01_class_acess.package1;

 

public class B {

           A a; //A클래스 접근 가능(필드로 선언할 수 있음)

}

 

 

[C.java] 클래스의 접근 제한

package textbook.chapter6.exam01_class_acess.package2;

 

import textbook.chapter6.exam01_class_acess.package1.B;

 

public class C {

           A a; //A클래스 접근 불가능(컴파일 에러)

           B B;

}

 

6.13.2 생성자 접근 제한

§  생성자가 가지는 접근 제한에 따라 호출 여부 결정

§  필드와 메소드의 접근 제한 (p.262~264)

§  클래스 내부, 패키지 내, 패키지 상호간에 사용할 지 고려해 선언

객체를 생성하기 위해서는 new 연산자로 생성자를 호출해야 합니다

생성자를 어디에서나 호출할 수 있는 것은 아닙니다

생성자라 어떤 접근 제한을 갖느냐에 따라 호출 가능 여부가 결정됩니다.

생성자는 아래와 같이 public, protected, default, private 접근 제한을 가질 수 있습니다.

 

 

public class ClassName {

    //public 접근 제한

      public ClassName(...) { ... }

    //protected 접근 제한

      protected ClassName(...) { ... }

    //default 접근 제한

      ClassName(...) { ... }

    //private 접근 제한

      private ClassName(...) { ... }

}

 

클래스에 생성자를 선언하지 않았을 때 자동으로 선언되는 기본 생성자는 클래스와 같은 접근 제한을 가집니다.

접근 제한자 

생성자

설명

 public

클래스( ... ) 

public 접근 제한은 모든 패키지에서 아무런 제한 없이 생성자를 호출할 수 있도록 합니다. 생성자가 public 접근 제한을 가진다면 클래스도 public 접근 제한을 가지는 것이 정상적입니다. 클래스가 default 접근 제한을 가진다면 클래스 사용이 같은 패키지로 한정되므로, 비록 생성자가 public 접근 제한을 가지더라도 같은 패키지에서만 생성자를 호출할 수 있습니다

protected

클래스( ... ) 

protected 접근 제한은 default 접근 제한과 마찬가지로 같은 패키지에 속하는 클래스에서 생성자를 호출할 수 있도록 합니다. 차이점은 다른 패키지에 속한 클래스가 해당 클래스의 자식(child)클래스라면 생성자를 호출할 수 있습니다.

default

클래스( ... ) 

생성자를 선언할 때 public 또는 private 를 생략 했다면 생성자는 default 접근 제한을 가집니다. default 접근 제한은 같은 패키지에서는 아무런 제한 없이 생성자를 호출할 수 있으나, 다른 패키지에서는 생성자를 호출할 수 없도록 합니다

private

클래스( ... ) 

private 접근 제한은 동일 패키지이건 다른 패키지이건 상관없이 생성자를 호출하지 못하도록 제한합니다. , 클래스 외부에서 new 연산자로 객체를 만들 수 없습니다. 오로지 클래스 내부에서만 생성자를 호출할 수 있고, 객체를 만들 수 있습니다


[A.java] 생성자의 접근 제한

 

package textbook.chapter6.exam02_constructor_acess.package1;

 

public class A {

           //필드

            A a1 = new A(true);

            A a2 = new A(1);

            A a3 = new A("문자열");

 

            //생성자

            public A(boolean b) {} //public 접근 제한

            A(int b) {}                                //default 접근 제한

            private A(String s) {} //private 접근 제한

}

 

 

[B.java] 생성자의 접근 제한

package textbook.chapter6.exam02_constructor_acess.package1;//패키지 동일

 

public class B {

           // 필드

           A a1 = new A(true);

           A a2 = new A(1); // A클래스와 같은 패키지이므로 default 생성자 호출가능.

           // A a3 = new A("문자열"); //private 생성자 접근 불가(컴파일 에러)

}

 

 

[C.java] 생성자의 접근 제한

package textbook.chapter6.exam02_constructor_acess.package2;

 

import textbook.chapter6.exam02_constructor_acess.package1.A;

 

public class C {

             //필드

            A a1 = new A(true);     

            //A a2 = new A(1); //default 다른 패키지이므로 default 생성자 호출 불가. 

            //A a3 = new A("문자열");  //private 생성자이므로 접근 불가

 

}

 

가끔 전체 프로그램에서 단 하나의 객체만 만들도록 보장해야 하는 경우가 있다. 이럴 경우 여러 개의 객체를 만들지 못하도록 설계해야 하는데 이것을 싱글톤 패턴이라고 한다.

싱글톤 패턴은 생성자를 private접근제한으로 선언하고 ,자신의 유일한 객체를 리턴하는 getInstance() 정적 메소드를 선언하는 것을 말한다.

 

6.13.3 필드와 메소드의 접근 제한

필드와 메서드를 선언할 때 고려해야 할 사항은 클래스 내부에서만 사용할 것인지

패키지 내에서만 사용할 것인지, 아니면 다른 패키지에서도 사용할 수 있도록 할 것인지를 결정해야 합니다

이것은 필드와 메서드가 어떤 접근 제한을 갖느냐에 따라 결정됩니다.

 

 

필드와 메서드는 public, protected, default, private 접근 제한을 가질 수 있습니다.

//필드 선언

[ public | protected | private ] [static] 타입 필드;

 

//메소드 선언

[ public | protected | private ] [static] 리턴 타입 메소드( ... ) { ... }

 

접근 제한자 

생성자

설명

 public

필드

메소드 ( ... )

public 접근 제한은 모든 패키지에서 아무런 제한 없이 필드와 메소드를 사용할 수 있도록 해줍니다. 필드와 메소드가 public 접근 제한을 가질 경우 클래스도 public 접근 제한을 가져야 합니다. 클래스가 default 접근 제한을 가지게 되면 같은 패키지 안에서만 클래스가 사용되기 때문입니다

protected

필드

메소드 ( ... )

protected 접근 제한은 default 접근 제한과 마찬가지로 같은 패키지에 속하는 클래스에서 필드와 메소드를 사용할 수 있도록 합니다. 차이점은, 다른 패키지에 속한 클래스가 해당 클래스의 잣기 클래스라면 필드와 메소드를 사용할 수 있습니다

default

필드

메소드 ( ... )

필드와 메소드를 선언할 때 public 또는 private 를 생략했다면 default 접근제한을 가진다. default 접근 제한은 같은 패키지에서는 아무런 제한 없이 필드와 메소드를 사용할 수 있으나, 다른 패키지에서는 필드와 메소드를 사용할 수 없도록 한다

private

필드

메소드 ( ... )

private 접근 제한은 동일 패키지이건 다른 패키지이건 상관 없이 필드와 메소드를 사용하지 못하도록 제한합니다. 오로지 클래스 내부에서만 사용할 수 있습니다

 

 

[A.java] 필드와 메소드의 접근 제한

package textbook.chapter6.field_method_access.package1;

 

public class A {

           // 필드

           public int field1; //public 접근 제한

           int field2;                     //default 접근 제한

           private int field3; //private 접근 제한

 

           // 생성자

           public A() {

                       field1 = 1;

                       field2 = 1;

                       field3 = 1;

                       // 클래스 내부일 경우 접근 제한자의 영향을 받지 않습니다.

                       method1();

                       method2();

                       method3();

           }

          

           //메소드

           public void method1() {}//public 접근 제한

           void method2() {}//default 접근 제한

           private void method3() {}//private 접근 제한

}

 

[B.java] 필드와 메소드의 접근 제한

 

package textbook.chapter6.field_method_access.package1;//패키지가 동일

 

public class B {

           public B() {

                       A a = new A();

                       a.field1 = 1;

                       a.field2 = 1;

                       // a.field3 = 1;// private 필드와 메서드 접근 불가.

                      

                       a.method1();

                       a.method2();

                       // a.method3();// private 필드와 메서드 접근 불가.

           }

}

 

[C.java] 필드와 메소드의 접근 제한

 

package textbook.chapter6.field_method_access.package2;

 

import textbook.chapter6.field_method_access.package1.A;

 

public class C {

           public C() {

                       A a = new A();

                       a.field1 = 1;

                       // a.field2 = 1;// default 필드 접근 불가(컴파일 에러)

                       // a.field3 = 1;// private 필드 접근 불가(컴파일 에러)

                      

                       // public 필드와 메서드만 접근 가능.

                       a.method1();

                       // a.method2();// default 필드 접근 불가(컴파일 에러)

                       // a.method3();// private 필드 접근 불가(컴파일 에러)

           }

}

 

6.14 GetterSetter 메소드

일반적으로 객체 지향 프로그래밍에서 객체의 데이터는 객체 외부에서 직접적으로 접근하는 것을 막습니다.

객체의 데이터를 외부에서 마음대로 읽고 변경할 경우 객체의 무결성이 깨어질 수 있기 때문입니다.

 

예를 들어 자동차의 속도는 음수가 될 수 없는데 외부에서 음수로 변경하면 무결성이 깨집니다

myCar.speed = -100;

 

이러한 문제점 해결을 위해 메서드를 통해 데이터를 변경하는 방법을 선호합니다

데이터는 외부에서 접근할 수 없도록 막고 메서드는 공개해서 

외부에서 메서드를 통해 데이터에 접근하도록 유도하는 것입니다

메서드는 매개값을 검증해서 유효한 값만 데이터로 저장할 수 있기 때문

 

이런 역할을 하는 메서드가 Setter입니다

void setSpeed(double speed) {

    if(speed<0) {

      this.speed = 0;

     return;    

     }

    else {

     this.speed = speed;

     }

 }


외부에서 객체의 데이터를 읽을  때도 메서드를 사용하는 것이 좋습니다

객체 외부에서 객체의 필드값을 사용하기에 부적절한 경우도 있습니다

이런 경우에 메서드로 필드값을 가공한 후 외부로 전달하면 됩니다

이 메서드가 Getter 메서드입니다.

 

double getSpeed() {

    double km = speed *1.6; 필드값인 마일을 km 단위로 환산 후 외부로 리턴

    return km;

  }


클래스를 선언할 때 가능하다면 필드를 private 로 선언해서 외부로부터 보호하고

필드에 대한 Setter Getter 메서드를 작성해서 필드값을 안전하게 변경/사용하는 것이 좋습니다

 

아래 코드는 Setter Getter 메서드를 선언하는 방법을 보여주는 코드입니다.

 

 

private 타입 fieldName;//필드 접근 제한자 :private

 

 

//Getter

public 리턴타입 getFieldName(){

    return fieldName;

 }

 

 

//Setter

public void setFieldName(타입 fieldName) {

   this.fieldName = fieldName;

 }

필드 타입이 boolean 이라면 Getter get으로 시작하는 것이 아니라 is 로 시작하는 것이 관례입니다.

 

 

private boolean stop; //필드 접근 제한자 :private

 

 

//Getter

public boolean isStop() {

   return stop;

 }

 

 

//Setter

public void setStop(boolean stop) {

    this.stop = stop;

 }

만약 외부에서 필드값을 읽을 수만 있고 변경하지 못하도록(읽기 전용)하려면 

Getter 메서드만 선언해도 되고, 아니면 Setter 메서드를 private 접근 제한을 갖도록 선언해도 좋습니다.

이클립스는 선언된 필드에 대해 자동적으로 Getter Setter 메서드를 생성시키는 기능이 있습니다.

필드를 선언한 후 메뉴에서 Source -> Generate Getters and Setters 를 선택하면 

선언된 필드에 대한 Getter Setter 를 자동 생성시킬 수 있습니다.

 

[Car8.java] GetterSetter 메소드 선언

 

public class Car8 {

 

           // 필드

           private int speed;

           private boolean stop;

 

           // 생성자

 

           // 메소드

           public int getSpeed() {

                       return speed;

           }

 

           public void setSpeed(int speed) {

                       if (speed < 0) {

                                  this.speed = 0;

                                  return;

                       } else {

                                  this.speed = speed;

                       }

           }

 

           public boolean isStop() {

                       return stop;

           }

 

           public void setStop(boolean stop) {

                       this.stop = stop;

                       this.speed = 0;

           }

}

[
CarExample8.java] GetterSetter 메소드 사용

 

public class CarExample8 {

           public static void main(String[] args) {

                       Car8 myCar = new Car8();

 

                       // 잘못된 속도 변경

                       myCar.setSpeed(-50);

 

                       System.out.println("현재 속도: " + myCar.getSpeed());

 

                       // 올바른 속도 변경

                       myCar.setSpeed(60);

 

                       // 멈춤

 

                       if (!myCar.isStop()) {

                                  myCar.setStop(true);

                       }

 

                       System.out.println("현재 속도: " + myCar.getSpeed());

           }

}

 

v  클래스 선언할 때 필드는 일반적으로 private 접근 제한

§  읽기 전용 필드가 있을 수 있음 (Getter의 필요성)

§  외부에서 엉뚱한 값으로 변경할 수 없도록 (Setter의 필요성)

§  Getter

§  private 필드의 값을 리턴 하는 역할 - 필요할 경우 필드 값 가공

§  getFieldName() 또는 isFieldName() 메소드

v  필드 타입이 boolean 일 경우 isFieldName()

v  Setter

§  외부에서 주어진 값을 필드 값으로 수정

v  필요할 경우 외부의 값을 유효성 검사

§  setFieldName(타입 변수) 메소드

v  매개 변수 타입은 필드의 타입과 동일

 

6.15 어노테이션

=>어노테이션(Annotation)이란?

§  프로그램에게 추가적인 정보를 제공해주는 메타데이터(metadata)

@AnnotationName

§  어노테이션 용도

v  컴파일러에게 코드 작성 문법 에러 체크하도록 정보 제공

v  소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동 생성하게 정보 제공

v  실행 시(런타임시) 특정 기능 실행하도록 정보 제공

 

컴파일러에게 코드 문법 에러를 체크하도록 정보를 제공하는 대표적인 예는 @Override 어노테이션입니다.

@Override 는 메서드 선언 시 사용, 메서드가 오버라이드(재정의)된 것임을 

컴파일러에게 알려주어 컴파일러가 오버라이드 검사를 하도록 합니다

정확히 오버라이드가 되지 않았다면 컴파일러는 에러를 발생시킵니다

어노테이션은 빌드 시 자동으로 XML 설정 파일을 생성하거나

배포를 위해 JAR 압축 파일을 생성하는데에도 사용됩니다

그리고 실행 시 클래스의 역할을 정의하기도 합니다.



6.15.1 어노테이션 타입 정의와 적용

=>어노테이션 타입 정의

소스 파일 생성: AnnotatoinName.java

v  소스 파일 내용

    • 어노테이션 타입 적용

 

 

어노테이션은 엘리먼트(element)를 멤버로 가질 수 있습니다.

 

 각 엘리먼트는 타입과 이름으로 구성되고, 디폴드 값을 가질 수 있습니다.

public @interface AnnotationName {

  타입 elementName() [default ];

  ...

}

 

엘리먼트의 타입으로는 기본타입이나 String, 열거타입, Class타입 그리고 이들의 배열 타입을 사용있음.

엘리먼트 이름 뒤에는 ()를 붙어야함.

public @interface AnnotationName {

 String elementName1();

 int elementName2() default 5;

}

 

 

이렇게 정의한 어노테이션을 코드에서 적용할 때는 아래와 같이 합니다.

@AnnotationName(elementName1="" , elementName2=3);

또는

@AnnotationName(elementName1="");

 

elementName1은 디폴트 값이 없으므로 반드시 값을 기술해야 하고

elementName2는 디폴트 값이 있으므로 생략가능.

 

v  기본 엘리먼트 value

    • 어노테이션 적용할 때 엘리먼트 이름 생략 가능

    • 두 개 이상의 속성을 기술할 때에는 value=값 형태로 기술

6.15.2어노테이션 적용 대상

§  코드 상에서 어노테이션을 적용할 수 있는 대상

§  java.lang.annotation.ElementType 열거 상수로 정의

 

 

어노테이션 적용대상을 지정할 때에는 @Target 어노테이션을 사용

@Target의 기본 엘리먼트인 value ElementType 배열을 값으로 가집니다

어노테이션이 적용될 대상을 복수 개로 지정하기 위해서입니다.

 

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})

pubilc @interface AnnotationName{

}

 

 

아래 처럼 클래스, 필드, 메서드만 어노테이션을 적용할 수 있고 생성자는 적용할 수 없습니다.

@AnnotationName

public class ClassName{

    @AnnotationName

    private String fieldName;

 

   //@AnootationName (x)  @Target CONSTRUCTOR 가 없어서 생성자는 적용할 수 없습니다.

   public ClassName() { }

 

  @AnnotationName

  public void methodName() { }

}

 

6.15.3어노테이션 유지 정책

§  어노테이션 적용 코드가 유지되는 시점을 지정하는 것

§  java.lang.annotation.RetentionPolicy 열거 상수로 정의

 

      리플렉션(Reflection): 런타임에 클래스의 메타 정보를 얻는 기능

클래스가 가지고 있는 필드, 생성자, 메소드, 어노테이션의 정보를 얻을 수 있음

런타임 시 어노테이션 정보를 얻으려면 유지 정책을 RUNTIME으로 설정

 

어노테이션 유지 정책을 지정할 때는 @Retention어노테이션을 사용한다.

@Retention의 기본 엘리먼트인 valueRetentionPolicy 타입이므로 위 세 가지 상수 중 하나를 지정.

코드 자동 생성 툴을 개발하지 않는 이상작성하는 어노테이션은 대부분 런타임 시점에 사용하기 위한 용도

 

 

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface AnnotationName {

}

 

6.15.4런타임시 어노테이션 정보 사용하기

§  클래스에 적용된 어노테이션 정보 얻기

      클래스.class 의 어노테이션 정보를 얻는 메소드 이용

§  필드, 생성자, 메소드에 적용된 어노테이션 정보 얻기

      다음 메소드 이용해 java.lang.reflect 패키지의 Field, Constructor, Method 클래스의 배열 얻어냄

 

§  Field, Constructor, Method가 가진 다음 메소드 호출

      어노테이션 정보를 얻기 위한 메소드

어노테이션 자체는 표식일 뿐이지만, 리플랙션을 이용해서 어노테이션의 적용 여부와 엘리먼트 값을 읽고 적절히 처리할 수 있습니다. 클래스에 적용된 어노테이션 정보를 얻으려면 java.jang.Class를 이용하면 되지만, 필드, 생성자, 메서드에 적용된 어노테이션 정보를 얻으려면 Class의 다음 메서드를 통해서 java.lang.reflect 패키지의 Field, Constructor, Method 타입의 배열을 얻어야 합니다.

 

[PrintAnnotation] 에노테이션 정의

@Target({ElementType.METHOD})//메소드에만 적용하도록 했고

@Retention(RetentionPolicy.RUNTIME)//런타임 시까지 어노테이션 정보를 유지하도록 했다

public @interface PrintAnnotation {

           String value() default "-";//기본 엘리먼트 value는 구분선에 사용될 문자

           //각각 디폴트 값으로 "-" 15를 주었다.

           int number() default 15;//반복 출력 횟수

}

 

[Service.java] 어노테이션 적용 클래스

public class Service {

           @PrintAnnotation//엘레먼트의 기본값으로 적용했고

           public void method1() {

                       System.out.println("실행 내용1");

           }

 

           @PrintAnnotation("*")//엘레먼트의 value값을 "*"로 설정

           public void method2() {

                       System.out.println("실행 내용2");

           }

 

           @PrintAnnotation(value = "#", number = 20)

           //엘레먼트의 value값을 "#"으로 설정 ,number값을 20으로 설정

           public void method3() {

                       System.out.println("실행 내용3");

           }

}

 

[PrintAnnotationExample.java]

public class PrintAnnotationExample {

           public static void main(String[] args) {

                       //servive클래스로부터 메소드 정보를 얻음

                       //sevice 클래스에 선언된 메소드 얻기(리플렉션)

                       Method[] declaredMethods = Service.class.getDeclaredMethods();

                      

                       //Method 객체를 하나씩 처리

                       for(Method method:declaredMethods) {

                                  //printAnnotation이 적용되었는지 확인

                                  if(method.isAnnotationPresent(PrintAnnotation.class)) {

                                              //PrintAnnotation 객체 얻기

                                              PrintAnnotation printAnnotation = method.getAnnotation(PrintAnnotation.class);

                                             

 

                                              //메소드 이름 출력

                                              System.out.println("[" + method.getName() +"]");

                                              //구분선 출력

                                              for(int i = 0; i <printAnnotation.number() ; i++) {

                                                         System.out.print(printAnnotation.value());

                                              }

                                              System.out.println();

                                             

                                              try {

                                                         //메소드 출력

                                                         method.invoke(new Service());

                                              }catch(Exception e) {

                                                         System.out.println();

                                              }

                                  }

                       }

           }

}

 

 

 

연습문제

1. 객체와 클래스에 대한 설명으로 틀린 것은 무엇입니까? (3)

 

1. 클래스는 객체를 생성하기 위한 설계도 (청사진)와 같은 것이다.

2. new 연산자로 클래스의 생성자를 호출함으로써 객체가 생성된다.

3. 하나의 클래스로 하나의 객체만 생성할 수 있다.

4. 객체는 클래스의 인스턴스이다.

 

2. 클래스의 구성 멤버가 아닌 것은 무엇입니까? (4)

1. 필드 (field)

2. 생성자 (constructor)

3. 메소드 (method)

4. 로컬 변수 (local variable)

 

3. 필드 , 생성자 , 메소드에 대한 설명으로 틀린 것은 무엇입니까? (4)

1. 필드는 객체의 데이터를 저장한다.

2. 생성자는 객체의 초기화를 담당한다.

3. 메소드는 객체의 동작 부분으로, 실행 코드를 가지고 있는 블록이다.

4. 클래스는 반드시 필드와 메소드를 가져야 한다.

 

4. 필드에 대한 설명으로 틀린 것은 무엇입니까? (3)

1. 필드는 메소드에서 사용할 수 있다.

2. 인스턴스 필드 초기화는 생성자에서 할 수 있다.

3. 필드는 반드시 생성자 선언 전에 선언되어야 한다.

4. 필드는 초기값을 주지 않더라도 기본값으로 자동 초기화된다.

 

5. 생성자에 대한 설명으로 틀린 것은 무엇입니까? (1)

1. 객체를 생성하려면 생성자 호출이 반드시 필요한 것은 아니다.

2. 생성자는 다른 생성자를 호출하기 위해 this ()를 사용할 수 있다.

3. 생성자가 선언되지 않으면 컴파일러가 기본 생성자를 추가한다.

4. 외부에서 객체를 생성할 수 없도록 생성자에 private 접근 제한자를 붙일 수 있다.

 

6. 메소드에 대한 설명으로 틀린 것은 무엇입니까? (4)

1. 리턴값이 없는 메소드는 리턴 타입을 void로 해야 한다.

2. 리턴 타입이 있는 메소드는 리턴값을 지정하기 위해 반드시 return문이 있어야 한다.

3. 매개값의 수를 모를 경우 "..."를 이용해서 매개 변수를 선언할 수 있다.

4. 메소드의 이름은 중복해서 선언할 수 없다.

 

7. 메소드 오버로딩에 대한 설명으로 틀린 것은 무엇입니까? (2)

1. 동일한 이름의 메소드를 여러 개 선언하는 것을 말한다.

2. 반드시 리턴 타입이 달라야 한다.

3. 매개 변수와 타입, , 순서를 다르게 선언해야 한다.

4. 매개값의 타입 및 수에 따라 호출될 메소드가 선택된다.

 

8. 인스턴스 멤버와 정적 멤버에 대한 설명으로 틀린 것은 무엇입니까? (2)

1. 정적 멤버는 static으로 선언된 필드와 메소드를 말한다.

2. 인스턴스 필드는 생성자 및 정적 블록에서 초기화될 수 있다.

3. 정적 필드와 정적 메소드는 객체 생성 없이 클래스를 통해 접근할 수 있다.

4. 인스턴스 필드와 메소드는 객체를 생성하고 사용해야 한다.

 

9. final 필드와 상수(static final)에 대한 설명으로 틀린 것은 무엇입니까? (2)

1. final 필드와 상수는 초기값이 저장되면 값을 변경할 수 없다.

2. final 필드와 상수는 생성자에서 초기화될 수 있다.

3. 상수의 이름은 대문자로 작성하는 것이 관례이다.

4. 상수는 객체 생성 없이 클래스를 통해 사용할 수 있다.

 

10. 패키지에 대한 설명으로 틀린 것은 무엇입니까? (4)

1. 패키지는 클래스들을 그룹화시키는 기능을 한다.

2. 클래스가 패키지에 소속되려면 패키지 선언을 반드시 해야 한다.

3. import문은 다른 패키지의 클래스를 사용할 때 필요하다.

4. mycompany 패키지에 소속된 클래스는 yourcompany에 옮겨 놓아도 동작한다.

 

11. 접근 제한에 대한 설명으로 틀린 것은 무엇입니까? (3)

1. 접근 제한자는 클래스, 필드, 생성자, 메소드의 사용을 제한한다.

2. public 접근 제한은 아무런 제한 없이 해당 요소를 사용할 수 있게 한다.

3. default 접근 제한은 해당 클래스 내부에서만 사용을 허가한다.

4. 외부에서 접근하지 못하도록 하려면 private 접근 제한을 해야 한다.

 

12. 다음 클래스에서 해당 멤버가 필드, 생성자, 메소드 중 어떤 것인지 빈칸을 채우세요.

public class Member {

private String name;                            // 필드

 

public Member(String name) {...}            // 생성자

 

public void setName(String name) {...}     // 메소드

}

 

13. 현실 세계의 회원을 Member 클래스로 모델링하려고 합니다. 회원의 데이터로는 이름, 아이디, 패스워드, 나이가 있습니다. 이 데이터들을 가지는 Member 클래스를 선언해보세요.

[Member.java]

public class Member {

           //작성 위치

           private String name;

           private String id;

           private String password;

           private int age;

}

 

14. 위에서 작성한 Member 클래스에 생성자를 추가하려고 합니다. 다음과 같이 Member 객체를 생성할 때 name 필드와 id 필드를 외부에서 받은 값으로 초기화하려면 생성자를 어떻게 선언해야 합니까?

Member user1 = new Member("홍길동","hong");

Member user2 = new Member("강자바","java");

[Member.java]

public class Member {    

           //작성위치

           Member(String name, String id) {

                      

           }

}

 

15. MemberService 클래스에 login() 메소드와 logout() 메소드를 선언하려고 합니다. login() 메소드를 호출할 때에는 매개값으로 idpassword를 제공하고, logout() 메소드는 id만 매개값으로 제공합니다. MemberService 클래스와 login(),logout() 메소드를 선언해보세요.

1. login() 메소드는 매개값 id "hong" , 매개값 password "12345"일 경우에만 true로 리턴하고 그 이외의 값일 경우에는 false를 리턴하도록 하세요.

2. logout() 메소드의 내용은 "로그아웃 되었습니다."가 출력되도록 하세요.

[MemberService.java]

public class MemberService {

           //작성위치

           public boolean login(String id, String password) {

                       if(id=="hong" && password=="12345") {

                                  return true;

                       }else {

                                  return false;

                       }

           }

          

           public void logout(String id) {

                       System.out.println("로그아웃 되었습니다.");

           }

}

 

[MemberServiceExample.java]

public class MemberServiceExample {

           public static void main(String[] args) {

                       MemberService memberService = new MemberService();

                       boolean result = memberService.login("hong", "12345");

                       if(result) {

                                  System.out.println("로그인 되였습니다.");

                                  memberService.logout("hong");

                       }else {

                                  System.out.println("id또는 password가 올바르지 않습니다.");

                       }

           }

}

 

16. PrinterExample 클래스에서 Printer 객체를 생성하고 println() 메소드를 호출해서 매개값을 콘솔에 출력하려고 합니다. println() 메소드의 매개값으로는 int,boolean,double,String 값을 줄 수 있습니다. Printer 클래스에서 println() 메소드를 선언해보세요.

 [Printer.java]

public class Printer {

           //작성 위치

           public void println(int a){

                       System.out.println(a);

           }

          

           public void println(boolean a){

                       System.out.println(a);

           }

          

           public void println(double a){

                       System.out.println(a);

           }

          

           public void println(String a){

                       System.out.println(a);

           }

}

 

 

[PrinterExample.java]

public class PrinterExample {

           public static void main(String[] args) {

                       Printer printer = new Printer();

                       printer.println(10);

                       printer.println(true);

                       printer.println(5.7);

                       printer.println("홍길동");

           }

}

 

17. 16번 문제에는 Printer 객체를 생성하고 println() 메소드를 생성했습니다. Printer 객체를 생성하지 않고 PrinterExample 클래스에서 다음과 같이 호출하려면 Printer 클래스를 어떻게 수정하면 될까요?

 

[Printer2.java]

public class Printer2 {

           //작성 위치

           public static void println(int a){

                       System.out.println(a);

          }

          

           public static void println(boolean a){

                       System.out.println(a);

           }

          

           public static void println(double a){

                       System.out.println(a);

           }

          

           public static void println(String a){

                       System.out.println(a);

           }

}

 [PrinterExample2.java]

public class PrinterExample2 {

           public static void main(String[] args) {

                       Printer2.println(10);

                       Printer2.println(true);

                       Printer2.println(5.7);

                       Printer2.println("홍길동");

           }

}

 

18. ShopService 객체를 싱글톤으로 만들고 싶습니다. ShopServiceExample 클래스에서 ShopService getInstance() 메소드로 싱글톤을 얻을 수 있도록 ShopService 클래스를 작성 해보세요.

[ShopService.java]

public class ShopService {

           private static ShopService singleton = new ShopService();

          

           private ShopService() {}

          

           static ShopService getInstance() {

                       return singleton;

           }

}

 

[ShopServiceExample.java]

public class ShopServiceExample {

           public static void main(String[] args) {

                       ShopService obj1 = ShopService.getInstance();

                       ShopService obj2 = ShopService.getInstance();                      

                       if(obj1 == obj2) {

                                  System.out.println("같은 ShopService 객체 입니다.");

                       }else {

                                  System.out.println("다른 ShopService 객체 입니다.");

                       }

           }

}

 

19. 은행 계좌 객체인 Account 객체는 잔고(balance) 필드를 가지고 있습니다. balance 필드는 음수값이 될 수 없고, 최대 백만 원까지만 저장할 수 있습니다. 외부에서 balance 필드를 마음대로 변경하지 못하도록 하고, 0 <= balance <= 1,000,000 범위의 값만 가질 수 있도록 Acoount 클래스를 작성해보세요.



1. Setter Getter를 이용하세요.

2. 0 1,000,000 MIN_BALANCE MAX_BALANCE 상수를 선언해서 이용하세요.

3. Setter의 매개값이 음수이거나 백만 원을 초과하면 현재 balance 값을 유지하세요.

 

 

[Account.java]

public class Account {

           //작성위치

           static final int MIN_BALANCE = 0;

           static final int MAX_BALANCE = 1000000;

          

           private int balance;

 

           public int getBalance() {

                       return balance;

           }

 

           public void setBalance(int balance) {

                       if(balance < MIN_BALANCE || balance > MAX_BALANCE) {

                                  return ;

                       }

                       this.balance = balance;

           }

}

 

 

[AccountExample.java]

public class AccountExample {

           public static void main(String[] args) {

 

                       Account account = new Account();

                      

                       account.setBalance(10000);

                       System.out.println("현재 잔고:" + account.getBalance());

                      

                       account.setBalance(-100);

                       System.out.println("현재 잔고:" + account.getBalance());

                      

                       account.setBalance(2000000);

                       System.out.println("현재 잔고:" + account.getBalance());

                      

                       account.setBalance(300000);

                       System.out.println("현재 잔고:" + account.getBalance());

           }

}

 

20. 다음은 키보드로부터 계좌 정보를 입력받아서, 계좌를 관리하는 프로그램입니다. 실행 결과를 보고, 알맞게 BankApplication 클래스의 메소드를 작성해보세요.

 

[Account2.java]

public class Account2 {

           private String ano;

           private String owner;

           private int balance;

          

           public Account2(String ano, String owner, int balance) {

                       this.ano = ano;

                       this.owner = owner;

                       this.balance = balance;

           }

 

           public String getAno() {

                       return ano;

           }

 

           public void setAno(String ano) {

                       this.ano = ano;

           }

 

           public String getOwner() {

                       return owner;

 

           }

 

           public void setOwner(String owner) {

                       this.owner = owner;

           }

 

           public int getBalance() {

                       return balance;

           }

 

           public void setBalance(int balance) {

                       this.balance = balance;

           }

          

}

 

 

[BankApplication.java]

public class BankApplication {

           private static Account2[] accountArray = new Account2[100];

           private static Scanner scanner = new Scanner(System.in);

 

           public static void main(String[] args) {

                       boolean run = true;

                       while (run) {

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

                                  System.out.println("1.계좌생성 | 2.계좌목록 | 3.예금 | 4.출금 | 5.종료");

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

                                  System.out.print("선택> ");

 

                                  int selectNo = scanner.nextInt();

 

                                  if (selectNo == 1) {

                                              createAccount();

                                  } else if (selectNo == 2) {

                                              accountList();

                                  } else if (selectNo == 3) {

                                              deposit();

                                  } else if (selectNo == 4) {

                                              withdraw();

                                  } else if (selectNo == 5) {

                                              run = false;

                                  }

                       }

                       System.out.println("프로그램 종료");

 

           }

 

           // 계좌 생성하기

           private static void createAccount() {

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

                       System.out.println("계좌생성");

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

 

                       System.out.print("계좌번호:");

                       String ano = scanner.next();

 

                       System.out.print("계좌주:");

                       String owner = scanner.next();

 

                       System.out.print("초기입금액:");

                       int balance = scanner.nextInt();

 

                       Account2 account = new Account2(ano, owner, balance);

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

                                  if (accountArray[i] == null) {

                                              accountArray[i] = account;

                                              System.out.println("결과 : 계좌가 생성되었습니다.");

                                              break;

                                  }

                       }

           }

 

           // 계좌 목록 보기

           private static void accountList() {

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

                       System.out.println("계좌목록");

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

 

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

                                  Account2 account = accountArray[i];

                                  if (accountArray[i] != null) {

                                              System.out.print(account.getAno());

                                              System.out.print("   ");

                                              System.out.print(account.getOwner());

                                              System.out.print("   ");

                                              System.out.print(account.getBalance());

                                              System.out.println();

                                  }

                       }

 

           }

 

           // 예금하기

           private static void deposit() {

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

                       System.out.println("예금");

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

                      

                       System.out.print("계좌번호:");

                       String ano = scanner.next();

 

                       System.out.print("예금액:");

                       int money = scanner.nextInt();

                      

                       Account2 account = findAccount(ano);

                      

                       if(account == null) {

            System.out.println("결과: 계좌가 없습니다.");

            return;

        }

                      

                       account.setBalance(account.getBalance() + money);

                       System.out.println("결과: 입금이 성공되었습니다.");

           }

 

           // 출금하기

           private static void withdraw() {

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

                       System.out.println("출금");

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

                      

                       System.out.print("계좌번호:");

                       String ano = scanner.next();

 

                       System.out.print("출금액:");

                       int money = scanner.nextInt();

                      

                       Account2 account = findAccount(ano);

                       if(account == null) {

            System.out.println("결과: 계좌가 없습니다.");

            return;

        }

                      

                       account.setBalance(account.getBalance() - money);

 

                       System.out.println("결과: 출금이 성공되었습니다.");

           }

 

           // Account 배열에서 ano동일한 Account 객체 찾기

           private static Account2 findAccount(String ano) {

                       Account2 account = null;

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

                                  if(accountArray[i]  != null) {

                                              if(accountArray[i].getAno().equals(ano)) {

                                                         account = accountArray[i];

                                                         break;

                                              }

                                  }

                       }

                       return account;

           }

}

 

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

08. 인터페이스  (0) 2020.09.30
07. 상속  (0) 2020.09.29
05. 참조 타입  (0) 2020.09.27
04. 조건문과 반복문  (0) 2020.09.26
03. 연산자  (0) 2020.09.24
반응형

출처 : 이것이 자바다

참조 타입

5.1 데이터 타입 분류

프로그램이 하는 일은 결국 데이터를 처리하는 것이다.

=> 데이터 타입 : 저장되는 값이 무엇이냐이다.

1) 기본 타입은 정수 ,실수, 문자 , 논리 리터럴을 저장하는 타입

byte, char, short, int, long, float, double, boolean을 이용해서 선언된 변수는 실제 값을 변수 안에 저장하지만,

2) 참조 타입인  객체(Object) 의 번지를 참조하는 타입으로

배열, 열거, 클래스, 인터페이스를 이용해서 선언된 변수는 메모리 번지를 값으로 갖는다.

   번지를 통해 객체를 참조한다는 뜻에서 참조 타입이라고 부른다.

 

변수가 스택 영역에 생성되고, 객체는 힙 영역에 생성된다

 

 

 

 

메모리상에서 이 변수들이 갖는 값을 그림으로 표현하면 오른쪽 그림이다.

변수가 스택 영역에 생성되고 객체는 힙 영역에 생성되는 것이다.

int double 변수인 ageprice는 직접 값을 저장하고 있지만 ,String클래스 변수인 namehobby는 힙 영역의 String 객체 주소 값을 가지고 있다. 주소를 통해 객체를 참조한다는 뜻에서 String 클래스 변수를 참조 타입 변수라고 한다.

 

5.2 메모리 사용 영역

JVM이 사용하는 메모리 영역

java.exeJVM은 운영체제에서 할당받은 메모리 영역(Runtime Data Area)을 다음과 같이 세부 영역으로 구분해서 사용한다.

 

5.2.1 메소드(Method) 영역

=>메소드 영역

메소드 영역에는 코드에서 사용되는 클래스(.~class)들을 클래스 로더로 읽어 클래스별로 런타임 상수풀(runtime constant pool),필드(field) 데이터, 메소드(Method) ,메소드 코드 , 생성자(constructor)코드 등을 분류해서 저장한다.

메소드 영역은 JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역이다.

JVM 시작할 때 생성

로딩된 클래스 바이트 코드 내용을 분석 후 저장

모든 스레드가 공유

 

=>힙 영역

객체와 배열이 생성되는 영역이다.

JVM 시작할 때 생성

객체/배열 저장

사용되지 않는 객체는 Garbage Collector 가 자동 제거

힙 영역에도 두가지가 있다.

 

=>JVM 스택

스레드 별 생성

추가적으로 스레드를 생성하지 않았담녀 main 스레드만 존재하므로 JVM스택도 하나이다.

메소드 호출할 때마다 Frame을 스택에 추가(push)

메소드 종료하면 Frame 제거(pop)

예외 발생시 printStackTrace()메소드로 보여주는 Stack Trace의 각 라인은 하나의 프레임을 표현한다. printStackTrace() 메소드는 예외 처리에서 설명한다.

프레임 내부에는 로컬 변수 스택이 있는데 , 기본 타입 변수와 참조 타입 변수가 추가 (push) 되거나 제거(pop)된다.변수가 이 영역에 생성되는 시점은 초기화가 될 때, 즉 최초로 변수에 값이 저장될 떄이다. 변수는 선언된 블록 안에서만 스택이 존재하고 블록을 벗어나면 스택에서 제거된다.

 

스택의 생성 및 소멸

 

기본 타입 변수는 스택 영역에 직접 값을 가지고 있지만  , 참조 타입 변수는 값이 아니라 힙 영역이나 메소드 영역의 객체 주소를 가진다.

 

배열 변수 scores에는 배열의 힙 영역의 주소가 저장된다.

 

 

5.3  참조 변수의  == , != 연산

변수의 값이 같은지 다른지 비교

=>기본 타입: byte, char, short, int, long, float, double, boolean

의미 : 변수의 값이 같은지 다른지 조사

=>참조 타입: 배열, 열거, 클래스, 인터페이스

의미 : 동일한 객체를 참조하는지 다른 객체를 참조하는지 조사

 

 

5.4 nullNullPointerException

=> null()

변수가 참조하는 객체가 없을 경우 초기값으로 사용 가능

참조 타입의 변수에만 저장가능

null로 초기화된 참조 변수는 스택 영역 생성

 

 

 

참조 타입 변수가 null값을 가지는지 확인하려면 다음과 같이 == , != 연산을 수행하면 된다.

 

 

 

=> NullPointerException의 의미

예외(Exception) : 자바는 프로그램 실행 도중에 발생하는 오류를 예외라고 부른다.

사용자의 잘못된 조작 이나 잘못된 코딩으로 인해 발생하는 프로그램 오류

NullPointerException

참조 변수가 null 값을 가지고 있을 때

객체의 필드나 메소드를 사용하려고 했을 때 발생

참조 타입 변수를 사용하는 것은 곧 객체를 사용하는 것을 의미하는데 , 참조할 객체가 없으므로 사용할 수 가 없는 것이다.

 

 

 

 

 

 

이유는 intArray변수가 참조하는 배열 객체가 없기 때문이다.

 

 

 

 

 

 

String은 클래스 타입이므로 참조 타입이다.참조하는 String객체가 없기 때문이다.

 

5.5 String타입

문자열을 저장하는 클래스 타입

String 변수;

큰 따옴표로 감싼 문자열 리터럴을 대입하면 된다.

변수 = "문자열";

 

변수 선언과 동시에 문자열을 저장할 수도 있다.

String 변수 = "문자열";

 

다음은 두 개의 String 변수를 선언하고 문자열을 저장한다.

 

 

 

 

 

 

 

문자열은 String 객체로 생성되고 변수는 String 객체를 참조한다.

 

문자열 리터럴 동일하다면 String 객체 공유

 

 

 

 

일반적으로 변수에 문자열을 저장할 경우에는 문자열 리터럴을 사용하지만 ,new 연산자를 사용해서 직접 String 객체를 생성시킬 수 도 있다. new연산자는 힙 영역에 새로운 객체를 만들 때 사용하는 연산자로 객체 생성 연산자라고 한다.

=>new 연산자를 이용한 String 객체 생성

힙 영역에 새로운 String 객체 생성

String 객체를 생성한 후 번지 리턴

 

 

 

문자열 리터럴로 생성하느냐 new연산자로 생성하느냐에 따라 비교 연산자의 결과가 달라질 수 있다.

 

 

String name1 = "신민철";

String name2 = "신민철";

String name3 = new String("신민철");

 

new 연산자는 힙 영역에 새로운 객체를 만들 때 사용하는 연산자로 객체 생성 연산자라고 한다.

== 연산자는 변수에 저장된 객체 번지가 동일한지를 검사한다.

equals() 메소드는 원본 문자열과 매개값으로 주어진 비교 문자열이 동일한지 비교한다.

JVM은 참조되지 않은 객체를 쓰레기 객체로 취급하고 쓰레기 수집기(Gabage Collector)를 구동시켜 메모리에서 자동 제거한다.

 

문자열은 String 객체로 생성되고 변수는 String 객체를 참조한다.

문자열 리터럴이 동일하다면 String 객체를 공유하도록 되어 있다.

equals()메소드는 원본 문자열과 매개값으로 주어진 비교 문자열이 동일한지 비교한 후 true또는 false를 리턴한다.

 

[StringEqualsExample.java]문자열 비교

public class StringEqualsExample {

       public static void main(String[] args) {

               String strVar1 = "신민철";

               String strVar2 = "신민철";

 

               if (strVar1 == strVar2) {

                      System.out.println("strVar1 strVar2 참조가 같음");

               } else {

                      System.out.println("strVar1 strVar2 참조가 다름");

               }

 

               if (strVar1.equals(strVar2)) {

                      System.out.println("strVar1 strVar2 참조가 문자열이 같음");

               }

 

               String strVar3 = new String("신민철");

               String strVar4 = new String("신민철");

 

               if (strVar3 == strVar4) {

                      System.out.println("strVar3 strVar4 참조가  같음");

               } else {

                      System.out.println("strVar3 strVar4 참조가  다름");

               }

 

               if (strVar3.equals(strVar4)) {

                      System.out.println("strVar3 strVar4 문자열이 같음");

               }

 

       }

}

 

== 연산자는 변수에 저장된 객체 번지가 동일한지를 검사한다

equals() 메소드는 문자열만을 비교한다

 

String 변수는 참조 타입이므로 초기값으로 null을 대입할 수 있다.

null String 변수가 참조하는 String 객체가 없다는 뜻이다.

ex)

String hobby = null;

 

다음 코드는 hobby 변수가 String 객체를 참조하였으나, null을 대입함으로써 더 이상 String 객체를 참조하지 않도록 할 수 있다.

참조를 잃는 String 객체는 JVM 쓰레기 객체로 취급하고 쓰레기 수집기를 구동시켜 메모리에서 자동 제거한다.

ex)

String hobby = "여행";

hobby = null;

 

 

5.6 배열 타입

5.6.1 배열이란 ?

변수는 한 개의 데이터만 저장할 수 있다. 따라서 저장해야 할 데이터의 수가 많아지면 그만큼 많은 변수가 필요하다.

 

성적

 

 

 

평균

 

 

 

위와 같은 방법은 매우 비효율적이고 지루한 코딩이 된다.

 

=>배열이란?

같은 타입의 데이터를 연속된 공간에 저장하는 자료구조

각 데이터 저장 위치는 인덱스(index) 부여해 접근

 

 

 

 
 

 

 

 

 

 

score[인덱스]

 

==>배열의 장점

중복된 변수 선언 줄이기 위해 사용

반복문 이용해 요소들을 쉽게 처리

 

배열은 선언과 동시에 저장할 수 있는 데이터 타입이 결정된다.

만약 다른 타입의 값을 저장하려고 하면 타입 불일치(Type mismatch)컴파일 오류가 발생한다.

배열의 또 다른 특징은 한번 생성된 배열은 길이를 늘리거나 줄일 수 없다.

 

5.6.2 배열 선언

배열을 사용하기 위해 우선 배열 변수 선언

두가지 형태:

타입[] 변수;        타입 변수[];

 

 

대괄호 []는 배열 변수를 선언하는 기호로 사용되는데 , 타입 뒤에 붙을 수도 있고 변수 뒤에 붙을 수도 있다.타입은 배열에 저장될 데이터의 타입을 말한다.

 

배열 변수는 참조 변수에 속한다.

배열도 객체이므로 영역에 생성되고 배열 변수는 영역의 객체를 참조하게 된다.

배열 변수는 참조 변수 - 배열 생성되기 전 null로 초기화 가능

타입[] 변수 = null;

배열 변수가 null 값을 가진 상태에서 항목에 접근 불가

변수[인덱스]” 못함

NullPointerException 발생

배열 변수는 배열을 생성하고 참조하는 상태에서 값을 저장하거나 읽어야 한다.

 

5.6.3 값 목록으로 배열 생성

배열 항목에 저장될 값의 목록이 있다면 ,다음과 같이 간단하게 배열 객체를 만들 수 있다.

변수 선언과 동시에 값 목록 대입

데이터 타입[] 변수 = { 0, 1, 2, 3, ... };

 

 

 

 

 

 

중괄호 {}는 주어진 값들을 항목으로 가지는 배열 객체를 힙에 생성하고 , 배열 객체의 번지를 리턴한다. 배열 변수는 리턴된 번지를 저장함으로써 참조가 이루어진다.

String[] names = {"신용권" , "홍길동", "감자바"};

값을 바꾸고 싶다면 다음과 같이 대입 연산자를 사용하면 된다.

names[1] = "홍삼원";

 

[ ArrayCreateByValueListExample1.java]값 목록으로 배열 생성

public class ArrayCreateByValueListExample1 {

 

       public static void main(String[] args) {

 

               int[] score = { 83, 90, 87 };

               System.out.println("score[0] : " + score[0]);

               System.out.println("score[1] : " + score[1]);

               System.out.println("score[2] : " + score[2]);

 

               int sum = 0;

               for (int i = 0; i < 3; i++) {

                      sum += score[i];

               }

 

               System.out.println("총합 : " + sum);

               double avg = (double) sum / 3;

               System.out.println("평균 : " + avg);

 

       }

}

 

변수 선언 후 값 목록 대입 -> 컴파일 에러

 

 

=>값 목록으로 배열 생성

배열 변수를 미리 선언한 후 , 값 목록들이 나중에 결정되는 상황이라면 new연산자를 사용하면 된다.

변수 = new 타입[]{ 0, 1, 2, 3, ... };

 

:

String[] names = null;

names = new String[]{"신용권" ,"홍길동" ,"감자바"};

 

메소드의 매개값이 배열일 경우에도 마찬가지이다.

add()메소드가 있을 경우 ,값 목록으로 배열을 생성함과 동시에 add()메소드의 매개값으로 사용하고자 할 떄는 반드시 new연산자를 사용해야 한다.

int add(int[] scores){ ... }

int result = add( {95, 85, 90} ) ;//컴파일 에러

int result = add( new int[] {95, 85, 90});

 

[ ArrayCreateByValueListExample2.java]값의 리스트로 배열 생성

public class ArrayCreateByValueListExample2 {

       public static void main(String[] args) {

               int[] scores;

               scores = new int[] { 83, 90, 87 };

               int sum1 = 0;

               for (int i = 0; i < 3; i++) {

                      sum1 += scores[i];

               }

 

               System.out.println("총합 : "+sum1);

               //리턴된 총합을 sum2 저장

               int sum2 = add(new int[] { 83, 90, 87 });

               System.out.println("총합 : "+sum2);

               System.out.println();

 

       }

      

       //총합을 계산해서 리턴하는 메소드

       public static int add(int[] scores) {

               int sum = 0;

               for (int i = 0; i < 3; i++) {

                      sum += scores[i];

               }

 

               return sum;

       }

}

 

5.6.4 new 연산자로 배열 생성

배열 생성시 값 목록을 가지고 있지 않음

향후 값들을 저장할 배열을 미리 생성하고 싶을 경우

 

타입[] 변수 = new 타입[길이];//길이는 배열이 저장할 수 있는 값의 수를 말한다.

 

타입[] 변수 = null;
변수 = new 타입[길이];

 

 

 
 

 

 

 

 

 

 

 

 

저장될 수 있는 공간을 확보하고 , 배열의 생성 번지를 리턴한다. 리턴된 번지는 intArray변수에 저장한다. 4byte이다.

 

new연산자로 배열을 처음 생성할 경우 ,배열은 자동적으로 기본값으로 초기화된다.

int [] scores = new int[30];

 

String배열

String[] names = new String[30];

 

==>타입별로 배열의 초기값:

 

 

 

 

 

 

 

 

 

new 연산자로 배열을 처음 생성할 경우, 배열은 자동적으로 기본값으로 초기화된다.

변수[인덱스] = ;

배열이 생성되고 나서 새로운 값을 저장하려면 대입 연산자를 사용하면 된다.

int [] scores = new int[3];

scores[0] = 83;

scores[1] = 90;

scores[2] = 75;

 

[ ArrayCreateByNewExample.java]new 연산자로 배열 생성

public class ArrayCreateByNewExample {

 

    public static void main(String[] args) {

 

        int[] arr1 = new int[3];

        for (int i = 0; i < 3; i++) {

            System.out.println("arr1[" + i + "] : " + arr1[i]);

        }

 

        arr1[0] = 10;

        arr1[1] = 20;

        arr1[2] = 30;

 

        for (int i = 0; i < 3; i++) {

            System.out.println("arr1[" + i + "] : " + arr1[i]);

               }

       

        double[] arr2 = new double[3];

        for (int i = 0; i < 3; i++) {

            System.out.println("arr2[" + i + "] : " + arr2[i]);

        }

 

        arr2[0] = 0.1;

        arr2[1] = 0.2;

        arr2[2] = 0.3;

 

        for (int i = 0; i < 3; i++) {

            System.out.println("arr2[" + i + "] : " + arr2[i]);

               }

       

        String[] arr3 = new String[3];

        for (int i = 0; i < 3; i++) {

            System.out.println("arr3[" + i + "] : " + arr3[i]);

        }

 

        arr3[0] = "1";

        arr3[1] = "2";

        arr3[2] = "3";

 

        for (int i = 0; i < 3; i++) {

            System.out.println("arr3[" + i + "] : " + arr3[i]);

               }

       }

}

 

5.6.5 배열 길이

배열에 저장할 수 있는 전체 항목 수

코드에서 배열의 길이 얻는 방법

 

:

 

 

배열의 길이는 읽기 전용

 

배열의 길이는 for문의 조건식에서 주로 사용

 

 

 

[ ArrayLengthExample.java]배열의 length 필드

public class ArrayLengthExample {

           public static void main(String[] args) {

                       int[] scores = { 83, 90, 87 };

 

                       int sum = 0;

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

                                  sum += scores[i];

                       }

                       System.out.println("총합 : " + sum);

 

                       double avg = (double) sum / scores.length;

                       System.out.println("평균 : " + avg);

           }

}

만약 배열의 인덱스를 초과해서 사용하면 ArrayIndexOutOfBoundsException 발생한다.

배열의 인덱스 범위는 0 ~ (길이-1)이다.

 

5.6.6 커맨드 라인 입력

main()메소드

public static void main(String[] args){ ... }

 

배열의 선언과 사용

"java 클래스" 프로그램을 실행하면JVM 길이가 0 String 배열을 먼저 생성하고 main() 메소드를 호출할 때매개값으로 전달한다.

 

문자열 목록으로 구성된 String[] 배열이 생성되고 main()메소드를 호출 할 때 매개값으로 전달된다.

 

[ MainStringArrayArgument.java]main() 메소드의 매개 변수

public class MainStringArrayArgument {

           public static void main(String[] args) {

                       if (args.length != 2) { // 입력된 데이터 개수가 2개가 아닐 경우

                                  System.out.println("프로그램의 사용법");

                                  System.out.println("java MainStringArrayArgument num1 num2");

                                  System.exit(0);

                       }

 

                       String strNum1 = args[0];

                       String strNum2 = args[1];

 

                       int num1 = Integer.parseInt(strNum1); // 문자열을 정수로 변환

                       int num2 = Integer.parseInt(strNum2);

 

                       int result = num1 + num2;

                       System.out.println(num1 + " + " + num2 + " = " + result);

           }

}

이클립스에서 프로젝트 오른쪽 마우스 클릭

Run ->Run Configurations

 

 

 

 

 

명령어 cmd에서

java MainStringArrayArgument 10 20

 

int 변수 Integer.parseInt("정수로 변환 가능한 문자열");

NumberFormatException

5.6.7 다차원 배열

=>2차원 배열 이상의 배열

수학의 행렬과 같은 자료 구조

 

 

자바는 1차원 배열을 이용해 2차원 배열 구현

값들이 행과 열로서 구성된 배열을 2차원 배열이라고 한다.

자바는 2차원 배열을 중첩 배열 방식으로 구현한다.

 

세계의 배열 객체를 생성한다.

 

일차원 배열이 서로 연결된 구조로 다차원 배열을 구현하기 때문에 수학 행렬 구조가 아닌 계단식 구조를 가질 있다

 

생성 원리는 수학 행렬과는 근복적으로 다르지만 사용 방식은 행렬과 동일하다.

int[][] scores = new int[2][];

scores[0] = new int[2];

scores[1] = new int[3];

 

주의할 점은 정확한 배열의 길이를 알고 인덱스를 사용해야 한다.

ArrayIndexOutOfBoundsException

int [][] scores = {{95, 80} , {92, 96}}

 

 

 

int score = scores[0][0]  ;//95

int score = scores[1][1] ; 96

 

[ ArrayInArrayExample.java]배열 속의 배열

public class ArrayInArrayExample {

           public static void main(String[] args) {

                       int[][] mathScores = new int[2][3];

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

                                  for (int k = 0; k < mathScores[i].length; k++) {

                                              System.out.println("mathScores[" + i + "][" + k + "]=" + mathScores[i][k]);

                                  }

                       }

                       System.out.println();

 

                       int[][] englishScores = new int[2][];

                       englishScores[0] = new int[2];

                       englishScores[1] = new int[3];

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

                                  for (int k = 0; k < englishScores[i].length; k++) {

                                              System.out.println("englishScores[" + i + "][" + k + "]=" + englishScores[i][k]);

                                  }

                       }

                       System.out.println();

 

                       int[][] javaScores = { { 95, 80 }, { 92, 96, 80 } };

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

                                  for (int k = 0; k < javaScores[i].length; k++) {

                                              System.out.println("javaScores[" + i + "][" + k + "]=" + javaScores[i][k]);

                                  }

                       }

           }

}

 

5.6.8 객체를 참조하는 배열

=>기본 타입(byte, char, short, int, long, float, double, boolean) 배열

각 항목에 직접 값을 가지고 있음

=>참조 타입(클래스, 인터페이스) 배열 - 각 항목에 객체의 번지 가짐

 

 

 

                       String[] strArray = new String[3];

                       strArray[0] = "Java";

                       strArray[1] = "Java";

                       strArray[2] = new String("Java");

 

                       System.out.println(strArray[0] == strArray[1]); //true(같은 객체를 참조)

                       System.out.println(strArray[0] == strArray[2]); //false (다른 객체를 참조)

                       System.out.println(strArray[0].equals(strArray[2]));//true (문자열이 동일)

 

[ArrayReferenceObjectExample.java]객체를 참조하는 배열

public class ArrayReferenceObjectExample {

       public static void main(String[] args) {

               String[] strArray = new String[3];

               strArray[0] = "Java";

               strArray[1] = "Java";

               strArray[2] = new String("Java");

 

               System.out.println(strArray[0] == strArray[1]);

               System.out.println(strArray[0] == strArray[2]);

              System.out.println(strArray[0].equals(strArray[2]));

       }

}

 

5.6.9 배열 복사

배열은 한 번 생성하면 크기 변경 불가

더 많은 저장 공간이 필요하다면 보다 큰 배열을 새로 만들고 이전 배열로부터 항목 값들을 복사

 

=>배열 복사 방법

    • for문 이용
    • System.arrayCopy() 메소드 이용
    • Arrays 클래스 이용

 

[ ArrayCopyByForExample.java]for문으로 배열 복사

public class ArrayCopyByForExample {

           public static void main(String[] args) {

                       int[] oldIntArray = { 1, 2, 3 };

                       int[] newIntArray = new int[5];

 

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

                                  newIntArray[i] = oldIntArray[i];

                       }

                      

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

                                  System.out.print(newIntArray[i] + ", ");

                       }

           }

}

 

System.arraycopy(Object src, int srcPos, Object dest, int destPos, int lengrh);

얕은 복사 (shallow copy) : 이전 항목이 참조하는 객체와 동일한 객체 참조

깊은 복사 (deep copy) : 참조하는 객체도 별도로 생성

 

[ ArrayCopyExample.java]System.arraycopy()로 배열 복사

public class ArrayCopyExample {

           public static void main(String[] args) {

                       String[] oldStrArray = { "java", "array", "copy" };

                       String[] newSrtArray = new String[5];

 

                       System.arraycopy(oldStrArray, 0, newSrtArray, 0, oldStrArray.length);

 

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

                                  System.out.print(newSrtArray[i] + ", ");

                       }

           }

}

 

5.6.10 향상된 for

배열 및 컬렉션(15장에서 다룸)의 항목 요소를 순차적으로 처리

인덱스 이용하지 않고 바로 항목 요소 반복

향상된 for문은 반복 실행을 하기 위해 카운터 변수와 증감식을 사용하지 않는다

배열 컬렉션 항목의 개수만큼 반복하고, 자동적으로 for문을 빠져나간다.

 

 

[ AdvancedForExample.java]향상된 for

public class AdvancedForExample {

           public static void main(String[] args) {

                       int[] scores = { 95, 71, 84, 93, 87 };

 

                       int sum = 0;

                       for (int score : scores) {

                                  sum = sum + score;

                       }

                       System.out.println("점수 총합 = " + sum);

 

                       double avg = (double) sum / scores.length;

                       System.out.println("점수 평균 = " + avg);

 

           }

}

 

5.7 열거 타입(Enumeration Type)

한정된 값만을 갖는 데이터 타입

한정된 값은 열거 상수(Enumeration Constant)로 정의

 

5.7.1 열거 타입 선언

열거 타입 이름으로 소스 파일(.java) 생성한다.

열거 타입 이름은 소스 파일명과 대소문자가 모두 일치해야 한다.

파일 이름과 동일한 이름으로 다음과 같이 선언 (첫 글자 대문자)

Week.java

MemberGrade.java

ProductKind.java

 

열거 타입 선언

 

 

=>한정된 값인 열거 상수 정의

열거 상수 이름은 관례적으로 모두 대문자로 작성

다른 단어가 결합된 이름일 경우 관례적으로 밑줄( _ )로 연결

 

 

 

Package Explorer 뷰에서 프로젝트를 선택한 다음 메뉴에서 [File -> New -> Enum]

 

[ Week.java]열거 타입 선언

public enum Week {

    MONDAY,

    TUESDAY,

    WEDNESDAY,

    THURSDAY,

    FRIDAY,

    SATURDAY,

    SUNDAY

}

 

5.7.2 열거 타입 변수

=>열거 타입 변수 선언

열거 타입도 하나의 데이터 타입이므로 변수를 선언하고 사용해야 한다.

 

 

=>열거 상수 값 저장 - 열거 타입 변수값은 열거 상수 중 하나

 

 

 

=>열거 타입 변수는 참조 타입

열거 타입 변수는 참조 타입이므로 null 값 저장 가능

 

 

열거 타입도 참조 타입이다, 열거 상수는 열거 객체로 생성된다.

그리고 메소드 영역에 생성된 열거 상수가 해당 Week객체를 각각 참조하게 된다.

 

 

 

열거 타입 변수느느 today는 스택 영역에 생성된다.

 

 

 

 

동일한 Week객체를 참조하기 때문이다.

 

 

자바는 컴퓨터의 날짜 및 요일,시간을 프로그램에서 사용할 수 있도록 하기 위해 Date,Calendar, LocalDateTime등의 클래스를 제공한다. LocalDateTime은 자바 8부터 지원하는 API이다.

 

Calendar 변수 선언

Calendar now = Calendar.getInstance();

 

int year = now.get ( Calendar.YEAR ); //

int month = now.get ( Calendar.MONTH ) + 1; //

int day = now.get ( Calendar.DAY_OF_MONTH ); //

int week = now.get(Calendar.DAY_OF_WEEK); //요일(1~7)

int hour = cal.get(Calendar.HOUR_OF_DAY);  //시간

int minute = cal.get(Calendar.MINUTE); //
int second = cal.get(
Calendar.SECOND);//

[
EnumWeekExample.java]열거 타입과 열거 상수

import java.util.Calendar;

 

public class EnumWeekExample {

           public static void main(String[] args) {

                       Week today = null; // 열거 타입 변수 선언

 

                       Calendar cal = Calendar.getInstance();

                       int week = cal.get(Calendar.DAY_OF_WEEK); // (1) ~ (7)까지의 숫자를 리턴

 

                       switch (week) {

                       case 1:

                                  today = Week.SUNDAY;

                                  break;

                       case 2:

                                  today = Week.MONDAY;

                                  break;

                       case 3:

                                  today = Week.TUESDAY;

                                  break;

                       case 4:

                                  today = Week.WEDNESDAY;

                                  break;

                       case 5:

                                  today = Week.THURSDAY;

                                  break;

                       case 6:

                                  today = Week.FRIDAY;

                                  break;

                       case 7:

                                  today = Week.SATURDAY;

                                  break;

                       }

 

                       System.out.println("오늘 요일: " + today);

 

 

 

                       if (today == Week.SUNDAY) {

                                  System.out.println("일요일에는 축구를 합니다.");

                       } else {

                                  System.out.println("열심히 자바 공부합니다.");

                       }

           }

}

 

 

5.7.3 열거 객체의 메소드

열거 객체는 열거 상수의 문자열을 내부 데이터로 가지고 있음

열거 타입은 컴파일 시 java.lang.Enum 클래스를 자동 상속

열거 객체는 java.lang.Enum  클래스의 메소드 사용 가능

 

 

 

=>name() 메소드

name() 메소드는 열거 객체가 가지고 있는 문자열을 리턴한다.

리턴 되는 문자열은 열거 타입을 정의할 때 사용한 상수 이름과 동일하다.

Week today = Week.SUNDAY;
String name = today.name();

 

=>ordinal() 메소드

ordinal() 메소드는 전체 열거 객체 번째 열거 객체인지 알려준다.

Week today = Week.SUNDAY;
int ordinal = today.ordinal();

 

=>compareTo() 메소드

compareTo() 메소드는 매개값으로 주어진 열거 객체를 기준으로 전후로 번째 위치하는지를 비교한다.

만약 열거 객체가 매개값의 열거 객체보다 순번이 빠륻면 음수가 , 순번이 늦다면 양수가 리턴된다.

Week day1 = Week.MONDAY;
Week day2 = Week.WEDNESDAY;
int result1 = day1.compareTo(day2); --> -2
출력
int result 2 = day2.compareTo(day1);-->2
출력

 

=>valueOf() 메소드

valueOf() 메소드는 매개값으로 주어지는 문자열과 동일한 문자열을 가지는 열거 객체를 리턴한다.

Week weekDay = Week.valueOf("SATURDAY");

 

=>values() 메소드

values() 메소드는 열거 타입의 모든 열거 객체들을 배열로 만들어 리턴한다.

Week[] days = Week.values();

for(Week day : days) {

            System.out.println(day);

        }

 

배열의 인덱스는 열거 객체의 순번과 같고 각 인덱스 값은 해당 순법의 열거 객체 번지이다.

 

 

[ EnumMethodExample.java]열거 객체의 메소드

public class EnumMethodExample {

       public static void main(String[] args) {

               // name() 메소드

               Week today = Week.SUNDAY;

               String name = today.name();

               System.out.println(name); // SUNDAY

 

               // ordinal() 메소드

               int ordinal = today.ordinal();

               System.out.println(ordinal); // 6

 

               // compareTo() 메소드

               Week day1 = Week.MONDAY;

               Week day2 = Week.WEDNESDAY;

               int result1 = day1.compareTo(day2);

               int result2 = day2.compareTo(day1);

               System.out.println(result1); // -2

               System.out.println(result2); // 2

 

               // valueOf() 메소드

               /*

                * Week weekDay = Week.valueOf("SUNDAY");

                * if(weekDay == Week.SATURDAY

                * || weekDay == Week.SUNDAY) {

                * System.out.println("주말 이군요");

                * } else {

                * System.out.println("평일 이군요"); }

                */

 

               if (args.length == 1) {

                      String strDay = args[0];

                      Week weekDay = Week.valueOf(strDay);

                      if (weekDay == Week.SATURDAY || weekDay == Week.SUNDAY) {

                             System.out.println("주말 이군요");

                      } else {

                             System.out.println("평일 이군요");

                      }

               }

 

               // values() 메소드

               Week[] days = Week.values();

               for (Week day : days) {

                      System.out.println(day);

               }

       }

}

 

연습문제

1. 참조 타입에 대한 설명으로 틀린 것은 무엇입니까? (4)

 

1. 참조 타입에는 배열 , 열거 , 클래스 , 인터페이스가 있다.

2. 참조 타입 변수의 메모리 생성 위치는 스택이다.

3. 참조 타입에서 ==,!= 연산자는 객체 번지를 비교한다.

4. 참조 타입은 null 값으로 초기화할 수 없다.

 

2. 자바에서 메모리 사용에 대한 설명으로 틀린 것은 무엇입니까? (3)

 

1. 로컬 변수는 스택 영역에 생성되며 실행 블록이 끝나면 소멸된다.

2. 메소드 코드 , 상수 , 열거 상수는 정적(메소드) 영역에 생성된다.

3. 참조되지 않는 객체는 프로그램에서 직접 소멸 코드를 작성하는 것이 좋다.

4. 배열 및 객체는 힙 영역에 생성된다.

 

3. 자바에서는 사용자가 직접소멸코드를 작성할수 없다.

 

3. String 타입에 대한 설명으로 틀린 것은 무엇입니까? (2)

 

1. String은 클래스이므로 참조 타입이다.

2. String 타입의 문자열 비교는 == 를 사용해야 한다.

3. 동일한 문자열 리터럴을 저장하는 변수는 동일한 String 객체를 참조한다.

4. new String ("문자열")은 문자열이 동일하더라도 다른 String 객체를 생성한다.

 

2. String 타입의 문자열 비교는 equals( ) 를 사용해야 한다.

 

4. 배열을 생성하는 방법으로 틀린 것은 무엇입니까? (2)

 

1. int[]array = {1,2,3};

2. int[]array;araay = {1,2,3};

3. int[]araay = new int[3];

4. int[][]array = new int[3][2];

 

5. 배열의 기본 초기값에 대한 설명으로 틀린 것은 무엇입니까? (3)

 

1. 정수 타입 배열 항목의 기본 초기값은 0 이다.

2. 실수 타입 배열 항목의 기본 초기값은 0.0f 또는 0.0 이다.

3. boolean 타입 배열 항목의 기본 초기값은 true 이다.

4. 참조 타입 배열 항목의 기본 초기값은 null 이다.

 

3. boolean 타입 배열 항목의 기본 초기값은 false 이다.

 

6. 배열의 길이에 대한 문제입니다. array.length 의 값과 array[2].length 의 값은 얼마입니까?

 

int[][] array = {

{95,86},

{83,92,96},

{78,83,93,87,88}

};

 

array.length -> (3)

array[2].length -> (5)

 

7. 주어진 배열의 항목에서 최대값을 구해보세요 (for문을 이용하세요).

package sec5_example;

 

public class Exercise07 {

    public static void main(String[] args) {

        int max = 0;

        int[] array = {1,5,3,8,2};

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

            if(max<array[i]) {

                max = array[i];

            }

        }

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

    }

}

 

max: 8

 

8. 주어진 배열의 전체 항목의 합과 평균값을 구해보세요(중첩 for문을 이용하세요.)

import java.lang.reflect.Array;

 

public class Exercise08 {

    public static void main(String[] args) {

        int[][] arry = {

                {95,86},

                {83,92,96},

                {78,83,93,87,88}

        };

        

        int sum = 0;

        double avg =0.0;

        int count = 0;

        

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

            for (int j = 0; j < arry[i].length; j++) {

                sum += arry[i][j];

                count++;

            }

        }

        avg=(double)sum/count;

        

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

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

    }

}

sum: 881

avg: 88.1

 

 

9. 다음은 키보드로부터 학생 수와 각 학생들의 점수를 입력받아서, 최고 점수 및 평균 점수를 구하는 프로그램입니다. 실행 결과를 보고, 알맞게 작성해보세요(참고로 16라인에서 Scanner nextInt () 메소드는 콘솔에 입력된 숫자를 읽고 리턴합니다).

package sec5_example;

 

import java.util.Scanner;

 

public class Exercise09 {

    public static void main(String[] args) {

        boolean run = true;

        int studentNum = 0;

        int[] scores = null;

        Scanner scanner = new Scanner(System.in);

        

        while(run) {

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

            System.out.println("1.학생수 | 2.점수입력 | 3.점수리스트 | 4.분석 | 5.종료");

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

            System.out.print("선택>");

            

            int selectNo = scanner.nextInt();

            

            if(selectNo ==1) {

                System.out.print("학생수>");

                studentNum = scanner.nextInt();

                scores = new int[studentNum];

            } else if(selectNo ==2) {

                for (int i = 0; i <studentNum; i++) {

                    System.out.print("scores["+i+"]>");

                    int score=scanner.nextInt();

                    scores[i] = score;

                }

            } else if(selectNo ==3) {

                for(int i=0;i<studentNum;i++) {

                System.out.println("score[" + i +"]:" + scores[i]);

                }

            } else if(selectNo ==4) {

                int sum = 0;

                int max = 0;

                double avg = 0;

                for(int i=0;i<studentNum;i++) {

                    sum+=scores[i];

                    if(max<scores[i]) {

                        max=scores[i];

                    }

                }

                avg = sum/studentNum;

                System.out.println("최고 점수:" + max);

                System.out.println("평균 점수:" + avg);

                

            } else if(selectNo ==5) {

                run = false;

            }

        }

        System.out.println("프로그램 종료");

    }

 

}

 

 

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

07. 상속  (0) 2020.09.29
06. 클래스  (0) 2020.09.28
04. 조건문과 반복문  (0) 2020.09.26
03. 연산자  (0) 2020.09.24
02.변수와 타입  (1) 2020.09.22
반응형

출처:이것이 자바다 

조건문과 반복문

4.1 코드 실행 흐름 제어

=>정상적인 코드 실행 흐름

main() 메소드의 시작인 중괄호 { 에서 끝 중괄호 } 까지 위->아래 방향으로 실행

=>제어문의 역할

코드 실행 흐름을 개발자가 원하는 방향으로 변경할 수 있도록 도와줌

 

 

v  제어문의 종류

조건문

      if, switch

반복문

      for, while, do-while

break, continue

제어문의 중첩

제어문의 중괄호 내부에 다른 제어문 작성 가능

      다양한 흐름 발생 가능

루핑(looping) : 반복문일 경우는 제어문 처음으로 다시 되돌아가 반복 실행한다.

 

4.2 조건문(if,switch)

4.2.1 if

조건식 결과 따라 중괄호 { } 블록을 실행할지 여부 결정할 때 사용

중괄호 블록을 작성하지 않으면 코드의 가독성(코드 해석)이 좋지 않고 ,버그 발생의 원인이 될 수 있다.

    • 조건식

      true 또는 false값을 산출할 수 있는 연산식

      boolean 변수

      조건식이 true이면 블록 실행하고 false 이면 블록 실행하지 않음

 

 

[ IfExample.java] If

public class IfExample {

       public static void main(String[] args) {

               int score = 93;

 

               if (score >= 90) {

                      System.out.println("점수가 90보다 큽니다.");

                      System.out.println("등급은 A입니다.");

               }

 

               if (score < 90)

                      System.out.println("점수가 90보다 작습니다.");

                      System.out.println("등급은 B입니다.");

       }

}

 

4.2.2 if- else

조건식 결과 따라 실행 블록 선택

 

 

[ IfElseExample.java] if - else

public class IfElseExample {

    public static void main(String[] args) {

        int score = 85;

 

        if(score >= 90) {

            System.out.println("90보다 크다");

            System.out.println("A");

        } else {

            System.out.println("90 아래");

            System.out.println("B");

        }

    }

}

 

4.2.3 if- else if -else

복수의 조건식 두어 조건식을 만족하는 블록만 실행

 

 

[ IfElseIfElseExample.java ]if-else if - else

public class IfElseIfElseExample {

       public static void main(String[] args) {

               int score = 75;

 

               if (score > 90) {

                      System.out.println("점수가 100 ~ 90입니다.");

                      System.out.println("등급은 A입니다.");

               } else if (score >= 80) {

                      System.out.println("점수가 80 ~ 89입니다.");

                      System.out.println("등급은 B입니다.");

               } else if (score >= 70) {

                      System.out.println("점수가 70 ~ 79입니다.");

                      System.out.println("등급은 C입니다.");

               } else {

                      System.out.println("점수가 70 미만 입니다.");

                      System.out.println("등급은 D입니다.");

               }

       }

}

 

=>Math.random() 메소드를 활용

이 메소드는 0.01.0사이에 속하는 double타입의 하나를 리턴한다. 0.0은 범위에 포함되고 1.0은 범위에 포함되지 않는다.

0.0 <= Math.random() < 1.0

 

1~ 10 까지 정수중에서 하나의 정수를 얻기

0.0* 10 <= Math.random()* 10 < 1.0 * 10

(0.0)                                        (10.0)

====>int로 강제 타입변환

(int)0.0* 10 <= Math.random()* 10 < (int)1.0 * 10

0                   (0,1,2,3,...9)                        (10)

1 ~ 10까지의 정수

(int)0.0* 10 +1 <= Math.random()* 10 < (int)1.0 * 10 +1

1          (1,2,3,...10)                  (11)

 

 

int num = (int) (Math.random()* n)+start;

int num = (int) (Math.random()*6) +1;

int num = (int) (Math.random()*45) +1;

 

[IfDiceExample.java]주사위의 번호를 뽑는 예제

public class IfDiceExample {

       public static void main(String[] args) {

               int num = (int) (Math.random() * 6) + 1; // 주사위 번호 하나 뽑기

 

               if (num == 1) {

                      System.out.println("1번이 나왔습니다.");

               } else if (num == 2) {

                      System.out.println("2번이 나왔습니다.");

               } else if (num == 3) {

                      System.out.println("3번이 나왔습니다.");

               } else if (num == 4) {

                      System.out.println("4번이 나왔습니다.");

               } else if (num == 5) {

                      System.out.println("5번이 나왔습니다.");

               } else {

                      System.out.println("6번이 나왔습니다.");

               }

       }

}

 

4.2.4 중첩 if

코드 실행 흐름을 이해하는 것이 가장 중요

 

 

[ IfNestedExample.java]중첩 if

public class IfNestedExample {

       public static void main(String[] args) {

               int score = (int) (Math.random() * 20) + 81;

               System.out.println("점수: "+score);

 

               String grade;

 

               if (score >= 90) {

                      if (score >= 95) {

                             grade = "A+";

                      } else {

                             grade = "A";

                      }

               } else {

                      if (score >= 85) {

                             grade = "B+";

                      } else {

                             grade = "B";

                      }

               }

 

               System.out.println("학점: "+grade);

       }

}

 

4.2.5 switch

조건 제어문

변수나 연산식의 값에 따라 실행문 선택할 때 사용

 

장점 : 비교 대상이 많을 때 if문 보다 효율적이다.

단점 : 사용이 제한 적이다. (실수나 변수 못 쓴다.), 10 <변수 < 15와 같은 범위 값에는 쓸수 없다.

 

case가 없으면 default로 가서 실행문을 실행시킨다.

default는 생략 가능하다.

 

[SwitchExample.java]Switch

public class SwitchExample {

       public static void main(String[] args) {

               int num = (int) (Math.random() * 6) + 1;

 

               switch (num) {

               case 1:

                      System.out.println("1번이 나왔습니다.");

                      break;

               case 2:

                      System.out.println("2번이 나왔습니다.");

                      break;

               case 3:

                      System.out.println("3번이 나왔습니다.");

                      break;

               case 4:

                      System.out.println("4번이 나왔습니다.");

                      break;

               case 5:

                      System.out.println("5번이 나왔습니다.");

                      break;

               default:

                      System.out.println("6번이 나왔습니다.");

                      break;

               }

       }

}

 

case끝에 break 가 붙어 있는 이유는 다음 case를 실행하지 말고 switch문을 빠져나가기 위해서이다.

break가 없다면 다음 case가 연달아 실행되는데,이때에는 case값과는 상관없이 실행된다.

 

[ SwitchNoBreakCaseExample.java]break문이 없는 case

public class SwitchNoBreakCaseExample {

       public static void main(String[] args) {

               int time = (int) (Math.random() * 4) + 8;

               System.out.println("[현재시간 : " + time+" ]");

 

               switch (time) {

               case 8:

                      System.out.println("출근합나다.");

               case 9:

                      System.out.println("회의를 합니다.");

               case 10:

                      System.out.println("업무를 봅니다.");

               default:

                      System.out.println("외근을 나갑니다.");

               }

       }

}

 

영어 대소문자에 관계없이 똑같은 알파벳이라면 동일하게 처리하도록 만든 swithc문이다.

[SwitchCharExample.java]char타입의 Switch

public class SwitchCharExample {

       public static void main(String[] args) {

               char grade = 'B';

 

               switch (grade) {

               case 'A':

               case 'a':

                      System.out.println("우수 회원입니다.");

                      break;

               case 'B':

               case 'b':

                      System.out.println("일반 회원입니다.");

                      break;

               default:

                      System.out.println("손님입니다.");

               }

       }

}

 

자바 6까지는 switch문의 괄호에는 정수 타입(byte, char,short,int, long)변수나 정수값을 산출하는 연산식만 올 수 있었다.

자바 7부터는 string타입의 변수도 올 수 있다.

[ SwitchStringExample.java]String타입의 Switch

public class SwitchStringExample {

       public static void main(String[] args) {

               String position = "과장";

 

               switch (position) {

               case "부장":

                      System.out.println("700만원");

                      break;

               case "과장":

                      System.out.println("500만원");

                      break;

               default:

                      System.out.println("300만원");

               }

       }

}

 

 

 

 

4.3 반복문 (for, while, do -while)

4.3.1 for

1부터 5까지의 합 :

 

 

 

 

 

 

 

 

 

코드가 간결하면 개발 시간을 줄일 수 있고 ,오류가 날 확률도 줄어든다.

 

 

 

초기화식을 생략할 수 도 있다.

int i = 0;

for( ; i <= 100; i++){  ....

}

 

 

 

 

 

어떤 경우에는 초기화식이 둘 이상이 있을수도 있다.

증감식도 둘 이상이 있을 수 있ㄷ.

이런 경우에는 쉼표(,) 로 구분해서 작성하면 된다.

[ForSumFrom1To10Example.java] 부터 10까지 출력

public class ForSumFrom1To10Example {

 

           public static void main(String[] args) {

                       for (int i = 1; i <= 10; i++) {

                                  System.out.println(i);

                       }

           }

}

 

[ ForSumFrom1To100Example.java ]1부터 100까지 합을 출력

public class ForSumFrom1To100Example {

 

       public static void main(String[] args) {

               int sum = 0;

               for (int i = 1; i <= 100; i++) {

                      sum += i;

               }

               System.out.println("1 ~ 100 : "+sum);

       }

 

}

 

System.out.println("1 ~ " + i + " : "+sum); =>이런식으로 하면 오류난다. i for문을 벗ㅇ나서는 사용할 없기 때문이다.

 

1부터 100까지의 합을 출력 [ ForSumFrom1To100Example2.java]i부분 수정

public class ForSumFrom1To100Example2 {

 

       public static void main(String[] args) {

               int sum = 0;

               int i = 0;

               for (i = 1; i <= 100; i++) {

                      sum += i;

               }

               System.out.println("1 ~ "+(i-1)+" : "+sum);

       }

}

 

주의할점 : 부동소수점 타입을 사용하지 말아야 한다.

[ ForFloatCounterExample.java]float 타입 카운터 변수

public class ForFloatCounterExample {

 

       public static void main(String[] args) {

               for(float x = 0.1f ; x <= 1.0f ; x += 0.1f) {

                      System.out.println(x);

               }

       }

 

}

구구단 출력하기

public class ForMultiplicationTableExample {

       public static void main(String[] args) {

               for (int m = 2; m <= 9; m++) {

                      System.out.println("*** " + m + " ***");

                      for (int n = 1; n <= 9; n++) {

                             System.out.println(m + " x " + n + " = " + (m * n));

                      }

               }

       }

}

 

4.3.2 while

for문이 정해진 횟수만큼 반복한다면,while문은 조건식이 true일 경우 계속해서 반복한다.

 

 

 

[ WhilePrintFrom1To10Example.java]1부터 10 까지 출력

public class WhilePrintFrom1To10Example {

       public static void main(String[] args) {

               int i = 1;

               while (i <= 10) {

                      System.out.println(i);

                      i++;

               }

       }

}

 

while문 내에서 계속 누적되는 값을 갖는 변수는 while문 시작 전에 미리 선언해 놓아야 합니다.

[WhileSumForm1To100Example.java]1부터 100까지 합을 출력

public class WhileSumForm1To100Example {

    public static void main(String[] args) {

        int sum = 0;

        int i = 1;

       

        while(i<=100) {

            sum += i;

            i++;

        }

       

        System.out.println("1~" + (i-1) + " : " + sum);

    }

}

 

무한 루프는 무한히 반복하여 실행하기 때문에 언젠가는 while문을 빠져 나가기 위한 코드가 필요하다.

 

 

int keyCode = System.in.read();

 

 

[ WhileKeyControlExample.java]키보드로 while문 제어

public class WhileKeyControlExample {

 

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

               boolean run = true;

               int speed = 0;

               int keyCode = 0;

 

               while (run) {

                      if (keyCode != 13 && keyCode != 10) {

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

                             System.out.println("1.증속 | 2.감속 | 3.중지");

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

                             System.out.print("선택: ");

                      }

 

                      keyCode = System.in.read(); // 키보드의 코드를 읽음

 

                      if (keyCode == 49) { // 1

                             speed++;

                             System.out.println("현재 속도=" + speed);

                      } else if (keyCode == 50) { // 2

                             speed--;

                             System.out.println("현재 속도=" + speed);

                      } else if (keyCode == 51) { // 3

                             run = false; // while문을 종료하기 위해 run 변수에 false 저장

                      }

               }

 

               System.out.println("프로그램 종료");

       }

 

}

while문을 빠져나가기 위한 또 다른 방법으로 break문을 이용하는 방법도 있다.

System.out.printIn() 메소드는 매개값을 출력하고 다음 행으로 이동.

System.out.print() 메소드는 매개값을 출력만 하고 다음 행으로 이동하지 않는다.

 

4.3.3 do-while

while문은 시작할 때부터 조건식을 검사하여 블록 내부를 실행할지 결정하지만 , do -while 는 블록 내부의 실행문을 우선 실행시키고 실행 결과에 따라서 반복 실행을 계속할지 결정하는 경우도 발생한다.

조건 따라 반복 계속할지 결정할 때 사용하는 것은 while문과 동일

무조건 중괄호 { } 블록을 한 번 실행한 후, 조건 검사해 반복 결정

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

주의할 점은 while()뒤에 반드시 세미콜론(;)을 붙어야 한다.

System.in.read()메소드는 하나의 키 코드만 읽기 때문에 콘솔에 입력된 문자열을 한 번에 읽을 수 없다.

 

 

 

Scanner scanner = new Scanner(System.in);//Scanner객체 생성

String inputString = scanner.nextLine();//nextLine() 메소드 호출

 

 

 

!inputString.equals("q")

 

import java.util.Scanner;

 

[ DoWhileExample.java] do-while

public class DoWhileExample {

       public static void main(String[] args) {

               System.out.println("메시지를 입력하세요");

               System.out.println("프로그램을 종료하려면 q 입력하세요.");

 

               Scanner scanner = new Scanner(System.in); // Scanner 객체 생성

               String inputString;

 

               do {

                      System.out.print(">");

                      inputString = scanner.nextLine(); // 키보드가 입력한 문자열을 얻음

                      System.out.println(inputString);

               } while (!inputString.equals("q")); // 문자열을 비교할 때는 equal() 메소드를 사용.

               // q 저장되어 있으면 false 산출되어 종료

               System.out.println();

               System.out.println("프로그램 종료");

               scanner.close();

       }

}

 

4.3.4 break

for, while, do-while문 종료 (반복 취소)

Switch문 종료

대개 if문과 같이 사용

if문 조건식에 따라 for문과 while문 종료할 때 사용

 

 

 

 

 

 

 

 

 

 

[ BreakExample.java ]breakwhile문 종료

public class BreakExample {

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

               while (true) {

                      int num = (int) (Math.random() * 6) + 1;

                      System.out.println(num);

                      if (num == 6) {

                             break;

                      }

               }

               System.out.println("프로그램 종료");

       }

}

 

반복문이 중첩된 경우

반복문이 중첩되어 있을 경우 break; 문은 가장 가까운 반복문만 종료

바깥쪽 반복문까지 종료시키려면 반복문에 이름(라벨)을 붙이고, break 이름;” 사용

 

 

 

 

 

 

 

 

 

 

 

[ BreakOutterExample.java]바깥쪽 반복문 종료

public class BreakOutterExample {

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

               Outter: for (char upper = 'A'; upper <= 'Z'; upper++) {

                      for (char lower = 'a'; lower <= 'z'; lower++) {

                             System.out.println(upper + "-" + lower);

                             if (lower == 'g') {

                                    break Outter;

                             }

                      }

               }

               System.out.println("프로그램 실행 종료");

       }

}

 

 

4.3.5 continue

for, while, do-while문에서 사용

for: 증감식으로 이동

while, do-while: 조건식으로 이동

continue문은 반복문을 종료하지 않고 계속 반복을 수행한다는 점이 break문과 다르다.

 

 
 

 

 

 

 

 

 

 

 

 

 

[ContinueExampl.java]continue를 사용한 for

public class ContinueExample {

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

               for (int i = 1; i <= 10; i++) {

                      if (i % 2 != 0) {

                             continue;

                      }

                      System.out.println(i);

               }

       }

}

특정 조건을 만족하는 경우에 continue문을 실행하지 않고 다음 반복으로 넘어간다.

 

연습문제

1. 조건문과 반복문의 종류를 괄호 ( ) 속에 넣어 보세요.

 

조건문 : ( if ) , ( switch )

반복문 : ( for ) , ( while ) , ( do - while )

 

2. 조건문과 반복문을 설명한 것 중 틀린 것은 무엇입니까? (2)

 

1. if문은 조건식의 결과에 따라 실행 흐름을 달리할 수 있다.

2. switch문에서 사용할 수 있는 변수의 타입은 int , double이 될 수 있다.

3. for문은 카운터 변수로 지정한 횟수만큼 반복시킬 때 사용할 수 있다.

4. break문은 switch, for, while문을 종료할 때 사용할 수 있다.

 

2. switch(변수) {

정수,String

}

 

3. for문을 이용해서 1부터 100까지의 정수 중에서 3의 배수의 총합을 구하는 코드를 작성해보세요.

package sec4_example;

 

public class Exercise03 {

 

    public static void main(String[] args) {

        int sum = 0;

        int i = 0;

        for(i=1;i<=100;i++) {

            if(i%3==0) {

                sum = sum+i;

            }

        }

        System.out.println("3 배수의  :" + sum);

    }

}

 

3 배수의  :1683

 

4. while문과 Math.random() 메소드를 이용해서 두 개의 주사위를 던졌을 때 나오는 눈을 (1,2) 형태로 출력하고, 눈의 합이 5가 아니면 계속 주사위를 던지고, 눈의 합이 5이면 실행을 멈추는 코드를 작성해보세요. 눈의 합이 5가 되는 조합은 (1,4) , (4,1) , (2,3) , (3,2) 입니다.

package sec4_example;

 

public class Exercise04 {

    public static void main(String[] args) {

    

        while (true) {

            int num1 = (int) (Math.random()*6+ 1;

            int num2 = (int) (Math.random()*6+ 1;    

            if(num1 + num2 ==5) {

                System.out.println("(" + num1 +"," + num2 + ")");

                break;

            }

            else {

                System.out.println("(" + num1 +"," + num2 + ")");

            }

        }

        

    }

}

(4,4)

(1,3)

(3,5)

(6,2)

(1,6)

(4,6)

(4,2)

(4,6)

(5,6)

(3,6)

(4,3)

(4,4)

(5,6)

(3,1)

(2,1)

(1,2)

(1,4)

 

5. 중첩 for문을 이용하여 방정식 4x + 5y = 60의 모든 해를 구해서 (x,y) 형태로 출력해보세요.

, x y 10 이하의 자연수입니다.

package sec4_example;

 

public class Exercise05 {

    public static void main(String[] args) {

         

        for(int x=0;x<=10;x++) {

            for(int y=0;y<=10;y++) {

                if(4*x+5*y==60) {

                    System.out.println("(" + x + "," + y + ")");

                }

            }

        }

    }

}

(5,8)

(10,4)

 

6. for문을 이용해서 실행 결과와 같은 삼각형을 출력하는 코드를 작성해보세요.

package sec4_example;

 

public class Exercise06 {

 

    public static void main(String[] args)

    {        

        for(int i=1;i<=5;i++)

        {

            for(int j=1;j<=i;j++)

            {

                System.out.print("*");

            }

            System.out.println();

        }

    }            

}

*

**

***

****

*****

 

7. while문과 Scanner를 이용해서 키보드로부터 입력된 데이터로 예금, 출금, 조회, 종료 기능을 제공하는 코드를 작성해보세요. 이 프로그램을 실행시키면 다음과 같은 실행 결과가 나와야 합니다.

package sec4_example;

 

import java.util.Scanner;

 

public class Exercise07 {

    public static void main(String[] args) {

        boolean run = true;

        

        int balance = 0;

        

        Scanner scanner = new Scanner(System.in);

        

        while(run) {

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

            System.out.println("1. 예금 | 2.출금 | 3.잔고 | 4.종료");

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

            System.out.println("선택> ");

            

            int num = scanner.nextInt();

            

            switch (num) {

            case 1:

                System.out.print("예금액>");

                int deposit = scanner.nextInt();

                balance += deposit;

                break;                

            case 2:

                System.out.print("출금액>");

                int withdraw = scanner.nextInt();

                balance -= withdraw;

                break;

            case 3:

                System.out.println("잔고>" + balance);                

                break;    

            case 4:

                run = false;

                break;            

            }

        }

        System.out.println("프로그램 종료");

    }

}

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

1. 예금 | 2.출금 | 3.잔고 | 4.종료

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

선택> 

1

예금액>10000

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

1. 예금 | 2.출금 | 3.잔고 | 4.종료

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

선택> 

2

출금액>2000

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

1. 예금 | 2.출금 | 3.잔고 | 4.종료

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

선택> 

3

잔고>8000

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

1. 예금 | 2.출금 | 3.잔고 | 4.종료

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

선택> 

4

프로그램 종료

 

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

06. 클래스  (0) 2020.09.28
05. 참조 타입  (0) 2020.09.27
03. 연산자  (0) 2020.09.24
02.변수와 타입  (1) 2020.09.22
01. 자바 시작하기  (0) 2020.09.20
반응형

출처:이것이 자바다 

연산자

3.1 연산자와 연산식

프로그램에서 데이터를 처리하여 결과를 산출하는 것을 연산(Operations)이라고 한다.

연산자(Operator) : 연산에 사용되는 표시나 기호

피연산자(Operand ) : 연산되는 데이터

연산식(expressions) : 연산자와 피연산자를 이용하여 연산의 과정을 기술한 것

예를 들어 다음 연산식에서 +, -, *, ==은 연산자이고 x, y, z 변수는 피연산자이다.

 

자바 언어에서는 다양한 연산자를 제공하고 있다.이 연산자들은 피연산자를 연산해서 값을 산출하는데, 산출되는 값의 타입은 연산자별로 다르다.

 

산술연산자

비교연산자

 

단항, 이항 ,삼항 연산자

단항 연산자 : 부호 연산자와 증가/감소 연산자는 피연산자 하나만을 요구하므로

++x;

이항 연산자 : 그 이외의 연산자는 두개의 피연산자를 요구

x + y;

삼항 연산자 : 조건 연산자는 조건식 A,B와 같이 세 개의 피연산자가 필요함

(sum > 90) ? "A" :"B";

 

연산식은 반드시 하나의 값을 산출한다.

int result = x+y;

 

연산식은 다른 연산식의 피연산자 위치에도 올 수 있ㄷ.

boolean result = (x+y) < 5;

 

3.2 연산의 방향과 우선순위

대부분의 연산자느 왼쪽에서 부터 오른쪽으로 (->) 연산을 시작한다.

100 * 2 / 3 % 5  => 1

 

하지만 단항 연산자(++, --, ~ , ! ), 부호 연산자(+, -) 대입 연산자 ( =, += , -= , ...) 오른쪽에서 왼쪽 (<-)으로 연산된다.

a = b = c = 5

위 연산식은 c = 5, b= 5, a = 5 순서로 실행된다.

 

우선순위 정리한 표

 

괄호()를 사용해서 먼저 처리해야 할 연산식을 묶는 것이 좋다.

 

만약 var1 + var2먼저 진행하고 싶다면 :

1. 단항, 이항, 삼항 연산자 순으로 우선순위를 가진다.

2. 산술, 비교, 논리, 대입 연산자 순으로 우선순위를 가진다.

3. 단항과 대입 연산자를 제외한 모든 연산의 방향은 왼쪽에서 오른쪽이다(→).

4. 복잡한 연산식에는 괄호()를 사용해서 우선순위를 정해준다

 

3.3 단항연산자

피연사가 단 하나뿐인 연산자

부호 연산자 (+, - ) , 증감 연산자(++, --) ,논리 부정 연산자 (!) , 비트 반전 연산자 (~)

 

3.3.1 부호 연산자(+,-)

연산식

설명

+

피연산자

피연산자의 부호 유지

-

피연산자

피연산자의 부호 변경

 

+, -는 산술 연산자이기도 하고 , 부호 연산자이기도 하다.

부호 연산자로 쓰일 때에는 하나의 피연산자만 필요하다.일반적으로 부호 연산자를 다음과 같이 정수 및 실수 리터럴 앞에 붙여 양수 및 음수를 표현한다.

int i1 = +100;

int i2 = -100;

double d1 = +3.14;

double d2 = -10.5;

 

부호 연산자를 정수 또는 실수 타입 변수 앞에 붙일 수 도 있다.이 경우는 변수를 양수 및 음수로 표현한 것이 아니고 ,변수 값의 부호를 유지하거나 바꾸기 위해 사용된다.

+연산자는 변수 값의 부호를 유지한다.

-연산자는 변수 값의 부호를 양수는 음수로 , 음수는 양수로 바꾼다.

int x = -100;

int result1 = +x; //-100

int result2 = -x; //100

 

부호 연산자를 사용할 때 주의할 점은 부호 연산자의 산출 타입은 int타입이 된다는 것이다.

short s = 100;

short result = -s;//컴파일 에러 short타입 값을 부호 연산하면 int타입 값으로 바뀐다.

=>

shors s = 100;

int reuslt3 = -s;

 

부호 연산자

[SignOperatorExample.java] 부호 연산자

public class SignOperatorExample {

 

           public static void main(String[] args) {

                       int x = -100;

                       int result1 = +x;

                       int result2 = -x;

                       System.out.println("result1=" + result1);

                       System.out.println("result2=" + result2);

                      

                       short s = 100;

                       //short result3 = -s//컴파일 에러

                       int reuslt3 = -s;

                       System.out.println("reuslt3=" + reuslt3);

                      

           }

 

}

 

 

3.3.2 증감 연산자(++,--)

연산식

설명

++

피연산자

다른 연산을 수행하기 전에 피연산자의  값을 1 증가시킴

--

피연산자

다른 연산을 수행하기 전에 피연산자의  값을 1 감소시킴

피연산자

++

다른 연산을 수행한 후에 피연산자의 값을 1 증가시킴

피연산자

--

다른 연산을 수행한 후에 피연산자의 값을 1 감소시킴

 

증감 연산자가 변수 앞에 있으면 우선 변수를 1증가 또는 1감소시킨 후에 다른 연산자와 계산한다.

증감 연산자가 변수 뒤에 있으면 다른 연산자를 먼저 처리한 후 변수를 1증가 또느 1감소시킨다.

int x = 1;

int y = 1;

int result1 = ++x + 10;//12

int reuslt2 = y++ + 10;//11

 

증감연산자

 

[IncreaseDecreaseOperatorExample.java] 증감 연산자

public class IncreaseDecreaseOperatorExample {

          

           public static void main(String[] args) {

                       int x = 10;

                       int y = 10;

                       int z;

                      

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

                       x++;

                       ++x;

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

                      

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

                       y--;

                       --y;

                       System.out.println("y="+y);

                      

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

                       z = x++;

                       System.out.println("z="+z);

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

                      

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

                       z = x++;

                       System.out.println("z="+z);

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

                      

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

                       z = ++x + y++;

                       System.out.println("z="+z);

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

                       System.out.println("y="+y);

           }

}

 

++i  i = i+1

 

3.3.3 논리 부정 연산자(!)

boolean 타입에만 사용가능

 

 

조건문과 제어문에서 사용되고 두가지 상태 (true/false)를 번갈아가면 변경하는 토글(toggle)기능을 구현할 때도 주로 사용한다.

 

논리 부정 연산자

[DenyLogicOperatorExample.java] 논리 부정 연산자

public class DenyLogicOperatorExample {

 

           public static void main(String[] args) {

                       boolean play = true;

                       System.out.println(play);

                      

                       play = !play;

                       System.out.println(play);

                      

                       play = !play;

                       System.out.println(play);

           }

 

}

 

3.3.4 비트 반전 연산자(~)

정수타입( byte, short,int,long)의 피연산자에만 사용되며 , 피연산자를 2진 수로 표현했을 때 비트값은 01, 10으로 반전한다. 연산후 , 부호 비트인 치상위 비트를 포함해서 모든 비트가 반전되기 때문에 ,부호가 반대인 새로운 값이 산출된다.

 

피연산자는 연산을 수행하기 전에 int타입으로 변환되고 , 비트 반전이 일어난다.

 

byte v1 =10;

byte v2 = ~v1;//컴파일 에러

=>

byte v1 =10;

int = ~v1;

 

비트 반전 연산자의 결과를 이용하면 부호가 반대인 정수를 구할 수 도 있다.

byte v1 = 10;

int v2 = ~v1 + 1;//-10 v2에 저장

 

자바는 정수값을 총 32비트의 이진 문자열로 리턴하는 Integer.toBinaryString()메소드를 제공한다.

String v1BinaryString = Integer.toBinaryString(10);

리턴하는 str의 문자수를 조사해서 32보다 작으면 앞에 0을 붙이도록 한 것이다.

           public static String toBinaryString(int value) {

                       String str  = Integer.toBinaryString(value);

                       while(str.length() < 32) {

                                  str = "0" + str;

                       }

                       return str;

           }

 

비트 반전 연산자

[BitReverseOperatorExample.java] 비트 반전 연산자

public class BitReverseOperatorExample {

          

           public static void main(String[] args) {

                       int v1 = 10;

                       int v2 = ~v1;

                       int v3 = ~v1 + 1;

                      

                       System.out.println(toBinaryString(v1) + "(십진수 : " + v1 +")");

                       System.out.println(toBinaryString(v2) + "(십진수 : " + v2 +")");

                       System.out.println(toBinaryString(v3) + "(십진수 : " + v3 +")");

                       System.out.println();

                      

                       int v4 = -10;

                       int v5 = ~v4;

                       int v6 = ~v4 + 1;

                       System.out.println(toBinaryString(v4) + "(십진수 : " + v4 +")");

                       System.out.println(toBinaryString(v5) + "(십진수 : " + v5 +")");

                       System.out.println(toBinaryString(v6) + "(십진수 : " + v6 +")");

                      

           }

          

           public static String toBinaryString(int value) {

                       String str  = Integer.toBinaryString(value);

                       while(str.length() < 32) {

                                  str = "0" + str;

                       }

                       return str;

           }

 

}

 

3.4 이항 연산자

피연산자가 2개인 연산자

    • 종류

      산술 연산자: +, -, *, /, %

      문자열 연결 연산자: +

      대입 연산자: =,  +=,  -=,  *=,  /=,  %=, &=, ^=, |=, <<=, >>=, >>>=

      비교 연산자: <, <=, >, >=, ==, !=

      논리 연산자: &&, ||, &, |, ^, !

      비트 논리 연산자: &, |, ^

      비트 이동 연산자: <<, >>, >>>

 

3.4.1 산술 연산자(+, -, *, /, %)

 

이 산술 연산자는 boolean타입을 제외한 모든 기본 타입에 사용할 수 있다.

 

 

산술 연산자의 특징은 피연산자들의 타입이 동일하지 않을 경우 다음과 같은 규칙을 사용해서 피연산자들의 타입을 일치시킨 후 연산을 수행한다.

1)피연산자들이 모두 정수 타입이고 ,int 타입(4byte) 보다 크기가 작은 타입일 경우 모두 int타입으로 변환후 , 연산을 수행한다. 따라서 연산의 산출 타입은 int이다.

 byte + byte -> int + int  = int

2)피연산들이 모두 정수 타입이고 ,long타입이 있을 경우 모두 long타입으로 변환후 , 연산을 수행한다. 따라서 연산의 산출 타입은 long이다.

int + long -> long + long = long

3)피연산자 중 실수 타입(float타입, double타입) 이 있을 경우 , 크기가 큰 실수 타입으로 변환 후 ,연산을 수행한다. 따라서 연산의 산출 타입은 실수 타입이다.

int + double -> double + double = double

 

 

long타입을 제외한 정수의 산술 연산은 무조건 int타입으로 변환 후 연산을 수행하고 ,산출 타입이 int이기 때문에 int타입 변수에 산출값을 대입해야 한다.

                       byte byte1 =1;

                       byte byte2 = 1;

                       byte byte3 = byte1 + byte2; //컴파일 오류

======>수정

int byte3 = byte1+byte2;

이유는 자바 가상 기계(JVM)가 기본적으로 32비트 단위로 계산하기 때문이다.

 

 

 

                       int int1 = 10;

                       int int2 = 4;

                       int result2 = int1/ int2; //2

                       double result3 = int1 /int2; //2.0

 

double 타입으로 강제 타입 변환(캐스팅)한 후 산술 연산을 하면 된다.

double result3 = (int* 1.0)/ int2;

double result3 = (double) int1/int2;

double reuslt3 = int1/ (double) int2;

 

산술 연산자

[ArithmeticOperatorExample.java] 산술 연산자

public class ArithmeticOperatorExample {

 

           public static void main(String[] args) {

                       int v1 = 5;

                       int v2 = 2;

                      

                       int result1 = v1+v2;

                       System.out.println("result1="+result1);

                      

                       int result2 = v1-v2;

                       System.out.println("result2="+result2);

                      

                       int result3 = v1*v2;

                       System.out.println("result3="+result3);

                      

                       int result4 = v1/v2;

                       System.out.println("result4="+result4);

                      

                       int result5 = v1%v2;

                       System.out.println("result5="+result5);

                      

                       double result6 = (double)v1/v2;

                       System.out.println("result6="+result6);

           }

 

}

 

char타입 ->int타입이다.

char타입 연산

[CharOperatorExample.java] char 타입 연산

public class CharOperatorExample {

          

           public static void main(String[] args) {

                       char c1 = 'A'+1;

                       char c2 = 'A';

                       //char c3 c2 +1;//컴파일 에러

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

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

           }

          

}

리터럴 간의 연산은 타입 변환 없이 해당 타입으로 계산

char c1 = 'A'+1;

 

 

//int타입으로 변환

char c2 = 'A';

char c3 c2 +1;//컴파일 에러

=>

char c3 = (char)(c2+1);

올바른 계산을 위해 값을 미리 검정해야 하고 ,정확한 계산을 위해 실수 타입을 피해야 하며 , 특수값 처리에 신경 써야 한다.

 

=>오버플로우 탐지

산술 타입으로 표현할 수 없는 값이 산출되었을 경우 ,오버플로우가 발생하고 쓰게기값(엉뚱한 값)을 얻을 수 있기 때문이다.

[ OverflowExample.java]오버플로우

public class OverflowExample {

       public static void main(String[] args) {

               int x = 1000000;

               int y = 1000000;

               int z = x * y;

               System.out.println(z);

       }

}

컴파일 에러는 발생하지 않지만 ,변수 z에서는 올바른 값이 저장되지 않는다.

 

[ OverflowExample.java ]오버플로우 해결

public class OverflowExample {

       public static void main(String[] args) {

               //int x = 1000000;

               //int y = 1000000;

               //int z = x * y;

               //System.out.println(z);

              

               long x = 1000000;

               long y = 1000000;

               long z = x * y;

               System.out.println(z);

       }

}

 

[CheckOverflowExample.java]산술 연산 전에 오버플로우를 탐지 : 메소드로 오버플로우 확인

public class CheckOverflowExample {

 

       public static void main(String[] args) {

               try {

                      int result = safeAdd(2000000000,2000000000);

                      System.out.println(result);

               }catch(ArithmeticException e) {

                      System.out.println("오버플로우가 발생하여 정확하게 계산할 없음");

               }

       }

      

       public static int safeAdd(int left, int right) {

               if((right > 0)) {

                      if(left > (Integer.MAX_VALUE - right)) {

                             throw new ArithmeticException("오버플로우 발생");

                      }

               }else {

                      if(left < (Integer.MIN_VALUE - right)) {

                             throw new ArithmeticException("오버플로우 발생");

                      }

               }

               return left + right;

       }

}

 

=>정확한 계산은 정수 사용

부동소수점(실수) 타입을 사용하지 않는 것이 좋다.

 

[ AccuracyExample1.java]정확하게 계산할 때에는 부동소수점 타입을 사용하지 않는다.

public class AccuracyExample1 {

 

       public static void main(String[] args) {

               int apple = 1;

               double pieceUnit = 0.1;

               int number = 7;

              

               double result = apple - number *pieceUnit;

               System.out.println("사과 한개에서 ");

               System.out.println("0.7 조각을 빼면, ");

               System.out.println(result + "조각이 남는다.");

       }

 

}

근사치로 처리 하기 때문이다.

 

 

[AccuracyExample2.java]정확하게 계산할 때에는 부동소수점 타입을 사용하지 않는다.

public class AccuracyExample2 {

 

           public static void main(String[] args) {

                       int apple = 1;

                      

                      

                       int totalPieces = apple * 10;

                       int number = 7;

                       int temp = totalPieces - number;

                      

                       double result = temp / 10.0;

                      

                       System.out.println("사과 한개에서 ");

                       System.out.println("0.7 조각을 빼면, ");

                       System.out.println(result + "조각이 남는다.");

           }

 

}

 

=>NaNInfinity연산

/ 또는 % 연산자를 사용할 떄도 주의 할 점 이 있다.

5 / 0  ->ArighmeticException예외 발생

5 % 0 ->ArighmeticException예외 발생

 

예외처리 를 하는게 좋다.

try{

           //int z = x /y ;

           int z = x % y ;

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

}catch(AirthmeticException e){

           System.out.println("0으로 나누면 안됨");

}

 

실수 타입은 0.0 또는 0.0f 로 나누면 AirthmeticException이 발생하지 않고 , /연산의 결과는 Infinity(무한대) 값을 가지며 , %연산의 결과는 NaN(Not a Number) 을 가진다.

5 / 0.0 ->Infinity

5 % 0.0 ->NaN

 

Infinity + 2 -> Infinity

NaN + 2 -> NaN

 

/%연산의 결과가 Infinity또는 NaN인지 확인하려면 Double.isInfinite()Double.isNaN() 메소드를 이용하면 됩니다.

[ InfinityAndNaNCheckExample.java] InfinityNaN

public class InfinityAndNaNCheckExample {

 

           public static void main(String[] args) {

                       int x = 5;

                       double y = 0.0;

                      

                       double z = x / y;

                       //double z = x % y;

                      

                       System.out.println(Double.isInfinite(z));

                       System.out.println(Double.isNaN(z));

                      

                       System.out.println(z + 2); //문제가 되는 코드

           }

 

}

 

 

if(Double.isInfinite(z) ||  Double.isNaN(z) ){

 

 

       System.out.println(" 산출 불가");

}else{

       System.out.println(z + 2);

}

 

=>입력값의 NaN 검사

부동소수점(실수)을 입력받을 때는 반드시 NaN 검사를 해야 한다.

[ InputDataCheckNaNExample1.java] "NaN" 문자열의 문제점

public class InputDataCheckNaNExample1 {

 

       public static void main(String[] args) {

               String userInput = "NaN";

               double val = Double.valueOf(userInput);

              

               double currenBalance = 10000.0;

              

               currenBalance += val;

               System.out.println(currenBalance);

       }

 

}

 

[ InputDataCheckNaNExample2.java] "NaN"을 체크하고 연산 수행

public class InputDataCheckNaNExample2 {

 

       public static void main(String[] args) {

               String userInput = "NaN";

               double val = Double.valueOf(userInput);

              

               double currenBalance = 10000.0;

              

               if(Double.isNaN(val)) {

                      System.out.println("NaN 입력되어 처리할 없음.");

                      val = 0.0;

               }

              

               currenBalance += val;

               System.out.println(currenBalance);

       }

 

}

 

3.4.2 문자열 연결 연산자(+)

문자열 연결 연산자인 +는 문자열을 서로 결합하는 연산자이다.

                  String str1 = "JDK" + 6.0;

                       String str2 = str1 + "특징";

 

왼쪽에서 부터 오른쪽으로 연산이 진행된다.

"JDK" + 3 + 3.0;

 

3 + 3.0 +"JDK";

 

[ StringConcatExample.java]문자열 연결 연산자

public class StringConcatExample {

 

       public static void main(String[] args) {

               String str1 = "JDK" + 6.0;

               String str2 = str1 + "특징";

               System.out.println(str2);

              

               String str3 = "JDK" + 3 + 3.0;

               String str4 = 3 + 3.0 +"JDK";

               System.out.println(str3);

               System.out.println(str4);

       }

 

}

 

3.4.3 비교연산자(<.<=,>,>=, == . !=)

boolean타입인 true/flase를 산출한다.

대소(<, <=, >, >=) 또는 동등(==, !=) 비교해 boolean 타입인 true/false 산출

 

    • 동등 비교 연산자는 모든 타입에 사용
    • 크기 비교 연산자는 boolean 타입 제외한 모든 기본 타입에 사용
    • 흐름 제어문인 조건문(if), 반복문(for, while)에서 주로 이용

      실행 흐름을 제어할 때 사용

만약 피연산자가 char타입이면 유니코드 값으로 비교 연산을 수행한다.

 ('A' < 'B')  ----------> (65 < 66)

 

[CompareOperatorExample1.java]비교 연산자

public class CompareOperatorExample1 {

 

       public static void main(String[] args) {

               int num1 = 10;

               int num2 = 10;

               boolean result1 = (num1 == num2);

               boolean result2 = (num1 != num2);

               boolean result3 = (num1 <= num2);

               System.out.println("result1=" + result1);

               System.out.println("result2=" + result2);

               System.out.println("result3=" + result3);

 

               char char1 = 'A';

               char char2 = 'B';

               boolean result4 = (char1 < char2);

               System.out.println("result4=" + result4);

       }

 

}

 

비교 연산자에서도 연산을 수행하기 전에 타입 변환을 통해 피연산자의 타입을 일치시킨다.

'A' == 65 ->true

3 == 3.0 ->true

 

그러나 한가지 예외가 있다.

0.1 == 0.1f ->false

이유는 이진 포맷의 가수를 이용하는 모든 부동소수점 타입은 0.1을 정확히 표현할 수가 없어서 0.1f0.1의 근사값으로 표현

 

[ CompareOperatorExample2.java] 비교 연산자

public class CompareOperatorExample2 {

       public static void main(String[] args) {

        int v2 = 1;

        double v3 = 1.0;

        System.out.println(v2 == v3); //true

       

        double v4 = 0.1;

        float v5 = 0.1f;

        System.out.println(v4 == v5); //false

        System.out.println((float)v4 == v5); //true

        System.out.println((int)(v4*10) == (int)(v5*10)); //true

    }

}

 

=>문자열 비교

String타입의 문자열을 비교할 때는 대소 (<, <= , > , >=)연산자를 사용할 수 없고 , 동등(== , != ) 비교 연산자는 사용할 수 있으나 같은지 ,다른지를 비교하는 용도로는 사용되지 않는다.

String strVar1 = "신용권";

String strVar2 = "신용권";

String strVar3 = new String("신용권");

 

자바는 문자열 리터럴이 동일하다면 동일한 String 객체를 참조하도록 되어 있다. strVar1strVar2는 동일한 String객체의 번지값을 가지고 있다. 그러나 strVar2은 객체 생성 연산자인 new로 생성한 새로운 String객체의 번지값을 가지고 있다.

strVar1 == strVar2 ->true

strVar2 == strVar3 ->false

equals()메소드는 원본 문자열과 매개값으로 주어진 비교 문자열이 동일한지 비교한 후 true또는 false를 리턴한다.

boolean result = str1.equals(str2);

아래 것으로 변경=>

strVar1.equals(strVar2)

strVar2.equals(strVar3)

 

[ StringEqualsExample.java] 문자열 비교

public class StringEqualsExample {

       public static void main(String[] args) {

               String strVar1 = "신민철";

               String strVar2 = "신민철";

               String strVar3 = new String("신민철");

 

               System.out.println(strVar1 == strVar2);

               System.out.println(strVar1 == strVar3);

               System.out.println();

               System.out.println(strVar1.equals(strVar2));

               System.out.println(strVar1.equals(strVar3));

       }

}

 

3.4.4 논리 연산자 (&&, || , & , |, ^, !)

 

논리곱(&&), 논리합(||), 배타적 논리합(^) ,논리 부정(!) 연산 수행

피연산자는 boolean 타입만 사용 가능

&& 는 앞의 피연산자가 false라면 뒤의 모든 피연사자를 평가하지 않고 바로 false라는 산출 결과를 낸다.

그러나 &는 두 피연사자 모두를 평가해서 산출 결과를 낸다.

|| 는 앞의 피연산자가 true라면 뒤의 모든 피연사자를 평가하지 않고 바로 true라는 산출 결과를 낸다.

그러나 |는 두 피연사자 모두를 평가해서 산출 결과를 낸다.

 

[ LogicalOperatorExample.java]논리 연산자

public class LogicalOperatorExample {

       public static void main(String[] args) {

               int charCode = 'A';

 

               if ((charCode >= 65) & (charCode <= 90)) {

                      System.out.println("대문자 이군요");

               }

 

               if ((charCode >= 97) && (charCode <= 122)) {

                      System.out.println("소문자 이군요");

               }

 

               if (!(charCode < 48) && !(charCode > 57)) {

                      System.out.println("0~9 숫자 이군요");

               }

 

               int value = 6;

 

               if ((value % 2 == 0) | (value % 3 == 0)) {

                      System.out.println("2 또는 3 배수 이군요");

               }

 

               if ((value % 2 == 0) || (value % 3 == 0)) {

                      System.out.println("2 또는 3 배수 이군요");

               }

       }

}

 

3.4.5 비트 연산자(&, |, ^, ~, <<, >>, >>>)

비트(bit) 단위로 연산 하므로 0 1이 피연산자

                               0 1로 표현이 가능한 정수 타입만 비트 연산 가능

                               실수 타입인 float double은 비트 연산 불가

    • 종류

      비트 논리 연산자(&, |, ^, ~)

      비트 이동 연산자(<<, >>, >>>)

 

=>비트 논리 연산자(&, |, ^, ~)

피 연산자가 boolean타입일 경우 일반 논리 연산자

피연산자가 정수 타입일 경우 비트 논리 연산자로 사용

비트 연산자는 피연산자를 int타입으로 자동 타입 변환 후 연산 수행

 

 

4525 관련 계산

 

 

byte num1 = 45;

byte num2 = 25;

byte result = num1 & num2 ; //컴파일 에러 => int result = num1 & num2;

int로 계산한다

 

 

[ BitLogicExample.java ]비트 논리 연산자

public class BitLogicExample {

       public static void main(String[] args) {

               System.out.println("45 & 25 = " + (45 & 25));

               System.out.println("45 | 25 = " + (45 | 25));

               System.out.println("45 ^ 25 = " + (45 ^ 25));

               System.out.println("~45 = " + (~45));

       }

}

 

=>비트 이동 연산자(<<, >>, >>>)

정수 데이터의 비트를 좌측 또는 우측으로 밀어 이동시키는 연산 수행

 

 

좌측 이동 연산자를 이용하여 중수 13비트만큼 왼쪽으로 이동

int result = 1  << 3;

 

 

-83비트 만큼 오르쪽으로 이동

int result = -8 >> 3

 

int result = -8 >>> 3

 

[ BitShiftExample.java ]비트 이동 연산자

public class BitShiftExample {

 

       public static void main(String[] args) {

               System.out.println("1 << 3" + (1 << 3));

               System.out.println("-8 >> 3" + (-8 >> 3));

               System.out.println("-8 >>> 3" + (-8 >>> 3));

       }

 

}

 

3.4.6 대입 연산자(=,  +=,  -=,  *=,  /=,  %=, &=, ^=, |=, <<=, >>=, >>>=)

오른쪽 피연산자의 값을 좌측 피연산자인 변수에 저장

모든 연산자들 중 가장 낮은 연산 순위 -> 제일 마지막에 수행

오늘쪽 피연사자는 리터럴 및 변수 ,그리고 다른 연산식이 올 수 있다.

단순히 오른쪽 피 연산자의 값을 변수에 저장하는 단순 대입연사자가 있고, 정해진 연산을 수행한 후 결과를 변수에저장하는 복합 대입 연산자도 있다.

    • 종류

      단순 대입 연산자

      복합 대입 연산자

 정해진 연산을 수행한 후 결과를 변수에 저장

a = b = c = 5

순서 1) c = 5

     2) b = c = 5

     3) a = b = c = 5

 

대입 연산자의 종류

 

 

[ AssignmentOperatorExample.java] 대입 연산자

public class AssignmentOperatorExample {

       public static void main(String[] args) {

               int result = 0;

               result += 10;

               System.out.println("result=" + result);

               result -= 5;

               System.out.println("result=" + result);

               result *= 3;

               System.out.println("result=" + result);

               result /= 5;

               System.out.println("result=" + result);

               result %= 3;

               System.out.println("result=" + result);

       }

}

 

3.5 삼항 연산자

세 개의 피연산자를 필요로 하는 연산자

앞의 조건식 결과에 따라 콜론 앞 뒤의 피연산자 선택 -> 조건 연산식

 

 

 

 

[ ConditionalOperationExample.java]삼항 연산자

public class ConditionalOperationExample {

    public static void main(String[] args){

        int score =85;

        char grade = (score > 90) ? 'A' : ((score > 80 ? 'B' : 'C'));

        System.out.println(score + " " + grade);

    }

}

 

연습문제

1. 연산자와 연산식에 대한 설명 중 틀린 것은 무엇입니까?

 

1. 연산자는 피연산자의 수에 따라 단항, 이항, 삼항 연산자로 구분된다.

2.비교 연산자와 논리 연산자의 산출 타입은 boolean (true/false) 이다.

3.연산식은 하나 이상의 값을 산출할 수도 있다.

4.하나의 값이 올 수 있는 자리라면 연산식도 올 수 있다.

 

2. 다음 코드를 실행했을 때 출력 결과는 무엇입니까?

 

package sec3;

 

public class Exercise02 {

    public static void main(String[] args) {

        int x = 10;

        int y = 20;

        int z = (++x) + (y--);

        System.out.println(z);

    }

 

}

 

 

3. 다음 코드를 실행했을 때 출력 결과는 무엇입니까?

package sec3;

 

public class Exercise03 {

 

    public static void main(String[] args) {

        int score = 85;

        String result = (!(score>90))? "":"";

        System.out.println(result);

    }

}

 

 

4. 534자루의 연필을 30명의 학생들에게 똑같은 개수로 나누어 줄 때 학생당 몇 개를 가질 수 있고, 최종적으로 몇 개가 남는지를 구하는 코드입니다. ( #1 ) ( #2 )에 들어갈 알맞은 코드를 작성하세요.

package sec3;

 

public class Exercise04 {

 

    public static void main(String[] args) {

        int pencils = 534;

        int students = 30;

        

        //학생  명이 가지는 연필 

        int pencilsPerStudent = ( #1 );

        System.out.println(pencilsPerStudent);

        

        //남은 연필 

        int pencilsLeft = ( #2 );

        System.out.println(pencilsLeft);

    }

}

 

#1 = pencils / students

#2 = pencils % students

 

5. 다음은 십의 자리 이하를 버리는 코드입니다. 변수 value의 값이 356이라면 300이 나올 수 있도록 ( #1 ) 에 알맞은 코드를 작성하세요(산술 연산자만 사용하세요).

package sec3;

 

public class Exercise05 {

    public static void main(String[] args) {

        int value = 356;

        System.out.println( #1 );

    }

}

 

#1 = value /100 * 100

 

6. 다음 코드는 사다리꼴의 넓이를 구하는 코드입니다. 정확히 소수자릿수가 나올 수 있도록 ( #1 ) 에 알맞은 코드를 작성하세요.

package sec3;

 

public class Exercise06 {

 

    public static void main(String[] args) {

        int lengthTop = 5;

        int lengthBottom = 10;

        int height = 7;

        double area = ( #1 );

        System.out.println(area);

    }

 

}

 

 

 

#1 = 7 * (lengthTop+lengthBottom)/2

 

7. 다음 코드는 비교 연산자와 논리 연산자의 복합 연산식입니다. 연산식의 출력 결과를 괄호( ) 속에 넣으세요.

package sec3;

 

public class Exercise07 {

 

    public static void main(String[] args) {

        int x = 10;

        int y = 5;

        

        System.out.println((x>7&& (y<=5));

        System.out.println((x%3 ==2|| (y%2 != 1));

    }

}

 

 

8. 다음은 % 연산을 수행한 결과값에 10을 더하는 코드입니다. NaN 값을 검사해서 올바른 결과가 출력될 수 있도록 ( #1 ) 에 들어갈 NaN을 검사하는 코드를 작성하세요.

package sec3;

 

public class Exercise08 {

    public static void main(String[] args) {

        double x =5.0;

        double y =0.0;

        

        double z = x % y;

        

        if(#1) {

            System.out.println("0.0으로 나눌  없습니다.");

        } else {

            double result = z + 10;

            System.out.println("결과: " + result);

        }

    }

}

 

 

 

 

 

 

 

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

06. 클래스  (0) 2020.09.28
05. 참조 타입  (0) 2020.09.27
04. 조건문과 반복문  (0) 2020.09.26
02.변수와 타입  (1) 2020.09.22
01. 자바 시작하기  (0) 2020.09.20
반응형

출처:이것이 자바다 

변수와 타입

2.1 변수

2.1.1  변수란?

데이터를 메모리에 저장한다.

변수(Variable)는 값을 저장할 수 있는 메모리의 공간을 의미한다.

수시로 값이 변동될 수 있기 때문이다.

변수에는 복수 개의 값을 저장할 수 없고 , 하나의 값만 저장할 수 있다.

 

변수란, 하나의 값을 저장할 수 있는 메모리 공간이다.

 

2.1.2 변수의 선언

변수 선언은 어떤 타입의 데이터를 저장할 것인지 그리고 변수 이름이 무엇인지를 결정한다.

프로그램은 변수 이름을 통해서 메모리 주소에 접근하고 , 그곳에 값을 저장하거나 그곳에 있는 값을 읽는다.

 

같은 타입 변수 선언한 예:

int x,y,x ;

 

명명규칙(naming convention)

 

 

예약어:

 

 

가급적이면 한글을 포함하지 않는 것이 좋다.

 

2.1.3 변수의 사용

=>변수값 저장

변수에 값을 저장할 때는 대입 연산자(=)를 사용한다.

우측의 값을 좌측 변수에 저장한다는 의미

초기값: 변수를 선언하고 처음 값을 저장할 경우

변수에 초기값을 주는 행위를 변수의 초기화라고 한다.

 

 

int score ; //변수 선언

score = 90; //값 저장

 

 

 

 

 

int score = 90;

 

변수의 초기값은 코드에서 직접 입력하는 경우가 많은데 ,소스 코드에서 직접 입력된 값을 리터럴(literal)이라고 부른다. 리터럴은 값의 종류에 따라 정수 리터럴 , 실수 리터털, 문자 리터럴, 논리 리터럴로 구분된다.

리터럴 은 상수(constant)와 같은 의미이다. "값을 한 번 저장하면 변경할 수 없는 변수"로 정의

 

==>정수 리터럴

소수점이 없는 10진수 => 0, 75, -100

0으로 시작되는 리터럴 8진수 => 02, -04

0x또는 0X 16진수 => 0x5, 0xA, 0xB3, 0xAC08

정수 리터럴을 저장할 수 있는 타입은 byte, char, short, int ,long

==>실수 리터럴

소수점이 있는 10진수 =>0.25 , -3.14

대문자 E또는 소문자 e가 있는 10진수 => 5E7 , 0.12E-5

E -> 10

float, double

==>문자 리터럴

작은 따옴표(') => 'A' , '' , ''\t' ,''\n'

역슬래쉬(\) 가 이스케이프문자

 

char

 

==>문자열 리터럴

큰 따옴표(")

"대한민국"

"탭 만큼 이동 \t 합니다."

"한줄 내려 쓰기 \n 합니다."

string

 

==>논리 리터럴

true , false

boolean

 

=>변수값 읽기

변수 선언하고 초기화가 되지 않을 경우 에러가 난다.

 

[VariableExample.java] 변수 선언과 초기화

public class VariableExample {

 

       public static void main(String[] args) {

               //10 변수 value 초기값으로 설정

               int value = 30;

               //변수 value값을 읽고 10 더하는 산술 연산을 수행

               //연산의 결과값을 변수 result 초기값으로 저장

               int result = value + 10;

               //변수 result 값을 읽겨 콘솔에 출력

               System.out.println(result);

       }

 

}

 

2.1.4 변수의 사용 범위

변수는 선언된 블록 내에서만 사용이 가능하다.

locla variable -메소드 블록 내에서 선언된 변수

[VariableScopeExample.java] 변수의 사용 범위

public class VariableScopeExample {

 

       public static void main(String[] args) {

               int v1= 15;

               if(v1 > 10) {

                      int v2 = v1 -10;

               }

               //int v3= v1+v2+5; //v2변수를 사용할 없기 때문에 에러가 발생

       }

 

}

 

2.2 데이터 타입

2.2.1 기본(원시 : primitive)타입

기본 타입이란 정수 ,실수 , 문자 , 논리 리터럴을 직접 저장하는 타입

 

메모리에는 01을 저장하는 최소 기억 단위인 비트가 있다.

그리고 8개의 비트를 묶어서 바이트라고 한다.

기본 타입은 정해진 메모리 사용 크기(바이트 크기)로 값을 저장

실수 타입일 경우 가수와 지수 부분에 사용되는 bit 크기에 따라서 값의 범위가 결정된다.

 

2.2.2 정수 타입(byte, char, short, int ,long)

 

자바는 기본적을 정수 연산을 int타입으로 수행한다.

주의 할점 :

메로리 사용량

잘못된 결과

 

=>byte타입

색상 정보 및 파일 또는 이미지 등의 이진(바이너리)데이터를 처리

 

만약 -128 ~ 127을 초과하는 값이 byte타입 변수에 저장 될 경우 컴파일 에러 ("Type mismatch: cannot convert from int to byte)가 발생한다.

 

[ByteExample .java] byte 타입 변수

public class ByteExample {

       public static void main(String[] args) {

               byte var1= -128;

               byte var2 = -30;

               byte var3 = 0;

               byte var4 = 30;

               byte var5 = 127;

               //byte var6 = 128;//컴파일 에러

              

               System.out.println(var1);

               System.out.println(var2);

               System.out.println(var3);

               System.out.println(var4);

               System.out.println(var5);

              

       }

}

 

 

 

자리수를 초과할 경우 - 로 변한다.

[GarbageValueExample.java] byte 타입 변수

public class GarbageValueExample {

 

       public static void main(String[] args) {

               byte var1 = 125;

               int var2 = 125;

               for(int i = 0; i < 5; i++) {

                      var1++;

                      var2++;

                      System.out.println("var1: "+var1+ "\t" +"var2: "+var2);

               }

       }

 

}

 

=>char타입

자바는 모든 문자를 유니코드로 처리한다.

0 ~ 65535범위의 2byte크기를 가진 정수값

자바는 하나의 유니코드를 저장하기 위해 2byte 크기인 char타입을 제공한다.

 

16진수 값

char c = 64;

char c = '\u0041';

int타입으로도 저장가능하다.

char c= 'A'

int uniCode = c;

[ CharExample.java] char 타입 변수

public class CharExample {

       public static void main(String[] args) {

               char c1= 'A';//문자를 직접 저장

               char c2 = 65; //10진수로 저장

               char c3 ='\u0041'; //16진수로 저장

              

               char c4 = '';//문자를 직접 저장

               char c5 = 44032; //10진수로 저장

               char c6 = '\uac00';//16진수로 저정

                            

               int uniCode = c1;//유니코드 얻기

              

               System.out.println(c1);

               System.out.println(c2);

               System.out.println(c3);

               System.out.println(c4);

               System.out.println(c5);

               System.out.println(c6);

               System.out.println(uniCode);

       }

}

 

String name = "홍길동";

String은 기본 타입이 아닌다. String은 클래스 타입이고 String변수는 참조 변수이다.

String 객체가 생성되고 ,String변수는 String객체의 번지를 참조하게 된다.

 

 

 

char c = '';//컴파일 에러 ->char c = ' ';

 

String str = "";

 

=>short타입

 

=>int타입

int number = 10;

int octNumber = 012;

int hexNumber = 0xA;

 

 

[ IntExample.java] int 타입 변수

public class IntExample {

 

       public static void main(String[] args) {

               int var1 = 10;

               int var2 = 012;

               int var3 = 0xA;

              

               System.out.println(var1);

               System.out.println(var2);

               System.out.println(var3);

       }

 

}

 

[ LongExample.java ]long타입 변수

public class LongExample {

 

       public static void main(String[] args) {

               long var1 = 10;

               long var2 = 20L;

               //long var3 = 1000000000000;//컴파일 에러

               long var4 = 1000000000000L;

              

               System.out.println(var1);

               System.out.println(var2);

               System.out.println(var4);

       }

 

}

 

범위를 넘어서면 오류가 난다.

 

2.2.3 실수 타입(Float, double)

메모리 사용크기에 따라 두가지로 나눈다.

 

 

실수는 정수와 달리 부동 소수점(floating -point)방식으로 저장된다.

 

 

 

자바는 실수 리터럴을 double로 간주한다.

 

 

 

               double var1 = 3.14;

               //float var2 = 3.14//컴파일 에러

               float var3 = 3.14F;

 

               int var6 = 3000000;

               double var7 = 3e6;

               float var8 = 3e6f;

               double var9 = 2e-3;

 

[FloatDoubleExample.java] float double 타입

public class FloatDoubleExample {

 

       public static void main(String[] args) {

               //실수값 저장

               double var1 = 3.14;

               //float var2 = 3.14//컴파일 에러

               float var3 = 3.14F;

              

               //정밀도 테스트

               double var4 = 0.1234567890123456789;

               float var5 = 0.1234567890123456789F;

              

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

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

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

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

              

               //e사용하기

               int var6 = 3000000;

               double var7 = 3e6;

               float var8 = 3e6f;

               double var9 = 2e-3;

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

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

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

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

       }

 

}

 

2.2.4 논리 타입(boolean)

[ BooleanExample.java]boolean 타입

public class BooleanExample {

 

       public static void main(String[] args) {

               boolean stop = true;

               if(stop) {

                      System.out.println("중지합니다.");

               }else {

                      System.out.println("시작합니다.");

               }

       }

 

}

 

2.3 타입 변환

2.3.1 자동 타입 변환

자동 타입 변환(Promotion)은 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것을 말한다.

 

 

 

               byte byteValue = 10;

               int intValue = byteValue;//자동 타입 변환이 일어난다.

byte 1byte 크기를 가진다.

int 4byte 크기를 가진다.

 

변환 이전의 값은 변환 이후에도 손실 없이 그래도 보존된다.

 

정수 타입이 실수 타입으로 변환하는 것은 무조건 자동 타입 변환이 된다. 실수 타입으로 변환된 이후의 값은 정수값이 아닌 .0이 붙은 실수값이 된다.

               int intValue = 200;

               double doubleValue = intValue;//200.0

char 타입의 경우 int타입으로 자동 변환되면 유니코드 값이 int타입에 저장된다.

               char charValue = 'A';

               int intValue = charValue; //64 저정

 

byte타입을 char타입으로 자동 변환시킬 없다.

               byte byteValue = 65;

               char charValue = byteValue;// 컴파일 에러

               char charData = (char)byteData;//강제 타입 변환(조금 후에 설명됨)

 

[PromotionExample] 자동 타입 변환

public class PromotionExample {

 

       public static void main(String[] args) {

               byte byteValue = 10;

               int intValue = byteValue;//int <- byte 자동 타입 변환이 일어난다.

               System.out.println(intValue);

              

               char charValue = '';

               intValue = charValue; //int <- char

               System.out.println("가의 유니코드 = " +intValue);

              

               intValue = 500;

               long longValue = intValue;//long <- int

               System.out.println(longValue);

              

               intValue = 200;

               double doubleValue = intValue; //double <-int

               System.out.println(doubleValue);

       }

 

}

 

2.3.2 강제 타입 변환

큰 크기의 타입은 작은 크기의 타입으로 자동 타입 변환을 할 수 없다.

강제적으로 큰 데이터 타입을 작은 데이터 타입으로 쪼개어서 저장하는 것을 강제 타입 변환(캐스팅:Casting)이라고 한다.

               int intValue = 103029770;

               byte byteValue = (byte)intValue;//강제 타입 변환(캐스팅)

byte만 남긴다.

               long longValue = 300;

               int intValue = (int)longValue ;//intValue 300 그대로 저장된다.

int타입은 char타입으로 자동 변환되지 않기 때문에 강제 타입 변환을 사용해야 한다.

               int intValue = 'A';

               char charValue = (char)intValue;

               System.out.println(charValue);

실수 타입은 정수 타입으로 자동 변환되지 않기 때문에 강제 타입 변환을 사용해야 한다. 소수점 이하 부분은 버려지고,정수 부분만 저장된다.

               double doubleValue = 3.14;

               int intValue = (int)doubleValue; //intValue 정수 부분인 3 저장된다.

[ CastingExample.java] 강제 타입 변환

public class CastingExample {

 

       public static void main(String[] args) {

               int intValue = 44032;

               char charValue = (char)intValue;

               System.out.println(charValue);

              

               long longValue = 500;

               intValue = (int)longValue;

               System.out.println(intValue);

 

               double doubleValue = 3.14;

               intValue = (int)doubleValue;

               System.out.println(intValue);

       }

 

}

 

강제 타입 변환에서 주의할 점은 사용자로부터 입력받은 값을 변환할 때 값의 손실이 발생하면 안된다는 것이다.

[CheckValueBeforeCasting.java] 변환으로 인한 테이터 손실이 발생되지 않도록 한다.

public class CheckValueBeforeCasting {

 

       public static void main(String[] args) {

               int i = 128;

              

               if((i<Byte.MAX_VALUE) || (i > Byte.MAX_VALUE)) {

                      System.out.println("byte 타입으로 변환할 없습니다.");

                      System.out.println("값을 다시 확인해 주세요");

               }else {

                      byte b = (byte)i;

                      System.out.println(b);

               }

       }

 

}

 

최대값 최소값을 벗어나는지 반드시 검사하고 , 만약 벗어난다면 타입 변환을 하지 말아야 한다.

 

 

강제 타입 변환에서 또 다른 주의점이 있다. 정수 타입을 실수 타입으로 변환할 때 정밀도 손실을 피해야 한다.

 

정수 타입을 실수 타입으로 변환할 때 정밀도 손실을 피한다.

[FromIntFloat.java] 정수 타입을 실수 타입으로 변환할 때 정밀도 손실을 피한다.

public class FromIntFloat {

 

       public static void main(String[] args) {

               int num1 = 123456780;

               int num2 = 123456780;

              

               float num3 = num2;

               num2 = (int)num3;

              

               int result = num1 - num2;

               System.out.println(result);

       }

 

}

이유는 int값을 float타입으로 자동 변환하면서 문제가 발생했기 때문이다.

 

 

int값을 손실 없이 float타입의 값으로 변환할 수 있으려면 가수 23비트로 표현 가능한 값이어야 한다.

해결책은 모든 int값을 실수 타입으로 안전하게 변환시키는 double타입을 사용하는 것이다.

 

int의 크기는 32비트이므로 double의 가수 52비트보다는 작기 때문에 어떠한 int 값이라도 안전하게 정밀도 손실 없이 double타입으로 변환될 수 있다.

 

정수 타입을 실수 타입으로 변환할 때 정밀도 손실을 피한다.

[FromIntToDouble.java] 정수 타입을 실수 타입을 변환할 때 정밀도 손실을 피한다.

public class FromIntToDouble {

 

       public static void main(String[] args) {

               int num1 = 123456780;

               int num2 = 123456780;

              

               double num3 = num2;

               num2 = (int)num3;

              

               int result = num1 - num2;

               System.out.println(result);

       }

 

}

 

2.3.3 연산식에서의 자동 타입 변환

연산은 기본적으로 같은 타입의 피연산자(Operand)간에만 수행되기 때문에 서로 다른 타입의 피연산자가 있을 경우 두 피연산자 중 크기가 큰 타입으로 자동 변환된 후 연산을 수행한다.

: int 타입 피연산자가 double타입으로 자동 변환되고 연산을 수행한다.

 

만약 int타입으로 꼭 연산을 해야 한다면 double타입을 int타입으로 강제 변환하고 덧셈 연산을 수행하면 된다.

 

자바는 정수 연산일 경우 int타입을 기본으로 한다. 그 이유는 피연산자를 4byte 단위로 저장하기 때문이다.

 

 

예를 들어 char타입의 연산 결과는 int타입으로 산출되므로 int타입 변수에 결과를 저장해야 한다. casting해야 한다.

               char ai = 'A';

               int result = ai +1;     //'A' 유니코드보다 1 유니코드가 저장

               char na = (char)result; //'B' 저장됨

 

만약 피연산자 중 하나가 long 타입이라면 다른 피연산자도 long 타입으로 자동 타입 변환되고 연산의 결과는 long 타입이 된다.

 

 

float 타입과 float 타입을 연산하면 연산의 결과는 float 타입으로 나오지만, 피연산자 중에 실수 리터럴이나 double 타입이 있다면 다른 피연산자도 double 타입으로 자동 타입 변환되어 연산되므로 결과는 double 타입으로 산출된다.

 

[OpreationsPromotionExample.java] 연삭식에서 자동 타입 변환

public class OpreationsPromotionExample {

 

       public static void main(String[] args) {

               byte byteValue1 = 10;

               byte byteValue2 = 20;

               //byte byteValue3 = byteValue1 + byteValue2;//컴파일 에러

               int intValue1 = byteValue1 + byteValue2;

               System.out.println(intValue1);

              

               char charValue1 = 'A';

               char charValue2 = 1;    

               //char charValue3 = charValue1 + charValue2;//컴파일 에러

               int intValue2 = charValue1 + charValue2;;

               System.out.println("유니코드="+intValue2);

              System.out.println("출력문자="+(char)intValue2);

              

               int intValue3 = 10;

               int intValue4 = intValue3 / 4;

               System.out.println(intValue4);

              

               int intValue5 = 10;

               //int intValue6 = 10 / 4.0; //컴파일 에러

               double doubleValue = intValue5 / 4.0;

               System.out.println(doubleValue);

       }

 

}

 

 

연습문제

1. 자바에서 변수에 대한 설명 중 틀린 것은 무엇입니까? (4)

 

1. 변수는 하나의 값만 저장할 수 있다.

2. 변수는 선언 시에 사용한 타입의 값만 저장할 수 있다.

3. 변수는 변수가 선언된 중괄호 ( {} ) 안에서만 사용 가능하다.

4. 변수는 초기값이 저장되지 않은 상태에서 읽을 수 있다.

 

2. 변수 이름으로 사용 가능한 것을 모두 선택하세요. (1,4,5)

 

1.modelName

2.class

3.6hour

4.$value

5._age

6.int

 

3. 다음 표의 빈칸에 자바의 기본 타입 (Primitive Type) 8개를 적어보세요.

크기/타입 1byte 2byte 4byte 8byte
정수타입 byte char
short
int long
실수타입     float double
논리타입 boolean      

 

4. 다음 코드에서 타입, 변수 이름, 리터럴에 해당하는 것을 적어 보세요.

 

int age;

age = 10;

double price = 3.14;

 

타입 : (int),(double)

변수 이름 : (age),(price)

리터럴 : (10),(3.14)

 

5. 자동 타입 변환에 대한 내용입니다. 컴파일 에러가 발생하는 것은 무엇입니까? (3)

 

byte byteValue = 10;

char charValue = 'A';

 

1. int intValue = byteValue;

2. int intValue = charValue;

3. short shortValue = charValue;

4. double doubleValue = byteValue;

 

6. 강제 타입 변환 (Casting) 에 대한 내용입니다. 컴파일 에러가 발생하는 것은 무엇입니까? (4)

 

int intValue = 10;

char charValue = 'A';

double doubleValue = 5.7;

String strValue = "A";

 

1. double var = (double) intValue;

2. byte var = (byte) intValue;

3. int var = (int) doubleValue;

4. char var = (char) strValue;

 

7. 변수를 잘못 초기화한 것은 무엇입니까? (3)

 

1. int var1 = 10;

2. long var2 = 10000000000L;

3. char var3 = ''; //작은 따옴표 두 개가 붙어 있음

4. double var4 = 10;

5. float var5 = 10;

 

8. 연산식에서의 타입 변환 내용입니다. 컴파일 에러가 생기는 것은 무엇입니까? (1)

 

byte bytebyteValue = 10;

float floatValue = 2.5F;

double doubleValue = 2.5;

 

1. byte result = byteValue + byteValue;

2. int result = 5 + byteValue;

3. float result = 5 + floatValue;

4. double result = 5+ doubleValue;

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

06. 클래스  (0) 2020.09.28
05. 참조 타입  (0) 2020.09.27
04. 조건문과 반복문  (0) 2020.09.26
03. 연산자  (0) 2020.09.24
01. 자바 시작하기  (0) 2020.09.20
반응형

출처:이것이 자바다 

자바 시작하기

1.1 프로그래밍 언어란?

기계어는 01로 이루어진 이진 코드이기 때문에 사람이 이해하기에는 매우 어렵다.

사람의 언어와 기계어의 다리 역할을 하는 프로그래밍 언어

=>프로그래밍 언어:

==>고급언어: 컴퓨터와 대화할 수 있도록 만든 언어 중에서 사람이 쉽게 이해할 수 있는 언어      

고급언어로 작성된 소스는 컴퓨터가 바로 이해할 수 없기 때문에 컴파일 과정을 통해서 컴퓨터가 이해할 수 있는 01로 이루어진 기계어로 변환한 후 컴퓨터가 사용하게 됩니다.

==>저급언어: 기계어에 가까운 언어를 말하는데, 대표적으로 어셈블리어가 저급 언어에 속한다.

저급언어는 사람이 쉽게 이해할 수 없기 때문에 배우기가 매우 까다롭다.

 

대표적인 프로그래밍 언어 c , c++, java

이 언어들로 작성된 내용을 소스라고 부르고, 이 소스는 컴파일러라는 소프트웨어에 의해 기계어로 변환된 후 컴퓨터에서 실행할 수 있게 된다.

프로그램이란 컴퓨터에서 특정 목적을 수행하기 위해 프로그래밍 언어로 작성된 소스를 기계어로 번역한 것을 말한다.

 

1.2 자바란?

1.2.3 자바 소개

1995년 썬 마이크로시스템즈

자바는 1991년에 썬의 엔지니어들에 의해서 고안된 오크(Oak)라는 언어에서부터 시작되었다.

오크는 가전제품에서 사용될 목적이었다.

자바는 메모리 및 cpu를 지나치게 많이 사용학 때문에 윈도우 프로그래밍 언어로는 부적합하다는 문제점이 있다. 하지만 1999년부터 인터넷이 활성화되면서 웹 애플리케이션 구축용 언어로 자바가 급부상해다.

금융, 공공, 대기업 등의 엔터프라이즈 기업 환경에서 실행되는 서버 애플리케이션을 개발하는 중추적인 언어로 자리매김하고 있다.

 

1.2.2 자바의 특징

=>이식성이 높은 언어이다.

다른 실행 환경을 가진 시스템 간에 프로그램을 옮겨 실행할 수 있는 것을 말한다.

자바는 자바 실행 환경(jre:java runtime environment)이 설치되어 있는 모든 운영체제에서 실행 가능하다.

=>객체지향 언어이다.

OOP(Object Oriented Programming)

캡슐화,상속, 다형성 기능

=>함수적 스타일 코딩을 지원한다.

람다식을 자바 8부터 지원한다.

=>메모리를 자동으로 관리한다.

c++은 메모리에 생성된 객체를 제거하기 위해 개발자가 직접 코드를 작성해야 한다. 잘 하지 않을 경우 프로그램이 다운되는 현상을 겪게 된다.

java는 개발자가 직접 메모리에 접근할 수 없도록 설계되었으며 , 메모리는 자바가 직접 관리한다.

객체 생성 시 자동으로 메모리 영역을 찾아서 할당하고 ,사용이 완료되면 쓰레기 수집기(Garbage Collector)를 실행시켜 자동적으로 사용하지 않는 객체를 제거시켜준다.

=>다양한 애플리케이션을 개발할 수 있다.

Java SE(Starndard Edition) - 기본 에디션

Java SE는 자바 프로그램들이 공통적으로 사용하는 자바 가상 기계(JVM: Java Virtual Machine)를 비롯해서 자바 프로그램 개발에 필수적인 도구와 라이브러리 API를 정의한다. 클라이언트와 서버 프로그램에 상관없이 자바 프로그램을 개발하기 위해서는 반드시 Java SE 구현체인 자바 개발 키트(Java Development Kit)를 설치해야 한다.

Java EE(Emterprise Edition) - 서버용 애플리케이션 개발 에디션

분산 환경(네트워크 ,인터넷)에서

서버용 애플리케이션

분산 처리 컴포넌트인 EJB(Enterprise Java Bean )그리고 XML 웹 서비스 등

=>멀티 스레드를 쉽게 구현할 수 있다.

하나의 프로그램이 동시에 여러 가지 작업 처리

=>동적 로딩(Dynamic Loading)을 지원한다.

객체가 필요한 시점에 클래스를 동적 로딩해서 객체를 생성한다. 유지보수를 쉽게 빠르게 진행 할 수 있다.

=>막강한 오픈소스 라이브러리가 풍부하다.

 

1.2.3 자바 가상 기계(JVM)

자바 프로그램은 완전한 가계어가 아닌 ,중간 단계의 비이트 코드

JVM은 운영체제에 종속적이다.

 

1.3 자바 개발 환경 구축

1.3.1 자바 개발 도구 (JDK)설치

JDK (Java Development Kit) : 자바 개발 키트 : 프로그램 개발에 필요한 자바 가상 기계 , 라이브러리 API,컴파일러 등의 개발 도구가 포함

JRE (Java Runtime Environment) : 자바 실행 환경 : 프로그램 실행에 필요한 자바 가상 기계(JVM). 라이브러리 API만 포함되어있다.

JRE =  JVM + 표준 클래스 라이브러리

JDK =  JRE + 개발에 필요한 도구

https://www.oracle.com/index.html 자바 8이상

 

=>환경설정 추가

 

 

 

JAVA_HOME은 이책에서 필요없다.

Path만 설정하면 된다.

 

환경 변수 Path가 잘 적용되었는지 체크하기 위해 명령 프롬프트를 실행하고 (기존에 실행된 명령 프롬프타가 있다면 닫고 새로 열어야 된다.)

명령어 : javac -version

 

1.3.2 API 도큐먼트

API(Application Programming Interface)

https://docs.oracle.com/javase/8/docs/api/

 

1.4 자바 프로그램 개발 순서

1.4.1 소스 작성에서부터 실행 까지

java.exe명령어가 실행되면 jvm은 바이트 코드 파일(Hello.class)을 메모리로 로드하고, 최적의 기계어로 번역하ㄴ다. main()메소드를 찾아 실행시킨다.

 

[Hello.java] 자바 소스 파일

public class Hello {

           public static void main(String[] args) {

                       System.out.println("Hello, welcome to the java world!");

           }

}

 

1.4.2 프로그램 소스 분석

클래스 : 필드 또는 메소드를 포함하는 블록

메소드 : 어떤 일을 처리하는 실행문들을 모아 놓은 블록

메소드 블록은 단독으로 작성될 수 없고 항상 클래스 블록 내부에서 작성되어야 합니다.

클래스의 이름: 주의할 점은 소스 파일명과 대소문자가 일치해야 한다. 그리고 숫자로 시작할 수 없고 , 공백을 포함해서도 안 된다.

java.exeJVM을 구동시키면 제일 먼저 main()메소드를 찾아서 실행시킨다. 프로그램 실행 진입점(entry point)라고 한다. main()메소드가 없는 클래스를 java.exe로 실행시키면 에러 메시지가 나타난다.

 

1.5 주석과 실행문

1.5.1 주석 사용하기

컴파일 과정에서 주석은 무시되고 실행문만 바이트 코드로 번역된다.

//

/* ~ */

/** ~ */ =>도큐먼트 주석 javadoc.exe명령어로 APTI도큐먼트를 생성하는데 사용한다.

 

[Hello.java] 주석 사용하기

public class Hello {

           //프로그램 실행 진입점

           public static void main(String[] args) {

                       //콘솔에 출력하는 실행문

                       System.out.println("Hello, welcome to the java world!");

           }//end of main

}//end of class

 

1.5.2 실행문과 세미콜론(;)

; 실행문이 끝났음을 표시해준다.

 

[RunStatementExample.java] 실행문과 세미콜론(;)

public class RunStatementExample {

           public static void main(String[] args) {

                       int x = 1; //변수 x를 선언하고 1을 저장

                       int y = 2; //변수 y를 선언하고 2을 저장

                       int result = x + y;//변수 result를 선언하고 x y를 더한 값을 저장

                       System.out.println(x+"+" +y +"="+result);//콘솔에 출력하는 메소드 호출

           }

}

 

1.6 이클립스 설치

1.6.1 이클립스 소개

디버깅이란 모듸 실행을 해서 코드의 오류를 찾는 것을 말한다.

이클립스는 자바 프로그램을 개발하기 이한 통합 개발 환경(IDE: Integrated Development Environments)

 

1.6.2 이클립스 다운로드

https://www.eclipse.org/

Eclipse IDE for Java EE Developsers

 

1.6.3 워크스피이스

디렉토리설정

[File - Switch Workspace - Other .. ]에서 변경

 

1.6.4 퍼스펙티브와 뷰

perspective

 

Console View

[Window -> Show View -> Console]

 

1.6.5 프로젝트 생성

[File -> New -> Java Project]

1.6.6 소스 파일 생성과 컴파일

[프로젝트 마우스 오른쪽 -> New -> Class]

 

에디터의 행번호를 보고 싶다면 메뉴에서

방법 1:

[Window -> Preferences] 를 클릭하고 트리 메뉴에서 [General -> Editors -> Text Edtors] =>show line numbers

방법 2:

클래스의 부분을 오른쪽 마우스 클릭하면 Show line numbers를 체크하면 된다.

 

bin디렉토리를 보고 싶다면

[Window -> show View -> Navigaor]를 선택하면 된다.

 

1.6.7 바이트 코드 실행

[class 마우스 오른쪽 버튼 -> Run As -> Java Application]

ð  console뷰에서 보인다.

 

1.7 풀인원 설치와 실행

학습 자료

www.hanbit.co.kr.exam/2147 소스 다운

 

연습문제

1. JDK JRE의 차이점을 설명한 것 중 틀린 것은 무엇입니까? (4)

 

1. JDK JRE와 컴파일러 등의 개발 도구가 포함된다.

2. 자바 프로그램을 개발하려면 JDK가 반드시 필요하다.

3. 자바 프로그램을 실행만 하려면 JRE를 설치해도 상관없다.

4. JRE에는 컴파일러(javac.exe)가 포함되어 있다.

 

JDK = JRE + 개발에 필요한 도구

JRE에는 프로그램 실행에 필요한 자바 가상 기계(JVM) , 라이브러리 API만 포함되어 있다.

 

2. JVM에 대한 설명으로 틀린 것은 무엇입니까? (3)

 

1. JVM java.exe 명령어에 의해 구동된다.

2. JVM은 바이트 코드를 기계어로 변환시키고 실행한다.

3. JVM은 운영체제에 독립적이다 (운영체제별로 동일한 JVM이 사용된다).

4. 바이트 코드는 JVM에 독립적이지만, JVM은 운영체제에 종속적이다.

 

JVM은 운영체제에 종속적이다.

 

3. 자바 프로그램 개발 과정을 순서대로 나열하세요.

 

1. javac.exe로 바이트 코드 파일(~.class)을 생성한다.

2. java.exe JVM을 구동시킨다.

3. 자바 소스 파일(~.java)을 작성한다.

4. JVM main() 메소드를 찾아 메소드 블록을 실행시킨다.

 

3 -> 1 -> 2 -> 4

 

4. 자바 소스 파일을 작성할 때 틀린 것은 무엇입니까? (4)

 

1. 자바 소스 파일명과 클래스 이름은 대소문자가 동일해야 한다.

2. 클래스 블록과 메소드 블록은 반드시 중괄호 {} 로 감싸야 한다.

3. 실행문 뒤에는 반드시 세미콜론(;)을 붙여야 한다.

4. 주석은 문자열 안에도 작성할 수 있다.

 

5. 자바 주석문의 종류가 아닌 것은 무엇입니까? (4)

 

1. // : 행 주석

2. /* */ : 범위 주석

3. /** **/ : API 도큐먼트 주석

4. <!-- --!> : 범위 주석

 

6. 이클립스에 대한 설명으로 틀린 것은 무엇입니까? (4)

 

1. 이클립스는 JDK (JRE)를 설치해야만 실행할 수 있다.

2. 이클립스에서 소스 파일을 저장하면 자동 컴파일되어 바이트 코드 파일이 생성된다.

3. 워크스페이스는 프로젝트들이 생성되는 기본 디렉토리를 말한다.

4. .metadata는 프로젝트의 소스 파일들이 저장되는 디렉토리이다.

 

 

 

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

06. 클래스  (0) 2020.09.28
05. 참조 타입  (0) 2020.09.27
04. 조건문과 반복문  (0) 2020.09.26
03. 연산자  (0) 2020.09.24
02.변수와 타입  (1) 2020.09.22

+ Recent posts