보통 코딩테스트에서 문장을주고 단어를 재배열하거나 이런 문제를 많이 낸다.

문장에서 단어는 보통 띄어쓰기로 구분이 되어있는데 이를 배열에 저장하는 법이 있다.

split을 사용하면 쉽게 가능하다.

String[] result = words.split(" ");

이를 실행하면 자동으로 String배열에 띄어쓰기마다 잘라서 각 단어를 저장해준다.

이렇게 문자열을 자를 때 사용하는 메서드가 하나더 있다.

substring메서드를 사용하는 것이다.
substring(시작위치) 또는, substring(시작위치, 끝위치)로 할 수 있다.

String str = "hello";

String result = str.substring(1);
System.out.println(result); // ello 출력

String result2 = str.substring(0,1);
System.out.println(result2) // h 출력

'Java > 짜잘한팁' 카테고리의 다른 글

[Java/Tip] 문자열 앞뒤 공백 지우기  (0) 2021.09.11

다형성한 타입의 조변수로 여러 타입의 객체를 참조할 수 있도록 하는 것이다.

다시말하자면

조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 하는것

다음과 같은 예제를 보자

class Car {
    private String engine;

    void turnOn()
    void turnOff()
    String getEngine()
    void setEngine(String engine)
}

class ElectroCar extends Car{
    String battery;
    void chargeBattery()
}

이런경우는 ElectorCarCar를 상속하고있다.

이럴때 인스턴스 객체를 다음과 같이 생성할 수 있다.

// 1번
Car car = new ElectroCar();
// 2번
ElectroCar= new ElectroCar();

이렇게 상속하는 관계일 경우에는 부모 클래스 타임의 참조변수로 자식 클래스의 인스턴스를 참조하도록 하는 것도 가능하다.

이렇게 상속하는 경우는 어떤 차이점이 있냐면

둘 다 같은 타입의 인스턴스지만 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다.

저 예시로 cartesla는 사용할 수 있는 멤버의 개수가 다르다.

  • teslaElectroCar의 멤버인 batterychangeBatttery()메서드를 사용이 가능하다.
  • carbatterychageBattery()의 메서드 사용이 불가능하다.

그렇다면 이렇게 생각할 수도 있을 것이다.

자식 타입이 참조변수로 조상타입의 인스턴스를 참조하는 케이스이다.

ElectroCar car = new Car();

이러한 경우에는 항상 생각해야할 것이 있다.

클래스는 상속을 통해서 확장이 가능하다 하지만 축소는 될 수가 없다.
부모 인스턴스의 개수는 자식 인스턴스의 멤버의 개수보다 같거나 적어야한다.

부모타입의 참조변수 → 자식타입의 인스턴스 참조 가능

자손타입의 참조변수 → 부모타입의 인스턴스 참조 불가능

참조변수의 형변환

참조변수도 형변환이 가능하다 형변환할 수 있는 조건은 다음과 같다.

  • 서로 상속관계에 있는 클래스만 가능하다.
  • 자식타입의 참조변수를 부모타입의 참조변수로 하는것이 가능하다.
  • 부모 타입의 참조변수를 자식타입의 참조변수로 형변환이 가능하다.
  • 자식타입의 참조변수를 부모타입의 참조변수로 형변환 할 때에는 작은 자료형에서 큰 자료형으로 형변환 하는 것이므로 생략이 가능하다.

형변환의 예시를 보자

Car car = null;
ElectroCar tesla1 = new ElectroCar();
ElectroCar tesla2 = null;

car = tesla1; // 작은것에서 큰것을 형변환 함으로 형변환 생략 (업캐스팅)
tesla2 = (ElectroCar)car; // 큰것에서 작은것으로 변환이므로 형변환 필요 (다운캐스팅)

이러한 두번째처럼 작은 곳에서 큰곳으로의 형변환은 생략할 수 없기 때문에

instanceof연산자를 사용하여 인스타입이 어떤것인지 확인하는 것이 안전하다.

이러한 형변환을 했을 때 틀리기 쉬운 오류들이 있다. 다음 예시를 보자

Car car = null;
ElectroCar tesla = new ElectroCar();

car = tesla;
car.chargeBattery(); // -> 불가능 하다. 

이러한 결과가 불가능한 이유는 형변환은 단지 참조변수의 타입을 변환하는 것이지 인스턴스를 변환하는 것은 아니기 때문이다

carCar인스턴스이기 때문에 메서드 호출이 불가능한것이다.

만약에 이런경우를 보자

Car car = null;
ElectroCar tesla1 = new ElectroCar();
ElectroCar tesla2 = null;

car = tesla;

tesla2 = (ElectroCar)car;
tesla2.chargeBattery(); // -> 가능하다.

이는 인스턴스가 tesla2가 형변화된 car를 받고 ElectroCar의 인스턴스이기 때문에 메서드를 사용 가능하다.

다운캐스팅을 함으로서 car에서 사용할 수 없었던 ElectroCar 의 기능을 사용할 수 있는 것이다.

정리하자면

  • 서로 상속관계에 있는 타입간의 형변환은 양방향 자유롭게 수행될 수 있다.
  • 참조 변수가 가리키는 인스턴스의 자손타입으로 형변환은 허용되지 않는다.
  • 참조변수가 가리키는 인스턴스의 타입이 무엇인지 instanceof 를 사용해서 확인하는 것이 중요한다.
  • 컴파일 시에는 참조변수간의 타입만 확인하기 때문에 오류가 없지만 메서드를 호출하거나 ㅎ라때는 에러가 발생할 수 있다.

Instanceof연산자

instaceof연산자는 참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아볼 수 있는 연산자이다.

bool형으로 연산의 결과를 반환한다.

  • ture가 나왔을 경우는 참조변수가 검사한 타입으로 형변환이 가능하다.
  • false가 나왔을 경우는 형변환이 불가능하다는 것이다.
ElectroCar tesla = new ElectroCar();

System.out.println(tesla instanceof ElectroCar); //true

System.out.println(tesla instanceof Car); //true

System.out.println(tesla instanceof Object); //true

tesla는 당연히 CarObject클래스를 다중상속 하였기 때문에 부모타입의 연산에 true를 결과로 얻는다.

참조변수와 인스턴스의 연결

우리는 형변환을 배워서 부모클래스던지 자식클래스로 참조변수의 타입을 변경할 수 있다.

만약에, 자식클래스와 부모클래스에 똑같은 변수가 있다고 생각해보자

인스턴스는 다음과 같이 2개를 생성하였다.

class Car{
    String name = "Parent car";
    void whoseCar(){
        System.out.println("Parent car");
    }
}

class ElectroCar extends Car{
    String name = "Child car";
    void whoseCar(){
        System.out.println("Child car");
    }
}

public static void main(String args){
    Car car = new ElectroCar();
    ElectroCar tesla = new ElectroCar();

    car.whoseCar(); // Child Car
    tesla.whoseCar(); // Child Car

    System.out.println(car.name); // Parent Car
    System.out.println(tesla.name); // Child Car
}

조금신기한 결과가 나타났다.

결과적으로 부모 클래스와 자식 클래스에 중복으로 정의됬을 경우

부모타입의 참조변수를 사용했을 경우는 조상클래스의 선언된 멤버변수가 사용된다.

하지만 메서드의 경우에는 참조변수의 타입에 관계 없이 인스턴스의 메서드(오버라이딩된 메서드)가 호출된다.

매개변수의 다형성

다형성은 클래스에만 국한하지 않고 메서드의 매개변수에서도 적용이 된다.

물품들을 구매하는 예제를 보자.

class Product{
    int price;
    int bonusPoint;
}

class Tv extends Product {}
class Computer extends  Product {}
class Audio extends Product {}

class Buyer{
    int money = 10000;
    int bonusPoint = 0;
}

여기서 구매를 한다는 표시로 buy()라는 메서드를 다음과 같이 만들것이다.

buy()는 일반적으로 Tv, Computer, Audio마다 각각 price가 다르기 때문에 이러한 buy()메서드를 총 3개를 만들어야할것이다.

class Buyer{
    int money = 10000;
    int bonusPoint = 0;

    void buy(Tv t){
        money -= t.price;
        bonusPoint += t.bonusPoint;
    }

    void buy(Computer c){
        money -= c.price;
        bonusPoint += c.bonusPoint;
    }

    void buy(Audio a){
        money -= a.price;
        bonusPoint += a.bonusPoint;
    }
}

이런식으로 총 3개의 매개변수가 다른 buy매서드를 오버로딩 해야할 것이다.

하지만 매개변수의 다형성을 이용한다면 다음과 같이 하나의 메서드로 줄일 수 있다.

class Buyer{
    int money = 10000;
    int bonusPoint = 0;

    void buy(Product p){
        money -= p.price;
        bonusPoint += p.bonusPoint;
    }

}

왜냐하면 제품들은 모두 Product를 상속받았기 때문이다.

이런방식으로 모든 클래스의 부모클래스는 Object이기 때문에 이를 활용한 예제도 가능하다는 것을 잊지 말자

또한, 이러한 객체들을 배열로 다룰수 있다.

Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();

이런식으로 부모타입인 Product 타입의 배열을 사용함으로서 상속한 자식들을 하나의 배열로 쉽게 이용할 수 있다.

Reference

  • 자바의 정석

'Java > Java' 카테고리의 다른 글

[Java/Study] 인터페이스  (0) 2021.09.11
[Java/Study] 추상클래스  (0) 2021.09.11
[Java/Study] 제어자  (0) 2021.09.09
[Java/Study] Package 와 Import 및 터미널로 자바 실행방법  (0) 2021.09.08
[Java/Study] 오버라이드  (0) 2021.09.07

제어자란?

제어자(modifier)는 변수와 메서드의 선언부에 함께 사용되어 부가적인 의미를 나타낸다.

제어자는 2가지 종류로 나뉜다.

  • 접근제어자
    • public, protected, default, private
  • 접근제어자 외의 것들
    • static, final, abstract, native, transient, synchronized, volatile, strictfp

제어자는 하나의 대상에 하나만 쓸수 있는 것이 아니라 하나의 대상에 대해서 여러 제어자를 조합하여 사용하는 것이 가능하다.

Static

static클래스의 라는 의미와 공통적인이라는 의미를 가지고 있다.

이러한 static이 붙은 메서드나 맴버변수는 인스턴스에 관계없이 같은 값을 가진다

static멤버변수, 메서드, 초기화 블럭에 사용된다.

static(클래스 변수) 와 인스턴스 변수의 차이점이 궁금하다면 이곳에 자세히 나와있다.

  • 멤버변수에서 사용이 되면 클래스변수가 되어서 모든 인스턴스에서 공통적으로 사용할 수 있다. 또한, 인스턴스를 생성하지 않고도 사용이 가능하다.
  • 메서드에서 사용이 되면 인스턴스를 생성하지 않고도 호출이 가능하다. 또한, static메서드 내에서 인스턴스 멤버들을 직접 사용할 수 없다.

Final

final은 마지막의 또는 변경될 수 없는이라는 의미를 가지고 있다.

final도 2장의 상수를 다루면서 설명하였다. 설명

final클래스, 메서드, 멤버변수, 지역변수에서 사용할 수 있다.

  • 클래스에서 사용이 되면 확장 될 수 없는 클래스가 된다. 그래서 다른 클래스의 부모클래스가 될 수 없다.
  • 메서드에서 사용이 되면 오버라이딩을 통해 재정의 될 수 없다.
  • 변수에서 사용이 되면 값을 변경할 수 없는 상수가 된다.

final은 항상 선언과 동시에 초기화를 하는 변수이다.

하지만 인스턴스변수인 경우는 생성자에서 초기화를 할 수 있다.

class Car {
    final String NAME;

    Car(String name){
        NAME = name;
    }
}

생성자를 사용하면 인스턴스마다 각기 다른값을 final로 가지게 할 수 있다.

Abstract

abstract미완성의 의미를 가지고 잇다. abstract가 붙으면 추상이라는 말이 따라온다.

abstract클래스메서드에 사용이 가능하다.

abstract클래스에 붙으면 추상클래스라고 말하고 이는 설계도에 비유하면 미완성 설계도라고 만 알고가자

추상클래스는 나중에 따로 작성할 것이다.

abstract메서드에 붙으면 추상메서드라고 말하고 이는 이러이러한 기능이 있다는 것만 설명하고 기능을 구현을 하지 않은 것이다.

선언부는 작성되어있지만 구현부는 작성이 되지 않은 것이다.

abstract class Car{
    abstract void move();
}

이는 아무런 구현이 없어 쓸모없어 보이지만 이 클래스를 상속받는 클래스에게 원하는 기능을 오버라이딩을 해야한다

접근 제어자 (access modifier)

접근 제어자는 멤버 또는 클래스에 사용하여 이를 외부에서 접근하지 못하도록 제한하는 역할을 한다.

접근 제어자의 종류는 다음과 같다.

  • private : 같은 클래스 내에서만 접근이 가능하다.
  • default : 같은 패키지 내에서만 접근이 가능하다.
  • protected : 같은 패키지 안에서 그리고 다른 패키지의 자손클래스에서 접근이 가능하다.
  • public : 모두 접근이 가능하다.

넓은쪽 에서 좁은 쪽 순서로는 다음과 같다.

public > protectd > (default) > private

캡슐화(encapsulation)

접근 제어자를 사용하는 이유는 클래스의 내부에 선언된 데이터를 보호하기 위해서이다.

이를 보통 캡슐화라고 한다.

또한, 클래스 내부에서만 사용하는 맴버들을 private로 지정하여 외부에 노출시키지 않음으로 복잡성을 줄이는 것 또한 캡슐화라고한다.

캡슐화된 값들을 사용하기 위해서는 Getter/Setter라는 메소드를 이용하여 값을 접근한다.

class Car{
    private String name;

    String getName(){
        return name;
    }
    void setName(String name){
        this.name = name;
    }
}

Getter는 멤버 변수의 값을 반환하는 역할을 한다.

Setter는 멤버 변수의 값을 설정하는 역할을 한다.

Singleton 패턴

Singleton은 디자인 패턴줄하나로 인스턴스를 단 하나만 생성할 수 있게 하는 방법이다.

이는 생성자에 접근 제어자를 사용하는 방식으로 이루어져있다.

생성자의 접근 제어자를 private 로 지정한다면 외부에서 생성자에 접근할 수 없으므로 인스턴스를 생성할 수 없게 된다.

class Car{
    private static Car car = new Car(); // static을 사용

    private Car(){
        /...
    }

}

public static void main(String[] argc){
        Car car = new Car() // -> 불가능 Car()는 private이기 때문이다.
}

생성자가 private이기 때문에 더이상의 인스턴스를 생성할 수 없다.

private이기 때문에 인스턴스에 접근조차 할수가 없다. 그러므로 class 안에서 생성된 인스턴스를 불러올 방법을 찾아야한다.

// 해결방법
class Car{
    private static Car car = new Car(); // static을 사용

    private Car(){
        /...
    }

    public static Car getInstance(){
        return car;
    }
}

getInstance() 메서드를 사용하여 미리생성된 car인스턴스를 반환한다.

또한, static으로 생성되었기 때문에 main함수에서 접근이 가능하다.

이는 생성자가 private이기 때문에 다른 클래스의 조상이 될 수 없다.

이러한 싱글톤 패턴에는 문제점이있다.

  • 단 하나의 인스턴스를 사용하기 때문에 동시에 객체의 변수를 변경하고 요청한다면 오류가 생길 수 있다.
  • 싱글톤 패턴을 구현하는 코드 자체가 많이들어간다.
  • private생성자 이기때문에 자식을 만들기가 어려워진다.

이러한 문제점들이 존재한다.

제어자의 조합

제어자는 조합이 가능한데 마음대로 쓸수 있는 것들은 아니다.

제어자는 다음과 같은 사항을 준수해야한다.

  1. 메서드에 staticabstract를 함께 사용할 수 없다.
    • abstract는 메서드를 구현하지 않지만 static은 메서드 구현이 필요하기 때문이다.
  2. 클래스에 abstractfinal을 동시에 사용할 수 없다.
    • abstract는 항상 상속을 받아야한다는 의미이다. 하지만 final은 클래스에서 상속을 받을수 없다는 의미 이기 때문에 서로 상반된다.
  3. abstract메서드의 접근 제어자가 private 일 수 없다.
    • abstact는 상속을 받아서 자식클래스에서 구현이 되야한다. 하지만 private일 때는 자식클래스에서 abstact메서드를 접근할 수 없기 때문이다.
  4. 메서드에 privatefinal을 같이 사용할 필요는 없다.
    • privatefinal을 쓰면 서로 의미가 같아져서 하나만 써도 의미가 충분하다. (메소드의 오버라이딩 금지)

Reference

  • 자바의 정석

'Java > Java' 카테고리의 다른 글

[Java/Study] 추상클래스  (0) 2021.09.11
[Java/Study] 다형성  (0) 2021.09.10
[Java/Study] Package 와 Import 및 터미널로 자바 실행방법  (0) 2021.09.08
[Java/Study] 오버라이드  (0) 2021.09.07
[Java/Study] 상속  (0) 2021.09.07

Package란?

package는 클래스의 묶음이다. 서로 관련된 클래스들끼리 그룹 단위로 묶어 놓음으로써 클래스를 효율적으로 관리할 수 있는 방법이다.

또한, package는 하나의 디렉토리로 생각하면 이해가 쉽다.

클래스들을 묶어놓은 폴더라고 생각해도 좋다.

이를 압축한것 들이 jar확장자로 저장이된다. jrelib파일에 가면 여러가지 .jar파일이 있다.

Package의 특징

  • 하나의 소스파일에는 첫 번째 문장으로 단 한 번의 패키지 선언만을 허용한다.
package com.ex01; //이런형식으로 보통 되어있음

But package가 두번선언되는 일은 일어날 수 없음

// 안되는 예
package com.ex01;
package com.ex02;
  • 모든 클래스는 반드시 하나의 패키지에 속해야 한다
    • 지금까지 package안에 적지 않은 경우도 많다 이를 위반하는것인가??
    • 그것이 아니라 만약 package를 선언하지 않았으면 이름없는 패키지로 자동으로 속하게 된다 그래서 실행이 지금까지 됬던 것이다.
  • 패키지는 .을 구분자로 하여 계층구조로 구성할 수 있다.
    • ex) package com.ex01com이라는 package안에 ex01이라는 package가 하나더 있는 구조이다.
  • 패키지는 물리적으로 클래스 파일을 포함하는 하나의 디렉토리이다.
    • 클래스의 정의는 클래스의 묶음 이기 때문에 클래스를 포함하는 디렉토리라고 라고 생각한다.

Package의 선언

package를 선언하는 방법은 클래스 또는 인터페이스의 맨 윗줄에 package 패기지명;을 적어주면된다.

중요한점은 맨 윗줄이다 물론 주석과 공백은 제외할 수 있다.

이것은 package 작성의 권장사항인데 package의 이름은 소문자로만 구성하는 것을 원칙으로 하고있다.

왜냐하면 클래스명과 쉽게 구분하기 위해서 다음과 같은사항으로 적고 있다.

Terminal로 실행하는 법

일단 .java파일을 하나 만든다.

image

나는 C:\javaStudy안에 PackageTest.java라는 파일을 만들었다.

이 그리고 packagecom.codechobo.book안에 설정을 하였다.

그 후에 Termal을 열어서 프로젝트의 Test.java파일이 있는 경로로 이동하고

javac -d . Test.java를 입력한다.

image

javac는 자바 컴파일러를 실행한다는 명령어이고

-d옵션은 소스파일에 지정된 경로를 통해 패키지의 위치를 찾아 클래스파일을 생성하는 옵션이다.

지정된 패키지가 없으면 패키지를 자동적으로 생성을 해준다.

-d는 해당 패키지의 루트 디렉토리 경로를 적어주는 것이다. 바로 PackageTest.java파일이 현재 디렉토리에 있으므로 .만 적어준다.

image

-d옵션을 통해서 패키지와 .class파일이 생성이 된것이 보일 것이다.

이제 패키지의 루트 디렉토리클래스패스를 포함시켜야 한다. 그래야 JVM이 실행시 PackageTest.class를 찾을 수 있기 때문이다.

그 후 -cp옵션을 이용해서 일시적으로 클래스패스를 지정할수있다,.

image

이렇게 하면 정상적으로 작동 되는 것을 볼 수 있다.

혹은 환경변수를 설정해주면 생략하고 바로 실행이 가능하다.

Import 문

소스코드를 사용할때 다른 패키지를 사용할 때 계속해서 패키지명을 붙여서 작성해야한다.

이런 번거로움을 줄여주기 위해서 import문을 사용하여 패키지의 정보를 불러올 수 있다.

import문 선언방법

import문 선언에는 두가지 방법이 있다.

  • 모든 패키지에 클래스를 불러오기
  • 모든 패키지에 특정 클래스 만 불러오기
// 모든 클래스 불러오기
import 패키지명.*;

// 특정 클래스 불러오기
import 패키지명.클래스명.

하지만 *를 사용한다고해서 모든 클래스를 불러오는 것은 아니다.

하위 클래스는 불러오지 못한다.

ex) import java.*import java.lang.*를 불러오지 못함

Static import문

import를 쓰지 않는다면 클래스명에 패키지 이름까지 적어줘야했다

java.util.Date date = new java.util.Date();

이를 import문을 사용하면 다음과 같이 클래스명과 패키지이름을 제외시킬수 있다.

Date date = new Date();

여기서 static import를 진행하면 맴버를 호출할 때 클래스 이름도 생략할 수 있다.

예를들어보자

System.out.println("Hello World");

//static import 진행
import static java.lang.System.out;

out.println("Hello world); 

이처럼 특정 클래스의 static맴버를 자주 사용할 때 사용하면 코드가 간결해질 수 있다.

Refrence

  • 자바의 정석

'Java > Java' 카테고리의 다른 글

[Java/Study] 다형성  (0) 2021.09.10
[Java/Study] 제어자  (0) 2021.09.09
[Java/Study] 오버라이드  (0) 2021.09.07
[Java/Study] 상속  (0) 2021.09.07
[Java/Study] 생성자  (0) 2021.09.07

Java의 상속을 공부하다가 문득 고민이 생겼다.

Java는 분명 단일 상속을 하는 언어이다. 그런데 만약 이런경우가 생기면 어떨까?

Java에서 Car클래스와 Tesla라는 클래스를 만든다.

그리고 TeslaCar를 상속받는다. 하지만 Object 클래스는 모든 클래스의 최상위 개체라는 말을 들었다.

TeslaCar를 상속받는다. 그러면 Object는 모든 클래스를 상속하기 때문에

TeslaObject를 상속하는 것이 아닌가?

결론적으로 TeslaObjectCar를 상속하는 것 이므로 단일 상속의 원칙에 위반된다라고 생각했다.

그래서 검색을 해보니 JAVA API에서 확인해본 결과

Float 클래스는 Number클래스만 상속을 한다. 그리고 Number클래스는 Object클래스를 상속한다고 나와있다.

그렇기 때문에 결론적으로는 Float클래스는 직접적으로 Object클래스를 접근하는 것은 아니고

부모클래스가 Obejct 상속받는것이라고 생각한다.

오버라이딩

생성일: 2021년 9월 7일 오후 4:07
태그: 발표자료, 자바스터디

오버라이딩의 조건

오버라이딩을 사용하기 위해서는 조건이 존재한다.

자식클래스와 부모클래스의 오버라이딩하는 메서드와

  • 이름이 같아야한다.
  • 매개변수가 같아야 한다.
  • 반환타입이 같아야한다.

결국 오버로딩과 달리 선언부는 부모클래스와 일치해야한다라는 것을 볼 수 있다.

하지만 접근제한자와 예외는 제한된 조건 하 다르게 변경이 가능하다.

제한된 조건들

  1. 접근 제어자는 조상 클래스의 메서드보다 좁은 범위로 변경 할 수 없다.
  2. 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.
  3. 인스턴스 메서드를 static메서드로 또는 그 반대로 변경할 수 있다.

첫번째 조건은, 에서의 접근제어자의 범위를 좁은것 부터 나열한다면

public → protected → (default) → private 순이다.

만약, 부모 메서드가 private라면 자식 메서드는 public 으로 변경하여 오버라이드 할 수 있다.

두번째 조건은, 말그대로 조상 클래스 메서드의 예외보다 자식 클래스 메서드의 예외가 더 작아야만 한다. 근데 갯수가 문제가 아니다. 개수가 작아야한다고는 명시하지 않았다.

class Child extends Parent {
    void method() throws Exception{
        /....
    }
}

이러한 메서드는 오류가 난다. 왜냐하면 Exception모든 종류의 예외를 포함한다.

예외의 최고봉 👍이다 그렇기 때문에 잘못된 오버라이딩 이다.

오버로딩 vs 오버라이딩

오버로딩오버라이딩은 이름부터 비슷해서 자주 헷갈리는 개념이다.

오버라이딩의 조건

오버라이딩을 사용하기 위해서는 조건이 존재한다.

자식클래스와 부모클래스의 오버라이딩하는 메서드와

  • 이름이 같아야한다.
  • 매개변수가 같아야 한다.
  • 반환타입이 같아야한다.

결국 오버로딩과 달리 선언부는 부모클래스와 일치해야한다라는 것을 볼 수 있다.

하지만 접근제한자와 예외는 제한된 조건 하 다르게 변경이 가능하다.

제한된 조건들

  1. 접근 제어자는 조상 클래스의 메서드보다 좁은 범위로 변경 할 수 없다.
  2. 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.
  3. 인스턴스 메서드를 static메서드로 또는 그 반대로 변경할 수 있다.

첫번째 조건은, 에서의 접근제어자의 범위를 좁은것 부터 나열한다면

public → protected → (default) → private 순이다.

만약, 부모 메서드가 private라면 자식 메서드는 public 으로 변경하여 오버라이드 할 수 있다.

두번째 조건은, 말그대로 조상 클래스 메서드의 예외보다 자식 클래스 메서드의 예외가 더 작아야만 한다. 근데 갯수가 문제가 아니다. 개수가 작아야한다고는 명시하지 않았다.

class Child extends Parent {
    void method() throws Exception{
        /....
    }
}

이러한 메서드는 오류가 난다. 왜냐하면 Exception모든 종류의 예외를 포함한다.

예외의 최고봉 👍이다 그렇기 때문에 잘못된 오버라이딩 이다.

오버로딩 vs 오버라이딩

오버로딩오버라이딩은 이름부터 비슷해서 자주 헷갈리는 개념이다.

오버로딩이란 기존에 없는 새로운 메서드를 정의하는 것이다. (새로만듦)
오버라이딩이란 상속받은 메서드의 내용을 변경하는 것이다. (변경, 수정)

만약, 매개변수의 종류가 다르다 라고 하면 오버로딩일 가능성이 크다.

Super & Super()

super은 자식 클래스에서 부모 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조 변수이다.

this는 자기 자신을 가리키듯 super는 부모클래스를 가리킨다.

superthis는 닮은 점이 많다. 근본적으로는 다른 값을 가르키지만 쓰임이 비슷하다.

class Parent{
    int x = 1;
}

class Child extends Parent{

    int x = 2;    

    void printX(){
        System.out.println("x =" + x); // 2가 출력된다
        System.out.println("this.x =" + this.x); // 2가 출력된다.
        System.out.println("super.x =" + this.x); // 부모의 값인 1이 출력된다.
    } 
}

또한, 변수 뿐만이 아니라 부모의 메서드를 호출할때도 super가 사용된다.

superthis와 닮은 점이 많다고 했다 . this()는 생성자를 다시 호출할 때 사용했듯이

부모 클래스의 생성자를 호출할때 super()가 사용된다.

super()는 특징이 있다.

Object 클래스를 제외한 모든 클래스의 생성자 첫 줄에 생성자 , this() , super()를 쓰지 않으면 컴파일러가 자동적으로 super();를 생성자의 첫줄에 추가한다.

그래서 만약 자식 클래스의 부모클래스의 생성자가 없고 특별히 다른것을 명시해주지 않으면 오류가 난다.

class Parent{
    int x;
    int y;
}

class Child extends Parent{
    int z;
    Child(int x, int y, int z){
        // 명시를 안했기 때문에 자동으로 컴파일러가 **super();** 가 들어감
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

위와 같은 코딩을 하면 오류가 나게된다.

그렇기 때문에 상속관계에서는 어떤 생성자를 사용할것이지 명시해 두는것이 중요하다.

이렇게 복잡하게 쌓였을 때 생성자의 호출순서가 어려울수가 있다.

생성자의 호출 순서는 다음과 같다.

자식 생성자 → 부모 생성자 → Object()

Reference

  • 자바의 정석

'Java > Java' 카테고리의 다른 글

[Java/Study] 제어자  (0) 2021.09.09
[Java/Study] Package 와 Import 및 터미널로 자바 실행방법  (0) 2021.09.08
[Java/Study] 상속  (0) 2021.09.07
[Java/Study] 생성자  (0) 2021.09.07
[Java/Study] 변수와 메서드  (0) 2021.09.07

상속

생성일: 2021년 9월 7일 오후 2:14

상속이란?

상속은 기존의 클래스를 재사용하여 새로운 클래스로 작성하는 것이다.

이는 기존의 클래스를 재사용 함으로서 코드를 공통적으로 관리할 수 있기 때문에 코드 추가 및 변경이 매우 용이하다.

상속을 하는 법은 class의 선언뒤에 extends키워드와 상속하고 싶은 클래스를 명시하면된다.

class 자식클래스이름 extends 부모클래스이름{
    ...
}

보통 상속을 해주는 클래스부모 클래스 또는 조상 클래스 라한다.

상속을 받는 클래스를 자식클래스 또는 자손 클래스라한다.

자식 클래스의 특징

  • 자식 클래스는 부모 클래스가 가지는 맴버변수와 메서드를 모두 사용할 수 있다.
  • 부모 클래스생성자초기화 블럭상속되지않는다.
  • 자식 클래스맴버 개수는 조상 클래스 보다 항상 같거나 많다.
  • 자식 클래스의 인스턴스를 생성하면 부모 클래스의 맴버 + 자식 클래스의 맴버가 합쳐진 하나의 인스턴스로 생성이된다. → 벤다이어그램 생각하면 이해가 쉬움

상속관계와 포함관계 판별하는 팁

보통 그냥 상속을 해야할지 혹은 포함만 하면 될지 고민할 때가 많다.

이때는 is a인지 has a 인지 확인을 하면된다.

상속관계를 설명할때는 is a'~는(은) ~이다.라고 생각하면 좋다.

ex) 만화책은 책이다. → (o)

ex) 핫도그는 소시지이다. → (x)

포함관계를 설명할 떄는 has a'~은 ~를 가지고 있다.라고 판별하면 된다.

ex) 핫도그는 소시지를 가지고 있다. → (o)

ex) 만화책은 책을 가지고 있다. → (x)

단일 상속

Java와 달리 C++에서는 여러 부모로 부터 자식이 상속을 받을 수 있다.

하지만 Java는 다중 상속을 금지한다.

Java는 자식클래스는 단 하나의 부모클래스에게서만 상속을 받을 수 있다. 라는 것이 단일 상속이다.

다중상속의 문제점으로는 다이아몬드 문제가 있다.

Object Class

Object Class모든 클래스의 부모이다.

이는 단일 상속의 설명 때문에 햇갈릴 수도 있는데 이런것이다.

자식 클래스는 부모클래스와 Object 클래스를 직접적으로 다중상속받는 것이 아니다.

부모클래스가 Object Class를 상속 받기 때문에 자식클래스도 사용가능한 것이다

자식 클래스 → 부모 클래스 → Object 클래스

위의 글처럼 상속관계가 이루어진다.

Reference

  • 자바의 정석

'Java > Java' 카테고리의 다른 글

[Java/Study] Package 와 Import 및 터미널로 자바 실행방법  (0) 2021.09.08
[Java/Study] 오버라이드  (0) 2021.09.07
[Java/Study] 생성자  (0) 2021.09.07
[Java/Study] 변수와 메서드  (0) 2021.09.07
[Java/Study] 클래스와 객체  (0) 2021.09.06

생성자

생성일: 2021년 9월 7일 오전 11:32

생성자란?

생성자는 인스턴스가 생성될 때 호출되는 '인스턴스 초기화 메서드' 이다.

생성자의 조건

  1. 생성자의 이름은 클래스의 이름과 같다.
  2. 생성자는 리턴 값이 없다.

생성자의 생성

생성자는 다음과 같이 정의한다.

클래스이름 (타입 변수명, ... ) {
    // 보통 초기화 코드
}

Book(){
    pageNumber = 0;
}

생성자 라는 이름은 생성자가 인스턴스를 생성한다. 라고 오해하기 쉽지만

new라는 연산자가 인스턴스를 생성하는 것이기 때문에 햇갈리면 안된다.

생성자는 new할 때 그저 호출 되는 메소드라고 생각하는 것이 편하다

생성자의 오버로딩

생성자는 오버로딩이 가능하다. 그렇기 떄문에 생성자는 여러개를 만들 수 있다.

이러한 생성자들은 2가지로 나뉜다.

기본생성자

기본생성자는 아무런 매개변수도 없는 생성자 이다.

클래스이름() {

}

만약, 클래스가 생성자를 정의하지 않으면 컴파일러가 제공하는 기본생성자를 통해 자동으로 추가를 해준다.

이러한 추가를 해주느 생성자는 안에 아무런 내용이 없는 기본생성자이다

매개변수가 있는 생성자

매개변수가 있는 생성자는 생성과 즉시 특정한 값으로 초기화를 시켜주고 싶을 때 사용한다.

생성자로 변수를 생성하고 메소드를 이용하여 특정한 값을 추가하기 보단

생성즉시 값을 넘겨서 초기화하는것이 더 효율적이고 코드도 간결하기 때문이다.

생성자 안에서 다른 생성자 추가하기

생성자 안에서 다른 생성자를 한다는것은 잘 이해가 되지 않는데 사용하는 기능이라고한다.

메소드도 재귀함수기능이 있듯이 이를 그냥 사용하면 되지 않겠냐 생각을 했는데

그렇지않고 this()를 사용하여 다시 호출 해주면 된다.

class Book{

    int pageNumber;

    Book(){
        this(1);
    }
    Book(int pageNumber){
        this.pageNumber = pageNumber;
    }

}

생성자의 활용

생성자를 이용하여 생성과 동시에 인스턴스를 복사 할 수 있다.

생성할 때 매개변수로 인스턴스를 받고 복사하면 된다.

class Book{

    int pageNumber;

    Book(){
        this(1);
    }

    // 첫번째 방법
    Book(Book book){
        pageNumber = book.pageNumber;
    }

    // 두번째 방법
    Book(int pageNumber){
        this.pageNumber = pageNumber;
    }

    Book(Book book){
        this(book.pageNumber);
    }

}

첫번째 방법은 바로 인스턴스의 변수를 꺼내서 복사하는 방법이다.

두번쨰 방법은 생성자안의 생성자를 통해서 인스턴스를 복사하는 법이다.

멤버변수의 초기화 시기와 순서

클래스 변수의 초기화 시점 : 클래스가 처음 로딩될 때 단 한번 초기화 된다. (static변수)

인스턴스 변수의 초기화 시점 : 인스턴스가 생성될 때 마다 생성자를 통해 각 인스턴스 별로 초기화가 이루어짐

클래스변수의 초기화순서 : 기본값 → 명시적초기화 → 클래스 초기화 블럭

인스턴스변수의 초기화순서 : 기본값 → 명시적초기화 → 인스턴스 초기화 블럭 → 생성자

명시적 초기화

명시적 초기화는 선언과 동시에 초기화하는 것이다.

class Book(){
    int pageNumber = 1;
}

인스턴스 초기화 블럭

생성자를 오버로딩하면서 인스턴스를 초기화 할때 인스턴스들의 초기화가 중복되는 내용들이 있을 것이다.

이때 인스턴스 초기화 블럭을 사용하면 해결할 수 있다.

class Book(){
    **{
        pageNumber = 1;
    }**
}

이런방식으로 class 안에서 {}를 사용해서 초기화를 진행하면 된다.

클래스 초기화 블럭

클래스 초기화 블럭은 인스턴스 초기화 블럭과 비슷하다.

인스턴스 초기화 블럭과 마찬가지로 {}를 사용하지만 {}앞에 static이라는 키워드를 붙여주면된다,

 class Book(){
    static{
        pageNumber = 1;
    }
}

Reference

  • 자바의 정석

'Java > Java' 카테고리의 다른 글

[Java/Study] 오버라이드  (0) 2021.09.07
[Java/Study] 상속  (0) 2021.09.07
[Java/Study] 변수와 메서드  (0) 2021.09.07
[Java/Study] 클래스와 객체  (0) 2021.09.06
[Java/Study] 자료형  (1) 2021.09.05

+ Recent posts