덤프뜨기 (백업하기)


mysqldump -u (사용자이름[ex:root]) -p 백업할데이터베이스명 테이블명1 테이블명2  > 백업파일명.sql


mysqldump -u (사용자이름[ex:root]) -p --all-databases > 백업파일명.sql


특정 데이터베이스를 덤프하거나 모든 DB를 백업하는 방법이다.

테이블명을 입력하면 입력한 테이블명만 dump되고 

데이터베이스 안에 모든 테이블을 받으려면 입력하지 않으면 된다.




덤프저장 (백업복구)


mysql -u (사용자이름[ex:root]) -p 복구할데이터베이스명 < 백업파일명.sql


mysql -u (사용자이름[ex:root]) -p  < 백업파일명.sql


특정 데이터베이스를 덤프하거나 모든 DB를 복구하는 방법이다.

복구는 테이블 한개든 여러개든 전부든 테이블명을 입력하지 않아도 된다.

새로운 프로젝트 수정건을 받고 프로젝트에 맞게 톰캣7 과 JDK1.7을 설정해 주고 MAVEN인스톨을 했더니 제목과 같은 에러가 났다.


........................ Received fatal alert: protocol_version -> [Help 1] 


프로토콜버전이 맞지 않은거 같은데 나의 얇디 얆은 지식으로 해결할 수가 없어 바로 구글링을 하는 도중


MAVEN Repositoey가 https [TLS v1.2] 프로토콜로 연결되어야 하는데 


JDK 1.7 버전은 TLS v1.0 ~ v1.1이 기본값이라 프로토콜 버전이 달라서 에러가 났다는걸 알았다.


알아본 해결 방안으로는

1. jdk1.8 이상 버전을 사용하기

2. TLS v1.2로 바꾸기

2-1 System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2"); 메서드를 사용하여 https.protocols 속성을 지정해주는 방법

2-2 JVM옵션에 -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2 속성을 주는 방법


원인과 방법을 알았으나 애처롭게도 그 방법들을 적용하는 구체적인 방법은 없었으며 삽질을 계속 반복하다 쉬운 방법 하나를 발견했다.

나는 어차피 윈도우와 이클립스에서만 프로젝트 작업을 하므로 이클립스 JVM옵션을 설정해주면 되는 것이다.


eclipse가 깔려있는 디렉토리로 가면 (보통 eclipse 이름 그대로) eclipse.ini 라는 설정 파일이 있다.

여기에 2-2 방법에 나온 -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2 을 추가해주면 된다.




참고

http://sunghs.tistory.com/58

https://stackoverflow.com/questions/50946420/could-not-transfer-artifact-https-repo-maven-apache-org-maven2-received-fat

http://freestrokes.tistory.com/68


접속하기

 

$ mysql -u root -p

 

먼저 root 계정으로 접속한다.

 

 

 

사용자 확인하기

 

mysql> use mysql;

 

mysql> select host,user from user;

 

 

 

 

사용자 추가하기

 

mysql> create user '사용자'@'localhost(또는 %)' identified by '비밀번호';

 

%는 외부에서의 접근을 허용한다

 

 

 

사용자 삭제하기

 

mysql> drop user '사용자'@'localhost';

 

 

 

 

사용자에게 데이터베이스 권한 부여

 

mysql> grant all privileges on *.* to '사용자'@'localhost';

 

mysql> grant all privileges on DB이름.* to '사용자'@'localhost';

 

mysql> grant all privileges on DB이름.테이블명 to '사용자'@'localhost';

 

mysql> grant select on DB이름.테이블명 to '사용자'@'localhost';

 

mysql> grant update(컬럼1, 컬럼2) on DB이름.테이블명 to '사용자'@'localhost';

 

이렇게 특정 데이터베이스의 권한을 줄 수도 

특정 권한 ex) select 권한만 줄 수도

특정 컬럼에만 update의 권한을 줄 수도 있다.

 

all privieges 는 모든 권한을 

*.*은 모든 데이터베이스의 모든 테이블을 뜻한다.

 

@뒤에 특정 ip를 설정 할 수 있다.

특정 ip : @'192.168.1.18'

특정 ip 대역대 : @'192.168.1.%'

전체 : @'%'

 

 

사용자 생성, 권한 부여 한번에 하기

 

mysql> grant all privileges on *.* to '사용자'@'localhost' identified by '비밀번호';

 

이렇게 한번에 사용자 생성과 권한 부여를 할 수 있다.

 

 

사용자 권한 삭제하기

 

mysql> revoke all on DB이름.* from '사용자'@'localhost';

 

권한 부여와 구조가 같다. 

마찬가지로 응용해서 특정한 조건을 줄 수 있다.

 

 

변경사항 반영하기

mysql> flush privileges;

 

사용자 권한 확인하기

 

mysql> show grants for '사용자명'@'localhost';

 

 

 

java.net 패키지 


Provides the classes for implementing networking applications.

네트워킹 응용 프로그램을 구현하기위한 클래스를 제공합니다.


java api 설명에 있는 문장을 가져왔다.

이 패키지는 위 설명과 같이 네트워크 환경을 구성하고 소켓 통신 프로그래밍을 만들 수 있게 도와준다.


대표적인 클래스에 대해 알아보고 간단한 TCP소켓 프로그래밍을 해보자!



INnetAddress


자바에서는 IP주소를 다루기 위해 위 클래스를 제공하며 다음과 같은 메서드가 정의되어 있다.


 메서드

설명 

 byte[] getAddress()

 IP주소를 byte배열로 반환한다.

 static InetAddress getByAddress(byte[] addr)

 byte배열을 통해 IP주소를 얻는다.

 static InetAddress getByName(String host)

 도메인명(host)을 통해 IP주소를 얻는다.

 static InetAddress[] getAllByName(String host)

 도메인명(host)에 지정된 모든 호스트의 IP주소를 배열에 담아 반환한다.

 static InetAddress getLocalHost()

 지역호스트의 IP주소를 반환한다. 

 String getCanonicalHostName()

 Fully Qualified Domain Name을 반환한다.

 String getHostAddress()

 호스트의 IP주소를 반환한다. 

 String getHostName()

 호스트의 이름을 반환한다. 

 boolean isMulticastAddress()

 IP주소가 멀티캐스트 주소인지 알려준다. 

 boolean isLoopbackAddress()

 IP주소가 loopback 주소(127.0.0.1)인지 알려준다. 


예제를 보자


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package source.ch16;
import java.net.*;
import java.util.*;
 
class NetworkEx1 {
    public static void main(String[] args) 
    {
        InetAddress ip = null;
        InetAddress[] ipArr = null;
 
        try {
            ip = InetAddress.getByName("www.naver.com");
            System.out.println("getHostName() :"   +ip.getHostName());
            System.out.println("getHostAddress() :"+ip.getHostAddress());
            System.out.println("toString() :"      +ip.toString());
 
            byte[] ipAddr = ip.getAddress();
            System.out.println("getAddress() :"+Arrays.toString(ipAddr));
 
            String result = "";
            for(int i=0; i < ipAddr.length;i++) {
                result += (ipAddr[i] < 0) ? ipAddr[i] + 256 : ipAddr[i];
                result += ".";
            }
            System.out.println("getAddress()+256 :"+result);
            System.out.println();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
 
        try {
            ip = InetAddress.getLocalHost();
            System.out.println("getHostName() :"   +ip.getHostName());
            System.out.println("getHostAddress() :"+ip.getHostAddress());
            System.out.println();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        
 
        try {
            ipArr = InetAddress.getAllByName("www.naver.com");
 
            for(int i=0; i < ipArr.length; i++) {
                System.out.println("ipArr["+i+"] :" + ipArr[i]);
            }            
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
 
    } // main
}
cs


getHostName() :www.naver.com

getHostAddress() :210.89.164.90

toString() :www.naver.com/210.89.164.90

getAddress() :[-46, 89, -92, 90]

getAddress()+256 :210.89.164.90.


getHostName() :MSDN-SPECIAL

getHostAddress() :192.168.17.1


ipArr[0] :www.naver.com/210.89.164.90

ipArr[1] :www.naver.com/125.209.222.141


InetAddress 타입 변수로 직접 출력을 찍으면 마지막 2행처럼 도메인명/ip주소 형식으로 나온다.



URL 


URL은 Uniform Resource Location 의 줄임말로 흔히 우리가 알고있는 URL주소이다.

URL은 프로토콜://호스트명:포트번호/경로명/파일명?쿼리스트링#참조의 형태로 이루어져 있다.

이 URL을 다루기 위한 클래스로 주로 URL 구성요소를 구하는 메서드로 구성 되어있다.

모든 메서드를 나열할 순 없으니 예제를 통해 간단히 알아보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package source.ch16;
import java.net.*;
 
class NetworkEx2 {
    public static void main(String args[]) throws Exception {
        URL url = new URL("http://sleepyeyes.tistory.com/admin/entry/post/?type=post&returnURL=/manage/posts/");
 
        System.out.println("url.getAuthority() : "+ url.getAuthority());
        System.out.println("url.getDefaultPort() : "+ url.getDefaultPort());
        System.out.println("url.getPort() : "+ url.getPort());
        System.out.println("url.getFile() : "+ url.getFile());
        System.out.println("url.getHost() : "+ url.getHost());
        System.out.println("url.getPath() : "+ url.getPath());
        System.out.println("url.getProtocol() : "+ url.getProtocol());
        System.out.println("url.getQuery() : "+ url.getQuery());
        System.out.println("url.getRef() : "+ url.getRef());
        System.out.println("url.getUserInfo() : "+ url.getUserInfo());
        System.out.println("url.toURI() : "+ url.toURI());
    }
}
cs


url.getAuthority() : sleepyeyes.tistory.com

url.getDefaultPort() : 80

url.getPort() : -1

url.getFile() : /admin/entry/post/?type=post&returnURL=/manage/posts/

url.getHost() : sleepyeyes.tistory.com

url.getPath() : /admin/entry/post/

url.getProtocol() : http

url.getQuery() : type=post&returnURL=/manage/posts/

url.getRef() : null

url.getUserInfo() : null

url.toURI() : http://sleepyeyes.tistory.com/admin/entry/post/?type=post&returnURL=/manage/posts/



URLConnection


이 클래스는 어플리케이션과 URL간의 통신연결을 나타내는 클래스의 최상위 클래스로 추상클래스이다.

HttpURLConnection 과 JarURLConnection 이 상속받아 구현한 클래스이다.


이 클래스의 메서드를 이용하면 URL의 관련된 정보를 읽고 쓸 수 있다.



URLConnection의  대표 메소드


 메소드명

설명 

String getContentType()

mime타입 리턴 

getContentEncoding

인코딩 리턴

getHeaderFields()

 헤더 정보 리턴

InputStream getInputStream()

 문서를 읽기 위한 InputStream 객체 리턴








1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package source.ch16;
import java.net.*;
import java.io.*;
 
public class NetworkEx3 {
    public static void  main(String args[]) {
        URL url = null;
        String address = "http://www.kpu.ac.kr/index.do?sso=ok";
        String line = "";
 
        try {
            url = new URL(address);
            URLConnection conn = url.openConnection();
            
            System.out.println("getContentEncoding() : "+conn.getContentEncoding());
            System.out.println("getContentType() : "+conn.getContentType());
            System.out.println("getHeaderFields() : "+conn.getHeaderFields());
            
            try(InputStream raw = conn.getInputStream()){
                InputStream buffer = new BufferedInputStream(raw);
 
int c;
                while((c = buffer.read())!=-1) {
                    System.out.print((char)c);
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    } 
}
     cs


getContentEncoding() : null

getContentType() : text/html;charset=euc-kr

getHeaderFields() : {Transfer-Encoding=[chunked], null=[HTTP/1.1 200 OK], Server=[Jeus WebContainer/JEUS 5.0 (fix #27)], Connection=[Keep-Alive], Set-Cookie=[JSESSIONID=aFgKdVgDi3OMhdwQ4h20zQHP567USB0MsENPEUcpCVAH0Sa30XUgQhKCrP6aaa4v;Path=/, visitUrlGubun=kpu_1|;Path=/, logNonM=yes;Path=/], Date=[Wed, 24 Oct 2018 12:00:49 GMT], Content-Type=[text/html;charset=euc-kr]}

<!DOCTYPE HTML>

<html lang="ko">

<head>

<meta charset="euc-kr">

<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">

<meta name="format-detection" content="telephone=no">

<meta name="viewport" content="width=1000">

<link id="favicon" href="/images/favicon-32.ico" rel="shortcut icon">

....




소켓 프로그래밍


소켓이란 프로세스간의 통신에 사용되는 양쪽 끝단을 의미한다.

자바에서는 java.net패키지를 통해 소켓 프로그래밍을 지원하는데, 소켓통신에 사용되는 프로토콜에 따라 다른 종류의 소켓을 구현하여 제공한다.


크게 TCP와 UDP로 나뉘는데 이 둘의 차이는 간단하게 알아보면


-TCP 연결지향적이며, 오류제어, 흐름제어, 혼잡제어, 타이머재전송 등의 기능을 하며 연결지향이란말은 데이타를 전송하는 측과 데이타를 전송받는 측에서 전용의 데이타 전송 선로(Session)을 만든다는 의미이다. 데이타의 신뢰도가 중요하다고 판단될때 주로 사용된다.


-UDP 비연결지향이며, 최소한의 오류제어 기능만 수행한다. 단순히 데이타를 받거나, 던져주기만 하는 프로토콜이다. UDP는 특히 실시간 멀티미디어 정보를 처리하기 위해서 주로 사용한다.


http://sleepyeyes.tistory.com/4?category=747108




TCP소켓 프로그래밍

 

Socket 클래스와 ServerSocket 클래스를 제공한다.


Socket : 프로세스간의 통신을 담당하며, InputStream과 OutputStream을 가지고 있다. 이 스트림들을 이용해 프로세스간의 통신이 이루어진다.


ServerSocket : 포트와 연결(bind)되어 외부의 연결요청을 기다리다 연결요청이 오면 Socket을 생성해서 소켓과 소켓간의 통신이 이루어지도록 한다. 


실제 통신은 소켓끼리 하지만 그 소켓끼리를 연결해주는 역할을 서버소켓이 하는 것이다.

한 포트에는 하나의 서버소켓만 연결할 수 있는데 

한 포트에 둘 이상의 서버소켓이 연결된다면 클라이언트 입장에서 그 둘을 구분할 수 없기 때문이다. 


과정


간단한 예제를 보면서 이해해보자


Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package source.ch16;
 
import java.net.*;
import java.io.*;
import java.util.Date;
import java.text.SimpleDateFormat;
 
public class TcpIpServer {
    public static void main(String args[]) {
        ServerSocket serverSocket = null;
        
        try {
            //서버소켓을 생성하여 7777번 포트와 결합(bind)시킨다.
            serverSocket = new ServerSocket(7777);
            System.out.println(getTime()+"서버가 준비되었습니다.");
 
        } catch(IOException e) {
            e.printStackTrace();
        }
        
        while(true) {
            try {
                System.out.println(getTime()+"연결요청을 기다립니다.");
                // 서버소켓은 클라이언트의 연결요청이 올 때까지 실행을 멈추고 계속 기다린다.
                // 클라이언트의 연결요청이 오면 클라이언트 소켓과 통신할 새로운 소켓을 생성한다.
                Socket socket = serverSocket.accept();
                System.out.println(getTime()+ socket.getInetAddress() + "로부터 연결요청이 들어왔습니다.");
                
                // 소켓의 출력스트림을 얻는다.
                OutputStream out = socket.getOutputStream();
                DataOutputStream dos = new DataOutputStream(out);
 
                // 원격소켓(remote socket)에 데이터를 보낸다.
                dos.writeUTF("[Notice] Test Message1 from Server.");
                System.out.println(getTime()+"데이터를 전송했습니다.");
 
                // 스트림과 소켓을 닫아준다.
                dos.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } // while
    } // main
 
    // 현재시간을 문자열로 받환하는 함수
    static String getTime() {
        SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
        return f.format(new Date());
    }
// class
 
cs

client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package source.ch16;
import java.net.*;
import java.io.*;
 
public class TcpIpClient { 
    public static void main(String args[]) {
        try {
            String serverIp = "127.0.0.1";
 
            System.out.println("서버에 연결중입니다. 서버IP :" + serverIp); 
            // 소켓을 생성하여 연결을 요청한다.
// 연결하고자 하는 서버의 ip와 포트번호를 알아야한다.
            Socket socket = new Socket(serverIp, 7777); 
 
            // 소켓의 입력스트림을 얻는다.
            InputStream in = socket.getInputStream();
            DataInputStream dis = new DataInputStream(in);
 
            // 소켓으로 부터 받은 데이터를 출력한다.
            System.out.println("서버로부터 받은 메시지:"+dis.readUTF());      
            System.out.println("연결을 종료합니다.");
 
            // 스트림과 소켓을 닫는다.
            dis.close();
            socket.close();
            System.out.println("연결이 종료되었습니다.");
        } catch(ConnectException ce) {
            ce.printStackTrace();
        } catch(IOException ie) {
            ie.printStackTrace();
        } catch(Exception e) {
            e.printStackTrace();  
        }  
    } // main
// class
 
cs


위에 그림으로 본 과정과 똑같아 이해하기가 수월하다.


여기에 쓰레드를 이용하면 동시의 여러 클라이언트의 접속, 요청도 동시에 처리할 수 있고

데이터 송신과 수신도 동시에 할 수 있다.


위 두개의 기능을 다 포함시킨 예제를 마지막으로 보자


Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package source.ch16;
import java.net.*;
import java.io.*;
import java.util.*;
 
public class TcpIpMultichatServer {
    HashMap clients;
    
    
    TcpIpMultichatServer() {
        clients = new HashMap();
        Collections.synchronizedMap(clients); //동기화 처리
    }
 
    public void start() {
        ServerSocket serverSocket = null;
        Socket socket = null;
 
        try {
            serverSocket = new ServerSocket(7777);
            System.out.println("서버가 시작되었습니다.");
 
            while(true) {
                socket = serverSocket.accept();
                System.out.println("["+socket.getInetAddress()+":"+socket.getPort()+"]"+"에서 접속하였습니다.");
                ServerReceiver thread = new ServerReceiver(socket);
                thread.start();
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    } // start()
 
    //모든 클라이언트에게 채팅을 전송
    void sendToAll(String msg) {
        Iterator it = clients.keySet().iterator();
        
        while(it.hasNext()) {
            try {
                DataOutputStream out = (DataOutputStream)clients.get(it.next());
                out.writeUTF(msg);
            } catch(IOException e){}
        } // while
    } // sendToAll
 
    public static void main(String args[]) {
        new TcpIpMultichatServer().start();
    } 
    class ServerReceiver extends Thread {
        Socket socket;
        DataInputStream in;
        DataOutputStream out;
 
        ServerReceiver(Socket socket) {
            this.socket = socket;
            try {
                in  = new DataInputStream(socket.getInputStream());
                out = new DataOutputStream(socket.getOutputStream());
            } catch(IOException e) {}
        }
 
        public void run() {
            String name = "";
            try {
                name = in.readUTF();
                sendToAll("#"+name+"님이 들어오셨습니다.");
                //클라이언트 추가
                clients.put(name, out);
                System.out.println("현재 서버접속자 수는 "+ clients.size()+"입니다.");
 
                while(in!=null) {
                    sendToAll(in.readUTF());
                }
            } catch(IOException e) {
                // ignore
            } finally {
                sendToAll("#"+name+"님이 나가셨습니다.");
                //나가면 HashMap에서 제거
                clients.remove(name);
                System.out.println("["+socket.getInetAddress() +":"+socket.getPort()+"]"+"에서 접속을 종료하였습니다.");
                System.out.println("현재 서버접속자 수는 "+ clients.size()+"입니다.");
            } // try
        } // run
    } // ReceiverThread
// class
 
cs


client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package source.ch16;
import java.net.*;
import java.io.*;
import java.util.Scanner;
 
public class TcpIpMultichatClient {
    public static void main(String args[]) {
        if(args.length!=1) {
            System.out.println("USAGE: java TcpIpMultichatClient 대화명");
            System.exit(0);
        }
 
        try {
            String serverIp = "127.0.0.1";
            // 소켓을 생성하여 연결을 요청한다.
            Socket socket = new Socket(serverIp, 7777); 
            System.out.println("서버에 연결되었습니다.");
            Thread sender   = new Thread(new ClientSender(socket, args[0]));
            Thread receiver = new Thread(new ClientReceiver(socket));
 
            sender.start();
            receiver.start();
        } catch(ConnectException ce) {
            ce.printStackTrace();
        } catch(Exception e) {}
    } // main
 
    static class ClientSender extends Thread {
        Socket socket;
        DataOutputStream out;
        String name;
 
        ClientSender(Socket socket, String name) {
            this.socket = socket;
            try {
                out = new DataOutputStream(socket.getOutputStream());
                this.name = name;
            } catch(Exception e) {}
        }
 
        public void run() {
            Scanner scanner = new Scanner(System.in);
            try {
                if(out!=null) {
                    out.writeUTF(name);
                }    
 
                while(out!=null) {
                    out.writeUTF("["+name+"]"+scanner.nextLine());                    }
            } catch(IOException e) {}
        } // run()
    } // ClientSender
 
    static class ClientReceiver extends Thread {
        Socket socket;
        DataInputStream in;
 
        ClientReceiver(Socket socket) {
            this.socket = socket;
            try {
                in = new DataInputStream(socket.getInputStream());
            } catch(IOException e) {}
        }
 
        public void run() {
            while(in!=null) {
                try {
                    System.out.println(in.readUTF());
                } catch(IOException e) {}
            }
        } // run
    } // ClientReceiver
// class
 
cs


다소 복잡하지만 처음 과정도를 염두해두고 주석과 함께 천천히 보면 이해가 간다.



참고

http://diaryofgreen.tistory.com/98

http://codedragon.tistory.com/6417

https://m.blog.naver.com/PostView.nhn?blogId=tndus0450&logNo=220153206530&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F

자바의 정석 3판

Calendar 


Calendar 클래스는 추상클래스이기 때문에 직접 객체를 생성할 수 없고, 메서드를 통해서 완전히 구현된 클래스의 인스턴스를 얻어야 한다.


Calendar today = Calendar.getInstance();


System.out.println(today.get(Calendar.YEAR); 

System.out.println(today.get(Calendar.MONTH);    // ( 0~11 0:1월)

System.out.println(today.get(Calendar.DATE);

System.out.println(today.get(Calendar.DAY_OF_WEEK);    // ( 1~7 1:일요일)


처음 보고 드는 생각. 뭔가 되게 복잡해보이고 왜 월은 0부터 했는데 일은 또 1부터 시작하며 요일에 시작이 일요일이라 헷갈리네..

또 메소드만으로 불러지지 않고 클래스 변수를 매개변수로 사용하여 복잡해 보인다는 느낌을 받았다.



이번에 공부하면서 알아보니 


Date는 jdk 1.0 Calendar는 1.1 부터 써왔던 클래스이고 사용되어지면서 단점이 극명하게 드러나 

다들 기본 API를 외면한체 Joda-Time이라는 오픈소스 라이브러리를 사용한다고 한다. 


기존 Calendar, Date 클래스의 문제점


1. 불변객체가 아니다

- set으로 변경이 가능하다. 여러 객체에서 Calendar이나 Date 객체가 공유되면 한 곳에서 바꾼 값이 다른 곳 에서도 바뀌는 부작용이 생길 수있다.

- 멀티 쓰레드 환경에서 안전하지 못하다.


2. 윤초와 같은 특별한 상황을 고려하지 않았다.


3. 상수 필드 남용

calendar.add( Calendar.SECOND , 2 ); Calendar.JUNE 과같이 의미없는 상수가 들어가도 컴파일 시점에서 걸러낼 수가 없다.


4. 헷갈리는 월 지정

- 위에서 본 것 처럼 월의 시작이 0이다. 그래서 6월을 쓰려면 calendar.set(1582, 5 , 4); 이렇게 써야하고

calendar.set(1582, Calendar.JUNE , 4); 같은 상수도 만들었다 (Calendar.JUNE는 5가 찍힌다.)

일부러 가독성을 높이기위해 calendar.set(1582, 6-1 , 4); 이렇게 쓰기도 한다고 한다.


5. 일관성 없는 요일 상수

Calendar는 일요일부터 1~7 이고 Date는 일요일이 0으로 시작한다. 두 클래스는 빈번히 서로를 불러내는데 두 클래스 사이의 일관성이 없다.

6. 겹치는 클래스명

-java.util.Date  java.sql.Date클래스는 전자의 상속을 받는 클래스다. 그런데 클래스명이 같다니...

이렇게 단점이 많았다고 한다.

 그 후 jdk1.8 버전에서 드디어 개선된 java.time패키지가 등장했다. Joda-Time 라이브러리의 영향을 많이 받았고 기존 클래스들의 단점을 극복한 새로운 API라고 한다.

 아직 Date와 Calendar가 쓰이긴 하지만 구지 앞으로 안쓰여질 클래스에대해 깊게 알아보는것 보다 앞으로 쓰여질 클래스에 대해 공부하는것이 낫겠다 생각이들어 java.time패키지를 알아보려 한다.



- java.time패키지의 핵심 클래스


LocalDate : 날짜를 나타내는 클래스

LocalTime : 시간을 나타내는 클래스

LocalDateTime : 날짜, 시간을 모두 표현하는 클래스

ZonedDateTime : LocalDateTime + 시간대까지 표현하는 클래스.


Period : 두 날짜간의 차이를 표현하기 위한 클래스

Duration : 두 시간의 차이를 표현하기 위한 클래스


이들 클래스의 특징은 String클래스처럼 불변이라는 것이다. 

그래서 날짜나 시간을 변경하는 메서드들은 기존의 객체를 변경하는 대신 항상 새로운 객체를 반환한다.



- 객체 생성하기 


 now() 현재 날짜와 시간을 저장하는 객체 생성


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.time.*;
 
public class DateTime {
    public static void main(String args[]) {
    
        
        LocalDate date = LocalDate.now();
        LocalTime time = LocalTime.now();
        LocalDateTime dateTime = LocalDateTime.now();
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        
        System.out.println(date); //2018-10-01        
        System.out.println(time); //21:45:54.575
        System.out.println(dateTime); //2018-10-01T21:45:54.575
        System.out.println(zonedDateTime); //2018-10-01T21:45:54.576+09:00[Asia/Seoul]        
    }
}
cs

 of() 설정해주기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.time.*;
 
public class DateTime {
    public static void main(String args[]) {
    
        LocalDate date = LocalDate.of(20150318);
        LocalTime time = LocalTime.of(113030);
        LocalDateTime dateTime = LocalDateTime.of(date, time);
        ZonedDateTime zonedDateTime = ZonedDateTime.of(dateTime, ZoneId.of("Asia/Seoul"));
        
        System.out.println(date); //2015-03-18
        System.out.println(time); //11:30:30
        System.out.println(dateTime); //2015-03-18T11:30:30
        System.out.println(zonedDateTime); //2015-03-18T11:30:30+09:00[Asia/Seoul]
    }
}
 
cs




- LocalDate와 LocalTime


 java.time 패키지의 가장 기본이 되는 클래스

위에서 보았던 now() of()는 static 메서드로 구현

of()는 다음과 같이 여러가지로 오버로딩 되어있음

public static LocalDate of(int year, Month month, int dayOfMonth)


public static LocalDate of(int year,int month, int dayOfMonth)

public static LocalTime of(int hour,int minute)


public static LocalTime of(int hour, int minute, int second)


public static LocalTime of(int hour,int minute, int second, int nanoOfSecond)



-특정 필드의 값 가져오기 getxxx()


간단히 get~() 메서드로 호출이 가능하다. Calendar와 달리 월의 범위는 1~12이고 요일도 월~일 1~7 이다.



                     LocalDate  

 int getYear() 

 년도(2000)

 int getMonthValue()

 월(12) 

 Month getMonth() 

 월(DECEMBER) 

 int getDayOfMonth()

 일(31)

 int getDayOfYear()

 같은 해의 1월 1일부터 몇번째 일(365)

 DayOfWeek getDayOfWeek()

 요일(FRIDAY) .getValue()=5

 int lengthOfMonth()

 같은 달의 총 일수(31)

 int LengthOfYear()

 같은 해의 총 일수(365), 윤년이면 366

 boolean isLeapYear()

 윤년여부 확인 (false) 


LocalTime

 int getHour()

 시(23) 

 int getMinute() 

 분(59) 

 int getSecond() 

 초(59) 

 int getNano() 

 나노초(0) 


등이 있다..


필드의 값 변경하기 widh(), plus(), minus()


LocalDate withYear(), Month(), DayOfMonth()....

LocalTime withHour(), Minute(), Second().....  를 이용해 개별 필드 값을 변경 할 수 있다.


위에서 언급 했다시피 객체의 값을 변경하는 것이 아닌 새로운 객체를 생성해서 반환하므로 대입연산자가 필요하다.


1
2
date = date.withYear(2012); // 년도를 2012년으로 변경
time = time.withHour(12);  // 시간을 12시로 변경
cs


LocalDate plusYears(), Months(), Days(), Weeks() ...
LocalTime plusHours, Minutes(), Seconds(), ... 

마찬가지로 대입연사자 필요

1
2
date = date.plusYears(10); // 10년 후
time = time.plusHours(5); // 5시간 후
cs



-날짜와 시간의 비교 isAfter(), isBefore(), isEqual()


예제를 보면 이해가 간다.


1
2
3
4
5
6
7
8
9
10
LocalDate date = LocalDate.of(20150318);
LocalDate date2 = LocalDate.of(20150319);
 
boolean b = date.isAfter(date2);
boolean b1 = date.isBefore(date2);
boolean b2 = date.isEqual(date2);
 
    System.out.println(b); //false
    System.out.println(b1); //true
    System.out.println(b2); //false
cs




-LocalDateTiem과 ZonedDateTime


LocalDate           +      LocalTime        ->  LocalDateTime

LocalDateTime     +     시간대              -> ZonedDateTime


객체 생성법은 위에서 처럼 now() of()를 사용하면 된다.

역시 다양하게 of()가 오버라이딩 되어있다.



LocalDateTime은 LocalDate와 LocalTime을 합쳐서 만들 수도 있지만

만든걸 각각 변환 할 수도 있다.


1
2
3
4
5
6
7
8
9
LocalDate date = LocalDate.of(20150318);
LocalTime time = LocalTime.of(113030);
 
LocalDateTime lo = LocalDateTime.of(date, time); // 만들기
LocalDateTime lo = date.atTime(time); //atTime()
LocalDateTime lo = time.atDate(date); //atDate()
    
LocalDate date = lo.toLocalDate(); // todate
LocalTime time = lo.toLocalTime(); // totime
cs



ZonedDateTime 역시 합쳐서 또는 분해가 된다..


1
2
3
LocalDateTime lo = LocalDateTime.now(); 
ZoneId zid = ZoneId.of("Asia/Seoul");
ZonedDateTime zdt = lo.atZone(zid); //atZone으로 합치기
cs

1
2
3
LocalDate date = zdt.toLocalDate(); 
LocalTime time = zdt.toLocalTime(); 
LocalDateTime lo = zdt.toLocalDateTime(); // 분해
cs


-OffsetDateTime
ZonedDateTime 과의 차이점은 일광절약시간 (써머타임/하절기에 표준시를 원래 시간보다 한 시간 앞당긴 시간을 쓰는 것을 말한다) 규칙을 
포함 하느냐 안하느냐의 차이다. 컴퓨터에게 계절별로 시간을 더했다 뺐다 하는건 안좋으므로 변화 없이 시간체계를 유지하는 것이 안전하다.

1
OffsetDateTime odt = zdt.toOffsetDateTime();
cs



TemporalAdjusters


이달의 4번째 금요일은 며칠인지, 지난 주 토요일이 며칠인지와 같은 날짜계산을 하기위한 클래스이다.


firstDayOfNextYear()다음 해의 첫 날
firstDayOfNextMonth()다음 달의 첫 날
firstDayOfYear()올 해의 첫 날
firstDayOfMonth()이번 달의 첫 날
lastDayOfYear()올 해의 마지막 날
lastDayOfMonth()이번 달의 마지막 날
firstInMonth(DayOfWeek dayOfWeek)이번 달의 첫 번째 요일
lastInMonth(DayOfWeek dayOfWeek)이번 달의 마지막 요일
previous(DayOfWeek dayOfWeek)지난 요일(당일 미포함)
previousOrSame(DayOfWeek dayOfWeek)지난 요일(당일 포함)
next(DayOfWeek dayOfWeek)다음 요일(당일 미포함)
nextOrSame(DayOfWeek dayOfWeek)다음 요일(당일 포함)
dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)이번 달의 n번째 요일
LocalDate with(TemporalAdjuster adjuster) 메소드를 사용
1
2
LocalDate today = LocalDate.now();
LocalDate nextMonday = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
cs
이런식으로 사용하면 된다.


Period와 Duration 클래스


앞서 잠시 언급한 것과 같이 Period는 날짜의 차이를 Duration은 시간의 차이를 계산하기 위한 클래스이다.


- between() static 메소드이며 다음과 같이 구현한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
        LocalDate date = LocalDate.of(20150318);
        LocalDate date2 = LocalDate.of(20180420);
        LocalTime time = LocalTime.of(113030);
        LocalTime time2 = LocalTime.of(123550);
        
        Period pe = Period.between(date, date2);
        Duration du = Duration.between(time, time2);
        
        System.out.println(pe.getYears()); //3
        System.out.println(pe.getMonths()); //1
        System.out.println(pe.getDays()); //2
        
        System.out.println(du.getSeconds()); // 3920
cs


애석하게도 Duration에는 시, 분 차이를 구하는 메소드가 없다.. getSeconds() 와 getNano() 뿐이다.

물론 나누고 계산해서 시 분 을 구할 수 있겠지만 불편하다.


1
2
3
4
5
    LocalTime se = LocalTime.of(00).plusSeconds(du.getSeconds());
        int hour = se.getHour();
        int min = se.getMinute();
        int sec = se.getSecond();
        int nano = se.getNano();
cs

이 방법을 사용하면 된다. (그나저나 왜 안만들었지?;;)



- between()와 비슷한 기능을하는 until()도 있다. 다른점은 이 메서드는 인스턴스 메서드라는 것이다.


1
2
3
4
5
6
Period pe = Period.between(date, date2);
Period pe2 = date.until(date2);
long a = date.until(date2, ChronoUnit.DAYS);
 
Duration du = Duration.between(time, time2);
long b = time.until(time2, ChronoUnit.HOURS); //아까와는 다르게 시간과 분을 바로 구할 수 있다.
Time은 until()을 써보자!!
cs

until()메서드는 Duration 반환 타입이 없다. 매개변수가 2개인 until()은 D-Day를 구할때 좋다. 



- of(), with() / 역시 이 클래스에도 설정, 변경 메서드인 of와 with가 있다!





1
2
Period pe = pe.withYears(2);//, Months(), Days()
Duration du = du.withSeconds(2); //Nanos()
cs



아까 LocalDateTime과 ZonedDateTime처럼 to메서드로 변환이 가능하다.


1
2
3
4
5
6
7
8
9
10
    LocalDate date = LocalDate.of(20150318);
    LocalDate date2 = LocalDate.of(20180420);
    LocalTime time = LocalTime.of(113030);
    LocalTime time2 = LocalTime.of(123550);
    
    Period pe = Period.between(date, date2);
    Duration du = Duration.between(time, time2);
        
    System.out.println(pe.toTotalMonths()); //37
    System.out.println(du.toHours());       //1
cs

 Period

 long toTotalMonths()

 년원일을 월단위로 변환 후 반환(일 단위 무시)

Duration

 long toDays()

 일단위로 변환해서 반환

 long toHours()

 시간단위로 변환해서 반환

 long toMinutes()

 분단위로 변환해서 반환

 long toMillis()

 천분의 일초 단위로 변환해서 반환

 long toNanos()

 나노초 단위로 변환해서 반환




참조


https://d2.naver.com/helloworld/645609


오버로딩의  조건

1. 메소드 이름이 같아야하고

2. 매개변수의 개수 또는 타입이 달라야 한다.


자바는 오버로딩이라는 기능이 구현되어 있어

매개변수의 개수타입이 달라도 같은 이름의 메소드명으로 동일 기능을 구현 할 수 있다.


그래서 매개변수의 타입이 달라도 하나의 메소드명으로 오버로딩 할 수 있고

또 매개변수의 개수가 달라도 역시 오버로딩 가능하다.


여기서 드는 생각이 만약 매개변수의 개수가 사용자의 쓰임에 따라 달라진다면? 또 그 수가 무한이 늘어난다면?? (말이 좀 이상..)

일일이 매개변수 하나하나 오버로딩 해주어야 할 것인가? 라는 의문이 생긴다


1
2
3
4
String divide(String s1, String s2){...}
String divide(String s1, String s2, String s3){...}
String divide(String s1, String s2, String s3, String s4){...}
String divide(String s1, String s2, String s3, String s4, String s5){...}
cs

이렇게...?????



하지만 JDK1.5부터 매개변수의 개수를 동적으로 지정해 줄 수 있게 되었는데 이 기능을 가변인자(variable argument)라고 한다.


가변인자가 없었던 전 버전에서는 매개변수로 컬렉션이나 배열을 사용 했었다.


1
2
3
4
void sum(Vector<String> v) {
        for(Object a: v)
            System.out.println(a);
    }
cs
1
2
3
4
void sum(String [] str) {
        for(String a:str)
            System.out.println(a);
    }
cs
 

사용하려면

1
2
3
4
5
6
7
public static void main(String args[]) {
        Varargs v = new Varargs();
        Vector<String> ve = new Vector<String>();
        ve.add("a");
        ve.add("b");
        v.sum(ve);
}
cs
1
2
3
4
5
public static void main(String args[]) {
        Varargs v = new Varargs();
        String [] s = {"a""b""c"};
        v.sum(s);
}
cs


이 같은 경우 따로 백터 객체를 만드는 등 조금 복잡? 하고

v.sum()과  같이 인자를 생략해 줄 수 없다.




가변인자 사용법


 키워드 ... 을 사용한다


1
2
3
4
void sum(String...str) {
        for(String a:str)
            System.out.println(a);
}
cs

다음과 같이 타입...변수명 으로 사용한다.


1
2
3
4
5
6
public static void main(String args[]) {
    Varargs v = new Varargs();
    v.sum("a","b","c");
    v.sum();
    v.sum(new String [2]);
}
cs

빈 인자값이나 같은 타입에 배열도 인자값으로 줄 수 있다.

위 코드들을 보고 눈치 챌 수도 있는데

가변인자는 내부적으로 배열을 생성해서 사용한다! (향상된 for문 str, 인자값으로 배열 넣어짐)

그래서 가변인자를 마구 난발하지는 말도록 하자.



만약 가변인자 외에도 다른 매개변수가 더 있다면 가변인자는 마지막에 선언해야 한다.


1
2
3
4
void sum(String s, String...str) {
        for(String a:str)
            System.out.print(a+s);
}
cs
1
2
3
4
public static void main(String args[]) {
        Varargs v = new Varargs();
        v.sum("-","a","b","c");
    }
cs

 위와 같은 코드로 여러 문자열을 구분자를주어 나누어 줄 수 있다.

a-b-c-




가변인자 메소드 오버로딩 주의점


만약 오버로딩 된 두 메소드가 있다면


1
2
3
4
5
6
7
8
void sum(String s, String...str) {
        for(String a:str)
            System.out.print(a+s);
    }
    void sum(String...str) {
        for(String a:str)
            System.out.print(a);
    }
cs
1
2
3
4
public static void main(String args[]) {
        Varargs v = new Varargs();
        v.sum("-","a","b","c");
    }
cs

이 메인 메소드를 돌려 본다 생각해보자.

컴파일러는 어떤 메소드를 사용 해야하는지 구분을 못한다. 그러므로 컴파일 에러가 난다.


가능하면 가변인자를 사용한 메소드는 오버로딩을하지 않는 것이 좋다.




가변인자를 사용한 대표적인 예


printf() 메소드가 있다.



앞의 문자열에 지시자 ex} %d, %s 로 뒤의 값을 형식화 해주는 메소드 인데

뒤의 값을 사용자가 마음대로 수를 정할 수있다.


가변인자를 사용한 메소드이기 때문에 가능했던 것이다.




참고

http://gyrfalcon.tistory.com/entry/Java-Varargs



자바를 처음 공부할 때 헷갈렸던 것 중에 하나가 있는데

바로 변수를 지칭하는 용어가 너무 많아 헷갈렸었다.


멤버변수 지역변수 인스턴스변수 클래스변수 참조변수...등등

어떤게 어떤건지 왜이리 지칭하는 수식어가 많은지 생각을 했었는데 이를 한 곳에서 정리해주는 곳을 찾고 싶었으나 결국 찬찬히 공부하면서 배웠다.

하지만 다시 정리도 하고 나같은 성질 급한 사람이 있을 수 도 있으니 정리해본다.


기본형변수

참조변수

멤버변수

클래스변수

인스턴스변수

지역변수

매개변수


내가 아는 변수의 종류들이다. 무려 7가지가 있는데 나누는 기준이 다르다 크게 두가지 기준이 있다.


1. data type 에 따른 분류


기본형변수참조변수로 나뉜다.


기본형변수는 자료의 실제값을 저장한다.


8가지 종류의 타입이 있다.

논리형 : boolean 

문자형 : char                      

정수형 : byte            

 short

 int

 long

실수형 : float

 double


참조변수는 값이 저장되어 있는 주소값을 값으로 갖는다.


8가지 기본형 변수를 제외한 나머지 타입이다.

대표적으로 String이 있고 사용자가 얼마든지 새로운 클래스를 만들어 낼 수 있기때문에 무한하다.



2. 선언 위치에 따른 분류


크게 멤버변수지역변수로 나뉘며


멤버변수클래스변수인스턴스변수를 통틀어서 부르는 용어이다.


클래스영역에 선언된 변수를 멤버변수라 하며 그중 앞에 static 이붙은 변수를 클래스 변수라고 한다.


인스턴스변수

클래스 영역에 선언되고

인스턴스 생성시 만들어진다.

각각의 인스턴스마다 다른 값을 가질 수 있다.

그러므로 인스턴스 생성이 필수이며 각 인스턴스마다 다른 값을 가져야 할 때 사용된다



클래스변수

인스턴스변수 앞에 static 을 붙이기만 하면 된다.

인스턴스변수가 각각의 인스턴스마다 다른값을 가질 수 있는 거와 달리 

값을 공유하는 변수이다.

클래스 로딩시 생성되며 

클래스이름.변수이름 이렇게 인스턴스 생성 필요없이 바로 쓸 수 있다.


지역변수

메소드 내에 선언되며 메소드 호출시 생성되고 메소드가 종료되면 사라진다.


매개변수

흔히 파라미터라고 불린다. 메소드에서 입력값을 받을 때가 있는데 그때 사용되는 변수를 매개변수라고 한다.

매개변수도 매소드 내에 선언된 것으로 간주되므로 지역변수이다.

인자값은 호출시 메소드입력부의 넣는 값이며 이값은 매개변수에 복사되어 대입된다.





예제를 보고 직접 구분해보자!


1
2
3
4
5
6
7
8
9
10
11
12
13
public class Variable {
    int a;
    static String b;
    void m(int c){
        int d=c;
    }
    public static void main(String args[]) {
        int e=0;
        Variable v = new Variable();
        v.m(e);
    }
}
 
cs




2번줄     a 기본형변수이면서 멤버변수인스턴스변수

3번줄     b참조변수이면서 멤버변수클래스변수

4번줄     c기본형변수이면서 매개변수 이면서 지역변수

5번줄     d기본형변수이면서 지역변수

7번줄     args참조변수이면서 매개변수 이면서 지역변수

8번줄     e는 기본형변수이면서 지역변수

9번줄     v는 참조변수이면서 지역변수

10번줄   e는 인자값으로 값0이 매개변수에 복사되어 넣어진다.

객체지향 언어


 흔히 절차지향언어랑 많이 비교 되지만 객체지향언어가 절차적 즉 순서대로 실행 되어지는 것이 아닌건 아니다.

음 말이 어려운데 말하고 싶은거는 객체지향이 절차지향에 반대말이 아니란 것이다! 결국 실행은 한줄씩 순서대로 진행한다.

그리고 또 어떤 것이 좋고 어떤 것이 나쁜 개념이 아니다 각각의 특징이 있다.


 객체지향 언어는 각각의 기능? 을 클래스로 만들고 (모듈화) 그 클래스의 객체를 생성하여 코딩하는 것인데


-재사용성이 높고

-유지보수가 용이하며

-제어자의 이용으로 신뢰성 높은 프로그래밍이 가능하다(데이터 보호) 


 라는 특징을 가지고있다.




클래스와 객체


클래스 : 객체를 정의해 놓은 것

객체 : 클래스를 바탕으로 만들어진 객체


흔히 붕어빵 기계(틀)와 붕어빵 예시가 나오는데

이 때 붕어빵 기계를 클래스

붕어빵을 객체라고 생각한다.


붕어빵 기계는 붕어빵을 만들기 위해 존재하는 것으로

그 자체 만으로는 쓸모가 없다. 단지 붕어빵(객체, 인스턴스)을 만들기 위해 존재한다.


만약 붕어빵 틀 없이 붕어빵을 만들면 매번 다른 붕어빵이 생기고 모양을 잡는 등 힘들 것이다.

하지만 붕어빵 기계가 있으면 고민없이 그대로 찍어내면 된다.


이를 아까 말한 객체지향의 특징과 같이 생각해보면 좋다.




객체와 인스턴스


클래스로부터 객체를 만드는 과정 : 클래스의 인스턴스화

클래스로부터 만들어진 객체 : 인스턴스


객체와 인스턴스는 같은 의미지만

객체는 모든 인스턴스를 대표하는 포괄적인 의미를 가진다.



객체의 구성요소


속성과 기능, 두종류의 요소로 이루어져 있으며

멤버변수와 메소드 라는 용어로 많이 쓰인다.


자동차로 예를들어보면

전폭, 전고, 전장(크기), 배기량, 연비, 색상, 최고속력 등은 속성이고

시동걸기, 가속하기, 감속하기, 에어컨작동 등은 기능이다.


이를 토대로 자동차 클래스를 만들어보면

다음과 같이 만들어 볼 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Car{
    int speed=0;
    int maxSpeed=200;
    String color;
    boolean power;
    
    void startEngine() {
        power= !power;
    }
    void accel(){
        if(speed<maxSpeed)
            speed++;
    }
    void breaking(){
        if(speed!=0)
            speed--;
    }
}
cs


인스턴스의 생성과 사용


1
2
3
4
5
6
7
8
9
10
public static void main(String args[]) {
        Car car = new Car();
        car.color="white";
        car.accel();
        //car.breaking();
        System.out.println("현재 속력은"+car.speed+"입니다.");
        
        Car car2=car;
        System.out.println(car2.speed);
    }
cs


현재 속력은1입니다.

1


인스턴스 생성방법은 이렇다.

Car car= new Car();

클래스명 변수명 = new 클래스명();

new 키워드를 사용하며 이때 저장 하는 참조변수의 타입과 인스턴스의 타입은 같아야한다. (다형성 예외)


생성한 인스턴스는 변수명에 .을붙여 접근 가능하다

car.멤버변수or메소드


이때 car라는 변수는 참조변수로 생성된 인스턴스공간의 주소값을 저장한다

하나의 참조변수는 하나의 값만을 저장하며

여러 참조변수가 하나의 인스턴스를 가르킬 수 있다.


car 와 car2는 같은 인스턴스 주소값을 저장하고 있으며 

그래서 car.speed와 car2.speed는 같은 값을 반환한다.



 

 자바의 대표적인 특징으로

 플랫폼의 독립적이다, 객체지향적이다, 자동으로 메모리를 관리해준다 라는 특징이 있다.


 여기서 3번째 언급한 자동 메모리 관리는 흔히 알고있는 가비지 컬렉터가 더 이상 쓸모없어진 객체들을 자동으로 지워주는 기능을 뜻한다.


 처음에 자바 공부를 할 때에 별로 와닿지 않았는데 나는 개발자가 직접 메모리 관리를 해주어야하는 다른 언어를 배운적도 없고 

 자동으로 관리를 해주는데 신경 쓸 필요가 있나? 라는 생각이 들어 그냥 그렇게 넘어 갔었다.


 하지만 JVM에 대해 공부하면서 항상 언급되는 heap영역의 설명 중 'JVM의 성능 등의 이슈에서 가장 많이 언급되는 공간이다' 라는 설명을 항상 보았고 의문이 생겨 알아보게 되었다.


이 글을 보기전에 먼저 JVM 메모리구조에 대해 공부하는 것이 좋다. 검색하면 많이 나온다. (내 블로그에도 있지만.. 미약하다)



본론



 heap 영역은 크게 Young Generation 영역과 Old Generation 영역 으로 구성되며 Young 영역은 Eden과 두개의 SS(survivor space)로 나뉘어진다.


heap에 객체가 적재되는 과정


1. 객체가 새로 생성되면 먼저 Eden에 속하게 된다. 그러다 꽉 차게되면 


2. 필요없어진 객체를 비우고 살아남은 객체들을 SS중 한 곳으로 보낸다


3. 1,2의 과정을 반복하다 SS도 차게되면 역시 필요 없어진 객체를 비우고 살아남은 객체들을 남아있던 SS 로 보낸다. (반드시 한 SS는 비워진 상태여야 한다.)


4. 이 과정을 거치며 더 이상 SS에도 공간이 없어지면 살아남은 객체를 Old영역으로 보낸다.





Generation GC가 탄생한 배경


왜 heap영역을 저렇게 나누고 이리저리 옮겨가며 저장을 하는 것일까???



그 이유를 알기전에 먼저 알아야할 개념이 있다.


Stop the World (STW)


 말 그대로 GC발생시 JVM은 실행중인 어플리케이션을 멈추게 한다. GC를 수행하는 쓰레드를 제외한 나머지에 모든 쓰레드의 작업을 중지시킨다. 

그래서 heap 영역의 성능 튜닝 즉 GC튜닝이란 이 STW의 시간을 최소한으로 줄이는 것이다.



David ungar라는 사람이 weak generational hypothesis 라는 가설을 세운다. 그 내용은


     대부분의 객체는 금방 죽는다.  


무슨 말이냐면 대부분의 생성된 객체는 금방 쓸모가 없어진다. 즉 GC의 대상이 된다는 것이다


그래서 heap 전체를 정리해줄 필요 없이 Young영역만을 주기적으로 관리해주고 가끔씩만 Old영역을 정리해주면 되는 것이다.


여기서 Young영역에서 일어나는 GC를 마이너GC라 부르며 상대적으로 속도가 빠르다. (1초이내)

Old 영역에서 일어나는 GC는 메이저GC라 부르며 속도가 느리다. (STW시간이 길다) 


이 heap영역의 Young영역과 Old영역의 메모리는 설정이 가능한데 최대한 마이너GC만으로 메모리가 유지 될 수 있도록 적절하게 설정해주는 것이 필요하다고 생각한다.



GC의 종류


결국에는 Old 영역도 채워질 것이고 그러면 메이저GC가 발생 할 것이다. 이 Old영역의 GC는 채택하고 있는 방식에 따라 달라지므로 다음 5가지 방식에 대해 알아보자.


1. Serial GC (-XX:+UseSerialGC)


1) old 살아있는 개체 식별(mark)
2) heap 앞부분부터 확인해 살아있는것만 남김(sweep)
3) 각 객체들이 연속되게 쌓이도록 heap 의 가장 앞 부분부터 적재(compact)


이렇게 mark-sweep-compact 알고리즘을 사용하며 단일코어 싱글 쓰레드를 사용하여 부담이 적지만 성능이 안좋다.



2. Parallel GC  (-XX:+UseParallelGC)


Serial GC와 같은 알고리즘을 사용하지만 멀티 쓰레드를 사용하여 속도가 더 빠르다는 특징이 있다. 





3. Parallel Old GC


업뎃 예정...



4. CMS (Concurrent Mark-Sweep) GC  (-XX:+UseConcMarkSweepGC)


내용이 어렵지만 쉽게 말하면 

백그라운드 쓰레드를 작동시켜 Old 영역의 쓰레기들을 지속적으로 없애 줍니다. 

그래서 STW가 거의 없다는 장점이 있습니다.


하지만 2가지 단점이 있는데 

 - 백그라운드에서 항상 쓰레드가 도니 CPU를 많이 잡아먹고

 - 기본적으로 Compact 단계를 제공하지 않아 메모리 파편화가 생깁니다 

그래서 결국 파편화가 심해지면 이를 정리해주는 시간이 다른 방식의 GC를 사용할 때 생기는 STW시간보다 길어 질 수 있습니다.



5. G1 GC (-XX:+UseG1GC)


heap을 Young Old로 구조적으로 나누지 않고 개념적으로만 나눈다. 


이렇게 통으로 바둑판식으로 관리한다. 


CMS GC 방식처럼 백그라운드 쓰레드로 Old영역을 관리하며 필요없어진 부분을 통째로 날리며 살아남은 객체는 다른 부분으로 옮겨주어

CMS 의 단점이던 메모리 파편화를 해결한 방식 입니다.




각 jdk 별로 기본적으로 채택한 GC 방식은 다음과 같습니다.


  • Java 7 - Parallel GC
  • Java 8 - Parallel GC
  • Java 9 - G1 (proposed)




마냥 자바의 메모리 관리는 가비지 컬렉터가 알아서 해준다~ 라고 생각 하고만 있었지만

이제는 적어도 적절한 GC를 선택 하고 튜닝을 해줄 수 있고 필요하다는 걸 알게 되었다.



참고,출처

https://okky.kr/article/379036

https://yckwon2nd.blogspot.com/2014/04/garbage-collection.html

https://www.slipp.net/wiki/pages/viewpage.action?pageId=26641949

http://www.holaxprogramming.com/2013/07/20/java-jvm-gc/

http://12bme.tistory.com/57

https://d2.naver.com/helloworld/1329

http://lyb1495.tistory.com/3



'java' 카테고리의 다른 글

자바[JAVA] 자바 변수 정리  (6) 2018.09.09
자바[JAVA] 객체지향언어 클래스와 객체  (0) 2018.09.09
자바[java] nextInt() 다음 nextLine()이 안돼요  (0) 2018.07.30
자바[java] 다형성  (4) 2018.07.12
자바[java] 예외처리  (2) 2018.07.10

전송 방식


get방식 URL에 파라미터를 붙여서 전송


post방식 데이터 영역을 이용




인코딩 디코딩 방법



POST


인코딩 : 페이지에 charset 을 따름


1
<%@ page language="java" contentType="text/html; charset=UTF-8" %>
cs
페이지 디렉티브의 charset을 따른다 이번에 공부하면서 처음 알았다.





디코딩 : request.setCharEncoding("utf-8"); 사용


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta  charset="UTF-8">
<title>post</title>
</head>
<body>
<form action="post.jsp" method="post">
<input type="text" name="test">
<input type="submit" value="전송">
</form>
<%    request.setCharacterEncoding("utf-8");
    String a = request.getParameter("test"); %>
<%=%>
</body>
</html>
cs

13행 처럼 해주면 된다 간단하다. 

주의할 점은 파라미터 값을 사용하기 전에 선언해야한다. 그 뒤로 나오는 코드에만 적용이 되기 때문이다.




GET


인코딩


1. <a>태그 사용시 : 페이지 charset을 따름

1
<a href="http://localhost:8080/TestProject/trans/get.jsp?test=안녕">링크</a>
cs


2. <form>태그 사용시 : 페이지 charset을 따름

1
2
3
<form action="get.jsp" method="get">
<input type="text" name="test">
</form>
cs

1번 2번의 경우 post방식 처럼 모두
1
<%@ page language="java" contentType="text/html; charset=UTF-8" %>
cs
페이지 디렉티브 charset으로 인코딩 된다


3. 직접 주소에 파라미터 입력시 : 웹 브라우저마다 다름

크롬 : UTF-8

익스플로러 : MS949 (설정으로 UTF-8 사용가능)




디코딩


1. 기본설정 charset은 WAS마다 다름

톰캣8 : UTF-8

톰캣7 : ISO-8859-1


그래서 크롬 브라우저와 톰캣8을 이용하면 별다른 설정 없이 한글 파라미터가 사용 가능했던 것이었다


2. server.xml 파일 변경하기

server.xml 파일을 보면  <Connector> 태그가 있다.

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>


2-1 URL인코딩 지정해주기

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>

URIEncoding="" 에 원하는 캐릭터 셋을 넣어 URL인코딩 방식을 정할 수 있다.



2-2 post 방식 처럼 request 사용하기

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" useBodyEncodingForURI="true"/>

useBodyEncodingForURI="true" 를 넣어주면 post 디코딩 처럼 request.setCharacterEncoding("")을 사용 할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<%@ page language="java" contentType="text/html; charset=euc-kr" %>
<!DOCTYPE html>
<html>
<head>
<meta  charset="UTF-8">
<title>get</title>
</head>
<body>
 
<form action="get.jsp" method="get">
<input type="text" name="test">
<input type="submit" value="전송">
</form>
 
<% request.setCharacterEncoding("euc-kr"); %>
<%= request.getParameter("test"%>
</body>
</html>
cs


1행에 charset에 euc-kr 로 인코딩 하고 (form태그 get방식이니까)

15행에 request메소드로 디코딩 해주었다.



아직 방법 정도 밖에 몰라 아쉽다.





'JSP' 카테고리의 다른 글

[JSP] out.println 줄바꿈  (0) 2018.08.07
[JSP] Get방식 Post방식 차이점  (1) 2018.07.26

+ Recent posts