JAVA15
문자열 붙이기 과거에는 "" +"" 혹은 StringBuilder 혹은 StringBuffer 객체를 이용해서 무한 append 했었죠.
String html =
"<html>\n" +
"<body>\n"+
" <h1>Java 15 새로운 문자열 붙이기...완전 좋네요!</h1>\n"+
" <p>didispace.com</p>\n"+
"</body>\n"+
"</html>\n";
StringBuilder sb = new StringBuilder();
sb.append("abc");
sb.append("def");
sb.append("ghi");
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 될 수 있다.
일반 클래스 하나 생성해 보자
public class JEP371HiddenClasses {
public static String hello() {
return "https://rainsister.tistory.com";
}
}
해당 클래스를 컴파일 하고 나서
String filePath = "JEP371HiddenClasses.class";
byte[] b = Files.readAllBytes(Paths.get(filePath));
log.info(Base64.getEncoder().encodeToString(b));
아래와 같은 코드(문자열)을 얻을 수 있다.
yv66vgAAAD0AFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAZaHR0cHM6Ly93d3cuZGlkaXNwYWNlLmNvbQcACgEALmNvbS9kaWRpc3BhY2UvZGVidWcvamF2YTE1L0pFUDM3MUhpZGRlbkNsYXNzZXMBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAMExjb20vZGlkaXNwYWNlL2RlYnVnL2phdmExNS9KRVAzNzFIaWRkZW5DbGFzc2VzOwEABWhlbGxvAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAYSkVQMzcxSGlkZGVuQ2xhc3Nlcy5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAGAAEAEgAAAAIAEw==
리텐션(Retention)을 이용하여 위에서 작성한 클래스를 로등하여 히든클래스의 hello함수를 호출할수 있다.
@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 는 아까 출력된 문자열들이다.
일단 Base64 로 해당 코드를 복호화하고 리텐션을 이용하여 히든클래스의 프록시를 생성한다.
Class<?> proxy = MethodHandles.lookup()
.defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE)
.lookupClass();
이분을 유심히 살펴보면 히든클래스 생성이랑 ,일반 클래스 생성차이를 알수 있다.
bytes:jvm 규격의 바이트 코드.
initialize: 클래스 코기화 진행 여부.
options:java 클래스 타입 -> 여기를
java.lang.invoke.MethodHandles.Lookup.ClassOption 확인하면 됨.
Last updated