InnerClass

  • 클래스가 다른 클래스를 포함하는 경우, 내부에 포함된 클래스의 명칭

  • 파일 크기의 최소화, 보안, 성능 향상, 이벤트 처리 등을 쉽게 하기 위해 사용

  • 자바 클래스 구조를 더 조직화하고, 소스코드를 구현시 효율을 높일 수 있음

  • 내부 클래스가 생성되기 위해 외부 클래스의 객체가 반드시 필요

  • 내부 클래스는 정의되는 위치에 따라 멤버 클래스와 지역 클래스로 나뉨

  • 멤버클래스

    • 멤버 변수와 동일한 위치에 선언된 내부 클래스
    • static예약어가 붙은 static 멤버와 instance 멤버로 나뉨
    • 동일한 클래스 뿐아니라 다른 클래스에서도 활용 가능
    • 클래스의 멤버 변수와 성격이 비슷
  • 지역클래스

    • 메서드 내에 클래스가 정의되어 있는 경우
    • 지역클래스와 무명클래스로 나뉨
    • 활용 범위가 메서드 블록 내부로 제한되는 특징을 갖는 등 지역 변수와 성격이 비슷

Comment and share

LocalDate

로컬 날짜 클래스로 날짜 정보만 필요할 때 사용한다.
LocalDate currentDate = LocalDate.now();
: 컴퓨터 현재의 날짜 정보를 저장한다.
LocalDate targetDate = LocalDate.of(int year, int month, int dayOfMonth);
파라미터로 주어진 날짜 값을 저장한다.
|리턴타입|메소드(매개변수)|설명
|-|-|-|
|int|getYear()|년|
|Month|getMonth()|Month 열거 값(JANUARY, FEBRUARY, MARCH ..)|
|int|getMonthValue()|월(1, 2, 3 ..)|
|int|getDayOfYear()|일년의 몇 번째 일|
|int|getDayOfMonth()|월의 몇 번째 일|
|DayOfWeek|getDayOfWeek()|요일(MONDAY, TUESDAY, WEDNESDAY..)|
|boolean|isLeapYear()|윤년여부|

LocalTime

로컬 시간 클래스로 시간 정보만 필요할 때 사용하면 된다.
LocalTime currentTime = LocalTime.now();
: 컴퓨터의 현재 시간정보
LocalTime targetTime = LocalTime.of(int hour, int minute, int second, int nanoOfSecond)
파라미터로 주어진 시간 값을 저장한다.
|리턴타입|메소드(매개변수)|설명
|-|-|-|
|int|getHour()|시간|
|int|getMinute()|분|
|int|getSecond()|초|
|int|getNano()|나노초|

LocalDateTime

날짜와 시간 정보가 모두 필요할 때 사용하면 된다.
LocalDateTime currentDateTime = LocalDateTime.now();
: 컴퓨터의 현재 날짜와 시간 정보
LocalDateTime targetDateTime = LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond);
파라미터로 주어진 날짜와 시간값을 저장한다.

ZonedDateTime

ISO-8601 달력 시스템에서 정의하고 있는 타임존의 날짜와 시간을 저장하는 클래스이다. 결과는 2016-04-01T16:54:05.739+09:00[Asia/Seoul]와 같고, 맨 뒤에 +09:00[Asia/Seoul] 협정세계시와의 시차(+9시간)와 ZoneId(Asia/Seoul) 정보가 붙는다.
ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of(“UTC”));
UTC기준 현재 시각을 표시해준다.
ZonedDateTime seoulDateTime = ZonedDateTime.now(ZoneId.of(“Asia/Seoul”));
|리턴타입|메소드(매개변수)|설명
|-|-|-|
|ZoneId|getZone()|ZoneId를 리턴(Asia/Seoul)|
|ZoneOffset|getOffset()|UTC와의 시차를 리턴(+09:00)|

Comment and share

startswith()

startsWith() 함수는 대상 문자열이 특정 문자 또는 문자열로 시작하는지 체크하는 함수이다. 해당 문자열로 시작되는지 여부를 확인하고 boolean 에 맞춰 true/false 값을 리턴한다.

public class StartsWithTest{

    public static void main(String[] args){

        String startsWithT = "자바 코딩 테스트 ";

        System.out.println( startsWithT.startsWith("자바") );  // true
        System.out.println( startsWithT.startsWith("자바 ") );// true
        System.out.println( startsWithT.startsWith("자") );// true
        System.out.println( startsWithT.startsWith(" 자") );// false
    }
}

Startswith()는 공백도 취급한다.

endswith()

endsWith() 함수는 대상 문자열이 특정 문자 또는 문자열로 끝나는지 체크하는 함수이다. 해당 문자열로 끝나는 여부를 확인하고 boolean 에 맞춰 true/false 값을 리턴한다.

public class EndsWithTest{

    public static void main(String[] args){
         String endsWithT = "자바 코딩 테스트 ";

        System.out.println( endsWithT.endsWith("테스트") );  // false
        System.out.println( endsWithT.endsWith("테스트 ") );// true
        System.out.println( endsWithT.endsWith("트 ") );// true
        System.out.println( endsWithT.endsWith(" 테") );// false
    }
}

테스트 뒤에 공백이 있기 때문에 공백을 넣지 않으면 false가 나온다.

Comment and share

indexof

특정 문자나 문자열이 앞에서부터 쳐음 발견되는 인덱스를 반환하며 만약 찾지 못했을 경우”-1”을 반환한다.

public class IndexOfTest{

    public static void main(String[] args){

        String indexOfTestOne = "Hello world";

        System.out.println( indexOfTestOne.indexOf("o") );  // 4
        System.out.println( indexOfTestOne.indexOf("x") );  // -1
        System.out.println( indexOfTestOne.indexOf("o",5) );  // 7
    }
}

.indexof(“찾을문자”,”시작할 위치”) 이런식으로 사용하면된다.
시작할위치는 생략 가능하며 생략할 경우 0번째 부터 찾기 시작한다.

lastindexof

lastindexOf()는 특정 문자나 문자열이 뒤에서부터 처음 발견되는 인덱스를 반환하며 만약 찾지 못했을 경우 “-1”을 반환합니다.

public class IndexOfTest{

    public static void main(String[] args){

        String indexOfTestOne = "Hello world";

        System.out.println( indexOfTestOne.lastIndexOf("o") );  // 7
        System.out.println( indexOfTestOne.lastIndexOf("x") );  // -1
        System.out.println( indexOfTestOne.lastIndexOf("o",5) );  // 4
    }
}

사용법은 indexof와 같으며 뒤에서부터 찾기 시작한다.
오른쪽에서 몇번째 위치하는지를 반환하는게 아니라 말그대로 인덱스
즉, 왼쪽에서 몇번쨰 위치하는지를 인덱스로 반환한다.

Comment and share

String VS StringBuffer/StringBuilder

String과 StrungBuffer/StrungBuilder 클래스의 가장 큰 차이점은 String은 불변의 속성을 갖는다는 점이다.
그렇기 때문에 변하지 않는 문자열을 자주 읽어들이는 경우 String을 사용해 주면 좋은 성능을 기대할 수 있다. 그러나 문자열 추가, 수정, 삭제 등의 연산이 빈번하게 발생하는 알고리즘에 String클래스를 사용하면 힙메모리에 많은 가비지가 생성되어 힙메모리 부족으로 어플리케이션 성능에 치명적인 영향을 끼치게 된다.

이를 해결하기 위해 가변성을 가지는 StringBuffer/StringBuilder클래스를 도입했다.

StringBuffer VS StringBuilder

이 두클래스의 큰 차이점은 동기화의 유무이다. StringBuffer는 동기화 키워드를 지원하여 멀티쓰레드 환경에서 안전하다는 점이다. 참고로 String도 불변성을 가지기 때문에 마찬가지로 멀티쓰레드 환경에서의 안정성을 가지고 있다.

반대로 StringBuilder는 동기화를 지원하지 않기 때문에 멀티쓰레드 환경에서 사용하는 것은 적합하지 않지만 동기화를 고려하지 않는 만큼 단일쓰레드에서의 성능은 StringBuffer보다 뛰어나다.

Comment and share

StringBuffer Class

StringBuffer Class는 변하는 문자열을 다룰 때 사용한다. 객체 생성시 크기를 정하지 않으면 기본적으로 16개의 문자를 저장할 수 있는 버퍼 공간을 가진다.

String클래스의 객체는 한 번생성이 되면 내용이 변하지 않는 반면에 StringBuffer클래스의 객체는 문자열의 내용을 변경할 수 있다. StringBuffer 클래스의 메소드는 문자열 처리 후의 결과를 원래의 StringBuffer 객체에 반영하고, 메소드 리턴 타입은 void 이다.

생성자

StringBuffer()
초기 문자열이 없고 16개의 문자를 저장할 수 있는 버퍼를 가진 객체를 생성한다.
StringBuffer(String str)
str의 초기 문자열을 가지고 16개의 문자를 저장할 수 있는 버퍼를 가진 객체를 생성한다.
StringBuffer(int length)
초기 문자열이 없고 length개의 문자를 저장할 수 있는 버퍼를 가진 객체를 생성한다.

메소드

append()

append()메소드는 이수로 전달된 값을 문자열로 변한한 후, 해당 문자열의 마지막에 추가한다.
이 메소드는 String클래스의 concat() 메소드와 같은 결과를 반환하지만, 내부적인 처리 속도가 훨씬 빠르다.
예제

StringBuffer str = new StringBuffer("Java");
System.out.println("원본 문자열 : " + str);

System.out.println(str.append("수업"));
System.out.println("append() 메소드 호출 후 원본 문자열 : " + str);

결과

원본 문자열 : Java
Java수업
append() 메소드 호출 후 원본 문자열 : Java수업

capacity()

capacity()메소드는 StringBuffer 인스턴스의 현재 버퍼 크기를 반환한다.
예제

StringBuffer str01 = new StringBuffer();
StringBuffer str02 = new StringBuffer("Java");

System.out.println(str01.capacity());
System.out.println(str02.capacity());

결과

16
20

위의 예제처럼 길이가 4인 문자열로 StringBuffer 인스턴스를 생성하면, 기본적으로 생성되는 여유 버퍼 크기인 16에 문자의 길이인 4를 더한 총 20개의 문자를 저장할 수 있는 버퍼가 생성된다.

delete()

delete()메소드는 전달된 인덱스에 해당하는 부분 문자열을 해당 문자열에서 제거한다. 또한, deleteCharAt() 메소드를 사용하면 특정 위치의 문자 한 개만을 제거할 수도 있다.
예제

StringBuffer str = new StringBuffer("Java Oracle");
System.out.println("원본 문자열 : " + str);

① System.out.println(str.delete(4, 8));
System.out.println(str.deleteCharAt(1));
System.out.println("deleteCharAt() 메소드 호출 후 원본 문자열 : " + str);

결과

원본 문자열 : Java Oracle
Javacle
Jvacle
deleteCharAt() 메소드 호출 후 원본 문자열 : Jvacle

위 예제의 ①번 라인에서는 delete() 메소드를 사용하여 해당 문자열에서 인덱스가 4인 위치의 문자부터 7인 위치의 문자까지를 삭제한다.

이처럼 delete() 메소드는 첫 번째 매개변수로 전달된 인덱스부터 두 번째 매개변수로 전달된 인덱스 바로 앞의 문자까지를 삭제하는 메소드이다.

insert()

insert()메소드는 인수로 전달된 값을 문자로 변환한 후, 해당 문자열의 지정된 인덱스 위치에 추가한다. 이때 전달된 인덱스가 해당 문자열의 길이와 같으면, append()메소드와 같은 결과를 반환한다.
예제

StringBuffer str = new StringBuffer("Java 만세!!");
System.out.println("원본 문자열 : " + str);

① System.out.println(str.insert(4, "Script"));
System.out.println("insert() 메소드 호출 후 원본 문자열 : " + str);

결과

원본 문자열 : Java 만세!!
JavaScript 만세!!
insert() 메소드 호출 후 원본 문자열 : JavaScript 만세!!

Comment and share

String Class

String 객체가 하나 생성되면, 그 값은 길어지거나 줄어들 수 없으며 그 문자들 중 어떤 것도 바뀔 수 없다.
그래서 String 객체는 변경불능이라고 한다.

String클래스의 자주 사용하는 함수이다.
|함수|반환형|설명
|—|—|—
|CharAt(int index)|char|index로 지정된 첨자 위치에 있는 문자를 반환한다.
|compareTo(String str)|int|이 String이 String str보다 사전적 순서에서 앞서면 음수값, 같으면 0값, 뒤에 있으면 0값이다.
|Concat(String str)|String|이 String과 str을 접합하여 구성되는 새로운 String을 반환한다.
|equals(String str)|boolean|이 String이 str과 같은 문자열이면 (대소문자 구분) True, 그렇지 않으면 False 반환
|equalslgnoreCase(String str)|boolean|이 String이 str과 같은 문자열이면(대소문자 미 구분) True, 그렇지 않으면 False 반환
|length()|int|이 String의 문자 개수를 반환한다.
|replace(char oldChar, char newChar)|String|String에 나타나는 oldChar를 모두 new Char로 변경한다.
|substring(int offset, int endIndex)|String|이 String의 offset 위치에서부터 endIndex-1까지에 걸친 문자열을 반환한다.
|toLowerCase()|String|모든 대문자를 소문자로 변환한다.
|toUpperCase()|String|모든 소문자를 대문자로 변환한다.

예제

public class StringClass {
    
    public static void main(String[] args){
        
        String text = "First String V";
        String concat, upperCase, replace, subString;
        
        System.out.println("기본 String : "+ text);
        System.out.println("기본 String 길이 : "+text.length());    // 문자열 길이 출력
        
        concat = text.concat(", Second String V");    // 문자열 연결
        
        upperCase = concat.toUpperCase();        // 문자열 대문자로 변환
        
        replace = upperCase.replace('V', 'K');    //  문자 V를 K로 변환
        
        subString = replace.substring(3, 10);    // 3~9 문자열 잘라내기
        
        
        System.out.println("Concat String : " + concat);
        System.out.println("upperCase String : " + upperCase);
        System.out.println("replace String : " + replace);
        System.out.println("subString String : " + subString);
        
        
    }

}

System.out.println(“기본 String 길이 : “+text.length()); // 문자열 길이 출력

text인 “First String V” 의 문자열 길이를 반환한다.

-> 14

concat = text.concat(“, Second String V”); // 문자열 연결

text인 “First String V” 뒤에 concat 메소드로 “, Second String V” 를 연결했다.

-> First String V, Second String V

upperCase = concat.toUpperCase(); // 문자열 대문자로 변환

concat인 “First String V, Second String V” 의 문자열을 대문자로 변환한다

-> FIRST STRING V, SECOND STRING V

replace = upperCase.replace(‘V’, ‘K’); // 문자 V를 K로 변환

upperCase인 “FIRST STRING V, SECOND STRING V” 문자열 중 ‘V’ 문자를 ‘K’ 문자로 변환 한다.

-> FIRST STRING K, SECOND STRING K

subString = replace.substring(3, 10); // 3~9 문자열 잘라내기

replace 인 “FIRST STRING K, SECOND STRING K” 문자열의 3번째 부터 9번째 문자열까지 잘라낸다 (0부터 시작)

-> ST STRI

Comment and share

JVM과 메모리

메모리는 OS가 관리하는데, 모든 프로그램들은 OS위에서 돌아간다.
프로그램이 돌아가려면 메모리가 있어야된다.
JVM도 메모리가 필요하면 OS에게 메모리 요청을 한다.
그런데 OS가 처음부터 자기가 가진 메모리를 전부 다 줘버리면, 다른 프로그램들에게 줄 메모리가 없게 된다.
때문에 각 프로그램에게 메모리의 일정부분만 빌려주는 방식으로 관리가 된다.

JVM을 실행하다가 메모리가 부족하면 OS에게 메모리를 더 달라고 요청한다. 그러면 OS가 또 JVM에게 메모리를 더 빌려준다.
JVM은 OS로 부터 받은 메모리들 중, 어디에다가 저장할지 그 주소를 할당하야 한다.
이 때, JVM은 자기가 받은 메모리 안에서, 절대주소가 아니라 거기에 대한 상대주소를 할당한다. 이걸 offset주소라고 한다.

Garbage Collector

프로그램을 실행하다보면 가비지가 발생하게 된다.
가비지는 정리되지 않은 메모리, 유효하지 않은 메모리 주소를 말한다.
가비지 컬렉터는 메모리가 부족할 때 가비지를 정리해주는 프로그램을 말한다.
때문에 JVM의 가비지 컬렉터는 메모리를 다른 용도로 사용할 수 있게 ‘메모리 해제’를 시키는 프로그램이다.
참고로 가비지 컬렉터는 JVM이 OS에게 추가로 메모리를 더 요청할 때 실행된다.
또, 서버 프로그램인 경우에는 24시간 내내 돌아가는데, 이때에는 JVM이 한가할 때 가비지 컬렉터가 실행된다.

Comment and share

메모리(RAM)

프로그램이 실행하게 되면 OS는 메모리(RAM)에 공간을 할당해 준다.
할당해주는 메모리 공간은 4가지(Code, Data, Stack, Heap)가 있다.

코드(Code) 영역

우리가 작성한 소스코드가 들어가는 부분.
즉, 실행할 프로그램의 코드가 저장되는 영역으로 텍스트영역이라고도 부른다.
코그영역은 실행 파일을 구성하는 명령어들이 올라가는 메모리 영역으로 함수, 제어문, 상수 등이 여기에 저장된다.

데이터(Data) 영역

전역변수와 Static변수가 할당되는 영역
프로그램의 시작과 동시에 할당되고, 프로그램이 종료되어야 메모리가 소멸되는 영역.

스택(Stack) 영역

프로그램이 자동으로 사용하는 임시 메모리 영역.
함수 호출 시 생성되는 지역 변수와 매개변수가 저장되는 영역이고,
함수 호출이 완료되면 사라진다.

힙(Heap) 영역

프로그래머가 할당/해체하는 메모리 공간이다.
Java에서는 가비지 컬렉터가 자동으로 해제한다.
이 공간에 메모리 할당하는 것을 동적 할당이라고도 부른다.

Heap과 Stack영역은 같은 공간을 공유한다. 그래서 Heap이 메모리 위쪽 주소부터 할당되고 Stack은 아래쪽 부터 할당된다. 각 영역이 상대 공간을 침범하는 일이 발생할 수 있는데 이를 각각 Heap Overflow, Stack Overflow라고 칭한다.

Comment and share

클래스의 상속

class Person {

    protected int age;
    
    protected String name;
    
    public Persion(int age, String name) {
        this.age = age;
        this.name = name;
    }
    
    public int getAge() {
        return this.age;
    }
    
    public String getName() {
        return this.name;
    }
}

age와 name이라는 멤버 변수를 가지고 있는 Person 클래스를 생각해보자. 이 클래스를 상속 받는 Student 클래스는 다음과 같이 정의할 수 있다.

class Student extends Person {
    
    protected String studentNumber;
    
    public Student(int age, String name, String studentNumber) {
        
        super(age, name);
        this.studentNumber = studentNumber;
    }
    
    public String getStudentNumber() {
    
        return this.studentNumber;
    }
}

‘extends’라는 키워드를 이용해서 Person 클래스를 상속받아 확장하여 Student 클래스를 정의했다. Student 클래스 정의에는 직접적으로 나와있지 않지만 부모 클래스인 Person 클래스의 메소드인 getAge()와 getName() 메소드를 호출 할 수 있다.

일반적으로 두 클래스 간의 관계가 ‘IS-A’ 관계이면 상속을 사용한다. Student is a person이므로 상속을 통해서 클래스를 정의하는게 자연스럽다.

클래스의 위임

상속과 다르게 위임은 다른 클래스의 객체를 멤버로 갖는 형태의 클래스 정의다.

class Employee {
    
    private Department department;
    
    private String name;
    
    publiv Employee(String name, Department department) {
        
        this.name = name;
        this.department = department;
    }
    
    public String getDepartmentName() {
    
        return this.department.getName();
    }
}

이 경우 특정 메소드 호출을 멤버 클래스의 메소드에 포워드(Forward)하는 식으로 구현하게 된다.

Employee 클래스와 Department 클래스 사이의 관계를 살펴보면 ‘IS-A’ 관계는 아니다. (Employee is a Department는 어색하다.) 따라서 멤버 변수로 Department 클래스를 포함하는 Delegation 형태로 구현을 했다.

상속과 위임

  • 두 클래스의 관계가 ‘IS-A’ 관계이면 상속(Inheritance)을 써야한다.
  • 기존에 존재하는 API에 넘겨줘야 하는 경우 상속(Inheritance)을 써야한다.
  • final 클래스를 확장하고 싶은 경우 위임(Delegation)을 써야한다.

Comment and share

Hyeon Soo Ahn

author.bio


author.job