import java.util.*;
import java.io.*;
public class Main {
public static int A;
public static int B;
public static boolean bOkay=true;
public static ArrayList<String> anws=new ArrayList<>();
public static void Prints(){
System.out.println();
for(int i=0;i<B;i++){
for(int j=0;j<A;j++){
if(maps[i][j].bCheck==true){
System.out.print(1+",");
}else{
System.out.print(0+",");
}
}
System.out.println();
}
System.out.println();
}
public static class Robot{
public int x;
public int y;
public int dir;
public Robot(int x,int y, int dir){
this.x=x;
this.y=y;
this.dir=dir;
}
}
public static class RMaps{
public int rnum;
public boolean bCheck=false;
public RMaps(int rnum, boolean bCheck){
this.rnum=rnum;
this.bCheck=bCheck;
}
}
public static class TestCommand{
public int r;
public char command;
public int loop;
public TestCommand(int r,char command, int loop){
this.r=r;
this.command=command;
this.loop=loop;
}
}
public static void forword(int x, int y,int dir,int rnum){
switch (dir){
case 0:
//n
int checkY=y-1;
if(checkY<0){
//wall
int tmp=rnum+1;
String tmpAnw="Robot "+tmp+" crashes into the wall";
anws.add(tmpAnw);
bOkay=false;
break;
}
if(maps[checkY][x].bCheck==true){
//robot collision
int tmp=rnum+1;
int tmp2=maps[checkY][x].rnum+1;
String tmpAnw="Robot "+tmp+" crashes into robot "+tmp2;
anws.add(tmpAnw);
bOkay=false;
break;
}
robots.get(rnum).y=checkY;
break;
case 1:
//w
int checkX=x-1;
if(checkX<0){
int tmp=rnum+1;
String tmpAnw="Robot "+tmp+" crashes into the wall";
anws.add(tmpAnw);
bOkay=false;
break;
}
if(maps[y][checkX].bCheck==true){
//robot collision
int tmp=rnum+1;
int tmp2=maps[y][checkX].rnum+1;
String tmpAnw="Robot "+tmp+" crashes into robot "+tmp2;
anws.add(tmpAnw);
bOkay=false;
break;
}
robots.get(rnum).x=checkX;
break;
case 2:
//s
int checkY2=y+1;
if(checkY2>=B){
//wall
int tmp=rnum+1;
String tmpAnw="Robot "+tmp+" crashes into the wall";
anws.add(tmpAnw);
bOkay=false;
break;
}
if(maps[checkY2][x].bCheck==true){
//robot collision
int tmp=rnum+1;
int tmp2=maps[checkY2][x].rnum+1;
String tmpAnw="Robot "+tmp+" crashes into robot "+tmp2;
anws.add(tmpAnw);
bOkay=false;
break;
}
robots.get(rnum).y=checkY2;
break;
case 3:
int checkX2=x+1;
if(checkX2>=A){
//wall
int tmp=rnum+1;
String tmpAnw="Robot "+tmp+" crashes into the wall";
anws.add(tmpAnw);
bOkay=false;
break;
}
if(maps[y][checkX2].bCheck==true){
//robot collision
int tmp=rnum+1;
int tmp2=maps[y][checkX2].rnum+1;
String tmpAnw="Robot "+tmp+" crashes into robot "+tmp2;
anws.add(tmpAnw);
bOkay=false;
break;
}
robots.get(rnum).x=checkX2;
break;
default:
break;
}
}
public static RMaps maps[][];
public static ArrayList<Robot> robots=new ArrayList<>();
public static ArrayList<TestCommand> testCommands=new ArrayList<>();
public static void main(String[] args) throws Exception {
Scanner scan= new Scanner(System.in);
A=scan.nextInt(); //5
B=scan.nextInt(); //4
maps=new RMaps[B][A];//4 x 5
int n=scan.nextInt();
int m=scan.nextInt();
for(int i=0;i<B;i++){//y 4
for(int j=0;j<A;j++){//x 5
maps[i][j]=new RMaps(-1,false);
}
}
for(int i=0;i<n;i++){
int x=scan.nextInt()-1; // 5
int y=B-scan.nextInt(); // 4
String dir=scan.next();
int d=0;
if(dir.charAt(0)=='N'){
d=0;
}else if(dir.charAt(0)=='W'){
d=1;
}
else if(dir.charAt(0)=='S'){
d=2;
}
else if(dir.charAt(0)=='E'){
d=3;
}
robots.add(new Robot(x,y,d));
maps[y][x].bCheck=true;
maps[y][x].rnum=i;
}
//Prints();
for(int i=0;i<m;i++){
int r=scan.nextInt();
String command=scan.next();
int loop=scan.nextInt();
testCommands.add(new TestCommand(r,command.charAt(0),loop));
}
for(int t=0;t<testCommands.size();t++){
int rnum=testCommands.get(t).r-1;
char commad=testCommands.get(t).command;
int loop =testCommands.get(t).loop;
int initx=robots.get(rnum).x;
int inity=robots.get(rnum).y;
bOkay=true;
for(int i=0;i<loop;i++){
int x=robots.get(rnum).x;
int y=robots.get(rnum).y;
int dir=robots.get(rnum).dir;
switch(commad){
case 'L':
dir=dir+1;
robots.get(rnum).dir=dir%4;
break;
case 'R':
dir=dir-1;
if(dir<0){
dir=3;
}
robots.get(rnum).dir=dir%4;
break;
case 'F':
forword(x,y,dir,rnum);
if(bOkay==false){
i=loop+1;
continue;
}
break;
default:
break;
}
}
if(bOkay==true){
maps[inity][initx].bCheck=false;
maps[inity][initx].rnum=-1;
maps[robots.get(rnum).y][robots.get(rnum).x].rnum=rnum;
maps[robots.get(rnum).y][robots.get(rnum).x].bCheck=true;
//Prints();
//System.out.println(robots.get(rnum).x+","+robots.get(rnum).y+","+robots.get(rnum).dir);
}
if(anws.size()>0){
break;
}
}
if(anws.size()>0){
System.out.print(anws.get(0));
}else{
System.out.print("OK");
}
}
}
먼저 hibernate 란 뭘까? Hibernate는 자바 기반의 객체 관계 매핑(ORM) 라이브러리입니다. ORM은 객체 지향 프로그래밍 언어를 사용하여 데이터베이스와의 상호작용을 추상화하는 프로그래밍 기법 중 하나로, 개발자가 객체 지향적인 방식으로 데이터베이스를 다룰 수 있게 해줍니다. Hibernate는 이 ORM을 구현한 대표적인 프레임워크 중 하나입니다. Hibernate의 주요 목적은 Java 어플리케이션에서 사용하는 데이터베이스 작업을 단순화하고, 데이터베이스와 객체 사이의 불일치를 해결하는 것입니다. 이를 통해 개발자는 복잡한 JDBC(Java Database Connectivity) 코드를 작성하는 대신, 더 간결하고 객체 지향적인 코드로 데이터베이스 작업을 수행할 수 있습니다. -chat gpt- chat gpt 선생님께서는 이렇게 설명하신다.역시나 정확하시다.
그냥 쉽게 탑 , 바텀, 왼쪽, 오른쪽으로 천천히 시계방향으로 회전시킨다고 생각하면 쉽게 풀립니다.
임의의 숫자는 백트래킹으로 순서를 정해주면 됩니다.
import java.util.*;
import java.lang.*;
import java.io.*;
public class Main {
public static int initmaps[][];
public static int maps[][];
public static int copymaps[][];
public static boolean bCheck[];
public static int n;
public static int m;
public static int k;
public static int mins =0;
public static ArrayList<TestCommand>testCommands=new ArrayList<>();
public static ArrayList<TestCommand>testSaveCommands=new ArrayList<>();
public static class TestCommand{
public int r;
public int c;
public int s;
public TestCommand(int r, int c, int s){
this.r=r;
this.c=c;
this.s=s;
}
}
public static void prtints(int maps[][],int n, int m){
System.out.println("");
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
System.out.print(maps[i][j]+",");
}
System.out.println("");
}
}
public static void rotation(int startr,int endr,int startc ,int endc){
//top
for(int i=startc; i < endc ;i++){
copymaps[startr][i+1] =maps[startr][i];
}
//left
for(int i=startr+1; i<=endr ;i++){
copymaps[i-1][startc] =maps[i][startc];
}
//right
for(int i=startr; i<endr ;i++){
copymaps[i+1][endc] =maps[i][endc];
}
//bottom
for(int i=startc+1 ; i<=endc ; i++){
copymaps[endr][i-1] =maps[endr][i];
}
}
public static void gRotation(int mr,int mc, int ms){
//make range
int startR = mr - ms - 1;
int endR = mr + ms - 1;
int startC = mc - ms - 1;
int endC = mc + ms - 1;
//rotation
for(int i=0;i<ms;i++){
rotation(startR+i,endR-i,startC+i,endC-i);
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
int tmp=copymaps[i][j];
maps[i][j]=tmp;
}
}
}
public static void backtracking(int cnt){
if(cnt>=k){
//prtints(maps,n,m);
for(int i=0;i<testSaveCommands.size();i++){
//System.out.println("r"+testSaveCommands.get(i).r);
gRotation(testSaveCommands.get(i).r,testSaveCommands.get(i).c, testSaveCommands.get(i).s);
}
//prtints(maps,n,m);
//System.out.println("");
for(int i=0;i<n;i++){
int sum=0;
for(int j=0;j<m;j++){
sum+=maps[i][j];
}
if(sum<=mins||mins==0){
mins=sum;
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
int tmp =initmaps[i][j];
maps[i][j]=tmp;
copymaps[i][j]=tmp;
}
}
}
for(int i=0;i<k;i++){
if(bCheck[ i ]==false){
bCheck[ i ]=true;
testSaveCommands.add( testCommands.get( i ) );
backtracking(cnt+1 );
testSaveCommands.remove( testSaveCommands.size()-1);
bCheck[ i ]=false;
}
}
}
public static void main(String[] args) throws Exception {
Scanner scan= new Scanner(System.in);
n=scan.nextInt();
m=scan.nextInt();
k=scan.nextInt();
maps=new int[n][m];
initmaps=new int[n][m];
copymaps=new int[n][m];
bCheck=new boolean[k];
//make map
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
int tmp =scan.nextInt();
maps[i][j]=tmp;
copymaps[i][j]=tmp;
initmaps[i][j]=tmp;
}
}
for(int z=0;z<k;z++) {
int r = scan.nextInt();
int c = scan.nextInt();
int s = scan.nextInt();
testCommands.add(new TestCommand(r,c,s));
}
//backtracking
for(int i=0;i<testCommands.size();i++){
if(bCheck[i]==false) {
bCheck[i] = true;
testSaveCommands.add(testCommands.get(i));//341
backtracking(1 );
testSaveCommands.remove(testSaveCommands.size()-1);
//testSaveCommands.remove(testCommands.size()-i);
bCheck[i] = false;
}
}
System.out.print(mins);
}
}
기존에는 spring jpa에 대해서만 좀 많이 사용하다보니 순수 jpa에 대해서는 관련해서 작성해보려고 합니다.
일단 아래 구조를 보겠습니다.
Spring 에서 제공하는건 Repository를 통해서 훨씬 편리하게 jpa를 이용했는데요. 순수하게 jpa를 사용하는 상황도 있겠죠. Spring 자체도 사람이 만든거라 완벽한게 아니기 때문에 알아둘 필요는 있을거 같습니다.
순수 자바 JPA 란? 순수 자바 JPA (Java Persistence API)는 자바 표준 ORM (Object-Relational Mapping) 기술입니다. JPA를 사용하면 자바 객체와 데이터베이스 테이블 간의 매핑을 구성하여, 객체 지향적인 방식으로 데이터베이스를 다룰 수 있습니다. 순수 JPA API를 사용하는 경우, Spring과 같은 추가 프레임워크에 의존하지 않고, JPA 스펙을 직접 구현하는 방식으로 작업합니다. 이러한 접근 방식은 애플리케이션의 데이터 접근 계층에서 높은 수준의 이식성과 유연성을 제공합니다.
사용 예시
persistence.xml 설정 파일 작성: JPA를 사용하기 위해서는 META-INF/persistence.xml 파일에 영속성 유닛 설정을 정의해야 합니다. 이 파일에는 데이터베이스 연결 설정, 엔터티 매니저 설정 등이 포함됩니다.
EntityManagerFactory 생성: 애플리케이션이 시작할 때 Persistence 클래스를 사용하여 EntityManagerFactory 인스턴스를 생성합니다. 이 인스턴스는 애플리케이션의 생명주기 동안 단 하나만 존재해야 합니다.
EntityManager 생성: 데이터베이스 작업을 수행할 때마다 EntityManagerFactory를 통해 EntityManager 인스턴스를 생성합니다. EntityManager는 데이터베이스 작업을 수행하는 데 사용됩니다.
트랜잭션 관리: 데이터베이스 작업을 수행하기 전에 트랜잭션을 시작해야 합니다. EntityManager를 사용하여 트랜잭션을 시작하고, 작업이 완료된 후에는 트랜잭션을 커밋하거나 롤백합니다.
엔터티 작업 수행: EntityManager를 사용하여 엔터티를 생성, 조회, 수정, 삭제하는 등의 작업을 수행할 수 있습니다.
리소스 정리: 작업이 완료되면 EntityManager를 닫고, 애플리케이션이 종료될 때 EntityManagerFactory를 닫아야 합니다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("YourPersistenceUnit");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// 엔터티 작업 수행
// 예: 엔터티 저장
MyEntity myEntity = new MyEntity();
em.persist(myEntity);
em.getTransaction().commit();
em.close();
emf.close();
JPA API (Java Persistence API)란? JPA API (Java Persistence API)는 자바 애플리케이션에서 관계형 데이터베이스를 사용하는 방식을 표준화한 인터페이스 모음입니다. JPA는 자바 EE (Enterprise Edition)의 일부로, 자바 SE (Standard Edition) 애플리케이션에서도 사용될 수 있습니다. 이 API는 객체-관계 매핑 (ORM) 기능을 제공하여, 자바 개발자가 데이터베이스 테이블을 자바 객체로 매핑하고 관리할 수 있게 해줍니다
JPA API의 주요 목적과 기능
표준화된 ORM 지원: JPA는 엔터티(Entity)라고 하는 자바 객체와 데이터베이스 테이블 간의 매핑을 통해 ORM을 구현합니다. 이를 통해, 개발자는 데이터베이스 작업을 객체 지향적인 방식으로 수행할 수 있습니다.
데이터베이스 독립성: JPA를 사용하면 데이터베이스 작업을 데이터베이스에 특화된 SQL 문법 없이 수행할 수 있습니다. 이는 애플리케이션이 특정 데이터베이스 기술에 종속되지 않도록 해줍니다.
표준 API 제공: JPA는 EntityManager와 같은 일련의 API를 제공합니다. 이 API를 통해 엔터티의 생명 주기를 관리하고, CRUD (Create, Read, Update, Delete) 작업을 수행할 수 있습니다.
쿼리 언어: JPA는 JPQL (Java Persistence Query Language)과 Criteria API를 포함하여, 타입 안전 쿼리 작성을 지원합니다. 이를 통해 복잡한 조회 작업도 객체 지향적으로 처리할 수 있습니다.
트랜잭션 관리: JPA는 트랜잭션 관리를 위한 API를 제공합니다. 이를 통해 개발자는 데이터의 일관성을 유지하면서 데이터베이스 작업을 수행할 수 있습니다.
JPA 작동 원리
JPA의 핵심은 엔터티 매니저 (EntityManager)에 있습니다. 엔터티 매니저는 엔터티의 생성, 조회, 업데이트, 삭제 등의 작업을 관리합니다. 엔터티 매니저는 영속성 컨텍스트라는 컨테이너 안에서 엔터티의 생명 주기를 관리합니다. 영속성 컨텍스트는 엔터티의 상태를 관리하며, 데이터베이스와의 동기화를 담당합니다. 개발자는 JPA의 EntityManager를 사용하여 엔터티와 관련된 작업을 수행합니다. 예를 들어, 엔터티를 생성하고 데이터베이스에 저장하기 위해서는 persist 메소드를 사용하고, 데이터베이스에서 엔터티를 조회하기 위해서는 find나 JPQL, Criteria API 등을 사용할 수 있습니다. JPA를 사용함으로써, 개발자는 데이터베이스와의 상호작용을 추상화된 형태로 다루면서도, 데이터베이스 작업을 효율적이고 표준화된 방식으로 수행할 수 있게 됩니다. JPA는 개발자로 하여금 데이터베이스 작업에 드는 시간과 노력을 줄이고, 애플리케이션의 이식성과 유지보수성을 향상시키는 데 도움을 줍니다.
그렇다면 다음엔 hibernate, jpa, database 관계에 대해서 코드로 확인하며 작성해보도록 하겠습니다.
getDeclaredConstructor().newInstance()는 자바 Reflection API의 일부로 사용되며, 클래스의 새 인스턴스를 동적으로 생성할 때 사용됩니다. Reflection API를 사용하면 실행 시간(runtime)에 프로그램의 구조를 검사하고 조작할 수 있습니다. 이것은 특히 클래스의 타입이 컴파일 타임에 알려지지 않았을 때 유용합니다.
getDeclaredConstructor(): 이 메소드는 호출되는 클래스의 지정된 파라미터를 가진 생성자를 반환합니다. 파라미터가 없으면 기본 생성자를 반환합니다.
newInstance(): getDeclaredConstructor() 메소드로 얻은 생성자를 사용하여 클래스의 새 인스턴스를 생성합니다. 이 메소드는 해당 생성자의 public, protected, private에 관계없이 어떤 접근 제한자를 가진 생성자든지 인스턴스화할 수 있습니다.
getDeclaredConstructor().newInstance()를 사용하는 예제 코드입니다:
import java.util.HashMap;
import java.util.Map;
public class InstanceFactory {
private Map<String, Class<?>> classMap = new HashMap<>();
public InstanceFactory() {
// Here we map strings to classes
classMap.put("MyClass", MyClass.class);
// Add other classes to the map as needed
}
public Object createInstance(String key) throws Exception {
Class<?> clazz = classMap.get(key);
if (clazz != null) {
return clazz.getDeclaredConstructor().newInstance();
}
return null;
}
public static void main(String[] args) {
InstanceFactory factory = new InstanceFactory();
try {
Object myClassInstance = factory.createInstance("MyClass");
// Use myClassInstance as needed
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MyClass {
// MyClass definition
}
문자열 키를 입력받고 classMap에서 해당하는 Class<?> 객체를 찾은 다음, 리플렉션을 사용하여 해당 클래스의 새 인스턴스를 생성하는 createInstance 메소드를 가지고 있습니다.
즉 classMap 키 값을 가지는 클래스들 put하여 다른 클래스들도 이용이 가능하겠죠.
예를들어 vehicle inteface가 존재한다면 class car, bus, train 을 상속받아 쓴다고 가정하면 손쉽게 클래스명의 hash 키를 통하여 동적으로 클래스 인스턴스를 생성하여 사용할수 있습니다.
자바에서 클래스나 인터페이스의 메타데이터를 읽어와서 실행 시간에 객체의 속성, 메소드, 생성자 등을 검사하거나 조작할 수 있게 해주는 기능입니다. 이 API를 사용하면 컴파일 타임에는 알려지지 않은 클래스의 객체를 생성하고, 메소드를 호출하며, 필드에 접근할 수 있습니다. 다시 말해서, 자바의 Reflection API를 사용하면 컴파일된 자바 코드 내부를 동적으로 탐색하고, 코드의 구조를 분석하며, 수정할 수 있게 됩니다.
Reflection API의 장단점
장점:
IDE나 디버깅 툴에서 코드의 구조를 분석할 때
컴파일 타임에 클래스의 타입이 결정되지 않는 프레임워크나 애플리케이션 개발 시
리플렉션을 이용해 특정 어노테이션을 분석하고 그에 따른 처리를 할 때
런타임에 사용자의 입력에 따라 다른 클래스의 메소드를 실행시키는 어플리케이션 개발 시
Reflection API의 중요 클래스와 인터페이스에는 Class, Method, Field, Constructor, Array, ReflectPermission 등이 있습니다. 예를 들어 Class 객체는 forName() 메소드를 통해 이름으로부터, 또는 .class 문법을 통해 직접 클래스를 로딩하여 얻을 수 있으며, 이를 통해 해당 클래스의 정보를 얻거나 객체를 생성할 수 있습니다.
단점:
Reflection API는 강력한 만큼 주의해서 사용해야 합니다. 이 API를 사용하면 private 멤버에 접근하거나 수정할 수 있어 보안 문제를 일으킬 수 있으며, 예외 처리를 제대로 하지 않을 경우 예기치 않은 문제를 야기할 수 있습니다. 또한, Reflection을 사용한 코드는 보통 직접적인 코드 호출보다 성능이 떨어지므로 성능에 민감한 애플리케이션에서는 사용을 자제하는 것이 좋습니다.
활용:
Reflection은 애플리케이션 개발보다는 프레임워크나 라이브러리에서 많이 사용된다. 프레임워크나 라이브러리는 사용자가 어떤 클래스를 만들지 예측할 수 없기 때문에 동적으로 해결해주기 위해 Reflection을 사용한다.
실제로 intellij의 자동완성, jackson 라이브러리, Hibernate 등등 많은 프레임워크나 라이브러리에서 Reflection을 사용하고 있다.
Spring Framework에서도 Reflection API를 사용하는데 대표적으로 Spring Container의 BeanFactory가 있다. Bean은 애플리케이션이 실행한 후 런타임에 객체가 호출될 때 동적으로 객체의 인스턴스를 생성하는데 이때 Spring Container의 BeanFactory에서 리플렉션을 사용한다.
Spring Data JPA 에서 Entity에 기본 생성자가 필요한 이유도 동적으로 객체 생성 시 Reflection API를 활용하기 때문이다. Reflection API로 가져올 수 없는 정보 중 하나가 생성자의 인자 정보이다. 그래서 기본 생성자가 반드시 있어야 객체를 생성할 수 있는 것이다. 기본 생성자로 객체를 생성만 하면 필드 값 등은 Reflection API로 넣어줄 수 있다.