제어자란?

제어자(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

변수와 메서드

생성일
속성 
태그 

클래스가 가질수 있는 변수에대해서 알아보자 😃

클래스가 가질 수 있는 변수의 종류

클래스가 가질 수 있는 변수는 총 3개로 나뉠수가 있다,

  • 멤버변수
    • 클래스 변수 static이 붙음
    • 인스턴스 변수 static 붙지 않음
  • 지역변수 → 메서드 안에 있는 변수

이들은 선언 위치에 따라서 역할이 구분된다. 그러므로 어떤 변수인지 파악하기 위해서는

선언된 위치를 눈여겨 보면 좋다.

변수의 종류와 특징

변수의 종류 선언 위치 생성시기
클래스변수 클래스 영역 클래스가 메모리에 올라갈 때
인스턴스 변수 클래스 영역 인스턴스가 생성되었을 때
지역 변수 클래스 영역 이외의 영역 변수 선언문이 수행되었을 때

이중 지역변수는 자주들어봤을 텐데 클래스 변수와 인스턴스 변수는 처음들었을 것이다.

이들의 특징은 다음과 같다.

인스턴스변수

인스턴스 변수는 클래스의 인스턴스를 생성할 때 만들어진다.

인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있다.

클래스 변수

클래스 변수는 인스턴스 변수안에 static을 붙인것 이다.

static을 사용했기 때문에 공통된 저장공간을 공유하게 된다.

각 인스턴스가 생성되어도 이값은 각 인스턴스마다 같다.

또한, 인스턴스를 생성하지 않아도 클래스이름.클래스변수와 같이 .을 사용하여 접근 할 수 있다.

결국 static이 붙었기 때문에 전역변수 취급을 받는다.

메서드

메서드(method)는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다.

메서드를 사용하는 이유

  1. 높은 재사용성메서드는 한번 만들어 놓으면 몇번이든 재호출 할 수 있으며 다른프로그램에서도 사용할 수 있다.
  2. 중복된 코드의 제거프로그램을 구성하면 반복되는 코드가 있기 마련이다. 이러한 코드들을 메서드를 만들어 재사용 한다면 코드의 양이 줄어들어 오류가 발생할 가능성이 줄어드는 이점이 있다.
  3. 프로그램의 구조화메서드를 만들어 main 메서드 안에서 모든 문장을 넣는 식으로 프로그램을 작성할 필요가 없다.
  4. 각각의 작업단위를 쪼개서 필요한 클래스를 만들어 그 클래스에 여러 개의 메서드를 담아서 프로그램의 구조를 단순화 시킨다면 나중에 문제가 있을 때 쉽게 찾아 문제를 해결 할 수 있는 장점이 있다.

메서드의 선언

메서드는 선언부(header)구현부(body)로 나뉘어져 있다. 사실 함수를 선언하는 것과 비슷한다.

반환타입 매서드이름 (매개변수){
    //매서드의 코드
}

//예시
int sum (int a, int b){
    return a + b;
}

메서드에서 는 반환타입이 void가 아닌 이상 항상 값을 return해줘야 한다.

메서드에서 반환된 값은 반환 타입과 일치하거나 혹은 자동 형변환을 메서드가 알아서 해준다.

또한, 반환값은 반드시 하나인것을 명시해야 한다.

그리고 메서드는 return을 하면 항상 종료된다 중간에 다른코드가 있거나 밑에 다른코드가 있더라도

값을 반환하면 종료가 된다.

메서드의 호출

메서드는 호출되면 스택과 같은 구조로 쌓인다.

이를 자세히 알기 위해서는 JVM의 메모리 구조에대해서 알아야한다

JVM은 프로램이 실행 되면 프로그램을 수행하는데 필요한 메모리를 할당받는다.

이러한 메모리들은 용도에 따라 달라진다. 보통 다음과 같은 구조에 메모리를 할당한다.

  1. 메서드 영역메서드 영역에서는 클래스파일을 읽고 클래스 데이터를 이곳에 저장한다. 또한, 클래스 변수도 함께 저장한다
  2. 힙은 보통 인스턴스가 생성되는 공간이다 보통의 인스턴스 변수들이 생성된다.
  3. 보통 Stack을 뺀 모든 변수들이 이곳에서 생성이 된다.
  4. Call Stack(호출스택)호출스택은 메서드 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출 될 떄 마다 메서드를 위한 메모리 공간이 할당되며 이러한 메서드의 지역변수연산의 중간결과등을 저장한다.호출스택의 제일위에 있는 메서드는 자신을 실행시킨 메서드이다. 바로 아래에 있는 메서드는 위의 메서드를 호출한 메서드이다.
  5. Call stack 말처럼 stack처럼 쌓이면서 저장되고 작업을 마치면 stack 위에 있던 메서드가 사용한 공간이 반환되며 비워진다.

Stack을 배웠다면 이해하기가 쉬울 것이다.

매개변수의 특징

보통 매개변수는 지역변수취급을 당한다고 생각하면 편하다.

매개변수가 들어와서 작업을 행했을 때 값이 바뀌어도 원래 호출하였던 매개변수의 값은 변하지 않는다.

C/C++ 언어에서는 포인터를 사용하여 Call by Reference를 사용하여 바꿀 수 있지만 자바에서는 포인터가 존재하지 않는다.

하지만 자바에서도 참조형 매개변수가 있다. 이는 매개변수의 타입이 참조형인 매개변수를 뜻한다.

이는 값이 변하면 원본에 영향을 미칠 수 있다.

class Book {int pageNumber;}

public static void main(String[] args){
    Book book = new Book();
  book.pageNumber = 1;
  System.out.printf("pageNumber = %d",book.pageNumber); // 1출력
  nextPage(book);
  System.out.printf("pageNumber = %d",book.pageNumber); // 2출력 -> 값이 변함
}

static void nextPage(Book book){
    book.pageNumber += 1;
}

또한, 이뿐만이 아니라 배열을 매개변수로 이용해도 똑같은 결과를 얻을 수 있다.

그렇기 때문에 밑의 예제와 같이 결과값을 저장하고 싶을때 배열을 매개변수로 사용 할 수 있다.

void add (int a, int b, int[] result){
    result[0] = a + b;
}

참조형의 반환

이뿐만이 아니라 참조형은 반환타입에서도 특별하게 사용된다,

보통 return을 하면 값을 반환하는데 참조형을 반환하면 특별하게 주소를 반환한다,

그렇기 때문에 호출결과를 저장하는 타입의 일치가 필요하다.

재귀 호출

보통 코딩테스트나 백트레킹 기술에 사용되는 기술이다. 영어로는 Recursive call이라 한다.

이는 자기 자신을 메소드에서 호출하는 것이다.

위에서 메서드는 Stack처럼 쌓인다. 라고하였다 이러한 Stack 을 이용하여 쉽게 유추 할 수 있다.

재귀호출을 사용할 때에는 반드시 종료조건을 명시 해줘야한다.

단순히 반복문을 사용해도 되는데 재귀호출을 사용하는 이유는

간혹 몇겹의 반복문을 작성하는 것 보다 재귀호출이 비효율적이더라도 쉽게 알아보기 편하게 작성할 수 있기 떄문이다.

예시로 펙토리얼피보나치 가 있다.

클래스 메서드 & 인스턴스 메서드

변수에도 클래스 변수, 인스턴스 변수가 있듯이 함수에도 존재한다.

변수와 마찬가지로 static이 붙으면 클래스메서드 붙지 않으면 인스턴스 메서드이다.

인스턴스 메서드는 메서드 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드 이다.

클래스 메서드는 메서드 중 인스턴스와 관계없는 메서드를 클래스 메서드라고 정의한다.

하지만 인스턴스를 사용하지 않는다고 해서 반드시 클래스 메서드를 사용해라라는 것은 아니다.

하지만 사용하는 것을 권장한다 왜냐하면 인스턴스를 생성할 때마다 static이 없으면 메서드를 찾는 과정이 추가적으로 필요하기 때문에 static 유무에 시간이 더걸리거나 덜 걸린다.

또한, 클래스 메서드에는 중요한 조건이 있는데 클래스 메서드는 인스턴스 변수를 사용할 수 없다.

단순히 생각하면 쉽다. 클래스 메서드static이라 인스턴스 호출전에 사용이 가능한데

인스턴스 변수는 인스턴스가 생성되지 않으면 존재하지 않을 수도 있기 때문이다.

오버로딩

오버로딩은 같은 클래스 내에 같은 이름의 메서드를 여러 개 정의 하는 것을 말한다.

오버로딩을 하기 위해서는 다음과 같은 조건을 만족해야한다.

  1. 매서드 이름이 같아야한다.
  2. 매개변수의 개수 또는 타입이 달라야 한다.

또한, 주의 해야할 점이 매개변수의 개수 또는 타입이 달라야하는 거지 리턴 타입만 다른 경우는

포함 되지 않는다.

오버로딩은 내가 원하는 같은 동작을 매개변수가 달라져도 똑같이 구현이 가능하다는 장점이 있다.

다음과 같은 예를 보자.

int sum(int a, int b){
    return a+b;
}

float sum(float a, float b){
    return a+b;
}

이런식으로 나는 실수와 정수를 똑같은 sum()이라는 매서드를 통해 구별없이 계산하고 싶다.

만약, 오버로딩이 없다면 이를 sumInt() 라는 메서드와 sumFlaot()라는 각기의 메서드로 만들어야 할 것이다.

이뿐 만이 아니라 다른 타입을 구현하고 싶을 떄도 타입의 개수에 따라 엄청나게 같은기능을 하는 이름이 다른 메서드들이 늘어날 것이다.

이는 너무 비효율적이다.

가변인자 & 오버로딩

기존에는 내가 매개변수를 100개를 생성하려면 일일히 100개를 다 적어야했다.

이는 너무 비효율적이다. 이를 해결하기 위해서 JDK 1.5버전부터 매개변수를 동적으로 지정할 수 있게 되었다. 이를 가변인자라고 한다.

예시로 문자열을 합쳐주는 메서드를 만든다고 가정한다. 매개변수가 2개일 경우는 다음과 같다.

String concat(String str1, String str) {};

하지만 만약 매개변수의 갯수가 4개만 되더라도 많이 복잡해진다.

String concat(String str1, String str2, String str3, String str4) {};

이럴 때 가변인자를 사용하면 매개변수를 한번만 써서 구현이 가능하다.

String concat(String... str) {};

이렇게 가변인자로 구현을 한다면 매개변수의 갯수에 구애 받지 않게 할 수 있다.

또한, 배열을 넘겨줄수도 있다.

가변인자를 사용할 때 주의 할점이 있는데 항상 가변 인자는 매개변수의 에 위치해야한다.

String concat(String hello, String... str) {}; -> (o)

String concat(String... str, String hello) {}; -> (x) 

또한, 배열을 매개변수로 넣어준다고 하였는데 허용되지 않는 것도 있다.

String concat (String... str) {}; 

concat(new String[] { "Hello", "world"} -> (o)

concat({"Hello","World"}) -> (X)

제일 밑과 같이 저런 형식으로는 사용이 불가능 하다 배열을 생성하고 넣어주는 것은 괜찮다.

또한, 가변인자를 사용한 메서드의 오버로딩매개변수의 변화를 쉽게 컴파일러가 못알기 때문에

가변인자를 사용했으면 오버로딩을 사용하지 않는 것이 좋다.

이렇게 생각하면 결국 배열을 매개변수로 메서드를 생성하는 것도 가능하지 않을까? 하는 의문점이 들 수있다.

물론 맞는 소리지만 배열을 매개변수로 매서드를 생성했을 때는 반드시 인자를 지정해 줘야한다 이러한 추가적인 불편함이 있기 때문에 가변인자를 사용한다.

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

클래스와 객체

클래스객체를 정의해놓은 것이다 클래스를 사용하여 객체를 만든다.

보통 클래스는 못들어봤어도 객체라는 단어에는 익숙할 것이다.

객체는 말 그대로 '실제로 존재하는 것' 사물이 될수도 있고 혹은 무형의 어떤것이 될 수 도 있다.

이러한 객체는 클래스를 사용하여 만든다.

예시를 들어보자 우리가 사용하는 책이라는 것은 유형의(실제로 존재하는) 객체이다.

이를 만들기위해서는 책을 만드는 기계가 필요할 것이다. 이게 바로 클래스라는 존재이다.

객체지향이론 관점에서는 클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화 라고 한다.

그리고 클래스로부터 만들어진 객체인스턴스라 한다.

즉, 객체는 책 그것을 만들기 위해 사용되는 것은 클래스는 책을 만드는기계이고

클래스(책을 만드는기계)로부터 만들어진 객체(책)은 인스턴스라하고, 이 과정을 인스턴스화라하고한다.

객체의 구성

객체는 두가지로 구성된다

  • 속성(property): 멤버변수, 특성, 필드...
  • 기능(function) : 메서드 , 함수 ...

속성은 예시로 들어서 설명하자면 객체를 구성하는 요소라고도 볼 수 있다.

예를들어서 책을 구성하는 종이 일 수 도있고, 책을 보호하는 북커버 이러한 것들이 속성이다

기능은 말 그대로 기능이다. 책을 예시로 들면 책장을 넘기는 것, 혹은 책갈피를 넣는것 이런것들이 된다.

// 예시

//속성-> 맴버변수(variable)
int pageNumber; // 총 몇 페이지인지?

//기능 -> 매서드
nextPage(); // 다음장으로 넘기는 매서드

//클래스의 예시

class Book {
    // 속성 -> 맴버변수들
    int pageNumber; // 페이지의 총수
    int nowPage; // 현재 페이지

    // 기능 -> 매서드
    void open(); // 책을 열기
    void close(); // 책을 닫기
    void nextPage(); // 다음장으로
}

인스턴스 생성 방법

위에처럼 class Book 즉 Book 이라는 클래스를 만든것은 기계를 만든것과 같다.

사용하기 위해서는 이책이 무엇인지 인스턴스화를 진행해야한다. 인스턴스화를 하는 방법은 다음과 같다.

클래스명 변수명 = new 클래스명();

Book onepice = new Book(); 

이러한 과정을 하면 Book클래스의 인스턴스가 메모리의 빈 공간에 생성이된다.

이러한 것들은 각 자료형에 해당하는 기본값으로 초기화 된다.

혹은 생성자를 만들어서 내가 원하는 값으로 초기화하거나 할 수도 있다.

빈공간이 생성되면서 onepice라는 참조변수에 생성된 객체의 주소값이 전달이 된다.

객체의 멤버변수나 매소드에 접근하기 위해서는 이제 참조변수.맴버변수처럼 .을 사용해야한다.

주의할점으로 같은 클래스로 인스턴스를 생성하면 값이 같은거라고 생각하는데 차이가 있다.

// book1 생성
Book book1 = new Book();

// book2 생성
Book book2 = new Book(); 

이때 book1과 book2의 pageNumber은 각각 다를 수 밖에 없다

왜냐하면 new를 통해서 새로운 메모리에 두번 생성했기 때문에

각각의 맴버변수는 다른 주소를 가지고 있기 때문이다.

객체 배열

많은 수의 객체를 다뤄야할 때 객체를 배열로 다룰수도 있다

// book1, book2, book3 생성
Book book1, book2, book3; 

// 배열을 통해 책 3권생성
Book[] bookArr = new Book[3];

이와같이 여러가지 객체가 많아진다면 생성하기가 힘들다.

이러한 객체를 배열을 통해서 생성하고 다룰수 있다.,

이러한 객체를 배열에 저장할때는 주의할 점이 있다.

사실 객체를 생성하였지만 객체를 생성한것이 아니라 객체 배열을 생성한 것이다

그렇기 때문에 각각의 bookArr[0], bookArr[1], bookArr[2]에 대해서는 객체가 생성되지 않았다.

그렇기 때문에 객체를 생성해서 배열의 각 요소에 저장해주는 과정을 더해줘야 한다.

//객체 배열 생성
Book[] bookArr = new Book[3];

// 방법 1
bookArr[0] = new Book();
bookArr[1] = new Book();
bookArr[2] = new Book();

// 방법 2
Book[] bookArr = {new Book(), new Book(), new Book()};

// 방법 3
for(int i = 0 ;i < bookArr.length; i++){
    bookArr[i] = new Book();
}

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.07
[Java/Study] 자료형  (1) 2021.09.05

+ Recent posts