skarltjr / Memory_Write_Record

나의 모든 학습 기록
0 stars 0 forks source link

JAVA A TO Z #4

Open skarltjr opened 3 years ago

skarltjr commented 3 years ago

todo

skarltjr commented 3 years ago

자바의 실행과정

1. 컴파일 과정

2. 빌드 과정

3. 바이트 코드란 :

4. jit컴파일러란 :

5. 전체적인 실행 과정


세부사항

image

-JVM JRE JDK java는 os에 독립적 그러나 jvm에게 종속적 image

jit 컴파일러 image

-JVM 의 구성요소는 크게 3가지로 구성 되어있다. 클래스 로더 시스템 (Class Loader) 메모리 (Jvm Memory) 엔진 (Execution Engine) image

클래스 로더 시스템 (Class Loader) image

메모리 (Jvm Memory) image

엔진 (Execution Engine) 실행엔진은 말 그대로 클래스 로딩 과정을 통해 런타임 데이터 영역에 배치된 바이트 코드를 명령어 단위로 읽어서 실행. 이제 이 과정을 수행하고 기계가 읽을수 있는 코드로 변경을 해주는데, 이때 사용되는게 인터프리터와 JIT컴파일러 이다.

skarltjr commented 3 years ago

-JDK / JRE

-JDK JDK는 자바 프로그램을 작성하고, JRE를 실행하는데 필요한 툴들을 가지고 있다. 그리고 컴파일러 (javaC) 와 자바 어플리케이션 런처, Appletiviewer 등을 포함하고 있다. 컴파일러는 자바 코드르를 바이트 코드로 변경을 해주는데 이는 JVM이 읽을 수 있는 언어로 변경해주는 것이다. 자바 어플리케이션 런처는 JRE를 실행시키는데, 필요한 클래스나, 메인 메서드를 로딩한다. JDK > JRE > JVM 이런식으로 가지고 있는 것이다. 그래서JRE와 개발에 필요한 툴을 JDK가 제공해 주는 것이다.

-JRE JRE는 클래스 라이브러리, JVM, 여러 Supporting 파일들을 가지고 있다. Debuger와 Compiler과 같은 개발 도구는 포함되어있지 않는다. 즉, JRE는 소스코드를 읽기 위해, JDK는 소스코드를 작성하기 위한

skarltjr commented 3 years ago

자바의 PRIMITIVE TYPE(기본 타입/ int long ....) vs REFERENCE TYPE(Integer...)

image

-자바의 타입추론 var 타입추론은 말그대로 개발자가 변수의 타입을 명시적으로 적어주지 않고도, 컴파일러가 알아서 이 변수의 타입을 대입된 리터럴로 추론하는 것이다. Var는 초기화값이 있는 지역변수 (Local Vairable)로만 선언이 가능하다.

잘못된 var 사용 image image image image image

skarltjr commented 3 years ago

클래스

객체 (객체란 속성(상태)과 기능(동작)을 가진 덩어리)

인스턴스 (생성된 객체, 어떤 클래스에 속하는 각각의 객체)


-자바의 배열 배열 타입은 클래스가 아니다. 하지만, 배열의 인스턴스들은 Obejcts(객체)이다. 즉 배열은 ‘java.lang.Objects’ 에 상속 받는다. 그래서 배열은 ‘Cloneable interface’ (객체 자신의 메모리를 복사하는 Object의 인터페이스)를 implement 받는다. 그리고 CloneNotSupportedException 을 따로 throw로 예외처리를 해주지않고도 완벽하게 보장하는 clone() 메소드를 오버라이딩 한다.

-배열의 직렬화 배열은 또한 ‘Serializable (자바의 직렬화, 자바 시스템 내부에서 사용되는 Object , Data를 외부에서 사용할 수 있게 바이트 형태로 변환하는 기술, 즉 JVM에서 데이터를 저장하는 스택, 힙에 쌓여있는 데이터를 바이트 형태로 변환한다고 생각하면 된다.)’ 인터페이스를 implements 한다. 그러므로 배열을 직렬화 시킨다면, 어떤 배열이든 직렬화가 가능하다. Array type widening conversions Array (배열)은 기본적으로 ‘Object’를 상속 받고, ‘Cloneable’ 과 ’ Serializable’ 인터페이스를 implements 하기 때문에, 모든 배열 타입은 다음 세가지 유형중 하나로 변경이 확장 할 수 있다. 하지만 특정 배열 타입은 다른 배열 타입으로 확장할 수 있다. 만약, 어떠한 배열이 T 라는 레퍼런스 타입을 타입으로 지정하고 있고, T타입에서 S타입으로 할당 할 수 있다면,T[ ] 배열은 S[ ] 배열로 할당 할 수 있다.

skarltjr commented 3 years ago

-자바 연산자 중 equals - 동등성 / 동일성 - (== 연산자 (EqualsOperators))

‘==’ 연산자는 기본적으로 프리미티브 타입에 한해서 두 피연산자의 값이 같으면 true, 아니면 false를 리턴한다고 생각하면 된다. 이는 프리미티브 타입에 한해서 ‘Value(값)’이 서로 같은지 비교를 한다. 만약 프리미티브 타입이 아닌 ‘레퍼런스 타입’은 각 객체의 참조 주소를 비교하게 된. 결국 두개의 값이 같은지 판단하는게 아니라, 두개의 주소가 같은지 판단하는 것이다.또한 String 문자열은 서로를 비교할 수 없다.

String st1 = new String("aaa");
String st2 = new String("aaa");

System.out.println(st1==st2); // false  객체간 == 은 주소값을 비교
System.out.println(st1.equals(st2));  // true equals는 객체의 값을 비교

‘==’연산자가 같은 타입이지 않을 때, 예를들어보자 만약 short 타입과 long 타입이 있다고 가정해보자 어찌 됐든 이 둘을 비교하기 위해서는 서로 타입이 같은 상황에서 비교가 가능하다. 그러므로 8바이트 짜리를 4바이트로 변경하는 건 위험

-Instanceof 연산자(instanceof operator) 프리미티브타입 x / 레퍼런스타입만 가능

        System.out.println("str" instanceof String);//true
        System.out.println("" instanceof Object);//true
        System.out.println(null instanceof Integer); // null은 instanceof 어디에도 false
        Object o = new int[]{1, 2, 3};
        System.out.println(o instanceof Object);//true
        System.out.println(o instanceof int[]);//true

우선 hashCode() 메소드를 실행해서 리턴된 해시코드 값이 같은지를 본다. 해시 코드값이 같으면 equals() 메소드로 다시 비교한다. 이 두개가 모두 맞아야 동등 객체로 판단한다.

롬복 
@EqualsAndHashCode
equals와 hashcode를 만들어 주는 것

equals: 두 객체의 내용이 같은 지 확인
hashcode: 두 객체가 같은 객체인지 확인

Tip.
@EqualsAndHashCode(of="id"): 연관 관계가 복잡해 질 때, @EqualsAndHashCode에서 서로 다른 연관 관계를 순환 참조하느라 무한 루프가 발생하고, 결국 stack overflow가 발생할 수 있기 때문에 id 값만 주로 사용
skarltjr commented 3 years ago

-자바의 클래스 ​

클래스란?

image

-익명클래스

public class Pet{
    String name = "돼지";
    public String getName(){
            return name;
    }
}
public static void main(String[] args){
    Pet pet = new Pet(){
            String name = "익명 돼지";
            @Override
            public String getName(){
                return name;
            }
    };
    System.out.println(pet.getName()); // 결과 : 익명 돼지
}

-그러나 자바에서 기본 클래스와 익명클래스는 동일하지 않다. 같은 놈이라고 생각하지않는다.

-NEW 키워드

ex) Study라는 클래스가 있을 때
Study study;   --> 는 선언이 된건가? x 
Study study = new Study(); 로  new / 생성자로 초기화 해줘야한다. 

-그런데 String 같은 레퍼런스 타입도 클래스로 정의 되었는데 왜 new를 사용하지 않는가? new 생성은 Heap 메모리 영역에, ' = " "' 은 상수 풀 (Runtime constant pool)에 저장

image image

      String asd = "qwe";
        String qwe = new String("qwe");
        System.out.println(asd == qwe); // false
        System.out.println(asd.equals(qwe)); //true

-자바의 생성자 생성자는 이전에 설명한 new 연산자와 사용하고, 객체를 생성하는 역할과 객체 초기화 역할을 한다. 생성자가 제대로 실행도지 않는다면, 객체의 주소값이 리턴도지 않을 뿐더라, 객체가 heap에 올라가지도 않을 것이다

skarltjr commented 3 years ago

-상속 extends 이미 존재하는 클래스를 기반으로 새 클래스를 만드는 방법.

-자식 클래스가 부모 클래스의 한 종류(is-a) is-a 관계 : 상속관계, 부분집합 관계

-부모와 자식이 있을 경우 부모부터 초기화된다

  1. 메모리에 객체 생성
  2. 부모 생성자 호출
  3. 자식 생성자 호출

-다중 상속 자바는 다중 상속을 지원하지 않는다.

부모의 멤버변수,함수 접근- private protected public

★부모에서 자식으로 타입변환은 안전하지만

자식에서 부모는 컴파일러가 오류를 발생시킨다. +부모가 동일해도 형제끼리는 캐스팅 할 수 없다.

-상속의 장단점

-장점 재사용성 코드 중복 줄어든다 관련 코드를 한 파일로 관리할 수 있다

-단점

상속 단계가 증가하면 추상화하기 힘들다 잘못된 상속

-super 키워드 super는 현 객체의 부모. super()는 부모 생성자 호출

-다이나믹 메소드 디스패치 (Dynamic Method Dispatch) =동적함수

정적 디스패치 컴파일 시점에 어떤 메서드가 실행될지 알 수 있다.

동적 디스패치 method가 ★오버라이드 되어있는 경우 컴파일 시점이 아닌 실행시점에서 어떤 메소드를 실행할 지 결정된다.

-추상클래스 인스턴스를 만들 수 없는 클래스 (인스턴스를 만들 수 있는 클레스는 구체 클래스) 다른 클래스의 부모 클래스가 될 수 있다 반드시 추상 메서드가 있을 필요는 없다

-Final 키워드 클래스 앞에 붙는 final 더 이상 상속하지 못함

skarltjr commented 3 years ago

-Static 1.클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통적으로 사용해야하는 것에 static을 붙인다.

  1. static이 붙은 멤버변수는 인스턴스를 생성하지 않아도 사용할 수 있다.

    • static이 붙은 멤버변수(클래스변수)는 클래스가 메모리에 올라갈때 이미 자동적으로 생성되기 때문이다.
    
    public class main {
    public static void main(String[] args) {
        String name = new pet().name;
        new per.xxxxxxxxxxxxxx; 사용불가 // static이 붙은 메서드(함수)에서는 인스턴스 변수를 사용할 수 없다.
        System.out.println(name);
    }
    public static class pet{
        String name = "qwe";
    }
    public class per{
        String name2 = "qweasd";
    }
    }

3. static이 붙은 메서드(함수)에서는 인스턴스 변수를 사용할 수 없다.

 - static이 메서드는 인스턴스 생성 없이 호출가능한 반면, 인스턴스 변수는 인스턴스를 생성해야만 존재하기 때문에... static이 붙은 메서드(클래스메서드)를 호출할 때 인스턴스가 생성되어있을수도 그렇지 않을 수도 있어서 static이 붙은 메서드에서 인스턴스변수의 사용을 허용하지 않는다. (반대로, 인스턴스변수나 인스턴스메서드에서는 static이 붙은 멤버들을 사용하는 것이 언제나 가능하다. 인스턴스변수가 존재한다는 것은 static이 붙은 변수가 이미 메모리에 존재한다는 것을 의미하기 때문이다.)

4. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.

 - 메서드의 작업내용중에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없다. 반대로 인스턴스변수를 필요로 하지 않는다면, 가능하면 static을 붙이는 것이 좋다. 메서드 호출시간이 짧아지기 때문에 효율이 높아진다. (static을 안붙인 메서드는 실행시 호출되어야할 메서드를 찾는 과정이 추가적으로 필요하기 때문에 시간이 더 걸린다.)

5. 클래스 설계시 static의 사용지침

 - 먼저 클래스의 멤버변수중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지

    살펴보고 있으면, static을 붙여준다.

 - 작성한 메서드 중에서 인스턴스 변수를 사용하지 않는 메서드에 대해서 static을

    붙일 것을 고려한다.

예제

class MemberCall {

  int iv = 10;

  static int cv = 20;

  int iv2 = cv;

// static int cv2 = iv; 에러. 클래스변수는 인스턴스 변수를 사용할 수 없음.

  static int cv2 = new MemberCall().iv;   // 굳이 사용하려면 이처럼 객체를 생성해야함.

  static void classMethod1() {

        System.out.println(cv);

// System.out.println(iv); 에러. 클래스메서드에서 인스턴스변수를 바로 사용할 수 없음.

        MemberCall c = new MemberCall();      

        System.out.println(c.iv);   // 객체를 생성한 후에야 인스턴스변수의 참조가 가능함.

 }

  void instanceMethod1() {

        System.out.println(cv);             

        System.out.println(iv);  // 인스턴스메서드에서는 인스턴스변수를 바로 사용가능.

 }

  static void classMethod2() {

        classMethod1();

// instanceMethod1(); 에러. 클래스메서드에서는 인스턴스메서드를 바로 호출할 수 없음.

        MemberCall c = new MemberCall();

        c.instanceMethod1(); // 인스턴스를 생성한 후에야 인스턴스메서드를 호출할 수 있음.

  }

  void instanceMethod2() { // 인스턴스메서드에서는 인스턴스메서드와 클래스메서드

        classMethod1();         // 모두 인스턴스생성없이 바로 호출이 가능하다.

        instanceMethod1();

 }

}

skarltjr commented 3 years ago

자바의 패키지

1. 패키지의 역할

패키지는 연관된 클래스를 담는 컨테이너 역할을 한다. 패키지 내에는 외부로부터 접근 가능한 클래스들과 특정 목적을 위해 접근이 제한된 클래스가 존재한다.

1-1) 동일한 이름을 가진 클래스들을 구분할 수 있다.

livestudy.week7.Test , livestudy.week6.Test

1-2) 접근을 제어할 수 있다

protected : 같은 패키지에 존재하는 클래스와 자식 클래스에서 접근 가능 default : 같은 패키지에 존재하는 클래스에서 접근 가능

1-3) 데이터캡슐화(혹은 데이터 은닉)의 용도로 사용할 수 있다.


2. 패키지 사용방법

하위 패키지

3. 패키지 내의 클래스에 접근하기

// util 패키지의 모든 클래스 가져오기
import java.util.*;

// 일반적으로 클래스명은 2개의 패키지에 동일한 이름의 클래스가 존재할 때 구별하기 위해 쓰인다.
import java.util.Date;
import my.package.Date;

4. 패키지의 종류

4-1) Built-in 패키지

4-2) 사용자 정의 패키지

public class MyClass{ public void getNames(String s){ System.out.println(s); } } 다른 패키지에서 import 해서 사용할 수 있다.

// myPackage에 존재하는 MyClass 클래스를 import해서 사용할 수 있다. import myPackage.MyClass;

public class PrintName{ public static void main(String args[]){ String name = "Pikachu"; MyClass mc = new MyClass(); mc.getNames(name); } }


#### 5. static import 사용하기
- 임의의 패키지의 클래스에서 public static으로 정의된 멤버(필드나 메서드)를 사용할 때, 클래스명을 언급하지 않고도 사용할 수 있다.

#### 6. 디렉토리 구조
패키지명은 클래스들을 저장하기 위해 사용하는 디렉토리의 구조와 연관되어 있다.

- 실제 디렉토리 구조는 패키지명과 동일하게(패키지\하위 패키지) 저장되어 있다.
com.zzz.project1.subproject2패키지의 MyClass 클래스가 존재한다면, 실제 클래스 파일은 다음과 같이 저장되어 있다.
$BASE_DIR/com/zzz/project1/subproject2/MyClass.class
$BASE_DIR은 패키지의 기본 디렉토리가 된다.
- 기본 디렉토리($BASE_DIR)은 파일 시스템의 어디에나 위치할 수 있다.
따라서 자바 컴파일러와 JVM은 기본 디렉토리의 위치를 알고 있어야 한다.
이를 위해서 필요한 환경 변수(environment variable)을 CLASSPATH라 부른다.
- CLASSPATH는 커맨드 쉘이 실행할 프로그램을 찾을 수 있게끔 PATH를 알려주는데 사용된다.

#### CLASSPATH란?

`import org.company.Menu;`
해당 명령어의 의미는 org.company 패키지에 있는 Menu라는 클래스를 현재 클래스에서 사용할 수 있게 하는 것이다.

JVM은 Menu클래스의 위치를 찾아서 해당 클래스의 인스턴스를 생성한다.

`Menu menu = new Menu();`
그럼 JVM은 어떻게 해당 클래스를 찾는 것일까?
만약 JVM이 Menu 클래스를 찾기 위해 존재하는 모든 클래스를 검사해야 한다면 매우 비효율적일 것이다. 그러므로 우리는 CLASSPATH 변수를 사용하여 해당 클래스가 위치한 곳을 JVM에게 알려준다.

만약 Menu 클래스가 dir이라는 디렉토리에 존재한다면, Menu 클래스의 전체 경로는 dir/org/company/Menu가 된다.

이 때 dir이라는 디렉토리를 classpath 변수로 등록해 놓고, 나머지 정보(org/company/Meny)는 import 명령어를 통해 제공해주므로서 외부 패키지의 클래스를 가져와 사용할 수 있게 된다.

#### 접근제어자
![화면 캡처 2021-01-03 013702](https://user-images.githubusercontent.com/62214428/103461774-379c7180-4d64-11eb-87e3-247555525a01.png)

![화면 캡처 2021-01-03 014159](https://user-images.githubusercontent.com/62214428/103461888-efca1a00-4d64-11eb-8ec8-851440fd7ddc.png)

####
- 모든 클래스는 패키지에 속해있다.
- 만약 파일 내에 패키지가 명시되어 있지 않다면, 해당 클래스 파일은 특별한 unnamed package(defualt)로 이동한다.
skarltjr commented 3 years ago

인터페이스

인터페이스는 일종의 추상클래스이다. 인터페이스는 추상클래스처럼 추상메소드를 갖지만 추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 일반 메소드 또는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메소드와 상수만을 멤버로 가질 수 있으며, 그 외의 다른 어떠한 요소도 허용하지 않는다. (자바 8버전부터 default 예약어를 통해 일반 메소드구현이 가능하다.

⭐️ 그렇다면 추상클래스와 인터페이스는 왜 분리했을까?
- 사용용도!!! 를 생각해라
- 다중상속은 불가하지만 다중impl은 가능하다

Dog라는 클래스가 있다고 생각해보자
모든 Dog들이 공통적으로 가져야할 특성이 있을것이다. kind, age, height, weight 등..
이렇게 공통적으로 가져가는 부분을 추상클래스로 정의한다면 모든 Dog는 공통부분을 지닐 수 있다.

그러나 모든 개가 동일한 행동을하진 않을것이다 어떤개는 짖을수도, 물수도, 수영을 할 수도 있을것이다.
따라서 인터페이스를 통해 여러 기능을 특정 개에 맞게 구현해낼 수 있다.

⭐️
즉 추상클래스는 ~이다
즉 인터페이스는 ~를 할 수 있다.
interface 인터페이스 { 
         public static final 타입 상수이름 = 값;
         public abstract 메소드이름(매개변수);
}
public interface Animal {
    void sound();
}
public class Dog implements Animal {

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

    public void sleep() {
        System.out.println("새근새근 잡니다.");
    }
}
public class Lion implements Animal {

    @Override
    public void sound() {
        System.out.println("크아앙");
    }

    public void hunting() {
        System.out.println("사냥을 합니다.");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal lion = new Lion();

        dog.sound();
        lion.sound();

      //  dog.sleep();     X 
      //  lion.hunting();  X

      ((Dog)dog).sleep();     // O
      ((Lion)lion).hunting();     // O
    }
}
public interface EchoMode {

    void EchoMode();
}
public interface NormalMode {

    void NormalMode();
}
public interface SportsMode {

    void SportsMode();
}
public class Car implements EchoMode, SportsMode, NormalMode{

    @Override
    public void EchoMode() {
        System.out.println("에코 모드로 주행 합니다.");
    }

    @Override
    public void NormalMode() {
        System.out.println("기본 모드로 주행 합니다.");
    }

    @Override
    public void SportsMode() {
        System.out.println("스포츠 모드로 주행 합니다.");
    }
}

접근제어자에서 사용하는 default와 같은 키워드이지만, 접근제어자는 아무것도 명시하지 않은 접근제어자를 default라 하며

인터페이스의 default method는 'default'라는 키워드를 명시해야 한다.

interface MyInterface {
   default void printHello() {
      System.out.println("Hello World!");
      }
}

-★implements한 클래스에서 재정의가 가능하다.

public interface ICalculator {

    int add(int x, int y);
    int sub(int x, int y);

    default int mul(int x, int y) {

        return x * y;
    }

    static void print(int value) {

        System.out.println(value);
    }
}
public class CalcTest {

    public static void main(String[] args) {

        ICalculator cal = new Calculator();

        // cal.print(100); error
        ICalculator.print(100); 
        // interface의 static 메소드는 반드시 interface명.메소드 형식으로 호출
    }
}

-★interface이름.메소드로 호출해야 한다.

java9 에서는 private method와 private static method가 추가 되었다.

java8의 default method와 static method는 여전히 불편하게 만든다.

단지 특정 기능을 처리하는 내부 method일 뿐인데도, 외부에 공개되는public method로 만들어야하기 때문이다.

interface를 구현하는 다른 interface 혹은 class가 해당 method에 엑세스 하거나 상속할 수 있는 것을 원하지 않아도,

그렇게 될 수 있는 것이다.

java9 에서는 위와 같은 사항으로 인해 private method와 private static method라는 새로운 기능을 제공해준다.

→코드의 중복을 피하고 interface에 대한 캡슐화를 유지 할 수 있게 되었다.

public interface Car {
    void carMethod();

    default void defaultCarMethod() {
        System.out.println("Default Car Method");

        privateCarMethod();
        privateStaticCarMethod();
    }

    private void privateCarMethod() {
        System.out.println("private car method");
    }

    private static void privateStaticCarMethod() {
        System.out.println("private static car method");
    }
}
DefaultCar.java 클래스 - Car 인터페이스 구현체

public class DefaultCar implements Car{

    @Override
    public void carMethod() {
        System.out.println("car method by DefaultCar");
    }
}
public class Main {
    public static void main(String[] args) {
        DefaultCar car = new DefaultCar();

        car.carMethod();
        car.defaultCarMethod();
    }
}

car method by DefaultCar Default Car Method private car method private static car method

Process finished with exit code 0

skarltjr commented 3 years ago

자바의 예외처리

화면 캡처 2021-01-18 181844


RuntimeException 종류

  1. NullPointerException(NPE) - NullPointerException 의 발생 원인은 비어있는 객체에 무슨 행동을 하려할 때, 발생
  2. ArrayIndexOufOfBoundsException
    • Checked Exception 과 Unchecked Exception - 컴파일러단계에서 확인이 가능한가? -> 런타임exception경우 unchecked

+++ mvc 예외처리 https://www.notion.so/cce3fc21976f4400aa4ed8d3fb26497b

skarltjr commented 3 years ago

멀티쓰레드 프로그래밍

Process란

Thread란

Thread클래스와 Runnable인터페이스

Thread의 상태

화면 캡처 2021-01-25 180925

Thread메서드

Thread의 상태를 확인하는 메서드

화면 캡처 2021-01-25 181705

쓰레드의 우선순위

메인 쓰레드

동기화 Synchronize


데드락 DeadLock

참고 : https://sujl95.tistory.com/63


자바는 크게 3가지 영역의 메모리 영역이 존재 클래스파일은 크게 필드 , 생성자, 메서드로 구성

자바의 멀티쓰레드에서는 쓰레드끼리 stack을 제외한 다른 영역 공유 -> 동기화문제


멀티 쓰레드 환경에서 공유변수 volatile키워드

참고 : https://nesoy.github.io/articles/2018-06/Java-volatile

skarltjr commented 3 years ago

자바 Enum

enum Fruit {
    APPLE, PEACH, BANANA;    

    Fruit() {
        System.out.println("생성자 호출 " + this.name());
    }
}

enum의 메서드

java.lang.Enum은 모든 열거형의 조상이고 모든 열거형은 Enum을 상속받는다

public abstract class Enum<E extends Enum<E>>
        implements Constable, Comparable<E>, Serializable {

    private final String name;

    private final String name() {
        return name;
    }

}

EnumSet

enum Color {
    RED, YELLOW, GREEN, BLUE, BLACK, WHITE

}

public class EnumDemo {

    public static void main(String[] args) {
        EnumSet<Color> set1, set2, set3, set4, set5;

        set1 = EnumSet.allOf(Color.class);
        set2 = EnumSet.of(Color.RED, Color.GREEN, Color.BLUE);
        set3 = EnumSet.complementOf(set2);
        set4 = EnumSet.range(Color.YELLOW, Color.BLACK);

        set5 = EnumSet.noneOf(Color.class);
        set5.add(Color.BLACK);
        set5.add(Color.BLUE);
        set5.remove(Color.BLUE);

        System.out.println("set1 = " + set1);
        System.out.println("set2 = " + set2);
        System.out.println("set3 = " + set3);
        System.out.println("set4 = " + set4);
        System.out.println("set5 = " + set5);
        System.out.println(set5.contains(Color.BLACK));
    }
}
skarltjr commented 3 years ago

어노테이션

장점

@Override

빌트인 어노테이션과 메타어노테이션

빌트인 어노테이션

메타 어노테이션

커스텀 어노테이션 - 메타어노테이션을 조합하여 새로운 어노테이션을 만들어서 사용할 수 있다.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : account")
public @interface CurrentUser {
}

어노테이션 프로세서

skarltjr commented 3 years ago

자바의 I/O

입출력

스트림 stream

바이트 기반 스트림 - inputStream , OutputStream

보조 스트림

// 기반 스트림을 이용해 보조 스트림을 생성한다. BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

// Buffered**Stream 생성 시 사이즈도 정의하여 생성할 수 있다. (2번째 파라미터) // default : 8192 BufferedInputStream bis = new BufferedInputStream(fileInputStream, 8192);

// 보조스트림을 이용해 데이터를 읽는다. bufferedInputStream.read();

- ★입출력 자체의 기능은 당연히 보조스트림이 아닌 InputStream/outputstream 이 수행한다.

#### 문자기반 스트림 - Reader,Writer
- 바이트기반(1byte)이 아닌 문자기반(2byte)
-  InputStream =>Reader , OutpuStream=>writer

### 채널기반의 스트림 NIO (new input/output)
- 새로운 입출력 패키지

![화면 캡처 2021-02-27 132641](https://user-images.githubusercontent.com/62214428/109375349-73385f80-78ff-11eb-8cb1-d9c851f30054.png)

- I/O는 스트림기반  vs NIO는 채널기반
![화면 캡처 2021-02-27 133051](https://user-images.githubusercontent.com/62214428/109375427-06719500-7900-11eb-9a27-b98b2f228dad.png)

- 스트림 VS 채널
: IO는 스트림기반으로 입 / 출력을 구분하여 단방향 스트림을 생성
: NIO는 채널기반으로 채널은 양방향 - 입출력을 위한 별도의 채널생성X

- NON버퍼 VS 버퍼
: IO는 버퍼를 사용하지않는다. - 읽은 데이터를 즉시처리
: NIO는 기본적으로 무조건 버퍼에 저장한다 - IO보다 성능면에서 우수

- 블로킹 : 데이터를 읽어 올 때 데이터를 기다리기 위해 멈춰있는 것을 뜻한다. 예를 들어 사용자가 데이터를 입력하기 전까지 기다리고 있을 때 블락킹 상태에 있다고 한다.
- 블로킹 VS NON블로킹 
: IO는 블로킹 : 입력 스트림의 read() 메소드를 호출하면 데이터가 입력되기 전까지 Thread는 블로킹(대기상태) - 빠져나오기 위해선 스트림을 종료하는 방법 뿐
: NIO는 블로킹 , 넌 블로킹 둘 다 - NIO는 interrupt를 통해 블로킹을 빠져나올 수 있다.
------------------------

#### 바이트기반 스트림 InputStream / OutputStream
- 매서드
![화면 캡처 2021-02-23 164145](https://user-images.githubusercontent.com/62214428/108814392-10d91980-75f6-11eb-895d-b2a59ff58a0c.png)
![화면 캡처 2021-02-23 164200](https://user-images.githubusercontent.com/62214428/108814395-120a4680-75f6-11eb-82b8-009931efb715.png)

----------------------------

#### print스트림 
- print, println, printf등으로 데이터를 문자로 출력하는 문자기반 스트림역할을 수행
- 흔히 사용하는 sout도 print스트림
- 문자기반 스트림 reader writer : 문자를 다루기 위해 byte대신 char타입을 다루는 것 뿐만 아니라  문자를 다루기 위한 encoding을 자동제공

---------------------------
#### InputStreamReader와 OutputStreamWriter
- 바이트 기반 스트림을 문자 기반 스트림으로 연결시켜주는 역할을 수행
- 추가적으로 바이트기반 스트림의 데이터를 지정된 인코딩의 문자데이터로 변환하는 작업을 수행

InputStream resourceAsStream = getClass().getResourceAsStream("/zones_kr.csv"); BufferedReader reader = new BufferedReader(new InputStreamReader(resourceAsStream)); List zoneList = reader.lines().map(line -> { String[] split = line.split(","); return Zone.builder().city(split[0]).localNameOfCity(split[1]).province(split[2]).build(); }).collect(Collectors.toList()); zoneRepository.saveAll(zoneList);

-----------------------------

## 표준 입출력-System.in, System.out, System.err

public final static InputStream in = null;

public final static PrintStream out = null;

public final static PrintStream err = null;

- 실제로는  `return new PrintStream(new BufferedOutputStream(fos, 128), true, enc);`처럼  BufferedInputStream과 BufferedOutputStream의 인스턴스를 사용

#### 표준입출력의 대상을 변경하는 setOut(), setErr(), setIn()

try (FileOutputStream fos = new FileOutputStream("test.txt"); PrintStream ps = new PrintStream(fos)) {

        // System.out 의 출력 대상을 test.txt 파일로 변경
        System.setOut(ps);

        System.out.println("남기석");
    }
    catch (IOException e) {
        e.printStackTrace();
    }
- sout의 대상이 test파일로 변경 -> 남기석이 파일에 작성

----------------------------
#### 파일과 객체 ㅣ 직렬화 
- serialization  : 객체를 데이터스트림으로 (ex) json으로)
- deserialization : 반대
![화면 캡처 2021-02-27 142244](https://user-images.githubusercontent.com/62214428/109376359-45efaf80-7907-11eb-8729-33a002e214fd.png)
- ★ A라는 객체! 객체란 결국 다양한 인스턴스 변수의 집합체
                          A객체 아래
인스턴스변수1    인스턴스변수2 .... 이 존재

- 이것을 말 그래도 쭉 펴주는것이 직렬화 - 이를통해 객체의 모든 인스턴스 변수값을 스트림에 write 할 수 있도록

------------------------
#### ObjectInputStream, ObjectOutputStream
- 직렬화(스트림에 객체를 출력)에는 ObjectOutputStream을 사용
- 역직렬화(스트림으로부터 객체를 입력)에는 ObjectInputStream을 사용 

- 파일에 객체저장하기

FileOutputStream fos = new FileOutputStream("objectfile.ser"); ObjectOutputStream out = new ObjectOutputStream(fos);

out.writeObject(new UserInfo());

- ★그런데 여기서 객체가 직렬화가 불가능하다면?  : Serializable

public class UserInfo implements java.io.Serializable{ String name; String password; int age; }

- ★ 1. 부모가 Serializable이라면 자식은 자동으로 Serializable
- ★ 2. 자식이 Serializable이라면 부모는 Serializable (x ) - 해당사항 x
- transient 키워드를 통해 인스턴스 변수를 직렬화에서 제외시킬 수 있다.

-----------------------------------
####  파일입출력 
- File클래스
- exist를 통해 파일이 존재하는지 확인 후 사용
- ★주의 파일클래스는 입출력을 지원하는것이 아니라 파일 자체에 대한 내용(크기,속성 등)을 위한 클래스로 입출력은 스트림을 통해서
- `FileInputStream fis = new FileInputStream("C:/Temp/image.gif");`
예시

public static void main(String[] args) { System.out.println("hi");

    try(FileInputStream fis = new FileInputStream("경로")){
        int data;
        while((data = fis.read()) != -1){
            System.out.write(data);
        }
    }catch(Exception e){
        e.printStackTrace();
    }
}

- FileOutputStream 
- 기본적으로 동일한 경로의 파일이 존재하면 지우고 다시 만든다.

//만약 기존내용에 추가적으로 작성을 하고싶다면 파라미터 true를 추가 FileOutputStream fos = new FileOutputStream("C:/Temp/image.gif", true);

FileOutputStream fos = new FileOutputStream(file, true);

- write() 메소드를 호출한 이후 "flush()" 메소드로 출력 버퍼에 잔류하는 데이터를 완전히 출력하도록 하며, 모든 작업이 끝난 후 close() 로 파일을 닫아줘야 한다. 

- 문자기반 (텍스트 파일을 위한) FileReader
- 문자기반이기 때문에 텍스트가 아닌 그림 오디오등은 x

Resource resource = new ClassPathResource("zones_kr.csv"); List zoneList = Files.readAllLines(resource.getFile().toPath(), StandardCharsets.UTF_8).stream() .map(line -> { String[] split = line.split(","); return Zone.builder().city(split[0]).localNameOfCity(split[1]).province(split[2]).build(); }).collect(Collectors.toList()); zoneRepository.saveAll(zoneList);

skarltjr commented 3 years ago

자바의 제네릭

제네릭이란? : 데이터의 타입을 일반화하는 것

왜? 사용하는가 : 컴파일타임에 잘못된 타입사용을 걸러낼 수 있다.

class GenericSample<T>{
    T element;
    void setElement(T element){
    this.element = element;
  }
}

GenericSample<Integer> inte = newGenericSample<>();

제네릭의 주요개념( 바운디드타입, 와일드카드)

바운드타입 : 특정한 타입의 하위 타입들로 제한 / ex) Number타입 하위의 int long 등

public class BoundType<T extends Number> {
    T element;

    public void setElement(T element) {
        this.element = element;
    }

    public T getElement() {
        return element;
    }
}
   public static void main(String[] args) {
        BoundType<Integer> inte = new BoundType<>(); //number하위타입integer
        inte.setElement(3);  // set
        System.out.println(inte.getElement());//get이 가능
    }

와일드카드

  1. Upper Bounded WildCard :List<? extends AnyClass>처럼 AnyClass를 상속받은 어떠한 하위 클래스가 와도 사용가능

  2. Lower Bounded WildCard :반대로 List<? super AnyClass> AnyClass의 부모 클래스만

메서드와 제네릭

public class GenericSample{
    public <T> void sample(T ele) {
        T value = ele;
        System.out.println(value);
    }
}
 public static void main(String[] args) {
        GenericSample genericSample = new GenericSample();
        String data = " hello";
        genericSample.sample(data);
    }

Erasure : 제네릭의 타입 소거

ex) 스택 구현예시와 같은 클래스가 존재할 때

public class Stack<T> {
    public T[] elements;

    public Stack(int capacity) {
        elements = (T[])new Object[capacity];
    }

    public void push(T data) {
        // ~~~
    }
}
1. 만약 파라미터가 바인딩되지않은경우 T->object
2. 바인딩된다면 그대로 진행 후 첫 번째로 들어온(바인딩된) 파라미터를 Comparable로 대체

https://sujl95.tistory.com/73 참고

skarltjr commented 3 years ago

자바의 람다식

1. 람다식 사용법

람다식을 작성하는 방법

2. 함수형 인터페이스

아래의 인터페이스가 존재한다고 했을 때

 interface MyFunction {
        public abstract int max(int a, int b);
    }

인터페이스를 구현한 익명 객체 생성은

    MyFunction f = new MyFunction() {
                          public int max(int a, int b) {
                              return a > b ? a : b;
                          }
                  };

    int big = f.max(5, 3);

★ 앞서 람다식은 익명객체와 동등하다고 했다. - 람다식으로 변환하면

MyFunction  f = (int a, int b) -> {
  return a>b ? a : b;
}

★ 주의할 점은 이러한 기능 하나의 매서드를 포함한 인터페이스일 때만 해당된다.

@FunctionalInterface를 통해 컴파일러가 검증을 해준다.

@FunctionalInterface
    interface MyFunction {
        public abstract int max(int a, int b);
    }

3. Variable Capture

자바가 이 문제를 해결하는 방법이 바로 Variable Capture

: 컴파일시점에서 멤버 매서드 내부에서 생성된 개게가 멤버 매서드 내부에서 사용되는 지역변수를 사용할 경우 객체 내부로 값을 복사해온다. 주의해야할 점은 final 키워드 or final 성격을 가진 변수만 가능하다.

++ 매서드 생성자에 대한 내용은 아래 참조 https://yadon079.github.io/2021/java%20study%20halle/week-15 참고

skarltjr commented 3 years ago

객체 지향과 데코레이터 패턴

1.

public interface Window {
    public void draw();
}

2.

public class SimpleWindow implements Window {
    @Override
    public void draw() {
        System.out.println("draw");
    }
}

3.

abstract class WindowDecorator implements Window {
    protected Window decoratedWindow;

    public WindowDecorator(Window decoratedWindow) {
        this.decoratedWindow = decoratedWindow;
    }
}

4.

public class VerticalScrollBarDecorator extends WindowDecorator {
    public VerticalScrollBarDecorator(Window decoratedWindow) {
        super(decoratedWindow);
    }

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

}

5.

public class HorizontalScrollBarDecorator extends WindowDecorator {
    public HorizontalScrollBarDecorator(Window decoratedWindow) {
        super(decoratedWindow);
    }

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

}
skarltjr commented 3 years ago

주의 ! 어떤 결과가 나올까?

class Main {
  public static void main(String[] args) {
    Integer a = 127;  // == > Integer a = Integer.valueOf(127);
    Integer b = 127;
    Integer c = 128;
    Integer d = 128;
    Integer e = 1;
    Integer f = 1;

    System.out.println(a==b);
    System.out.println(c==d);
    System.out.println(e==f);

  }
}

참고 : https://meetup.toast.com/posts/185

skarltjr commented 3 years ago

결과

99162322
1197534572
989110044
989110044

1. 메모리

2. 스레드 세이프

class Main {

public static void main(String[] args) { StringBuffer stringBuffer = new StringBuffer(); StringBuilder stringBuilder = new StringBuilder();

new Thread(() -> {
    for(int i=0; i<10000; i++) {
        stringBuffer.append(i);
        stringBuilder.append(i);
    }
}).start();

new Thread(() -> {
    for(int i=0; i<10000; i++) {
        stringBuffer.append(i);
        stringBuilder.append(i);
    }
}).start();

new Thread(() -> {
    try {
        Thread.sleep(5000);

        System.out.println("StringBuffer.length: "+ stringBuffer.length());
        System.out.println("StringBuilder.length: "+ stringBuilder.length());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

} }

#### 빌더의 값이 더 작은 것을 확인할 수 있다.
결과 :  스트링버퍼는 멀티스레드 환경에서 동시에 건드리지 못하도록 막는다. // 반면 빌더는 이런 동기화 부분이 제외됐고 결과가 다르다. 
따라서 : 멀티스레드 환경에서 스레드 세이프한 스트링버퍼 사용

StringBuffer.length: 77780 StringBuilder.length: 46982

- 그럼 마냥 StringBuffer가 좋느냐? -> 동기화는 그만큼 오버헤드발생. 성능에 따라 빌더를 사용
참고 : https://novemberde.github.io/2017/04/15/String_0.html

--- 직접 작성 쓰레드 코드

class Main { public static void main(String[] args) { StringBuilder bl= new StringBuilder(); StringBuffer bf = new StringBuffer();

class Mythread extends Thread{
@Override
public void run(){
  for(int i=0;i<10000;i++){
    bf.append(i);
    bl.append(i);
  }
}

public void check(){
    System.out.println("buffer = "+bf.length());
    System.out.println("builder = "+bl.length());
  }
}

Mythread mt1 = new Mythread();
Mythread mt2 = new Mythread();

mt1.start();
mt2.start();

Mythread mt3 = new Mythread();
try{
    mt3.sleep(10000);
    mt3.check();
}catch (InterruptedException e) {
    e.printStackTrace();
}

} }

결과

buffer = 77780 builder = 51572


- 예외로 당연히 조인을 추가한다면 mythread1이 끝날 때 까지 기다리기 때문에 둘 다 같은 값. 정상적으로 나온다

mythread1.start(); try { mythread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } mythread2.start();

skarltjr commented 3 years ago

정적 멤버 클래스

simple ex)

main

class Main {
  public static void main(String[] args) {
      Myclass ss = new Myclass(3);
      ss.getMadeId();
  }
}

Myclass / Idmaker

public class Myclass{
  private int count = 100;
  private int id = 0;

  Myclass(){
  }
  Myclass(int count){
    this.count = count;
    System.out.println("turn = a");
  }

  void getMadeId(){
    System.out.println("turn = b");
    this.id = new Idmaker(0).getId();
    System.out.println("turn = d");
    System.out.println(this.id);
  }

  private static class Idmaker{
    private int id = 0;
    Idmaker(int count){
        this.id = count + 123;
        System.out.println("turn = c");
    }

    private int getId(){
      return this.id;
    }    
  }
}

turn a / turn b / turn c / turn d 순서 봐보기

skarltjr commented 3 years ago

자바 제네릭 - 배열과 리스트

공변과 불공변


- 위 코드에서 배열과 리스트는 어떤 차이가 있을까?
- 에러 발생의 시점에 차이가 있다.
✔︎ 위 상황에서 배열은 런타임 시점에 ArrayStoreException가 나온다
✔︎ 리스트는 런타임 x, 컴파일 시점에 이미 에러가 잡힌다.
- 즉 제네릭 - 배열 / 리스트에서 배열은 프로그램이 이미 실행된 후 에러가 발생하지만 리스트는 실행하기 전 미리 에러를 파악할 수 있다는 장점이 있다.
skarltjr commented 3 years ago

프록시와 프록시 패턴(디자인 패턴)

프록시

프록시 패턴

skarltjr commented 3 years ago

자바 리플렉션

리플렉션이란?

@Controller
@RequestMapping("/articles")
public class ArticleController {    

    @Autowired    
    private ArticleService articleService;       

    @PostMapping
    public String write(UserSession userSession, ArticleDto.Request articleDto){

    }

    @GetMapping("/{id}")
    public String show(@PathVariable int id, Model model) {

    }
}

리플렉션의 동작 방식을 알아보자


public class ArticleService {

public void foo() { System.out.println("call foo"); } }

public static void main(String[] args){ ContainerService containerService = new ContainerService();

  ArticleController articleController = containerService.getObject(ArticleController.class);

  articleController.foo();

}


-------
#### 전체적인 동작을 살펴보자
문제 상황 : articleController의 foo는 articleService의 foo를 실행한다. 그러나 컨트롤러가 articleService가 뭔지알고 가져오는가?

public class ArticleController { @AutoWired private ArticleService articleService;

public void foo(){ articleService.foo(); } }



1. main에서 `containerService.getObject(ArticleController.class);`
2. `ContainerService`의  `createInstance`매서드가 실행 -> `ArticleController`인스턴스 생성
3. `ArticleController`의 필드 중 `Autowired` 어노테이션을 가진 필드만 선별
4. `ArticleController`인스턴스의 필드 중 `Autowired`어노테이션을 가진 `ArticleService`필드 주입
이렇게 DI가 리플렉션을 통해 어떻게 주입되는지 살펴볼 수 있다.
skarltjr commented 2 years ago

결과를 예측해봐라

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

        for (int i : b) {
            System.out.println(i);
        }
int[] a = {1, 2, 3};
        int[] b = a;
        a[0] = 3;

        for (int i : b) {
            System.out.println(i);
        }

        System.out.println(a.hashCode());
        System.out.println(b.hashCode());
        // 2083562754
        // 2083562754
skarltjr commented 2 years ago

스레드를 활용하여 싱글톤 패턴 동시에 접근테스트

  1. 싱글톤

    
    public class Settings {
    private static Settings instance;
    
    public Settings() {
    }
    
    public static synchronized Settings getInstance() {
        if (instance == null) {
            instance = new Settings();
        }
        return instance;
    }

}

public class Main { public static void main(String[] args) { MyThread myThread1 = new MyThread(1); MyThread myThread2 = new MyThread(2);

    myThread1.start();
    myThread2.start();

}

}

class MyThread extends Thread { public Settings settings; private int num; public MyThread(int num) { this.num = num; }

@Override
public void run() {
    for (int i = 0; i < 10000; i++) {
        settings = Settings.getInstance();
        System.out.println(settings + " thread " + num);
    }
}

}

2. 결과는

algo.Settings@74719816 thread 2 algo.Settings@74719816 thread 1 algo.Settings@74719816 thread 2 algo.Settings@74719816 thread 1 .....

skarltjr commented 2 years ago
skarltjr commented 2 years ago

a의 값을 변경할 수 있는가? 기본적으로 final은 l value의 r value값을 고정한다. 그 말은 즉 a의 값은 Myclass("hello")의 주소값으로 고정되어있다. a의 객체의 값을 바꿀 수 있느냐? Myclass("hello") 주소를 따라가서 나오는 값을 변경한다.

skarltjr commented 2 years ago

자바의 this keyword

자바의 'this' keyword는 이 클래스를 기반으로 생성된 인스턴스를 가리키는 참조

잘 생각해보자.
this는 인스턴스를 가리키는! 참조
인스턴스 자체가 아니다!
public class Temp {

    public Temp getTempClass() {
        return this;
    }
}

이와같은 클래스가 존재한다고 해보자
this는 해당 클래스로 생성된 인스턴스를 가리키는 참조

그렇다면 아래의 결과는 어떨까?
public class Main {
    public static void main(String[] args) throws IOException {
        Temp temp = new Temp();

        System.out.println(temp.hashCode());
        System.out.println(temp.getTempClass().hashCode());

        System.out.println(temp == temp.getTempClass());
        System.out.println(temp.equals(temp.getTempClass()));
    }
}

747464370
747464370
true
true

결국 this 키워드는 인스턴스를 가리키는 참조로 temp 인스턴스를 가리키는 참조를 따라가보면 temp가 나온다
skarltjr commented 2 years ago

Java 직렬화

직렬화란??

직렬화란

자바 시스템 내부에서 사용되는 object 또는 Data를 외부의 자바 시스템에서도 사용할 수 있도록 바이트 형태로 데이터를 변환하는 기술
- jvm의 메모리에 상주되어 있는 객체 데이터를 바이트 형태로 변환
- JVM의 메모리에만 상주되어 있는 객체 데이터를 그대로 영속화(persist)가 필요할 때 사용

장점 : 
- 시스템이 종료되더라도 없어지지 않는 장점을 가지며 영속화된 데이터이기 때문에 네트워크로 전송도 가능. 
- 필요할 때 직렬화 된 객체 데이터를 가져와서 역직렬화하여 객체를 바로 사용
⭐️단점 :
- 직렬화를 통해 변환된 바이트 형태의 데이터를 역직렬화 할 때 이전 객체와 동일한 객체여야한다
- 즉 자주 변경되는 비즈니스적인 데이터를 Java 직렬화을 사용하면 문제가 발생
- 따라서 serialVersionUID를 통해 관리가 필요

정리하자면 직렬화는 장점만큼 단점이 뚜렷하다
jvm 메모리에 상주하는 객체 데이터를 영속화하여 편리하게 사용할 수 있지만 변경에 굉장히 취약
개발자가 직접 컨트롤이 가능한 클래스의 객체가 아니라면 직렬화를 지양해야한다.