개발을 하다보면, "예상치 못한" 상황을 많이 마주하게 된다. 대표적인 경우가 오류, 예외

 

오류(error) : 일반적으로 회복이 불가능한 문제. 주로 시스템 레벨에서, 주로 환경적인 이유로 발생

                    코드의 문제로 발생하는 경우도 있지만, 일단 발생하는 경우 일반적으로 회복이 불가. (종료되기때문)

                    에러 발생 시 어떠한 에러로 프로그램이 종료되었는지를 확인하고 대응 (logging 처리)

 

예외(Exception) :  일반적으로 회복이 가능한 문제

                               회복이 가능하다는 전제는, 그 예외가 발생할 수 있다는 것을 인지하고 대응했을 것

                               현실적으로 코드레벨에서 할 수 있는 문제상황에 대한 대응은 "예외처리"에 속함

                               ==> 예외처리를 자세하게 할 수록 완성도 높은 구현 가능

                               ==> 습관을 잘 들여놓는게 중요하다!!

 

<예외(Exception)의 종류>

1. 컴파일 에러(예외) : 컴파일 단계에서 발생하는 오류 (.java ==> .class)

-    대부분의 경우 코드 작성 단계에서 프로그래밍 언어의 규칙을 지키지 않았기 때문에 발생(클래스명, 접근가능여부 등)

-    해결방법 : 문법에 맞게 코드 수정

 

2. 런타임 에러(예외) : 주로 처리하게 될 에러(예외)로서, 컴파일은 잘 되었지만 프로그램이 실행도중 발생하는 에러

-    Checked Exception : 확인된 예외로서, 컴파일시점에 check하는 예외. 이것에 대한 처리를 하지 않으면 컴파일 에러

-    Unchecked Exception : 런타임 시점에 확인되는 에러로서, 예외처리가 반드시 필요하지 않음

 

<예외 발생과 try-catch, finally 문>

1. 예외를 어떻게 정의할 것인지 : 클래스를 만들어서 한다. extends Exception

2. 예외가 발생할 수 있음을 어떻게 알릴지 : 예외가 발생할 수 있는 logic에 flag를 달아놓는다 ?

3. 사용자는 예외가 발생할 수 있음을 알고 예외를 핸들링하는지

==> 이 흐름에서 나오는 것들이 try, catch, finally, throw 같은 키워드

 

예시)

<예외 클래스 만들기>

- Exception 클래스를 상속받아 만든다.

class ourException extends Exception(){

    public ourException(){

        super("출력할 메세지?")                                   

    }

}

 

<예외가 발생할 수 있는 메소드에 선언부에 flag(표시)>

- 메소드를 선언할 때 뒤에 throws ourException을 붙이고, 내용부분에서 exception을 정의하고, 예외클래스 생성, throw

public void dangerousMethod() throws ourException

    if(확인할조건){

        throw new ourException                 ==>  throw를 만나면 return을 만난것처럼 종료된다.

        }

    else{

            원래내용....

        }

}

 

<예외발생하는 메소드 사용 시 try-catch-finally 사용>

....코드 중...

 

try{

    // 예외처리가 되어있는 메소드를 "시도" 해보는 부분

    ourClass.dangerousMethod();

}catch( ourException e ){

    System.out.println(e.getMessage());          //  ourException e는 Exception을 상속받았기때문에 getMessage를 사용가능

                                                                       //  message는 ourException의 생성자에서 super로 넘겨줬다.

} finally {

    예외가 발생하든 발생하지 않든, 실행될 로직;

    // 예외가 발생하면 핸들링 후 실행, 발생안하면 그냥 실행.

}

 

===> 만약 throws로 처리가 되어있는 메소드를 쓸 때, try-catch문을 사용 안해주면 컴파일 오류가 난다.

 

<Exception 클래스 구조>

수많은 에러에 대한 것을 추상화하고, 객체로 만들어 주는 것은 어려운 일이다.

위에 나온 에러 대응 프로세스는 언어 설계 차원에서의 대응 프로세스이기도 하기 때문에, 이 문제들을 추상화 해서 객체로 만들어주는 것은 자바 언어에서 지원해준다. 따라서, 현실에서 마주하는 개념이나 이슈들을 객체지향 프로그래밍으로 어떻게 구현하는지에 대한 좋은 예시로서 공부할 수 있다.

 

==Java의 Throwable Class==

-시작은 모든 객체의 원형인 Object 클래스.

- Throwable Class는 "문제 상황"을 뜻하는 클래스 --> 자식으로 Error와 Exception 클래스가 있다.

- Error와 Exception 클래스는 각각 IOerror 클래스, RuntimeException 클래스와 같이 구분되어 처리된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

          

<override>

부모로부터 상속받은 메서드의 내용을 재정의하는 것

1. 선언부가 부모 클래스의 메서드와 일치해야 함

2. 접근 제어자를 부모 클래스의 메서드보다 좁은 범위로 변경할 수 없음.

3. 예외는 부모 클래스의 메서드보다 많이 선언할 수 없다.

 

★override할 함수 위에 @Override 라고 써준다 (annotation)

이유 : 자바가 override 되고 있는지 체크해줌 (?)

 

<super>

super와 super()

 

super : this와 비슷하게 부모클래스의 멤버를 참조할 수 있는 키워드. 그냥 부모를 가리킨다고 보면 된다.

super() : super가 부모 클래스의 이름이니까, super()는 부모클래스의 생성자를 호출함.

             ==>자식클래스는 생성될 때, 부모클래스들이 같이 생성되면서 하나로 합쳐지게 되기 때문에, 자식클래스의 생성                     자에서는 부모클래스의 생성자가 첫줄에 호출되어야함. 만약 안써주면 컴파일러가 부모의 기본생성자 추가

 

<다형성>

부모타입 변수 = 자식타입객체; 는 자동으로 부모타입으로 변환이 일어난다.

                       ==>    Map<String> strMap = new HashMap<>()   자식클래스의 생성자로 부모클래스를 생성

                       ==> 자식은 부모의 모든 멤버를 가지고있기 때문으로  생각하기

 

Hobby hobby = new Hobby(Sports sport1) 이런식으로 Hobby의 생성자가 Sports 타입을 받아야한다고 할때,

이 대신 Sports를 상속받은 Sportsclimbing을 넣어주면 이것이 부모클래스로 자동 형변환이 일어나면서 Hobby를 생성할 수 있는 것이 다형성이다. 이 때, 자식클래스에서 override한 내용을 가지고 가서 형변환이 일어나기 때문에 결국 들어가는 자식 인스턴스의 속성에 따라 부모클래스의 내용이 바뀌므로, Hobby의 내용이 다양해질 수 있다.

 

=> 다형성 기능으로 인해서 클래스 객체의 원래 클래스명을 체크할 필요가 있을 수 있다. 이때 사용하는 것이

      instance of

 대상객체 instance of 클래스이름   ===> boolean을 return해줌. (자기부터 부모클래스들은 다 true를 return)

 

 

 

<생성자>

Constructor. 객체가 생성(new)될 때 호출되며, 객체를 초기화하는 역할을 하며, 부가적인 역할도 함.

모든 클래스는 반드시 생성자가 있어야함 (안만들어주면 컴파일러가 기본생성자로 만들어줌)

컴파일러에 의해 생성되는 기본 생성자는 해당 클래스의 접근제어자를 따라간다.

생성자도 오버로딩 가능

 

<this>

자기 자신(인스턴스)를 가리키는 변수.

왜 ? 생성자에서 생성할 때, 클래스에서 정한 변수명과 파라미터로 정한 변수명이 겹칠 경우가 있음

public ClimbingGym(String name){

    this.name = name

}

이런식으로 this 써준다. 생성자에서 필드변수를 가리키는 경우에는 this.변수명 으로 써주는게 국룰

 

오버로딩에서도 많이 활용된다.

this는 Car를 가리키므로  this()는 즉  Car()와 같다. Car 클래스의 생성자를 호출하는 것.

 

<제어자>

제어자는 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미를 부여함

접근 제어자 : public // protected // default // private

그 외 제어자 : static // final // abstract

 

public : 접근 제한이 전혀 없음

protected : 같은 패키지 내에서 + 다른패키지의 자손클래스에서 접근 가능

default : 같은 패키지 내에서만 접근 가능

private : 같은 클래스 내에서만 접근 가능

 

클래스에 사용 가능한 접근제어자 : public // default

메서드 & 멤버변수에 사용 가능 : public // protected // default // private

 

메서드에 static과 abstract를 동시에 사용 불가

클래스에 abstract와 final을 동시에 사용 불가

abstract메서드의 접근 제어자가 private일 수 없다

메서드에 private과 final을 같이 사용할 필요는 없다

 

 

접근제어자는 객체의 무결성 즉, 변경이 없는 상태를 유지하기 위해 사용한다.

외부에서 필드에 접근하는 것을 막기 위해 필드에 private, default 등의 접근 제어자를 사용할 수 있다.

 

==>제어자때문에 나오는 개념이 ★★★★★Getter // Setter★★★★★

 

<Getter & Setter>

★ getter와 setter는 직접적인 값의 조회와 세팅을 방지하기 위해 사용됨 !!

보통 하나의 필드마다 getter와 setter가 존재함 getColor(), setColor() 와 같이 camelCase로 선언하는게 국룰

 

예를들어, double type으로 선언한 age필드에 누가 person.age = "27살" 이런식으로 값을 직접 바꾸게되면 안되기때문에 setAge() 같은 public한 setter 메소드를 사용해 값을 변경하도록 하고, 그 안에 특정한 로직을 담게된다.

 

외부에서 객체의 private한 필드를 읽을 필요가 있을 때 Getter 메서드를 사용. Getter를 이용해 내부 로직을 숨기면서, 내보내야 하는 정보만 내보낼 수 있다.

 

<상속>

부모클래스를 상속받은 자식클래스는 부모클래스의 필드나 메서드를 사용할 수 있다.

상속을 사용하면 코드의 중복이 제거되고, 재사용성이 크게 증가하여 생산성과 유지보수성에 매우 유리해진다.

상속 keyword : extends

public class 자식클래스 extends 부모클래스 { }

 

-부모클래스에 새로운 필드와 메서드가 추가되면 자식클래스는 이를 상속받아 사용할 수 있다.

-자식클래스에 새로운 필드와 메서드가 추가되어도 부모클래스는 어떠한 영향도 받지 않는다.

-따라서 자식 클래스의 멤버 개수는 부모클래스보다 항상 같거나 많다.

 

★Java는 다중상속을 허용하지 않음 : 클래스간의 관게가 복잡해지기 때문

★부모 클래스에 final인 멤버가 있으면 상속 불가 : 변경 불가하기 때문에 override할 수 없기때문

overload : 클래스 내에 같은 이름의 메소드를 여러가지로 정의  // override : 부모클래스의 메서드를 재정의

 

<추상 클래스>

-미완성된 설계도. 부모는 완성시키지 않은 method를 가지고 있고, 자식은 이를 상속받아서 완성시킴

- abstract 키워드를 class 앞에 넣어줘서 사용

eg) public abstract class 추상클래스명;                 ==> {}가 없고, 세미콜론으로 선언만 함

 

1. 추상 클래스는 추상 메서드를 포함할 수 있다 (없어도 선언 가능하긴함)

2. 추상 클래스는 자식 클래스에 상속되어서 자식 클래스에 의해서만 완성될 수 있음

3. 추상 클래스는 여러개 자식클래스 중에서 공통적인 필드나 메서드를 추출해서 만들 수 있다.

 

부모클래스를 자식들이 가져다 쓴다는 느낌보다, 자식클래스들의 공통된 특징을 묶어주는 느낌이 강하다(추상화)

상속받은 클래스에서 추상 클래스의 추상 메서드는 반드시 오버라이딩 되어야 한다(인터페이스와 다른 점)

 

<Interface>

두 객체를 연결해주는 다리.

- 상속관계가 없는 다른 클래스들이 서로 동일한 메서드를 구현해야할 때 인터페이스는 구현 클래스들의 동일한 사용 방법과 행위를 보장해줄 수 있다.

 

예를들어, 멀티 리모컨 인터페이스를 통해 삼성티비 객체, LG티비 객체의 채널을 변경할 수 있음

 

interface 키워드로 선언하며,   public interface 인터페이스명{ }    과 같은 형태가 됨. public // default 접근자 지정 가능

 

1. 인터페이스의 모든 멤버 변수는 public static final  : *생략가능 -생략시 컴파일러가 자동으로 추가

2. 인터페이스의 모든 메서드는 public abstract : *생략가능-생략시 컴파일러가 자동 추가(static, default 메서드 제외)

3. 생략되는 제어자는 컴파일러가 자동으로 추가해줌

 

- 인터페이스는 추상 클래스와 마찬가지로 직접 인스턴스를 생성할 수 없어, 클래스에 구현되어 생성된다.

 

public class 클래스명 implements 인터페이스명{

    @Override

    public 리턴타입 메서드이름(매개변수 ...{

            //실행문

        }

}

 

- 인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩 되어야 함. (안하면 컴파일 시 오류 발생)

- 인터페이스의 추상 메서드를 일부만 구현해야 한다면, 해당 클래스를 추상 클래스로 변경해주면 된다

    ==> implements 받는 클래스를 추상클래스로 선언한 뒤, 이것을 필요한 클래스에 상속해서 override

- 인터페이스 간의 상속이 가능하다. 인터페이스간의 상속은 extends 키워드를 사용하며, 다중상속 가능

 

===========Interface의 default, static 메서드=============

--------------interface의 디폴트 메서드----------------

-디폴트 메서드는 추상 메서드의 기본적인 구현을 제공하는 메서드.

-default 역시 접근 제어자가 public이며, 생략 가능

-추상 메서드가 아니기때문에 인터페이스의 구현체들에서 필수로 재정의할 필요는 없다.

 

--------------interface의 static 메서드----------------

-static 메서드의 경우, interface에 바로 접근 가능.

-이유 : static 메서드는 compile 단계에서 생성되기 때문에 구현체를 선언하지 안하도 쓸 수 있다.

 

<인터페이스의 다형성>

A가 interface, B는 interface를 implement받은 객체라고 할 때,

A a1 = new B(); 를 하면 B라는 구현체가 A로 형변환 일어나게 된다.

C는 구현체 B를 상속받은 객체라고 할 때,

A a2 = new C(); 를 하면 C가 A로 형변환됨.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<객체지향>

Java는 대표적인 객체지향 언어. 객체빼면 시체

객체 = Object. 속성행위로 구성이 되어있다. 속성 = field // 행위 = method

객체지향 언어에서의 소프트웨어는 객체들의 조립. 객체들의 상호작용을 고려해야함.

상호작용 = 매개변수(parameter)를 넘겨주어 메서드를 호출시킨다.

객체 관계 : 사용 관계 // 포함 관계 // 상속 관계

 

클래스에서 자주 나오는 개념 : 캡슐화 // 상속 // 다형성 // 추상화

1.캡슐화(encapsulation) - 속성과 메서드를 하나로 묶어 객체로 만든 후, 내부 구현 내용은 외부에서 알 수 없게 감추는 것

    ==> 보안상의 이유, 외부에서 메서드를 잘못 사용하여 객체가 변하지 않게. Java에서는 접근 제어자를 써서 구현

 

2. 상속(inheritance) : 부모 객체가 가지고 있는 필드와 메서드를 자식 객체에 물려준다.

    ==> 그대로 쓸지, 가공해서 쓸건지(override) 결정해서 사용. 코드 중복이 줄어들며, 부모와 자식간의 일관성 유지 가능

 

3. 다형성 : 객체가 연산(메소드)를 수행할 때, 하나의 행위에 대해 각 객체의 속성(특성)에 따라 여러가지로 재구성되는 것

 

4. 추상화 : 객체에서 공통된 부분들을 모아 상위 개념으로 새롭게 선언하는 것.

==> eg) 여러 종류의 자동차들이 공통으로 가진 가속, 브레이크, 속도와 같은 것들을 모아서 새롭게 선언

 

=======클래스를 토대로 생성된 객체(Object)를 해당 클래스의 인스턴스라고 부른다.=============

- 동일한 클래스로 여러가지 인스턴스를 만들 수 있다.

- 클래스는 설계도, 객체는 만들어진 제품이라고 볼 수 있음

 

<클래스>

생성 방법 :

1. 만들고자 하는 클래스를 선언

2. 객체가 가지고 있어야할 속성(필드)를 정의

3. 객체를 생성하는 방식을 정의(생성자) - 생성자는 클래스 이름과 동일한 이름을 가진 메서드 형태

4. 객체가 가지고있어야 할 method를 정의

 

생성자가 아무 역할(파라미터를 받거나, 로직을 수행)을 하지 않으면 기본 생성자라고 하고, 생략 가능

 

객체 생성 방법

new를 통해 ClimbingGym이라는 클래스를 인스턴스화 했고, 생성자에 넣어놓은 출력

가 실행됨.  생성된 인스턴스를 그대로 프린트해보면, 주소값이 출력된다. 참조형 변수라는 뜻. 따라서,

아래와같이 ClimbingGym 객체로 이루어진 리스트도 선언 가능하다.

객체의 필드에는, 생성된 후 변하지 않는 부분과 변하는 부분이 있다. 이를 다루기 위해 set과 get을 공부하게 될것

또한, 그 값이 또다른 객체인 필드도 있다.

Athlete객체를 만들고,

ClimbingGym 클래스에 소속 선수들을 Athlete 인스턴스로 저장할 수 있는 Array 필드를 생성,

addAthlete 메서드를 추가해준 후 Athlete를 넣어주면 작동하는 것을 볼 수 있다.

 

===============Class, 객체 관련 잡다===================

-클래스의 필드를 선언하고 초기화하지 않으면, 각 변수 type에 맞는 default 값으로 할당됨

-클래스의 필드에 외부에서 접근할 땐 Class.필드 와 같이 .을 찍어서 접근한다.

-클래스의 내부에서 필드에 접근할 때는 변수명을 바로 써서 접근 가능

-메서드는 꼭 return값이 있어야 하는건 아니다

-메서드의 파라미터는 가변길이로 선언 가능 void addAthlete(Athlete... athletes) ==> addAthlete(jay1, jay2, jay3...)

 

<클래스의 멤버>

member = field + method

클래스의 멤버는 선언하는 방법에 따라서 인스턴스 멤버 // 클래스 멤버

                           =>static 등

인스턴스 멤버 : 인스턴스 필드 + 인스턴스 메서드

클래스 멤버 : 클래스 필드 + 클래스 메서드

==> 인스턴스 멤버는 객체 생성 후 사용할 수 있고, 클래스 메서드는 객체 생성 없이도 사용할 수 있다.

==> 이유 : 객체가 인스턴스화 될 때마다 모든 메서드가 생성된다고 생각하면 메모리낭비가 심할 것을 알 수 있다.

                 따라서 메서드는 메서드 영역에 두고서 모든 인스턴스들이 공유해서 사용함. 대신, 객체를 인스턴스화                                 해야 사용할 수 있는것.

                 클래스 메서드의 경우, Java의 클래스 로더에 의해 메서드영역에 저장되기 때문에 객체생성 없이 사용O

                 이러한 메서드를 만들어주는 것이 static 이다. 고정된 영역을 가지기 때문이라고 생각하면 될듯

==>일반적으로 인스턴스마다 모두 가지고 있을 필요 없는 공용데이터를 저장하는 필드는 클래스 멤버로 선언

                                                                                                                            ->eg) static String name = "재형";

==>인스턴스 필드를 사용하지 않고 실행되는 메서드는 static을 붙여주어 클래스 메서드로 선언

==>클래스멤버는 클래스이름.멤버  와 같이 클래스이름으로 접근하는 것이 좋다. 약속 !

 

<메서드>

-------------메서드 오버로딩------------

같은 이름의 메서드로 여러가지 기능을 구현 : 매개변수의 타입 또는 개수, 순서가 다르면 동일한 이름으로 정의 가능

대표적인 예시가, println() : 들어오는 매개변수의 type에 따라 다른 방법으로 출력해야 하기 때문. println의 정의 보면 앎

장점 : 같은 기능에 대해 메서드 이름을 절약할 수 있으며, 혼선을 방지 가능

 

--------------기본형 & 참조형 매개변수-----------

매개변수의 타입이 기본형일때는, 값이 복사되어서 넘어가기때문에 원본값 변경X

매개변수의 타입이 참조형일때는, 주소값을 넘겨주기 때문에 메서드 내에서 원본값 변경 가능

 

 

 

 

<연산자> 

산술연산 : +(덧셈)   -(뺄셈)    *(곱셈)    / (나눗셈)      << ,  >> (비트연산자)

 

비교연산자 :   <,  >,  <=,  >=,   ==,    !=

 

논리연산자 :  &&(and) ,   ||(or),    !(not)

 

대입연산자 : =, ++, --

 

기타연산자: (type)(형 변환 연산자)   //   ? :  (삼항연산자)  //   instance of

 

연산자 우선순위 : 산술 -> 비교 -> 논리 -> 대입

 

피연산자 자동 형변환 : 타입이 다른 두 개의 연산을 진행할 때, 더 큰 type으로 맞춰주게됨

 

비트연산 : <<하면 왼쪽으로 자리수 옮기기 (0101 -> 1010) // >>는 오른쪽옮기기 (1010 -> 0101)

 

<switch - case문>

switch(month){

    case 1:

        monthString = "1월" ;

            break;

    case 2:

        monthString = "2월" ;

            break;

............

    defalut:

        monthString = "unknown";

}

 

swith안에 오는 연산자가 case (조건)일때, indentation 안의 코드를 실행한다.

각 case 안에 break가 있어야 switch문을 탈출할 수 있으며, case에 모두 해당되지 않을 때 실행할 default를 줘야한다.

if와 다르게 조건을 하나만 지정할 수 있다. 대신 가독성이 좋음

 

<반복문>

for문, while문, do-while문이 있다.

for문, while문은 C랑 문법 똑같음

iterable에서의 for문은

for (int num : number){ }와 같이 써주며, 이 때 콜론 오른쪽에는 배열이 오게됨.

 

=========do-while문=========

while문과 다르게, 작업을 먼저하고 조건을 비교

 

do{

    작업 ~~~

} while(조건);

 

<배열>

new 명령어를 통해서 생성

int[] arr = new int[8]

값을 주려면 {1,2,3} 이런식으로

int배열은 기본적으로 0, bool은 false, String은 null로 채워짐

 

======Arrays 유틸리티=====

Arrays.fill(intArr , 1)  : intArr의 값을 모두 1로 초기화

등등 좋은 메서드 많다.

 

<배열에서의 복사>

int[] arr1 = {a,b,c}   이런식으로 선언하면, arr1이라는 변수는 주소값만 담고있다.

따라서, int[] arr2 = arr1  과 같이 대입해주면, arr2는 arr1의 주소값을 담게되므로, arr2의 값을 수정하면 arr1도 수정됨.

이를 얕은복사라고 함(주소값을 복사)

 

값을 복사(깊은복사) 하고싶으면, for문으로 하나하나 element를 대입해주거나,

int[] arr2 = arr.clone(); 메서드를 사용  ==> arr과 같은 값, 다른 주소를 리턴. but, 2차원 이상 배열에서는 얕은복사됨

 

따라서, 완전히 깊은복사를 하고싶으면 Arrays 유틸리티의 copyOf(arr, arr.length) 메소드 사용

eg)

int[] a = {1,2,3,4};

int[] b = Arrays.copyOf(a, a.length);

 

<가변배열>

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

두번째 차원의 배열은 길이가 달라도 넣을 수 있음

 

<String 유용한 메소드>

str.length() // str.charAt(3)  // str.substring(0,3) // str.equals(str2) // str.toCharArray();

String(char[])  ==> String으로 바꿔줌

 

<Collection>

★컬렉션은 기본형 변수가 아닌 참조형 변수를 저장한다

 

배열만 사용했을때 아쉬운 부분들을 커버해줌

Collection에는 ArrayList, LinkedList Set, Stack, Queue, Map  있음

컬렉션의 기능 : 크기 자동조정 / 추가 / 수정 / 삭제 / 반복 / 순회 / 필터 / 포함확인 etc.....

 

-------List------- : 순서가 있는 데이터의 집합 (데이터의 중복 허용) ==> 배열과 비슷

변수의 타입을 명시할 때, 기본형이 아닌 그 Wrapper타입으로 명시해줌 (컬렉션은 참조형 변수만 담으니까)

 

1. ArrayList<Integer> intList = new ArrayList<Integer>();

intList.add(100)    intList.add(200)    intList.add(300)

intList.get(0)  ==> 100       intList.set(1,15)   ==>  intList의 두번째 요소가 15로 바뀜

intList.remove(0)   ==>  intList의 첫번째요소를 삭제     intList.clear()   ==>  intList의 값들을 모두 삭제

print(intList.toString());  ==>  intList의 요소들을 볼 수 있게 해줌 ?

 

2. LinkedList<Integer> linkedist = new LinkedList<Integer>();   ==> 값을 조회할때는 느리지만, 추가/삭제는 빠름

linkedList.add(index : 2, element : 4)  ==> linkedList의 2번인덱스에 4를 추가

linkedList.set(index : 1, element : 10)  ==> linkedList의 1번인덱스의 값을 10으로 바꿈

remove, clear 등 ArrayList와 메소드들은 비슷함

 

-------Stack------- : FILO(first in last out)  ==> 최근 저장한 데이터를 나열하거나, 데이터의 중복처리를 막고싶을때

Stack<Integer> intStack = new Stack<Integer>();   ==> 선언 및 생성

intStack.push(10)    ==> 스택에 10을 넣음

intStack.isEmpty()   ==>  비었으면 true, 아니면 false

intStack.pop()   ==>  stack의 맨 위에거 꺼내고, 그것을 return

intStack.peek() ==> 맨위에거 리턴해줌. 하지만, pop하진않음

intStack.size() ==> 크기 return

 

-------Queue-------FIFO(first in first out)   ==>   생성자가 없는 인터페이스 (new로 만들지 않음)

Queue<Integer> intQueue = new LinkedList<>();    ==> 생성자가 없기때문에 생성자있는애로 만들어줌

.add(10)  ==> Stack과 같음    .isEmpty()도,   .size()도 같다

intQueue.poll()  ==> Queue의 제일 아래 (먼저들어간) element를 빼주고, 이 값을 리턴

intQueue.peek() ==> 보기만 함. poll과 같은값이 return되지만, 이 값이 Queue에서 빠지지 않음

 

 

 

-------Set-------순서가 없는 데이터의 집합 (데이터 중복 X) ==> 순서가 보장되지 않지만, 중복X,  생성자 없음

*HashSet, TreeSet 등으로 응용해서 같이 사용 가능

Set<Integer> intSet = new HashSet<>();     ==>  Set은 생성자가 없기때문에, 생성자가 있는 HashSet으로 생성

                                                                                                                             ≫생성자는 별도로 공부

.add(10)  //  .contains(10)  //  .remove()     etc....

 

 

-------Map-------순서가 없는 (Key, Value) 쌍으로 이루어진 데이터의 집합 ==> 파이썬의 dictionary와 비슷

★Key는 유니크한 값들

HashMap, TreeMap 등으로 활용가능

 

Map<String, Integer> intMap = new HashMap<>();

intMap.put('일', 11)    intMap.put('이', 22)     ==> .put('key', value) Set에 값을 넣어줌. 중복된 key에 대해서 덮어쓰기함

intMap.get('key')  ==> key값에 해당하는 value를 가져옴

intMap.keySet()  ==> Map에서 key만 빼서 배열로 리턴(Map을 순회해야할 때 for문에 활용)

======>  for (String key: intMap.keySet()) { }   이런식으로 활용

intMap.values()   ==>  Map에서 value들만 빼서 배열로 리턴

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<Java 개요>

A언어 : 입,출력 // 문맥

==> B언어 : A언어기능 + 기계식 데이터 타입, 연산기능, methods 

==> C언어 : B언어기능 + 자료형 데이터 타입, 자료구조(분류통)

 

이후에 등장한 것이 Java. C언어의 많은 특징들을 가지고왔다

1990년대에 등장, 어디서나 마시는 커피(Java)처럼 어디서나 동작 가능한 언어

==> 공통 실행환경 필요 : JVM (Java Virtual Machine) -> 운영체제 위에 올리는 토퍼같은것

==> C언어기능 + JVM, 클래스, 객체

 

Java 장점 : 공통 실행환경의 존재로, 쓰임이 많다. 대표적인 객체지향 언어

                   안정성이 높다, 보안성이 좋다 컴파일러가 오류를 체크하고, 각종 보안이 들어가있음

                   커뮤니티가 크다 -> 다양한 개발 도구와 라이브러리 존재

 

<JVM>

JVM : 자바가 구동될 수 있는 가상의 기기

byte code : Java코드를 운영체제가 읽을 수 있게 .class 코드로 바꾼 코드

compiler : 변환기

interpreter : 운영체제가 읽은 바이트코드를 기계가 실행할 수 있는 기계어로 번역

JIT컴파일러(Just In Time) : 빠른 Java .class 코드 해석기 -> 인터프리터의 효율을 높여준다?

메모리영역 : Java의 데이터를 저장하는 영역 -> 운영체제로부터 JVM이 할당받은 메모리 영역

클래스 로더 : .class 바이트코드를 메모리영역에 담는 운반기

가비지컬렉터(GC) : 메모리영역에서 안쓰는 데이터를 주기적으로 청소

Runtime : 프로그램이 실행중인 상태

--------JRE, JDK-------

JRE: Java Runtime Environment  ==> 자바를 "실행"할 수 있는 환경

JDK: Java Development Kit  ==> JRE를 포함하고, .java파일을 .class파일로 변환해주는 Java compiler(javac) 기능이 있음

                                                      ==> 코드를 디버깅하는 jdb 등의 기능이 있음

 

지금으로서는 JDK만 알아두고, JDK와 IntelliJ(IDE) 를 설치할 것.

class : .class파일을 만드는 영역. Main 클래스의 이름은 .java파일의 이름과 일치시켜줘야함

public : 제어자. Main class를 public으로 만들어놓으면 어디서든 접근 가능

static : 이 프로그램이 시작될 때, 무조건 실행되는 상태가 된다? (추가공부 필요)

void : output의 타입이 void인 것을 선언. 자바에서는 input과 output의 타입을 선언해줘야한다.

          ==>void는 출력이 없다는 것을 말함

(String[] args)  :  input의 타입과 변수명을 선언하고있음

System.out.println("~~") : System이라는 클래스의 out 객체의 println이란 메소드를 실행

 

<변수와 상수>

--------변수----------

int num;    :  num이라는 이름의 integer type 저장공간을 선언

String name;    :   name이라는 이름의 String type 저장공간을 선언

 

int num = 10;    :  선언과 동시에 10이라는 값으로 "초기화"

int num;   이후  num = 10       :   선언을 해놓고 나중에 값을 대입

 

--------상수----------

final int num = 10;         :      final이라는 키워드를 추가하여 상수로 선언

num = 20;                : 상수는 값 변경이 안되기 때문에 에러가 난다.

 

--------변수의 타입----------

1.기본형

=> int, char, string, boolean etc....

=> string은 "쌍따옴표로 감싸고"  //  char은 '작'은 따옴표로 감싼다

=> 정수형 변수

byte byteNumber = 127; // byte 는 -128 ~ 127 범위의 숫자만 저장 가능합니다.

short shortNumber = 32767; // short 는 -32,768~32,767 범위의 숫자만 저장 가능합니다.

int intNumber = 2147483647; // int 는 -21억~21억 범위의 숫자만 저장 가능합니다.

long longNumber = 2147483647L; // long 은 숫자뒤에 알파벳 L 을 붙여서 표기하며 매우 큰수를 저장 가능합니다.

 

=> 실수형 변수는 float(4byte), double(8byte)

float (4byte) : 3.4 * -10^38 ~ 3.4 * 10^38(long 보다 큼)범위의 숫자 저장이 가능합니다.

double (8byte) : 1.7 * -10^308 ~ 1.7 * 10^308(long 보다 큼)범위의 숫자 저장이 가능합니다.

 

 

2.참조형 : 레퍼런스가 있음. 어떤 공간의 주소값을 바라보고 있는 녀석

 

String, Object, Array, List .... 등 단일공간에 담을 수 없는 값을 저장

 

배열 선언 방식 :    int[ ] arr = {1, 2, 3}

참조형 변수는 주소값을 가진다고 했다. 이상한 값이 나오는 이유는 arr 배열이 시작되는 메모리 주소값을 주기 때문.

 

따라서 값을 출력하려면 Java에서 제공하는 Arrays 유틸리티의 toString 메소드를 사용해야한다.

 

*참고 : Stack영역은 주소값을 저장, Heap 영역은 원본 값을 저장. 참조형 변수의 경우 Stack에 주소값이 있고, 이를 참조하여 Heap의 저장공간에 접근함. Heap은 동적으로 할당된 메모리 영역이기 때문에 크기가 계속 늘어날 수 있는 참조형 변수의 원본을 저장함. Stack은 정적으로 할당된 메모리 영역이므로 크기가 몇 byte인지 정해져있는 기본형 변수를 저장. 참조형변수의 주소값은 크기가 정해져있기 때문에 Stack에 저장된다.

 

숫자형 변수타입의 크기 순서 :  byte(1) -> short(2) -> int(4) -> long(8) -> float(4) -> double(8)

 

3.Wrapper Class : 기본형 변수를 클래스로 한번 wrapping(감싸다) 하는 변수

 

클래스는 Java와 같은 객체지향 언어의 꽃이다. 클래스로 변수를 관리하면 객체지향의 많은 이점을 챙길 수 있다.

----boxing----  

==> num.methods()    : 다양한 메소드를 사용할 수 있다.

 

----unboxing----

int n = num.intValue() ;

 

============= 변수 입력받기 ============

import java.util.Scanner ;

Scanner sc = new Scanner(System.in);

int asciiNumber = sc.nextInt();      //입력받는 부분, 변수이름에 대입

char ch = (char)asciiNumber;       //입력받은 아스키코드를 문자로 형변환

 

nextLine().charAt(0);  :  Line을 입력받고 0번째 char 가져옴

 

** 형변환 하는 방법 : (char)변수이름   //  (int)변수이름  등등

 

============= 문자, 문자열 ============

문자 : 기본형 변수, 홑따옴표,  문자 뒤에 \0  (Null문자)가 없다.

문자열 : 참조형 변수(), 쌍따옴표, 문자 뒤에 \0 (Null문자)가 있다. (끝을 알려주기위해)

 

============= 입력, 출력 ============

Java 프로그램은 기본적으로 Scanner.in 객체의 next~~ 메소드를 이용해서 입력을 받음

Java프로그램은 기본적으로 System.out 객체의 print~~ 메소드를 이용해서 출력함

 

<형 변환>

float, double -> int : 소수점 버려짐

int -> double, float : 소수점 생김

 

eg)

double doubleNumber = 10.5

int intNumber = (int)(doubleNumber)          ===> intNumber : 10

 

위처럼 (int)같은 타입을 명시해서 typecasting하는 것을 명시적 형 변환이라고 한다.

But, 자동으로 바꿔주는 케이스도 있다.

 

===========자동으로 형변환되는 경우==========

- int형으로 선언된 변수에 byte자료형을 넣어주면 int로 자동 형변환되어 저장됨

- char타입 값을 미리 선언해놓은 int형 변수에 할당하면 자동으로 아스키코드로 바꿔서 할당됨

- int타입 값을 long 변수에 넣으면 long으로 형변환되어 저장됨

- int타입 값을 double 변수에 넣으면 double로 형변환

 

===> 작은 크기의 타입에서 큰 크기의 타입으로 할당될 때 자동 형변환이 일어남

===> 마찬가지로, 작은 크기의 type과 큰 크기의 type이 계산이 될 때, 자동으로 큰 크기의 type에 맞춰 형변환되어 계산됨

eg) int + double = double    근데이걸 int에 할당하면 소수점 버려짐

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+ Recent posts