[Java] 간단하지 않은 간단한 기초 지식 정리 - 02

✨New Wisdom✨·2020년 12월 1일
1

📕 Java 📕

목록 보기
2/24
post-thumbnail

이 노트는 "윤성우의 열혈 java 프로그래밍" 책을 공부하면서
내가 이해한대로 다시 정리하면서 작성되었다.

패키지(Package)의 이해

패키지 선언의 의미와 목적

클래스를 구분하고 파악하는데 도움이 된다.
클래스 이름이 겹치는 문제도 해결한다.
서로 다른 패키지의 두 클래스는 인스턴스 생성 시 사용하는 이름이 다르다.
서로 다른 패키지의 두 클래스 파일은 저장되는 위치가 다르다.

하나의 소스 파일에는 public으로 선언된 클래스의 정의를 하나만 둘 수 있다.
소스파일의 이름은 public으로 선언된 클래스의 이름과 동일해야 한다.

정보 은닉

'정보'는 클래스의 '인스턴스 변수'를 의미한다.
정보를 은닉한다는 것은 인스턴스 변수를 숨긴다는 뜻이다.

인스턴스 변수의 직접적 접근을 허용하면 중대한 문제가 발생할 수 있다.
인스턴스 변수에 private 선언을 추가하자.

getter

  • 인스턴스 변수의 값을 참조하는 용도로 정의된 메소드

setter

  • 인스턴스 변수의 값을 설정하는 용도로 정의된 메소드

접근 수준 지시자

접근의 허용 수준을 결정할 때 선언하는 키워드

종류

지시자클래스 내부동일 패키지상속 받은 클래스이외의 영역
private⭕️
default⭕️⭕️
protected⭕️⭕️⭕️
public⭕️⭕️⭕️⭕️

default

키워드가 아닌 아무런 선언도 하지 않은 상황

  • 클래스의 정의 (public과 default만 가능)
  • 클래스의 인스턴스 변수와 메소드

클래스 정의 대상의 public과 default 선언이 갖는 의미

클래스가 public으로 선언되면 위치에 상관없이
어디서든 해당 클래스의 인스턴스를 생성할 수 있다.

default로 선언되면 동일 패키지로 묶인 클래스 내에서만 인스턴스 생성이 가능하다.

캡슐화

하나의 목적을 이루기 위해 관련 있는 모든 것을 하나의 클래스에 담아 두는 것.
클래스를 적절히 캡슐화 시키면 프로그램이 간결해진다.

포함 관계로 캡슐화 완성하기

한 클래스가 다른 클래스의 인스턴스를 멤버로 가질 수 있는데, 이런 관계를 포함관계라고 한다.

static 선언을 붙여서 선언하는 클래스

'인스턴스 변수'는 인스턴스가 생성되었을 때 생성된 인스턴스 안에 존재하는 변수이다.
하지만 '클래스 변수'는 인스턴스의 생성과 상관없이 존재하는 변수이다.

선언된 클래스의 모든 인스턴스가 공유하는 '클래스 변수(static 변수)'

클래스 내에 선언된 변수 앞에 static 선언을 붙이면 인스턴스 변수가 아닌 '클래스 변수'가 된다.

package com.newwisdom;
class InstCnt {
    static int instNum = 0; // 클래스 변수 (static 변수)
    
    InstCnt() {
        instNum++; // static 변수 값 증가
        System.out.println("인스턴스 생성 : " + instNum);
    }
    
}
class ClassVar {
    public static void main(String[] args) {
        InstCnt cnt1 = new InstCnt();
        InstCnt cnt2 = new InstCnt();
        InstCnt cnt3 = new InstCnt();
    }
}
출력
인스턴스 생성 : 1
인스턴스 생성 : 2
인스턴스 생성 : 3

static으로 선언된 변수는 변수가 선언된 클래스의 모든 인스턴스가 공유하는 변수이다.
클래스 변수는 인스턴스 내에 존재하는 변수가 아니라 '어떠한 인스턴스에도 속하지 않는 상태로 메모리 공간에 딱 하나만 존재하는 변수'이다.

클래스 변수의 접근 방법

클래스 내부 접근
변수의 이름을 통해 직접 접근

way.num++;

클래스 외부 접근
클래스 또는 인스턴스의 이름을 통해 접근

AccessWay.num++;

클래스 변수의 초기화 시점과 초기화 방법

클래스 변수는 인스턴스 생성 이전에 메모리 공간에 존재한다.
즉 클래스 변수는 해당 클래스 정보가 가상머신에 의해 읽히는 순간 메모리에 할당된다.
이는 인스턴스 생성과는 무관하게 이뤄진다.

class InstCnt {
    static int instNum = 0; // 클래스 변수의 정상적 초기화 방법

    InstCnt() {
        instNum = 100; // 클래스 변수의 초기화가 아니다.
    }
}

클래스 변수는 언제 사용할 것인가?

인스턴스 간 데이터 공유가 필요한 상황에서 클래스 변수를 선언한다!
참조를 목적으로만 존재하는 값은 final 선언이 된 클래스 변수에 담는다!
(이는 참조를 위한 값이니 public으로 선언해도 괜찮은 값이다.)

static 선언을 붙여서 선언하는 클래스 메소드

클래스 내 정의된 메소드에 static 선언을 하면 '클래스 메소드'가 된다.

클래스 메소드의 정의와 호출

  • 인스턴스 생성 이전부터 접근이 가능하다.
  • 어느 인스턴스에도 속하지 않는다.

인스턴스 생성을 목적으로 설계되지 않는다!

클래스 메소드로 정의하는 것이 더 나은 경우

  • 외부에 기능을 제공하기 위한 메소드일 때
  • 인스턴스 변수의 값을 참조하거나 수정하지 않을 때

클래스 메소드에서 인스턴스 변수에 접근이 가능한가?

불가능!
클래스 메소드는 인스턴스에 속하지 않으니 인스턴스 변수에 접근이 불가능 하고,
클래스 메소드는 인스턴스 메소드의 호출도 불가능하다.

또 다른 용도의 static 선언

static 초기화 블록

클래스 변수와 마찬가지로 가상머신이 클래스의 정보를 읽어 들일 때 실행된다.
static 초기화 블록을 사용하면 클래스 변수 선언과 동시에 초기화 할 수 있다.

class DateOfExecution {
	static String date;
    
    static {
    	LocalDate nDate = LocalDate.now();
    	date = nDate.toString();
    }
    
    public static void main(String[] args) {
    	System.put.println(date);
    }
}

메소드 오버로딩

메소드 오버로딩의 조건

호출할 메소드를 찾을 때 다음 두 가지 정보를 참조하여 메소드를 찾게 된다.

  • 메소드의 이름
  • 메소드의 매개변수 정보

매개변수의 선언이 다르면 동일한 이름의 메소드 정의를 허용한다.

생성자 또한 오버로딩이 가능하다.

키워드 this를 이용한 인스턴스 변수의 접근

매개변수와 인스턴스 변수명이 같을 때 this 키워드를 이용하면 인스턴스 변수를 가리킬 수 있다.

String 클래스

문자열 생성을 위한 두 가지 방법의 차이점은?

String str1 = new String("My String")';
String str2 = "Your String";

str1은 같은 문자를 == 연산을 할 경우 false(다른 인스턴스 참조)가 나오고,
str2는 true(동일 인스턴스 참조)가 나온다.

기본 자료형의 값을 문자열로 바꾸기

valueOff 메소드를 사용하자!

double e = 2.63412;
String se = String.valueOf(e);

1차원 배열의 이해와 활용

1차원 배열의 생성 방법

자바에서는 배열도 인스턴스이다.

int[] ref = new int[5]; // 길이가 5인 int형 1차원 배열의 생성문

int[] ref 는 참조변수의 선언이고, new int[5] 는 배열 인스턴스 생성이다.

1차원 배열의 참조변수는 배열의 길이에 상관없이 참조가 가능하다.

배열의 생성과 동시에 초기화 하기

int[] arr = new int[] {1, 2, 3};

배열의 길이를 생략한다.

enhanced for문

enhanced for문 이해와 활용

  • 코드의 양이 절대적으로 줄어든다.
  • 반복문 구성 과정에서 배열의 길이 정보를 직접 확인하고 입력할 필요가 없다.
for(요소 : 배열) {
	반복할 문장들
}

다차원 배열의 이해와 활용

2차원 배열의 생성

int[][] arr = new int[3][4];

세로 길이가 3, 가로 길이가 4인 int형 2차원 배열

2차원 배열의 초기화

생성과 동시에 초기화가 가능하다.

int[][] arr = new int[3][3] {
	{11, 22, 33},
    {44, 55, 66},
    {77, 88, 99}
};

상속의 기본 문법 이해

상속은 코드의 재활용을 위한 문법이다? ❌
상속은 연관된 일련의 클래스들에 대해 공통적인 규약을 정의할 수 있다.

상속의 가장 기본적인 특성

기존에 정의된 클래스에 메소드와 변수를 추가하여 새로운 클래스를 정의하는 것이 상속이다.
extends 는 상속을 의미하는 키워드이다.

  • 상속의 대상이 되는 클래스 : 상위 클래스, 기초 클래스, 부모 클래스
  • 상속을 하는 클래스 : 하위 클래스, 유도 클래스, 자식 클래스

상속과 생성자

Man 클래스(상위 클래스)

class Man {
	String name;
    public Man(String name) {
    	this.name = name;
    }
    
    public void tesllYourName() {
    	System.out.println("My name is " + name);
    }
}

BusinessMan 클래스(하위 클래스)

class BusinessMan extends Man {
	String company;
    String position;
    
    public BusinessMan(String company, String position) {
    	this.company = company;
        this.position = position;
    }
    
    public void tellYourInfo() {
    	System.out.println("My company is "  + company);
        System.out.println("My position is " + position);
        tellYourName();
    }
}

String name; 은 상속으로 인해 BusinessMan 클래스에 존재하지만 초기화 되지 않는 문제 발생.
따라서 이 변수도 초기화해주어야 한다.

class BusinessMan extends Man {
	String company;
    String position;
    
    public BusinessMan(String name, String company, String position) {
    	this.name = name; // 상위 클래스 멤버 초기화
    	this.company = company;
        this.position = position;
    }
    
    public void tellYourInfo() {
    	System.out.println("My company is "  + company);
        System.out.println("My position is " + position);
        tellYourName();
    }
}

근데 적절한 생성자 정의의 형태는 아니다.

하위 클래스의 인스턴스 생성 시 상위 클래스, 하위 클래스의 생성자 모두 호출된다.
하위 클래스의 인스턴스 생성 시 상위 클래스의 생성자가 먼저 호출된다.

하위 클래스의 생성자에서 상위 클래스의 생성자를 명시적으로 호출하지 않으면 인자를 받지 않는 생성자가 자동으로 호출된다.
상위 클래스의 생성자를 명시적으로 호출하려면 super 키워드를 사용해라!
상위 클래스의 생성자는 하위 클래스 생성자의 맨 첫 문장으로 등장해야 한다.

자바는 상속 관계에 있을지라도, 상위 클래스의 멤버는 상위 클래스의 생성자를 통해서 초기화하도록 유도되고 있다.

단일 상속만을 지원하는 자바

자바는 프로그램이 과도하게 복잡해지는 것을 막기 위해 단일 상속만을 지원한다.
즉 하나의 클래스가 상속할 수 있는 클래스의 수가 최대 하나라는 것이다.

class A {...}
class Z extends A {...}

하지만 상속의 깊이를 더하는 것은 얼마든지 가능하다.

class A {...}
class M extends A {...}
class Z extends M {...}

하지만 다중 상속으로 설계하는 일은 극히 드물다.

클래스 변수, 클래스 메소드와 상속

static 선언이 붙는 '클래스 변수'와 '클래스 메소드'의 상속

🤔 상위 클래스에 위치한 클래스 변수와 메소드에 하위 클래스에서 어떻게 접근하는가?
선언된 접근 수준 지시자가 접근을 허용한다면 변수의 이름만으로도 접근이 가능하다!

상속을 위한 두 클래스의 관계

상속의 기본 조건인 'IS-A 관계'

하위 클래스는 상위 클래스의 모든 특성을 지니며 자신만의 추가적인 특성을 더하게 된다.
'IS-A'는 '~은 ~이다.'로 표현되는 관계이다.
ex) 노트북은 컴퓨터이다.

메소드 오버라이딩

메소드 오버라이딩은 상위 클래스에 정의된 메소드를 하위 클래스에서 다시 정의하는 것을 뜻한다.

상위 클래스의 참조변수가 참조할 수 있는 대상의 범위

다음과 같은 상속 관계를 가질 때

class SmartPhone extends MobilePhone {...}

다음과 같은 문장들을 구성할 수 있다.

SmartPhone phone = new SmartPhone("010-555-777", "Nougat");
// or
MobilePhone phone = new SmartPhone("010-555-777", "Nougat");

모바일폰을 상속하는 스마트폰도 일종의 모바일 폰이다.
MobilePhone을 상속하는 SmartPhone 인스턴스는 MobilePhone 인스턴스 이기도 하다.
따라서 MobilePhone형 참조변수는 SmartPhone 인스턴스를 참조할 수 있다.
이렇듯 상위 클래스의 참조변수는 하위 클래스의 인스턴스를 참조할 수 있다.
MobilePhone phoneMobilePhone의 인스턴스인 동시에 SmartPhone의 인스턴스가 된다.
그러나 이럴 경우 phoneSmartPhone의 메소드 호출은 불가능하다.

참조변수 간 대입과 형 변환

Cake가 상위 클래스이고 CheeseCake가 하위 클래스일 때,

CheeseCake ca1 = new CheeseCake();
Cake ca2 = ca1;

위의 코드는 가능하지만

Cake ca3 = new CheeseCake();
CheeseCake ca4 = ca3;

위의 코드는 불가능하다.
🤔 왜?
자바는 참조변수의 타입 정보를 기준으로 대입의 가능성을 판단하기 때문이다!
형 변환을 하면 가능하다!

Cake ca3 = new CheeseCake();
CheeseCake ca4 = (CheeseCake)ca3;

메소드 오버라이딩

메소드의 이름, 메소드의 반환형, 메소드의 매개변수 선언이 같아야
오버라이딩이 가능하다.
여기서 말하는 오버라이딩은 무효화 됨을 의미한다.

class Cake {
	public void yammy() {}
}
class CheeseCake extends Cake {
	public void yammy() {} // Cake 메소드 오버라이딩
}
class ChocoCheeseCake extends CheeseCake {
	public void yammy() {} // CheeseCake 메소드 오버라이딩
}
Cake c1 = new ChocoCheeseCake();
CheeseCake c2 = new ChocoCheeseCake();
ChocoCheeseCake c3 = new ChocoCheeseCake();
c1.yammy(); // ChocoCheeseCake의 메소드 호출
c2.yammy(); // ChocoCheeseCake의 메소드 호출
c3.yammy(); // ChocoCheeseCake의 메소드 호출

ChocoCheeseCake 인스턴스를 대상으로 오버라이딩 된 메소드를 호출하면 가장 마지막으로 오버라이딩한 메소드가 호출된다.
상위 클래스에 정의된 오버라이딩 된 메소드를 호출하려면 super 키워드를 사용한다.
변수는 오버라이딩 되지 않는다.

instanceof 연산자

참조 변수가 참조하는 인스턴스의 클래스나 참조하는 인스턴스가 상속하는 클래스를 묻는 연산자이다.

클래스와 메소드의 final 선언

해당 클래스를 다른 클래스가 상속하는 것을 원치 않는다면 final 선언을 추가한다.

profile
🚛 블로그 이사합니다 https://newwisdom.tistory.com/

0개의 댓글