[Day 1]

자바의 장점

  1. 플랫폼 독립성: 플랫폼(Windows, Rinux, Mac 등)에 영향을 받지 않으므로 다양한 환경에서 사용 가능

  2. 객체 지향 언어이기 때문에 유지보수가 쉽고 확장성이 좋음

  3. 프로그램이 안정적이다

  4. 풍부한 기능을 제공하는 오픈소스다(JDK)

[Day 2]

음의 정수 표현

  • 양수의 2의 보수를 취한 후 1을 더하여 음수를 표현

[Day 4]

상수(final)

  • 변하지 않는 값
  • 한 번 값을 넣으면 다른 값을 대입할 수 없다

형 변환(type conversion)

  • 변수에 다른 자료형의 값이 대입되는 경우 형 변환 발생
  • 묵시적 형 변환

- 변환되는 자료형을 명시할 필요 없음

- 작은 수에서 큰 수로, 덜 정밀한 수(정수)에서 더 정밀한 수(실수)로 대입되는 경우

  • 명시적 형 변환

- 변환되는 자료형을 명시해야 하며 자료의 손실이 발생할 수 있다

- 큰 수에서 작은 수로, 더 정밀한 수에서 덜 정밀한 수로 대입되는 경우

  • 자료형 크기 비교

- 정수형: byte(1byte) < short(2byte) = char(2byte, 문자형) < int(4byte) < long(8byte)

- 실수형: float(4byte) < double(8byte)

[Day 5]

증가 감소 연산자

  • 1만큼 더하거나 1만큼 뺄 때 사용하는 연산자
  • 항의 앞/뒤 위치에 따라 연산의 결과가 달라짐에 주의
int val;
int num = 0;

val = ++num; //num 값이 1증가한 후 val 변수에 num값을 대입, val = 1, num = 1
val = num++; //val 변수에 num 값을 대입한 후 num 값이 1증가, val = 1, num = 2
val = --num; //num 값이 1감소한 후 val 변수에 num값을 대입, val = 1, num = 1
val = num--; //val 변수에 num 값을 대입한 후 num 값이 1감소, val = 1, num = 0

단락 회로 평가(short circuit evaluation)

  • 논리 연산자를 사용하는 연산에서 결과가 확정될 경우 뒤의 연산은 생략한다

- 논리 곱(&&)은 앞의 항이 false이면 뒤의 항의 결과를 평가하지 않아도 false이므로 생략

- 논리 합(   )은 앞의 항이 true이면 뒤 항의 결과를 평가하지 않아도 true이므로 생략

[Day 8]

객체지향 프로그래밍

위키백과-객체 지향 프로그래밍

- 컴퓨터 프로그래밍 패러다임 중 하나

- 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 객체 간의 상호작용으로 구상

객체지향 프로그래밍 구성요소

  • 클래스(Class)

- 한 집단의 속성(attribute)과 행위(behavior)를 정의한 것

- 객체지향 프로그램의 기본적인 사용자 정의 데이터형

- 각각의 클래스는 독립적으로 디자인해야 한다

  • 객체(Object)

- 클래스의 인스턴스(실제로 메모리상에 할당된 것)

- 고유의 속성(attribute)을 가지며 클래스에서 정의한 행위(behavior)를 수행할 수 있다

  • 메서드(Method)

- 객체에 명령을 내리는 메시지

- 객체 간의 통신에도 사용

객체지향 프로그래밍 특징

  • 추상화

- 불필요한 정보는 숨기고 중요한 정보만을 표현함으로써 프로그램을 간단히 만드는 것

- 캡슐화: 접근 제어를 통해서 자료의 세부 정보를 은닉, 인위적 변형으로 인한 오류 방지

위키백과-캡슐화

  • 상속

- 새로운 클래스가 기존 클래스의 속성과 메서드를 이용할 수 있게 한다

- 상속을 통해 프로그램의 요구에 맞추어 클래스를 수정할 수 있고 클래스 간의 종속 관계를 형성함으로써 객체를 조직화할 수 있다

  • 다형성

- 한 요소에 여러 개념을 넣어 놓는 것

- 오버라이딩: 같은 이름의 메소드가 여러 클래스에서 다른 기능을 하는 것

- 오버로딩: 같은 이름의 메소드가 매개변수나 자료형에 따라서 다른 기능을 하는 것

  • 동적 바인딩

- 필요할 때마다 동적으로 메모리를 생성하고, 필요 없는 메모리는 제거

- 작은 메모리로 큰 프로그램을 실행할 수 있지만, 정적 바인딩에 비해 프로그램 속도가 느리다

함수와 스택 메모리

  • 스택 메모리

- 함수가 호출될 때 사용하는 메모리

- 함수의 기능 수행이 끝나면 자동으로 반환

//함수 만들기
public class FunctionTest {
	public static void main(String[] args) {
		int num1 = 10;
		int num2 = 30;
		
		int sum = addNum(num1, num2);
		System.out.println(sum);
	}
	
	public static int addNum(int n1, int n2) {
		int result = n1 + n2;
		return result;
	}
}

image-20220803085219093

[Day 9]

인스턴스와 힙(heap) 메모리

  • 인스턴스

- 클래스가 메모리에 생성된 것

- 하나의 클래스 코드에서 여러 개의 인스턴스를 생성

- 힙(heap) 메모리에 생성됨

- 각 인스턴스는 메모리에 개별적으로 생성됨

image-20220804083414390

  • 힙 메모리

- new 예약어를 통해 메모리 생성

- garbage collecter를 통해 메모리 제거

참조 변수와 참조 값

  • 참조 변수: 인스턴스 생성 시 선언하는 변수
  • 참조 값: 인스턴스가 생성되는 힙 메모리 주소
Student student = new Student(); //student가 참조 변수
System.out.println(student); //힙 메모리의 주소 값 반환(참조 값)

용어 정리

  • 객체 - 객체 지향 프로그램의 대상, 클래스의 인스턴스
  • 클래스 - 한 집단의 속성과 행위를 정의한 것
  • 인스턴스 - 클래스가 메모리에 생성된 것
  • 멤버 변수 - 클래스의 속성
  • 메서드 - 객체에 명령을 내리는 메시지
  • 참조 변수 - 인스턴스 생성 시 선언하는 변수
  • 참조 값 - 인스턴스가 생성되는 힙 메모리 주소

생성자

  • 인스턴스를 초기화하는 명령어 집합
  • 생성자의 이름은 클래스의 이름과 같다
  • 메소드가 아니므로 상속되지 않으며 리턴 값이 없다

  • 생성자를 아예 만들지 않으면 디폴트 생성자 자동 생성

[Day 10]

기본 자료형과 참조 자료형

기본자료형 & 참조자료형

기본 자료형(primitive data type)

  • 자바 컴파일러에 의해 해석되는 자료형
  • 스택(Stack) 메모리에 저장
  • 사용하기 전에 반드시 선언(Declared)되어야 함

  • 8가지를 미리 정의하고 제공
  • OS(운영체제)에 따라 자료형의 길이가 변하지 않는다
  • 비객체 타입이므로 null 값을 가질 수 없다. 만약 null을 넣고 싶다면 Wrapper Class를 활용해야 한다.

img

참조 자료형 (reference data type)

  • 기본형을 제외한 모든 자료형
  • JAVA 최상위 클래스인 Object 클래스를 상속
  • 클래스 타입(class type), 인터페이스 타입(interface type), 배열 타입(array type), 열거 타입(enum type) 등 이 있다
  • 빈 객체를 의미하는 Null이 존재
  • 문법상으로는 에러가 없지만 실행시켰을 때 에러가 나는 런타임 에러가 발생
    • 예) 객체나 배열을 Null 값으로 받으면 NullPointException이 발생하므로 변수 값을 넣어야 한다.
  • Heap 영역에 생성

정보은닉

private 접근 제어자

  • 클래스의 외부에서 내부의 멤버 변수나 메서드에 접근하지 못하게 한다
  • 멤버 변수나 메서드를 외부에서 수정하지 못하도록 하여 오류를 줄일 수 있음
  • 필요한 경우 get(), set() 메서드를 통해 값을 변경하도록 할 수 있음

[Day 12]

static 변수

//사용 형식: static 자료형 변수명
static int num;
  • 여러 개의 인스턴스가 같은 메모리의 값을 공유하기 위해 사용

  • 프로그램이 메모리에 적재(load)될 때 데이터 영역의 메모리에 생성(인스턴스가 생성될 때x, heap영역 x)
  • 클래스 변수라고도 한다
  • 인스턴스 생성과 관계없이 클래스 이름으로 직접 참조
//static변수
Student.serialNum = 100; //serialNum이 static변수

//멤버변수(인스턴스변수)
Student stu = new Student();
stu.serialNum = 100;

static변수 vs 인스턴스 변수

image-20220804082852128

Tip.스태틱 메서드 안에서는 멤버 변수를 사용할 수 없다

public class Student {
	static int serialNum = 10000;
	int studentID;
	
	public static int getSerialNum() {
		this.studentID = 10; //static메서드 안에서는 멤버 변수 사용 불가능
		return serialNum;
	}
}

3. 변수의 유효 범위

지역 변수(로컬 변수)

  • 선언 위치: 함수 내부에 선언
  • 사용 범위: 함수 내부에서만 사용
  • 메모리: 스택
  • 생성과 소멸: 함수가 호출될 때 생성, 함수 동작 완료 후 소멸

멤버 변수(인스턴스 변수)

  • 선언 위치: 클래스 내부에 선언
  • 사용 범위: 클래스 내부에서 사용, private이 아니면 참조 변수로 다른 클래스에서 사용 가능
  • 메모리: 힙
  • 생성과 소멸: 인스턴스가 생성될 때 힙에 생성, 가비지 컬렉터에 의해 소멸

static 변수(클래스 변수)

  • 선언 위치: static 예약어를 사용해 클래스 내부에 선언
  • 사용 범위: 클래스 내부에서 사용, priavate이 아니면 클래스 이름으로 다른 클래스에서 사용 가능
  • 메모리: 데이터 영역
  • 생성과 소멸: 프로그램이 시작할 때 상수와 함께 데이터 영역에 생성, 프로그램이 끝나고 메모리를 해제할 때 소멸

static응용: singleton 패턴

  • 인스턴스를 하나만 만들어야 하는 경우에 사용!
public class Company {
	//내부에서 인스턴스 생성
	private static Company instance = new Company();
	
	//외부에서 생성자를 사용하지 못하게 한다
	private Company() {};
	
	//내부에서 생성한 인스턴스를 외부에서 사용할 수 있도록 해주는 메서드
	public static Company getInstance() {
		return instance;
	}
}
public class CompanyTest {
	public static void main(String[] args) {
		Company c1 = Company.getInstance();
		Company c2 = Company.getInstance();
		
		System.out.println(c1==c2);//true => 같은 인스턴스를 가르킨다
	}
}

[Day 17]

접근 제어자(Access Modifier, 접근 제한자, 접근 지정자)

  • 변수나 메소드의 사용 권한을 설정
  • private: 클래스 내에서만 사용 가능 => 클래스
  • default: 같은 패키지의 클래스에서만 사용 가능 => 패키지
  • protected: 같은 패키지 혹은 상속 받은 클래스만 사용 가능 => 패키지 + 상속
  • public: 모든 클래스에서 사용 가능 => 모든

상속에서 클래스 생성 과정

  • 하위 클래스의 인스턴스가 생성될 때 상위 클래스의 인스턴스가 먼저 생성된다
  • 상위 클래스의 생성자가 호출된 후 하위 클래스의 생성자가 호출된다
  • 하위 클래스의 생성자에서는 무조건 상위 클래스의 생성자가 호출되어야 한다

=> 따로 구현하지 않으면 컴파일러가 상위 클래스의 기본 생성자를 호출하는 super()를 넣어준다

  • 만약 상위 클래스에 기본생성자가 없을 경우 하위 클래스는 명시적으로 상위 클래스를 호출해야 한다

super 예약어

  • 하위 클래스가 상위 클래스에 접근할 때 사용

  • this가 자기 자신의 인스턴스 주소를 가지는 것처럼 super는 하위 클래스가 상위 클래스에 대한 주소를 가진다

캐스팅(Casting, 형변환)

  • 타입을 변환하는 것
  • 자바의 상속 관계에 있는 부모와 자식 클래스 간에는 서로 간의 형변환이 가능

업캐스팅

  • 자식 클래스의 객체가 부모 클래스 타입으로 형변환 되는 것
  • 묵시적 형 변환(타입을 명시하지 않아도 됨)
  • 부모 클래스의 멤버 변수와 메서드만 사용 가능

다운캐스팅

  • 업캐스팅된 것을 다시 원상태로 돌리는 것

  • 다운캐스팅할 때는 타입을 명시적으로 지정해줘야 한다

//부모 클래스
class Person{
	String name;
	Person(String name){
		this.name = name;
	}
}

//자식 클래스
class Student extends Person{
	String check;
	Student(String name){
		super(name);
	}
}

public class Main{
	public static void main(String[] args){
		Person p = new Student("홍길동"); //업캐스팅
        p.check = "컴파일 에러 발생";	// 컴파일 에러 발생
        
		Student s = (Student)p;	// 다운캐스팅
		s.name = "김유신";
		s.check = "check!";
	}
}

가상 메서드(virtual method)

  • 객체의 변수나 메서드의 참조는 그 타입에 따라 이루어 지지만, 가상 메서드는 타입과 상관없이 실제 생성된 인스턴스의 메서드가 호출된다

  • 자바는 모든 메서드가 가상 메서드이다

Customer vc = new VIPCustomer(); //Customer타입의 VIPCustomer인스턴스 생성
vc.calcPrice(10000); //메서드 실행 시 
// 메서드가 재정의 되지 않았으면 타입(Customer)의 메서드가 실행된다
// 메서드가 재정의 되었으면 인스턴스(VIPCustomer)의 메서드가 실행된다

Tip. 업캐스팅한 경우

  • 자식 클래스에만 정의된 멤버 변수, 메서드는 사용 불가
  • 자식 클래스에서 오버라이드한 메서드는 자식 클래스의 메서드가 사용됨

[Day 19]

추상 클래스

  • 추상 메서드를 포함한 클래스
  • 추상 메서드는 구현코드 없이 메서드의 선언만 있음
abstract in add(int x, int y); //추상 메서드 O
abstract in add(int x, int y) { }; //구현부({ })가 있으면 추상 메서드 X
  • abstract 예약어 사용
  • 추상 클래스는 인스턴스화(new)할 수 없음

구상 클래스

  • 클래스내의 메소드가 모두 구현된 클래스
  • 인스턴스화(new)할 수 있음

[Day 20]

템플릿 메서드 패턴

  • java 디자인 패턴 중 하나
  • 일부분을 서브 클래스로 캡슐화해 전체 업무 구조는 바꾸지 않으면서 특정 단계의 동작만을 바꾸는 패턴
  • 추상 클래스와 구상 클래스를 활용해 기능의 흐름을 정의한다
  • 추상 클래스로 선언된 상위 클래스에서 템플릿 메서드를 활용하여 전체적인 흐름을 정의한다

​ -> 하위 클래스에서 구현되어야 하는 부분은 추상 메서드로 선언

​ -> 공통으로 사용하는 기능은 일반 메서드로 선언(하위 클래스에서 재정의 하면 안되는 경우 final로 선언)

  • 프레임워크에서 많이 사용되는 설계 패턴

템플릿 메서드 패턴 참고

템플릿 메서드 패턴 참고2

후크(Hook) 메서드

  • 추상 클래스에서 빈 구현부로 정의된 메서드
  • 하위 클래스에서 선택적으로 오버라이드해서 사용할 수 있음

Tip. final예약어

  • final 변수는 오직 한 번만 값을 할당할 수 있다.
  • final 메서드는 하위 클래스에서 오버라이딩할 수 없다
  • final 클래스는 상속되지 않는다

[Day 21]

인터페이스

  • 비슷한 목적의 서로 다른 동작을 가지는 클래스들을 구현할 때 틀을 제공하는 일종의 추상 클래스
  • 추상 메서드와 상수 만으로 이루어진다(일반적인 추상 클래스는 생성자, 필드, 일반 메서드 포함 가능)
public interface Calc {
	//상수( public static final이 자동으로 붙어 상수가 됨)
	double PI = 3.14;
	int ERROR = -999999999;
	
	//추상 메서드(public abstract가 자동으로 붙어 추상 메서드가 됨)
	int add(int num1, int num2);
	int substract(int num1, int num2);
}
  • 인터페이스를 구현(implements)한 클래스는 인터페이스 형으로 형 변환할 수 있음

-> 이 경우 인터페이스에 선언한 메서드만 사용 가능, 구현 클래스에서 따로 선언한 메서드는 사용 불가(업 캐스팅과 동일)

  • 여러 인터페이스 구현 가능(자바의 단일 상속과 다름)

자바의 다중 상속 금지 이유와 인터페이스를 통한 보완

인터페이스의 장점

  • 대규모 프로젝트 개발 시 일관되고 정형화된 개발을 위한 표준화가 가능
  • 클래스의 작성과 인터페이스의 구현을 동시에 진행할 수 있으므로, 개발 시간 단축
  • 클래스와 클래스 간의 관계를 인터페이스로 연결하면, 클래스마다 독립적인 프로그래밍이 가능

Tip. 인터페이스와 추상 클래스는 인스턴스 생성 불가

[Day 23]

디폴트 메서드

  • 인터페이스에서 기본 구현을 가지는 메서드
  • 공통으로 사용하는 메서드를 구현
  • 구현 클래스에서 재정의 가능

인터페이스 상속

  • 인터페이스 간에도 상속이 가능
  • 구현 코드의 상속이 아니므로 형 상속(type inheritance)라고 한다

  • 구현 시 상속 받은 상위 인터페이스의 추상 메서드도 모두 구현해야 한다

  • 예시
public interface X {
	void x();
}
public interface Y {
	void y();
}
//인터페이스 상속
public interface MyInterface extends X, Y {
	void myMethod();
}
public class MyClass implements X, Y, MyInterface {

	@Override
	public void y() {
		System.out.println("y()");
	}

	@Override
	public void x() {
		System.out.println("x()");
	}
	
	@Override
	public void myMethod() {
		System.out.println("myMethod()");
	}
	
	public static void main(String[] args) {
		MyClass myClass = new MyClass();
		//전부 사용 가능
		myClass.x();
		myClass.y();
		myClass.myMethod();
		
		X xClass = myClass; //X 인터페이스로 형변환
		xClass.x(); //사용 가능
		//xClass.y(); //사용 불가
		//xClass.myMethod(); //사용 불가
	}
}
  • 클래스를 상속 받으면서 동시에 인터페이스 구현도 가능하다

  • 예시

public interface Queue {
	void enQueue(String title);
	String deQueue();
	int getSize();
}
import java.util.ArrayList;

public class Shelf {
	protected ArrayList<String> shelf;
	
	public Shelf() {
		shelf = new ArrayList<String>();
	}
	
	public ArrayList<String> getShelf(){
		return shelf;
	}
	
	public int getCount() {
		return shelf.size();
	}
}
public class BookShelf extends Shelf implements Queue {

	@Override
	public void enQueue(String title) {
		shelf.add(title);
	}

	@Override
	public String deQueue() {
		return shelf.remove(0);
	}

	@Override
	public int getSize() {
		return getCount();
	}
	
}
public class BookShelfTest {
	public static void main(String[] args) {
		Queue shelfQueue = new BookShelf();
		shelfQueue.enQueue("도서1");
		shelfQueue.enQueue("도서2");
		shelfQueue.enQueue("도서3");
		
		System.out.println(shelfQueue.deQueue());
		System.out.println(shelfQueue.deQueue());
		System.out.println(shelfQueue.deQueue());
	}
}

[Day 24]

기본 클래스

java.lang 패키지

  • 많이 사용하는 기본 클래스들이 속한 패키지(Object, String, Integer, System 등)

  • 프로그래밍시 import하지 않아도 자동으로 import됨

Object 클래스

  • 모든 클래스의 최상위 클래스
  • 모든 클래스는 Object 클래스를 상속 받는다(컴파일러가 자동으로 상속 시킴)
  • java.lang.Object 경로

toString() 메서드

  • 객체의 정보를 String으로 바꿀 때 사용
  • String 클래스 => 문자열 반환
  • Integer 클래스 => 정수 값 반환

equals() 메서드

  • 두 인스턴스의 주소 값을 비교하여 true/false 반환
  • 재정의하여 두 인스턴스가 논리적으로 동일한지 판단하도록 하기도 한다

hashCode() 메서드

  • 자바 가상 머신이 저장한 인스턴스 주소 값을 10진수로 나타낸다
  • 자료의 특정 값(키 값)에 대해 저장 위치를 반환해주는 해시 함수를 사용한다
[저장 위치] = hash.([ ]);
index = hash.(key);
  • 힙 메모리에 인스턴스가 저장되는 방식이 해시이다

서로 다른 메모리의 인스턴스가 같다면? (equals 재정의)

  • 재정의 된 equals() 메서드의 값이 true가 나와야 함
  • 동일한 hashCode() 반환 값을 가져야 함

=> 논리적 동일함을 위해 equals() 메서드를 재정의 하였다면 hashCode() 메서드도 재정의하여 같은 값이 반환되도록 한다

  • String 클래스: 동일한 문자열 인스턴스에 대해 동일한 값이 반환된다
  • Integer 클래스: 동일한 정수 값 인스턴스에 대해 동일한 값이 반환된다

  • 예시
class Student {
	int studentID;
	String studentName;
	
	public Student(int studentID, String studentName) {
		this.studentID = studentID;
		this.studentName = studentName;
	}

	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Student) {
			Student std = (Student)obj; //매개변수를 Object 타입으로 받으므로 다운 캐스팅
			if(studentID == std.studentID) 
				return true;
			else
				return false;
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		return studentID;// 대부분 equals 재정의 할 때 이용했던 멤버변수 값 사용 
	}
}

public class EqualsTest {
		public static void main(String[] args) {
			Student std1 = new Student(10001, "Tomas");
			Student std2 = new Student(10001, "Tomas");
			
			System.out.println(std1 == std2); //인스턴스 주소가 다르므로 false
			System.out.println(std1.equals(std2)); //studentID값이 같으므로 true
			System.out.println(std1.hashCode() == std2.hashCode()); //같은 주소 값을 반환하여 true
		}
}

clone() 메서드

  • 객체의 원본 유지하고 복사본을 만들어 사용할 때 사용하는 메서드
  • 기본 틀(prototype)을 두고 복잡한 생성과정을 반복하지 않고 복제
  • clone() 메서드를 사용하면 객체의 정보(멤버변수 값)가 같은 인스턴스가 생성되어 객체 지향 프로그램의 정보은닉, 객체보호 관점에 위배될 수 있다

=> 객체의 clone() 메서드 사용을 허용한다는 의미로 cloneable 인터페이스를 명시해 준다

class Point {
	int x;
	int y;
	
	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	public String toString() {
		return "x=" + x + ", " + "y=" + y;
	}
}

class Circle implements Cloneable{
	Point point;
	private int radius;
	
	public Circle(int x, int y, int radius) {
		point = new Point(x, y);
		this.radius = radius;
	}
	
	public String toString() {
		return "원점은 " + this.point + "이고, 반지름은 " + radius + "입니다";
		//this.point하면 point 멤버변수의 타입 클래스의 toString을 실행
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}

public class ObjectCloneTest {
	public static void main(String[] args) throws CloneNotSupportedException {
		Circle circle = new Circle(10, 20, 5);
		Circle cloneCircle = (Circle)circle.clone();
		
		//서로 다른 해시코드 값을 가진 인스턴스가 확인된다
		System.out.println(System.identityHashCode(circle));
		System.out.println(System.identityHashCode(cloneCircle));
		
		System.out.println(circle.toString()); // 원점은 x=10, y=20이고, 반지름은 5입니다
	}
}

[Day 25]

String 클래스

선언 방법

  1. 힙 메모리의 인스턴스로 선언
String str = new String("abc");
  1. 상수 풀에 있는 주소를 참조하여 선언
String str = "abc";

String 클래스로 문자열 연결

  • 한 번 생성된 String 값(문자열)은 불변(immutable)
  • 두 개의 String 값을 연결하면 새로운 인스턴스가 생성된다

=> 문자열 연결을 계속하면 garbage 메모리가 많이 생길 수 있다

=> 문자열을 자주 연결하고나 변경할 때는 StringBuilder, StringBuffer 사용하면 좋다

public class StringTest {
	public static void main(String[] args) {
		String str1 = new String("Hello");
		int instance1 = System.identityHashCode(str1);
		String str2 = new String("World");
		
		str1 = str1.concat(str2); //기존 인스턴스의 값을 바꾸는 것이 아닌 새로운 인스턴스 생성
		int instance2 = System.identityHashCode(str1);
		
		System.out.println(instance1 == instance2); //false 출력
	}
}

StringBuilder, StringBuffer 사용하기

  • 내부적으로 가변적인 char[] 배열을 가지고 있는 클래스
  • 문자열을 자주 연결하고나 변경할 때 사용하면 유용하다
  • 매번 인스턴스를 새로 생성하지 않고 기존 배열을 변경하여 garbage 메모리 생성 감소
  • StringBuffer는 멀티 쓰레드 프로그래밍에서 동기화(sybchronization)를 보장
  • 단일 쓰레드 프로그램에서는 StringBuilder 사용을 권장
  • toString 메서드로 String 반환

  • StringBuilder 예시
public class StringBuilderTest {
	public static void main(String[] args) {
		StringBuilder buffer = new StringBuilder("java");
		int instanceHash1 = System.identityHashCode(buffer);
		
		buffer.append(" and");
		buffer.append(" android");
		int instanceHash2 = System.identityHashCode(buffer);
		
		//계속해서 같은 인스턴스 사용
		System.out.println(instanceHash1 == instanceHash2); //true
		
		//String으로 출력하기
		String str2 = buffer.toString();
		System.out.println(str2); //java and android
	}
}

[Day 26]

제네릭 클래스

  • 변수의 선언, 메서드의 매개변수를 하나의 참조 자료형이 아닌 여러 자료형으로 변환될 수 있도록 프로그래밍하는 것
  • 실제 사용되는 참조 자료형으로의 변환은 컴파일러가 검증하므로 안정적인 프로그래밍 방식
  • 컬렉션 프레임워크에서 많이 사용
  • 여러 참조 자료형으로 대체될 수 있는 부분(매개 변수)을 하나의 문자로 표현

  • 예시
public abstract class Material {
	public abstract void doPrinting();
}
//<T extends Material>을 통해 Material 클래스를 상속한 클래스만 제네릭 타입에 입력 가능하도록 제한
public class ThreeDPrinter<T extends Material> { 
	private T material;

	public T getMaterial() {
		return material;
	}

	public void setMaterial(T material) {
		this.material = material;
	}

	@Override
	public String toString() {
		return material.toString();
	}
	
	public void printing() {
		material.doPrinting();
	}
}
public class Plastic extends Material {
	public String toString() {
		return "재료는 Plastic입니다.";
	}

	@Override
	public void doPrinting() {
		System.out.println("Plastic재료로 출력 중입니다.");
	}
}
public class Powder extends Material {
	public String toString() {
		return "재료는 Powder입니다.";
	}

	@Override
	public void doPrinting() {
		System.out.println("Powder재료로 출력 중입니다.");
	}
}
public class Water {
	public String toString() {
		return "재료는 Water입니다.";
	}
}
public class ThreeDPrinterTest {

	public static void main(String[] args) {
		ThreeDPrinter<Powder> printer = new ThreeDPrinter<Powder>();
		printer.setMaterial(new Powder());
		Powder powder = printer.getMaterial();
		System.out.println(printer); //재료는 Powder입니다.
		
		ThreeDPrinter<Plastic> plasticPrinter = new ThreeDPrinter<Plastic>();
		plasticPrinter.setMaterial(new Plastic());
		Plastic plastic = plasticPrinter.getMaterial();
		System.out.println(plasticPrinter); //재료는 Plastic입니다.
		
		// Water 클래스가 Material 클래스를 상속하지 않아 사용 불가
		/*
		ThreeDPrinter<Water> waterPrinter = new ThreeDPrinter<Water>();
		waterPrinter.setMaterial(new Water());
		System.out.println(waterPrinter); //재료는 Water입니다.
		*/
		
		plasticPrinter.printing(); //Plastic재료로 출력 중입니다.
	}

}

자료형 매개변수 T

  • type의 의미로 T를 많이 사용한다
  • 에서 <>는 다이아몬드 연산자라고 한다
  • static 키워드는 T에 사용할 수 없다
  • 다이아몬드 연산자 내부에서 자료형은 생략 가능
ArrayList<String> list = new ArrayList<>();

[Day 28]

컬렉션 프레임워크

  • 데이터를 저장하는 자료 구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현해 놓은 것
  • 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 방법을 제공하는 클래스의 집합
  • java.util 패키지에 구현되어 있다

컬렉션 인터페이스

  • 컬렉션을 다루는데 가장 기본적인 동작들을 정의하고 관련 메소드를 제공
  • 하위에 List와 Set 인터페이스가 있다
  • 여러 클래스들이 Collection 인터페이스를 구현한다

List 인터페이스

  • 순서(인덱스)가 있음
  • 중복 허용
  • 배열의 기능을 구현하기 위한 인터페이스
  • ArrayList, Vector, LinkedList, Stack, Queue 등이 구현

Set 인터페이스

  • 순서가 정해져 있지 않음
  • 중복을 허용하지 않음
  • HashSet, TreeSet 등이 구현

[Day 30]

내부 클래스

  • 클래스 내부에 선언된 클래스

자바-내부클래스

내부 클래스의 장점

  • 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있다
  • 코드의 복잡성을 줄일 수 있다

인스턴스 내부 클래스

  • 구현 위치: 외부 클래스의 멤버 변수 위치
  • 사용 가능한 외부 클래스 변수: 인스턴스 변수, 전역 변수
  • 객체 생성 방법: 외부 클래스를 먼저 만든 후 내부 클래스 생성
  • 정적 변수, 정적 메서드 사용 불가

정적 내부 클래스

  • 구현 위치: 외부 클래스의 멤버 변수 위치
  • 사용 가능한 외부 클래스 변수: 전역 변수(인스턴스 변수 사용 불가)
  • 객체 생성 방법: 외부 클래스와 무관하게 생성

지역 내부 클래스

  • 구현 위치: 메서드 내부
  • 사용 가능한 외부 클래스 변수: 인스턴스 변수, 역 변수
  • 객체 생성 방법: 메서드 호출

익명 내부 클래스

  • 구현 위치: 메서드 내부, 변수에 대입하여 직접 구현
  • 사용 가능한 외부 클래스 변수: 인스턴스 변수, 전역 변수
  • 객체 생성 방법: 메서드 호출 / 인터페이스 타입 변수에 대입할 때 new 예약어를 사용

Tip. 클래스 변수(Static 멤버)

  • 클래스 내에 Static 키워드로 선언된 변수
  • 처음 JVM이 실행되어 클래스가 메모리에 올라갈 때부터 프로그램이 종료될 때까지 유지
  • 클래스가 여러 번 생성되어도 Static 변수는 처음 한 번만 생성됨
  • 동일한 클래스의 모든 객체가 공유

Tip. 인스턴스 변수(Non-static 멤버)

  • 클래스 내에 선언된 변수
  • 객체 생성 시마다 매번 새로운 변수가 생성됨
  • 클래스 변수와 달리 공유되지 않음

인스턴스 내부 클래스, 정적 내부 클래스 예시

class OutClass{
	
	private int num = 10;
	private static int sNum = 20;
	private InClass inClass;
	
	public OutClass(){
		inClass = new InClass();
	}
	
	//인스턴스 내부 클래스
	private class InClass{
		int inNum = 200;
		//static int sInNum = 100; //인스턴스 내부 클래스에서는 정적 변수 사용 불가능
		
		void inTest() {
			System.out.println(num);
			System.out.println(sNum);
		}
		
		//인스턴스 내부 클래스에서는 정적 메서드 사용 불가능
		//static void sTest() { }
	}
	
	public void usingInTest() {
		inClass.inTest();
	}
	
	//정적 내부 클래스
	static class InStaticClass{
		int iNum = 100;
		static int sInNum = 200;
		
		void inTest() {
			//num += 10; //외부 클래스의 인스턴스 변수 사용 불가
			sNum += 10; //외부 클래스의 정적 변수는 사용 가능
			System.out.println(sNum);
			System.out.println(iNum);
			System.out.println(sInNum);
		}
		
		static void sTest() {
			System.out.println(sNum);
			//System.out.println(iNum); //정적 메서드는 인스턴스 변수 사용 불가
			System.out.println(sInNum);
		}
	}
}

public class InnerTest {
	public static void main(String[] args) {
		OutClass outClass = new OutClass();
		outClass.usingInTest();
		
		OutClass.InStaticClass sInClass = new OutClass.InStaticClass();
		sInClass.inTest();
		OutClass.InStaticClass.sTest();
	}
}

지역 내부 클래스 예시

class Outer{
	int outNum = 100;
	static int sNum = 200;
	
	public Runnable getRunnable(){
		
		int localNum = 100;
		
		//지역 내부 클래스
		class MyRunnable implements Runnable {
			@Override
			public void run() {
				outNum += 100; //인스턴스 변수는 수정 가능
				//localNum += 100; //지역 변수는 수정 불가(지역 변수는 상수가 된다)
				
				System.out.println(outNum);
				System.out.println(sNum);
				System.out.println(localNum); //지역 변수 사용은 가능
			}
		}
		
		return new MyRunnable();
	}
}

public class LocalInnerTest {
	public static void main(String[] args) {
		Outer outer = new Outer();
		outer.getRunnable().run();
	}
}

익명 내부 클래스 예시

  • 익명 내부 클래스는 추상메서드가 하나만 정의된 경우에만 사용 가능
class Outer{
	//익명 내부 클래스
	Runnable runnable = new Runnable() {
		@Override
		public void run() {
			System.out.println("runnable");
		}
	};
}

public class LocalInnerTest {
	public static void main(String[] args) {
		Outer outer = new Outer();
		outer.runnable.run();
	}
}

[Day 31]

람다식(lambda expression)

  • 자바에서 함수형 프로그래밍을 구현하는 방식
  • 자바8부터 지원
  • 클래스를 생성하지 않고 함수의 호출만으로 기능을 수행

함수형 프로그래밍

함수형 프로그래밍 참고

  • 순수 함수: 동일한 입력에는 항상 같은 값을 반환, 함수의 실행이 프로그램 실행에 영향을 미치지 않음
  • 불변성: 데이터는 변하지 않는다. 변경이 필요한 경우 원본 데이터의 복사본을 만들어서 작업한다

람다식 구현하기

  • 메서드 만들기
  • 함수 이름 반환 형을 없애고 화살표(->) 사용
  • 매개변수가 하나인 경우 자료형과 괄호 생략하기
  • 구현부가 한 문장인 경우 중괄호 생략(retrun이 있으면 return까지 생략)
//원래 메서드
int add(int x, int y){
	retrun x + y;
}

//함수 이름 반환 형을 없애고 화살표(->) 사용
(int x, int y) -> {return x + y;}

//구현부가 한 문장인 경우 중괄호 생략
(int x, int y) -> x + y;

함수형 인터페이스

  • 추상 메서드가 하나만 있는 인터페이스(다른 메서드는 있어도 됨)
  • @FunctionalInterface를 통해 함수형 인터페이스를 표시/검증할 수 있음
  • 람다식을 선언하기 위해 사용

  • 예시
@FunctionalInterface //함수형 인터페이스(추상 메서드를 하나만 가진다!)
public interface MyNumber {
	int getMaxNumber(int num1, int num2);
}

함수를 변수처럼 사용하는 람다식 예시

//함수형 인터페이스
interface PrintString{
	void showString(String str);
}

public class LambdaTest {
	public static void main(String[] args) {
        //일반적인 람다식
		PrintString lambdaPrint = str -> System.out.println(str);
		lambdaPrint.showString("test"); //test
		
        //람다식으로 구현한 함수 자체가 매개변수로 넘어간다
		showMyString(lambdaPrint); //test2 
		
        //구현부를 리턴한다
		PrintString reStr = returnPrint();
		reStr.showString("hello");//hello world 
	}
	
    //람다식으로 구현한 함수 자체가 매개변수로 넘어간다
	public static void showMyString(PrintString lambda) {
		lambda.showString("test2");
	}
	
    //구현부를 리턴한다
	public static PrintString returnPrint() {
		return s -> System.out.println(s + " world");
	}
}

[Day 32]

스트림(stream) API

스트림 API 참고

자료의 대상과 관계 없이 동일한 연산을 수행

  • 배열, 컬렉션을 대상으로 동일한 연산을 수행 함
  • 일관성 있는 연산으로 자료의 처리를 쉽고 간단하게 함

한 번 생성하고 사용한 스트림은 재사용 할 수 없음

  • 자료에 대한 스트림을 생성하여 연산을 수행하면 스트림은 소모됨
  • 다른 연산을 위해서는 새로운 스트림을 생성해야 함

스트림 연산을 기존 자료를 변경하지 않음

  • 자료에 대한 스트림을 생성하면 별도의 메모리 공간을 사용하므로 기존 자료를 변경하지 않음

스트림 연산은 중간 연산과 최종 연산으로 구분됨

  • 스트림에 대해 중간 연산은 여러 개 적용될 수 있지만 최종 연산은 마치막에 한 번만 적용됨
  • 최종 연산이 호출되어야 중간 연산의 결과가 모두 적용됨 => 지연 연산

reduce() 연산

  • 정의된 연산이 아닌 프로그래머가 직접 지정하는 연산을 적용

  • 최종 연산으로 스트림의 요소를 소모하며 연산 수행

  • 예시: reduce로 가장 긴 문자열 반환하기

    import java.util.Arrays;
    import java.util.function.BinaryOperator;
      
    class CompareString implements BinaryOperator<String>{
    	@Override
    	public String apply(String s1, String s2) {
    		if(s1.getBytes().length >= s2.getBytes().length)
    			return s1;
    		else return s2;
    	}
    }
      
    public class ReduceTest {
    	public static void main(String[] args) {
    		String[] greeting = {"안녕하세요~~~~~~~~", "hello", "Good Moring", "반갑습니다"};
      		
    		//구현부를 만들어서 사용하기
    		String str1 = Arrays.stream(greeting).reduce("", (s1, s2) ->{
    			if(s1.getBytes().length >= s2.getBytes().length)
    				return s1;
    			else return s2;
    		});
    		System.out.println(str1);//안녕하세요~~~~~~~~
      		
    		//BinaryOperator로 구현부 만들기
    		String str2 = Arrays.stream(greeting).reduce(new CompareString()).get();
    		System.out.println(str2);//안녕하세요~~~~~~~~
    	}
    }
    

[Day 33]

예외 처리

오류란?

  • 컴파일 오류: 코드 작성 중 발생하는 문법적 오류
  • 실행 오류: 프로그램이 의도하지 않은 동작을 하거나 중지되는 서비스 운영에 치명적인 오류
  • 자바는 예외 처리를 통해 프로그램의 비정상 종료를 막고 log를 남길 수 있음

오류와 예외 클래스

  • 시스템 오류(Error): 가상 머신에서 발생, 프로그래머가 처리할 수 없음

ex) 동적 메모리가 없는 경우, 스택 오버 플로우 등

  • 예외(Exception): 프로그램에서 제어할 수 있는 오류

ex) 읽어 들이려는 파일이 존재하지 않는 경우, 네트워크 연결이 끊어진 경우

예외 클래스의 종류

  • 모든 예외 클래스의 최상위 클래스는 Exception
  • 다양한 예외 클래스가 제공됨

try-with-resources문

  • 리소스를 자동 해제하도록 제공해주는 구문
  • 자바 7부터 제공
  • close()를 명시적으로 호출하지 않아도 try{} 블록에서 열린 리소스는 모두 자동 해제됨
  • 단, 해당 리소스가 AutoCloseable을 구현해야 함
public class AutoCloaseObj implements AutoCloseable {
	@Override
	public void close() throws Exception {
		System.out.println("close()");
	}
}
public class AutoCloseTest {
	public static void main(String[] args) {
		try(AutoCloaseObj obj = new AutoCloaseObj()){
			throw new Exception(); //강제로 예외 처리
		} catch (Exception e) {
			System.out.println("exection");
		}
	}
}

/* 결과
close()
exection
*/

사용자 정의 예외

  • JDK에서 제공되는 예외 클래스 외에 사용자가 필요에 의해 예외 클래스를 정의하여 사용
  • 기존 JDK 예외 클래스 중 가장 유사한 클래스에서 상속
  • 기본적으로 Exception에서 상속 가능
public class IDFormatException extends Exception {
	public IDFormatException (String message) {
		super(message);
	}
}
public class IDFormatTest {
	private String userID;
	
	public String getUserID() {
		return userID;
	}

	public void setUserID(String userID) throws IDFormatException {
		if(userID == null) {
			throw new IDFormatException("아이디는 null일 수 없습니다.");
		} else if(userID.length() < 8 || userID.length() > 20) {
			throw new IDFormatException("아이디는 8자 이상 20자 이하로 쓰세요.");
		}
		this.userID = userID;
	}

	public static void main(String[] args) {
		IDFormatTest idTest = new IDFormatTest();
		String userID = null;
		
		try {
			idTest.setUserID(userID);
		} catch (IDFormatException e) {
			System.out.println(e); //exception.IDFormatException: 아이디는 null일 수 없습니다.
		}
		
		userID = "1234567";
		try {
			idTest.setUserID(userID);
		} catch (IDFormatException e) {
			System.out.println(e); //exception.IDFormatException: 아이디는 8자 이상 20자 이하로 쓰세요.
		}		
	}
}

[Day 34]

자바 입출력

스트림(stream)

  • 자바에서 자료의 입출력(I/O)을 처리하는 통로
  • 자료의 흐름이 물과 같다는 의미에서 유래
  • 단방향 통신만 가능 => 입출력 동시에 불가

스트림의 구분

대상 기준

  • 입력 스트림: 대상으로부터 자료를 읽어 들이는 스트림
  • 출력 스트림: 대상으로 자료를 출력하는 스트림

자료의 종류

  • 바이트 스트림: 동영상, 음악 파일 등을 읽고 쓸 때 사용
  • 문자 스트림: 2바이트 단위로 처리, 바이트 단위 처리 시 발생하는 문자 깨짐을 방지

기능

  • 기반 스트림: 대상에 직접 자료를 읽고 쓰는 기능의 스트림

  • 보조 스트림: 직접 읽고 쓰는 기능은 없이 추가적인 기능을 더해주는 스트림

표준 입출력

  • System 클래스의 표준 입출력 멤버
public class System() {
	public static PrintStream out;
	public static PrintStream in;
	public static PrintStream err;
}

System.out

  • 표준 출력(모니터) 스트림
System.out.println("표준 출력");

System.in

  • 표준 입력(키보드) 스트림
int d = System.in.read(); //한 바이트 읽어내기

System.err

  • 표준 에러 출력(모니터) 스트림
System.err.println("데이터"); //빨갛게 출력

Scanner 클래스

  • java.util 패키지에 있는 입력 클래스
  • 문자뿐 아니라 정수, 실수 등 다른 자료형도 읽을 수 있음
  • 콘솔, 파일 등 여러 대상에서 자료를 읽을 수 있음

바이트 단위 스트림 - InputStream

  • 바이트 단위 입력용 최상위 스트림
  • 추상 메서드를 포함한 추상 클래스로 하위 클래스가 구현하여 사용

주요 하위 클래스

  • FileInputStream - 파일에서 바이트 단위로 자료를 읽습니다
  • ByteArrayInputStream - Byte배열 메모리에서 바이트 단위로 자료를 읽습니다
  • FilterInputStream - 기반 스트림에서 자료를 읽을 때 추가 기능을 제공하는 보조 스트림의 상위 클래스입니다

메서드

  • int read() - 입력 스트림으로부터 한 바이트의 자료를 읽습니다. 읽은 자료의 바이트 수를 반환합니다.
  • int read(byte b[ ]) - 입력 스트림으로부터 b[ ] 크기의 자료를 b[ ]에 읽습니다. 읽은 자료의 바이트 수를 반환합니다
  • int read(byte b[ ], int off, int len) - 입력 스트림으로부터 b[ ] 크기의 자료를 b[ ]의 off변수 위치부터 저장하여 len만큼 읽습니다. 읽은 자료의 바이트 수를 반환합니다.
  • void closer() - 입력 스트림과 연결된 대상 리소스를 닫습니다

바이트 단위 스트림 - OutputStream

  • 바이트 단위 출력용 최상위 스트림
  • 추상 메서드를 포함한 추상 클래스로 하위 클래스가 구현하여 사용

주요 하위 클래스

  • FileOutputStream - 바이트 단위로 파일에 자료를 씁니다
  • ByteArrayOutputStream - Byte배열에 바이트 단위로 자료를 씁니다
  • FilterOutputStream - 기반 스트림에서 자료를 쓸 때 추가 기능을 제공하는 보조 스트림의 상위 클래스입니다

메서드

  • int wirte() - 한 바이트를 출력합니다
  • int wirte(byte b[ ]) - b[ ] 배열에 있는 자료를 출력합니다
  • int wirte(byte b[ ], int off, int len) - b[ ] 배열에 있는 자료의 off 위치부터 len 개수만큼 자료를 출력합니다
  • void flush() - 출력을 위해 잠시 자료가 머무르는 출력 버퍼를 강제로 비워 자료를 출력합니다
  • void closer() - 출력 스트림과 연결된 대상 리소스를 닫습니다. 출력 버퍼가 비워집니다

flush()와 close() 메서드

  • 출력 버퍼를 비울 때 flush() 메서드 사용
  • close() 메서드 내부에서 flush()가 호출되므로 close() 메서드가 호출되면 출력 버퍼가 비워짐

문자 단위 스트림 - Reader

  • 문자 단위로 읽는 최상위 스트림

주요 하위 클래스

  • FileReader - 파일에서 문자 단위로 읽는 스트림 클래스
  • InputStreamReader - 바이트 단위로 읽은 자료를 문자로 변환해 주는 보조 스트림 클래스
  • BufferedReader - 문자로 읽을 때 배열을 제공하여 한꺼번에 읽을 수 있는 기능을 제공해 주는 보조 스트림

주요 메서드

  • int read() - 파일로부터 한 문자를 읽습니다. 읽은 값을 반환합니다
  • int read(char[ ] buf) - 파일로부터 buf 배열에 문자를 읽습니다
  • int read(char[ ] buf, int off, int len) - 파일로부터 buf 배열의 off 위체에서부터 len 개수만큼 문자를 읽습니다
  • void close() - 스트림과 연결된 파일 리소스를 닫습니다

[Day 35]

보조 스트림

  • 실제 읽고 쓰는 스트림이 아닌 보조적인 기능을 추가하는 스트림
  • 데코레이터 패턴
  • FilterInputStream과 FilterOutputStream이 보조스트림의 상위 클래스
  • 생성자의 매개 변수로 또 다른 스트림을 가짐

InputStreamReader와 OutputStreamwriter

  • 바이트 단위로 읽거나 쓰는 자료를 문자로 변환해주는 보조스트림
public class InputStreamReaderTest {
	public static void main(String[] args) {
		try(InputStreamReader irs = new InputStreamReader(new FileInputStream("reader.txt"))){
			int i = 0;
			while((i = irs.read()) != -1) {
				System.out.print((char)i);
			}
		} catch (IOException e) {
			System.out.println(e);
		}
	}
}

Buffered 스트림

  • 내부적으로 8192 바이트 배열을 가지고 읽거나 쓰기 기능을 제공하여 속도가 빨라짐

스트림 클래스

  • BufferedInputStream - 바이트 단위로 읽는 스트림에 버퍼링 기능을 제공합니다
  • BufferedOutputStream - 바이트 단위로 출력하는 스트림에 버퍼링 기능을 제공합니다
  • BufferedReader - 문자 단위로 읽는 스트림에 버퍼링 기능을 제공합니다
  • BufferedWriter - 문자 단위로 출력하는 스트림에 버퍼링 기능을 제공합니다

태그:

카테고리:

업데이트: