반응형

본 글은 책 자바의 정석을 ref 하며, 요약한 내용입니다.


 

✔ 자바는 객체지향 언어이다. (상속, 추상화, 캡슐화, 다형성)

✔ 풍부한 JAVA API 라이브러리를 제공한다.

✔ 자바 app은 JVM과 상호작용한다. 

 

JVM

소프트웨어로 구현된 하드웨어

자바가 실행되기 위해선 JVM이 필수적

운영체제에 종속적이다. (Write once, Run everywhere)

 

JRE(java runtime environment)

JVM + 자바 프로그램을 실행하는 도구들

* JRE가 설치되어 있다면 어떤 환경에서든지 자바 소스 파일을 실행할 수 있다.

* 개발이 필요없는 단계라면 JRE만으로 프로그램을 실행할 수 있다.

 

JDK(java devlopment kit)

JRE(java runtime environment) + JAVA API + 컴파일러.. (개발에 필요한 도구)

 

자바 프로그램 실행 과정

자바 app은 실행할 때 main 메서드를 시작점으로 한다.

Sample.java -> (javac.exe)(컴파일러) -> Sample.class -> (java.exe)(인터프리터) -> 프로그램 실행

 

 


 

변수

메모리 공간에 이름을 붙여주는 것

변수 타입에 맞게 메모리를 확보

 

변수의 초기화

이전에 사용했던 garbage value가 남아 있을 수 있어서 사용하기 이전에 초기화해주는 것이 바람직

* 전역 변수는 초기화 생략 가능

* 지역 변수는 반드시 초기화

 

변수의 종류

기본형 - boolean, byte, short, int, long, float, double, char

참조형 - 배열, 열거, 클래스, 인터페이스

* boolean을 제외한 나머지 7개의 기본형 타입은 서로 변환이 가능

* char 은 유니코드 체계를 위해 2byte (유니코드 정수 값이 저장된다)

* char과 shrot는 같은 2byte이지만 범위가 다르다.

* JVM 스택 연산에 4byte를 사용하므로 byte, short보다 int 형이 유리하다.

* 정수형 타입 크기를 벗어나면 overflow가 발생한다.

* 실수형 타입 float - 정밀도 7자리, double - 15자리

 

String 결합

한쪽이 String 이고, 연산자가 + 로 연결되어있다면 다른 한쪽도 String으로 만든 후 결합

 

printf

%5d  -  5칸 오른쪽정렬

%-5d  -  5칸 왼쪽 정렬

%14.10f  -  14칸. 소수점 이하 10칸

 

word

cpu가 한 번에 처리할 수 있는 데이터의 크기 32bit, 64bit

 

2진법, 8진법, 16진법

2진법 - 컴퓨터는 전기가 흐르면 1 흐르지 않으면 0

2진법을 이용하여 10진법, 8진법, 16진법 변환

 

실수의 진법 변환

소수부에 2를 계속 곱하여 0이 될 때까지 반복, 결과의 정수부 나열

 

2의 보수

N의 보수: 자릿수를 한자리 증가시키는, 더해서 0으로 만드는 수

ex) 숫자 73의 10의 보수 = 37 (73과 37은 보수관계)

 

✔ 보수에서는 자릿수가 중요하다.

만약 10진수가 2자리를 표현한다면 73과 37은 보수관계가 맞다. (73+37 = 100) "1"00 표현 불가

하지만 10진수가 3자리를 표현한다면 73과 937이 보수관계이다. (73+937 = 1000) "1"000 표현 불가

 

2의 보수에서는 MSB가 0이면 양수, 1이면 음수로 구분한다.

4자리 이진수에서는 0011의 2의 보수는 1101 (0011과 1101은 보수관계)

4자리 2의 보수 체계에서 1101은 십진수 -3의 역할을 한다.

십진수로 3인 0011의 반대 값은 -3인 1101

 

-3일 때 3의 보수(1101)를 구하고 더하면 -3의 효과를 낸다.

* 2의 보수 구하기 = 1의 보수 +1

 

오버플로우

4 자릿수의 bit체계에서 0111과 0001을 더하면 1000이 된다. MSB가 1이므로 음수다. 1000은 -8이다.

7+1의 결과는 8인데, 결과가 -8이 나왔다. 이를 표현 숫자 범위를 벗어난 오버플로우라고 한다.

 

인코딩과 디코딩

인코딩 - 문자를 숫자(지정된 바이트)로 

디코딩 - 숫자(지정된  바이트)를 문자로

디코딩을 하기 위해선 어떻게 인코딩했는지 알아야 한다.

 

UTF-8 UTF-16

UTF-8 -> 가변크기 1~4 byte 표현 (웹문서에서 유리, 아스키 코드와 호환됨, 대부분 프로그램의 Default)

* 110XXXXX 10XXXXXX 10XXXXXX

* 한 문자를 표현할 때 3Byte를 써야하는 경우 -> 110을 시작으로하고, 나머지 Byte는 10으로 시작.

* 110으로 문자 시작을 알림

UTF-16 -> 고정크기 2byte 표현 (자바에서 사용)

 

형 변환

기본형과 참조형 간의 형 변환은 불가능

더 큰 타입으로 대입될 때는 묵시적 형 변환, 작은 타입으로 대입될 때는 값이 손실되며 명시적 형 변환

 

정수형 -> 실수형 : 정밀도 제한으로 오차 발생 

실수형 -> 정수형 : 정수부만 저장

* byte < short < int < long < float < double

 

 


 

 

 

 

반응형
반응형

 

배열을 컬렉션 프레임워크로 변환

 

 

방법 1

 

int[] arr = {1,2,3,4,5};
List<Integer> list1 = new ArrayList<>();

for(int i = 0 ; i<arr.length; i++)
    list1.add(arr[i]);

 


 

방법 2

 

int[] arr = {1,2,3,4,5};
List<Integer> list = Arrays.stream(arr).boxed().collect(Collectors.toList());

int 기본형 배열은 boxed()가 필요하다.

 

 

String[] strArr = {"K", "O", "M"};
List<String> strList = Arrays.stream(strArr).collect(Collectors.toList());

일반적인 객체 배열은 boxed()가 필요하지 않다.

 

 

IntStream is = IntStream.of(1,2,3,4);
List<Integer> list2 = is.collect(Collectors.toList()); // 컴파일에러

그 이유는 Arrays.stream()을 이용해서 기본형 배열을 스트림으로 바꾸게 되면, 타입이 IntStream이 된다.

IntStream을 다시 Stream<T>와 같은 형태로 만들기 위해 boxed()를 사용한다.

 


 

컬렉션 프레임워크를 배열로 변환

 

방법 1

 

List<Integer> list = Arrays.asList(1,2,3,4,5);
int[] ar = new int[list.size()];

for(int i = 0; i<list.size(); i++)
    ar[i] = list.get(i);

 

방법 2

 

List<Integer> list = Arrays.asList(1,2,3,4,5);
int[] arr = list.stream().mapToInt(e->e).toArray();

배열을 컬렉션 프레임워크로 바꿀때와 마찬가지로 Stream<T>를 IntStream으로 변환 후 toArray()

 

 

 

 

 


 

반응형
반응형

 


 

메서드 참조란 말 그대로 다른 클래스의 메소드를 참조하여 사용한다입니다.

구현부를 빌려쓴다고 이해하시면 됩니다.

 

 

함수형 인터페이스가 클래스의 메서드 구현부를 빌려서 자신이 구현한 메서드인 것처럼 사용합니다.

 

 

람다식같은 경우는 직접 개발자가 구현부를 작성하는 것이고,

메서드 참조는 클래스를 빌려 쓰는 것입니다.

 

 

 

 

 

 

 

 

코드로 설명하겠습니다.

 


 

public class ProviderClass {
    public int providerFunc1(int x, int y){
        return x + y;
    }

    public int providerFunc2(int x, int y){
        return x - y;
    }

    public static int providerFunc3(int x, int y){
        return x * y;
    }

    public static int providerFunc4(int x, int y){
        return x / y;
    }
}

 

ProviderClass (메서드를 제공해줄 클래스)를 정의해두었습니다.

4개의 메소드를 정의해두었습니다.

 

3번 메소드, 4번 메서드는 static으로 선언해두었습니다.

 


 

@FunctionalInterface
public interface FuncInterface {
    public int shell(int x, int y);
}

 

메서드를 참조 사용하기 위해 껍데기 메서드가 있어야 합니다.

함수명 shell로 정의해두었습니다.

 

함수형 인터페이스 하나를 선언해두었습니다.

FuncInterface의 shell 메서드는 ProviderClass의 메서드의 구현부를 빌려서 사용할 겁니다.

 

껍데기 역할을 해줄 곳은 반드시 함수형 인터페이스여야 합니다.

함수형 인터페이스란 오로지 하나의 추상 메서드만을 갖고 있는 인터페이스를 말합니다.

 

하나의 추상 메서드만을 갖고 있어야 하는 이유는

여러 개의 추상 메서드를 갖고 있는 인터페이스가 다른 클래스의 메서드를 빌려 쓴다면,

타입의 혼란을 야기할 수 있기 때문에 반드시 하나의 추상 메서드만 있어야 합니다.

자바에서는 함수형 인터페이스가 아니면 메서드 참조를 할 수 없도록 막아둠

 

자바는 이러한 함수형 인터페이스를 제네릭으로 선언해 타입을 맞춰 API로 제공해줍니다.

java.util.function.*

 


 

public class mainClass {

    public static void main(String[] args) {

        // 메소드 제공 클래스
        ProviderClass providerClassInstance = new ProviderClass();

        // 제공받는 인터페이스
        FuncInterface funcInterface1 = providerClassInstance::providerFunc1; // 인스턴스 메소드는 "변수 명"으로 사용
        FuncInterface funcInterface2 = providerClassInstance::providerFunc2;
        FuncInterface funcInterface3 = ProviderClass::providerFunc3; // static 메소드는 "클래스 명"으로 사용
        FuncInterface funcInterface4 = ProviderClass::providerFunc4;

        // 참조하여 사용
        int sum = funcInterface1.shell(30,10); // 더하기
        int sub = funcInterface2.shell(30,10); // 빼기
        int mul = funcInterface3.shell(30,10); // 곱하기 (static)
        int div = funcInterface4.shell(30,10); // 나누기 (static)

        System.out.println(sum);
        System.out.println(sub);
        System.out.println(mul);
        System.out.println(div);
    }
}

 

인스턴스 메서드를 사용해야 할 때는

제공 클래스의 변수명::메서드명

 

클래스 메서드(static)를 사용할 때는

클래스 명::static 메서드 명

 

함수형 인터페이스 FuncInterface가 ProviderClass의 메서드들을 참조하면서

자신의 빈 껍데기 메서드 shell()로 ProviderClass에 구현된 메서드 기능을 참조하면서 자신의 것처럼 사용할 수 있습니다.

 

메서드를 참조하기 위해선 매개변수 타입, 리턴 타입, 개수가 일치해야 합니다.

 

 


 

메서드 참조: 함수형 인터페이스를 이용해서 다른 클래스의 메서드를 빌려쓰는 것

 


 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

익명 클래스는 말 그대로 클래스의 이름이 없다.

익명 클래스는 설계도가 1회성이라는 말이다.

 

 

이름이 없으므로 생성자를 구현할 수 없다.

익명 클래스를 정의하려면 상속을 받거나 인터페이스로 구현해야한다.

 

 

참조 변수에 넣어두고 재사용할 수 있다.

상위 클래스의 생성자 지정, 오버 라이딩은 가능하다.

 

 

 


상속을 받은 익명 클래스

 

상속받아서 사용할 Outer 클래스

 

Outer 클래스를 익명 클래스로 활용

 

참조변수 o는 Outer를 상속받아서 1회성 구현부를 작성하고 인스턴스를 생성한 것과 같다.

 


인터페이스로 구현한 익명 클래스

 

 

추상메서드 2개를 갖는 인터페이스를 정의한 후

 

 

상속과 마찬가지로 인터페이스를 익명 클래스로 구현해서 사용할 수 있다.

 

참조변수 ti는 TestInterface의 추상메서드들을 구현하고 인스턴스를 생성한 것과 같다.

 

 


람다식(함수형 인터페이스)

 

위에서 본 익명클래스들의 생성을 코드 구현을 더 짧게 하고자 하는 것이 람다식이다.

 

마찬가지로 람다식은 단순히 함수를 구현하는 것 같지만 사실 객체의 생성이다.

인터페이스를 구현받아서 추상메서드를 작성하고 익명 객체를 생성한 것이다.

 

 

익명 클래스의 구현을 람다식으로 바꿔줄 수 있다.

(매개변수) -> 메서드 구현부

 

대신, 조건으로 인터페이스는 하나의 추상 메서드만을 갖고 있어야 한다.

하나의 추상 메서드만을 갖고 있는 인터페이스를 함수형 인터페이스라 한다.

 

람다식은 함수형 인터페이스를 이용해서 익명 객체로 구현하는 과정을 짧게 만든 것이다.

함수형 인터페이스가 갖고 있는 하나의 추상메서드의 1회성의 구현부를 만든 후 객체를 생성한 것

 

 


자바에는 이러한 함수형 인터페이스를 미리 만들어 둔 API가 있다.

https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/function/package-summary.html

 

java.util.function (Java SE 15 & JDK 15)

Functional interfaces provide target types for lambda expressions and method references. Each functional interface has a single abstract method, called the functional method for that functional interface, to which the lambda expression's parameter and retu

docs.oracle.com

 

 

 

 


 

반응형
반응형

[JAVA] String 참조값 비교와 StringBuilder, StringBuffer 사용 이유


 

String에서 + 연산을 사용하면 안 되는 이유

StringBuilder, StringBuffer를 사용하는 이유

 


String에서 + 연산을 사용하면 메모리를 추가로 사용한다.

 

 

str1, str2 는 같은 곳을 참조함 (String pool에서의 같은 위치)

 

str3는 String을 + 연산을 사용해서 "abc"를 만들었는데도 String pool의 "abc"를 참조하지 않는다.

+연산을 String에서 하게 되면 String pool에서 찾지 않고 마치 new("abc")를 한 것처럼 "abc" 새로운 메모리가 생성된다.

이는 GC의 부담, 메모리의 낭비를 야기한다.

그러므로 String에서는 + 연산을 지양해야 함

 

== 연산자가 아닌 equals()를 사용하면 문자열은 전부 같으므로 결과는 모두 true이다.

 


StringBuilder, StringBuffer

 

 

StringBuilder도 내부적으로 toString()을 처리할 때 new 연산자를 사용하므로 새로운 메모리가 생성되지만,

toString()할 때 new 연산자를 단 한번 사용하기 때문에 여러 문자 결합에서 이점을 갖는다.

 


 

 

반응형
반응형

[JAVA] 자바 접근 제어자


자바의 접근제어자는 4종류가 있다.

 

                                                         public : 제한 없음

                                                         protected : 패키지 내부  //  다른 패키지여도 상속(extends) 했다면 사용 가능

                                                         defalut : 패키지 내부

                                                         private : 클래스 내부

 

 

이 중 접근제어자로 protected가 헷갈리는 경우가 많아 정리하고자 한다.

 

protected는 같은 패키지 내부에서 사용 가능하다. 이점은 헷갈리지 않는다.

헷갈리게 하는 부분은 다른 패키지여도 상속했다면 사용가능하다는 의미에서 헷갈린다.

 

결론부터 말하자면 protected는 메서드, 멤버변수에 사용가능하고

다른 패키지에서 사용하려면 protected 메서드, 멤버변수를 가진 class가 public이어야 한다.

 


테스트 구조도

 

패키지 Classtest

  • (default) DefaultClass 
  • (public) PublicClass

 

패키지 Classtest2

  • MainCalss

 

 

다른 패키지에서 DefaultClass를 import할 수 없다.

default는 같은 패키지에서만 사용할 수 있기 때문이다.

 


이제 PublicClass를 이용해서 protected를 테스트해보자.

PublicClass의 내부는 다음과 같다.

public 변수 number1

protected 변수 number 2

 

 

다른 패키지인 MainClass에서 PublicClass를 import 후 사용을 해봤다.

protected인 number 2가 보이지 않는다.

protected는 상속해야 사용 가능하기 때문이다.

 

 

상속을 하고 나서야 number 2를 확인할 수 있다.

 

 


사용 가능한 접근제어자

 

Class : public, default

멤버, 메서드, 생성자 : public, protected, default, private

 

 

Class에서는 public default 밖에 사용하지 못함에 주의하자.

 


 

반응형
반응형

[JAVA] 자바 String, StringBuilder 클래스 활용


 

자바를 사용하다 보면 문자열을 처리해줘야 할 경우가 많이 생긴다.

이때 String과 StringBuilder 클래스를 활용하면 좋다. 그리고 경우에 따라 String을 써야 할 경우와 StringBuilder를 써야 할 경우가 구분된다.

어떤 경우에 String과 StringBuilder를 맞게 써야 하는지 정리하고, 함수들의 활용법을 정리하고자 한다.

 


String과 StringBuilder의 구분

 

String 클래스와 StringBuilder는 용도가 다르다.

 

String은 클래스 명 그대로 문자를 이용해서 활용을 해야 할 때 사용하는 클래스이다.

* 문자를 변경, 검색, 반복, 대소문자 변환, 비교, 분리 등

"문자 특성"을 이용하기 위해 사용하는 클래스이다.

 

StringBuilder문자열을 배열처럼 관리하며 추가, 삭제, 삽입을 용이하게 하기 위해 사용한다.

* 문자를 추가, 삭제, 삽입, 뒤집기 등

"배열 index"를 이용하여 문자를 관리하는 클래스이다.

 

문자 특성을 이용한 작업을 처리할 땐 String 클래스를 이용하고, 변경이 빈번한 문자들을 배열처럼 관리하고 싶을 때 StringBuilder를 이용한다.

 

* String 클래스는 함수를 사용하면 반환 값을 사용해야 하므로 대입 연산자를 이용해야 한다.

ex) str = str.trim();

* StringBuilder는 내부적으로 추가, 삭제, 삽입, 변경을 처리하기 때문에 반환 값을 사용할 필요가 없다.

ex) sb.append(var);

 


자주 사용하는 String과 StringBuilder의 공통 함수

 

  • length() : 문자열의 총길이를 반환한다.
  • charAt(index) : index 위치에 해당하는 문자를 반환한다.
  • indexOf(String) : 문자열이 위치하는 index를 반환한다. (String에서는 char도 가능하다.)
  • substring(from, to) : from부터 to까지 해당되는 문자열을 반환한다. (to index는 포함하지 않는다.)

 


자주 사용하는 String 클래스 함수

 

비교

  • compareTo(String) : String과 비교 후 String보다 문자가 작다면 1, 크다면 -1, 같다면 0을 반환한다.
  • compareToIgnoreCase(String) : 대소문자 차이를 무시하고 비교한다.
  • equals(Object) : Object와 비교 후 같다면 true, 다르면 false를 반환한다. String 클래스는 문자열을 비교한다.

 

검색

 

  • contains(CharSequence) : CharSequence가 포함되어있는지 확인한 후 포함하면 true, 포함하지 않으면 false를 반환한다.
  • startWith(String) : String으로 시작하면 true, 아니면 false를 반환한다.
  • endWith(String) : String으로 끝나면 true, 아니면 false를 반환한다.

 

 

변환

 

  • concat(String) : String과 합친 후 합친 문자열을 반환한다.
  • repeat(int count) : count만큼 반복 후 반환한다.
  • replace(char or CharSequence, char or CharSequence) : char, CahrSequence 둘 다 가능하며 앞 인자를 뒷 인자로 변경한다.
  • toLowerCase() : 소문자로 변환 후 반환한다.
  • toUpperCase() : 대문자로 변환 후 반환한다.
  • trim() : 문자열의 양쪽 공백을 제거 후 반환한다.
  • toCharArray() : char 배열 자료형으로 반환한다.

 

 

분리, 결합

  • split(String regex) : regex를 기준으로 자른 후 String []로 반환한다.
  • String.join("str" ,String[]) : str을 사이에 넣어주며 String [] 배열을 합친다.

 

* CharSequence => String, StringBuilder, StringBuffer 등

 


자주 사용하는 StringBuilder 클래스 함수

 

추가

  • append() : StringBuilder에 추가한다.

 

삭제

  • delete(from, to) : from부터 to까지 해당되는 index들을 제거한다. (to는 제외)
  • deleteCharAt(index) : index에 해당하는 문자 하나를 제거한다.

 

삽입

  • insert(index, Object) : index위치에 Object를 추가한다.

 

변경

  • replace(from, to, String) : from, to 부분을 String으로 변경한다. (to는 제외)
  • setLength(len) : len만큼 길이를 변경한다. (len을 0으로 설정하면 내부가 비워지는 효과를 볼 수 있다.)
  • setChar(index, char) : 해당 index를 char로 변경한다.
  • reverse() : 문자열을 뒤집는다.

 

주의: StringBuilder는 equals()가 주소 비교를 한다.  toString()을 해야 한다.


자바 문서

https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/String.html#concat(java.lang.String) 

 

String (Java SE 15 & JDK 15)

All Implemented Interfaces: Serializable, CharSequence, Comparable , Constable, ConstantDesc public final class String extends Object implements Serializable, Comparable , CharSequence, Constable, ConstantDesc The String class represents character strings.

docs.oracle.com

https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/StringBuilder.html

 

StringBuilder (Java SE 15 & JDK 15)

All Implemented Interfaces: Serializable, Appendable, CharSequence, Comparable public final class StringBuilder extends Object implements Serializable, Comparable , CharSequence A mutable sequence of characters. This class provides an API compatible with S

docs.oracle.com

 

반응형
반응형

[JAVA] 자바 오버 로딩 (Overloading)


하나의 클래스 안에서 여러 개의 같은 이름의 메서드를 여러 개 정의하는 것을 오버 로딩이라고 합니다.

이름이 같은 함수가 여러 개의 인자를 갖고 있는 것처럼 보여서 과적되었다고 표현하는 것입니다.

오버 로딩은 조건이 필요한데, 3가지를 기억하시면 됩니다.

  • 메서드의 이름이 같아야 한다.
  • 매개변수의 개수 또는 타입이 달라야 한다.
  • 반환 타입이 다른 것은 오버 로딩에 영향을 미치지 않는다.

 

결국 오버 로딩이란 메서드들의 이름은 같지만, 매개변수의 개수 또는 타입이 달라질 때 사용하는 것입니다.

주의해야 할 점은 반환 타입이 다르다고 할지라도 이름과 매개변수가 같으면 같은 함수로 인식된다는 점입니다.

반환 타입은 오버 로딩에 영향을 주지 않습니다.

반환 타입은 넘겨주는 쪽에서 제대로 된 타입만 넘겨준다면, 받는 쪽에서 형 변환을 통해 사용할 수 있기 때문입니다.

 


실습 코드

 

public class OverloadingTest {
    public static void main(String[] args) {
        add(4,5);
        add(3L,2L);
        add(1,2,3);
    }
    static void add(int a, int b){
        System.out.println(a + b);
    }
    
    static void add(long a, long b){ // 타입이 다른 경우
        System.out.println(a + b);
    }
    
    static void add(int a, int b, int c){ // 개수가 다른 경우
        System.out.println(a+b+c);
    }
}
 
cs

 

 

매개변수의 숫자를 더하는 함수로 add 함수를 만들어놓고,

추가적으로 오버 로딩하여 타입이 다른 경우와 개수가 다른 경우를 테스트해보시면 함수의 이름이 같다고

하더라도 오버 로딩이 적용되어 올바르게 작동하는 점을 보실 수 있습니다.

 


반환 타입만 바꾼 경우

 

 

같은 함수의 이름과 매개변수를 같게 하여 반환 타입만 바꿔본 경우입니다. 같은 함수로 인식되어 오류가 발생합니다.

반환 타입만 바꾼다고 해서 오버 로딩이 되지 않으며 컴파일 오류가 발생합니다.

 


기변 매개변수

 

public class Main1{
    public static void main(String[] args) {
        System.out.println(defaultParameter(1,2));
        System.out.println(defaultParameter(1,2,3,4));
    }
 
    static int defaultParameter(int... a) {
        int sum = 0;
        for (int i : a) {
            sum+=i;
        }
        return sum;
    }
}
cs

 

자바에서 함수의 매개 변수의 개수를 바꿔가며 줄 때 함수의 매개 변수의 선언부에 타입... 변수라고 지정해주면

타입만 맞다면 최대 개수의 255개 내에서 제한없이 함수를 호출할 수 있습니다. 사실 배열 타입으로 선언된 매개변수입니다.

주의할 점은 기본 매개변수와 같이 사용한다면 항상 선언부의 맨 뒤에 와야 합니다.


 

오버 로딩의 개념 자체는 어렵지 않으며, 오버 라이딩과 혼동할 수 있으니 오버 라이딩도 함께 공부하시면 좋습니다.

반응형
반응형

[JAVA] 자바 BufferedReader 사용법


자바에서 입력을 받을 때 Scanner 클래스로 입력을 받아왔었다.

BufferedReader가 사용하기 불편해서 Scanner가 등장한 걸로 알고 있지만 백준 문제를 풀다 보면 Scanner를 사용했을 때

입력 자체에서 시간 초과가 걸리는 경우가 많아서 BufferedReader를 다시 사용하게 되었다.

 

 

Scanner는 내부적으로 정규 표현식이 너무 많이 적용되어있어서 parse 할 때는 편리하지만, 성능이 희생당한다.

 

 

추가로 출력을 해주는  BufferedWriter도 있지만, 출력을 할 때 StringBuilder에 담아서 출력만 해도 출력 시간 초과는 해결된다.

이 글에서는 BufferedReader만 간단하게 사용하는 법을 정리하기로 했다.

 

 


BufferedReader 사용법

 

 

1
2
3
4
5
6
7
8
9
10
11
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class BR {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = br.readLine();
        System.out.println(str);
    }
}
cs

 

사용하기 위해선 3가지 코드를 작성해주어야 한다.

 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import를 이런식으로 따로 해주거나

 

 
import java.io.*;
한번에 import를 처리해줘도 된다.

 

 

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

두개의 보조 스트림 BufferedReader, InputStreamReader를 사용해서 입력 객체를 생성해준다.

 

main함수에 throws IOException를 추가해주면 기본적인 준비는 마쳤다.

 
이제 br.readLine() 메서드로 입력을 받아줄 수 있다.

고려해야할 점은 br.readLine()의 return은 String이므로 String으로 입력을 받아야한다.

또한 BufferedReadr는 Line 단위로 읽는다.

 

자주 사용하는 추가적인 함수들

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.*;
import java.io.*;
 
public class BR {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = br.readLine();
        System.out.println(str);
 
        // 정수 변환시
        int n = Integer.parseInt(str);
 
        // 문자를 자를 시
        StringTokenizer st = new StringTokenizer(br.readLine());
        String str1 = st.nextToken();
        int m = Integer.parseInt(st.nextToken());
 
        String[] strs = br.readLine().split(" ");
 
    }
}
 
cs

 

 

문자를 입력을 받은 경우 보통 두 가지 경우가 발생한다.

  • 입력받은 문자를 숫자로 변환할 경우 
  • 입력받은 문자를 특정 문자 기준으로 자를 경우

 

11줄) 문자를 숫자로 변환할 경우는 Integer.parseInt()로 변환해주면 된다.

 

문자를 특정문자 기준으로 자를 경우 두 가지 방법이 가능하다.

14줄) StringTokenizer를 사용할 경우 StringTokenizer 생성자에 입력받을 문자를 넣은 후, nextToken() 함수로 하나 씩 가져와 사용할 수 있다.

공백이 아닌 특정 문자 기준으로 자르고 싶을때에는 new StringTokenizer(br.readLine(), "자를문자");

 

18줄) String.split()을 사용할 경우 반환을 String [] 배열로 받아주어야 한다. split() 함수의 인자로 자를 문자를 입력하면 된다.

 

 


 

반응형
반응형

[JAVA] 자바 Iterator와 ListIterator 사용법


자바에서는 Collection 인터페이스를 구현한 자료구조인 ArrayList, LinkedList, HashSet, TreeSet 등의 요소를 하나씩 반복하여

모든 요소를 확인할 수 있는 Iterator (단방향) ListIterator(양방향)가 있습니다.

 


Iterator 구현도

 

인터페이스가 추상메서드를 갖고 있다면 해당 인터페이스를 구현하는 클래스는 모두 해당 메서드의 구현부를 작성해야 합니다.

 

Iterator는 iterator()라는 함수명을 갖고 있는 추상 메서드가 반환을 합니다.

iterator() 추상 메서드의 위치는 Iterable이라는 인터페이스에서 작성을 해뒀습니다.

결국 Iterable을 구현한 모든 클래스는 iterator()라는 함수의 구현부를 작성해야합니다.

 

Collection 인터페이스

Collection 인터페이스가 Iterable를 상속받았습니다.

그래서 Collection을 구현한 자료구조 API는 iterator()함수를 구현을 해놨습니다.

실제 구현부는 ArrayList, LinkedList, HashSet, TreeSet 와 같은 실제 인스턴스를 생성하는 클래스에서 구현을 합니다.

설계 방식은 전부 다르므로 Iterator를 통해 요소를 가져오고 삭제하는 과정도 따로 작업을 해놨습니다.

 

iterator()를 호출하면 Itr이라는 내부 클래스명으로 Iterator를 상속받고, 객체를 생성해서 돌려줍니다.

iterator()의 반환인 Iterator 인터페이스가 Collection 순회를 돕는 hasNext(), next(), remove()를 구현하도록 하고 있습니다.

 

Iterator를 상속했으니, Iterator it = list.iterator() 와 같이 사용합니다.

 

주의점

List는 저장 순서를 유지하기 때문에 iterator를 사용하면 저장 순서를 유지하며 요소를 확인할 수 있지만,

Set은 저장 순서를 유지하지 않기 때문에 저장 순서대로 요소를 확인할 수 없습니다.

 

인터페이스 구현 순서

  1. Iterable
  2. Collection
  3. List, Set
  4. ArrayList, LinkedList, HashSet, TreeSet 등

 

아래 사진은 ArrayList 내부에 Iterator를 반환하는 iterator() 함수의 작성 내용입니다.

 

ArrayList iterator()

iterator()의 직접적인 구현은 ArrayList, LinkedList, HashSet, TreeSet에 작성하는 걸 확인할 수 있습니다.

iterator() 함수를 호출하게 되면 Itr() 인스턴스를 생성하여 return합니다.

Itr은 내부 클래스로 Iterator 인터페이스의 추상 메서드 hasNext(), next(), remove() 를 모두 구현합니다.

Iterator의 메서드는 JAVA API에서 확인할 수 있습니다.

 

https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Iterator.html

 

Iterator (Java SE 15 & JDK 15)

Type Parameters: E - the type of elements returned by this iterator All Known Subinterfaces: EventIterator, ListIterator , PrimitiveIterator , PrimitiveIterator.OfDouble, PrimitiveIterator.OfInt, PrimitiveIterator.OfLong, XMLEventReader All Known Implement

docs.oracle.com

 

 


Iterator, ListIterator 사용법

 

Iterator의 구현도는 복잡하지만 실제 사용하려는 프로그래머 입장에서는 iterator의 사용은 아주 단순합니다.

주의할 점은 Iterator, ListIterator의 cursor 위치는 시작할 때 맨 앞 요소 그 앞에 있습니다.

cursor의 위치는 요소를 가리키고 있는 것이 아니라 요소와 요소 사이에 있다라고 생각하시면 됩니다.

 

 

Iterator의 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.*;
 
public class IteratorTest {
    public static void main(String[] args) {
        ArrayList<Integer> arr_list = new ArrayList<>();
        arr_list.add(1);
        arr_list.add(2);
        arr_list.add(3);
        arr_list.add(4);
 
        // Iterator
        Iterator<Integer> itr = arr_list.iterator();
 
        while(itr.hasNext()){
            int n = itr.next();
            System.out.print(n + " ");
            if(n == 2)
                itr.remove();
        }
        System.out.println();
        System.out.println(arr_list);
    }
}
cs

 

12줄) iterator() 함수는 Iterator 인터페이스 return으로 받을 수 있는 Iterator를 Type으로 선언하여 사용해주시면 됩니다.

14줄) hasNext() 함수는 다음 요소가 있다면 true, 없다면 false를 return 합니다. 마지막 요소까지 확인할 수 있습니다.

15줄) next() 함수는 cursor 위치를 오른쪽으로 옮긴 후 왼쪽 요소를 반환합니다. cursor 위치는 요소와 요소 사이입니다.

* cursor가 지나온 요소를 반환한다고 생각하시면 됩니다.

18줄) remove() 함수는 next() 함수의 반환 값을 삭제합니다. 실제 ArrayList에도 영향을 미칩니다.

 

결과

 

 

 

ListIterator의 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.*;
 
public class ListIteratorTest {
    public static void main(String[] args) {
        ArrayList<Integer> arr_list = new ArrayList<>();
        arr_list.add(1);
        arr_list.add(2);
        arr_list.add(3);
        arr_list.add(4);
 
        // ListIterator
        ListIterator<Integer> it = arr_list.listIterator();
        System.out.print(it.next()+ " ");
        System.out.print(it.next()+ " ");
        System.out.print(it.previous()+ " ");
 
        System.out.println();
        System.out.println(arr_list);
 
    }
}
cs

 

ListIterator는 Iterator와 사용방법이 비슷합니다. 대신 ListIterator는 이전 요소로 되돌아갈 수 있습니다.

 

13, 14줄) it.next()를 부르면 다음 요소로 넘어갑니다. 15줄) it.previous() 호출하면 이전 요소로 되돌아갈 수 있습니다.

이런 식으로 양방향으로 이동 가능한 것이 ListIterator의 특징입니다.

 

여기서 cursor의 위치가 요소와 요소 사이에 있다는 것을 출력을 통해 확인해볼 수 있습니다. 

13줄) next() 함수를 호출하면 결과는 1입니다. cursor는 1과 2 사이에 있으며 왼쪽 요소(1)를 반환합니다.

14줄) next() 함수를 한번 더 호출하면 결과가 2입니다. cursor는 2와 3 사이에 있으며 왼쪽 요소(2)를 반환합니다.

 

여기까지 코드를 실행하면 현재 cursor의 위치는 2와 3사이 입니다.

이제 15줄) previous() 함수를 호출하면 cursor가 왼쪽으로 이동하며 cursor의 위치는 1과 2 사이가 됩니다.

대신 반환 요소를 현재 위치에서 오른쪽의 있는 요소(2)를 반환합니다.

이렇듯 커서는 요소와 요소 사이에 있으며, cursor가 이동한 후, 지나온 요소를 반환한다고 생각하시면 됩니다.

 

결과

 

반응형

+ Recent posts