# JAVA15

* ## 문자열 처리

문자열 붙이기 과거에는 "" +"" 혹은 StringBuilder 혹은 StringBuffer 객체를 이용해서 무한 append 했었죠.

```java
String html = 
    "<html>\n" +
    "<body>\n"+
    "  <h1>Java 15 새로운 문자열 붙이기...완전 좋네요!</h1>\n"+
    "  <p>didispace.com</p>\n"+
    "</body>\n"+
    "</html>\n";
```

```java
StringBuilder sb = new StringBuilder();
sb.append("abc");
sb.append("def");
sb.append("ghi");
```

```java
StringBuffer sb = new StringBuffer();
sb.append("abc");
sb.append("def");
sb.append("ghi");
```

하지만 JAVA 15부터 아래와 같이 쓸수 있게 되었네요. "" 아닌 """ (3개)를 쓰면 됩니다. 줄바꿈 자유롭게 할수 있습니다.

```
String html = """
    <html>
    <body>
      <h1>Java 15 새로운 문자열 붙이기...완전 좋네요!</h1>
      <p>didispace.com</p>
    </body>
    </html>
    """;
```

### 히든 클래스

다른 class의 bytecode에서 직접 사용할 수 없는 class이다. Hidden class는 runtime에 class를 생성하고 reflection을 통해 간접적으로 사용하는 framework에서 사용하기 위한 것이다. hidden class는 access 제어 중첩의 member로 정의될 수 있으며 다른 class와 독립적으로 unload 될 수 있다.

일반 클래스 하나 생성해 보자

```java
public class JEP371HiddenClasses {

    public static String hello() {
        return "https://rainsister.tistory.com";
    }

}
```

해당 클래스를 컴파일 하고 나서

```java
String filePath = "JEP371HiddenClasses.class";
byte[] b = Files.readAllBytes(Paths.get(filePath));
log.info(Base64.getEncoder().encodeToString(b));
```

아래와 같은 코드(문자열)을 얻을 수 있다.

```
yv66vgAAAD0AFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAZaHR0cHM6Ly93d3cuZGlkaXNwYWNlLmNvbQcACgEALmNvbS9kaWRpc3BhY2UvZGVidWcvamF2YTE1L0pFUDM3MUhpZGRlbkNsYXNzZXMBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAMExjb20vZGlkaXNwYWNlL2RlYnVnL2phdmExNS9KRVAzNzFIaWRkZW5DbGFzc2VzOwEABWhlbGxvAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAYSkVQMzcxSGlkZGVuQ2xhc3Nlcy5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAGAAEAEgAAAAIAEw==

```

## 리텐션(Retention)을 이용하여 위에서 작성한 클래스를 로등하여 히든클래스의 hello함수를 호출할수 있다.

```java
@Test
void testHiddenClasses() throws Throwable {
  // 1.히든클래스 로딩 
  String CLASS_INFO = "yv66vgAAAD0AFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAZaHR0cHM6Ly93d3cuZGlkaXNwYWNlLmNvbQcACgEALmNvbS9kaWRpc3BhY2UvZGVidWcvamF2YTE1L0pFUDM3MUhpZGRlbkNsYXNzZXMBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAMExjb20vZGlkaXNwYWNlL2RlYnVnL2phdmExNS9KRVAzNzFIaWRkZW5DbGFzc2VzOwEABWhlbGxvAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAYSkVQMzcxSGlkZGVuQ2xhc3Nlcy5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAGAAEAEgAAAAIAEw==";
  byte[] classInBytes = getDecoder().decode(CLASS_INFO);

  Class<?> proxy = MethodHandles.lookup()
    .defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE)
    .lookupClass();

  // class name 
  log.info(proxy.getName());
  // class에 어떤 함수가 있는지 보여주기
  for(Method method : proxy.getDeclaredMethods()) {
    log.info(method.getName());
  }
  // 2. hello함수 호출
  MethodHandle mh = MethodHandles.lookup().findStatic(proxy, "hello", MethodType.methodType(String.class));
  String result = (String) mh.invokeExact();
  log.info(result);
}
```

여기서 CLASS\_INFO 는 아까 출력된 문자열들이다.&#x20;

일단 Base64 로 해당 코드를 복호화하고 리텐션을 이용하여 히든클래스의 프록시를 생성한다.

```java
Class<?> proxy = MethodHandles.lookup()
    .defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE)
    .lookupClass();

```

이분을 유심히 살펴보면 히든클래스 생성이랑 ,일반 클래스 생성차이를 알수 있다.

* bytes：jvm 규격의 바이트 코드.
* initialize： 클래스 코기화 진행 여부.
* options：java 클래스 타입 -> 여기를 `java.lang.invoke.MethodHandles.Lookup.ClassOption 확인하면 됨.`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://blakes-organization.gitbook.io/rainsister/java/java15.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
