뛰어난 개발자는 회의 시간에 존다?

"뛰어난 개발자는 회사에서 잘 존다."는 말을 본 적 있다.

구성원 중의 한 명이 회의 시간에 '졸고 있다.'
회의를 주도하는 입장에서 집착해야 할 문제는 딱 그 지점이다.

회의 시간에 조는 문제를 이야기하는데 개발자 실력을 논한다?

그건 본질에서 벗어나는 말이다. 문제해결에 도움이 안 된다.

 

아래 내용은 그동안 개발자들에게
정말 회의 시간에 왜 조는지를 물어보고 대응한 내용이다.

가뜩이나 바쁜 스타트업에 참고가 되기를 바란다.

 

응 그래 너는 졸아도 돼.

개발자가 졸면 비용과 시간이 두배로 든다.

스타트업에서 개발자가 회의에서 졸면 어떤 일이 벌어질까?
회의의 주요 목적은 보통 3가지 정도이다.

  1. 정보전달
  2. 결정
  3. 상호 간의 소통

그런데 개발자가 회의에서 존다면?
정보전달도 다시, 결정 공유도 다시, 소통도 다시 해야 한다.

안 그래도 바쁜데 비용과 시간이 2배로 들어간다는 소리다.

그럼 어떻게 해야 회의 시간에 졸지 않을 수 있을까?

 

우리는 닥터 스트레인지가 아니야... 시간을 돌릴 수 없다구!

1. 쓸데없는 회의라서 조는 거다.

애초에 쓸데없는 회의에 개발자를 부르지 말자.

필요하지 않은 회의에 부르니까 졸고 있는 거다.

졸고 있을 그 시간에 일할 기회를 주자.


회의를 주도하는 사람이
개발자가 필요한 회의인지 아닌지만 구분해도 회사의 생산력이 올라간다.


개발자를 앉혀놓고 일장 연설을 하거나,

필요 없는 논의에 참여하게 하는 회사가 생각보다 너무 많다.
개발자들이 회의를 쓸데없어하는 이유가 있다.

지금 이 회의에 저 사람이 필요한가?

이것만 잘 정리해도 개발자는 졸지 않는다.

 

 

개발자는 제발 필요한 회의만 부르자.

2. 컨디션이 나쁘니까 조는 거다.

맨날 밤새고 일 시키니까 조는 거다. 과다한 업무를 시키지 말자.

어쩔 수 없다면 회의 전에 스트레칭하고 시작하자.

쉬는 시간을 명확하게 하고 시간을 정하자.

 

일 좀 그만 시켜라. 졸려 죽겠다.

1) 스트레칭

  • 회의 인원이 소수라고 가정했을 때 가장 좋았던 스트레칭 방법은 아래와 같다.
  • 모두 일어서서 둥그렇게 원을 그린다. 원을 그릴 공간이 없다면 의자를 밀어넣고 일어선다.
  • 구성원들이 자신이 아는 스트레칭 방법을 하나씩 공유하며 돌아가며 스트레칭을 한다.
  • 처음 시작한 사람을 중심으로 한 회기 혹은 두 회기를 돌고 나서 스트레칭을 마무리한다.
  • 이는 비폭력대화, 회복적 서클에서 많이 사용하는 방법인데 매우 효과적이었다.
    무엇보다 진행자가 더 할일이 없고 개발자도 말을 해야하기 때문에 졸지 않는다.

2) 확실한 회의시간과 쉬는시간

  • 구글의 서비스 회의방법이라 불리는 스프린트 에서 강조하는 부분이다.
  • 회의 시간 시간과 쉬는 시간을 학교 수업처럼 명확히 한다.
  • 회의시간이 명확히 보일 수 있도록 타임 타이머를 사용하는 것도 방법이다.

구글에서 사용하는 타임타이머. 1만원 대에서 4만원대까지 다양하다.

3. 말을 못하니까 조는거다.

자기 혼자 말하고 딴짓하거나 졸면 뭐라고 하는 회의시간. 교장선생님 훈화 말씀보다 어렵다.

실리콘밸리 임원들이 회의하는 법 에서는 효율적으로 회의하는 방법 5가지를 말한다.

  1. 회의의 목적과 성공요건을 반드시 기록한다.
  2. 발표보다 논의에 집중한다.
  3. 노트북 그리고 휴대전화 '반입금지'한다.
  4. 회의록을 작성하고 배포한다.
  5. 회의의 후속 조치를 실행한다.

모두 중요한 이야기이지만, 2번 항목에 주목하자.

발표보다 논의에 집중한다는 말이 무엇일까?

개발자가 회의 시간에 참여하면서 자기 이야기를 할 수 있다면,

회의 시간에 졸기 어려울 것이다.

개발자가 말할 수 있는 회의를 만들기 위해 많은 회의법을 도입했다.

그 중 쓸모 있었던 자료를 3가지를 꼽자면 아래와 같다.

 

게임스토밍

 

게임스토밍

이제 매뉴얼을 던지고 자유롭게 게임스토밍을 하라즐기면서 일하는 창조적 기술, 게임스토밍직장인이라면 누구나 가지고 있는 `회의 스트레스`. 그 중심에는 아이디어를 내야 한다는 압박감이 존재하고 있다. 이 아이디어에 대한 부담감은 좌절감을 일으키고 생산성을 저하시킨다. 이런 고질적인 문제의 해결방안으로 이 책은 '게임스...

www.yes24.com

 

- 회의 시 구성원들이 함께 이야기 할 수 있는 다양한 회의 방법이 소개되어 있다.

 

 

스프린트

 

스프린트

구글 수석디자이너가 직접 공개하는 구글은 어떻게 기획하고 실행하는가?지메일, 구글 서치, 크롬을 탄생시킨 바로 그 방식이 마침내 베일을 벗는다! 출간 즉시 아마존·뉴욕타임스·월스트리트저널 베스트셀러! 영국, 독일, 중국, 일본 등 출간 전 20개국 판권 계약! 페이스북, 우버, 에어비앤비에서 효과가 입증된 궁극의 솔루션. “스프린트로 해...

www.yes24.com

- 5일 만에 서비스 기획부터 테스트까지 끝내는 구글의 서비스 기획 방법

- 구성원들이 다양하게 회의에 참여 할 수 있는 방법이 나온다.

 

모떠꿈 워크샵 매뉴얼

 

모떠꿈 매뉴얼 최종본 by 더체인지

 

drive.google.com

- 게임 스토밍의 무료 버전이라고 생각하면 됩니다.

- 회의에서 적용 할 수 있는 다양한 회의법이 있습니다.

 

너무 복잡한가?

그럼 개발자가 회의를 진행 보는 것은 어떨까?

물론 회의 진행 전에 무엇을 해야 하는지 알려주어야한다.


회의 진행을 공유하는 일은
우리 조직이 어떻게 회의를 하는지
객관적으로 알 수 있는 기회이기도 하다.

모두에게 의미 있는 회의를 하자

의미있는 회의를 '약속해줘~' 제발...

 

모두에게 시간은 소중하다.

그러기 위해서 한 번 회의할 때 잘 해야 한다.

우리가 지금 하는 회의는 구성원에게 의미가 있는 회의인가?

지금 회의 시간에 개발자가 졸고 있다면 한번 생각해보자.

 

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

덧.

이 글을 쓴지 벌써 3년이 지났다.
이 글을 쓸 때는 정말 회의 때 마다 개발자님이 졸아서 참 답답했다.
지나고 보니 두가지 측면이 있었는데,

1. 나중에 알고보니 이때 개발자님이 사실은 업무 시간과 업무 외 시간에 몰래 다른 일을 하고 있었다. 건강상태도 안좋았고. 그러니까 회의시간에 조는 것. 나중에 다른 곳으로 보내드렸다.


2. 우리 회사에 관심이 있고 일 잘하는 개발자 분이 새로 들어왔을 오셨는데 절대 졸지 않으셨다. 오히려 적극적으로 참여해주셨다. 일 잘하고 나와 조직이 잘 맞는 사람과 일하면 인생이 행복하다.

3. 그럼에도 회의방법을 개선하고 멤버들의 컨디션을 체크하고 회의 진행자를 바꾸는 방법은 매우 의미가 있다. 무엇보다 개발자에게 필요없는 회의를 잡지 않는 것은 정말 중요하다.  

결론 : 회의는 필요한 만큼만! 일 잘하고 좋은 사람과 일하면 별로 걱정이 없다.





index.jsp

<%@ page contentType="text/html; charset=EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
    <h1>게시판 프로젝트</h1>
    <ul>
        <li><a href="board">고고고</a></li>        
    </ul>
</body>
</html>


BoardServlet.java

package Controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.BoardDao;
public class BoardServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //System.out.println("성공");
         req.setCharacterEncoding("euc-kr");
         resp.setCharacterEncoding("euc-kr");
        
         String KeyField = req.getParameter("KeyField");
         String KeyWord = req.getParameter("KeyWord");
        
         req.setAttribute("boardList", new BoardDao().getBoardList(KeyWord, KeyField));        
        
         RequestDispatcher view = req.getRequestDispatcher("List.jsp");
         view.forward(req, resp);     
    }
}




DBConnectionMgr.java

public class DBConnectionMgr {//vector와 AllayList를 차이 vector는 동시접근을 막음.
    private Vector connections = new Vector(10);
  //POOL 10개 /(Collection)VECTOR를 쓴 이유 : 다 쓰면 자동으로 추가시키도록
    private String _driver = "com.mysql.jdbc.Driver",
    //_url = "jdbc:mysql://localhost:3306/test",
    _url = "jdbc:mysql://localhost:3306/test?autoReconnect=true&useSSL=false", //보안접속방식을 사용하지 않겠다
    _user = "root",
    _password = "1111";
    private boolean _traceOn = false;
    private boolean initialized = false;
    private int _openConnections = 10;
    private static DBConnectionMgr instance = null;

......



BoardDto.jsp

package model;
public class BoardDto {
    private int no;
    private String subject;
    private String name;
    private String regdate;
    private int cnt;
    private String email;
    private String homepage;
    private String pw;
    private String content;
    
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getHomepage() {
        return homepage;
    }
    public void setHomepage(String homepage) {
        this.homepage = homepage;
    }
    public String getPw() {
        return pw;
    }
    public void setPw(String pw) {
        this.pw = pw;
    }       
    public int getNo() {
        return no;
    }
    public void setNo(int no) {
        this.no = no;
    }
    public String getSubject() {
        return subject;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getRegdate() {
        return regdate;
    }
    public void setRegdate(String regdate) {
        this.regdate = regdate;
    }
    public int getCnt() {
        return cnt;
    }
    public void setCnt(int cnt) {
        this.cnt = cnt;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    
    
}




BoardDao.java

package model;
import java.io.PrintWriter;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.mysql.jdbc.Connection;
import mybean.dbcp.DBConnectionMgr;
public class BoardDao {
    
    private DBConnectionMgr pool;
    private Connection conn;
    private PreparedStatement pstmt;
    private ResultSet rs;
        
    public BoardDao() {
        try {
           pool = DBConnectionMgr.getInstance();
        }
        catch(Exception err) {
           System.out.println("BoardDao() 오류 : " + err);
        }
    }       
    //목록을 불러오는 메소드
    public List<BoardDto> getBoardList(String KeyWord, String KeyField){
        ArrayList<BoardDto> list = new ArrayList<>();
        String sql = "";
        
        if( KeyField == null ) {
           KeyField = "name";
           KeyWord = "";
        }
        System.out.println("keyword : " + KeyWord);
        
        if(KeyWord.equals("") && KeyField.isEmpty()) {
           sql = "select * from board order by no desc";           
        }else {
           sql = "select * from board where "+ KeyField +" like '%" + KeyWord + "%' order by no desc";       
        }          
        try {          
           conn = (Connection)pool.getConnection();
           pstmt = conn.prepareStatement(sql);
           rs = pstmt.executeQuery();
           
           while(rs.next()) {
               BoardDto board = new BoardDto();
               
               board.setNo(rs.getInt("no"));
               board.setSubject(rs.getString("subject"));
               board.setName(rs.getString("name"));
               board.setRegdate(rs.getString("regdate"));
               board.setCnt(rs.getInt("cnt"));
               
               list.add(board);              
           }          
        }catch(Exception err) {
           err.printStackTrace();                   
        }finally {
           pool.freeConnection(conn, pstmt, rs);
        }       
        return list;
    }   
    //글 읽는 메소드가 필요 Read.jsp
    public BoardDto getBoard(int no, boolean hasRead) {
        BoardDto board = new BoardDto();
        String sql="";
        
        try {
           conn = (Connection) pool.getConnection();
           
           if(hasRead == true) {//읽었으니깐 카운트 올려주기한 update
               sql = "update board set cnt=cnt+1 where no=?";
               pstmt = conn.prepareStatement(sql);
               pstmt.setInt(1, no);
               pstmt.executeUpdate();
               //sql문의 1개의 바인딩 변수에 값을 채운 후 executeUpdate()메소드를 호출해
               //update문을 실행시켜 데이터 베이스에 정보를 수정함.
           }  
           //카운트를 올려주고 나서 이제 글을 가져와야함.
           sql = "select * from board where no=?";
           pstmt = conn.prepareStatement(sql);
           pstmt.setInt(1, no);
           //pstmt.executeQuery(); 얘는 select문으로 값을 가져오게끔 했으므로 결과값을 담아 넣을 변수가 필요함.
           rs = pstmt.executeQuery();
           while(rs.next()) {
               board.setNo(rs.getInt("no"));
               board.setSubject(rs.getString("subject"));
               board.setName(rs.getString("name"));
               board.setRegdate(rs.getString("regdate"));
               board.setCnt(rs.getInt("cnt"));   
               board.setHomepage(rs.getString("homepage")); 
               board.setEmail(rs.getString("email"));   
               board.setContent(rs.getString("content"));
               board.setPw(rs.getString("pw"));              
           }          
        }catch(Exception err) {
           System.out.println("getBoard()에러 : " + err);    
        }finally {
           pool.freeConnection(conn, pstmt, rs);       }
        return board;             
    }
    //글 등록하는 메소드 Post.jsp  
    public void insertBoard(BoardDto board) {
        try {
           conn = (Connection) pool.getConnection();
           String sql = "insert into board(name, subject, email, "
                   + "homepage, pw, content, regdate, cnt) "
                   + "value(?, ?, ?, ?, ?, ?, now(), 0)";
           
           pstmt = conn.prepareStatement(sql);           
           pstmt.setString(1, board.getName());
           pstmt.setString(2, board.getSubject());          
           pstmt.setString(3, board.getEmail());
           pstmt.setString(4, board.getHomepage());
           pstmt.setString(5, board.getPw());
           pstmt.setString(6, board.getContent());
           //pstmt.setString(7, board.getRegdate());
           //regdate cnt는 그냥 알아서 들어가라고 하고 위는 받아와서 ?에 넣으라는 소리였음! 아항~!
           pstmt.executeUpdate(); 
           
        }catch(Exception err) {
            System.out.println("insertBoard()에러 : " + err);    
        }finally {     
           pool.freeConnection(conn, pstmt);
        }
    } //db에 집어넣는 거니깐 return 값 없어도 됨.
    
    //글 수정하는 메소드 updateProc.jsp
    public void updateBoard(BoardDto board) {
        try {
           conn = (Connection) pool.getConnection();
           String sql = "update board set name=?, email=?, "
                   + "subject=?, content=?, pw=? where no=?";
           pstmt = conn.prepareStatement(sql);
           
           pstmt.setString(1, board.getName());
           pstmt.setString(2, board.getEmail());
           pstmt.setString(3, board.getSubject());
           pstmt.setString(4, board.getContent());
           pstmt.setString(5, board.getPw());
           pstmt.setInt(6, board.getNo());
           
           pstmt.executeUpdate();                                          
        }catch(Exception err) {
            System.out.println("UpdateBoard()에러 : " + err );                  
        }finally {
           pool.freeConnection(conn, pstmt);
        }       
    }   
    //글 삭제하는 메소드 delete.jsp
    public void deleteBoard(int no) {
           try {              
           conn = (Connection) pool.getConnection();
           
           String sql = "delete from board where no=?";
           pstmt = conn.prepareStatement(sql);
           pstmt.setInt(1, no);
           pstmt.executeUpdate();
           
        }catch(Exception err) {
            System.out.println("deleteBoard()에러 : " + err);        
        }finally {
           pool.freeConnection(conn, pstmt);
        }
        //update했으면 끝이지 뭐 리턴값 없어        
    }
}







List.jsp

<%@page import="model.BoardDto"%>
<%@page import="java.util.ArrayList"%>
<%@ page contentType="text/html;charset=euc-kr" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<HTML>
<head>
<link rel="stylesheet" href="bootstrap337/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="bootstrap337/css/bootstrap.min.css">
<style type="text/css">
    th{
        text-align:center;
        background-color:lightgrey;
        color:#999990;
    }
    .table>tbody>tr>td{
        text-align:center
    }
</style>
<script>
    function Read(no){
        document.Read.no.value = no;
        document.Read.submit();               
    }
    function check(){
        if(document.Search.KeyWord.value == "" ){
           alert("검색어를 입력하세요");
           document.Search.KeyWord.focus();           
           return;        
        }
        document.Search.submit();     
    }
</script>
<title>메인 게시판 화면임</title>
</head>
<body>
    <div>
    <table>
        <tr>
           <td align=left>Total : Articles( <font color=red> 1 / 10 Pages </font>)
           </td>
        </tr>
    </table>
    </div>
    
    <div class="col-md-10">
        <table class="table table-striped">
           <tr>
               <th>글 번호</th>
               <th>글 제목</th>
               <th>작성자</th>
               <th>작성날짜</th>
               <th>조회수</th>            
           <tr>
           <c:forEach items="${boardList}" var="list">
           <%--↑ 전체글이 다 뿌려짐 --%>          
           <tr>
               <td>${list.no}</td>
               <td><a href="javascript:Read(${list.no})">${list.subject}</a></td>            
               <td>${list.name}</td>
               <td>${list.regdate}</td>
               <td>${list.cnt}</td>              
           </tr>
           </c:forEach>   
    
           <tr>
               <td align="left">Go to Page</td>
               <td align="right"><a href="Post.jsp">[글쓰기]</a>
                                <a href="board">[처음으로]</a>
               </td>
           </tr>          
        </table>
    </div>
    <BR>
    
    
<%--검색기능 --%>
<form action="board" name="Search" method="post">
    <table border=0 width=527 align=center cellpadding=4 cellspacing=0>
    <tr>
        <td align=center valign=bottom>
        
           <select name="KeyField" size="1">
               <option value="name"> 이름
               <option value="subject"> 제목
               <option value="content"> 내용
           </select>
           <input type="text" size="16" name="KeyWord">
           
           <input type="button" value="찾기" onClick="check()">            
           <input type="hidden" name="page" value= "0">
        </td>
    </tr>
    </table>
</form>
<form name="Read" action="ReadServlet" method="post">
    <input type="hidden" name="no">
    <input type="hidden" name="command" value="Read">  
</form>
</body>
</HTML>



Post.jsp

<%@ page contentType="text/html; charset=EUC-KR" %>
<html>
<head><title>JSPBoard</title>
<link href="style.css" rel="stylesheet" type="text/css">
<script>
    function btn(){
        if(document.post.subject.value == ""){
           alert("내용을 적어주세요!");   
        }else if( document.post.pw.value == ""){
           alert("비밀번호를 적어주세요!");
        }else{
           document.post.submit();
        }       
    }
</script>
</head>
<body>
<br><br>
<table width=80% cellspacing=0 cellpadding=3>
 <tr>
  <td bgcolor=84F399 height=25 align=center>글쓰기</td>
 </tr>
</table>
<br>
<table width=80% cellspacing=0 cellpadding=3 align=center>
<form name="post" action="PostServlet" method="post" >    
 <tr>
  <td align=center>
   <table border=0 width=100% align=center>
    <tr>
     <td width=10%>성 명</td>
     <td width=90%><input type=text name=name size=10 maxlength=8></td>
    </tr>
    <tr>
     <td width=10%>E-Mail</td>
     <td width=90%><input type=text name=email size=30 maxlength=30></td>
    </tr>
    <tr>
     <td width=10%>홈페이지</td>
     <td width=90%><input type=text name=homepage size=40 maxlength=30></td>
    </tr>
    <tr>
     <td width=10%>제 목</td>
     <td width=90%><input type=text name=subject size=50 maxlength=30></td>
    </tr>
    <tr>
     <td width=10%>내 용</td>
     <td width=90%><textarea name=content rows=10 cols=50></textarea></td>
    </tr>
    <tr>
     <td width=10%>비밀 번호</td>
     <td width=90% ><input type=password name=pw size=15 maxlength=15></td>
    </tr>
    <tr>
     <td colspan=2><hr size=1></td>
    </tr>
    <tr>
     <td><input type="button" value="등록" onclick="btn()">  &nbsp;&nbsp;
         <input type=reset value="다시쓰기">&nbsp;&nbsp;
     </td>
    </tr>
   </table>
  </td>
 </tr>
</form>
</table>
</body>
</html>




Read.jsp

<%@page import="model.BoardDto"%>
<%@page import="model.BoardDao"%>
<%@ page contentType="text/html; charset=EUC-KR"%>
<html>
<head><title>JSPBoard</title>
<link href="style.css" rel="stylesheet" type="text/css">
<script>
    function List(){
        document.List.submit();       
    }
    
    function Update(no){
        document.Update.no.value = no;
        document.Update.submit();     
    }
    
    function Delete(no,pw){       
        document.Delete.no.value = no;
        document.Delete.pw.value = pw;
        document.Delete.submit();
    }
</script>
</head>
<body>
<%  request.setCharacterEncoding("euc-kr"); %>             
<br><br>
<table align=center width=70% border=0 cellspacing=3 cellpadding=0>
 <tr>
  <td bgcolor=9CA2EE height=25 align=center class=m>글읽기</td>
 </tr>
 <tr>
  <td colspan=2>
   <table border=0 cellpadding=3 cellspacing=0 width=100%>
    <tr>
     <td align=center bgcolor=#dddddd width=10%> 이 름 </td>
     <td bgcolor=#ffffe8>${Read.name}</td>
     <td align=center bgcolor=#dddddd width=10%> 등록날짜 </td>
     <td bgcolor=#ffffe8>${Read.regdate}</td>
    </tr>
    <tr>
     <td align=center bgcolor=#dddddd width=10%> 메 일 </td>
     <td bgcolor=#ffffe8 >${Read.email}</td>
     <td align=center bgcolor=#dddddd width=10%> 홈페이지 </td>
     <td bgcolor=#ffffe8 ><a href="http://" target="_new">${Read.homepage}</a></td>
    </tr>
    <tr>
     <td align=center bgcolor=#dddddd> 제 목</td>
     <td bgcolor=#ffffe8 colspan=3>${Read.subject}</td>
   </tr>
   <tr>
    <td colspan=4>${Read.content}</td>
   </tr>
   <tr>
    <td colspan=4 align=right>
    ${Read.name} 로 부터 글을 남기셨습니다. | 조회수 : ${Read.cnt}
    </td>
   </tr>
   </table>
  </td>
 </tr>
 <tr>
  <td align=center colspan=2>
    <hr size=1>
    [ <a href="javascript:List()">목 록</a> |
    <a href="javascript:Update(${Read.no})">수 정</a> |
    <a href="javascript:Delete(${Read.no},${Read.pw})">삭 제</a> ]<br>
  </td>
 </tr>
</table>
<form name="List" action="board" method="post"></form>
<form name="Update" action="ReadServlet" method="post" >
    <input type="hidden" name="command" value="Update">
    <input type="hidden" name="no">
</form>
<form name="Delete" action ="Delete.jsp" method="post">
    <input type="hidden" name="no">
    <input type="hidden" name="pw">   
</form>
</body>
</html>




Update.jsp

<%@ page contentType="text/html; charset=EUC-KR"%>
<html>
<head> <title>JSPBoard</title>
<link href="style.css" rel="stylesheet" type="text/css">
<script>
    function check(){
        if(document.UpdateProc.pw.value == ""){
           alert("비번을 입력해야 함.");
           document.UpdateProc.focus();
           return false;          
        }              
        
        document.UpdateProc.submit(); 
    }
</script>
</head>
<body>
<br><br>
<table width=460 cellspacing=0 cellpadding=3>
  <tr>
   <td bgcolor=#FF9018  height=21 align=center class=m>수정하기</td>
  </tr>
</table>
<form name="UpdateProc" action="UpdateServlet" method="post">
    <input type="hidden" name="no" value="${Update.no}">
    
<table width=70% cellspacing=0 cellpadding=7>
 <tr>
  <td align=center>
   <table border=0>
    <tr>
     <td width=20%>성 명</td>
     <td width=80%>
      <input type=text name=name size=30 maxlength=20 value="${Update.name}">
     </td>
    </tr>
    <tr>
     <td width=20%>E-Mail</td>
     <td width=80%>
      <input type=text name=email size=30 maxlength=30 value="${Update.email}">
     </td>
    </tr>
    <tr>
     <td width=20%>제 목</td>
     <td width=80%>
      <input type=text name=subject size=50 maxlength=50 value="${Update.subject}">
     </td>
    <tr>
     <td width=20%>내 용</td>
     <td width=80%>
      <textarea name=content rows=10 cols=50>${Update.content}</textarea>
     </td>
    </tr>
    <tr>
     <td width=20%>비밀 번호</td>
     <td width=80%><input type=password name=pw size=15 maxlength=15>
      수정시에는 비밀번호가 필요합니다.</td>
    </tr>
    <tr>
     <td colspan=2 height=5><hr size=1></td>
    </tr>
    <tr>
     <td colspan=2>
      <input type=Button value="수정완료" onClick="check()">     
      <input type=reset value="다시수정">
      <input type=button value="뒤로" onClick="history.back()">
     </td>
    </tr>
   </table>
  </td>
 </tr>
</table>
</form>
</body>
</html>





PostServlet.java

package Controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.BoardDao;
import model.BoardDto;
public class PostServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //System.out.println("성공");
        req.setCharacterEncoding("euc-kr");
        resp.setCharacterEncoding("euc-kr");
        
        BoardDto board = new BoardDto(); //값을 받아와서  DTO에 저장
        
        board.setName(req.getParameter("name"));
        board.setSubject(req.getParameter("subject"));       
        board.setEmail(req.getParameter("email"));
        board.setHomepage(req.getParameter("homepage"));     
        board.setPw(req.getParameter("pw"));
        board.setContent(req.getParameter("content"));
        
        new BoardDao().insertBoard(board);
        
        RequestDispatcher view = req.getRequestDispatcher("board");
        view.forward(req, resp);
    }
}



ReadServlet.java

package Controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.BoardDao;
import model.BoardDto;
public class ReadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
        doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //System.out.println("성공");
        String command = req.getParameter("command");
        String url = "";
        
        int no = Integer.parseInt(req.getParameter("no")); 
        String pw = req.getParameter("pw");
        
        if(command.equals("Read")) {
           req.setAttribute("Read", new BoardDao().getBoard(no, true));
           url = "Read.jsp";
               
        }else if(command.equals("Update")) {
           req.setAttribute("Update", new BoardDao().getBoard(no, true));
           url = "Update.jsp";                   
        }       
        else if(command.equals("Delete")) {
           BoardDto board = new BoardDao().getBoard(no, true);    
           
           if(pw != null) {
               if(pw.equals(board.getPw())) {
                   new BoardDao().deleteBoard(no);
                   url = "board";
               } else {           
                   url = "Delete.jsp";                       
               }
           }          
        }       
        RequestDispatcher view = req.getRequestDispatcher(url);
        view.forward(req, resp);      
    }
}




UpdateServlet.java

package Controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.BoardDao;
import model.BoardDto;
public class UpdateServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           //System.out.println("성공인감");           
            req.setCharacterEncoding("euc-kr");
            resp.setCharacterEncoding("euc-kr");
           
           int no = Integer.parseInt(req.getParameter("no"));
           BoardDto board = new BoardDao().getBoard(no, true);
            board.setName(req.getParameter("name"));
            board.setEmail(req.getParameter("email"));
            board.setSubject(req.getParameter("subject"));
            board.setContent(req.getParameter("content"));
            board.setNo(Integer.parseInt(req.getParameter("no")));
           
           String url="";
            if(req.getParameter("pw").equals(board.getPw())){
               //여기까지  dto에 저장을 한거임. 이제 dao 메소드에 보내줌.  
               new BoardDao().updateBoard(board);
               url = "board";            
           } else {
               req.setAttribute("Read", board);
               url = "Read.jsp";             
           }
           RequestDispatcher view = req.getRequestDispatcher(url);
           //자꾸 list.jsp로 보낼려고 하는데 이것도 요청이고 글 목록 그래로 가져와야 하니깐 board(servlet)으로 보내야지
           System.out.println("url : " + url);
           view.forward(req, resp);      
    }
}




Web이란?
일반어플리케이션은 한개의 컴퓨터로 한개의 언어로만 만들 수 있다.
하지만 웹어플리케이션은 2대 이상의 컴퓨터가 서로 상호작용하는 것이다.
그래서 여러개의 언어로 섞어서 만든다.



Publisher는 디자이너가 주는 웹디자인을 코드로 꾸며준다.
보통 프론트엔드를 담당한다.
Full-Stack 개발자는 프론트엔드와 백엔드
둘 다 하는 개발자이다.

HTML (Hyper Text Markup Language)

html은 수 많은 Markup Language 중에 하나이다.
Markup Language의 특징은 데이터를 양쪽에서 둘러싼(마크한) 언어이다.
XML은 Markup Language에서 가장 먼저 만들어진 메타언어(언어를 만드는 언어)이다.
HTML은 XML에서 파생되었다.


1. 용도 : 디자인

2. history

HTML을 자세히 배우고 싶다면 아래 홈페이지를 참고하라




Cross Browsing은 다양한 웹 브라우저에서 웹페이지여는 것을 말한다.
웹 브라우저 마다 HTML을 이용하는 형식이 달라서 좋지 않았다.
XHTML은 Cross Browsing을 위해서 나왔다.

HTML의 형식을 어도비 플래시는 멀티미디어 및 다양한 기술을 
웹에서 구현할 수 있도록 만들었다.
그러나 어도비에서 플래시 가격을 올리면 같이 올려져야만 했다.

이후 마이크로 소프트사는 Silverlight를 만들어 플래시의 독점에 대항하기도 했다.
W3C 특정기술이 특정회사에 종속되지 않도록 하기 위해 HTML5를 내놓았다.
HTML5는 특정기술 없이 멀티미디어, 위치기반을 비롯한 
다양한 기술을 웹에서 특정회사 프로그램의 도움 없이 쓸 수 있도록 만들었다.
HTML5는 자바스크립트와 같이 쓸 때 효과를 낼 수 있다.


3. 문법

(1) 기본구조
1
2
3
4
5
6
7
8
9
<html>
      <head>
          선언과 관련된 내용
      </head>
      <body>
           보여질 내용
      </body>
 </html>
 
cs

<HTML의 버전>



HTML 4버전을 보자.
똑같은 4.01 버전이라도 3개가 있다.
Strict은 문법을 빡빡하게
Transitional은 문법을 루즈하게 지킨다.
Frameset은 javadoc 같이 페이지에 프레임을 쉽게 넣을 수 있다.

복잡한 버전명시가
html5에서는 간단하게 되어있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html
 
<!-- HTML 4.01 을 쓸 때 사용한다.
https://www.w3schools.com/tags/tag_doctype.asp 참고-->
<!--
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">;
-->
 
<!-- 주석 -->
<!--HTML 문법을 써보자 -->
<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
    </body>
</html>
 
cs

시작태그와 끝 태그를 묶어서 Element 엘리먼트 라고 말한다.


(2) head 태그(01_head.html)

<방법>
    1) <title></title>
    2) <meta></meta>
    ...

<예제>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
    <head>
        <!--타이틀은 1개만 지정가능-->
        <title>여기는 제목입니다.</title>
        <!--메타태그는 프로그램에 의해서 자연스럽게 만들어진다.-->
        <!--메타태그는 언어형식 등 다양한 메타정보 지정가능-->
        <meta http-eqiv="Content-type"
        content = "text/html; charset=euc-kr"></meta>
        <!--메타태그에서 현재정보를 새로고침하고 네이버로 넘어가도록 한다.-->
        <meta http-equiv="refresh" content="3 ; url="http://www.naver.com"></meta>
    </head>
    <body>
 
        안녕하세요.
    </body>
</html>
 

cs




(3) body 태그 (02_body.html)

    값을 지정하는 방법은 태그와 태그사이에 넣는 방법과 속성에 넣는 방법이 있다.
    속성에 값을 넣는 방법을 알아보자.
    bgcolor, text, background...
    

<예제>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 <!DOCTYPE html>
<html>
    <head>
    </head>
    <body bgcolor="#ccccff" text="red" background="../images/dora (1).jpg">
      안녕하세요. 여기에 무엇이 보입니까?
    </body>
</html>
<!--#16진수 #ccccff를 살펴보자
처음 cc에는 빨간색(R)만 2의 8승인 256가지를 나타낼 수 있다.
중간에 cc는 초록색만(Green)만 2의 8승인 256가지를 나타낼 수 있고,
마지막에 ff는 파란색(Blue)만 2의 8승인 256가지를 나타낼 수 있다.
총 2의 24승인 1600만 가지의 색을 표현할 수 있다.
ffffff 빛을 다 통과하면 하얀색이다.
000000 빛을 다 막아서 검은색이다. -->
<!-- text="red" 글자를 색깔을 표현 할 수 있다.-->
<!--background="../images/dora (1).jpg"는 배경 이미지를 넣는 방법이다.-->
 
cs


<HTML의 색깔표현>
#16진수 #ccccff를 살펴보자
처음 cc에는 빨간색(R)만 2의 8승인 256가지를 나타낼 수 있다.
중간에 cc는 초록색만(Green)만 2의 8승인 256가지를 나타낼 수 있고,
마지막에 ff는 파란색(Blue)만 2의 8승인 256가지를 나타낼 수 있다.
총 2의 24승인 1600만 가지의 색을 표현할 수 있다.
ffffff 빛을 다 통과하면 하얀색이다.
000000 빛을 다 막아서 검은색이다.




(4) 글자꾸미기 (03_글자꾸미기.html)

태그와 태그사이에 값을 넣어보자 (03_글자꾸미기.html)

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<!-- 주석 -->
<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
      <!-- 글자의 크기 : <h숫자> -->
      <!-- 여기서 h는 header를 의미한다. 내용의 제목을 달아줄 때 사용한다.-->
      <!-- h태그는 기본적으로 줄 바꿈과 align 속성을 활용한 정렬기능이 된다.
      이는 일반 태그에는 없는 기능이다.-->
      일반글자
      일반글자
      <h6 align="left">글자크기</h6>
      <h5 align="right">글자크기</h5>
      <h4 align="center">글자크기</h4>
      <h3>글자크기</h3>
      <h2>글자크기</h2>
      <h1>글자크기</h1>
      <!--hr태그는 줄을 만들어준다. hr은 horizontal ruler 이다.-->
      <!--태그를 혼자 쓸 때에는 슬러쉬를 뒤에 쓴다.-->
      <hr/>
      <!--줄바꿈 : <br/>-->
      안녕<br/><br/><br/>
      하세요.
      <hr/>
      <!-- 문단 (문장의 단락을 구분 할 때 쓰는 태그) : <p/> -->
      여기는 한문단 입니다.<p/>
      <p align="center">여기는 두번째 문단입니다.</p>
      <hr/>
      <!--수평선 : <hr/> size는 넓이 width는 두께 align는 정렬-->
      <hr size="100"/>
      <hr size="10" width="300"/>
      <hr size="10" width="300" color="red"/>
      <hr size="10" width="300" color="red" align="left"/>
      <hr/>
      <!--다양한 글자속성-->
      <!--글자를 두껍게 b는 bold의 약자이다.-->
      <b>글자를 두껍게</b><br/>
      <strong>글자를 두껍게</strong><br/>
      <u>글자에 밑줄</u><br/>
      <strike>글자 가운데 선</strike><br/>
      <i>이탤릭체</i>
      <hr/>
      <!-- 리스트 출력 : <ol> odered list, <ul>-->
      <ol>
          <li>사과</li>
          <li>배</li>
          <li>귤</li>
      </ol>
      <ol type='i'>
          <li>사과</li>
          <li>배</li>
          <li>귤</li>
      </ol>
      중간에 다른 내용...
      <ol type='i' start="4">
          <li>사과</li>
          <li>배</li>
          <li>귤</li>
      </ol>
      <!--순서가 필요할때는 <ol> 순서가 필요없을 때는 <ul>-->
      <ul type="square">
          <li>사과</li>
          <li>배</li>
          <li>귤</li>
      </ul>
      <hr/>
      <!--글자 모양 : <font> 폰트 최대크기는 7까지-->
      <font size="7" color="green" face="궁서">
          글자 모양입니다.</font>
      <hr/>
      <!-- ****몇가지 Entity 소개 : &엔티티명;**** -->
      <!-- 엔티티는 표현하기 어려운 개체들을 따로 만들어 가져오는 것이다.-->
      <!-- &nbsp; 는 스페이스바를 한 칸 띄운 엔티티이다. sp는 space-->
      안녕                                        하세요.<br>
      안녕&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;하세요.<br>
      <!-- &lt; &gt; 는 꺽쇠를 문자로 보여주기 위한 엔티티 -->
      <!-- &lt; &gt; 는 less than greater then의 의미이다.-->
      <!-- html에서 <>는 문법의 일부이기 때문에 따로 엔티티로 표시해야한다.-->
      &lt;abc&gt;   <def> <br>
      <!--쌍따온표-->
      &quot;이건 뭘까? &quot;<br>
      <!-- 사이트 내의 저작권을 명시하는 마크 -->
      &copy;copyright 2017
      <hr/>
      <!--****데이터 고정 태그 : <pre>, <xmp>****-->
      <!--<pre>는 글자의 띄어쓰기나 줄바꿈 그대로 나오게 한다.-->
      <!--<pre>는 <pre>내의 html문법을 인식한다.-->
      <pre>
      눈감고 가라
                윤 동주
      태양을 사모하는 아이들아
      별을 사랑하는 아이들아
      밤이 어두웠는데
      <b><i>눈감고 가라</i></b>
      별부리에 돌이 채이거든
      감았던 눈을 와짝 떠라
    </pre>
    <br><br>
    <!--<xml>은 <xml>내의 html문법도 글자로 처리한다.-->
    <xmp>
      눈감고 가라
                윤 동주
      태양을 사모하는 아이들아
      별을 사랑하는 아이들아
      밤이 어두웠는데
      <b><i>눈감고 가라</i></b>
      별부리에 돌이 채이거든
      감았던 눈을 와짝 떠라
    </xmp>
    </body>
</html>
 
cs




(5) 이미지(04_image.html)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 주석 -->
<!DOCTYPE html>
<html>
    <head>
    </head>
    <!--<body background="../images/Tiger.jpg">-->
    <body>
      <!--원하는 위치에서 이미지를 넣을 수 있는 이미지 태그를 넣어보자-->
      <!--alt속성은 이미지에 마우스를 대면 글자가 나온다. 브라우저에 따라 다르다.-->
      <!--border는 테두리이다. -->
      <img src="../images/yong (1).jpg" width="400"
            height="400" alt="해파리" border="10"/>
      <br><br><br>
      <!--vspace : 수직간격조정, hspace : 수평간격조정-->
      <img src="../images/yong (2).jpg" border="1" vspace="20"/>
      <img src="../images/yong (2).jpg" border="1" hspace="20"/>
      <img src="../images/yong (2).jpg" border="1"/><br>
      <img src="../images/yong (2).jpg" border="1"/>
      <img src="../images/yong (2).jpg" border="1"/>
      <img src="../images/yong (2).jpg" border="1"/>
    </body>
</html>
 
cs




(6) 하이퍼링크 (05_hiperlink.html)

   <a>  
    앵커(Anchor)
     - 사전적 의미로는,  배의 닻을 의미
     - 인터넷 웹 상의 HTML 페이지에서는,  어떤 정보(대상)의 시작 지점을 알림
    
    1) 문서의 연결(이동)
    2) 멀티미디어(응용프로그램 기능 실행)
       - 멀티미디어 기능을 plug in을 통해서 실행

<예제>
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
<!DOCTYPE html>
<!--
    URL : 프로토콜명 ://도메인주소:포트번호/파일명#세부위치
http://www.naver.com
-->
<html>
    <head>
    </head>
    <body>
    <!--이동이 가능-->
    <a href="https://www.w3schools.com/">w3schools.com</a><br>;
    <!--꼭 절대경로가 아닌 상대경로를 사용해서 지정한다.-->
    <a href="sub/sub1.html">sub1.html</a><br>
    <!--같은 창에서 창을 띄울 때는 _self, 다른 창에 창을 띄울 때는 _blank-->
    <!--기본값은 _self이며 이는 생략이 가능하다.-->
    <a href="sub/sub1.html" target="_self">sub1.html</a><br>
    <a href="sub/sub2.html" target="_blank">sub2.html</a><br>
    <ul>
        <!--원하는 내용의 이름을 #으로 붙혀준다.-->
        <li><a href="sub/sub2.html#first">첫번째 주제</a></li>
        <li><a href="sub/sub2.html#second">두번째 주제</a></li>
        <li><a href="sub/sub2.html#third">세번째 주제</a></li>
    </ul>
    <hr/>
    <!--프로그램 실행-->
    <a href="res/OutofSight.mp4">단편 애니메이션</a><br>
    <!--서버에서만 실행 됨-->
    <video src="res/OutofSight.mp4" controls autocomplete>애니</video><br>
    <a href="res/zoomit.zip">압축파일</a><br>
    <!--pseudo protocol 보여지지 않는 가상의 프로토콜(약속)이다.-->
    <a href="mailto:goodeducoop@gmail.com">이메일 보내기</a>
    <hr/>
    <!-- 이미지 맵 : 이미지 내 범위를 설정하여 설정한 범위를 클릭하면 이동-->
    <img src="../images/nada1.png"/ usemap="#nada1"/>
    <!--사진과 좌표를 연결해준다.-->
    <map name="nada1">
        <!--선택할 위치의 범위를 사각형으로 지정한다.-->
        <!--범위가 사각형일 경우 이미지 내의 좌표를 대각선으로 두 곳을 잡는다.  -->
        <area shape="rect" coords="455, 85, 663, 257"
              href="http://www.daum.net"/>;
        <!--선택할 위치의 범위를 원으로 지정한다.-->
        <!--범위가 원일경우 중점의 좌표 하나와 반지름의 길이를 넣어준다.  -->
        <area shape="circle" coords="913, 177, 100"
              href="http://www.naver.net"/>;
        <!--범위가 다각형일경우 각 꼭지점마다 좌표를 하나씩 모두 지정해준다.-->
    </map>
    <img>
    </body>
</html>
cs




(7) 테이블 (06_table.html)
행(column)은 좌우, 열(row)은 상하 

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
<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <!--<center>가계부</center><br>
        화면의 가운데로 글씨를 쓴다. html5에서는 쓰지 않는다.-->
        <!--border로 행과 열을 구분-->
        <!--align으로 가운데 정렬-->
        <table border="1" width="300" height="200"
          align="center" bgcolor="pink"
          background="../images/yong (2).jpg">
          <!--<caption>은 테이블의 제목을 달기위해 쓴다.-->
          <caption>가계부</caption>
          <!--행은 tr 열은 td-->
          <tr>
              <!--특정행의 제목행은 <th>-->
              <th>1열</th><th>2열</th>
              <th>3열</th>
          </tr>
          <tr>
              <!--특정열에 색깔을 넣어보자.-->
              <td>1열</td><td bgcolor="yellow">2열</td>
              <td>3열</td>
          </tr>
        </table>
        <!--2번째 테이블-->
        <table border="1" width="200" height="100">
          <!--행은 tr 열은 td-->
          <tr>
              <!--특정행의 제목행은 <th>-->
              <th>1열</th><th>2열</th>
              <th>3열</th>
          </tr>
          <tr>
            <!--colspan으로 열을 합친다.-->
            <td colspan="2">1열</td>
            <!--rowspan으로 행을 합친다.-->
            <td rowspan="2">3열</td>
          </tr>
          <tr>
            <td>1열</td><td>2열</td>
          </tr>
        </table>
        <!--3번째 테이블-->
        <table border="1" width="200" height="100">
          <!--행은 tr 열은 td-->
          <tr>
              <!--특정행의 제목행은 <th>-->
              <th>1열</th><th>2열</th>
              <th>3열</th><th>4열</th>
          </tr>
          <tr>
            <td rowspan="3">가</td><td colspan="3">나</td>
          </tr>
          <tr>
            <td colspan="2">바</td><td rowspan="3">아</td>
          </tr>
          <tr>
            <td>차</td><td>카</td>
          </tr>
          <tr>
            <td colspan="3">파</td>
          </tr>
        </table>
    <body>
    </body>
</html>
cs



(8) DIV
     특정 블럭(구역) 설정
     전체적인 디자인 윤곽을 잡을 때 많이 쓴다.

<디자인 변천사>
a. 초창기 때는 프레임으로 틀을 짰다.
하지만 프레임은 링크를 연결하기 힘들었다.
b. 이후 테이블로 틀을 짜기 시작했다. 
브라우저마다 테이블이 다르게 보이는 문제가 생겼다.
c. 최근에는 div로 틀을 짠다.

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
<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
      <!--div는 개별적인 속성을 줄 수 없다. style을 통해 줄 수 있다. -->
      <!--div는 블럭처럼 한 칸씩 영향을 주며 쌓아나간다.-->
      <!--테이블을 대체해 틀을 잡는다.-->
      <div style="background-color:red">내용</div>
      <span style="background-color:red">내용</span><br>
      <!--div는 테이블보다 문법이 간단하면서 똑같은 효과를 줄 수 있다.-->
      <table width="100%">
          <tr>
              <td bgcolor="red">내용</td>
          <tr>
      </table>
      <hr/>
      <!--div는 블럭처럼 쌓을 수 있다.-->
      <div style="background-color:yellow;width:300px;height:100px">내용</div>
      <div style="background-color:cyan;width:300px;height:100px">내용</div>
      <br><br>
      <!--여러개의 div를 하나로 묶을 수 있다.-->
      <!--margin-top으로 여백을 줄 수 있다.-->
      <div style="margin-top:20px">
        <div style="background-color:yellow;width:300px;height:100px">내용</div>
        <div style="background-color:cyan;width:300px;height:100px">내용</div>
      </div>
      <hr/>
      <!--div는 여백이 있어도 기본적으로 한 줄 전체에 영향을 준다.-->
      <!--float 떠다니다, 둥둥띄워서 움직일 수 있도록 만들어준다.
      div를 좀 더 자유롭게 사용할 수 있도록 한다.-->
      <div style="background-color:yellow;width:300px;height:100px;float:left">내용</div>
      <div style="background-color:cyan;width:300px;height:100px;float:left">내용</div>
      <!--clear로 float의 속성을 지운다.-->
      <div style="clear:both"></div>
      <div style="margin-top:20px">
        <div style="background-color:yellow;width:300px;height:100px">내용</div>
        <div style="background-color:cyan;width:300px;height:100px">내용</div>
      </div>
      <hr/>
      <!--div로 4단 구성을 해보자-->
      <div style="width:600px;">
        <div style="height:50px;background-color:yellow">상단 메뉴</div>
        <div style="margin-top:10px">
          <div style="width:100px;height:300px;background-color:pink;float:left;margin-right:10px">왼쪽 사이드메뉴</div>
          <div style="width:490px;height:300px;background-color:lightgreen;float:left">컨텐츠 영역</div>
        </div>
        <div style="clear:both"></div>
        <div style="height:50px;background-color:lightblue;margin-top:10px">하단 메뉴</div>
    </div>
    </body>
</html>
cs






(9) Input type(08_inputtype.html) : 폼 태그

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
<!DOCTYPE html>
<html>
    <head>
    </head>
      <body>
        <!--submit, reset를 쓰려면 반드시 form 안에 있어야한다.-->
        <form>
        <!--문자열 입력-->
        <input type="text"/><br><br>
        <!--maxlength=""는 글자의 최대크기를 정할 수 있다. 글자수를 입력한다.-->
        <input type="text" size="30" maxlength="15"/><br><br>
        <!--disabled는 입력을 못하게 한다.-->
        <!--disabled는 값(홍길동)이 서버에 전송이 되지 않는다.-->
        <input type="text" value="홍길동" disabled="disabled"/><br><br>
        <!--readonly도 마찬가지로 입력을 못하게 한다.-->
        <!--readonly는 값(홍길동)이 서버로 전송이 된다.-->
        <input type="text" value="홍길동" readonly="readonly"/><br><br>
        <!--password 패스워드 입력을 할 때에만 쓴다.-->
        <input type="password" /><br><br>
        <!--많은 문자열을 입력할 수 있는 영역지정-->
        <textarea rows="5" cols="30"></textarea>
        <hr>
        <!--
        여러줄을 쓸 때 : <시작태그></끝태그>
        한 줄을 쓸 때 : <시작태그/>
        예외가 있는 태그가 여럿이 있다.
        그 중 textarea와 div는 반드시 시작과 끝태그를
        한 쌍으로 해주어야 한다.
        -->
        <!--선택에 따른 입력-->
        <!--라디오 이름을 동일하게 해야 그룹이 되어 1개만 선택 가능하다.-->
        <input type="radio" name="r1" checked="checked">첫번째 라디오<br>
        <input type="radio" name="r1">두번쨰 라디오<br>
        <br>
        <!--체크박스-->
        <!--체크박스를 같은이름으로 하면 프로그래밍을 할 때 배열로 활용 할 수 있다.-->
        <input type="checkbox" name="c1" checked="checked"/>첫번째 체크<br>
        <input type="checkbox" name="c1"/>두번째 체크<br>
        <input type="checkbox" name="c1"/>세번째 체크<br>
        <br>
        <!--선택창 select-->
        <select>
              <option>서울</option>
              <option selected="selected">대전</option>
              <option>대구</option>
              <option>부산</option>
        </select>
        <br>
        <!--사이즈를 지정하여 select를 리스트와 같이 사용한다.-->
        <!--multiple로 다중선택이 가능하도록 한다. ctrl을 같이 눌러 다중선택한다.-->
        <select size="4" multiple="multiple">
              <option>서울</option>
              <option>대전</option>
              <option>대구</option>
              <option>부산</option>
        </select>
        <!--버튼 관련-->
        <!--비어있는 버튼-->
        <input type="button" value="버튼"/><br><br>
        <button>버튼</button><br>
        <!--이미지로 빈버튼을 만들자-->
        <input type="image" src="../images/jesus.jpg"/><br>
        <!--submit : 지금까지 입력한 내용을 서버로 전송하는 기능이 있는 버튼-->
        <input type="submit" value="전송"/><br>
        <!--reset : 입력한 내용을 모두 지워서 다시 입력하게 만드는 버튼-->
        <input type="reset" value="취소"/><br>
        <hr>
        <!--기타-->
        <!--파일선택을 할 수 있다. 선택된 파일은 파일로 전송가능-->
        <input type="file"/><br>
        <!--화면에 보여지지 않고 값을 전달하기 위해 쓴다.-->
        <input type="hidden" name="id" value="scott"/>
      </form>
   </body>
</html>
cs


SQL(Structure Quary Language), SQLPLUS 사용하기




SQL(Structure Quary Language)

- 데이터베이스에 다룰 때 최적화된 언어

- java로 쓰면 10만개의 데이터 조회를 클래스, 

  변수선언, 반복문 10만번, 조건문 등등 을 써야하지만,

  SQL언어이면 1줄이면 데이터조회가 가능하다.

Quary Language : 질문하듯이 만든 언어이다.


SQL은 어떤 언어인가요?


1. 비절차적인 언어


2. 구성요소

SQL은 여러가지 언어를 조합해서 만든 것이다.

아래 네가지 언어를 합쳐서 SQL이라고 한다.


1) DDL (Data Definition Languge)

- 데이터 정의

- 데이터가 저장 될 수 있는 환경을 만들어 준다.

   ① CREATE 만들기

   ② DROP 삭제

   ③ ALTER 수정

- 환경을 만들고 삭제하고 수정한다.

- 개발자가 알고는 있어야 한다.


2) DML(Data Manipulation Languge)

- 데이터를 제어하는 언어

   ① INSERT 추가

   ② DELETE 삭제

   ③ UPDATE 수정

- 실제 데이터를 추가하고 삭제하고 수정한다.

- 개발자가 많이 사용한다.

        


3) DCL(Data Control)

- 보안, 백업, 계정관리...

- 전문적인 관리자들이 알아서 사용.

- 개발자는 거의 사용 할 일이 없다.

- GRANT정도만 알아두면 편하다.

- GRANT, REVOKE, .....


4) QL

- 검색 조회

- DB의 90%이상의 기능

- 매우 주요기능 개발자가 반드시 알아야한다.

- SELECT : 다른 것 합친 것 보다 기능이 많다.



sqlplus 사용법


1. 접속

[방법1]

sqlplus

사용자 ID : 

비밀번호 :


예)

User@DESKTOP-G1R697G C:\Users\User

> SQLPLUS


SQL*Plus: Release 11.2.0.1.0 Production on 일 11월 26 11:04:01 2017


Copyright (c) 1982, 2010, Oracle.  All rights reserved.


사용자명 입력: SCOTT

비밀번호 입력:



결과값

다음에 접속됨:

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Poduction

With the Partitioning, OLAP, Data Mining and Real Application Testig options


[방법2] 

sqlplus 사용자ID/비밀번호 (비밀번호가 보이기 때문에 반드시 뒤를 조심한다.)




[방법3] 

sqlplus 사용자ID

    비밀번호




4)  sqlplus 사용자ID/비밀번호@host명

- 다른 컴퓨터에 접속할 때 방법

- 별도의 설정이 필요하다.



5) connect 사용자ID/비밀번호

    conn ... (connect 의 약자)


 



2) 계정관리


show user 


를 치면 유저의 이름이 나온다.


SELECT username, account_status FROM DBA_USERS;


해석 : DBA_USERS 에서 username, account_status 를 가져와라


데이터베이스에는 데이터를 포함한 객체들로 구성되어 있다.



ALTER 

데이터가 아닌 그외의 나머지 수정


▶ 아래는 초기설정에서 사용자계정을 잠금으로 설정한 경우에 사용


ALTER user scott ACCOUNT UNLOCK; 

데이터가 아닌 scott이라는 사용자 계정을  잠금해제로 수정


ALTER user hr ACCOUNT UNLOCK; 

데이터가 아닌 hr이라는 사용자 계정을  잠금해제로 수정


ALTER user scott IDENTIFIED BY 1111;

데이터가 아닌 scott이라는 사용자 계정의 비밀번호를 1111로


ALTER user hr IDENTIFIED BY 1111; 

데이터가 아닌 hr이라는 사용자 계정의 비밀번호를 1111로


▶ scott을 연결해보자.


conn scott/1111

이는 샘플로 놓은 데이터이기 때문에 마음껏 사용해도 괜찮다.





★ Field( = duf, coumn, 속성)

칸 하나 하나

데이터의 최소단위


★레코드( = 튜블)

여기서 이름, 나이 성별, 주소 한 행을 레코드라고 한다.

레코드는 관련있는 필드끼리의 묶음이다.

- 필드 하나는 가치가 없지만 레코드부터 활용가치가 있다.

- 필드와 레코드까지는  메모리에 저장

- 테이블은 램에 저장



필드 < 레코드 < 테이블(파일) < 테이블 < 데이터베이스 < 데이터뱅크

여기서 실제 많이 사용하는 것은 데이터베이스 까지이다.


계정을 만들어 보자.


CREATE USER test1 IDENTIFIED BY 1111;


GRANT CONNECT TO test1;


GRANT 권한을 주는 객체

CONNECT 연결한다.

TO ~에게

test1 계정에 접근한다.


테이블을 생성하기 위한 명령어를 친다.


CREATE TABLE tbltest(id number, name varchar2(10));




권한이 불충분하다고 한다면, 관리자에게 간다.



GRANT RESOURCE TO test1 ;


다시 돌아가서 테이블을 생성한다.


CREATE TABLE tbltest(id number, name varchar2(10));




삭제 명령어인 DROP 을 사용해보자.

DROP USER test1;

를 누르면 삭제가 되지 않는다.

오라클의 안전장치 때문이다. 

테이블을 먼저 삭제하고 계정을 삭제해야한다.

계정 강제삭제는 CASCADE 를 누르면 된다.


DROP USER test1 CASCADE;

데이터베이스 개요, 오라클 소개 

데이터베이스 : 데이터를 모아 놓은 것

데이터를 활용하려면?

삽입, 삭제, 수정, 조회

이 네가지 기능이 반드시 필요하다.

이를 Database(DB)의 기본연산이라고 한다.

DBMS (Database Management System)
데이터베이스 관리 시스템

Oracle
Mysql
MongoDB
MS-SQL Server
Infomix
DB2
Sqlite
...


용도에 따라 구분한 Database

로컬용
- 하나의 컴퓨터 안에서만 내부에서 사용하는 데이터 베이스
- 예전에 많이 나옴
- 대표적인 로컬용 DB : Sqlite (안드로이드), Access (MS오피스)

서버용
- 네트워크 등 원격으로 외부에서 접속할 수 있도록 기능을 가짐  
- 최근에 주류. 대부분 데이터베이스는 서버용이다.
- 다른 컴퓨터가 접속하면 DB열람 가능
- 클라이언트, 서버 프로그램이 나뉘어져 있음

Oracle
- Full Version : 모든 기능 사용 가능, 용량 높음
- Express Version : 간단한 개발용, 간이용, 용량낮음

중소기업 이상의 데이터 베이스
오라클은 데이터 베이스 개발이 아니라 AS로 돈을 번다.

중소기업 등에서는 
Mysql
Infomix
을 많이 쓴다.

오라클을 국내에서는 아주 오래전에 나온 8i/9i 버전이 가장 많이 쓰이고 있다.


8i/9i(아주 오랫동안 사용) → 10g (단종, 보안취약) 
 11g(오랫동안 안정적으로 사용) → 12c(가장 최근에 나옴)

i, g, c 는 그 당시에 가장 트렌드 된 기술을 뒷글자로 붙힘.

i : iinternet  ▶인터넷
g : grid compotent  컴퓨터를 격자처럼 묶어서 사용
c : cloud ▶ 클라우드 서비스에서 알아서 제공


참고로 클라우드 서비스는 관리 서비스가 포함되어 db관리자가 사라질 수 있다.

오라클
데이터베이스 
실제 데이터를 관리할 수 있는 덩어리

소프트웨어
데이터베이스를 관리하기 위한 덩어리

데이터 베이스는 사용자에 따라 여러개 생성되지만 소프트웨어는 1번만 설치하면 된다.


오라클 oracle 설치방법 / docs 문서보기


<오라클 제품 종류>

Administrator (관리기능)
- 관리기능은 어마어마하다.
Developer(개발기능)
- 개발기능만 따지면 얼마되지 않는다.


데이터베이스는 설계가 매우 중요하다 
데이터베이스 설계에 관한 책을 사야 될 것이다.


<오라클에서 무료제공하는 클라이언트db 유틸리티>

sqlplus
오라클11g 에서 서버 프로그램은 오라클 클라이언트 유틸리티는 sqlplus 이다.
클라이언트 유틸리티 sqlplus는 도스에서 명령어를 쓸 수 있는데
오라클을 깔면 함께 깔린다.

sqldeveloper
윈도우에서 명령어 없이 사용하려면 sqldeveloper를 따로 깔아서 쓰면 된다.

<다른 회사 프로그램으로 오라클지원하는 유료제공 클라이언트db 유틸리티>
Toad
가장 비싸고 오래되었다.

그 외 sqlgate 등등이 있다.


<sqlplus를 접속해보자>

cmd 도스 창에서

sqlplus 를 눌러보자

사용자명 입력 : System
비밀번호 입력 : 1111

빠져나와 보자

quit


<Database 저장형태에 따른 구분>

1. 계층형 DB(HDB) -tree
- tree구조의 단점으로 조회하는데 시간이 오래걸린다.





2. 네트워크형 DB(NDB)
- 기본적으로 트리구조인데 그물망처럼 그래프(graph)로 묶는다.
- 어떤 것이든 연결이 되어 있어서 데이터가 이동
- 너무 복잡해서 설계가 어려워서 이론상으로만 생각한다.



3. 관계형 DB(RDB)
- table
- 현재 가장 많이 쓰는 DB 형태


4. 객체지향형 DB(ODB)
- object
- 현존하는 가장 좋은 DB방식
- 관리자들이 어려워서 못 쓴다.

5. 객체지향형 DB(ORDB)
- 관계형DB + 객체지향형 DB
- 오라클에서는 객체지향형 DB도 제공한다.


오라클 설치방법


오라클 홈페이지에 들어가자


https://www.oracle.com/index.html


아래 사진대로 하나씩 따라해보자.



Menu ▶ Database▶ All Database Download








전자메일 주소는 패스합니다. '예' 를 누른다.




DB 연습이므로 비밀번호는 기억하기 쉬운 1111로 한다.

실무에서 이렇게 하면 정말 큰일난다.





비밀번호 관리에 들어가서 관리자인 SYS와 SYSTEM의 계정잠금을 해제한다.




연습용 DB인 SCOTT과 HR의 비밀번호는 1111로 한다.

물론, DB 연습이라서 이렇게 한다.

실제로는 비밀번호 관리에 조심해야한다.





CMD에서 DB를 테스트 해보자.






<오라클 문서를 보려면 어떻게 해야할까?>


https://docs.oracle.com/cd/E11882_01/index.htm





Network 기본지식


Cisco : 세계최대 라우터 회사


NCSE :Cisco  네트워크 자격증


네트워크 입문자용 도서 추천

후니의 쉽게 쓴 시스코 네트워킹 

http://www.aladin.co.kr/shop/wproduct.aspx?ItemId=11083088



<네트워크와 운영체제>


네트워크(Network)

- 두 대 이상의 장치가 서로 연결되서 서로 작업을 할 수 있는 상태

- 서로 떨어져 있는 장치들의 연결이 네트워크이다.



운영체제


DOS(disk operating system)

- 한 대의 컴퓨터를 관리하는 시스템

- MS-DOS, Window 3.1, 95, XP, ME ... 7, 8, 10


NOS(network operating system)

- 여러대의 컴퓨터의 네트워크를 관리하는 시스템

- WindowsNT4.0, Linux ....

- 최근 나오는 운영체제는 어느정도 네트워크 관리 기능이 있다.



<서버와 클라이언트>


Client 클라이언트

- 손님

- 요청한다.

- 반드시 클라이언트가 먼저 요청한다.


Server 서버

- 서비스 제공자

- 응답한다.

- 클라이언트의 요청에 따라 응답한다.


역할에 따라 클라이언트가 되기도 하고 서버가 되기도 한다.


<도메인과 P2P>

도메인 : 하나의 서버의 역할이 확실히 정해져 있는 것을 도메인이라고 한다.

P2P : 내가 서버가 될 수도 있고 내가 클라이언트가 될 수 있는 것을 P2P라고 한다.




<최근 뜨는 언어>

Go : 스레드 처리에 강한 언어 (구글)

elang

Phython

스칼라



<네트워크에서 중요한 것>


1.프로토콜(Protocol)

- 회사간의 약속, 협정서, 규칙, 규약

- 정보를 서로 쉽게 공유하기 위한 약속


프로토콜 예시)


HTTP

Hyper Text Transfer Protocol : 하이퍼텍스트를 전송하기 위한 약속


Hyper Text = html : 문서와 다른 문서로 클릭만 하면 연결되어 보여짐


FTP 

File Transfer Protocol : 파일을 전손하기 위한 약속


IPX/SPX

Novel : 전세계적으로 매우 유명한 회사

Netware : novel사의 네트워크 운영체제

IPX/SPX 는 Netware의 프로토콜이다.

스타크래프트를 할 때 처럼 로컬네트워크끼리 

서로 연결하는 방법으로도 많이 사용했지만 원래 용도는

네트워크 프로토콜이다.


TCP/IP

매우 중요한 프로토콜



<TCP/IP>

OSI 7계층

- Open System Intercon-nection 에서의 약속




7계층 - 응용 계층

수신한 데이터로 서비스를 제공하거나 데이터를 송신하는 서비스를 하는 부분입니다.


6계층 - 표현 계층

데이터 자체가 표현되는 방법을 말한다. 데이터 압축이나 암호화가 이에 해당합니다.


5계층 - 세션 계층

단말기 사이의 연결을 구축하고 유지하며 종료시키는 역할을 한다. 또한 전달할 데이터를 동기화, 즉 데이터 교신 순서를 정합니다.


4계층 - 전송 계층 ★★★

네트워크 계층에 전달되는 데이터의 순서와 데이터의 에러를 찾아내고 필요하다면 다시 송수신을 한다. 경우에 따라 데이터를 분할하여 전송하고나 도착한 데이터를 역으로 조합합니다.


3계층 - 네트워크 계층 ★★★

두 지점간의 데이터 전송에 대해 경로 배정과 중계를 담당한다. 컴퓨터의 NIC(Network Interface Card)가 이에 해당하며 흔히 말하는 IP를 갖고 있습니다.


2계층 - 데이터 링크 계층

인접해 있는 단말기간에 데이터를 전달하는 역할과 제어를 담당한다. 데이터를 패킷으로 분할하고, 데이터 흐름을 조절하며, 전달 도중에 에러를 검사 및 발생했을 때 재전송을 합니다.


1계층 - 물리 계층

단말기간의 물리적인 교신 표준을 정의한다. 전기적인 신호 전압, 통신에 사용할 케이블 등 통신 장비들이 1계층에 해당합니다.


출처: http://serblin.tistory.com/2 [손석진의 프로그래밍]



데이터를 보내기 한 전달체계를 약속하고 프로그램이나 하드웨어를 만들 수 있도록 했다.

현재는 7계층이 모두 필요없기 때문에 요즘에는 TCP/IP 4계층으로 바뀌었다.

Java로 프로그램을 짜려면 전송계층과 네트워크계층을 알아야한다.



- (TCP/IP 는  수백개의 약속을 묶어서 대표적인 이름으로 부르는 것이다.)


4계층을 살펴보기 전에 7계층을 살펴보자.


전송계층은 다른 장치와이 연결은 당연하지만 제대로 전송이 되었는지 안정성을 체크한다.

전송계층에서 중요한 약속은 TCP, UDP 프로토콜이다.

네트워크계층은 다른장치와의 연결만을 신경쓴다. 네트워크계층의 중요한 약속이 IP이다.


전송계층 : TCP, UDP

네트워크 : IP


를 좀 더 알아보자.


먼저 TCP, UDP


<TCP, UDP>


TCP : 연결지향적

- 연결지향적 : 미리 연결을 해놓고 작업을 하는 방식이다.

- 전화장치와 비슷한다.

- 장점 : 데이터를 안전하게 주고 받을 수 있다.

- 단점 : 먼저 선을 연결해야하기 때문에 UDP와 비교해서 속도가 떨어진다.

- 1:1 통신에 많이 쓰인다.

- 중요한 정보일 때는 TCP이다.


UDP : 비연결지향적

- 비연결지향적 : 연결을 하지 않고 그냥 바로 데이터를 주고 받는다. 

필요할 때만 데이터를 주고 받고 필요하지 않으면 연결을 끊는다.

- 무전기와 비슷하다.

- 장점 : 필요할 때만 연결하기 때문에 주고 받는 속도가 빠르다.

- 단점 : 불안정하다.

- 불특정 다수를 향한, 주로 방송에 쓰인다.

- 정보가 약간은 손실되어도 괜찮거나, 대량의 파일을 처리할 때 쓴다.


최근에는 회선이 안정적이기 때문에 UDP를 많이 쓴다.

그래서 프로그램을 UDP를 많이 쓴다.



2 .ip, 포트, 소켓


보통네트워크를 만들면 서버용과 클라이언트용 두개를 한 쌍으로 만든다.

하지만 웹은 서버용만 만든다.

브라우저라는 클라이언트 프로그램이 있기 때문이다.


ip는 인터넷상에서 컴퓨터를 구별하게 해준다.

ip는 두가지가 있다. real IP와 virtual IP 이다.

IP는 충돌만 안나면 된다.


▶virtual IP 

사용자가 가상으로 지정하는 가짜 아이피 

한 지역에서만 사용하는 아이피 (주로 로컬네트워크)


▶RealIP 

인터넷 기관으로 받은 진짜 아이피 전세계적으로 사용하는 지정된 아이피



<Static IP 와 Dynamic IP>

▶Static IP

한번 입력하면 아이피가 바뀌지 않는다.

서버는 Static 고정아이피 서비스를 했다.


계속해서 아이피가 바뀐다.

000.000.000.000

32비트 주소 : 2에 32승 (IPV4 : IP버전 4)

40억개의 주소체계

예전에는 괜찮았지만 지금은 아이피가 모자르다.

IPV6 : IP버전 6 최근에 사용하는 주소체계

한국에서는 2개를 혼재해서 쓴다.



▶ Dynamic IP

내가 쓸때만 아이피를 부여받는다.


└ DHCP 서버

IP를 모아놓았다가 자동으로 다시 회수했다가 준다.


DNS(도메인 이름 서비스)

IP를 도메인으로 연결해준다.


<port 포트 >

모든 네트워크들은 통로를 하나씩 가지고 있는데

이를 포트라고 한다. 이 포트는 각 프로그램의 입구 번호,

아파트 동 호수라고 생각하면 된다.


<socket 소켓>

socket = IP+ Port + Data

내가 하고 싶은 것을 마음껏 하기 위해서는 소켓을 할 줄 알아야한다.

네트워크프로그램을 한다는 것은 소켓프로그램을 하는 것이다.


<스프링 : 프레임워크>

프로그램을 좀 더 빨리 쉽게 만들 수 있는 틀

웹을 조금 더 다른 방법으로 사용할 수 있도록해준다.

스프링을 이용해서 만들면 견고하고 안전하다.

한국에서 취업하기에는 좋다.



Network


1. 관련클래스 : java.net*


java.base > java.net



2. InetAddress

- IP를 객체화 시키는 클래스. 주도적으로 사용하는 클래스는 아니다.

- IP와 관련된 정보를 가져올 때 사용한다.

- is 메소드 : 주로 맞냐 아니냐를 묻는다.


<내 컴퓨터 ip주소 확인하기>

DOS 창을 열어서 ipconfig 를 열면 내컴퓨터 아이디 확인 할 수 있다.


예)

C:\Users\User>ipconfig

Windows IP 구성

무선 LAN 어댑터 로컬 영역 연결* 2:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김

   연결별 DNS 접미사. . . . :

이더넷 어댑터 이더넷:

   연결별 DNS 접미사. . . . :

   링크-로컬 IPv6 주소 . . . . : fe80::4919:ff9:ac3e:d9de%9

   IPv4 주소 . . . . . . . . . : 70.12.113.140

   서브넷 마스크 . . . . . . . : 255.255.255.0

   기본 게이트웨이 . . . . . . : 70.12.113.1

무선 LAN 어댑터 Wi-Fi:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김

   연결별 DNS 접미사. . . . :

터널 어댑터 로컬 영역 연결* 12:

   연결별 DNS 접미사. . . . :

   IPv6 주소 . . . . . . . . . : 2001:0:9d38:6abd:c1f:13bc:b9f3:8e73

   링크-로컬 IPv6 주소 . . . . : fe80::c1f:13bc:b9f3:8e73%5

   기본 게이트웨이 . . . . . . : ::

C:\Users\User>ping

사용법: ping [-t] [-a] [-n count] [-l size] [-f] [-i TTL] [-v TOS]

            [-r count] [-s count] [[-j host-list] | [-k host-list]]

            [-w timeout] [-R] [-S srcaddr] [-c compartment] [-p]

            [-4] [-6] target_name

옵션:

    -t             중지될 때까지 지정한 호스트를 ping합니다.

                   통계를 보고 계속하려면 <Ctrl+Break>를 입력합니다.

                   중지하려면 <Ctrl+C>를 입력합니다.

    -a             주소를 호스트 이름으로 확인합니다.

    -n count       보낼 에코 요청의 수입니다.

    -l size        송신 버퍼 크기입니다.

    -f             패킷에 조각화 안 함 플래그를 설정(IPv4에만 해당)합니다.

    -i TTL          Time To Live

    -v TOS         서비스 종류(IPv4에만 해당. 이 설정은 더

                   이상 사용되지 않으며 IP 헤더의 서비스 종류 필드에 영향을

                   주지 않음)입니다.

    -r count       count 홉의 경로를 기록합니다(IPv4에만 해당).

    -s count       count 홉의 타임스탬프(IPv4에만 해당)입니다.

    -j host-list   host-list에 따라 원본 라우팅을 완화합니다(IPv4에만 해당).

    -k host-list   host-list에 따라 원본 라우팅을 강화합니다(IPv4에만 해당).

    -w timeout     각 응답의 대기 시간 제한(밀리초)입니다.

    -R             라우팅 헤더를 사용하여 역방향 라우팅도

                   테스트합니다(IPv6에만 해당).

                   RFC 5095에 따라 이 라우팅 헤더는 사용되지

                   않습니다. 이 헤더를 사용할 경우 일부 시스템에서 에코

                   요청이 삭제될 수 있습니다.

    -S srcaddr     사용할 원본 주소입니다.

    -c compartment 라우팅 컴파트먼트 ID입니다.

    -p             Hyper-V 네트워크 가상화 공급자 주소에 대해 ping을 수행합니다.

    -4             IPv4를 사용합니다.

    -6             IPv6을 사용합니다.


<상대컴퓨터와 연결되어 있는지 확인하기>

ping을 도스에 쳐보자.

ping : 상대 컴퓨터가 네트워크에 연결되어 있는지 확인.


ping 이 안되면 네트워크가 연결이 안되었거나 방화벽등 다른 이유로 막혀있는 것이다.


예)

C:\Users\User>ping 180.70.152.166

Ping 180.70.152.166 32바이트 데이터 사용:

180.70.152.166의 응답: 바이트=32 시간=36ms TTL=51

180.70.152.166의 응답: 바이트=32 시간=21ms TTL=51

180.70.152.166의 응답: 바이트=32 시간=10ms TTL=51

180.70.152.166의 응답: 바이트=32 시간=23ms TTL=51

180.70.152.166에 대한 Ping 통계:

    패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),

왕복 시간(밀리초):

    최소 = 10ms, 최대 = 36ms, 평균 = 22ms


<아이피나 도메인 이름을 찾아줄 때>

nslookup

아이피나 도메인 이름을 찾아줄 때 사용


예)

C:\Users\User>nslookup

기본 서버:  nic.samsung.co.kr

Address:  203.241.132.34

> nslookup 125.209.222.141

서버:    [125.209.222.141]

Address:  125.209.222.141

DNS request timed out.

    timeout was 2 seconds.

DNS request timed out.

    timeout was 2 seconds.

*** 125.209.222.141에 대한 요청이 제한 시간을 초과했습니다.



Module java.base

Package java.net

Class InetAddress


를 가보면 생성자를 막아놓았다.

왜 막아 놓았을까?


싱글톤 Singleton 이기 때문에 인스턴스를 하나만 생성했다.


이렇게 클래스마다 특성이 다르기 때문에 API를 보아야한다.



package prjNetwork;

import java.net.InetAddress;

import java.net.UnknownHostException;

public class InetaddressTest {

    

    

    public static void main(String[] args) {

        

        try {

            InetAddress inet = InetAddress.getByName("google.co.kr");

            System.out.println(inet.getHostAddress());

            System.out.println(inet.getHostName());

        } catch (UnknownHostException e) {

            System.out.println("주소를 찾을 수 없습니다.");

        }

    }

}


※ 결과값


172.217.24.35

google.co.kr



package prjNetwork;

import java.net.InetAddress;

import java.net.UnknownHostException;

public class InetaddressTest {

    

    

    public static void main(String[] args) {

        

        try {

            //InetAddress클래스는 IP관련 정보를 가져올 때 사용한다.

            InetAddress inet = InetAddress.getByName("google.co.kr"); //

            System.out.println(inet.getHostAddress());        //호스트주소를 가져온다.

            System.out.println(inet.getHostName());            //사이트주소를 가져온다.

            

            System.out.println("----------------------------");

            inet = InetAddress.getByName("172.217.24.195"); //

            System.out.println(inet.getHostAddress());

            System.out.println(inet.getHostName());

            

            System.out.println("----------------------------");

            // Loopback 하나의 컴퓨터를 두 대의 컴퓨터처럼 사용하게 해준다.

            // LoopbackAddress 내컴퓨터 랜카드에서 제공하는 테스트를 위해 서버역할을 하는 가상도메인을 가져온다.

            // 로컬호스트는 내 컴퓨터에서 사용하는 가상도메인이다.

            inet = InetAddress.getLoopbackAddress();        //내컴퓨터 안의 서버용으로 쓰기 위한 가상도메인이다.

            System.out.println(inet.getHostAddress());

            System.out.println(inet.getHostName());

            

            

        } catch (UnknownHostException e) {

            System.out.println("주소를 찾을 수 없습니다.");

        }

    }

}



※ 결과값


172.217.24.35

google.co.kr

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

172.217.24.195

hkg12s13-in-f3.1e100.net

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



<소켓>

다른프로그램과의 통신을 시도하겠다는 의미

다른 컴퓨터의 프로그램과 소통할 수 있는 통로를 만들어 놓겠다.

소켓이 미리 선을 깔아 놓는 것이기 때문에 TCP방식을 쓴다는 이야기


<웹서버>

만약에 naver를 들어간다고 생각해보자.

우리는 어떻게 네이버의 화면을 볼 수 있을까?

웹서버가 있기 때문에 네이버의 프로그램에 들어갈 수 있다.

웹서버는 모두 포트가 있다.

웹서버의 기본포트는 80이다.


www.naver.com:80

누구에게나 공개가 되어있기 때문에 보통은 생략한다.


포트는 네트워크 프로그램에 달려있는 통로이자 문이다.




package prjNetwork;

import java.io.IOException;

import java.net.Socket;

import java.net.UnknownHostException;

public class SocketTest1 {

    public static void main(String[] args) {

        

        Socket socket = null;

        

        try {

            //소켓 : 다른프로그램과의 통신을 시도하겠다는 의미

            //다른 컴퓨터의 프로그램과 소통할 수 있는 통로를 만들어 놓겠다.

            //소켓이 미리 선을 깔아 놓는 것이기 때문에 TCP방식을 쓴다는 이야기

            //자바에서 소켓을 쓴다는 의미는 클라이언트가 된다는 뜻이다.

            socket = new Socket("www.naver.com";, 80);    

            System.out.println(socket);

        } catch (IOException e) {

            e.printStackTrace();

        }finally {

            try {

                socket.close();            //소켓을 닫아준다.

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

}



※ 결과값


Socket[addr=www.naver.com/202.179.177.21,port=80,localport=14573]



port=80

네이버의 포트번호 

(네이버 뿐 아니라 기본적으로 많이 쓰는 포트번호이다.)


localport=14573

내 컴퓨터의 포트번호

자동적으로 사용을 안하는 포트번호를 잡아준다.


www.naver.com

네이버의 주소


202.179.177.21,

네이버 서버주소


포트는 운영체제가 만들어놓은 문들(포트)을 가져다 쓴다.


아래 주소를 따라가보자.

C:\Windows\System32\drivers\etc

에는 운영체제에 네트워크 관련 파일들이 있다. 여기에서 services를 열어보자


...(중략)...

http               80/tcp    www www-http           #World Wide Web

hosts2-ns          81/tcp                           #HOSTS2 Name Server

hosts2-ns          81/udp                           #HOSTS2 Name Server

kerberos           88/tcp    krb5 kerberos-sec      #Kerberos

kerberos           88/udp    krb5 kerberos-sec      #Kerberos

hostname          101/tcp    hostnames              #NIC Host Name Server

iso-tsap          102/tcp                           #ISO-TSAP Class 0

rtelnet           107/tcp                           #Remote Telnet Service

...(중략)...


6만 여개 포트 중에서 쓰고 있는 포트 번호가 있다.

쓰고 있는 포트 번호를 제외하고 안쓰고 있는 포트번호를 부여받는다.




package prjNetwork;

import java.io.IOException;

import java.net.Socket;

import java.net.UnknownHostException;

public class SocketTest1 {

    public static void main(String[] args) {

        

        Socket socket = null;

        

        try {

            //소켓 : 다른프로그램과의 통신을 시도하겠다는 의미

            //다른 컴퓨터의 프로그램과 소통할 수 있는 통로를 만들어 놓겠다.

            //소켓이 미리 선을 깔아 놓는 것이기 때문에 TCP방식을 쓴다는 이야기

            //자바에서 소켓을 쓴다는 의미는 클라이언트가 된다는 뜻이다.

            socket = new Socket("www.naver.com";, 80);    

            System.out.println(socket);

            System.out.println("------------------------------------------------");

            

            //현재접속한 서버를 통해서 주소를 알 수 있다.

            System.out.println("서버주소 : " + socket.getInetAddress());

            System.out.println("서버주소 : " + socket.getInetAddress().getHostName());

            System.out.println("서버주소 : " + socket.getInetAddress().getHostAddress());

            System.out.println("서버주소 : " + socket.getPort());

            System.out.println("------------------------------------------------");

            

            //현재접속한 클라이언트(내 프로그램)를 통해서 주소를 알 수 있다.

            System.out.println("클라이언트주소 : " + socket.getLocalAddress());

            System.out.println("클라이언트주소 : " + socket.getLocalAddress().getHostName());

            System.out.println("클라이언트주소 : " + socket.getLocalAddress().getHostAddress());

            System.out.println("클라이언트주소 : " + socket.getLocalPort());

            

        } catch (IOException e) {

            e.printStackTrace();

        }finally {

            try {

                socket.close();            //소켓을 닫아준다.

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

}



※ 결과값


Socket[addr=www.naver.com/202.179.177.21,port=80,localport=14898]

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

서버주소 : www.naver.com/202.179.177.21

서버주소 : www.naver.com

서버주소 : 202.179.177.21

서버주소 : 80

클라이언트주소 : /70.12.113.140

클라이언트주소 : DESKTOP-G1R697G

클라이언트주소 : 70.12.113.140

클라이언트주소 : 14898



package prjNetwork;

import java.io.BufferedReader;

import java.io.FileWriter;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.net.Socket;

import java.net.UnknownHostException;

public class SocketTest2 {

    public static void main(String[] args) throws UnknownHostException, IOException {

        

        Socket socket = new Socket("www.multicampus.com";, 80);

        

        //받을 준비

        //서버가 보내서 입력된 데이터를 한 줄씩 읽는다.

        BufferedReader br =

                new BufferedReader(    //.getInputStream() 서버에서 무언가를 받을 때 쓰는 메서드

                        new InputStreamReader(socket.getInputStream(), "utf-8"));  

        

        //서버에게 무언가를 보낼준비.

        OutputStream out = socket.getOutputStream();

        //아래 ""의 값을 서버에 보낸다.

        out.write(("GET /index.html HTTT/1.0" + "\r\n\n").getBytes());

        out.flush();

        

        

        String line = null;

        while((line = br.readLine())!=null) {

            System.out.println(line);

        }

        

    }

}



※ 결과값


HTTP/1.1 404 Not Found

Date: Thu, 09 Nov 2017 02:33:59 GMT

Server:

Last-Modified: Fri, 12 Nov 2010 05:59:16 GMT

ETag: "d12-494d4ca5e5500"

Accept-Ranges: bytes

Content-Length: 3346

Connection: close

Content-Type: text/html

Content-Language: en

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=euc-kr" />

<link href="http://www.credu.com/Error/css/normal.css"; rel="stylesheet" type="text/css">

<script language="JavaScript"></script>

<title>Login</title>

</head>

<!-- ????? ÷?????? ???ε? ?????? ???? ??? -->

<script>

    function pop(url,name,w,h){ window.open(url,name,'width='+w+',height='+h+',scrollbars=yes, status=no') }

</script>

<body>

<table width="829" height="450" border="0" align="center" cellpadding="0" cellspacing="0">

  <tr>

    <td height="5" background="http://www.credu.com/Error/img/bg_top.gif"></td>;

  </tr>

<tr>

    <td background="http://www.credu.com/Error/img/bg.gif">;

      <table width="829" border="0" cellspacing="0" cellpadding="0" >

        <tr>        

        <td align="center">

        <!--///////////////////////////////////// $$ Start of ?????? /////////////////////////////////////////-->

        <table width="630" border="0" cellpadding="0" cellspacing="0">

          <tr>

            <td height="1" bgcolor="#d6e2ee"></td>

          </tr>

          <tr>

            <td bgcolor="#edf4fb">

            <table width="100%" border="0" cellspacing="0" cellpadding="0">

              <tr>

                <td><img src="http://www.credu.com/Error/img/Error_tit.gif"; width="630" height="90" alt=""></td>

              </tr>            

              <tr>

                <td style="padding-left:52; color:#62849e; font-family:????;"><img src="http://www.credu.com/Error/img/Error_dot.gif"; width="3" height="3" align="absmiddle" hspace="3"><strong>?????? ???????? ??? ?? ????? ???????? ???????.</strong></td>

              </tr>

              <tr>

                <td height="10"></td>

              </tr>

              <tr>

                <td style="font-size:11px; color:#888888; font-family:????; padding-left:61; line-height:17px"><!--- ???? ??????? ??????. --->

                ?????? ?????? ???? ??????? ??? ??? ????????? ??????.<br>

                ?????? ?????? ?????????? ?????? ??쿡 ???? ??? ???? ????帳???.

                </td>

              </tr>

              <tr>

                <td height="11"></td>

              </tr>

              <tr>

                  <td align="center">

                      <div class="Error_down">

                          <a href="http://www.credu.com/de_common/credu/popup/20090925/090925_report_error.html"; onclick="pop(href,'company',570,750); return false;"><img src="http://www.credu.com/Error/img/btn_Error_down.gif"; alt="???? ????????" border="0" /></a>

                      </div>

                  </td>

              </tr>

              <tr>

                <td height="5"></td>

              </tr>

              <tr>

                 <td align="center"><img src="http://www.credu.com/Error/img/Error_info.gif"; width="540" height="71"></td>

              </tr>

              <tr>

                <td align="center">&nbsp;<a href="mailto:webmaster@credu.com" onfocus="this.blur()"><img src="http://www.credu.com/Error/img/Error_btn_mail.gif" width="108" height="20" border="0" hspace="5" vspace="10"></a><a href="http://www.credu.com" onfocus="this.blur()"><img src="http://www.credu.com/Error/img/Error_btn_home.gif" border="0" vspace="10"></a></td>

              </tr>

              <tr>

                <td height="7"></td>

              </tr>

            </table>

            </td>

          </tr>

          <tr>

            <td height="2" bgcolor="#d6e2ee"></td>

          </tr>

         </table></td>

      </tr>

      <!--///////////////////////////////////// $$  END of ?????? /////////////////////////////////////////-->

    </table></td>

  </tr>

  <tr>

    <td height="4" background="http://www.credu.com/Error/img/bg_bottom.gif"></td>;

  </tr>

</table>

</body>

</html>





(3) URL, URLConnection

URL(Uniform Resource Locator)

실제 자원의 위치

해당 주소의 리소스를 가져다가 쓸 수 있게 해주는 클래스이다.

이 안에는 이미 소켓과 기본설정이 포함되어 있다.


package prjNetwork;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.UnsupportedEncodingException;

import java.net.MalformedURLException;

import java.net.URL;

public class URLTest {

    public static void main(String[] args) throws UnsupportedEncodingException, IOException {

        URL myurl = new URL("http://www.naver.com";);

        

        BufferedReader br =

                new BufferedReader(

                        new InputStreamReader(myurl.openStream(),"utf-8"));

        

        String line = null;

        while ((line=br.readLine()) != null) {

            System.out.println(line);

        }

            

    }

}



※ 결과값


<html>

<head><title>302 Found</title></head>

<body bgcolor="white">

<center><h1>302 Found</h1></center>

<hr><center> NWS </center>

</body>

</html>



4. 소켓방식


1) TCP


TCP : 연결지향적

- 연결지향적 : 미리 연결을 해놓고 작업을 하는 방식이다.

- 전화장치와 비슷한다.

- 장점 : 데이터를 안전하게 주고 받을 수 있다.

- 단점 : 먼저 선을 연결해야하기 때문에 UDP와 비교해서 속도가 떨어진다.

- 1:1 통신에 많이 쓰인다.

- 중요한 정보일 때는 TCP이다.


[참고]

https://ko.wikipedia.org/wiki/%EC%A0%84%EC%86%A1_%EC%A0%9C%EC%96%B4_%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C



TCP방식의 대표적인 클래스를 살펴보자.

-Sockett

-ServerSoket




package prjNetwork;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.net.Socket;

public class TcpClient1 {

    public static void main(String[] args) {

        Socket client = null;

        

        try {

            //하나의 컴퓨터로 클라이언트생성

            client =new Socket("70.12.113.139", 6666);    //클라이언트가 6666포트로 접근 가능

            

            BufferedReader bw =    

                    new BufferedReader(

                            new InputStreamReader(client.getInputStream()));

            

            System.out.println(bw.readLine());

        }catch(Exception err) {

            err.printStackTrace();

        }finally {

            

        }

    }

}

package prjNetwork;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.OutputStreamWriter;

import java.net.ServerSocket;

import java.net.Socket;

public class TcpServer1 {

    public static void main(String[] args) {

        System.out.println("*******서버 실행 중");

        

        //서버용 소켓과 데이터용 소켓 두 개가 필요하다.

        ServerSocket server =null;

        Socket client = null;

        

        while(true) {    //서버는 꺼지면 안되기 때문에 무한 반복을 한다.

            try {

            

                //처음에 포트번호를 주고 클라이언트가 포트번호로 접속하도록 한다.

                //윈도우에서 1~1024번은 예약되어있으므로 예약된 번호는 피해서 적어야 한다.

                server = new ServerSocket(6666);

                client = server.accept();//클라이언트가 접속을 하는지 안하는지 감시하고

                                         //서버소켓에 가지고 있는 정보를 다른 소켓에 넘겨준다.

                

                System.out.println("앗~~~~누군가 접속했습니다.");

                System.out.println("접속자 : " + client.getInetAddress().getHostName());

                System.out.println("접속자 : " + client.getPort());

                

                BufferedWriter bw =

                        new BufferedWriter( new OutputStreamWriter(client.getOutputStream()));

                bw.write("클라이언트님께 영광의 박수!!!!!!!!.");//상대방 컴퓨터에 쓴다.

                bw.flush();

                

            

            } catch (IOException e) {

            

            }

            finally {

                try {

                    server.close();

                    client.close();

                }catch (IOException e) {}

            }

    

            }//While end    

    }

}



cmd 창을 이용해 클라이언트를 실행하고

이클립스에서는 서버를 실행해서

다른 컴퓨터와 연결해보면


※ 결과값



*******서버 실행 중

앗~~~~누군가 접속했습니다.

접속자 : 70-12-113-139.pools.spcsdns.net

접속자 : 51106



누군가가 접속한 것을 알 수 있다.



concurrency 시스템 : 동시에 여러명이 접속했을 때 해결 할 수 있는 시스템





package prjNetwork2;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.net.Socket;

import java.util.Scanner;

public class TcpClient2 extends Thread{

    private Scanner scan;

    private Socket client;

    

    @Override

    public void run() {

        try {

            scan = new Scanner(System.in);

        

            BufferedWriter bw =

                    new BufferedWriter(

                            new OutputStreamWriter(client.getOutputStream()));

            

            System.out.println("메시지 : ");

            String msg;

            while((msg=scan.nextLine())!=null) {

                if(msg.equals("stop")) {

                    break;

                    

                }

                bw.write(msg + "\r\n"); // \r 커서 위치를 맨 앞으로

                bw.flush();

            }

            

            

        }catch(Exception err) {

            System.out.println("전송실패 : " + err);

        }

    }

    void connection() {

        scan = new Scanner(System.in);

        

        System.out.println("접속할 서버 : ");

        String serverName = scan.next();

        

        System.out.println("접속할 포트 : ");

        int port = scan.nextInt();

        try {

            client = new Socket(serverName, port);

            start();

        }

        catch(Exception err) {

            System.out.println("소켓생성실패 : " + err);

        }

    }

    

    public static void main(String[] args) {

        new TcpClient2().connection();

    }

}




package prjNetwork2;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.net.ServerSocket;

import java.net.Socket;

class Chatter extends Thread{

    private Socket socket;    //소켓 인스턴스 변수 생성

    Chatter(Socket s){        //생성사 생성

        socket = s;            

        //소켓의 주소를 가져옴

        System.out.println(socket.getInetAddress() + " 접속함");    

        start();    //스레드 시작

    }

    

    @Override

    public void run() {    //사용자로 부터 데이터를 읽어와 출력

        while(true) {

            try {

                BufferedReader br =    

                        new BufferedReader(

                                new InputStreamReader(socket.getInputStream()));

            }catch(Exception err) {

                System.out.println(socket.getInetAddress()+"종료됨");

                try{

                    socket.close();

                } catch(IOException e) {

                    

                }

            }

        }

    }

}

public class TcpServer2 {

    private static final int SEVER_PORT = 3000;    //포트번호를 상수로 지정

    private static ServerSocket server;

    private static Socket client;

    

    public static void main(String[] args) {

        try {

            server = new ServerSocket(SEVER_PORT);

            System.out.println("*****서버실행 중");

        }catch(Exception err) {

            System.out.println("서버 소켓생성 실패 : " + err);

        }

        

        connection();

    }

    

    static void connection() {

        while(true) {

            try {

                client = server.accept();

                new Chatter(client);

            }

            catch(Exception err) {

                System.out.println("연결실패 : " + err);

                }try {

                    server.close();

                

                }catch(IOException e) {

                    try {

                        client.close();

                        return;    

                    } catch (IOException e1) {

                        // TODO Auto-generated catch block

                        e1.printStackTrace();

                    }

        

            }

        }

        

    }

}










Swing

AWT -> Swing -> JavaFX

AWT
- 초창기 나왔기 때문에 지금 보면 기능이 빈약함
- JAVA + C 이기 때문에 호환성이 부족

Swing
- JAVA만으로도 사용이 가능함
- 지금 만들어도 괜찮은 퀄리티


1) 패키지 명이 javax로 시작 : javax.swing.*


클래스 이름 앞에 J로 시작하면 swing이다. (J가 없으면 AWT이다.)



package swing;

import java.awt.FlowLayout;

import javax.swing.ImageIcon;

import javax.swing.JButton;

import javax.swing.JFrame;

import event.WindowExit;

public class SwingTest1 extends JFrame{

    private JButton btn;                        //버튼인스턴스변수 생성

    private ImageIcon icon;                        //이미지를 저장하는 창고

    private ImageIcon icon2;                    //이미지를 저장하는 창고

    

    

    

    public SwingTest1() {                         //생성자

        

        setLayout(new FlowLayout());             // 자동정렬

        

        //addWindowListener(new WindowExit(this)); // x를 끄면 꺼진다.(awt에서 클래스를 만들어 사용)

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //x를 끄면 꺼진다.(Swing에서 사용)

        

        btn = new JButton("버튼");                 //버튼 인스턴스 생성

        

        icon = new ImageIcon(getClass().getResource("/images/duke (1).gif")); //이미지를 불러온다.

        icon2 = new ImageIcon(getClass().getResource("/images/duke (2).gif")); //이미지를 불러온다.

        //경로가 /로 시작하면 절재로 경로가 바뀌지 않는 절대경로이다.

        // /는 프로젝트의 처음 시작위치이다.

        

        btn.setIcon(icon);                      //버튼을 누르면 이미지를 호출한다. JIcon의 메서드.

        btn.setPressedIcon(icon2);               //눌렀을 때 이미지가 바뀐다.

        add(btn);                              //버튼을 Frame 추가

        

    }

    

    public static void main(String[] args) {

        

        SwingTest1 test = new SwingTest1();   //클래스 인스턴스 생성

        test.setSize(300, 400);                  //사이즈를 정함

        test.setVisible(true);                  //창이 보여지게 함 창을 끄면 false 상태가 됨.

    }

}



버튼이 바뀐다.







스윙은 테두리를 내가 원하는 테투리로 갈아 끼울 수 있다.

라벨에 테두리를 갈아 끼워보자.


java.desktop  > javax.swing.boader 

테두리를 모아놓은 패키지.




package swing;

import java.awt.Color;

import java.awt.FlowLayout;

import javax.swing.ImageIcon;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.border.BevelBorder;

public class SwingTest2 extends JFrame{

    private JButton btn;

    private ImageIcon icon;

    private JLabel lab;

    

    

    public SwingTest2() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new FlowLayout());

        

        btn = new JButton("버튼");

        icon = new ImageIcon(getClass().getResource("/images/duke (3).gif"));

        lab = new JLabel("스윙 라벨입니다.", icon, JLabel.CENTER);

        

        //lab.setBorder(new EtchedBorder(Color.BLUE, Color.RED));//프레임의 틀을 바꾸자

        lab.setBorder(new BevelBorder(BevelBorder.LOWERED));//프레임의 틀을 바꾸자

        

        add(btn);

        add(lab);

                

    }

    

    public static void main(String[] args) {

        SwingTest2 test = new SwingTest2();   //클래스 인스턴스 생성

        test.setSize(300, 400);                  //사이즈를 정함

        test.setVisible(true);                  //창이 보여지게 함 창을 끄면 false 상태가 됨.

    }

}








package swing;


import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;


import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JOptionPane;

import javax.swing.JTextField;


//확인버튼이 떴을 때 글자가 그대로

public class SwingTest3 extends JFrame implements ActionListener, KeyListener{

private JTextField field;

private JButton btnOk;

private JLabel lab;

public SwingTest3(){

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

field = new JTextField(30);

btnOk = new JButton("확인");

lab = new JLabel("안녕하세요.");

add("Center", field);

add("East", btnOk);

add("South", lab);

btnOk.addActionListener(this);

field.addKeyListener(this);

}

@Override

public void actionPerformed(ActionEvent arg0) {

if(field.getText().isEmpty()) { //만약 값이 비어있다면

//값이 비어 있다면 확인하고 값을 넣어달라고 창을 띄운다.

//JOptionPane.showMessageDialog(null, "반드시 데이터를 입력하시오");

//값이 비어있다면 확인하고 값을 입력하기 위해 창을 띄움

//String name = JOptionPane.showInputDialog("이름을 입력하세요.");

//lab.setText(name);

//값이 비어있다면 선택한다. 앞의 null은 주소값인데 별 의미는 없다.

int result = JOptionPane.showConfirmDialog(null, "예/아니오 선택");

lab.setText(new String().valueOf(result)); //주소값이 나오게 한다.

}else {

lab.setText(field.getText());

}

}

@Override

public void keyPressed(KeyEvent e) { //엔터키를 치면 입력된다.

if(e.getKeyChar() == KeyEvent.VK_ENTER) {

lab.setText(field.getText());

}

}


@Override

public void keyReleased(KeyEvent e) {

// TODO Auto-generated method stub

}


@Override

public void keyTyped(KeyEvent e) {

// TODO Auto-generated method stub

}


public static void main(String[] args) {

SwingTest3 test = new SwingTest3();   //클래스 인스턴스 생성

test.setSize(300, 100);       //사이즈를 정함

test.setVisible(true);       //창이 보여지게 함 창을 끄면 false 상태가 됨.


}


}





<Swing에서 트리구조 만들기>


tree

'트리'를 보여줄 수 있게 해주는 하나의 공간을 '트리'라고 한다.

실제로 트리 안에 아이템을 만들어주는 클래스는 따로 있다.



DefaultMutableTreeNode 

이 클래스는 트리구조의 아이템을 만들수 있도록 해준다.



트리에 어떻게 값을 넣을 수 있을까?

마우스 리스너의 기능 중 일부를 쓰기 위해 마우스 리스너를 상속받는 마우스 어댑터를 사용한다.

마우스를 눌렀을 때 이벤트가 발생하는 메소드 오버라이드해보자.


여기에 값을 넣으려면 두 개의 메서드를 이용하여 활용한다.


java.desktop >  JTree


.getRowForLocation() 행의 위치를 알고 싶을 때 사용

.getPathForLocation() 경로와 위치를 알고 싶을 때 사용


final JTree tree = ...;

MouseListener ml = new MouseAdapter() {

     public void mousePressed(MouseEvent e) {

         int selRow = tree.getRowForLocation(e.getX(), e.getY());

         TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());

         if(selRow != -1) {

             if(e.getClickCount() == 1) {

                 mySingleClick(selRow, selPath);

             }

             else if(e.getClickCount() == 2) {

                 myDoubleClick(selRow, selPath);

             }

         }

     }

};




tree.addMouseListener(ml);

getRowForLocation(e.getX(), e.getY())

getRowForLocation 행의 위치를 알려줄 때 사용

(MouseEvent e)의 x좌표 y좌표는 (e.getX(), e.getY())


이렇게 행의 위치를 알려준다.



getPathForLocation 은 경로와 위치를 알고 싶을 때 사용




package swing;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JScrollPane;

import javax.swing.JTree;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.tree.TreePath;

public class SwingTest4 extends JFrame{

    

    private JLabel lab;            // 레이블 변수를 만든다.

    private JTree tree;            // 트리구조의 구조공간 변수 생성

    private JScrollPane scroll; // 비어있는 스크롤이 달려있는 판을 준비하고

                                // 트리구조를 담을 수 있도록 한다.

    

    public SwingTest4() {

        

        //트리구조의 아이템을 만들어 준다.

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root =

                new DefaultMutableTreeNode("커피");

        

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode step1 =

                new DefaultMutableTreeNode("자바 커피");

        

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode step2 =

                new DefaultMutableTreeNode("원두 커피");

        

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode step2_1 =

                new DefaultMutableTreeNode("아메리카노");

        

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode step2_2 =

                new DefaultMutableTreeNode("헤이즐넛");

        

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode step2_3 =

                new DefaultMutableTreeNode("라떼");        

        

        root.add(step1);                                //root에 step1,2 를 담는다.

        root.add(step2);

        

        step2.add(step2_1);                                // step2에 step2_1,2,3을 담는다.

        step2.add(step2_2);

        step2.add(step2_3);

        tree = new JTree(root);                            //트리의 인스턴스를 생성하고

        scroll = new JScrollPane(tree);                    //스크롤바 판에 트리를 붙여 인스턴스 생성

        lab = new JLabel("여기에 선택한 항목이 나타납니다.");    //라벨을 붙힌다.

        

        

        

        add(scroll);                                    //트리 붙은 스크롤바 판을 프레임에 더한다.

        add("South", lab);                                //아래쪽에 라벨을 프레임에 더한다.

        

        tree.addMouseListener(new TreeMouseHandler());    //핸들러를 만든다.

        

    }

    

    class TreeMouseHandler extends MouseAdapter{

        //마우스 리스너의 기능 중 일부를 쓰기 위해 마우스 리스너를 상속받는 마우스 어댑터를 사용한다.

        

        @Override    //마우스를 눌렀을 때 이벤트가 발생하는 메소드 오버라이드

        public void mousePressed(MouseEvent e) {

            

            //System.out.println(tree.getRowForLocation(e.getX(), e.getY()));    //행의 위치를 알고 싶을 때 사용

            //System.out.println(tree.getPathForLocation(e.getX(), e.getY()));     //경로와 위치를 알고 싶을 때 사용

            

            int row = tree.getRowForLocation(e.getX(), e.getY());        //행의 위치값을 row변수에 담는다.

            TreePath path = tree.getPathForLocation(e.getX(), e.getY());//path라는 리턴값에 경로와 위치를 담는다.

                                                                                        //누르면 누른 값이 마지막 값으로 나온다.

            

            if(row != -1) { //선택했을 때만 결과가 나올 수 있도록 처리한다.

                lab.setText(path.getLastPathComponent().toString());

                //lab변수안에

                //.setText()안의 문자를 넣어라.

                //path.getLastPathComponent().toString()의 문자를 넣어라

                //path.getLastPathComponent()는 행의 마지막 값을 아래에 출력

            }

            

        }

    

        

        

        

    }

    

    public static void main(String[] args) {

        SwingTest4 test = new SwingTest4();               //클래스 인스턴스 생성

        test.setSize(300, 400);                              //사이즈를 정함

        test.setVisible(true);                              //창이 보여지게 함 창을 끄면 false 상태가 됨.

    }

}











2) MVC(Model View Controller) 패턴 설계

- 쉽게 말하면 역할분담이다.

- 데이터는 별도로 따로 처리하자

- 하나의 데이터로 다양하게 활용하자.


mvc는 역할이다.

- M 데이터, 자료이다.

- C 모델과 뷰의 관계의 소통이 원활 할 수 있도록 제어, swing에서는 내장되어 있다.

- V 뷰는 보여지는 것, 디자인 


- mvc를 기반으로 다양한 모델들이 파생된다.


- 데이터와 테이블은 분리되어 있다. 테이블은 뷰의 역할이다.

- 뷰는 데이터의 주로를 가지고 있다.





package swing;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.table.TableModel;

public class SwingTest5 extends JFrame implements ActionListener{

    private JTable table;

    private JButton btnDisplay;

    private String title[] = {"이름", "나이", "성별"}; //타이틀 데이터 준비

    private String data[][] = {                        //테이블에 들어갈 데이터 준비

            {"홍길동", "20", "남자"},

            {"임꺽정", "22", "남자"},

            {"신사임당", "25", "여자"}

        };

    private JScrollPane scroll;

    

    

    public SwingTest5() {

        //x버튼 누르면 끝남

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        

        //인스턴스 생성

        table = new JTable(data, title);

        scroll = new JScrollPane(table);

        btnDisplay = new JButton("콘솔에 출력");

        

        

        //fram에 붙여줌

        add("Center", scroll);      //스크롤 바를 넣으면 없던 제목이 생긴다.

        add("South", btnDisplay); //제목을 보고 싶으면 스크롤 바를 넣어야한다.

        btnDisplay.addActionListener(this);    //액션 리스너를 만들어 준다.

        

    }

    

    @Override

    public void actionPerformed(ActionEvent e) {

    TableModel model = table.getModel();           // 뷰인 테이블이 가리키는 데이터의 주소를 가져온다.

    

    for(int i=0; i<model.getColumnCount(); i++) {            //열의 개수

        System.out.print(model.getColumnName(i) + "\t");    //제목을 출력한다.

    }

    

    System.out.println();

    System.out.println("----------------------------------");

    

    for(int i=0; i<model.getRowCount(); i++) {                  //행의 개수만큼 출력할 수 있게

        for(int j=0; j<model.getColumnCount(); j++) {         //열의 개수만큼 출력할 수 있게

            System.out.print(model.getValueAt(i, j) + "\t"); //.getValueAt(i, j) 행과 열의 데이터를 출력하겠다.

        }

        System.out.println();

    }

    

    

    }

    

    public static void main(String[] args) {

        SwingTest5 test = new SwingTest5();               //클래스 인스턴스 생성

        test.setSize(300, 400);                              //사이즈를 정함

        test.setVisible(true);                              //창이 보여지게 함 창을 끄면 false 상태가 됨.

    }

}




출력하면 이클립스에 결과가 나온다.


※ 콘솔 출력 값


이름    나이    성별    

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

홍길동    20    남자    

임꺽정    22    남자    

신사임당    25    여자    







package swing;


import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.FocusEvent;

import java.awt.event.FocusListener;


import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.JTextField;

import javax.swing.event.MouseInputListener;

import javax.swing.table.DefaultTableModel;



//https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html 참조

public class SwingTest6 extends JFrame implements ActionListener, FocusListener{

private JTable table; //인스턴스 변수 생성



private JScrollPane scroll;

private String title[] = {"이름", "나이", "성별"};

private JButton btnAdd, btnDel;

private JPanel panel;

private JTextField tfName, tfAge, tfGender;


public SwingTest6() {//////////////////////////////////////생성자

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

///////////////////////////////////////////////////////인스턴스 변수생성

btnAdd = new JButton("추가");

btnDel = new JButton("삭제");

tfName = new JTextField("이름", 6);

tfAge = new JTextField("나이", 3);

tfGender = new JTextField("성별", 2);

panel = new JPanel();

//데이터의 실체가 없기 때문에 데이터가 있는 모델객체를 따로 만들어야 데이터를 가져올 수 있다.

DefaultTableModel model = new DefaultTableModel(title, 0); 

                //데이터를 보관할 수 있는 model 객체를 만들어 준다.

table = new JTable(model); //데이터를 모델객체에 담아준다.

scroll = new JScrollPane(table);//스크롤바에 테이블을 담아준다.

add("Center", scroll); //프레임 가운데에 스크롤바와 테이블을 담아준다.

panel.add(tfName); //패널에 이름을 담아준다.

panel.add(tfAge); //패널에 이름을 담아준다.

panel.add(tfGender); //패널에 이름을 담아준다.

panel.add(btnAdd); //패널에 이름을 담아준다.

panel.add(btnDel); //패널에 이름을 담아준다.

add("South", panel); //프레임 아래에 패널을 담아준다.

btnAdd.addActionListener(this);//addActionListener 핸들러를 만들어 준다.

btnDel.addActionListener(this);

tfGender.addFocusListener(this);//addFocusListener 핸들러를 만들어준다

tfAge.addFocusListener(this);

tfName.addFocusListener(this);

}

@Override //액션 오버라이드 메서드를 만든다.

public void actionPerformed(ActionEvent e) {

if(e.getActionCommand().equals("추가")) {  //"추가"를 눌렀을 때

//연관된 데이터이므로 배열로 3개를 준비한다.

String[] data = new String[3];

data[0] = tfName.getText();

data[1] = tfAge.getText();

data[2] = tfGender.getText();

//table의 자식클래스인 DefaultTableModel에 모델의 주소를 테이블에 물어본다.

DefaultTableModel model = (DefaultTableModel)table.getModel();

//모델에 한 행에 데이터를 추가한다.

model.addRow(data);

}

else {

//System.out.println(table.getSelectedRow());//삭제 버튼을 누르면 선택 행 주소가 출력됨

int row = table.getSelectedRow();

if(row == -1) { //로우 값이 없다면 -1이라면

JOptionPane.showMessageDialog(null, "반드시 선택해야합니다.");

return; //현재위치에서 즉시 원위치로 돌아간다. 메서드 종료. 

//actionPerformed를 호출한 놈에게 돌아감 -> 시스템으로 돌아감  = 종료

}

else {

//table의 자식클래스인 DefaultTableModel에 모델의 주소를 테이블에 물어본다.

DefaultTableModel model = (DefaultTableModel)table.getModel();

//모델에 선택된 현재 행에 데이터를 삭제한다.

model.removeRow(row);

}

}

}


@Override//클릭하면 이름이 지워지고 입력이 가능하도록 포커스 리스너를 만든다.

public void focusGained(FocusEvent arg0) {

JTextField add = (JTextField)arg0.getComponent();

//add.setText("");

add.setText(add.getSelectedText());

                

                //.setText() 수정하는 메소드

          //.getSelectedText() 이 TextComponent에 격납되어있는 선택된 텍스트를 돌려줍니다. 

          //선택 범위가 null이거나 문서가 비어 있으면 null을 반환합니다.

}


@Override

public void focusLost(FocusEvent arg0) {

// TODO Auto-generated method stub

}


public static void main(String[] args) {

SwingTest6 test = new SwingTest6();    //클래스 인스턴스 생성

test.setSize(300, 400);       //사이즈를 정함

test.setVisible(true);       //창이 보여지게 함 창을 끄면 false 상태가 됨.


}


}





Swing으로 만들어진 Demo파일 받아보기



오라클 홈페이지에 가서 아래와 같이 하면 Swing Demo 파일을 받아 볼 수 있습니다.

사진을 천천히 따라해 보세요.









































































[java] Window Programming


java로 윈도우 프로그램을 만들 수 있는 기술

AWT (윈도우 3.1 쯤 나온 기술) -> Swing (최근 나온 기술) -> JavaFX (가장 최신 기술)


AWT, Swing : 둘 다 사용 방법이 비슷하다.

JavaFX : AWT, Swing와 연관성은 있지만 사용방법이 꽤 다르다. 안드로이드 환경과 비슷하다.




<윈도우 프로그래밍의 3요소>

1. 재료 (Component)

- 윈도우 프로그래밍을 만들기 위한 재료

2. 디자인 (Layout)

3. 동작 (Event)



4. Component (재료) 더 알아보기


1) AWT(Abstract Window Toolkit) 


Abstract : 추상


버튼을 눌렀을 때 실제 기능은 코딩을 해야한다.

처음 버튼 자체는 껍데기일 뿐이다.

그렇기 때문에 Abstract 라고 말한다.


java.desktop

java.awt.Component


클래스를 살펴보자.




Component의 자식 클래스들을 만나보자


Button : 버튼


Canvas : 그림판 같이 그릴 수 있음


Checkbox : 체크박스


Choice : 항목이 숨겨져 있다가 버튼 누르면 리스트가 툭 튀어나옴


Container : 다른 컨포넌트를 담기위한 그릇이다. 모든재료는 Container에 담아야 사용가능하다.


    Container의 중요한 자식 클래스

     └ panel

          └ applet : 가장 대표적인 Container. 전체 프로그램의 뼈대 담당.

     └ window

          └ dialog

          └ frame : 가장 대표적인 Container. 전체 프로그램의 뼈대 담당.


Label : 글자만 출력 할 수 있는 재료


List : 처음부터 리스트가 있음


Scrollbar : 밑에나 아래 스크롤바를 달 수 있도록 함


TextComponent : 글자를 입력 할 수 있는 도구


    TextComponent 의 중요한 자식 클래스

     └ TextField : 딱 한줄 입력할 수 있는 텍스트 박스

     └ TextArea : 여러 줄 입력할 수 있는 텍스트 박스



AWT는 간단하지만, 스윙으로 가면 재료가 많아진다.



<Container 의 핵심 클래스 2가지>


applet

- 가장 대표적인 Container. 전체 프로그램의 뼈대 담당.

- 웹브라우저에서 사용 가능한 프로그램을 만든다.

- 이제는 보안과 웹기술의 발전으로 거의 쓰지 않는다.


frame

- 일반데스크 탑에서 실행되는 응요 프로그램

- 가장 대표적인 Container. 전체 프로그램의 뼈대 담당.


package component;

import java.awt.Frame;

import java.awt.Label;

public class LabelTest {

    public static void main(String[] args) {

        

        //Label클래스의 인스턴스를 생성한다.

        Label lab1 = new Label("첫번째 라벨"); //레이블 클래스는 바로 초기화가 가능하다.

        Label lab2 = new Label("두번째 라벨");

        Label lab3 = new Label("세번째 라벨");

        //Label을 그릇에 담아야 사용이 가능하다.

        

        //Frame클래스의 인스턴스를 생성한다.

        Frame f = new Frame();

        

        //재료들을 컨테이너에 담아준다.

        f.add(lab1);

        f.add(lab2);

        f.add(lab3);

        

        

        //화면 사이즈를 픽셀단위로 설정해준다.

        f.setSize(300, 400);

        

        //화면에 보여지게끔 설정을 해준다.

        f.setVisible(true);

        

        //프래임에 특성상 같은 위치에 겹쳐서 세번째만 보인다.

        //종료는 콘솔의 빨간 버튼을 눌러 종료한다.

    }

}


※ 결과값





프래임에 특성상 같은 위치에 겹쳐서 세번째만 보인다.

종료는 콘솔의 빨간 버튼을 눌러 종료한다.

프로그램에서 말하는 디자인은 공간 배치이다.


같은 코드를 Frame클래스를 상속받아 메인을 단순하게 만들어보자.




package component;

import java.awt.Frame;

import java.awt.Label;

public class LabelTest_1 extends Frame{

    //인스턴스 변수를 미리 만들어준다.

    private Label lab1, lab2, lab3;

    

    LabelTest_1(){

        //Label클래스의 인스턴스를 생성한다.

        lab1 = new Label("첫번째 라벨"); //레이블 클래스는 클래스 특성상 바로 초기화가 가능하다.

        lab2 = new Label("두번째 라벨");

        lab3 = new Label("세번째 라벨");

        //Label을 그릇에 담아야 사용이 가능하다.

        

        //재료들을 컨테이너에 담아준다.

        add(lab1);

        add(lab2);

        add(lab3);

        

        //화면 사이즈를 픽셀단위로 설정해준다.

        setSize(300, 400);

        

        //화면에 보여지게끔 설정을 해준다.

        setVisible(true);

        

    }

    

    public static void main(String[] args) {    

        //Frame클래스를 상속받아 LabelTest의 인스턴스를 생성한다. (?)

        LabelTest_1 f = new LabelTest_1();

        

    }

}


※ 결과값






<코드리펙토링>

- 코드리뷰

- 코드 전반적인 부분을 살펴보고 합리적이고 깔끔하게 고쳐나가는 작업



아래 예제를 실행해보자.



package component;

import java.awt.Color;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.Label;

public class LabelTest_1 extends Frame{

    //인스턴스 변수를 미리 만들어준다.

    private Label lab1, lab2, lab3;

    

    LabelTest_1(){

        

        setLayout(new FlowLayout());

        

        //Label클래스의 인스턴스를 생성한다.

        lab1 = new Label("첫번째 라벨"); //레이블 클래스는 클래스 특성상 바로 초기화가 가능하다.

        lab2 = new Label("두번째 라벨");

        lab3 = new Label("세번째 라벨");

        //Label을 그릇에 담아야 사용이 가능하다.

        

        //재료들을 컨테이너에 담아준다.

        add(lab1);

        add(lab2);

        add(lab3);

        

        //각각의 라벨의 배경색깔을 바꾼다.

        lab1.setBackground(Color.BLUE);

        lab2.setBackground(Color.RED);

        lab3.setBackground(Color.YELLOW);

        

        //setSize(300, 400); //화면 사이즈를 픽셀단위로 설정해준다.

        

        //300, 400은 가로세로 모니터에서 위치, 800, 600은 가로 세로 픽셀 크기

        //화면크기와 실행 위치까지 정할 수 있다.

        setBounds(300,400,800, 600);

        

        //화면에 보여지게끔 설정을 해준다.(출력)

        setVisible(true);

        

    }

    

    public static void main(String[] args) {    

        //Frame클래스를 상속받아 LabelTest의 인스턴스를 생성한다.

        LabelTest_1 f = new LabelTest_1();

        

    }

}


※ 결과값





package component;

import java.awt.Button;

import java.awt.Color;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.Label;

public class ButtonTest extends Frame{

    //인스턴스 변수를 미리 만들어준다.

    private Button b1, b2, b3;

    

    ButtonTest(){

        

        setLayout(new FlowLayout());

        

        //Label클래스의 인스턴스를 생성한다.

        b1 = new Button("첫번째 라벨"); //레이블 클래스는 클래스 특성상 바로 초기화가 가능하다.

        b2 = new Button("두번째 라벨");

        b3 = new Button("세번째 라벨");

        //Label을 그릇에 담아야 사용이 가능하다.

        

        //재료들을 컨테이너에 담아준다.

        add(b1);

        add(b2);

        add(b3);

        

        //각각의 라벨의 배경색깔을 바꾼다.

        b1.setBackground(Color.BLUE);

        b2.setBackground(Color.RED);

        b3.setBackground(Color.YELLOW);

        

        //setSize(300, 400); //화면 사이즈를 픽셀단위로 설정해준다.

        

        //300, 400은 가로세로 모니터에서 위치, 800, 600은 가로 세로 픽셀 크기

        //화면크기와 실행 위치까지 정할 수 있다.

        setBounds(300,400,800, 600);

        

        //화면에 보여지게끔 설정을 해준다.(출력)

        setVisible(true);

        

    }

    

    public static void main(String[] args) {    

        //Frame클래스를 상속받아 LabelTest의 인스턴스를 생성한다.

        ButtonTest f = new ButtonTest();

        

    }

}


※ 결과값



체크박스 : 다중선택

라디오 버튼 : 단일선택


체크박스를 라디오 버튼으로 만드는 방법은 그룹으로 묶는 것이다.



package component;

import java.awt.Checkbox;

import java.awt.CheckboxGroup;

import java.awt.FlowLayout;

import java.awt.Frame;

public class CheckboxTest extends Frame{

    Checkbox c1, c2, c3;

    Checkbox r1, r2;

    

    CheckboxGroup g1;

    

    CheckboxTest(){

        setLayout(new FlowLayout());               // 위치를 잡는 레이아웃으로 추측

        

                                                  //체크박스를 만든다. 체크박스는 다중선택이 가능하다.

        c1 = new Checkbox("첫번째 체크박스", true);   // 체크박스에 미리 체크가 되도록 true값을 줌

        c2 = new Checkbox("두번째 체크박스");

        c3 = new Checkbox("세번째 체크박스");

        

        g1 = new CheckboxGroup();                  // 라디오 버튼을 만들기 위해 체크박스 그룹을 만든다.

        

                                                  // 라디오 버튼을 만든다. 라디오 버튼은 하나만 선택해야한다.

        r1 = new Checkbox("첫번째 라디오", true, g1); //라디오 이름, 체크박스 선택유무, 그룹이름을 써준다.            

        r2 = new Checkbox("두번째 라디오", false, g1);

        

        

        add(c1);

        add(c2);

        add(c3);

        

        add(r1);

        add(r2);

        

        setSize(300, 400);

        setVisible(true);

        

    }

    

    public static void main(String[] args) {

        

        new CheckboxTest();//클래스를 호출하는 인스턴스 생성, 자기 자신이기 때문에 클래스 이름 생략

        

    }

}







Choice 메서드를 써보자.



package component;

import java.awt.Choice;

import java.awt.Frame;

public class ChoiceTest extends Frame{

    private Choice c;

    

    ChoiceTest(){

        c = new Choice();

        c.add("홍길동");

        c.add("임꺽정");

        c.add("김유신");

        c.add("강감찬");

        

        add(c);

        setSize(300, 400);

        setVisible(true);

    }

    

    public static void main(String[] args) {

        new ChoiceTest();

        

        

        

    }

}








Choice

- 하나를 선택한다. 

- 단일 선택만 가능

list 

- 펼쳐서 보여준다. 기본적으로 1개만 선택

- 다중성택도 가능



package component;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.List;

public class ListTest extends Frame{

    private List list1, list2;

    

    ListTest(){

        setLayout(new FlowLayout());

        

        list1 = new List(5, true);    //()인자는 출력될 아이템을 지정한다. 기본리스트는 4개이다.

        list2 = new List(3);

        

        list1.add("사과");

        list1.add("배");

        list1.add("포도");

        list1.add("귤");

        list1.add("레몬");

        

        list2.add("짜장면");

        list2.add("울면");

        list2.add("라면");

        list2.add("볶음면");

        list2.add("짬짜면");

        

        add(list1);

        add(list2);

        setSize(300, 400);

        setVisible(true);

        

    }

    

    

    public static void main(String[] args) {

        

        new ListTest();

    }

}

//윈도우를 이용해서 야구게임을 만들어보자.










TextField, TextArea 를 사용해보자.





package component;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.TextArea;

import java.awt.TextField;

public class TextTest extends Frame{

    private TextField tf;

    private TextArea ta;

    

    TextTest(){

        setLayout(new FlowLayout());

        

        

        tf = new TextField(30); //한 줄입력, 크기를 늘리고 싶다면 인자의 값을 쓴다.

        ta = new TextArea(5, 30);    //여러 줄 입력, 행과 열의 크기를 입력할 수 있다.

        

        add(tf);

        add(ta);

        

        setSize(600, 400);

        setVisible(true);

    }

    

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        new TextTest();

    }

}








package component;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.TextArea;

import java.awt.TextField;

public class TextTest extends Frame{

    private TextField tf;

    private TextArea ta;

    

    TextTest(){

        setLayout(new FlowLayout());

        

        

        tf = new TextField("여기는 textfied",30); //한 줄입력, 크기를 늘리고 싶다면 인자의 값을 쓴다.

        ta = new TextArea("여기는 TextArea", 5, 30);    //여러 줄 입력, 행과 열의 크기를 입력할 수 있다.

        

        add(tf);

        add(ta);

        

        setSize(600, 400);

        setVisible(true);

    }

    

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        new TextTest();

    }

}








Container

panel

- 가장 대표적인 Container. 전체 프로그램의 뼈대 담당.

- 윈도우 안에서 부분적인 영역을 처리할 때 사용한다.

- 내가 필요한 부분 디자인을 따로 만들어 사용하고자 했을 때

  접착제처럼 붙여 사용할 수 있도록 한다.

- 컨포넌트를 담을 수 있는 컨테이너가 패널이다.




package container;

import java.awt.Button;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.Panel;

public class PanelTest extends Frame {

    private Panel p1, p2;

    private Button b1, b2, b3, b4;

    

    PanelTest(){

        

        setLayout(new FlowLayout());

        

        p1 = new Panel();

        p2 = new Panel();

        b1 = new Button("패널 2 보이기");

        b2 = new Button("패널 2 안보이기");

        b3 = new Button("패널 1 보이기");

        b4 = new Button("패널 1 안보이기");

        

        p1.add(b1);

        p1.add(b2);

        

        p2.add(b3);

        p2.add(b4);

        

        add(p1);

        add(p2);

        

        setSize(300, 400);

        setVisible(true);

    }

    public static void main(String[] args) {

        new PanelTest();

    }

}









package container;

import java.awt.Button;

import java.awt.Color;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.Panel;

public class PanelTest extends Frame {

    private Panel p1, p2;

    private Button b1, b2, b3, b4;

    

    PanelTest(){

        

        setLayout(new FlowLayout());

        

        

        //Label클래스의 인스턴스를 생성한다.

        p1 = new Panel();

        p2 = new Panel();

        b1 = new Button("패널 2 보이기");

        b2 = new Button("패널 2 안보이기");

        b3 = new Button("패널 1 보이기");

        b4 = new Button("패널 1 안보이기");

        

        //재료들을 컨테이너에 담아준다.

        p1.add(b1);

        p1.add(b2);

        

        p2.add(b3);

        p2.add(b4);

        

        add(p1);

        add(p2);

        

        //각각의 라벨의 배경색깔을 바꾼다.

        p1.setBackground(Color.BLUE);

        p2.setBackground(Color.MAGENTA);

        //화면크기와 실행 위치까지 정할 수 있다.

        setSize(300, 400);

        //화면에 보여지게끔 설정을 해준다.(출력)

        setVisible(true);

    }

    public static void main(String[] args) {

        new PanelTest();//클래스를 호출하는 인스턴스 생성, 자기 자신이기 때문에 클래스 이름 생략

    }

}










이벤트를 넣어보자.

이벤트는 마우스로 클릭하거나 하는 등의 컴퓨터 상에서 벌어지는 모든 사건을 말한다.



package container;

import java.awt.Button;

import java.awt.Color;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.Panel;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

public class PanelTest extends Frame implements ActionListener{

    private Panel p1, p2;

    private Button b1, b2, b3, b4;

    

    PanelTest(){

        

        setLayout(new FlowLayout());

        

        

        //Label클래스의 인스턴스를 생성한다.

        p1 = new Panel();

        p2 = new Panel();

        b1 = new Button("패널 2 보이기");

        b2 = new Button("패널 2 안보이기");

        b3 = new Button("패널 1 보이기");

        b4 = new Button("패널 1 안보이기");

        

        //재료들을 컨테이너에 담아준다.

        p1.add(b1);

        p1.add(b2);

        

        p2.add(b3);

        p2.add(b4);

        

        add(p1);

        add(p2);

        

        //각각의 라벨의 배경색깔을 바꾼다.

        p1.setBackground(Color.BLUE);

        p2.setBackground(Color.MAGENTA);

        //버튼이 눌리면 ActionListener 메서드가 호출되도록 한다.

        b1.addActionListener(this);

        

        //화면크기와 실행 위치까지 정할 수 있다.

        setSize(300, 400);

        //화면에 보여지게끔 설정을 해준다.(출력)

        setVisible(true);

    }

    

    //ActionListener 상속받아 메서드를 오버라이드 한다. 버튼을 누르면 메서드가 호출돤다.

    @Override

    public void actionPerformed(ActionEvent arg0) {

        

        System.out.println("버튼이 눌렸어요~~~");

        

    }

    public static void main(String[] args) {

        new PanelTest();//클래스를 호출하는 인스턴스 생성, 자기 자신이기 때문에 클래스 이름 생략

    }

}



※ 결과값




이처럼 첫번째 버튼을 누르면 "버튼을 눌렀어요가 이클립스에 찍힌다.





package container;

import java.awt.Button;

import java.awt.Color;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.Panel;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

public class PanelTest extends Frame implements ActionListener{

    private Panel p1, p2;

    private Button b1, b2, b3, b4;

    

    PanelTest(){

        

        setLayout(new FlowLayout());

        

        

        //Label클래스의 인스턴스를 생성한다.

        p1 = new Panel();

        p2 = new Panel();

        b1 = new Button("패널 2 보이기");

        b2 = new Button("패널 2 안보이기");

        b3 = new Button("패널 1 보이기");

        b4 = new Button("패널 1 안보이기");

        

        //재료들을 컨테이너에 담아준다.

        p1.add(b1);

        p1.add(b2);

        

        p2.add(b3);

        p2.add(b4);

        

        add(p1);

        add(p2);

        

        //각각의 라벨의 배경색깔을 바꾼다.

        p1.setBackground(Color.BLUE);

        p2.setBackground(Color.MAGENTA);

        //버튼이 눌리면 ActionListener 메서드가 호출되도록 한다.

        b1.addActionListener(this); // ActionEvent 메서드와 같은 클래스에 있기 때문에 this

        b2.addActionListener(this);

        b3.addActionListener(this);

        b4.addActionListener(this);

        

        

        

        //화면크기와 실행 위치까지 정할 수 있다.

        setSize(300, 400);

        //화면에 보여지게끔 설정을 해준다.(출력)

        setVisible(true);

    }

    

    //ActionListener 상속받아 메서드를 오버라이드 한다. 버튼을 누르면 메서드가 호출돤다.

    @Override

    public void actionPerformed(ActionEvent arg0) {

        /*

        System.out.println(arg0);

        System.out.println(arg0.getActionCommand()); //버튼이 가지고 있는 레이블 값만 뽑아온다.

        System.out.println("버튼이 눌렸어요~~~");

        */

        

        String cmd = arg0.getActionCommand(); //버튼이 가지고 있는 레이블 값만 뽑아온다.

        

        if(cmd.equals("패널 2 보이기")) {

            p2.setVisible(true);

        }else if(cmd.equals("패널 2 안보이기")) {

            p2.setVisible(false);

        }else if(cmd.equals("패널 1 보이기")) {

            p1.setVisible(true);

        }else {

            p1.setVisible(false);

        }

        

    }

    public static void main(String[] args) {

        new PanelTest();//클래스를 호출하는 인스턴스 생성, 자기 자신이기 때문에 클래스 이름 생략

    }

}


※ 결과값







Frame


dispose()는 윈도우를 종료하는 윈도우 클래스의 메서드이다.


package container;

import java.awt.Button;

import java.awt.Frame;

public class FrameTest extends Frame{

    private Button b;

    

    FrameTest(){

        b = new Button("버튼");

        add(b);

        

        setSize(300, 400);

        setVisible(true);

        

        try {

            Thread.sleep(3000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        

        dispose(); // 윈도우를 종료시키는 메서드이다.

    }

    

    public static void main(String[] args) {

        new FrameTest();

    }

}


※ 결과값



버튼을 켜면 3초 후에 꺼진다.



package container;

import java.awt.Button;

import java.awt.Frame;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.rmi.MarshalledObject;

import java.rmi.Remote;

import java.rmi.RemoteException;

import java.rmi.activation.ActivationDesc;

import java.rmi.activation.ActivationException;

import java.rmi.activation.ActivationID;

import java.rmi.activation.ActivationInstantiator;

public class FrameTest extends Frame implements ActionListener{

    private Button b;

    

    FrameTest(){

        b = new Button("버튼");

        add(b);

        

        b.addActionListener(this);

        

        setSize(300, 400);

        setVisible(true);

        

        try {

            Thread.sleep(3000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        

        dispose(); // 윈도우를 종료시키는 메서드이다.

    }

    

    @Override

    public void actionPerformed(ActionEvent e) {

        

        dispose(); // 윈도우를 종료시키는 메서드이다.

    }

    

    public static void main(String[] args) {

        new FrameTest();

    }

}


※ 결과값


버튼의 x버튼을 누르면 없어진다.



2) Dialog


Window : 아무것도 없다.

- Dialog : 별도의 재료들로 만들어 줄 수 있다.


패널은 한번 붙이면 위치가 고정되지만,

Dialog는 창이 움직인다.

프로그램과 사용자 사이에서 소통창구가 되게 한다.

별도의 창이 사용되는 것은 Dialog가 대부분 이다.

서브윈도우로 사용된다.

자식클래스는 filrDialog가 있다.


(1) Custom(User Define) Dialog

다이얼로그는 서브 윈도우다.

다이얼로그를 내 마음대로 만들 수 있다.

다이얼로그를 그냥 상속받으면 커스텀 다이얼로그가 된다.

다이얼로그는 누가 나를 호출했는지가 가장 중요하다.


Dialog에서 가장 많이 사용하는 생성자


Dialog(Frame owner, String title, boolean modal)

생성자를 가장 많이 이용한다.


Frame owner 

- 이 다이얼로그를 생성한 객체의 주소


String title

- 다이얼로그의 주소 

- 새 창 다이얼로그의 타이틀 

- 예) 메모장 - 다른이름으로 저장


boolean modal

- 다이얼로그의 실행방식이다.

- true false 중에 하나를 쓰면 된다.

- true 이면 madal방식이고 false는 modaless방식이다.


<modaless 과 modal>


modal 

- 현재 윈도우를 종료하기 전 까지 다른 작업을 할 수 없게 하는 것이 modal방식이다. (modal 이 대부분이다.)


modaless

- modal의 반대. 현재 실행 중인 윈도우를 종료하지 않아도 다른 작업을 병행할 수 있는 상태.

훨씬 어렵고 신경써야 할 것이 많다.


(2) Common(System) Dialog

이미 만들어져있는 다이얼로그이다.

메모장의 파일열기 같이 운영체제가 

미리 만들어 놓은 다이얼로그를 가져다가 쓰는 것이다.

FileDialog가 이에 해당한다.


package container;

import java.awt.Button;

import java.awt.Color;

import java.awt.Dialog;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.Label;

import java.awt.Panel;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

class MessageDialog extends Dialog implements ActionListener{

    private String message;

    //Dialog 자식클래스 생성자를 만들었다.

    public MessageDialog(Frame arg0, String msg) {    //생성자의 인자값을 넣어 준다.

        super(arg0, "메시지 대화상자", true); // Dialog를 만들 때에는 반드시 부모 생성자를 호출해주어야 한다.

        

        setLayout(new FlowLayout()); //자동정렬됨

        

        message = msg;     //생성자의 인자값을 불러온다.

        Label lab = new Label(message);

        add(lab);

        

        Button b = new Button("종료");

        add(b);

        

        setBackground(Color.GRAY);

        

        b.addActionListener(this);

        

        setSize(200, 300);

        setVisible(true);

    }    

    @Override

    public void actionPerformed(ActionEvent e) {

        dispose();

    }

    

}

public class CustomDialogTest extends Frame implements ActionListener{

    private Panel p;

    private Button b1, b2;

    

    public CustomDialogTest() {

        p = new Panel();

        b1 = new Button("다이얼로그 열기");

        b2 = new Button("종료");

        

        p.add(b1);

        p.add(b2);

        

        add(p);

        

        b1.addActionListener(this);

        

        setSize(300, 400);

        setVisible(true);

    }

    

    @Override

    public void actionPerformed(ActionEvent e) {

        new MessageDialog(this, "이것은 메인에서 전달하는 메시지");    //현재 실행된 자기 자신의 주소를 넣어준다.

    }

    

    public static void main(String[] args) {

        new CustomDialogTest();

    }

}






본래 생성자의 목적에 맞게 디팩토링 하고 기능을 추가해보자.







package container;

import java.awt.Button;

import java.awt.Color;

import java.awt.Dialog;

import java.awt.FlowLayout;

import java.awt.Frame;

import java.awt.Label;

import java.awt.Panel;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

class MessageDialog extends Dialog implements ActionListener{

    private String messge;//생성자의 인자값을 불러온다.

    private Label lab;

    private Button b;

    

    //Dialog 자식클래스 생성자를 만들었다.

    public MessageDialog(Frame arg0, String msg) {    //생성자의 인자값을 넣어 준다.

        super(arg0, "메시지 대화상자", true); // Dialog를 만들 때에는 반드시 부모 생성자를 호출해주어야 한다.

        lab = new Label(msg);

        b = new Button("종료");

    

    }    

    

    void display() {

        setLayout(new FlowLayout()); //자동정렬됨

        

        add(lab);

        add(b);

        

        setBackground(Color.GRAY);

        

        b.addActionListener(this);

        

        setSize(200, 300);

        setVisible(true);

    }

    

    @Override

    public void actionPerformed(ActionEvent e) {

        dispose();

    }

    

}

public class CustomDialogTest extends Frame implements ActionListener{

    private Panel p;

    private Button b1, b2;

    

    public CustomDialogTest() {

        p = new Panel();

        b1 = new Button("다이얼로그 열기");

        b2 = new Button("종료");

        

        p.add(b1);    //패널에 버튼 추가

        p.add(b2);

        

        add(p);    //패널호출

        b1.addActionListener(this);

        

        setSize(300, 400);

        setVisible(true);

    }

    

    @Override

    public void actionPerformed(ActionEvent e) {

        MessageDialog md = new MessageDialog(this, "이것은 메인에서 전달하는 메시지");    //현재 실행된 자기 자신의 주소를 넣어준다.

        md.display();

    }

    

    public static void main(String[] args) {

         new CustomDialogTest();

    }

}






package container;

import java.awt.Button;

import java.awt.FileDialog;

import java.awt.Frame;

import java.awt.Panel;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

public class CommonDialogTest extends Frame implements ActionListener{

    FileDialog fopen, fsave;

    Panel p;

    Button btnOpen, btnSave;

    

    

    public CommonDialogTest() {

        p = new Panel();    //패널의 인스턴스 생성

        btnOpen = new Button("파일 열기");

        btnSave = new Button("파일 저장");

        

        //첫번째는 주소값, 두번째는 title, 세번째는 파일열기 or 저장하기로 할건지 지정 옵션

        fopen = new FileDialog(this, "파일 열기", FileDialog.LOAD);

        //첫번째는 주소값, 두번째는 title, 세번째는 파일열기 or 저장하기로 할건지 지정 옵션

        fsave = new FileDialog(this, "파일 저장", FileDialog.SAVE);        

        

        p.add(btnOpen);

        p.add(btnSave);

        

        add(p);

        

        btnOpen.addActionListener(this);

        btnSave.addActionListener(this);

        

    }

    

    @Override     //버튼을 눌렀을 때 행동하도록 상속받아 연결

    public void actionPerformed(ActionEvent arg0) {    

        if(arg0.getActionCommand().equals("파일 열기")) {

            fopen.setVisible(true);                         //fopen을 불러와 보여준다.

            System.out.println(fopen.getDirectory());    //현재 선택한 파일의 경로를 보여준다.

            System.out.println(fopen.getFile());        //현재 선택한 파일의 주소를 보여준다.

            

        }else {

            fsave.setVisible(true);                     //fsave을 불러와 보여준다.

        }

        

    }

    

    public static void main(String[] args) {

        CommonDialogTest test = new CommonDialogTest();

        test.setSize(300, 400);

        test.setVisible(true);

    }

}











5. Layout


1) Layout 매니저


메인윈도우가 커지든 안커지든 상관없이 중간에 매니저가 레이아웃 배치를 대신해준다.

이렇세 배치를 처리해주는 클래스를 layout 매니저라고 한다.


- FlowLayout : 기본매니저 

- BorerLayout : 기본매니저 

- GridLayout

- GridBagLayout

- CardLayout


<FlowLayout>

크기가 크거나 작아져도 변화된다. (기본매니저)


package layout;

import java.awt.Button;

import java.awt.FlowLayout;

import java.awt.Frame;

public class FlowLayoutTest extends Frame{

    

    Button b1, b2, b3, b4, b5;         //버튼을 인스턴스 변수를 선언한다.

    

    public FlowLayoutTest() {         //생성자

        

        setLayout(new FlowLayout()); //FlowLayout() 크기가 크거나 작아져도 변화된다.

                                     //setLayout() 어떤식으로 배치할지 매니저를 선택해준다.

        

        b1 = new Button("첫번째 버튼");     //버튼 인스턴스를 생성한다.

        b2 = new Button("두번째 버튼");

        b3 = new Button("세번째 버튼");

        b4 = new Button("네번째 버튼");

        b5 = new Button("다섯번째 버튼");

        

        add(b1);    //프레임에 b1버튼을 추가해서 화면에 보이게 한다.

        add(b2);

        add(b3);

        add(b4);

        add(b5);

    }

    

    public static void main(String[] args) {

        FlowLayoutTest test = new FlowLayoutTest(); //클래스 인스턴스 생성

        test.setSize(300, 400);    //사이즈를 정함

        test.setVisible(true);    //창이 보여지게 함

    }

}


※ 결과값








<BorerLayout>


왼쪽, 오른쪽, 위쪽, 아래쪽, 가운데 다섯 곳에 테두리를 기준으로 배치하는 방법 (기본매니저)

위치를 지정하지 않으면 계속 같은 곳에 나온다.

왼쪽일 때에는 west

오른쪽 일 때는 East

아래는 South

위에는 North

가운데는 center 

인자값을 쓸 때 첫글자는 반드시 대문자여야한다.



package layout;

import java.awt.BorderLayout;

import java.awt.Button;

import java.awt.Frame;

public class BorderLayoutTest extends Frame{

    

    Button b1, b2, b3, b4, b5;         //버튼을 인스턴스 변수를 선언한다.

    

    public BorderLayoutTest() {         //생성자

        

        setLayout(new BorderLayout()); //BorerLayout () 테두리를 기준으로 배치

                                       //setLayout() 어떤식으로 배치할지 매니저를 선택해준다.

        

        b1 = new Button("첫번째 버튼");       //버튼 인스턴스를 생성한다.

        b2 = new Button("두번째 버튼");

        b3 = new Button("세번째 버튼");

        b4 = new Button("네번째 버튼");

        b5 = new Button("다섯번째 버튼");

        

        add("North",b1);                //프레임에 b1버튼을 추가해서 화면에 보이게 한다.

        add("South",b2);                //인자에 어디에 배치할지 값을 넣어준다.

        add("East",b3);

        add("West",b4);

        add("Center",b5);

    }

    

    public static void main(String[] args) {

        BorderLayoutTest test = new BorderLayoutTest(); //클래스 인스턴스 생성

        test.setSize(300, 400);    //사이즈를 정함

        test.setVisible(true);    //창이 보여지게 함

    }

}


※ 결과값




<Container의 기본 매니저>

Container 는 기본으로 매니저를 가지고 있다.

Panel의 경우는 기본레이아웃이 FlowLayout이며,

Applet과 같은자식클래스도 마찬가지 이다.

Window의 경우 기본 레이아웃이 BorerLayout 이며,

Dialog FileDialog, Frame 과 같은 자식 클래스도 마찬가지 이다.


<GridLayout>

규격이 있는 테이블(표)을 만들어준다.

행과열을 지정하여 격자를 지정할 수 있는 레이아웃

Flowlayout과는 달리 정해진 행과 열의 갯수가 바뀌지 않는다.



package layout;

import java.awt.Button;

import java.awt.Frame;

import java.awt.GridLayout;

public class GridLayoutTest extends Frame{

    

    Button b1, b2, b3, b4, b5;         //버튼을 인스턴스 변수를 선언한다.

    

    public GridLayoutTest() {         //생성자

        

        setLayout(new GridLayout(2,3)); //GridLayout() 행과열을 지정하여 격자를 지정할 수 있는 레이아웃

                                        //2행 3열 짜리 칸을 만들고 배치하겠다.

                                        //setLayout() 어떤식으로 배치할지 매니저를 선택해준다.

        

        b1 = new Button("첫번째 버튼");     //버튼 인스턴스를 생성한다.

        b2 = new Button("두번째 버튼");

        b3 = new Button("세번째 버튼");

        b4 = new Button("네번째 버튼");

        b5 = new Button("다섯번째 버튼");

        

        add(b1);    //프레임에 b1버튼을 추가해서 화면에 보이게 한다.

        add(b2);

        add(b3);

        add(b4);

        add(b5);

    }

    

    public static void main(String[] args) {

        GridLayoutTest test = new GridLayoutTest(); //클래스 인스턴스 생성

        test.setSize(300, 400);    //사이즈를 정함

        test.setVisible(true);    //창이 보여지게 함

    }

}


※ 결과값






<GridBagLayout>

불규칙한 테이블(표)을 만들 수 있다.

자세한 사용법은 API의

java.desktop > java.awt > GridLayout 클래스 항목을 참고하면 된다. 

https://docs.oracle.com/javase/9/docs/api/index.html?overview-summary.html



<CardLayout>

같은 화면으로 여러개의 페이지를 보여주고자 했을 때 

각각 버튼 누를 때마다 몇 깨의 화면을 따로따로 보여줬을 때 

이벤트가 같이 나와야 한다.


package layout;

import java.awt.Button;

import java.awt.CardLayout;

import java.awt.Frame;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

//이벤트를 처리하기 위해서는 반드시 ActionListener 상속이 필요하다.

public class CardLayoutTest extends Frame implements ActionListener{

    

    Button b1, b2, b3, b4, b5;         //버튼을 인스턴스 변수를 선언한다.

    CardLayout card;                  //인스턴스 변수를 생성한다.

    

    public CardLayoutTest() {         //생성자

        card = new CardLayout();     //CardLayout()인스턴스 변수를 생성한다.

        setLayout(card);             //CardLayout() 같은 화면으로 여러개의 페이지를 보여주고자 했을 때

                                     // CardLayout()은 반드시 이벤트가 필요하다.

                                     //setLayout() 어떤식으로 배치할지 매니저를 선택해준다.

        

        

        

        b1 = new Button("첫번째 버튼");     //버튼 인스턴스를 생성한다.

        b2 = new Button("두번째 버튼");

        b3 = new Button("세번째 버튼");

        b4 = new Button("네번째 버튼");

        b5 = new Button("다섯번째 버튼");

        

        add(b1);    //프레임에 b1버튼을 추가해서 화면에 보이게 한다.

        add(b2);

        add(b3);

        add(b4);

        add(b5);

        

        b1.addActionListener(this);    //이벤트를 위해 액션리스너에 b1을 추가한다.

        b2.addActionListener(this);

        b3.addActionListener(this);

        b4.addActionListener(this);

        b5.addActionListener(this);

        

    }

    

    @Override    //상속을 하였음으로 액션리스너 메서드를 오버라이드한다.

    public void actionPerformed(ActionEvent e) {

        card.next(this);

    }    

    

    public static void main(String[] args) {

        CardLayoutTest test = new CardLayoutTest(); //클래스 인스턴스 생성

        test.setSize(300, 400);    //사이즈를 정함

        test.setVisible(true);    //창이 보여지게 함

    }

}



※ 결과값






<주로 쓰이는 레이아웃>

Layout중에서는

FlowLayout, BroderLayout, gridLayout

가 주로 쓰이며 나머지는 AWT이후에 나온 Swing에 

이미 더 좋은 기능이 나와있기 떄문에 참고만 하면 된다.



지금까지 재료(Component)와 디자인(Layout)을 알아보았다.

이제 동작(Event)을 알아보자



6. 동작(Event)

- 어떤 사건이 일어나는 것을 말한다.

- 이벤트에는 세 가지 요소가 있다.


1) 이벤트 소스 (컴퍼넌트)

    - 원본, 진원지

    - 어디에서 사건이 발생했는가? 위치를 파악한다.

    - 위치는 결국 재료(Component)를 말한다.

    - 어느 Component에서 사건이 일어났는지를 가장 먼저 파악해야한다.


2) 이벤트 클래스 (어떤사건?)

    (1) 어떤 사건인지를 사건의 종류를 파악한다.

    예) 클릭을 했는지, 더블클릭을 했는지, 드레그를 헀는지 알아본다.


    (2) java.util.EventObject ( java.base >  java.util > EventObject) 에

    java의 모든 Event 클래스, 사건관련 클래스가 들어있다.

    자식클래스를 보면 AWTEvent가 있음을 볼 수 있다.


    (3) AWTEvent에서 중요한 자식클래스는 아래 다섯 가지이다.


    ①ActionEvent 


      - 컴퍼넌트가 활성화 될 때 발생하는 이벤트 

      - 컴퍼넌트를 무언가 선택하면 선택된 표시가 발생하는 이벤트

      - 선택만 하면 발생하기 때문에 거의 모든 이벤트에 발생한다.


     ②AdjustmentEvent


      - 소리음량 조절 스크롤 바와 같이 조정가능한 컴퍼넌트에서 

        조정이 일어날 때 발생한다.

      - 스크롤바를 선택하면 윈도우도 선택되기 때문에 AdjustmentEvent와

        ActionEvent도 함께 발생된다.

      - 하지만 프로그래밍에서는 함께 발생된다고 하더라고 한개만 처리해야한다.

      - ActionEvent는 선택 뿐만 아니라 어떤 위치 값을 가지고 있는지도 나온다.

      - 똑같이 발생해도 어떤 선택을 할 것인가에 따라서 표면적으로 사용하는 클래스가 달라진다. 


    ③ComponentEvent

      - 자식에게 물려주기 위한 용도이다. 아래의 자식클래스들이 실제로 사용된다.

     └ ContainerEvent

         - 컨테이너의 컴퍼넌트가 추가/삭제되는 경우 발생하는 이벤트

         - 실행중에 원래 없던 디자인이 추가되거나 이미 있던 디자인이 삭제되면 쓴다.

         - 동적 디자인의 경우 사용되지만 거의 쓸 일은 없다. 

     └ FocusEvent

         - 컴퍼넌트에 포커스가 들어왔을 때 발생하는 이벤트

         - 키보드나 마우스를 특정 텍스트 박스를 눌렀을 때 깜박거리면 발생하는 이벤트

         - 무언가 관심을 받았을 때 발생하는 이벤트이다.

         - 액션이벤트와 겹친다.

     └ Inputevent

        - 입력할 때마다 발생하는 이벤트.

        - 인풋 이벤트 자체는 사용되지 않으면 자식클래스가 사용된다.

        └ KeyEvent : 키를 입력할 때 발생한다.

        └ MouseEvent : 마우스를 클릭하거나 움직일 때 발생한다.

     └ PaintEvent 

        - 그래픽이나 멀티미디어 쪽에서 쓰이게 된다.

        - 컴퍼넌트가 다시 그려질 때 발생하는 이벤트

        - 화면에서 새 창을 열었다가 닫았을 때 창이 지워졌다가 다시 그려지는 것이다.

        - 무언가 가렸다가 치웠을 때 다시 그리면서 발생한다.

        - MouseEvent와 겹친다.

     └ WindowEvent

        - 윈도우가 활성화 또는 닫힐 때 발생하는 이벤트

        - 액션이벤트와 겹친다.

         

    ④ItemEven

      - 리스트, 초이스와 같이 선택항목이 존재하는 

      컴퍼넌트에서 선택항목이 선택 될 때 발생하는 이벤트

      - 리스트에서 선택항목에 무언가를 선택할 때 

        액션, 포커스, 마우스, 윈도우 많은 이벤트가 겹친다. 

        이렇게 여러 이벤트가 겹칠 때에도 내가 원하는 행동에서 

        가장 가까운 것이 아이템 이벤트라면 아이템 이벤트를 선택하면 된다.


    ⑤TextEvent

        - 텍스트 컴퍼넌트(글자를 입력할 수 있는 컴퍼넌트)의 내용이 변화될 때 발생하는 이벤트

        - 글자는 쓰거나 수정 할 때 사용한다.

        - 키 이벤트와 겹치지만 용도가 다르기 때문에 예제를 반복하면 쓰임을 알 수 있다.



3) 이벤트 핸들러 (처리, 인터페이스로 만들어져 있음)

이벤트핸들러는 이벤트를 어떻게 처리할지 조정한다.

- 사건에 따라 대응 메뉴얼이 있다.

- 대응 메뉴얼에 따라 사건처리를 한다.

- 클래스가 아닌 인터페이스로 만들어져 있다.

- 이벤트만 처리하는 인터페이스를 '리스너(listener) 인터페이스'라고 한다.

- 이벤트는 스윙을 해도 달라지지 않는다.


java.desktop > java.awt.event

   - api를 보면 리스너 인터페이스 이름이 클래스 이름과 비슷하다는 것을 알 수 있다.

   - 리스너 인터페이스는 이벤트클래스를 처리하기 위해서 나온 인터페이스이다.

   - 어떤 이벤트 클래스를 쓸지 알아야 리스너 인터페이스를 쓸 수 있다.

   - 거의 특별한 정보가 아니라면 액션 이벤트를 쓴다.


4) 이벤트소스와 핸들러의 연결

    - 이벤트소스.add 이벤트클래스Listener(핸들러의 주소);


5) 이벤트 코드 처리 방식

    ① 이벤트 소스와 이벤트 핸들러가 같은 클래스인 경우 : 지금까지 했던 모든 예제

    ② 이벤트 소스와 이벤트 핸들러가 다른 클래스인 경우

    ③ 이벤트 핸들러가 내부 클래스인 경우

    ④ 이벤트 핸들러가 무명 클래스인 경우


    - 일반적인 경우 취향의 따라서 하면 된다



① 이벤트 소스와 이벤트 핸들러가 같은 클래스인 경우 : 지금까지 했던 모든 예제


package event;

import java.awt.Button;

import java.awt.Color;

import java.awt.Frame;

import java.awt.TextArea;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

//버튼을 클릭하면 활성화 될 수 있도록 액션리스너를 상속받는다.

public class EventTest1 extends Frame implements ActionListener{

    private Button btn1, btn2;           //인스턴스변수를 생성한다.

    private TextArea ta;

    

    EventTest1(){                        //생성자를 생성한다

        btn1 = new Button("눌러주세요.");  //인스턴스를 생성한다.

        btn2 = new Button("종료");

        ta = new TextArea();

        

        add("North", btn1);    //화면에 보이도록 Frame에 위치를 지정해 더해준다.

        add("Center", ta);

        add("South", btn2);

        

        btn1.addActionListener(this); // 버튼을 핸들러에 연결한다.

        btn2.addActionListener(this); // 버튼을 핸들러에 연결한다.

    }

    

    @Override    //이벤트핸들러이다. 이벤트를 어떻게 처리할지 조정한다.

    public void actionPerformed(ActionEvent arg0) {

        //String cmd = arg0.getActionCommand(); //현재 이벤트소스의 레이블값을 가져온다.

// -----아래 두줄과 위에 주석처리 된 한 줄과 같다.------

// 이벤트소스가 가진 모든 기능을 쓸 수 있도록 넘겨준다. 

// 부모클래스와 자식클래스의 참조관계를 살펴보자. 

// 자식클래스에 다시 넘겨서 자식이 가진 기능을 다 쓸 수 있게 한다.

//.getSource()는 자식 클래스의 모든 메소드를 쓸 수 있게 해준다.

Button btn = (Button)arg0.getSource();

// 현재 이벤트 소스의 레이블값을 가져온다.

// 부모클래스 + 버튼의 모든 기능을 쓸 수 있다.(상속에서 부모자식간의 참조관계 참고)

// 부모클래스의 더 많은 기능을 쓰고 싶을 때 사용한다.

String cmd = btn.getLabel();          

                                                  

        if(cmd.equals("눌러주세요.")) {                     //cmd의 텍스트가 같다면

            btn.setBackground(Color.GREEN);                 //컬러를 바꾸고

            ta.setText(ta.getText() + "버튼이 눌렸어요.\n"); //버튼이 눌렀어요가 입력된다.

        } else {

            dispose();                                     //아니면 사라진다.

        }

        

        

    }

    

    public static void main(String[] args) {

        //TODO 이벤트 소스와 핸들러가 같은 클래스인 경우

        

        EventTest1 test = new EventTest1(); // 인스턴스를 생성한다.

        test.setSize(300, 400);

        test.setVisible(true);

    }

}



※ 결과값







② 이벤트 소스와 이벤트 핸들러가 다른 클래스인 경우

- 이벤트를 클래스가 공동으로 쓸 경우에 사용한다.


package event;

import java.awt.Button;

import java.awt.Color;

import java.awt.Frame;

import java.awt.TextArea;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

class EventHandler implements ActionListener{

    private TextArea ta;         //EventTest2의 변수를 쓰려면 Getter and Setter를 쓰든지, 생성자를 호출할 불러오면 된다.

    private Button btn1, btn2;     //버튼 변수를 선언한다.

    private Frame f;             //EventTest2의 주소값을 넘겨받을 변수를 선언한다.

    

    

    EventHandler(TextArea ta, Button btn1, Button btn2, Frame f){ //생성자를 써서 변수를 호출한다.

        this.ta = ta;        // 핸들러주소값의 변수 ta에 EventTest2변수 ta를 넣겠다.

        this.btn1 = btn1;   // 핸들러주소값의 변수 btn1에 EventTest2변수 btn1를 넣겠다.

        this.btn2 = btn2;    // 핸들러주소값의 변수 btn2에 EventTest2변수 btn2를 넣겠다.

        this.f = f;            // 핸들러주소값을 EventTest2 변수f를 넣겠다.

    }

    

    @Override

    public void actionPerformed(ActionEvent arg0) {

        // TODO Auto-generated method stub

        

        String cmd = arg0.getActionCommand(); //현재 이벤트소스의 레이블값을 가져온다.

                        

        

        if(cmd.equals("눌러주세요.")) {                     //cmd의 텍스트가 같다면

            btn1.setBackground(Color.GREEN);             //컬러를 바꾸고

            ta.setText(ta.getText() + "버튼이 눌렸어요.\n"); //버튼이 눌렀어요가 입력된다.    

            

        }else {

            f.dispose();

        }

        

    }

    

}

//버튼을 클릭하면 활성화 될 수 있도록 액션리스너를 상속받는다.

public class EventTest2 extends Frame {

    private Button btn1, btn2;           //인스턴스변수를 생성한다.

    private TextArea ta;

    EventTest2(){                        //생성자를 생성한다

        btn1 = new Button("눌러주세요.");  //인스턴스를 생성한다.

        btn2 = new Button("종료");

        ta = new TextArea();

        

        add("North", btn1);    //화면에 보이도록 Frame에 위치를 지정해 더해준다.

        add("Center", ta);

        add("South", btn2);

        

        // 핸들러 클래스의 인스턴스를 생성한다.

        // 다른 클래스에 있는 경우 핸들러에 인스턴스 변수와 주소값을 인자값에 넘겨준다.

        EventHandler handler = new EventHandler(ta, btn1, btn2, this);

        

        btn1.addActionListener(handler); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.

        btn2.addActionListener(handler); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.

    }

    

    

    

    public static void main(String[] args) {

        //TODO 이벤트 소스와 핸들러가 다른 클래스인 경우

        

        EventTest2 test = new EventTest2(); // 인스턴스를 생성한다.

        test.setSize(300, 400);

        test.setVisible(true);

    }

}



※ 결과값








③ 이벤트 핸들러가 내부 클래스인 경우

- 이벤트를 클래스가 공동으로 쓰지 않고 자기만 쓰는 것이라면 내부클래스가 편하다.



package event;

import java.awt.Button;

import java.awt.Color;

import java.awt.Frame;

import java.awt.TextArea;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

//버튼을 클릭하면 활성화 될 수 있도록 액션리스너를 상속받는다.

public class EventTest2_1 extends Frame {

    private Button btn1, btn2;           //인스턴스변수를 생성한다.

    private TextArea ta;

    EventTest2_1(){                        //생성자를 생성한다

        btn1 = new Button("눌러주세요.");  //인스턴스를 생성한다.

        btn2 = new Button("종료");

        ta = new TextArea();

        

        add("North", btn1);    //화면에 보이도록 Frame에 위치를 지정해 더해준다.

        add("Center", ta);

        add("South", btn2);

        

        // 핸들러 클래스의 인스턴스를 생성한다.

        // 다른 클래스에 있는 경우 핸들러에 인스턴스 변수와 주소값을 인자값에 넘겨준다.

        EventHandler handler = new EventHandler();

        

        btn1.addActionListener(handler); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.

        btn2.addActionListener(handler); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.

    }

    

    class EventHandler implements ActionListener{    //내부클래스의 기능을 모두 쓴다.

                

        @Override

        public void actionPerformed(ActionEvent arg0) {

            // TODO Auto-generated method stub

            

            String cmd = arg0.getActionCommand(); //현재 이벤트소스의 레이블값을 가져온다.

                            

            

            if(cmd.equals("눌러주세요.")) {                     //cmd의 텍스트가 같다면

                btn1.setBackground(Color.GREEN);             //컬러를 바꾸고

                ta.setText(ta.getText() + "버튼이 눌렸어요.\n"); //버튼이 눌렀어요가 입력된다.    

                

            }else {

                dispose();

            }

            

        }

        

    }

    

    public static void main(String[] args) {

        //TODO 이벤트 소스와 핸들러가 다른 클래스인 경우

        

        EventTest2_1 test = new EventTest2_1(); // 인스턴스를 생성한다.

        test.setSize(300, 400);

        test.setVisible(true);

    }

}




※ 결과값






④ 이벤트 핸들러가 무명 클래스인 경우

- 액션리스너는 이벤트 핸들러를 상속받아 만들어주는 구현체이다. 

  액션 리스너가 있는 클래스는 한 번 만 쓰는 핸들러이기 때문에 축약해서 사용 할하는 문법을 만들었다.


<무명클래스>

- 인터페이스를 상속받는 별도의 구현체인 클레스를 만들지 않고 축약해서 만드는 방식

- 인터페이스로부터 클래스를 상속받아 클래스로 만들어야하는 과정을 생략한다.

- 하지만 클래스 이름은 없기 때문에 무명클래스라고 한다.

- 딱 한번만 만든다. 재활용 목적이 아니다.

- 무명클래스는 생성자를 만들 수 없다.

- 생성자를 쓸 수 없기 때문에 인자를 받지 못한다.


package event;

import java.awt.Button;

import java.awt.Color;

import java.awt.Frame;

import java.awt.TextArea;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

//버튼을 클릭하면 활성화 될 수 있도록 액션리스너를 상속받는다.

public class EventTest2_2 extends Frame {

    private Button btn1, btn2;           //인스턴스변수를 생성한다.

    private TextArea ta;

    EventTest2_2(){                        //생성자를 생성한다

        btn1 = new Button("눌러주세요.");  //인스턴스를 생성한다.

        btn2 = new Button("종료");

        ta = new TextArea();

        

        add("North", btn1);    //화면에 보이도록 Frame에 위치를 지정해 더해준다.

        add("Center", ta);

        add("South", btn2);

        

        

        //클래스를 메서드안에서 직접 만들어 버린다.

        //인터페이스로부터 클래스를 상속받아 클래스로 만들어야하는 과정을 생략

        //클래스 이름은 없기 때문에 무명클래스라고 한다.

        //자바5 부터 추가된 문법이다.

        ActionListener listen = new ActionListener() {            //딱 한 번만 만든다.

            @Override

            public void actionPerformed(ActionEvent arg0) {

                String cmd = arg0.getActionCommand();             //현재 이벤트소스의 레이블값을 가져온다.

                

                

                if(cmd.equals("눌러주세요.")) {                     //cmd의 텍스트가 같다면

                    btn1.setBackground(Color.GREEN);             //컬러를 바꾸고

                    ta.setText(ta.getText() + "버튼이 눌렸어요.\n"); //버튼이 눌렀어요가 입력된다.    

                    

                }else {

                    dispose();

                }

                

            }

            

        };

        

        btn1.addActionListener(listen); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.

        btn2.addActionListener(listen); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.

    }

    

    

    

    public static void main(String[] args) {

        //TODO 이벤트 소스와 핸들러가 다른 클래스인 경우

        

        EventTest2_2 test = new EventTest2_2(); // 인스턴스를 생성한다.

        test.setSize(300, 400);

        test.setVisible(true);

    }

}




※ 결과값






  


6. Adapter Class 어댑터클래스


Adapter Class는 왜 필요할까?


Interface MouseListener 안에 클래스를 살펴보자


mouseCliked 버튼을 클릭했을 때 발생하는 이벤트

mouseEntered   마우스가 버튼으로 들어갔을 때 발생하는 이벤트

mouseExited 마우스를 버튼 밖으로 나왔을 때 사용하는 이벤트 

mousePressed 마우스를 눌렀을 때 발생하는 이벤트

mouseReleased 마우스를 눌렀다가 띄었을 때 발생하는 이벤트

mousePressed + mouseReleased = mouseCliked


앞에서는 액션리스너를 주로 상속 받았다.

액션리스너는 추상메서드가 하나밖에 없었기 때문에 오버라이딩도 하나만 했다.

그러나 마우스 리스너의 경우만 보아도 오버라이딩를 추상메서드 5개를 해야한다.

그렇게되면 코드가 너무 지저분해진다.


인터페이스를 미리 오버라이딩 해놓은 클래스를 어댑터 클래스라고 한다.

인터페이스를 중간에 미리 오버라이딩 해놓은 어댑터 클래스를 

내가 필요한 메서드만 상속받기 위해서 상속한다.


MouseEvent

MouseAdapter


처럼,


각각의 리스너는 어댑터 클래스가 따로 있다.

메서드가 2개 이상 되는 리스너들만이 메서드가 있다.

액션리스너처럼 메서드가 1개 밖에 없는 리스너는 어댑터가 없다.

있을 필요가 없기 때문이다.




<어댑터 클래스를 이용하기 전>


package event;

import java.awt.Button;

import java.awt.Frame;

import java.awt.TextField;

import java.awt.event.WindowEvent;

import java.awt.event.WindowListener;

public class AdapterTest extends Frame implements WindowListener{

    private TextField tf;    //인스턴스 변수를 생성

    private Button btnExit;

    

    @Override

    public void windowActivated(WindowEvent e) {

        // TODO Auto-generated method stub

        

    }

    @Override

    public void windowClosed(WindowEvent e) {

        // TODO Auto-generated method stub

        

    }

    @Override

    public void windowClosing(WindowEvent e) {

        // TODO Auto-generated method stub

        dispose();

    }

    @Override

    public void windowDeactivated(WindowEvent e) {

        // TODO Auto-generated method stub

        

    }

    @Override

    public void windowDeiconified(WindowEvent e) {

        // TODO Auto-generated method stub

        

    }

    @Override

    public void windowIconified(WindowEvent e) {

        // TODO Auto-generated method stub

        

    }

    @Override

    public void windowOpened(WindowEvent e) {

        // TODO Auto-generated method stub

        

    }

    public AdapterTest() {

        tf = new TextField("x버튼을 누르면 종료합니다.");    //인스턴스 생성

        btnExit = new Button("종료");

        

        add("North", tf);

        add("Center", btnExit);

        

        //윈도우리스너를 상속받아야 X버튼에 접근 할 수 있다.

        //Frame 자체가 window의 포함되기 때문에 따로 이벤트 소스를 적지 않는다. (window만 해당된다.)

        //같은 클래스에서 호출하기 때문에 this를 쓴다.

        addWindowListener(this);

        

    }

    

    

    public static void main(String[] args) {

        AdapterTest test = new AdapterTest();

        test.setSize(300, 400);

        test.setVisible(true);

    }

}


※ 결과값




<어댑터 클래스를 이용할 때>

- 이벤트 소스와 이벤트 핸들러가 다른 클래스인 경우를 참고한다.


package event;

import java.awt.Button;

import java.awt.Frame;

import java.awt.TextField;

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import java.awt.event.WindowListener;

//쓸데없는 오버라이딩을 줄이기 위해 사용하는 어댑터 클래스

class WindowExit extends WindowAdapter{

    private Frame f;

    

    WindowExit(Frame f){

        this.f = f;

    }

    

    @Override    //윈도우 아뎁터를 상속받아 필요한 기능만 오버라이딩 한다.

    public void windowClosing(WindowEvent arg0) {

        f.dispose();

    }    

    

}

public class AdapterTest extends Frame {

    private TextField tf;    //인스턴스 변수를 생성

    private Button btnExit;

    

    

    public AdapterTest() {

        tf = new TextField("x버튼을 누르면 종료합니다.");    //인스턴스 생성

        btnExit = new Button("종료");

        

        add("North", tf);

        add("Center", btnExit);

        

        //윈도우리스너를 상속받아야 X버튼에 접근 할 수 있다.

        //Frame 자체가 window의 포함되기 때문에 따로 이벤트 소스를 적지 않는다. (window만 해당된다.)

        //같은 클래스에서 호출하기 때문에 this를 쓴다.

        //Frame에 윈도우 리스너를 연결하고 WindowExit에 주소값을 전달한다.

         addWindowListener(new WindowExit(this));    

        

    }

    

    

    public static void main(String[] args) {

        AdapterTest test = new AdapterTest();

        test.setSize(300, 400);

        test.setVisible(true);

    }

}



※ 결과값





<ItemListener 이용하기>


package event;

import java.awt.Checkbox;

import java.awt.CheckboxGroup;

import java.awt.Frame;

import java.awt.Panel;

import java.awt.TextArea;

import java.awt.event.ItemEvent;

import java.awt.event.ItemListener;

//체크박스를 선택하거나 할 때

public class ItemTest1 extends Frame implements ItemListener{

    Panel p;                            //인스턴스 변수를 만든다.

    Checkbox c1, c2, c3, r1, r2;

    CheckboxGroup g1;

    TextArea area;

    

    ItemTest1(){                        //생성자를 생성한다.

        

        //리스너에 생성된 WindowExit 인스턴스의 주소값을 넘겨준다.

        addWindowListener(new WindowExit(this));    

        

        p = new Panel();

        c1 = new Checkbox("딸기");        //인스턴스를 생성한다.

        c2 = new Checkbox("사과");

        c3 = new Checkbox("배");

        g1 = new CheckboxGroup();

        r1 = new Checkbox("남성", g1, true);

        r2 = new Checkbox("여성", g1, false);

        area = new TextArea();

        

        p.add(c1);                        //패널에 체크박스를 추가한다.

        p.add(c2);

        p.add(c3);

        p.add(r1);

        p.add(r2);

        

        add("North", p);                //레이아웃을 꾸며준다.

        add("Center", area);

        

        c1.addItemListener(this);        //아이템리스너에 주소값을 보낸다.

        c2.addItemListener(this);

        c3.addItemListener(this);

        r1.addItemListener(this);

        r2.addItemListener(this);

        

        //API를 찾아보고 메서드를 써보자

        

        

    }

    

    @Override

    public void itemStateChanged(ItemEvent e) {

        // TODO Auto-generated method stub

        

    }

    

    public static void main(String[] args) {

        ItemTest1 test = new ItemTest1(); //클래스 인스턴스 생성

        test.setSize(300, 400);              //사이즈를 정함

        test.setVisible(true);              //창이 보여지게 함

    }

}


※ 결과값



package event;

import java.awt.Checkbox;

import java.awt.CheckboxGroup;

import java.awt.Frame;

import java.awt.Panel;

import java.awt.TextArea;

import java.awt.event.ItemEvent;

import java.awt.event.ItemListener;

//체크박스를 선택하거나 할 때

public class ItemTest1 extends Frame implements ItemListener{

    Panel p;                            //인스턴스 변수를 만든다.

    Checkbox c1, c2, c3, r1, r2;

    CheckboxGroup g1;

    TextArea area;

    

    ItemTest1(){                        //생성자를 생성한다.

        

        //리스너에 생성된 WindowExit 인스턴스의 주소값을 넘겨준다.

        addWindowListener(new WindowExit(this));    

        

        p = new Panel();

        c1 = new Checkbox("딸기");        //인스턴스를 생성한다.

        c2 = new Checkbox("사과");

        c3 = new Checkbox("배");

        g1 = new CheckboxGroup();

        r1 = new Checkbox("남성", g1, true);

        r2 = new Checkbox("여성", g1, false);

        area = new TextArea();

        

        p.add(c1);                        //패널에 체크박스를 추가한다.

        p.add(c2);

        p.add(c3);

        p.add(r1);

        p.add(r2);

        

        add("North", p);                //레이아웃을 꾸며준다.

        add("Center", area);

        

        c1.addItemListener(this);        //아이템리스너에 주소값을 보낸다.

        c2.addItemListener(this);

        c3.addItemListener(this);

        r1.addItemListener(this);

        r2.addItemListener(this);

        

        //API를 찾아보고 딸기체크했습니다. 뜨게하기.

        

        

    }

    

    @Override

    public void itemStateChanged(ItemEvent e) {

        Checkbox cb = (Checkbox)e.getSource();

        if(cb.getState()) {//if문 안의 내용은 true값이다.

            area.setText(e.getItem() + "이(가) 선택됨");    //창애 선택된 내용이 입력된다.

        }else {

            area.setText(e.getItem()+ "이(가) 해제됨");

        }

        

    }

    

    public static void main(String[] args) {

        ItemTest1 test = new ItemTest1(); //클래스 인스턴스 생성

        test.setSize(300, 400);              //사이즈를 정함

        test.setVisible(true);              //창이 보여지게 함

    }

}





다중선택 예제를 해보자


package event;

import java.awt.Button;

import java.awt.Choice;

import java.awt.Frame;

import java.awt.List;

import java.awt.Panel;

import java.awt.TextArea;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.ItemEvent;

import java.awt.event.ItemListener;

public class ItemTest2 extends Frame implements ItemListener, ActionListener{

    //인스턴스 변수를 선언한다.

    private Panel p;

    private Button btnDisplay;

    private Choice choice;

    private List list;

    private TextArea area;

    private String[] items = {"서울", "경기", "인천", "수원"};

    

    ItemTest2(){

        addWindowListener(new WindowExit(this));    //x버튼을 누르면 꺼진다.

        

        //인스턴스를 선언한다.

        p = new Panel();                        

        btnDisplay = new Button("List 출력");

        choice = new Choice();

        list = new List();

        area = new TextArea();

        

        //패널에 재료를 더한다.

        p.add(choice);

        p.add(list);

        p.add(btnDisplay);

        

        //패널의 내부 위치를 설정한다.

        add("North", p);

        add("Center", area);

        

        /*

        for(int i=0; i<4; i++) {

            choice.add(items[i]);

            list.add(items[i]);

        */

        

        for(String item: items) {

            choice.add(item);

            list.add(item);

        }

        

        choice.addItemListener(this); //아이템리스너를 핸들러로 연결해준다.

        list.setMultipleMode(true); //setMultipleMode() 메서드로 다중선택이 되도록한다.

        btnDisplay.addActionListener(this); //액션리스너를 핸들러로 연결해준다.

        

    }

    

    @Override //상속받은 ActionListener 오버라이드

    public void actionPerformed(ActionEvent e) {

        area.setText("");

        String[] items = list.getSelectedItems();//리스트선택시 데이터를 가져오는 역할

        for(String item : items) {

            area.setText(area.getText() + item + "선택됨 \n");

        }

        

    }

    

    @Override //상속받은 ItemListener 오버라이드

    public void itemStateChanged(ItemEvent e) {

        //getSelectedItem()이미 메서드의 정보를 가지고 있기 때문에 바로 호출 할 수 있다.

        area.setText(choice.getSelectedItem() + "이 선택됨");

    

    }

    

    

    public static void main(String[] args) {

        

        ItemTest2 test = new ItemTest2(); //클래스 인스턴스 생성

        test.setSize(300, 400);              //사이즈를 정함

        test.setVisible(true);              //창이 보여지게 함

    }

}









package event;

import java.awt.Button;

import java.awt.Frame;

import java.awt.TextArea;

import java.awt.TextField;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;

import java.awt.event.TextEvent;

import java.awt.event.TextListener;

public class TextTest extends Frame implements TextListener, KeyListener{

    

    private Button btn;

    private TextField field;

    private TextArea area;

    

    

    public TextTest(){

        

        addWindowListener(new WindowExit(this));

        

        btn = new Button("OK");

        field = new TextField();

        area = new TextArea();

        

        add("North", btn);

        add("Center", area);

        add("South", field);

    

        field.addTextListener(this);

        field.addKeyListener(this);

    }

    

    @Override    //텍스트가 변하 때 마다 텍스트가 더해지는 리스너

    public void textValueChanged(TextEvent e) {

        //area.setText(area.getText() +                     

        //        "내용이 변했어요" + field.getText() + "\n");

        

    }

    @Override    //문자출력 (주로 자주 씀)  ㅏkeyTyped 문자출력을 조금 더 정교하게

    public void keyPressed(KeyEvent e) {

        

        if(e.getKeyChar() != KeyEvent.VK_BACK_SPACE) {//현재 입력된 키보드 값이 백스페이스가 아닐 때만 출력

                                                         //VK_BACK_SPACE가상키보드

        //textValueChanged보다 한 템포 출력이 느리다.

        //그래서 getKeyChar()현재입력된 키보드 값을 가져온다.

        area.setText(area.getText() +                     

                "내용이 변했어요" + e.getKeyChar() + "\n");

        }

    }

    

    public static void main(String[] args) {

        

        TextTest test = new TextTest();

        test.setSize(300, 400);

        test.setVisible(true);

        

    }

    

    @Override

    public void keyReleased(KeyEvent e) {

        // TODO Auto-generated method stub

        

    }

    @Override

    public void keyTyped(KeyEvent e) {

        // TODO Auto-generated method stub

        

    }

}




package event;

import java.awt.Button;

import java.awt.Checkbox;

import java.awt.CheckboxGroup;

import java.awt.Color;

import java.awt.Frame;

import java.awt.GridLayout;

import java.awt.Panel;

import java.awt.TextArea;

import java.awt.event.ItemEvent;

import java.awt.event.ItemListener;

//간단한 신호등 제어 프로그램

//3등식 눌렀을 때 빨간, 노랑, 초록

//4등식 눌렀을 때 빨간, 노랑, 초록, 좌회전

public class EventHomework extends Frame implements ItemListener{

    

    

    //인스턴스 변수 생성

    private Panel p1, p2, p3;

    private Checkbox rdoThree, rdoFour;

    private CheckboxGroup g1;

    private Checkbox chkRed, chkYellow, chkLeft, chkGreen;

    private Button btnRed, btnYellow, btnLeft, btnGreen;

    private TextArea area;

    private boolean flag = true;

    

    public EventHomework() {

        addWindowListener(new WindowExit(this));

                                        //재료 만들기

        p1= new Panel();                //패널 인스턴스 생성

        p2= new Panel();

        p3= new Panel();

        

        chkRed = new Checkbox("빨강");    //체크박스 인스턴스 생성

        chkYellow = new Checkbox("노랑");

        chkLeft = new Checkbox("좌회전");

        chkGreen = new Checkbox("초록");

    

        g1 = new CheckboxGroup();        //체크박스 그룹과 체크박스 인스턴스 생성

        rdoThree = new Checkbox("3등식", g1, false);

        rdoFour = new Checkbox("4등식", g1, true);

        

        btnRed = new Button("빨강");        //버튼 인스턴스 생성

        btnYellow = new Button("노랑");

        btnLeft = new Button();

        btnGreen = new Button("초록");

    

        

        p1.add(rdoThree);                //패널에 재료를 배치하여 디자인

        p1.add(rdoFour);

        

        p2.add(chkRed);

        p2.add(chkGreen);

        p2.add(chkLeft);

        p2.add(chkYellow);

        

        p3.setLayout(new GridLayout(1,4));

        p3.add(btnRed);

        p3.add(btnGreen);

        p3.add(btnLeft);

        p3.add(btnYellow);

        

        

        add("North", p1);                //레이아웃을 꾸며준다.

        add("West", p2);

        add("South", p3);

        

        chkRed.addItemListener(this);

        chkYellow.addItemListener(this);

        chkLeft.addItemListener(this);

        chkGreen.addItemListener(this);

        

        rdoFour.addItemListener(this);

        rdoThree.addItemListener(this);

        

    }

    

    //3등식 일 때는 btnLeft가 보이지 않는 메서드

    void rdoThree () {

        if(rdoThree.getState()) {

            btnLeft.setEnabled(true);

        

        }else {

            

        }

            

    }

    

    @Override

    public void itemStateChanged(ItemEvent arg0) {

                

    

            //4등식 눌렀을 때는 4개만 불 나오고, 3등식을 눌렀을 때는 3개만 불이 나온다.

            if(chkRed.getState()) {

                btnRed.setBackground(Color.RED);                

            }else {

                btnRed.setBackground(null);

            }

            if(chkYellow.getState()) {

                btnYellow.setBackground(Color.YELLOW);                

            }else {

                btnYellow.setBackground(null);

            }

            if(chkLeft.getState()&&rdoFour.getState()) {

                btnLeft.setLabel("←");

                btnLeft.setBackground(Color.PINK);

            }else {

                rdoThree();

                btnLeft.setLabel("");

                btnLeft.setBackground(null);        

            }    

            if(chkGreen.getState()) {

                btnGreen.setBackground(Color.GREEN);                

            }else {

                btnGreen.setBackground(null);

            }

    }

    

    public static void main(String[] args) {

        EventHomework test = new EventHomework(); //클래스 인스턴스 생성

        test.setSize(300, 400);                       //사이즈를 정함

        test.setVisible(true);                      //창이 보여지게 함

    }

}






7. 메뉴


1) Pull Down Menu (고정식)

    - 눌렀을 때 메뉴 전체가 아래로 나온다.

    - 아래 3가지는 고정식 메뉴의 요소들이다.

    ① MenuBar

        - 메뉴를 붙이기 위한 길다란 바

    ② Menu

        - 메뉴바 하나하나에 있는 메뉴

    ③ MenuItem

        - 메뉴 안에 있는 실행가능한 메뉴아이템



2) Pop Up Menu (이동식, Context Menu)

    - 팝업창처럼 툭 튀어나온다.

    - 위치에 따라서 각각의 메뉴가 달라진다.

    - 키보드에도 context 키가 있다.


메뉴아이템은 절대로 메뉴를 만들 수 없다.

메뉴아이템을 가질 수 있는건 메뉴 밖에 없다.



<UX 와 Swing>

UX(User Experience Design): 사용자의 경험을 바탕으로 디자인 해야한다.


RIA (Rich Internet Application) :  웹 애플리케이션의 장점은 유지하면서 

기존 웹 브라우저 기반 인터페이스의 단점인 늦은 응답 속도, 

데스크톱 애플리케이션에 비해 떨어지는 조작성 등을 개선하기 위한 기술의 통칭이다. 

예전에 많이 알려졌지만 지금은 사라짐


Swing은 UX를 생각하면서 만들었다.



package menu;

import java.awt.Frame;

import java.awt.Menu;

import java.awt.MenuBar;

import java.awt.MenuItem;

import event.WindowExit;

;

public class MenuTest1 extends Frame{

    private MenuBar bar;    //인스턴스 변수 생성

    private Menu file, edit, file_new;

    private MenuItem file_open, file_save, file_exit;

    private MenuItem edit_cut, edit_copy, edit_paste;

    private MenuItem file_new_java, file_new_c;

    

    public MenuTest1() {    //외부 접근을 위해 public 을 한다.

        addWindowListener(new WindowExit(this));

        

        bar = new MenuBar();    //인스턴스 생성

        

        file = new Menu("파일");

        edit = new Menu("편집");

        file_new = new Menu("새파일");    // 메뉴아이템은 절대로 메뉴를 만들 수 없다.

        

        bar.add(file);

        bar.add(edit);

        

        

        

        file_open = new MenuItem("파일열기");

        file_save = new MenuItem("파일저장");

        file_exit = new MenuItem("종료");

        

        

        edit_cut = new MenuItem("잘라내기");

        edit_copy = new MenuItem("복사하기");

        edit_paste = new MenuItem("붙여넣기");

        

        file.add(file_new);    //    

        file.add(file_open);    //디자인 배치

        file.add(file_save);

        file.addSeparator();    //구분자

        file.add(file_exit);

        

        edit.add(edit_cut);

        edit.add(edit_copy);

        edit.add(edit_paste);

        

        file_new_java = new MenuItem("자바");

        file_new_c = new MenuItem("C");

        

        file_new.add(file_new_java);

        file_new.add(file_new_c);

        

        

        

        setMenuBar(bar);    //메뉴바를 담는 형식이다.

        

    }

    

    public static void main(String[] args) {

        // TODO 고정식 메뉴

        

        MenuTest1 test = new MenuTest1(); //클래스 인스턴스 생성

        test.setSize(300, 400);              //사이즈를 정함

        test.setVisible(true);              //창이 보여지게 함

    }

}









package menu;

import java.awt.FileDialog;

import java.awt.Frame;

import java.awt.Menu;

import java.awt.MenuBar;

import java.awt.MenuItem;

import java.awt.TextArea;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.io.BufferedReader;

import java.io.FileReader;

import java.io.FileWriter;

import event.WindowExit;

;

public class MenuTest2 extends Frame implements ActionListener{

    private MenuBar bar;    //인스턴스 변수 생성

    private Menu file, edit, file_new;

    private MenuItem file_open, file_save, file_exit;

    private TextArea area;  

    private FileDialog fopen, fsave;

    

    public MenuTest2() {            

        

        addWindowListener(new WindowExit(this));

        

        bar = new MenuBar();    //인스턴스 생성

        file = new Menu("파일");

        area = new TextArea();

        

        bar.add(file);

        

        file_open = new MenuItem("파일열기");

        file_save = new MenuItem("파일저장");

        file_exit = new MenuItem("종료");

        

        fopen = new FileDialog(this, "파일열기", FileDialog.LOAD);

        fsave = new FileDialog(this, "파일저장", FileDialog.SAVE);

        

        

        file.add(file_open);    //디자인 배치

        file.add(file_save);        

        file.addSeparator();    //구분자

        file.add(file_exit);

        

        setMenuBar(bar);    //메뉴바를 담는 형식이다.

        add("Center", area);

        

        file_exit.addActionListener(this);            //오버라이드 연결해주는 핸들러

        file_open.addActionListener(this);

        file_save.addActionListener(this);

    }

    

    @Override

    public void actionPerformed(ActionEvent e) {

        

        if(e.getActionCommand().equals("종료")) {        //종료메뉴를 누르면 종료됨

            dispose();

        }else if(e.getActionCommand().equals("파일열기")) {

            

            //아래 내용은 java I/O 참고

            try {

                fopen.setVisible(true);        //파일열기

                

                String filepath = fopen.getDirectory() + "\\"    +

                        fopen.getFile();

                FileReader freader = new FileReader(filepath);//파일리더

                BufferedReader br = new BufferedReader(freader);

                

                String input = null;

                

                while((input = br.readLine()) != null) {

                    area.append(input + "\n");

                }

                

            }catch(Exception err) {

                err.printStackTrace();

            }

        }else {

            

            try {

                fsave.setVisible(true);            //파일저장하기

                

                String filepath = fsave.getDirectory() + "\\"    +

                        fsave.getFile();

                FileWriter fw = new FileWriter(filepath);

                

                fw.write(area.getText());

                fw.close();

                

            }catch(Exception err) {

                err.printStackTrace();

            }

            

        }

          

        

    }

    

    public static void main(String[] args) {

        // TODO 고정식 메뉴

        

        MenuTest2 test = new MenuTest2(); //클래스 인스턴스 생성

        test.setSize(300, 400);              //사이즈를 정함

        test.setVisible(true);              //창이 보여지게 함

    }

}





파일이 열리고 저장된다.










package menu;

import java.awt.Frame;

import java.awt.MenuItem;

import java.awt.PopupMenu;

import java.awt.event.MouseEvent;

import java.awt.event.MouseListener;

import event.WindowExit;

public class MenuTest3 extends Frame implements MouseListener{

    PopupMenu pmenu;

    MenuItem fileopen, filesave, exit;

    

    public MenuTest3() {

        addWindowListener(new WindowExit(this));

        

        pmenu = new PopupMenu();

        fileopen = new MenuItem("파일열기");

        filesave = new MenuItem("파일저장");

        exit = new MenuItem("종료");

        

        pmenu.add(fileopen);

        pmenu.add(filesave);

        pmenu.add(exit);

        

        add(pmenu);

        

        addMouseListener(this);

        

    }

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        MenuTest3 test = new MenuTest3(); //클래스 인스턴스 생성

        test.setSize(300, 400);              //사이즈를 정함

        test.setVisible(true);              //창이 보여지게 함

    }

    @Override

    public void mouseClicked(MouseEvent e) {

        // TODO Auto-generated method stub

        pmenu.show(this, e.getX(), e.getY());

    }

    @Override

    public void mouseEntered(MouseEvent e) {

        // TODO Auto-generated method stub

        

    }

    @Override

    public void mouseExited(MouseEvent e) {

        // TODO Auto-generated method stub

        

    }

    @Override

    public void mousePressed(MouseEvent e) {

        // TODO Auto-generated method stub

        

    }

    @Override

    public void mouseReleased(MouseEvent e) {

        // TODO Auto-generated method stub

        

    }

}


어디를 클릭해도 팝업메뉴가 나온다.






Thread 스레드


- C 나 C++ 의 Thread는 운영체제를 잘 알아야 하지만 Java의 Thread는 언어차원에서 해결하기 때문에 비교적 쉽다.


1. Process and Program

- 일반적으로 프로그램이라고 이야기하면 하드디스크에 저장되어 실행되지 않은 상태를 말한다. 

- 프로세스는 실행 중인 프로그램을 이야기한다.

- 프로그램 (실행X), 프로세스 (실행O)

- 프로그램이 보조기억장치에 있던 것을 cpu가 사용 할 수 있도록 

  보조기억장치에서 주기억장치로 프로그램이 로드된 상태가 프로세스다.


Multi Process (= Multi Tasking)

- 멀티프로세스는 여러개의 프로그램이 동시에 실행되는 것이다


시분할 (Time Sharing)

- 정확히 말하면 컴퓨터는 동시에 여러가지 작업을 할 수는 없다.

CPU는 한번에 한가지 작업만 할 수 있기 때문이다.

사실은 동시에 작업을 하지 않는다.

시간을 쪼개서 동시에 작업을 하는 것처럼 보이도록 한다.

이를 시분할 이라고 한다. 


Muti Processor

- 여러개의 CPU를 말한다.

- 일반적인 프로그램은 하나의 cpu만 사용하기 때문에 프로그램 성능은 똑같다.

- 윈도우와 같은 OS 는 프로그램이 멀티프로세스 

  할 수 있도록 시간사용을 스계쥴링 해주는 프로그램이다.


Thread란 무엇일까?

하나의 프로세스 안에서도 동시에 작업할 수 있어야 한다.

하나의 프로세스 안에서 실행되는 작업 단위를 스레드Thread 라고 한다.


2. Multi Thread

멀티스레드란 무엇일까?

하나의 프로세스 안에서 여러 개의 프로세스가 동시에 실행될 수 있도록 하는 것이다.

멀티스레드가 되어야 다운로드를 받는 중에도 X 버튼을 누를 수 있다.

게임을 만들 때에도 총을 쏠 때 피할 수 있으려면 멀티스레드를 할 수 있어야 한다.


3. 자바에서 지원하는 스레드 기법


1) Thread 클래스

- 다른 클래스를 상속 받을 필요가 없다면 스레드 클래스만 상속받아서 사용한다.


2) Runnamble 인터페이스

- 다른 클래스도 상속받고 스레드도 상속받아야 한다면,

자바에서는 클래스 다중상속이 안되기 때문에 다중상속이 가능한 

Runnamble 인터페이스를 상속받는다.



4. 모든 자바 클래스는 반드시 하나의 스레드를 가지고 있다.

- main 메서드가 하나의 스레드이다. 

- 모든 자바클래스는 메인스레드를 가지고 있다.


<Thread 클래스>

- 메인스레드를 제외한 나머지는 자식스레드이다.

- run() 메소드는 자식 스레드가 해야 할 일을 적어준다.




package prjThread;

class ThreadDemo extends Thread{

    //private String name;

    //어떤 스레드가 작업하는지 확인하기 위해 변수를 만든다.

    private String name;

    public ThreadDemo(String name) {

        this.name = name;

    }    

   

    

    @Override

    //callback 우리가 호출하는게 아니라 시스템이 호출하는 메서드

    //run()은 콜백메서드이기 때문에 시스템에게 부탁만 할 수 있다.

    //오버라이드 규칙상 부모로부터 받은 메서드를 똑같이 써야하기 때문에 throws 예외처리를 할 수 없다.

    public void run() {

        

        //1~5까지 합계를 구한다.

        int sum = 0 ;

        for(int i=0; i<5; i++) {

            

            try {

                sleep(100);    //thread에서 0.1초 단위로 한 쪽을 쉬게 하는 메서드이다.

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                

                e.printStackTrace();

            }

            

            sum += i;

           

            //1~5까지 합계를 출력한다.

            //임의로 이름을 붙힐 수 있도록 만들어 준다.

            //부모클래스에게 상속할 경우 getName()을 쓴다.

            System.out.println(name + ":" + sum);

            

            //출력을 해보면 순서는 실행 할 때 마다 다르지만 하나의 작업이 끝나고 두번째 작업을 한다.

        }

    }

    

}


public class ThreadTest1 {

    

    //메인스레드를 제외한 나머지는 자식스레드이다.

    public static void main(String[] args) {

    

        //부모가 스레드이고 부모로부터 상속 받았기 때문에 인스턴스도 스레드가 된다.

        //메인스레드와 함께 스레드가 2개가 되었다.

        //0부터 5까지 합계를 구하는 스레드가 되었다.

        ThreadDemo demo1 = new ThreadDemo("first");

        

        //인스턴스가 별개로 생성됨으로 스레드가 3개가 되었다.

        //0부터 5까지 합계를 구하는 스레드가 되었다.

        //원래 스레드는 각각 다른 클래스에 해야한다.

        ThreadDemo demo2 = new ThreadDemo("second");

        

        demo1.start(); //시스템에게 호출해달라고 부탁한다.

        demo2.start(); //시스템에게 호출해달라고 부탁한다.        

    }

}


※결과값

first:0

second:0

second:1

first:1

first:3

second:3

second:6

first:6

first:10

second:10







package prjThread2;

class ThreadDemo extends Thread{

    //private String name;

    

    public ThreadDemo(String name) {

        

        super(name); //현재 스레드의 이름을 부모에게 저장시킨다.

    }

    

    @Override

    //callback 우리가 호출하는게 아니라 시스템이 호출하는 메서드

    //run()은 콜백메서드이기 때문에 시스템에게 부탁만 할 수 있다.

    //오버라이드 규칙상 부모로부터 받은 메서드를 똑같이 써야하기 때문에 throws 예외처리를 할 수 없다.

    public void run() {

        

        //1~5까지 합계를 구한다.

        int sum = 0 ;

        for(int i=0; i<5; i++) {

            

            try {

                sleep(100);    //thread에서 0.1초 단위로 한 쪽을 쉬게 하는 메서드이다.

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            

            

            sum += i;

            

            //1~5까지 합계를 출력한다.

            //임의로 이름을 붙힐 수 있도록 만들어 준다.

            //부모클래스에게 상속할 경우 getName()을 쓴다.

            System.out.println(getName() + ":" + sum);

            

            //출력을 해보면 순서는 실행 할 때 마다 다르지만 하나의 작업이 끝나고 두번째 작업을 한다.

        }

    }

    

}


public class ThreadTest1 {

    

    //메인스레드를 제외한 나머지는 자식스레드이다.

    public static void main(String[] args) {

    

        

        //부모가 스레드이고 부모로부터 상속 받았기 때문에 인스턴스도 스레드가 된다.

        //메인스레드와 함께 스레드가 2개가 되었다.

        //0부터 5까지 합계를 구하는 스레드가 되었다.

        ThreadDemo demo1 = new ThreadDemo("first");

        

        //인스턴스가 별개로 생성됨으로 스레드가 3개가 되었다.

        //0부터 5까지 합계를 구하는 스레드가 되었다.

        //원래 스레드는 각각 다른 클래스에 해야한다.

        ThreadDemo demo2 = new ThreadDemo("second");

        

              

        

        demo1.start();

        demo2.start();

        

    }

}



※결과값

first:0

second:0

first:1

second:1

first:3

second:3

second:6

first:6

second:10

first:10






package prjThread;

class ThreadDemo extends Thread{

    //private String name;

    

    /*

    //어떤 스레드가 작업하는지 확인하기 위해 변수를 만든다.

    private String name;

    public ThreadDemo(String name) {

        this.name = name;

    }    

    */

    

    /*

    public ThreadDemo(String name) {

        

        super(name); //현재 스레드의 이름을 부모에게 저장시킨다.

    }

    */

    

    @Override

    //callback 우리가 호출하는게 아니라 시스템이 호출하는 메서드

    //run()은 콜백메서드이기 때문에 시스템에게 부탁만 할 수 있다.

    //오버라이드 규칙상 부모로부터 받은 메서드를 똑같이 써야하기 때문에 throws 예외처리를 할 수 없다.

    public void run() {

        

        //1~5까지 합계를 구한다.

        int sum = 0 ;

        for(int i=0; i<5; i++) {

            

            try {

                sleep(100);    //thread에서 0.1초 단위로 한 쪽을 쉬게 하는 메서드이다.

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            

            

            sum += i;

            

            //1~5까지 합계를 출력한다.

            //임의로 이름을 붙힐 수 있도록 만들어 준다.

            //부모클래스에게 상속할 경우 getName()을 쓴다.

            System.out.println(getName() + ":" + sum);

            

            //출력을 해보면 순서는 실행 할 때 마다 다르지만 하나의 작업이 끝나고 두번째 작업을 한다.

        }

    }

    

}


public class ThreadTest1 {

    

    //메인스레드를 제외한 나머지는 자식스레드이다.

    public static void main(String[] args) {

    

        /*

        //부모가 스레드이고 부모로부터 상속 받았기 때문에 인스턴스도 스레드가 된다.

        //메인스레드와 함께 스레드가 2개가 되었다.

        //0부터 5까지 합계를 구하는 스레드가 되었다.

        ThreadDemo demo1 = new ThreadDemo("first");

        

        //인스턴스가 별개로 생성됨으로 스레드가 3개가 되었다.

        //0부터 5까지 합계를 구하는 스레드가 되었다.

        //원래 스레드는 각각 다른 클래스에 해야한다.

        ThreadDemo demo2 = new ThreadDemo("second");

        */

        

        //따로 이름을 붙이지 않아도 자식스레드에 이름을 붙이기 때문에 그 이름을 써도 된다.

        ThreadDemo demo1 = new ThreadDemo(); //시스템에게 호출해달라고 부탁한다.

        ThreadDemo demo2 = new ThreadDemo(); //시스템에게 호출해달라고 부탁한다.        

        

        demo1.start();

        demo2.start();

        

    }

}


※결과값

Thread-1:0

Thread-0:0

Thread-0:1

Thread-1:1

Thread-1:3

Thread-0:3

Thread-0:6

Thread-1:6

Thread-1:10

Thread-0:10






package prjThread;

//Runnable 인터페이스는 스레드가 해야할 기능을 물려받았지 스레드가 아니다.

class ThreadDemo implements Runnable{

    @Override

    public void run() {

        //1~5까지 합계를 구한다.

        int sum = 0 ;

        for(int i=0; i<5; i++) {

            

            try {

                //thread에서 0.1초 단위로 한 쪽을 쉬게 하는 메서드이다.

                //static 메서드이기 때문에 어디서나 불러올 수 있다.

                Thread.sleep(500);    

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            

            

            sum += i;

            //run()메서드가 스레드를 연결하여 출력한다.

            System.out.println(Thread.currentThread().getName() +  ":" + sum);    

            

        }

    }

}


public class ThreadTest0 {

    //메인스레드를 제외한 나머지는 자식스레드이다.

    public static void main(String[] args) {

    ThreadDemo demo1 = new ThreadDemo();

    ThreadDemo demo2 = new ThreadDemo();

    

    Thread t1 = new Thread(demo1);

    Thread t2 = new Thread(demo2);

    

    t1.start();

    t2.start();

        

    }

}



※결과값

Thread-0:1

Thread-1:1

Thread-0:3

Thread-1:3

Thread-0:6

Thread-1:6

Thread-0:10

Thread-1:10




package prjThread;

class ThreadDemo2 extends Thread{//Thread를 상속받음

    @Override

    public void run() {             //run()은 시스템이 실행하는 메소드이다.

        System.out.println("자식 스레드 시작");

        

        //자식스레드릥 행동 1~9까지

        int cnt = 0;

        do {

            try {

                sleep(500);    //번갈아 가변서 일 할 수 있도록 0.5초 자식스레드에 쉬는 시간을 준다.

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            cnt++;

            System.out.print(cnt);

        }while(cnt<10);

        

        System.out.println("\n자식 스레드 종료\n");

    }    

    

}


public class ThreadTest2 {

    public static void main(String[] args) {

        

        System.out.println("메인 스레드 시작");

        

        ThreadDemo2 demo1 = new ThreadDemo2();    //ThreadDemo2 인스턴스가 스레드가 됨.

        demo1.start();                            //시스템에서 run()을 실행해달라고 요청.

        

        //자식스레드와 구별된 행동 1~9개 점 찍기

        int cnt = 0;

        do {

            try {

                Thread.sleep(200); //번갈아 가변서 일 할 수 있도록 메인스레드에 0.2초 쉬는 시간을 준다.

                                   //메인은 스레드클래스이지만 스래드 클래스는 아니기 때문에 Thread를 상속받는다.

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            cnt ++;

            System.out.print(".");

        }while(cnt<10);

        

        System.out.println("\n메인 스레드 종료\n");

    }

}



※ 결과값


메인 스레드 시작

자식 스레드 시작

..1..2...3..4.

메인 스레드 종료

5678910

자식 스레드 종료





Runnable 상속경우는 어떨까?



package prjThread;

class ThreadDemo2_1 implements Runnable{//Thread를 상속받지 못할 때는 Runnable인터페이스 상속

    String name;

    

    ThreadDemo2_1(String name){    //생성자를 생성

        this.name = name;        //인스턴스의 인자에 적힌 이름을 이름을 부모 클래스에 넣음

    }

    

    @Override

    public void run() {                                //run()은 시스템이 실행하는 메소드이다.

        System.out.println(name + "자식 스레드 시작");    //getName()을 이용해 부모생성자에 있는 이름을 가져옴.

        

        //자식스레드릥 행동 1~9까지

        int cnt = 0;

        do {

            try {

                Thread.sleep(500);    //번갈아 가변서 일 할 수 있도록 0.5초 자식스레드에 쉬는 시간을 준다.

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            cnt++;

            System.out.print(cnt);

        }while(cnt<10);

        

        System.out.println("\n자식 스레드 종료\n");

    }    

    

}


public class ThreadTest2_1 {

    public static void main(String[] args) {

        

        System.out.println("메인 스레드 시작");

        

        ThreadDemo2_1 demo1 = new ThreadDemo2_1("first");    //ThreadDemo2 demo1 인스턴스 생성

        ThreadDemo2_1 demo2 = new ThreadDemo2_1("second");    //ThreadDemo2 demo2 인스턴스 생성

        

        Thread t1  = new Thread(demo1); // Runnable에서 상속받은 클래스를 완전한 스레드기 되도록 만들어준다.

        Thread t2  = new Thread(demo2); // Runnable에서 상속받은 클래스를 완전한 스레드기 되도록 만들어준다.

        

        t1.start();                        //시스템에서 run()을 실행해달라고 요청.

        t2.start();                        //시스템에서 run()을 실행해달라고 요청.

        

        //자식스레드와 구별된 행동 1~9개 점 찍기

        int cnt = 0;

        do {

            try {

                Thread.sleep(200); //번갈아 가변서 일 할 수 있도록 메인스레드에 0.2초 쉬는 시간을 준다.

                                   //메인은 스레드클래스이지만 스래드 클래스는 아니기 때문에 Thread를 상속받는다.

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            cnt ++;

            System.out.print(".");

        }while(cnt<10);

        

        System.out.println("\n메인 스레드 종료\n");

    }

}


※ 결과값

메인 스레드 시작

first자식 스레드 시작

second자식 스레드 시작

..11..22...33..44.

메인 스레드 종료

556677889910

자식 스레드 종료

10

자식 스레드 종료


★ 이클립스 팁! ★

ctrl + alt + ↓(↑) = 이클립스에서 문장 복사 



package prjThread;

class ThreadDemo3 implements Runnable {

    

    String name;

    //Thread t; // 스레드 변수를 만들어 준다.

    

    ThreadDemo3(String n){

        name = n;

        //t = new Thread(this); //스레드의 인스턴스를 생성한다.

        //t.start(); //스레드 시작을 시스템에 요청한다.

        new Thread(this).start(); //자기 자신의 주소를 불러와 스레드 시작을 시스템에 요청한다.

    }

    

    @Override

    public void run() {

        for(int i=0; i<5; i++) {

            System.out.println(name + ":" + i);

        }

    }

}

public class ThreadTest3{

    public static void main(String[] args) {

        ThreadDemo3 d1 = new ThreadDemo3("스레드1"); //자기 자신의 주소가 인스턴스에 생성되었다.

        ThreadDemo3 d2 = new ThreadDemo3("스레드2"); //자기 자신의 주소가 인스턴스에 생성되었다.

        ThreadDemo3 d3 = new ThreadDemo3("스레드3"); //자기 자신의 주소가 인스턴스에 생성되었다.

    

        }

}


※ 결과값

스레드1:0

스레드1:1

스레드3:0

스레드3:1

스레드3:2

스레드3:3

스레드3:4

스레드2:0

스레드2:1

스레드2:2

스레드2:3

스레드2:4

스레드1:2

스레드1:3

스레드1:4




5. Thread의 Lifecycle


스레드의 일생을 알아보자.

스레드가 어떻게 생겨서 어떻게 사라지는가?


<실행>

★ thread()

 - 프로세스 작업의 최소 실행단위이다.


★ start()

 - 스레드는 반드시 Start 로 시작해야 한다.


★ run()

 - 스레드가 일을 하기 위해서는 

   Run()이라는 방 안에 들어가야만 한다.

   Run 방 안에는 1개의 

   스레드만 들어 갈 수 있다.

 - 모든 스레드는 run()으로 간다.



<비동기화 경우 휴식>

★ suspend()

- 스레드를 잠시 강제로 쉬도록 한다.

- 위험하다. 깨우지 않으면 계속 쉰다.

- 깨우기 위해 resume() 메서드를 사용한다.


★ sleep()

 - 일반적으로 가장 권장하는 휴게실이다.

 - 자동으로 start()에 돌아간다.


★ block

 - 시스템이 로딩 중일 때 다른 일을 할 수 

   있는 상태와 같다.

- 자동으로 start()로 돌아간다.


<동기화 경우 휴식>

★ wait()

  - 동기화 일 때만 쉬러 간다.

  - 동기화를 하기 위해 

     synchronization을 해야 한다.

  - 여러 개의 스래드가 동시에 같이 쉴 수 있다.



<종료>

1. 자연스럽게 종료 : 가장 좋다.

 

2. 강제종료 : 부득이한 경우에만 사용


   ① Stop

     - 무조건 바로 중지

     - 위험부담이 크다


   ② interrupt()

     - 여유를 주고 중지 


   ③ 직접처리

     - 가장 선호하는 방식




<동기화>

- 순서를 정해서 메모리(heap)에 접근하는 의미를 가지고 있다.

- 동시점근을 막고 접근 순서를 개발자가 통제하는 방법이다.

- 작업을 1번에 1개씩 처리해야 할 때 쓴다.

- 동기화가 깨지는 이유는 일을 동시에 처리하려고 하기 때문이다.

- 동기화가 깨졌을 때 문제가 생길 수도 있는 영역에 쓴다.

예 ) 돈을 ATM에 넣었는데 통장에는 없을 때



<동기화의 유의 할 점>

- 동기화를 하면 성능은 떨어진다.

- 동기화는 꼭 필요한 곳에서만 한다.


<대표적인 동기화 알고리즘>

1.세마포어 알고리즘

- 기다리다가 없는 공간이 있으면 들어간다.

2.뮤텍스 알고리즘

- 기다리다가 없는 공간이 있어도 줄서던 대로 기다린다.


동기화가 없다면 어떻게 될까?


package prjThread;

class Toilet{

    public void openDoor(String name) {

        System.out.println(name + " : 입장");

        

        

        for(int i=0; i<100000; i++) {

            if(i == 5000) {

                System.out.println(name + " : 끄응~~~");

            }

        }

        System.out.println(name + " : 퇴장");

        

        

    }

}


class Family extends Thread{

    Toilet toilet;

    String who;

    

    

    Family(Toilet t, String w){

        toilet = t;

        who = w;

    }

    

    @Override

    public void run() {

        toilet.openDoor(who); //who인자를 넣어 openDoor를 불러온다.

    }

    

    

}


public class SyncTest1 {

    public static void main(String[] args) {

        // TODO 왜 동기화인가?

        

        Toilet t = new Toilet();

        

        Family father = new Family(t, "아버지");

        Family mother = new Family(t, "어머니");

        Family brother = new Family(t, "형");

        Family sister = new Family(t, "누나");

        Family me = new Family(t, "나");

        

        father.start();

        mother.start();

        brother.start();

        sister.start();

        me.start();

        

    }

}


※ 결과값


어머니 : 입장

나 : 입장

아버지 : 입장

형 : 입장

나 : 끄응~~~

누나 : 입장

아버지 : 끄응~~~

어머니 : 끄응~~~

형 : 끄응~~~

누나 : 끄응~~~

형 : 퇴장

나 : 퇴장

누나 : 퇴장

어머니 : 퇴장

아버지 : 퇴장



1개의 화장실에는 꼭 1명만 가야한다.

그러나 동기화가 안된 상태에서 스레드를 동작하면

화장실에 여러명이 가는 대참사가 벌어진다.

1화장실에 1명씩 가도록 동기화하려면 어떻게 해야할까?


이럴때는 synchronized로 동기화처리하여 

스레드를 순차적으로 접근할 수 있도록 한다.

동기화는 반드시 메서드 단위로 붙여주어야한다.


package prjThread;

class Toilet{

    

    //synchronized로 동기화처리하여 스레드를 순차적으로 접근할 수 있도록 한다.

    public synchronized void openDoor(String name) {

        System.out.println(name + " : 입장");

        

        

        for(int i=0; i<100000; i++) {

            if(i == 5000) {

                System.out.println(name + " : 끄응~~~");

            }

        }

        System.out.println(name + " : 퇴장");

        

        

    }

}

class Family extends Thread{

    Toilet toilet;

    String who;

    

    

    Family(Toilet t, String w){

        toilet = t;

        who = w;

    }

    

    @Override

    public void run() {

        toilet.openDoor(who); //who인자를 넣어 openDoor를 불러온다.

    }

    

    

}


public class SyncTest1 {

    public static void main(String[] args) {

        // TODO 왜 동기화인가?

        

        Toilet t = new Toilet();

        

        Family father = new Family(t, "아버지");

        Family mother = new Family(t, "어머니");

        Family brother = new Family(t, "형");

        Family sister = new Family(t, "누나");

        Family me = new Family(t, "나");

        

        father.start();

        mother.start();

        brother.start();

        sister.start();

        me.start();

        

    }

}


※ 결과값

아버지 : 입장

아버지 : 끄응~~~

아버지 : 퇴장

나 : 입장

나 : 끄응~~~

나 : 퇴장

누나 : 입장

누나 : 끄응~~~

누나 : 퇴장

형 : 입장

형 : 끄응~~~

형 : 퇴장

어머니 : 입장

어머니 : 끄응~~~

어머니 : 퇴장



6. synchronized


<사용법>

1) 메서드 앞에 사용 할 때

2) 특정 변수나 메서드 내에 일부코드를 사용하고 싶을 때 

- 공유객체는 인스턴스 관련 코드들이다.

- 여기서 공유객체란 사용할 수 있는 범위를 정해주는 값이다.


synchronized(공유객체) {

        코드

}


<컬렉션과 동기화>

컬렉션에서 ArrayList 는 비동기화되어있지만, vector는 동기화가 되어 있다.

가급적이면 컬렉션에서 ArrayList를 써야하는 이유가 이 때문이다.



<Stack 컬렉션>

- 스택메모리와 똑같이 사용할 수 있도록 만든 컬렉션이다.

- 집어넣을 때는 push

- 꺼낼때는 pop이다.


자판기의 돈을 먹고 음료를 먹어보자.




package prjThread;

import java.util.Stack;

//////////////////////////////////////////////////자판기

class AutoMachine{                                //음료수를 저장할 수 있는 공간을 마련한다. 컬렉션으로 준비하자

    Stack store = new Stack();                     //스택메모리와 똑같이 사용할 수 있도록 만든 컬렉션 (먼저 넣으면 나중에 나옴)

    

    

    //음료수를 넣을 때 (관리자용)

    synchronized void putDrink(String drink) {    //동기화 시켜서 음료수를 넣고 꺼내게 한다.

        store.push(drink);                        //음료수를 넣는다.

        notify();                                //비어있을 때는 꺼내지 않지만 안비워져 있을 때는 꺼내야한다.        

    }

    

    //음료수를 꺼낼 때 (사용자용)

    synchronized String getDrink() {            //동기화 시켜서 음료수를 넣고 꺼내게 한다.

        while(store.isEmpty())

            try {

                wait();                            //창고가 비워져 있을 때는 기다려야한다.

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            

        

        return store.pop().toString();  //음료수를 뺀다.

    }

    

}


////////////////////////////////////////////////음료수 공급자

                                              //음료수를 공급하는 제공하는 클래스이다.

class Producer implements Runnable{

    private AutoMachine auto;

    

    Producer(AutoMachine a){                   //생성자이다.

        auto = a;

    }

    

    @Override

    public void run() {                          //자판기에 음료수를 집어넣는 작업을 할 수 있다.

        for(int i =0; i<10 ; i++) {           //음료수 10개를 집어넣겠다.

                                              // 공급자가 음료수를 넣는다.

        System.out.println(Thread.currentThread().getName() +

                             " : 음료수 No. " + i + "채워넣음");

        auto.putDrink("음료수 No." + i);

        

                                              //음료수 넣는 속도를 늦춘다. 천천히 하나씩.

        try {

            Thread.sleep(500);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        

      }

    

   }

}


///////////////////////////////////////////////소비자

class Consumer implements Runnable{             //소비자를 만든다.

    private AutoMachine auto;

    

    Consumer(AutoMachine a){                  //생성자이다.

        auto = a;

    }

    @Override

    public void run() {

        for(int i=0; i<10; i++) {             //음료수를 친구 몪까지 10개를 꺼내간다.

                                             //소비자가 음료수를 꺼내먹었다.

            System.out.println(Thread.currentThread().getName() +

                              ":" + auto.getDrink() + "꺼내먹음");

                                            

            try {

                Thread.sleep(500);               //음료수 넣는 속도를 늦춘다. 천천히 하나씩.

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    }

    

}


//////////////////////////////////////////////main

public class SyncTest2 {

    public static void main(String[] args) { // 자판기에 돈을 넣고 음료를 먹어보자

        AutoMachine auto = new AutoMachine();

        

        Producer hong = new Producer(auto);

        Consumer kim = new Consumer(auto);

        

        

                                             //스레드 생성자에 이름을 두개 넘겨줄 수 도 있다.

        Thread h = new Thread(hong, "홍길동");

        Thread k = new Thread(kim, "김유신");

        

        h.start();

        k.start();

        

    }

}


※ 결과값

홍길동 : 음료수 No. 0채워넣음

김유신:음료수 No.0꺼내먹음

홍길동 : 음료수 No. 1채워넣음

김유신:음료수 No.1꺼내먹음

홍길동 : 음료수 No. 2채워넣음

김유신:음료수 No.2꺼내먹음

홍길동 : 음료수 No. 3채워넣음

김유신:음료수 No.3꺼내먹음

홍길동 : 음료수 No. 4채워넣음

김유신:음료수 No.4꺼내먹음

홍길동 : 음료수 No. 5채워넣음

김유신:음료수 No.5꺼내먹음

홍길동 : 음료수 No. 6채워넣음

김유신:음료수 No.6꺼내먹음

홍길동 : 음료수 No. 7채워넣음

김유신:음료수 No.7꺼내먹음

홍길동 : 음료수 No. 8채워넣음

김유신:음료수 No.8꺼내먹음

홍길동 : 음료수 No. 9채워넣음

김유신:음료수 No.9꺼내먹음



교착상태 (Dead Lock) : 오도가도 못하는 상태

교착상태 때는 강제종료를 해야한다.


7. 강제종료

1) stop()

2) interrupt()

3) 직접처리



무한 실행되는 클래스를 만들어보자



package prjThread;

class StopDemo implements Runnable{//Runnable인터페이스를 상속받는다.

    @Override

    public void run() { //Thread에 필수적인 run메소드를 오버라이드 한다.

        try {            //예외처리를 해준다.

            while(true) {

                System.out.println("Thread is alive...");

                Thread.sleep(500); //0.5초 간격으로 메시지가 나오게끔 한다.

            }

        }catch(InterruptedException err){

            

        }

        finally{

            System.out.println("Thread is dead...");

        }

    }

    

    

}

public class StopTest {

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        StopDemo demo = new StopDemo();

        Thread t = new Thread(demo);

        t.start();

    }

}


※ 결과값

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...


stop 메소드를 써서 멈춰보자.


package prjThread;

class StopDemo implements Runnable{//Runnable인터페이스를 상속받는다.

    @Override

    public void run() { //Thread에 필수적인 run메소드를 오버라이드 한다.

        try {            //예외처리를 해준다.

            while(true) {

                System.out.println("Thread is alive...");

                Thread.sleep(500); //0.5초 간격으로 메시지가 나오게끔 한다.

            }

        }catch(InterruptedException err){

            err.printStackTrace();

        }

        finally{

            System.out.println("Thread is dead...");

        }

    }

    

    

}

public class StopTest {

    public static void main(String[] args) throws InterruptedException {

        // TODO Auto-generated method stub

        StopDemo demo = new StopDemo();

        Thread t = new Thread(demo);

        t.start();

        

        Thread.sleep(3000);    //3초 후에

        t.stop();            //끝난다.

    }

}


※ 결과값

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is dead...



stop 메서드는 스래드를 끝낼 때 

여지를 주지 않기 때문에 문제가 있어 잘 쓰지 않는다.

또한 try~ catch 문에서 catch가 실행되지 않는다.

stop 메서드는 바로 꺼지기 때문에 예외처리를 할 수 없기 때문이다.



package prjThread;

class StopDemo2 implements Runnable{//Runnable인터페이스를 상속받는다.

    @Override

    public void run() { //Thread에 필수적인 run메소드를 오버라이드 한다.

        try {            //예외처리를 해준다.

            while(true) {

                System.out.println("Thread is alive...");

                Thread.sleep(500); //0.5초 간격으로 메시지가 나오게끔 한다.

            }

        }catch(InterruptedException err){

            err.printStackTrace();

        }

        finally{

            System.out.println("Thread is dead...");

        }

    }

    

    

}

public class StopTest2 {

    public static void main(String[] args) throws InterruptedException {

        // TODO Auto-generated method stub

        StopDemo2 demo = new StopDemo2();

        Thread t = new Thread(demo);

        t.start();

        

        Thread.sleep(3000);    //3초 후에

        t.interrupt();            //끝난다.

    }

}


※ 결과값

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

java.lang.InterruptedException: sleep interrupted

Thread is dead...

    at java.lang.Thread.sleep(Native Method)

    at prjThread.StopDemo2.run(StopTest2.java:10)

    at java.lang.Thread.run(Unknown Source)


결과값을 보면 catch 값으로 예외처리 된 오류메세지가 보인다.

이처럼 interrupt 메서드는 stop 메서드보다 안전하다.

개발자가 예외처리를 할 수 있기 때문이다.


사용자가 임의로 스레드를 멈추는 방법을 살펴보자.

직접 제어하는 방법이 가장 안전하다.


package prjThread;

class StopDemo3 implements Runnable{//Runnable인터페이스를 상속받는다.

    private boolean stopped = false;//처음 결과값을 false로 준다.

    

    void off() {

        stopped = true;

    }

    

    

    @Override

    public void run() {             //Thread에 필수적인 run메소드를 오버라이드 한다.

        try {                        //예외처리를 해준다.

            while(!stopped) {        // stopped가 true가 되면 끝나게 한다.

                System.out.println("Thread is alive...");

                Thread.sleep(500);  //0.5초 간격으로 메시지가 나오게끔 한다.

            }

        }catch(InterruptedException err){

            err.printStackTrace();

        }

        finally{

            System.out.println("Thread is dead...");

        }

    }

    

    

}

public class StopTest3 {

    public static void main(String[] args) throws InterruptedException {

        // TODO Auto-generated method stub

        StopDemo3 demo = new StopDemo3();

        Thread t = new Thread(demo);

        t.start();

        

        Thread.sleep(3000);    //3초 후에

        demo.off();          //이처럼 사용자가 임의로 스레드를 멈출 수 있다.

    }

}



※ 결과값

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is alive...

Thread is dead...





8. 종료시점을 정하는 방법

- 스레드가 끝나는 시점이 제 각각일 때 마무리가 애매해질 수 있다.

- 끝나는 시점을 동일하게 처리할 수 있는 방법이 필요하다.


1) isAlive()

- 스레드한테 살아있냐고 물어보고 다른 스레드가 살아있으면 끝날 때 까지 기다린다.

- 스레드가 끝나는 것을 사용자가 직접 처리해야하기 때문에 어렵다.


2) join()

- 다른 스레드가 안끝났다면 스레드가 동시에 끝날 때 까지 돕는다.

- 스레드가 끝나는 것을 자동으로 해준다. 


isAlive() 를 사용해보자.




package prjThread;

class FinishDemo extends Thread{//Thread를 상속받음

    FinishDemo(String name){    //생성자를 생성

        super(name);             //인스턴스의 인자에 적힌 이름을 이름을 부모 클래스에 넣음

    }

    

    @Override

    public void run() {                                    //run()은 시스템이 실행하는 메소드이다.

        System.out.println(getName() + "자식 스레드 시작"); //getName()을 이용해 부모생성자에 있는 이름을 가져옴.

        

        //자식스레드릥 행동 1~9까지

        int cnt = 0;

        do {

            try {

                sleep(500);    //번갈아 가변서 일 할 수 있도록 0.5초 자식스레드에 쉬는 시간을 준다.

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            cnt++;

            System.out.print(cnt);

        }while(cnt<10);

        

        System.out.println("\n자식 스레드 종료\n");

    }    

    

}

public class FinishTest {

    public static void main(String[] args) {

        

        System.out.println("메인 스레드 시작");

        

        FinishDemo demo1 = new FinishDemo("first");    //ThreadDemo2 demo1 인스턴스가 스레드가 됨.

        FinishDemo demo2 = new FinishDemo("second");    //ThreadDemo2 demo2 인스턴스가 스레드가 됨.

        

        

        demo1.start();                            //시스템에서 run()을 실행해달라고 요청.

        demo2.start();                            //시스템에서 run()을 실행해달라고 요청.

        

        //자식스레드와 구별된 행동 1~9개 점 찍기

        int cnt = 0;

        do {

            try {

                Thread.sleep(200); //번갈아 가변서 일 할 수 있도록 메인스레드에 0.2초 쉬는 시간을 준다.

                                   //메인은 스레드클래스이지만 스래드 클래스는 아니기 때문에 Thread를 상속받는다.

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            cnt ++;

            System.out.print(".");

        }while(cnt<10);

        

        System.out.println("\n메인 스레드 종료\n");

    }

}


※ 결과값

메인 스레드 시작

second자식 스레드 시작

first자식 스레드 시작

..11...22..33..44...55..66...77..88...99..1010

자식 스레드 종료

자식 스레드 종료

.

메인 스레드 종료


isAlive()는 죽었는지 살았는지 물어보기만 할 뿐 

처리를 하지 않아 개발자가 직접 조건을 넣어야한다.


.join() 메서드를 보자.




package prjThread;

class FinishDemo extends Thread{//Thread를 상속받음

    FinishDemo(String name){    //생성자를 생성

        super(name);             //인스턴스의 인자에 적힌 이름을 이름을 부모 클래스에 넣음

    }

    

    @Override

    public void run() {                                    //run()은 시스템이 실행하는 메소드이다.

        System.out.println(getName() + "자식 스레드 시작");//getName()을 이용해 부모생성자에 있는 이름을 가져옴.

        

        //자식스레드릥 행동 1~9까지

        int cnt = 0;

        do {

            try {

                sleep(500);    //번갈아 가변서 일 할 수 있도록 0.5초 자식스레드에 쉬는 시간을 준다.

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            cnt++;

            System.out.print(cnt);

        }while(cnt<10);

        

        System.out.println("\n자식 스레드 종료\n");

    }    

    

}


public class FinishTest {

    public static void main(String[] args) throws InterruptedException { //예외처리를 해준다.

        

        System.out.println("메인 스레드 시작");

        

        FinishDemo t1 = new FinishDemo("first");    //ThreadDemo2 demo1 인스턴스가 스레드가 됨.

        FinishDemo t2 = new FinishDemo("second");    //ThreadDemo2 demo2 인스턴스가 스레드가 됨.

        

        

        t1.start();                            //시스템에서 run()을 실행해달라고 요청.

        t2.start();                            //시스템에서 run()을 실행해달라고 요청.

        

        //자식스레드와 구별된 행동 1~9개 점 찍기

        int cnt = 0;

        do {

            try {

                Thread.sleep(200); //번갈아 가aus서 일 할 수 있도록 메인스레드에 0.2초 쉬는 시간을 준다.

                                   //메인은 스레드클래스이지만 스래드 클래스는 아니기 때문에 Thread를 상속받는다.

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            cnt ++;

            System.out.print(".");

            

        }while(cnt<10);

        //while(t1.isAlive() || t2.isAlive()); //.isAlive()로 메인스레드가 자식스레드가 끝날 때 까지 기다리게끔 한다.

        

        t1.join();

        t2.join();

        

        System.out.println("\n메인 스레드 종료\n");

    }

}


※ 결과값

메인 스레드 시작

second자식 스레드 시작

first자식 스레드 시작

..11..22...33..44.55667788991010

자식 스레드 종료

자식 스레드 종료

메인 스레드 종료



t1이 끝날 때 까지 메인메서드가 기다린다.

t2가 끝날 때 까지 메인메서드가 기다린다.

메인이 가장 마지막에 끝난다.

.join() 메서드가 알아서 이를 처리한다.

<이클립스에서 자바 파일 압축하기!>

이클립스에서 자바 파일 압축은 Export로 합니다!

1. 자바 프로젝트 폴더에서 오른쪽 클릭을 하고 Export를 누릅니다.

2. Runnable JAR file을 선택하고 NEXT를 누릅니다.



3. 압축하고 싶은 Class파일을 선택합니다.





4. 원하는 폴더를 선택하고 저장합니다.




5. Finish를 누릅니다.





'개발 > Java' 카테고리의 다른 글

[java] 윈도우 프로그래밍 Window Programming  (1) 2017.11.05
[java] 스레드 Thread  (0) 2017.11.02
[java] 입력과 출력 IO (Input Output)  (0) 2017.10.30
[java] 예외처리(Exception)  (0) 2017.10.30
[java] 제네릭 Generic  (0) 2017.10.28

IO 입력과 출력 (Input Output)


표준 IO

모니터와 키보드



IO (Input Output)  → NIO(New Input Output) 


- IO를 쉽게 쓸 수 있게 해줌

- 쉽게 쓸 수 있기 때문에 숨겨진 맥락이 있다.

- IO를 더 공부하고 싶으면 NIO 공부하면 좋다.


1. java.io.*

- 입출력은 java.io.에 모두 있다.

- java.lang에 있던 입출력은 java.io.패키지에서 가져온 것이다.


2. Stream

- 모든 입출력 구조는 Stream으로 이루어져있다.

- Stream은 시냇물이다. 시냇물의 특징은 단방향이고 순서대로 흘러간다.


1) 단방향



2) 원칙적으로 순차적

- 원칙적으로 순차적이지만 그렇지 않을 때도 있다.


3) 지연발생이 가능하다.


4) 어떤 장치를 사용하던간에 사용법은 동일하다.

- 이는 객체의 특징이기도 하다.



3. 자바에서 구현된 Steam객체


1) ByteStream

- 흘러들어오고 흘러나옴

- 1 바이트 씩 입출력을 하겠다.

- ByteStream이 컴퓨터가 이해할 수 있는 Stream이다.

- 사람이 쓰게에는 불편하다.


java.io에 부모이면서 추상클래스인

InputStream 과 OutputStream 두 가지 클래스가 있다.



추상클래스인지 알수 있는 이유는 abstract 때문이다.

추상클래스의 특징을 다시 살펴보자.



<추상 클래스>

    - 추상메서드를 1개 이상 가지고 있는 경우

    - abstract 키워드 사용

            abstract class 클래스명{

            }


    - 절대로 인스턴스를 생성할 수 없다.

     인스턴스가 없다 -> 실행할 수 없다. -> 직접일을 하지 않겠다.

     내가 가지고 있는 것을 자식에게 물려주는 용도로만 사용.

     자식을 위해 상속을 하는 의미로만 사용


     예)

     도형의 공통된 속성 A : 점, 선, 면적

     사각형 : A 상속

     원 : A 상속

     삼각형 : A 상속



InputStream

- 추상메서드이다.

- 대표메서드는 read이다.


OutputStream

- 추상메서드이다.

- 대표메서드는 write이다.



2) CharacterStream

    - 한 문자씩, 2바이트씩 입출력을 하겠다.

    - 사람이 쓰기에는 편하다.

    - CharacterStream써도 ByteStream으로 다시 바뀐다.

    - 실제 컴퓨터 안에서는 ByteStream만 존재한다.

    - CharacterStream은 개발자편의적인 일종의 포장지와 같다.

 


<개발자들 사이의 약속>
패키지 이름은 소문자로 한다.
클래스이름은 첫글자는 대문자로 한다.




<ByteStream알아보기>

read(byte[] b) 메소드
데이터를 읽을 때 byte로 읽는다.


예제 1)

package bitestream;
import java.io.IOException;
public class ByteTest1 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        byte data[] = new byte[10];
        
        System.out.println("10개의 문자 입력 : ");
        
        //입력은 예외처리를 반드시 해줘야한다.
        try {    //아래 출력문을 시도해보고
            System.in.read(data);
        } catch (IOException e) { //에러의 종류가 무엇인지 확인하고 잡겠다.
                                  // IOException 입출력 에러를 확인한다
            e.printStackTrace(); //어디에서 에러가 났는지 추적해주겠다.
        }
        
        System.out.println("입력된 값 : ");
        /*
        for(int i = 0; i<data.length; i++) {
            System.out.print((char)data[i]);
        }
        */
        
        //향상된 for문으로 써보기
        for(byte b: data) {
            System.out.println((char)b);
        }
    }
}

※ 결과값
10개의 문자 입력 :
sfasfasdfasdfafaf
입력된 값 :
sfasfasdfa



예제 2)


package bytestream;
import java.io.IOException;
public class ByteTest2 {
    public static void main(String[] args) throws IOException {
        //예외처리는 throws 로 한다.
        int input = System.in.read();
        
        //여기서 -1 은  키보드에서 ctrl + z를 누르면
        //종료되는  약속된 값이다. java뿐만 아니라 다른 언어에서도 쓰인다. (주로 윈도우에서 가능)
        while(input != -1) { // -1과 같으면 멈춘다.
                       
            System.out.print((char)input);
            input = System.in.read();
        }
    }
}

※ 결과값

sadfsadfasdfasdfadsf
sadfsadfasdfasdfadsf
adsfsadfafasdfasfsdaafds
adsfsadfafasdfasfsdaafds



이렇게 코드스타일을 바꿀 수도 있다.

package bytestream;
import java.io.IOException;
public class ByteTest2 {
    public static void main(String[] args) throws IOException {
        /*
        //예외처리는 throws 로 한다.
        int input = System.in.read();
        
        //여기서 -1 은  키보드에서 ctrl + z를 누르면
        //종료되는  약속된 값이다. java뿐만 아니라 다른 언어에서도 쓰인다. (주로 윈도우에서 가능)
        while(input != -1) { // -1과 같으면 멈춘다.
    
            System.out.print((char)input);
            input = System.in.read();
        */
        
        int input = 0;
        while(true) {
            input = System.in.read();
            if(input == -1) {
                break;
            }
            System.out.print((char)input);
        }
    }
}

※ 결과값
kljhgfdskjlhdfskl;sdfh
kljhgfdskjlhdfskl;sdfh
sdfgkjhgadkljlkdhj
sdfgkjhgadkljlkdhj
svkxjhkljdh;kasdfjh
svkxjhkljdh;kasdfjh


또 이렇게도 코드스타일을 바꿀 수 있다.

package bytestream;
import java.io.IOException;
public class ByteTest2 {
    public static void main(String[] args) throws IOException {
        /*
        //예외처리는 throws 로 한다.
        int input = System.in.read();
        
        //여기서 -1 은  키보드에서 ctrl + z를 누르면
        //종료되는  약속된 값이다. java뿐만 아니라 다른 언어에서도 쓰인다. (주로 윈도우에서 가능)
        while(input != -1) { // -1과 같으면 멈춘다.
    
            System.out.print((char)input);
            input = System.in.read();
        */
        /*
        int input = 0;
        while(true) {
            input = System.in.read();
            if(input == -1) {
                break;
            }
            System.out.print((char)input);
        }
        */
        
        
        int input=0;
        while((input = System.in.read()) != -1){
            System.out.print(((char)input));
        }
        
        
    }//main end
}//class end

※ 결과값
dafafdadgfafasdf
dafafdadgfafasdf
asfsadfsadfaf
asfsadfsadfaf
asdfasdfafadfafsafasfd
asdfasdfafadfafsafasfd

Java 입력장치의  가장 부모클래스는 InputStream이다.
InputStream은 추상클래스이며, 자식에게 참조하기 위해 있다.


다른 예제를 해보자


package bytestream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class ByteTest2 {
    //부모클래스이자 추상클래스인 InputStream이 참조변수 in을 받는다.
    static void StreamTest(InputStream in, OutputStream out) throws IOException {
        //예외처리는 throws 로 한다.
        int input = System.in.read();
        
        //여기서 -1 은  키보드에서 ctrl + z를 누르면
        //종료되는  약속된 값이다. java뿐만 아니라 다른 언어에서도 쓰인다. (주로 윈도우에서 가능)
        while(input != -1) { // -1과 같으면 멈춘다.
            //outputstrim에는 출력하기 위한 메서드로 print가 없고 write가 있다.
            //write메서드는 한글코드를 맞춰서 출력이 잘 된다.
            //print, println은 간이용 출력이고, 출력전문은 write메서드이다.
            out.write((char)input);
            System.out.print((char)input);
            input = System.in.read();
        }    
    
    }
    
    public static void main(String[] args) throws IOException {
        //InputStream에게 in의 주소를 받기 위한 참조변수를 준다.
        //in은 키보드 장치를 가리키는 참조변수이자 주소값이다.
        //out은 모니터 장치를 가리키는 참조변수이자 주소값이다.
        StreamTest(System.in, System.out);
        
        /*
        int input = 0;
        while(true) {
            input = System.in.read();
            if(input == -1) {
                break;
            }
            System.out.print((char)input);
        }
        
        
        int input=0;
        while((input = System.in.read()) != -1){
            System.out.print(((char)input));
        }
                */
        
    }//main end
}//class end

※ 결과값

ㄴㅁㅇㅁㄴㅇㅁ
ㄲ뇬¤ㄲ눙±ㄲ뉠·ㄲ눙±ㄲ뇬¤ㄲ뉠·ㄲ눙±
sdfdsafasdf
ssddffddssaaffaassddff


자바 IO 입출력의 특성상
파일로 출력해도 사용법은 똑같다.
파일로 입력받아 콘솔로 출력하는 예제를 해보자.

우선 test라는 파일을 만들고 위치를 적어보자.
나는 D:\\Dropbox\\workspaces\\MultiCampus\test.txt
에 만든 txt파일을 활용해보겠다.

package bytestream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
public class FileTest1 {
    public static void main(String[] args) throws IOException {
        // TODO 파일로부터 입력을 받아 콘솔로 출력
        //파일명의 위치를 적는다.
        //파일입력을 받는 인스턴스를 생성한다. 인자값에 입력받을 파일 이름을 넣는다.
        //보조기억장치에 있던 text/txt 파일을 로딩하여 메모리에 저장공간을 만든다.
   //test.txt 앞에 컴퓨터가 탭키 \t 로 인식하지 않도록 \를 하나 더 넣는다. 
        FileInputStream fin = new FileInputStream("D:\\Dropbox\\workspaces\\MultiCampus\\test.txt");
        
        int input = 0;
        while(input != -1) { //-1은 파일의 마지막을 뜻함
            input = fin.read();
                
            
            
            //print메서드는 아무런 준비없이 쓸 수 있다.
            //System.out.print((char)input);
            
            
            OutputStream out = System.out;
            //write 버퍼로 출력
            out.write((char)input);
            //아직 다 차지않은 버퍼를 방출해준다.
            out.flush();
        }
        
        //파일을 불러왔을 때 닫아주는 메서드이다.
        //가까운 시일내에 가비지 컬렉션에서 인스턴스가 정리된다.
        fin.close();
        
    }
    
}

※결과값


우후후후후후우후우후우후우후우후우후우후
ADADADADADADADADADADADADADADADADADADADAD?






키보드로부터 입력받아 파일로 출력받는 예제를 해보자.
참고로 입력은 파일이 없으면 에러가 나지만 출력은 파일이 없으면 새로 만들어준다.
test2.txt 파일을 새로 만들어서 해보자.

package bytestream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileTest2 {
    public static void main(String[] args) throws IOException {
        // TODO 키보드로부터 입력받아 파일로 출력
            
            //입력은 파일이 없으면 에러가 나지만 출력은 파일이 없으면 새로 만들어준다.
            //새로운 내용을 입력받아 기존 내용을 지울 때는 false
            //기존의 내용 뒤에 새로운 내용을 추가할 때는 true
            FileOutputStream fout =
                    new FileOutputStream("D:\\Dropbox\\workspaces\\MultiCampus\\test2.txt", true);
        
        int input = 0;
        while(input != -1) { //ctrl + z 는 실행 중지.
            input =System.in.read();
            
            if(input == -1)
                break;
            
            fout.write((char)input);
            fout.flush();    
        }
        fout.close();
    }
}

※ 결과값

gf,jndasflknasfdlknsdafk,lnsdafk,ln
lamdnlkdfn,lsfdnlksfdn
afdgsdfgsdfgsdfgsdfgsdfg
sfdgfsdgfdsgdsfgsdgffdsgs
sfdgsdfgsdfgsfgsfgsfg

D:\\Dropbox\\workspaces\\MultiCampus\\test2.txt

로 가면 이미 있는 파일 내용 뒤에 새로운 내용이 또 입력됨을 볼 수 있다.

test3.txt 파일을 새로 만들어서 아래 예제를 해보자.

package bytestream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileTest3 {
    public static void main(String[] args) throws IOException {
        FileOutputStream fout = new FileOutputStream("D:\\Dropbox\\workspaces\\MultiCampus\\test3.txt");
        
        for(int i=1; i<10; i++) {
            // \n은 줄바꿈이다.
            // \r linfeed로 첫번째 위치로 옮겨놓는 것이다.
            String data = i + "번째 줄입니다.\r\n";
            System.out.println(data);
            //문자열을 출력하려면 write는 bite로 쪼개서 넘겨야한다.
            //String 메서드 중 getByte()를 이용한다.
            fout.write(data.getBytes());
        }
        
    }
}

※ 결과값
1번째 줄입니다.
2번째 줄입니다.
3번째 줄입니다.
4번째 줄입니다.
5번째 줄입니다.
6번째 줄입니다.
7번째 줄입니다.
8번째 줄입니다.
9번째 줄입니다.


test3.txt 메모장에도 그대로 쓰인 것을 볼 수 있다.


<래퍼클래스와 필터클래스>
레퍼클래스는 비객체를 객체로 만들어 주는 클래스이다.
필터클래스는 객체를 더 확장 시켜서 더 많은 기능의 객체로 만들어준다.
필터클래스는 상속개념과 비슷하다. 실제 코드를 실시간으로 확장해서 쓰게 해준다.


java.io.FilterInputStream
java.io.DataInputStream

이 둘은 클래스의 기능을 바꾸어주는
필터클래스의 성향을 가진 클래스이다.







<ByteStream>

ByteStream은 Byte단위로 저장하기 때문에 
자식클래스들이 등장해서 도와준다.

package bytestream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataTest {
    public static void main(String[] args) throws IOException {
        // TODO DataInputStream, DataOUtputStream
        
        //DataInputStream, DataOUtputStream은 각각의 데이터타입의 맞게끔 기본데이터타입을 묶어서 처리해준다.
        FileOutputStream fout = new FileOutputStream("D:\\Dropbox\\workspaces\\MultiCampus\\test4.txt");
        
        //파일저장기능과 글자저장기능을 함께 쓴다.
        DataOutputStream dout = new DataOutputStream(fout);
        
        //글자를 저장해보자
        dout.writeChar('가');
        dout.writeInt(100);
        dout.writeDouble(3.14);
        dout.writeBoolean(true);
        
        dout.close();
        fout.close();
        //test4.txt 파일을 열어보면 컴퓨터가 알아들을 수 있는 모양으로 저장되어 있다.
        
        
        DataInputStream din =
            new DataInputStream(    
                new FileInputStream("D:\\Dropbox\\workspaces\\MultiCampus\\test4.txt"));
        
        //stream의 특성상 저장된 순서대로 호출해야한다.
        System.out.println(din.readChar());
        System.out.println(din.readInt());
        System.out.println(din.readDouble());
        System.out.println(din.readBoolean());
    }
}

※ 결과값

100
3.14
true

<RandomAccessFile>

IO의 특성상 순서대로 입출력이 되는데, 
특이하게 임의대로 입력할 수 있는 클래스가 있다.
바로 Class RandomAccessFile 클래스이다.
이 클래스는 java.lang.Object를 상속받아 저장된 데이터를 임의로 접근해서 가져온다.
메모리 주소값을 이용해 접근한다.




package bytestream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
    
    public static void main(String[] args) throws IOException {
        int data[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
        
        //다른 입출력 파일과는 다르게 RandomAccessFile로 저장 해야한다.
        //"r"은 읽기전용, "rw"은 읽기쓰기이다.
        RandomAccessFile raf =
            new RandomAccessFile("D:\\Dropbox\\workspaces\\MultiCampus\\test5.txt","rw");
        
        for(int i=0; i<data.length; i++) {
            raf.writeInt(data[i]);
        }
        
        //파일을 실행시키면 test5.txt가 원하는 위치에 컴퓨터가 보기쉬운 값으로 저장되어있다.
                
        //seek메서드는 원하는 위치를 찾아준다.
        //실제 인덱스값이 아니라 메모리에 있는 포인터의 주소값이다.
        //데이터가 정수형이라 4바이트임으로 바이트를 쪼개서 계산한다.
        raf.seek(0);
        System.out.println(raf.readInt());
        
        raf.seek(8);
        System.out.println(raf.readInt());
        
        //4바이트 포인트의 3번째 방 = 40
        //항상 메모리 주소값을 이용하여 접근한다.
        raf.seek(4*3);
        System.out.println(raf.readInt());
    }
}

※ 결과값
10
30
40



2. CharacterSteam

- 문자스트림은 실제하지 않는다.
- ByteStream을 편하게 하기 위한 일종의 포장지이다.
ByteStream에 비해 편하게 쓸 수 있지만 성능이 떨어진다.
- 이름끝에 Reader라고 쓰여있으면 문자스트림이다.

reader 메서드 : 읽는다.
writer 메서드 : 쓴다.

문자스트림의 약점을 보완하기 위해 사용하는 클래스가 BufferedReader 이다.


package bytestream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
public class FileTest1 {
    public static void main(String[] args) throws IOException {
        // TODO 파일로부터 입력을 받아 콘솔로 출력
        //파일명의 위치를 적는다.
        //파일입력을 받는 인스턴스를 생성한다. 인자값에 입력받을 파일 이름을 넣는다.
        //보조기억장치에 있던 text/txt 파일을 로딩하여 메모리에 저장공간을 만든다.
        FileInputStream fin = new FileInputStream("D:\\Dropbox\\workspaces\\MultiCampus\\test.txt");
        
        int input = 0;
        while(input != -1) { //-1은 파일의 마지막을 뜻함
            input = fin.read();
                
            
            
            //print메서드는 아무런 준비없이 쓸 수 있다.
            //System.out.print((char)input);
            
            
            OutputStream out = System.out;
            //write 버퍼로 출력
            out.write((char)input);
            //아직 다 차지않은 버퍼를 방출해준다.
            out.flush();
        }
        
        //파일을 불러왔을 때 닫아주는 메서드이다.
        //가까운 시일내에 가비지 컬렉션에서 인스턴스가 정리된다.
        fin.close();
        
    }
    
}

※ 결과값
ㅇㄴㄻㄴㅇㄻㄴㄹㅇ
ㅇㄴㄻㄴㅇㄻㄴㄹㅇ

package charstream;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileTest1 {
    public static void main(String[] args) throws IOException {
        // TODO 파일로부터 입력을 받아 콘솔로 출력
        
        //null은 주소값을 저장하고 있지 않다는 표시이다.
        //예외처리를 위해 변수를 밖으로 빼준다.
        FileReader fin = null;
        BufferedReader br = null;
        
        //파일명의 위치를 적는다.
        //파일입력을 받는 인스턴스를 생성한다. 인자값에 입력받을 파일 이름을 넣는다.
        //보조기억장치에 있던 text/txt 파일을 로딩하여 메모리에 저장공간을 만든다.
        try {
            br = new BufferedReader(
                new FileReader("D:\\Dropbox\\workspaces\\MultiCampus\\test.txt"));        
            
            String input = null;
            while((input=br.readLine()) != null) {
                //print로 해도 문자클래스가 깨지지 않는다.
                System.out.println(input);    
            }
        }
        catch(FileNotFoundException err) {
            
            //개발 중이라면 어디서 오류가 났는지 알도록 참조변수도 같이 출력한다.
            System.out.println("파일을 찾을 수 없다." + err);
        }
        catch(IOException err) {err.printStackTrace();}
        finally {
            try {br.close();}
            catch(Exception err) {}
        }
    }
}

※ 결과값
안녕 안녕 안녕 안녕 안녕 안녕 안녕 안녕
Hello Hello Hello Hello Hello Hello Hello
안녕 안녕 안녕 안녕 안녕 안녕 안녕 안녕
Hello Hello Hello Hello Hello Hello Hello


<IO에서 중요한 것>

Data Persistance 데이터 지속성

파일처리 : 데이터를 오랫동안 지속적으로 보관

DB = 파일을 안전하게 보관 할 수 있는 방법


<java 파일을 exe 실행파일 패키지로 만드는 방법>
JSmooth 프로그램을 이용하면 바로 만들 수 있다.

(구글링을 해보자!)


계속하여 charstream 이용하여 파일 입력 예제를 해보자.


package charstream;

import java.io.BufferedReader;

import java.io.FileWriter;

import java.io.IOException;

import java.io.InputStreamReader;

public class FileTest2 {

    public static void main(String[] args) throws IOException {

        // TODO 키보드로부터 입력받아 파일로 출력

            //입력은 파일이 없으면 에러가 나지만 출력은 파일이 없으면 새로 만들어준다.

            //새로운 내용을 입력받아 기존 내용을 지울 때는 false

            //기존의 내용 뒤에 새로운 내용을 추가할 때는 true

            FileWriter fout =

                    new FileWriter("D:\\Dropbox\\workspaces\\MultiCampus\\test2.txt", true);

            

            //바이트클래스를 문자클래스로 바꿔주는 필터클래스이다.

            //in(키보드입력)이라는 바이트스트림을 바꿔준다.

            InputStreamReader isr = new InputStreamReader(System.in);

            BufferedReader br = new BufferedReader(isr);

        

        String input = null;

        while(true) { //ctrl + z 는 실행 중지.

            input = br.readLine();

            

            if(input == null)

                break;

            

            fout.write(input);

            fout.flush();    

        }

        fout.close();

        isr.close();

        br.close();

    }

}



※ 아래 내용이 txt 파일에 입력된다.


ㅇㅀㅇㅎㄹㄴㅇㅀㄴㅇㅀ






package charstream;

import java.io.FileWriter;

import java.io.IOException;

public class FileTest3 {

    public static void main(String[] args) throws IOException {

        //파일로 저장하기 위한 문자 클래스이기 때문에 바꿔준다.

        FileWriter fout = new FileWriter("D:\\Dropbox\\workspaces\\MultiCampus\\test3.txt");

        

        

        for(int i=1; i<10; i++) {

            // \n은 줄바꿈이다.

            // \r linfeed로 첫번째 위치로 옮겨놓는 것이다.

            String data = i + "번째 줄입니다.\r\n";

            System.out.println(data);

            //문자열을 출력하려면 write는 bite로 쪼개서 넘겨야한다.

            //하지만 바이트 스트림이 아니기 때문에 .getBytes()을 쓸 필요가 없다.

            fout.write(data);

        }

        fout.close();

    }

}


※아래 내용이 txt 파일에 입력된다.

1번째 줄입니다.

2번째 줄입니다.

3번째 줄입니다.

4번째 줄입니다.

5번째 줄입니다.

6번째 줄입니다.

7번째 줄입니다.

8번째 줄입니다.

9번째 줄입니다.




3. PrintWriter


- Writer 문자스트림을 기반으로 출력을 좀 더 쉽게 하기 위한 클래스


PrintWriter는 println(줄바꿈) printf(포맷 : 형식을 지정한다.) 등의 다양한 기능을 지정한다.



package charstream;

import java.io.FileWriter;

import java.io.IOException;

import java.io.PrintWriter;

public class FileTest3 {

    public static void main(String[] args) throws IOException {

        //파일로 저장하기 위한 문자 클래스이기 때문에 바꿔준다.

        PrintWriter pw = new PrintWriter("D:\\Dropbox\\workspaces\\MultiCampus\\test3.txt");

        

        for(int i=1; i<10; i++) {

            // \n은 줄바꿈이다.

            // \r linfeed로 첫번째 위치로 옮겨놓는 것이다.

            String data = i + "번째 줄입니다.\r\n";

            System.out.println(data);

            //문자열을 출력하려면 write는 bite로 쪼개서 넘겨야한다.

            //하지만 바이트 스트림이 아니기 때문에 .getBytes()을 쓸 필요가 없다.

            //fout.write(data);

            pw.print(data);

            

            

        }

        //fout.close();

        pw.close();

        

    }        

}


※ 결과값

1번째 줄입니다.

2번째 줄입니다.

3번째 줄입니다.

4번째 줄입니다.

5번째 줄입니다.

6번째 줄입니다.

7번째 줄입니다.

8번째 줄입니다.

9번째 줄입니다.





<printf 메서드>

printf는 형식을 자유롭게 변경 할 수 있다.

printf의 첫번째 인자는 내가 원하는 데이터의 형식을 지정해준다.


pw.printf("%3s : %-5d  %5d %5.1f", "홍길동", 98, 67,(float)((98+67)/2));


%는 데이터를 표시될 곳이라는 위치를 나타내는 기호이다.

%다음에 나오는 숫자는 칸의 갯수, 자리를 예약했음을 의미한다.

숫자 다음에 나오는 영어 sstring 이다.

ddecimal 정수형이다.

f float이다.

%n은 줄바꿈을 하겠다는 뚯이다.



데이터는 순서대로 들어간다.

문자는 왼쪽부터, 숫자는 오른쪽부터 채워진다.

숫자를 왼쪽 부터 지정하고 싶으면 음수로 만들면 된다.


이런식으로 출력할 때 데이터 형식을 지정할 수 있다.

이와같은 형식은 파일이나 콘솔에 사용된다.



package charstream;

import java.io.BufferedWriter;

import java.io.FileWriter;

import java.io.IOException;

import java.io.PrintWriter;

public class FileTest4 {

    public static void main(String[] args) throws IOException {

        // TODO Auto-generated method stub

        //파일을 저장할 수 있도록 준비

        PrintWriter pw =

                new PrintWriter(

                    //성능을 개선하기 위한 목적으로 BufferedWriter로 한 번 더 포장

                    new BufferedWriter(

                    //자유로운 포맷(형식)변경을 위해 printf를 사용하기 위한 목적으로 PrintWriter로 한 번 더 포장    

                            new FileWriter("D:\\Dropbox\\workspaces\\MultiCampus\\sungjuk.txt")));

        

    pw.println("*******************************성적표************************************");    

    pw.println("------------------------------------------------------------------------");

    //printf는 형식을 자유롭게 변경 할 수 있다.

    //printf의 첫번째 인자는 내가 원하는 데이터의 형식을 지정해준다.

    //%는 데이터를 표시될 곳이라는 위치를 나타내는 기호이다.

    //%다음에 나오는 숫자는 칸의 갯수, 자리를 예약했음을 의미한다.

    //숫자 다음에 나오는 영어 s는 string 이다.

    //d는 decimal 정수형이다.

    //f는 float이다.

    //데이터는 순서대로 들어간다.

    //문자는 왼쪽부터, 숫자는 오른쪽부터 채워진다.

    //숫자를 왼쪽 부터 지정하고 싶으면 음수로 만들면 된다.

    //이런식으로 출력할 때 데이터 형식을 지정할 수 있다.

    //%n은 줄바꿈을 하겠다는 뚯이다.

    //이와같은 형식은 파일이나 콘솔에 사용된다.

    pw.printf("%3s : %-5d  %5d           %5.1f",

             "홍길동",  98,  67, (float)((98+67)/2));

    pw.printf("%3s : %-5d %5d %5.1f, %n", "임꺽정", 98, 67, (float)((98+67)/2));

    pw.printf("%3s : %-5d %5d %5.1f, %n", "신돌석", 98, 67, (float)((98+67)/2));

    pw.printf("%3s : %-5d %5d %5.1f %n", "유비", 98, 67, (float)((98+67)/2));

    //출력은 close(); 해야 버퍼가 마무리 한다.

    pw.close();

    }

}


※ 입력된 값

*******************************성적표************************************

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

홍길동 : 98        67            82.0임꺽정 : 98       67  82.0,

신돌석 : 98       67  82.0,

유비 : 98       67  82.0




위 코드는 아래와 같이 바꿀 수도 있다.


package charstream;

import java.io.BufferedWriter;

import java.io.FileWriter;

import java.io.IOException;

import java.io.PrintWriter;

public class FileTest4 {

    public static void main(String[] args) throws IOException {

        // TODO Auto-generated method stub


    //PrintWriter는 저장준비와 성능개선, 자유로운 포맷변경이 모두 포함되어 있다.

    PrintWriter pw = new PrintWriter("D:\\Dropbox\\workspaces\\MultiCampus\\sungjuk.txt");

        

    pw.println("*******************************성적표************************************");    

    pw.println("------------------------------------------------------------------------");

  

    pw.printf("%3s : %-5d  %5d           %5.1f",

             "홍길동",  98,  67, (float)((98+67)/2));

    //출력은 close(); 해야 버퍼가 마무리 한다.

    pw.printf("%3s : %-5d %5d %5.1f, %n", "임꺽정", 98, 67, (float)((98+67)/2));

    pw.printf("%3s : %-5d %5d %5.1f, %n", "신돌석", 98, 67, (float)((98+67)/2));

    pw.printf("%3s : %-5d %5d %5.1f %n", "유비", 98, 67, (float)((98+67)/2));

    pw.close();

    }

 }



※ 입력된 값

*******************************성적표************************************

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

홍길동 : 98        67            82.0임꺽정 : 98       67  82.0,

신돌석 : 98       67  82.0,

유비 : 98       67  82.0






4. Serializable (직렬화)


병렬 : 동시에 신호를 많이 보낼 경우 (예: 프린트)

직렬 : 신호를 적게 보낼 경우 (예 : 마우스)


직렬화(Serializable) : 직렬로 바꿔주는 상태



IO 에서의 직렬화는 무엇일까?

A장치가 B에게 복잡한 데이터를 보낼 때

복잡한 데이터를 단순화 시켜서 보내면

병렬로 보내는 것보다 안전하다.


이처럼, 


복잡한 데이터를 단순화 시켜서 보내는 작업을 직렬화라고 한다.


자바에서는 직렬화 기능이 시스템 내부에 있다.

직렬화를 할 때는 Serializable 이 붙어있는 인터페이스는 

시스템이 직렬화 과정을 거치도록 표시해준다.



예제를 살펴보자


package bytestreamtest;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInput;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

public class ObjectTest {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        Employee[] emp = new Employee[3];

        emp[0] = new Employee(1, "홍길동", "영업", 110, 1.4);

        emp[1] = new Employee(2, "임꺽정", "기술", 111, 1.5);

        emp[2] = new Employee(3, "신돌석", "개발", 112, 1.7);

        

        //System.out.println(emp[0]);

        

        //데이터를 묶은 객체단위로 파일에 저장하려면 어떻게 해야할까?

        //객체단위 저장은 objct의 writeObject(Object obj) 밖에 없다.

        //인스턴스를 만들어 메모리의 공간을 생성하고 emp.dat 파일을 만들어 연다.

        ObjectOutputStream oos =

        new ObjectOutputStream(new FileOutputStream("D:\\Dropbox\\workspaces\\MultiCampus\\emp.dat"));

        

        //emp.dat 파일에 배열의 정보를 쓴다.

        oos.writeObject(emp[0]);

        oos.writeObject(emp[1]);        

        oos.writeObject(emp[2]);

        

        //항상 파일을 불러왔으면 닫아줘야한다..

        oos.close();

        

        System.out.println("******사원정보*******");

        System.out.println("사번\t이름\t업무\t부서번호\t인사점수");

        System.out.println("-----------------------------------------");

        

        

        //인스턴스를 만들어 메모리의 공간을 생성하고 emp.dat 파일의 정보를 불러온다.

        ObjectInput ois =  

                new ObjectInputStream (new FileInputStream("D:\\\\Dropbox\\\\workspaces\\\\MultiCampus\\\\emp.dat"));

        

        //emp.dat 의 정보를 차례로 이클립스 내에서 볼 수 있게끔 프린트 해준다.

        for(int i=0; i<3; i++) {

            Employee e = (Employee)ois.readObject();

            System.out.println(e);

        }

        ois.close();

    }

}



※ 결과값

******사원정보*******

사번    이름    업무    부서번호    인사점수

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

1    홍길동    영업    110    1.4

2    임꺽정    기술    111    1.5

3    신돌석    개발    112    1.7





package FileTest;

import java.io.File;

import java.util.Date;

public class FileTest {

    public static void main(String[] args) {

        File f = new File("D:\\Dropbox\\workspaces\\MultiCampus\\emp.dat");

        

        if(f.exists()) {

            System.out.println("파일의 이름 : " + f.getName());

            System.out.println("상대경로 : " + f.getPath());

            System.out.println("절대경로 : " + f.getAbsolutePath());

            System.out.println("크기 : " + f.length() + "byte");

            //.lastModified는 현재날짜를 정수형으로 변환하기 때문에 Date메서드로 현재 날짜로 다시 변환한다.

            System.out.println("마지막 수정일자 : " + new Date(f.lastModified()));

        }else {

            System.out.println("파일이 존재하지 않는다.");

        }

        //파일을 삭제한다.

        f.delete();

    }

}


※ 결과값

파일의 이름 : emp.dat

상대경로 : D:\Dropbox\workspaces\MultiCampus\emp.dat

절대경로 : D:\Dropbox\workspaces\MultiCampus\emp.dat

크기 : 226byte

마지막 수정일자 : Wed Nov 01 13:35:50 KST 2017










'개발 > Java' 카테고리의 다른 글

[java] 스레드 Thread  (0) 2017.11.02
[java] 이클립스에서 자바 파일 압축하기!  (0) 2017.10.31
[java] 예외처리(Exception)  (0) 2017.10.30
[java] 제네릭 Generic  (0) 2017.10.28
[java] 컬렉션 Collection  (0) 2017.10.28

예외처리(Exception)


- C나 C++ 등에서는 java보다는 중요하게 생각하지 않지만,

- java에서는 예외처리를 하지 않으면 컴파일이 되지 않는다.


1. 예외처리란?

예외가 발생했을 때 예외에 대한 제어권을 시스템(JVM)이 아니라 개발자가 가질 수 있게 하는 방법


2. 왜 예외처리를 쓸까?

1) 예외가 발생했을 때 메시지에 대한 표현문제

2) 프로그램의 비정상적인 종료



아래 예제의 경우 처리를 시스템이 하기 때문에 문제가 생긴다.

에러의 정보는 별도의 인스턴스로 따로 보관되어 시스템이 처리한다.


에러가 발생하면 에러의 컨트롤 타워는 시스템이 된다.

개발자는 에러가 발생하면 시스템을 기다릴 수 밖에 없다.


예외처리를 하면 예외가 발생 했을 때 주도권을 시스템이 아니라

개발자가 원하는 방식으로 예외를 처리할 수 있도록 한다.


package prjExeption;

public class ExceptionTest1 {

    public static void main(String[] args) {

        // TODO 예외처리_1

        int [] arr = new int[3];

        

        System.out.println("첫번째 예외처리 테스트");

        

        

        //에러가 났을 경우 자바가상머신이 에러를 처리한다.

        //에러메시지가 내가 원하는 메시지가 아니라 프로그램이 원하는 방향이다.

        //에러가 나면 프로그램이 종료된다.

        arr[7] = 10; // 문법을 틀린 것을 아니지만 값이 배열의 범위를 벗어나서 에러

        

        //가상머신이 정보를 가져가서 메시지가 보이지 않는다.

        //이를 비정상적인 종료라고 한다.

        System.out.println("이 메시지가 보이는가?");

        

    }

}


※ 결과

첫번째 예외처리 테스트

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 7

    at prjExeption.ExceptionTest1.main(ExceptionTest1.java:15)


오류를 냈더니 자바에서 예외처리를 한 클래스가

java.lang.ArrayIndexOutOfBoundsException 이라고 알려준다.

이 정보를 활용하여 예외처리를 해보자.


package prjExeption;

public class ExceptionTest1 {

    public static void main(String[] args) {

        // TODO 예외처리_1

        int [] arr = new int[3];

        

        System.out.println("첫번째 예외처리 테스트");

        

//        arr[7] = 10;

        

        try {        

        arr[7] = 10; // 문법을 틀린 것을 아니지만 값이 배열의 범위를 벗어나서 에러

        }

        //예외가 나면 특정 인스턴스 변수에 저장되는데

        //예외를 가져오고 다른 인스턴스 변수에 저장할 수 있는 저장주소를 인자값에 넣어야한다.

        //에러 관련 클래스인 ArrayIndexOutOfBoundsException에 예외처리한 주소를 넣어준다.

        //java는 예외사항에 대한 클래스를 미리 만들어 놓아서 골라쓰면 된다.

        //예외처리할 클래스가 어떤 클래스인지는 에러를 내면 java에서 알려준다.

        catch(ArrayIndexOutOfBoundsException err) {    

            System.out.println("배열의 범위를 벗어났습니다.");

        }

        

        //가상머신이 정보를 가져가서 메시지가 보이지 않는다.

        //이를 비정상적인 종료라고 한다.

        System.out.println("이 메시지가 보이는가?");

        

    }

}


※ 결과값

첫번째 예외처리 테스트

배열의 범위를 벗어났습니다.

이 메시지가 보이는가?



JAVA API 문서를 들어가자

java.base -> java.lang 에서 예외처리 클래스를 찾아보자.



3. 예외처리는 어떻게 쓸까?


예외처리는 다섯 가지 문법만 알면된다.

이중에서 가장 핵심 키워드는 try/catch 문이다.

나머지는 필수 기능은 아니지만 좀 더 편리함을 제공한다.


1) try/catch block


try{            // 예외가 나는지 안나는지 감시, 모니터링을 시도한다.

      ...        // {} 안에서만 모니터링한다.

}               

catch(...){   //예외가 나면 중간에 system이 빼가지 못하도록 잡는다.

      ...

}


1-1 다중 try/catch 

예외가 발생할 만한 곳을 try~ catch  을 넣는다.

여러가지 예외처리를 위해 다중으로 catch를 넣는다.



package prjExeption;

public class ExceptionTest1 {

    public static void main(String[] args) {

        // TODO 예외처리_1

        int [] arr = new int[3];

        

        System.out.println("첫번째 예외처리 테스트");

        

//        arr[7] = 10;

        

        try {        

        //arr[7] = 10; // 문법을 틀린 것을 아니지만 값이 배열의 범위를 벗어나서 에러

        int i = 10/0;

        

        }

        

        //예외가 나면 특정 인스턴스 변수에 저장되는데

        //예외를 가져오고 다른 인스턴스 변수에 저장할 수 있는 저장주소를 인자값에 넣어야한다.

        //에러 관련 클래스인 ArrayIndexOutOfBoundsException에 예외처리한 주소를 넣어준다.

        //java는 예외사항에 대한 클래스를 미리 만들어 놓아서 골라쓰면 된다.

        //예외처리할 클래스가 어떤 클래스인지는 에러를 내면 java에서 알려준다.

        //가급적이면 위에서 구체적으로 예외를 잡을 수 있다.

        

        //참조변수가 가리킨 문자열로 출력을 해주면 된다.

        // 어떤 이유 때문에 에러가 발생했는지 쓴다.

        catch(ArrayIndexOutOfBoundsException err) {    

            //.toString은 생략이 가능하다.

            System.out.println("배열의 범위를 벗어났습니다." + err.toString());

        

        }

        //산술연산을 잘 못 했을 때 처리해주는 클래스

        catch(ArithmeticException err) {

            System.out.println("산술연산을 잘못했다.");

        }

        

        //밑으로 내려갈 수 록 더 넓은 범위를 잡을 수 있도록 부모 클래스를 지정한다.

        //가급적이면 구체적으로 해주면 좋다.

        catch(RuntimeException err) {

            System.out.println("실행시 오류 발생 : " + err);

        }

        //부모와 자식간의 참조관례로 지정

        catch(Exception err) {

            System.out.println("실행 예외 발생");

            

        }

        

        

        //가상머신이 정보를 가져가서 메시지가 보이지 않는다.

        //이를 비정상적인 종료라고 한다.

        System.out.println("이 메시지가 보이는가?");

        

    }

}


※결과값

첫번째 예외처리 테스트

산술연산을 잘못했다.

이 메시지가 보이는가?



2) throw

- 예외를 던진다. 일부로 에러를 발생시킨다.

- 내가 처리하지 않고 다른 메서드가 처리 할 수 있도록 만든다.

- 자신을 호출하기 위한 메소드에게 넘긴다.

- 예외처리를 한꺼번에 처리하기 위한 목적이다.


<특징>

- 블럭내부에서만 던질 수 있다. (try ~ catch가 아니더라도 메서드 내에서 사용가능하다.)

- 한 블럭에 단 한개만 던질 수 있다.


<일부러 에러를 발생시키는 이유>

test를 위해서 

   - 예외처리가 잘 실행되는지 Test를 해본다.

   - 예외처리의 주체, 위치를 바꾸기 위한 방법



package prjExeption;

public class ExceptionTest3 {

    public static void main(String[] args) {

        // TODO Throw의 간단한 예제

        try {

            System.out.println("여기는 try블럭 내부이다...");

            // 일부러 예외문을 발생시켜서 catch문이 동작할 수 있게 한다.

            //필수 키워드는 아니지만  원하는 곳에서 에러를 낼 수 있어 편하게 일 할 수 있다.

            throw new RuntimeException();

        }

        catch(RuntimeException err)    {

            System.out.println("잘 처리됨..." + err);

        }

        

        System.out.println("try/ catch가 끝나고 난 뒤...");

    }

}


※ 결과값


여기는 try블럭 내부이다...

잘 처리됨...java.lang.RuntimeException

try/ catch가 끝나고 난 뒤...



package prjExeption;

public class ExceptionTest3 {

    public static void main(String[] args) {

        // TODO Throw의 간단한 예제

        try {

            System.out.println("여기는 try블럭 내부이다...");

            // 일부러 예외문을 발생시켜서 catch문이 동작할 수 있게 한다.

            //필수 키워드는 아니지만  원하는 곳에서 에러를 낼 수 있어 편하게 일 할 수 있다.

            throw new RuntimeException();

        }

        catch(RuntimeException err)    {

            System.out.println("잘 처리됨..." + err);

            //main 을 호출하는 호출자에게 에러를 던진다.

            //내가 처리하지 않고 다른 매서드가 처리하게끔 에러를 던진다.

            //예외처리를 한꺼번에 처리하기 위한 목적이다.

            //throw err;

        }

        

        //System.out.println("try/ catch가 끝나고 난 뒤...");

    }

}


※ 결과값


여기는 try블럭 내부이다...

잘 처리됨...java.lang.RuntimeException


package prjExeption;

public class ExceptionTest3 {

    public static void main(String[] args) {

        // TODO Throw의 간단한 예제

        try {

            System.out.println("여기는 try블럭 내부이다...");

            // 일부러 예외문을 발생시켜서 catch문이 동작할 수 있게 한다.

            //필수 키워드는 아니지만  원하는 곳에서 에러를 낼 수 있어 편하게 일 할 수 있다.

            throw new RuntimeException("...상황에서 예외를 던짐");

        }

        catch(RuntimeException err)    {

            //.getMessege는 throw가 예외를 던질 때 인스턴스에 저장된 메시지를 가져온다.

            System.out.println("잘 처리됨..." + err.getMessage());

            //main 을 호출하는 호출자에게 에러를 던진다.

            //내가 처리하지 않고 다른 매서드가 처리하게끔 에러를 던진다.

            //예외처리를 한꺼번에 처리하기 위한 목적이다.

            //throw err;

        }

        

        System.out.println("try/ catch가 끝나고 난 뒤...");

    }

}


※ 결과값


여기는 try블럭 내부이다...

잘 처리됨......상황에서 예외를 던짐

try/ catch가 끝나고 난 뒤...




3) trows


- 예외를 던진다.

- 대신 예외처리를 부탁할 때 사용한다.

- 블럭외부 (메서드 외부)에서만 던질 수 있다.

- 여러개를 던질 수 있다.


- 강제성이 없다.

- throw와 예외를 던지는 이유가 다르다.

- 예외를 발생하는게 아니라 예외처리를 대신해달라고 자신을 호출한 메서드에게 부탁한다.

- 예외처리를 넘긴 후 부탁한 메서드가 처리를 못하면 그 다음으로 넘어간다.

- 아무도책임을 지지 않으면 가상머신에게 넘어간다. 


package prjExeption;

import java.io.IOException;

public class ExceptionTest4 {

    

    //second가 해야할 책임을 IOExceptiond으로 first에게 넘김

    //예외처리를 IOException, ArithmeticException 두개 처리함

    static void second() throws IOException, ArithmeticException{

        System.out.println("second 호출됨");

        

        System.out.print("입력:");

        //내부로 부터 입력을 받기 때문에 예외처리를 안해주면 에러가 생김

        char data = (char)System.in.read();    // 입력에러를 발생시키기 위해 씀. IOException으로 처리.

        

        int i = 10/0;    //산술에러를 발생시키기 위해 씀. ArithmeticException로 처리

    }

    

    //second가 해야할 책임을 IOExceptiond으로 main에게 넘김

    static void first() throws IOException, ArithmeticException {

        System.out.println("first 호출됨");

        //first에서 예외처리를 해야하기 때문에 try ~ catch로 처리

        second();

    }

    public static void main(String[] args) {

        // TODO Throws 예제

        //main이 예외처리를 해준다.

        try {

            first();

        }

        //클래스이름 두개를 넣기 싫으면 부모클래스를 넣어준다.

        //부모클래스로 넣어주면 자세한 내용이 나오지는 않는다.

        catch(Exception err) {

            

            System.out.println("main에서 다 처리함");

        }

        

    }

}



※ 결과값


first 호출됨

second 호출됨

입력:a

main에서 다 처리함


예외처리는 적절하게 쓰는 것이 중요하다.



package prjExeption;

import java.io.IOException;

public class ExceptionTest4 {

    

    //second가 해야할 책임을 IOExceptiond으로 first에게 넘김

    //예외처리를 IOException, ArithmeticException 두개 처리함

    static void second() throws IOException, ArithmeticException{

        System.out.println("second 호출됨");

        

        System.out.print("입력:");

        //내부로 부터 입력을 받기 때문에 예외처리를 안해주면 에러가 생김

        char data = (char)System.in.read();    // 입력에러를 발생시키기 위해 씀. IOException으로 처리.

        

        int i = 10/0;    //산술에러를 발생시키기 위해 씀. ArithmeticException로 처리

    }

    

    //second가 해야할 책임을 IOExceptiond으로 main에게 넘김

    static void first() throws IOException, ArithmeticException {

        System.out.println("first 호출됨");

        //first에서 예외처리를 해야하기 때문에 try ~ catch로 처리

        second();

    }

    public static void main(String[] args) {

        // TODO Throws 예제

        //main이 예외처리를 해준다.

        try {

            first();

        }

        //클래스이름 두개를 넣기 싫으면 부모클래스를 넣어준다.

        //부모클래스로 넣어주면 자세한 내용이 나오지는 않는다.

        catch(Exception err) {

            

            System.out.println("main에서 다 처리함");

            

            //프로그램의 순서를 파악하기 쉽게 정보를 뿌려준다.

            //어디서 에러가 났는지 추적하기에 좋다.

            err.printStackTrace();

            

        }

        

    }

}


※ 결과값


first 호출됨

second 호출됨

입력:a

main에서 다 처리함

java.lang.ArithmeticException: / by zero

    at prjExeption.ExceptionTest4.second(ExceptionTest4.java:16)

    at prjExeption.ExceptionTest4.first(ExceptionTest4.java:23)

    at prjExeption.ExceptionTest4.main(ExceptionTest4.java:31)






4) finally 블럭


- try/catch 와 함께 사용


try {

    ...

}

finally{

    ... //반드시 실행해야 하는 코드를 쓴다. 

}


* 반드시 실행해야만 하는 코드를 묶어줄 때 사용

* 네트워크를 연결했는데 닫아주거나, 데이터연결했는데 닫아주는 등 


package prjExeption;

import java.io.IOException;

public class ExceptionTest3 {

    

    //throws 는 예외처리를 대신 대할라고 자신을 호출한 메서드에게 부탁한다.

    public static void main(String[] args) throws IOException{

        // TODO Throw의 간단한 예제

        try {

            System.out.println("여기는 try블럭 내부이다...");

            // 일부러 예외문을 발생시켜서 catch문이 동작할 수 있게 한다.

            //필수 키워드는 아니지만  원하는 곳에서 에러를 낼 수 있어 편하게 일 할 수 있다.

            throw new RuntimeException("...상황에서 예외를 던짐");

        }

        catch(RuntimeException err)    {


        }

        finally {

            System.out.println("여기는 반드시 실행됨...");

        }

        

        

        System.out.println("try/ catch가 끝나고 난 뒤...");

    }

}


※ 결과값


여기는 try블럭 내부이다...

잘 처리됨......상황에서 예외를 던짐

여기는 반드시 실행됨...

try/ catch가 끝나고 난 뒤...


에러가 나거나 안나거나 반드시 실행된다.



package prjExeption;

import java.io.IOException;

public class ExceptionTest3 {

    

    //throws 는 예외처리를 대신 대할라고 자신을 호출한 메서드에게 부탁한다.

    public static void main(String[] args) throws IOException{

        // TODO Throw의 간단한 예제

        try {

            System.out.println("여기는 try블럭 내부이다...");

            // 일부러 예외문을 발생시켜서 catch문이 동작할 수 있게 한다.

            //필수 키워드는 아니지만  원하는 곳에서 에러를 낼 수 있어 편하게 일 할 수 있다.

            throw new RuntimeException("...상황에서 예외를 던짐");

        }

        catch(RuntimeException err)    {

            //.getMessege는 throw가 예외를 던질 때 인스턴스에 저장된 메시지를 가져온다.

            System.out.println("잘 처리됨..." + err.getMessage());

            

            //1. 리턴값 반환 2. 중간에 메서드 강제종료. 지금은 2번의 경우이다.

            return;

                        

        }

        //return을 해도 finally가 실행된다.

        finally {

            System.out.println("여기는 반드시 실행됨...");

        }

        

        

        //System.out.println("try/catch가 끝나고 난 뒤...");

    }

}


※ 결과값


여기는 try블럭 내부이다...

잘 처리됨......상황에서 예외를 던짐

여기는 반드시 실행됨...


return을 써도 그 무엇을 써도 finally는 반드시 실행이 된다.

하.지.만. finally보다 더 쎈 놈이 있다.


package prjExeption;

import java.io.IOException;

public class ExceptionTest3 {

    

    //throws 는 예외처리를 대신 대할라고 자신을 호출한 메서드에게 부탁한다.

    public static void main(String[] args) throws IOException{

        // TODO Throw의 간단한 예제

        try {

            System.out.println("여기는 try블럭 내부이다...");

            // 일부러 예외문을 발생시켜서 catch문이 동작할 수 있게 한다.

            //필수 키워드는 아니지만  원하는 곳에서 에러를 낼 수 있어 편하게 일 할 수 있다.

            throw new RuntimeException("...상황에서 예외를 던짐");

        }

        catch(RuntimeException err)    {

            //.getMessege는 throw가 예외를 던질 때 인스턴스에 저장된 메시지를 가져온다.

            System.out.println("잘 처리됨..." + err.getMessage());

            //인자값은 어떻게 컴퓨터가 종료되었는지를 개발자가 미리 정한 숫자로 보관하기 위해 쓰지만

            //따로 지정이 안되어 있으면 아무거나 써도 된다.

            //이를 사용하면 강제적으로 강하게 종료가 된다.

            //될 수 있으면 쓰면 안된다.

            System.exit(0);

                        

        }

        //System.exit(0);를 쓰면 finally가 실행되지 않는다.

        finally {

            System.out.println("여기는 반드시 실행됨...");

        }

        

        

        //System.out.println("try/catch가 끝나고 난 뒤...");

    }

}


※ 결과값

여기는 try블럭 내부이다...

잘 처리됨......상황에서 예외를 던짐


System.exit() 는 될 수 있으면 쓰지 말자.



4. 관련클래스


Throwable


Class Direct Known Subclasses:

Error, Exception


Error 

- 하드웨어에서 발생한 물리적인 예외를 말한다.

- 메모리, 컴퓨터 꺼짐 등등

- 하드웨어상 문제는 개발자가 신경 쓸 필요가 없다.

- Errors는 에러의 자식을 모아놓은 것이다. 개발자가 볼 필요가 별로 없다.


Exception

- 로직이나 코딩에서 발생한 예외를 말한다.

- 소프트웨어 상 발생한 에러

- 개발자가 신경써야 할 부분이다.

- Exceptions은 개발자가 신경써서 봐야할 예외이다.




자바 API를 살펴보면,

Throwable 클래스가 예외처리 클래스들의 부모이다.




<주요 메서드>


get messege();


printStackTrace()


toString() //Object라는 부모로 부터 오버라이딩함



클래스를 잘 살펴보면 어마 어마하게 상속받는다.


RuntimeException


- 프로그램을 실행해봐야 발생 할 수 있는 예외들이다.

- 예외처리를 해도되고 안해도 된다.

- 컴파일 하는데까지 지장은 받지 않는다,

- 예외처리를 강제로 하지 않아도 된다,

- 출력할 때는 상관이 없으나 입력을 받을 때는 매우 조심해야한다.



throws 


값을 입력 받을 때느 반드시 예외처리를 해야한다.




제네릭 Generic


- C++에서 아이디어를 가지고 온 문법

- C++에는 Template이라는 문법이 있다.

- 기능은 똑같지만 DataType별로 따로 만들어야 할 때가 있다.

   Datatype에 상관없이 Template을 이용하여 사용 할 수 있었다.

- java API에서 문서 제목에 <> 표시가 없는 것은 제네릭으로 쓸 수 없다.


1. 용도

1) 특정타입을(객체형)을 미리 검사

    - 실수 할 수 있는 데이터타입을  미리 방지한다.

    - 기본 데이터 타입을 쓸 수 없기 때문에 Wrapper 클래스를 쓴다. 예) 정수형은 Integer

2) C++의 Tempalate과 유사한 용도


2. 문법

1) Generic클래스로 만들때


class 클래스명<이름>{    

}

 

- 데이터 타입의 값을 비워두고 들어오는 데이터에 따라서 값을 결정한다.

- 값 대신에 이름을 임의로 지정하는데 개발자들은 c++ Template의 오마주로 T라고 주로 쓴다.


2) 사용 할 때

클래스명 변수명 = new 클래스명();                                                        //인스턴스 만드는 문법

클래스명<객체형 데이터타입> 변수명 = new 클래스명<객체형 데이터타입>(); //제네릭 인스턴스 만드는 문법




null 

- 현재 가리키고 있는 주소값이 없다. 

- 참조하고 있는 주소가 없다. 

- 인스턴스가 없다.


향상된 for문

배열이나 컬렉션만 쓸 수 있는 for문



for(변수 : ?){

}



데이터 개수만큼 하나씩 꺼내서 변수에 옮겨 담는다.

제네릭이나 컬렉션에서 데이터 타입이 달라서 

어렵다면 변수의 데이터타입을 Object로 한다.



package prjUtil;

import java.util.Vector;

public class GenericTest1 {

    public static void main(String[] args) {

        

   //Vector<String> v = new Vector()<String>;    

   // Java 7이상 버전에서만 앞에 제네릭을 선언했으면 뒤에는 생략가능하다.

   Vector<String> v = new Vector(); 


   //이 클래스를 String형식만 사용하겠다고 제네릭으로 선언하면 다른 형식을 찾아 검사해준다.

        v.add("hello");

        v.add("world");

        v.add("홍길동");

        // v.add(100); 다른 형식을 제네릭이 찾아 검사해준다.

        

        /*

        String str = null;                     //null : 현재 가리키고 있는 주소값이 없다. 인스턴스가 없다.

        for(int i=0; i<v.size(); i++) {

            str = (String)v.get(i);            //Object형 어떤 값이든 꺼내올 수 있다. 자식의 값으로 캐스팅 해줘야한다.

            System.out.println(str);         //스트링으로 출력하기 때문에

        }

        */

        

        for(String str : v) {                   //향상된 for문을 쓸 수 있다. (취향차이)

            System.out.println(str);

        }

        

    }

}


※ 결과값

hello

world

홍길동



제네릭은 데이터 타입의 값을 비워두고 들어오는 데이터에 따라서 값을 결정할 수 있다

'개발 > Java' 카테고리의 다른 글

[java] 입력과 출력 IO (Input Output)  (0) 2017.10.30
[java] 예외처리(Exception)  (0) 2017.10.30
[java] 컬렉션 Collection  (0) 2017.10.28
[java] java.util 패키지를 알아보자.  (0) 2017.10.27
[java] 인터페이스(InterFace)  (0) 2017.10.26


Collection


지금까지 배운 변수와 배열 클래스의 단점을 살펴보자.


변수

- 하나밖에 처리 못한다.


배열

1. 여러개를 처리할 수 있으나 데이터 타입이 정해진 것만 써야한다. -> 클래스로 해결가능

2. 크기가 정해져 있다. -> 연결리스트 알고리즘으로 해결가능

3. 삽입 삭제가 불가능하다. -> 연결리스트 알고리즘으로 해결가능

   (배열은 데이터를 저장 할 때 좋다.)


클래스

- 다른 데이터 타입으로 묶을 수 있다.

(다른 배열의 단점을 해결하지 못한다.)



배열의 모든 단점을 깔끔하게 해결 할 수는 없을까?


컬렉션 (Collection)

배열의 모든 단점을 해결

- 컬렉션 = 클래스 + 알고리즘


그럼 항상 컬렉션을 쓰면 되지 않을까?


그렇지 않다.


배열을 쓸 수 있다면 배열을 쓰는 것이 가장 빠르다.


java.util. 에 컬렉션이 모여있다.


클래스를 잘 알고 싶으면 부모를 공부해라

컬렉션 클래스를 알고 싶으면 부모인 컬렉션 인터페이스를 공부하라


대표적인 컬렉션 클래스를 살펴보자.


1. set 인터페이스

- 자주 꺼내쓰지 않는 경우


1) 저장용도

2) 중복제거

3) 정렬 순서가 없다.

  - 임의로 데이터가 저장된다.

4) 대표적인 클래스

  - HashSet, LinkedHashSet, TreeSet ...


2. List 인터페이스

- 자주 꺼내써야 하는 경우


1) 출력용도

   - 꺼내서 쓰는 용도

2) 중복저장

3) 정렬 순서 있다.

4) 대표적인 클래스

   - ArrayList, Vector, LinkedList


먼저, Set 을 알아보자.


<TreeSet>

SortedSet - TreeSet

SortedSet 라는 부모클래스를 상속받는 자식클래스이다.

set인터페이스 종류 중에서는 유일하하게 정렬기능이 있다.

저장하기에는 좋지만 꺼내서 쓰기는 어렵다.


<참고>

- 같은 형제클래스라도 주소는 남남이다.

- 상속은 부모자식간에만 된다.


package prjUtil;

import java.util.HashSet;

import java.util.TreeSet;

public class CollectionTest1 {

    public static void main(String[] args) {

        // TODO set계열의 클래스들

        //set은 정렬 순서와 상관없이 마구잡이로 나오기 때문에 출력이 어렵다.

        

        //HashSet 클래스를 쓰면 인스턴스를 만들어 놓으면 메모리가 허용하는 범위까지 크기를 늘린다.

        HashSet set = new HashSet();

        

        //add로 저장한다.

        set.add("carrie");

        set.add("kabbin");

        set.add("kairo");

        set.add("kairo");

        set.add("kariss");

        

        //.size 데이터의 개수를 확인

        //데이터를 꺼내서 사용하기가 어렵다.

        System.out.println("데이터의 개수 : " + set.size()); // 중복은 제외하고 저장

        //현재가 객체가 가르키는 값을 문자열로 출력

        System.out.println(set.toString());

        //자바의 모든객체는.toString이 있기 때문에 생략가능하다.

        System.out.println(set);

        

        

        TreeSet tree = new TreeSet();

        tree.add("juliet");

        tree.add("terry");

        tree.add("kabbin");

        tree.add("terry");

        tree.add("carrie");

        

        System.out.println("데이터 개수 :" + tree.size());

        //알파벳 기준으로 정렬하여 저장

        //저장하기에는 좋지만 꺼내서 쓰기는 어렵다.

        System.out.println(tree);

    }

}


※ 결과값

데이터의 개수 : 4

[kabbin, kairo, carrie, kariss]

[kabbin, kairo, carrie, kariss]

데이터 개수 :4

[carrie, juliet, kabbin, terry]


여기서 데이터를 꺼내오려면 어떻게 해야할까?


package prjUtil;

import java.util.HashSet;

import java.util.Iterator;

import java.util.TreeSet;

public class CollectionTest1 {

    public static void main(String[] args) {

        // TODO set계열의 클래스들

        //set은 정렬 순서와 상관없이 마구잡이로 나오기 때문에 출력이 어렵다.

        

        //HashSet 클래스를 쓰면 인스턴스를 만들어 놓으면 메모리가 허용하는 범위까지 크기를 늘린다.

        HashSet set = new HashSet();

        

        set.add("carrie");

        set.add("kabbin");

        set.add("kairo");

        set.add("kairo");

        set.add("kariss");

        

        //.size 데이터의 개수를 확인

        //데이터를 꺼내서 사용하기가 어렵다.

        System.out.println("데이터의 개수 : " + set.size()); // 중복은 제외하고 저장

        //현재가 객체가 가르키는 값을 문자열로 출력

        System.out.println(set.toString());

        //자바의 모든객체는.toString이 있기 때문에 생략가능하다.

        System.out.println(set);

        

        

        TreeSet tree = new TreeSet();

        tree.add("juliet");

        tree.add("terry");

        tree.add("kabbin");

        tree.add("terry");

        tree.add("carrie");

        

        System.out.println("데이터 개수 :" + tree.size());

        //알파벳 기준으로 정렬하여 저장

        //저장하기에는 좋지만 꺼내서 쓰기는 어렵다.

        System.out.println(tree);

        

        //set에서는 데이터를 어떻게 꺼내올까?

        //set은 한꺼번에 일괄적으로 데이터를 꺼내와야해서 불편하다.

        //그러므로 데이터를 순서대로 꺼내올 수 있도록 열거형으로 만들어 줄을 세운다.

        //.iterator()메소드는 데이터를 줄세우는 메소드이다.

        Iterator it = tree.iterator();

        while(it.hasNext()){

            System.out.println(it.next());

        }

        

        

    }

}


※ 결과값

데이터의 개수 : 4

[kabbin, kairo, carrie, kariss]

[kabbin, kairo, carrie, kariss]

데이터 개수 :4

[carrie, juliet, kabbin, terry]

carrie

juliet

kabbin

terry


여기서 데이터는 주소값에 저장된다.


<Arraylist>


package prjUtil;

import java.util.ArrayList;

public class CollectionTest2 {

    public static void main(String[] args) {

        // TODO List계열의 클래스

        ArrayList list = new ArrayList();

        list.add("carrie");

        list.add("kairo");

        list.add("kabbin");

        list.add("kairo");

        list.add("terry");

        

        //중복된 데이터를 걸러내지 못한다.

        System.out.println("데이터 개수 : " + list.size());

        //입력순서대로 정렬한다.

        System.out.println(list);

        

        for(int i =0; i<list.size(); i++) {

            //.get 인스턴스로 부터 실제 데이터를 꺼내오는 메서드

            //문자면 문자, 숫자면 숫자로 원래있던 데이터 타입을 꺼내옴

            System.out.println(list.get(i));

            

    

        }

        

    }

}


※ 결과값

데이터 개수 : 5

[carrie, kairo, kabbin, kairo, terry]

carrie

kairo

kabbin

kairo

terry


컬렉션에서는 검색기능을 간단하게 처리 할 수 있다.


package prjUtil;

import java.util.ArrayList;

public class CollectionTest2 {

    public static void main(String[] args) {

        // TODO List계열의 클래스

        ArrayList list = new ArrayList();

        

        list.add("carrie");  //.add로 값을 저장한다. 어떤 값이든 저장 할 수 있지만 꺼낼 때를 생각해야한다.

        list.add("kairo");

        list.add("kabbin");

        list.add("kairo");

        list.add("terry");

        

        

        System.out.println("데이터 개수 : " + list.size()); //중복된 데이터를 걸러내지 못한다.

        System.out.println(list);                                //입력순서대로 정렬한다.

        

        for(int i =0; i<list.size(); i++) {

                                                         //.get 인스턴스로 부터 실제 데이터를 꺼내오는 메서드

            System.out.println(list.get(i));        //문자면 문자, 숫자면 숫자로 원래있던 데이터 타입을 꺼내옴

        }

                                                         //검색 할 때 반복문을 안써도 된다.

        if(list.contains("kairo")) {                   //kairo면 "찾았다." 아니면 "못찾았다."

            System.out.println("찾았다.");

            System.out.println(list.indexOf("kairo")+"번째있다."); //.indexOf 찾고자하는 문자열에 위치를 알려준다.

        }else {

            System.out.println("못찾았다.");

        }

        

        list.add(2, 100);                      //배열과 다르게 임의의 위치에 위치지정하고 값을 추가 할 수 있다.

        System.out.println(list);

                                                  //위치지정하고 값을 삭제 할 수 있다.

        list.remove(3);                        //.removeall() 이나 .clear()를 쓰면 모든 값을 지울 수 있다.  

        System.out.println(list);

        

        list.removeAll(list);

        System.out.println(list);

        

    }

}


※ 결과값

데이터 개수 : 5

[carrie, kairo, kabbin, kairo, terry]

carrie

kairo

kabbin

kairo

terry

찾았다.

1번째있다.

[carrie, kairo, 100, kabbin, kairo, terry]

[carrie, kairo, 100, kairo, terry]

[]




3. Map

- 검색에는 최고

- Collection과는 다르게 Map 인터페이스를 을 상속한다.

- 두 개를 묶어서 한 쌍으로 저장한다.


1) 검색용도

2) 두개의 데이터를 한쌍으로 저장 (key, value)

3) HashMap, HashTable...



package prjUtil;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Set;

public class CollectionTest3 {

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        

        HashMap map = new HashMap();   //HashMap map을 사용한다.

        map.put("key1", "홍길동");             //put이라는 메서드를 사용해서 값을 입력

        map.put("key2", "임꺽정");

        map.put("key3", "유비");

        map.put("key4", "관우");

        map.put("key5", "장비");

        

        System.out.println("데이터 개수 : " + map.size()); //map의 개수를 알아본다.

        System.out.println(map.get("key"));

                                                       //.iterator()메소드는 데이터를 줄세우는 메소드이다.

        Set set = map.keySet();                 //순차적으로 값이 나올려면 set 계열의 메소드를 써야한다.

        Iterator it = set.iterator();               //set의 iterator() 메소드를 호출하여 줄을 세우고

        while(it.hasNext()) {                       //hasNext 그 다음 것을 가지고 있는지 물어본다.(있는지 없는지 검사)

            String key = (String)it.next();       //it.next() 줄을 세우고 나서 값을 불러온다.

            System.out.println(map.get(key));  //실제 데이터를 가지고 있는 것은 map이기 때문에 map을 쓴다.

                                                        //값을 key에다가 저장시키고 뽑아온다.

                                                        //.next() : 먼저 현재있는 데이터를 가져오고 다음 것을 꺼내온다.

        }

    

    }

}


※ 결과값

데이터 개수 : 5

null

홍길동

임꺽정

장비

유비

관우




'개발 > Java' 카테고리의 다른 글

[java] 예외처리(Exception)  (0) 2017.10.30
[java] 제네릭 Generic  (0) 2017.10.28
[java] java.util 패키지를 알아보자.  (0) 2017.10.27
[java] 인터페이스(InterFace)  (0) 2017.10.26
[java] 패키지 package  (0) 2017.10.25

java.util 패키지를 알아보자.



시간과 날짜 클래스

date

- 자바 초창기

- 단순히 시간과 날짜를 사용 할 때

calender

- 최근에 나온 보완되어 나온 클래스

- 그 외 시간과 날짜를 이야기 할 때

- 주로 많이 쓴다.


참고로 Java API에서 Deprecated 가 나온다면 될 수 있으면 쓰지말라는 뜻이다.

date클래스는 오래되었고 date클래스를 대체할 새로운 기능이 많이 나왔기 때문에 

문서를 읽다보면 Deprecated 가 많이 나오는 것을 볼 수 있다.


package prjUtil;

import java.util.Calendar;

import java.util.Date;

public class DateCalenderTest {

    public static void main(String[] args) {

        //Date();는 하나만이 아니라 여러개를 만들 수 있어서 불편하다.

        Date date = new Date();

        

        //new Date() 현재 시간을 보여줘라

        //인스턴스생성인데 어떻게 날짜와 시간을 보여줄까?

        //.toString이 생략되어있다.

        System.out.println(new Date());

        //java에 있는 모든 객체는 object 객체에 소속된 .toString이 달려있다.

        //.toString은 현재 객체에 있는 값을 문자열로 만들어준다.

        System.out.println(new Date().toString());

        

        //원래 값은 무엇이 나올까

        DateCalenderTest test = new DateCalenderTest();

        System.out.println(test.toString());

        //현지 시간설정에 맞게 설정할 수 있는 메서드

        System.out.println(new Date().toLocaleString());

        

        //Calender는 .getInstance() 메서드를 만들어야지만 사용가능하다.

        //내가 원하는 날짜와 시간 형식을 만들 수 있다.

        //싱글턴 패턴이기 때문에 절대로 두개 이상의 인스턴스를 만들지 않는다.

        Calendar cal = Calendar.getInstance();

        System.out.println(" 현재 날짜와 시간은 " +

                cal.get(Calendar.YEAR)+" 년 "+

                (cal.get(Calendar.MONTH)+1)+" 월 "+

                cal.get(Calendar.DATE)+" 일 "+

                cal.get(Calendar.HOUR)+" 시입니다. ");

        

    }

    @Override

    public String toString() {

        return "내가 임의로 만든 문자열";

    }

    

}


※ 결과값

Thu Oct 26 16:44:00 KST 2017

Thu Oct 26 16:44:00 KST 2017

내가 임의로 만든 문자열

2017. 10. 26 오후 4:44:00

현재 날짜와 시간은 2017 년 10 월 26 일 4 시입니다.



언어는 운영체제가 가지고 있는 기능을 끌어다 쓸 수 있도록 하는 것임을 유념하자.


Random 클래스를 써보자


package prjUtil;

import java.util.Random;

public class RandomTest {

    public static void main(String[] args) {

        // TODO 난수 처리

        Random r = new Random();

        

        

        

        //System.out.println("임의의 수 : " + r.nextInt());

        //System.out.println("임의의 수 : " + r.nextInt(5));

        //System.out.println("임의의 수 : " + (r.nextInt(5)+1));

        

        //내가 원하는 범위를 잡을 때 공식 = (최대값-최소값+1)+최소값

        System.out.println(r.nextInt((5-1+1)+1));

        

        //51~72사이의 임의의 값

        System.out.println(r.nextInt((71-52+1)+52));

        

        //7~13

        System.out.println(r.nextInt((7-13+1)+7));

        

        for(int i=0; i<5; i++) {

            System.out.println(r.nextInt(71-52+1)+52);

        }

    }

    

}


/*

* 1. 가위 바위 보 게임 만들어보기

* 가위 : 1, 바위 : 2, 보 : 3

* 입력 : 3

* 결과 : 승리(또는 패배) 2전 3승

*

* 2. 로또 추출기

* - 로또 추출기로 로또 사보기

*

*/



StringTokenizer 메서드를 알아보자.


문자열 단위로 분리해주는 클래스

StringTokenizer() 클래스 : 복잡한 문자열 구분 처리

split() 메서드 : 간단한 문자열 구분 처리


.trim()은 좌우의 공백을 없애주는 String클래스의 메소드이다.


StringTokenizer() 클래스는 열거형(Enumeration)인스턴스를 만들어준다.


열거형(Enumeration)이란?

index로 접근할 수 없다.

데이터를 다루기 쉽게 순서대로 접근 한 것이다.

순서대로 줄을 세워놓고 순서대로 꺼낸다.

순서대로 처리할 때는 배열보다 빠르다.

Enum이라고 줄여서 이야기한다.


package prjUtil;

import java.util.StringTokenizer;

public class StringTokenizerTest {

    public static void main(String[] args) {

        // TODO StringTokenizer() 클래스 : 복잡한 처리, split() 메서드 : 간단한 처리

        //split()으로 문자열을 단순하게 구분해본다.

        String data = "홍길동, 임꺽정, 신돌석, 강감찬";

        //복잡하게 되어있는 문자열을 StringTokenizer()로 구분한다.

        String data2 = "홍길동+ 임꺽정* 신돌석? 권율~강감찬";

        

        //split 배열로 구분하기

        //하나의 문자열을 콤마을 기준으로 스플릿이라는 메서드를 통해 4개의 문자열로 구분하겠다.

        String[] names = data.split(",");

        for(int i=0; i<names.length; i++) {

            //.trim()은 좌우의 공백을 없애주는 String클래스의 메소드이다.

            System.out.println(names[i].trim());

        }

        

        /*

        //기본생성자가 없어서 빨간줄이 나온다.

        //API문서를 찾아보면 사용하는 방법이 나온다. 2번째 방법을 쓴다.

        //StringTokenizer에서 생성되는 인스턴스는 열거형이다.

        StringTokenizer token = new StringTokenizer(data, ",");

        //token. 분리된 토큰의 개수를 알려준다.

        System.out.println(token.countTokens());

        */

        //구분자가 한가지가 아니더라도 여러개의 구분자를 지정할 수 있다.

        StringTokenizer token = new StringTokenizer(data2, "+*?~");

        //token. 분리된 토큰의 개수를 알려준다.

        System.out.println(token.countTokens());

        

        

        /*

        //순서대로 데이터를 써내올 수 있다.

        System.out.println(token.nextToken());

        System.out.println(token.nextToken());

        System.out.println(token.nextToken());

        System.out.println(token.nextToken());        

        */

        

        //.hasMoreTokens() 계속 데이터를 꺼내주다가 없으면 끝난다.

        while(token.hasMoreTokens()) {

            System.out.println(token.nextToken().trim());

        }

        

        String data3 = "JavaTM 언어사양 제2판:James Gosling,"

                + "Bill Join, Gilad Brach:무라카미 마사키:"

                + "피어슨 에듀케이션:2000:5500";

        

    

        

    }

}


crrentTimeMillis 메서드


시간차이 구하기 : System.crrentTimeMillis

CurrentTime는 System class에 있는 메소드이다.(java.lang 패키지에 있다.)

시간을 1000/1까지 측정할 수 있다.

System 클래스에 있는 nanoTime() 메서드는 1000/1보다 더 정말 한시간 측정이 가능하다.



package prjUtil;

public class CurrentTimeTest {

    public static void main(String[] args) throws InterruptedException {

        // TODO 시간차이 구하기 : System.crrentTimeMillis

        //CurrentTime는 System class에 있는 메소드이다.(java.lang 패키지에 있다.)

        //시간을 1000/1까지 측정할 수 있다.

        //System 클래스에 있는 nanoTime() 메서드는 1000/1보다 더 정말 한시간 측정이 가능하다.

        

        long start = System.currentTimeMillis();

        

        int sum = 0;

        for(int i=0; i<1000000000; i++) {

            sum = sum + i;

        }

        

        //이 시점에서 2초동안 멈추겠다.

        //걸린시간이 2초 + 처리한 시간이 나온다.

        Thread.sleep(2000);

        

        long end = System.currentTimeMillis();

        

        //1000분의 1초가 나온다.

        System.out.println("걸린시간:" + (end-start));

        

        //초단위까지만 보겠다. 이외의 정밀한 시간이 날라간다.

        System.out.println("걸린시간:" + ((end-start)/1000));

        

    }

}


※ 결과값

걸린시간:2380

걸린시간:2



DecimalFormat class 정리


숫자의 모양 형식을 원하는 모양으로 꾸며준다.


Wrapper 클래스

비객체와 객체는 캐스팅을 할 수 없다.

비객체와 객체가 서로 캐스팅이 필요할 때는 어떻게 해야할까?

이때는 java.lang의 Wrapper 클래스의 도움을 받는다.

모든 wrapper class는 java.lang 패키지에 있다.


Wrapper 클래스는 객체가 아닌 비객체로 객체로 포장해서 객체처럼 쓸 수 있게 해준다.        

Java에서 유일하게 객체가 아닌 비객체는 기본 Data Type 8개 밖에 없다.

각 데이터타입별 Wrapper클래스에 있다. Wrapper클래스는 비객체 데이터타입을 객체로 만들어준다.

Wrapper클래스의 이름은 각 데이터 타입에서 따왔다. 첫 글자는 무조건 대문자이다.


예)Double, Inteser ... 


Wrapper클래스의 자세한 설명은 아래를 참조하자.

http://hyeonstorage.tistory.com/168



package prjUtil;

import java.text.DecimalFormat;

public class DecimalFormatTest {

    public static void main(String[] args) {

        // TODO java.text.DecimalFormat

        // 숫자의 모양 형식을 원하는 모양으로 꾸며준다.

        

        double d1=2.523, d2=3.123;

        double result = d1 +d2;

        System.out.println(result);

        

        DecimalFormat df = new DecimalFormat("#.####");

        //.format 이라는 메서드가 result 값을 필터링

        //모든 값을 String으로 돌려줌

        String strResult = df.format(result);

        System.out.println(strResult);

        

        //여기서 계산을 하려면 어떻게 해야할까?

        //그렇다면 실수형이 되야 하는데 String이라서 어렵다.

        //비객체와 객체는 캐스팅을 할 수 없다.

        //이때는 java.lang의 Wrapper 클래스의 도움을 받는다.

        //pars 데이터타입 은 각 데이터타입별 Wrapper클래스에 있다..

        double d3 = Double.parseDouble(strResult);

        System.out.println(d3+d2+d1);

        

    }

}





★ 야구게임을 만들어보자! ★


package prjUtil;

import java.util.Random;

import java.util.Scanner;

/*

* 규칙

* 1. 임의의 숫자 3개 준비(컴퓨터)

*       - 중복이 없어야 한다.

*       - 단자리 숫자 (1~9)

* 2. 맞출 때 까지 게임진행

* ---------------------

*

* 과제

* 1. 모듈화

* 2. ball카운트 비교조건문을 반복문으로 바꿔라

* 3. 시도 횟수

* 4. 걸린 시간

* 5. 순위

* 6. 레벨조정 (숫자 하나씩 추가)

* 7. 점수

*       

*/

public class BaseBallGame {

    public static void main(String[] args) {

        // TODO 숫자야구게임

        

        

        //1.컴퓨터의 값 입력

        int com[] = new int[3];            // 3자리 숫자 배열 클래스 인스턴스 생성

        Random r = new Random();        // 랜덤으로 숫자 생성 클래스 인스턴스 생성

        

        for(int i=0; i<com.length; i++) {    //com 배열의 길이만큼 반복문을 돈다.

            com[i] = r.nextInt(9)+1;        //com 배열에서 1부터 9까지 랜덤숫자를 생성

            

            

            if(i == 1) {    //두번째 숫자가 저장되었을 떄 중복된다면 처음으로

                if(com[i] == com[i-1]) {    //현재입력된 숫자와 처음입력된 숫자를 비교한다.

                    i--;                    //현재 숫자와 처음 입력된 숫자가 같다면                     

                }                            //i는 0으로 돌아가 다시 반복문을 돈다.

            }

            if(i == 2) {    //세번째 숫자가 저장되었을 때

                if(com[i] == com[i-1] || com[i] == com[i-2]) {

                        i--;

                }//세번째 숫자와 첫번째 숫자, 두번째 숫자와 첫번째 숫자를 비교하여 중복된다면 다시.

                

            }

            

        }    

        System.out.println(com[0] + "," + com[1] + "," + com[2]);    


// if문을 for문으로 할 수도 있습니다.

//        if(i!=0) {

//        for(int j=0; j<i; j++) {

//            if(com[i]==com[j]) {

//                i--;

//                break;

//            }

//        }

//    }

//    

//}

//System.out.println(com[0] + "," + com[1] + "," + com[2]);

        

        //2.유저의 값 입력

        int user[] = new int[3];    // 유저 클래스 인스턴스 생성

        Scanner scan = new Scanner(System.in);    //스캐너를 입력해서 받음

        int strike = 0, ball = 0;                //스트라잌과 볼 변수 받음

        int inputNum = 0;                        //

        

        for(;;) {        // 무한반복을 한다.

            strike = 0; // 변수를 0으로 초기화 해준다.

            ball = 0;    // 변수를 0으로 초기화 해준다.

            

            System.out.println("숫자 입력 :");

            inputNum = scan.nextInt(); //입력받은 값을 user의 0번 방, 1번방, 2번 방에 따로 입력

            //처음 3자를 숫자가 들어올 때 100단위, 10단위, 1단위를 나누어서 저장

            

            user[0] = inputNum/100;         // 100을 나누어 1째 자리 수 비교

            user[1] = (inputNum%100)/10;    // 100의 나머지에 10을 나누어 2번째 자리 수 가져감

            user[2] = (inputNum%100)%10;    // 100의 나머지와 10의 나머지인 1을 가져감

            

            //System.out.println(user[0] + "," + user[1] + "," + user[2]);

        

            for(int i=0; i<3; i++) {

                if(com[i] == user[i]) {    //위치에 값을 비교

                    //==은 문자열일 때만 주소를 비교하고, 숫자일 때는 숫자를 비교한다.

                    strike++;

                }

            }

        

            // 컴퓨터가 생각한 숫자와 사용자가 생각한 숫자가

            // 위치가 다르지만 같다면 ball이 한개 올라간다.

            if(com[0]==user[1] || com[0]==user[2]) {

                ball++;

            }

            if(com[1]==user[0] || com[1]==user[2]) {

                ball++;

            }

            if(com[2]==user[0] || com[2]==user[1]) {

                ball++;

            }

            if(strike == 3) {

                System.out.println("축하합니다.");

                break;

            }

            //아웃임과 동시에 입력한 숫자가 무엇인지 알 수 있도록 보여준다.

            else if(strike==0 && ball==0){

                System.out.println("아웃입니다." +

                    user[0] + "," + user[1] + "," + user[2]);

            }

            else {

                System.out.println(strike+"스트라이크"+ball+

                    "볼 : " + user[0] + ","+ user[1] + "," + user[2]);

                

            }

            

        }

        

    }

}



※ 결과값


4,1,8
숫자 입력 :
234
0스트라이크1볼 : 2,3,4
숫자 입력 :
467
1스트라이크0볼 : 4,6,7
숫자 입력 :
418
축하합니다.


'개발 > Java' 카테고리의 다른 글

[java] 제네릭 Generic  (0) 2017.10.28
[java] 컬렉션 Collection  (0) 2017.10.28
[java] 인터페이스(InterFace)  (0) 2017.10.26
[java] 패키지 package  (0) 2017.10.25
[java] 클래스 (Class) part.3 : 상속 (Inheritance )  (0) 2017.10.24

인터페이스(InterFace)


1. 클래스를 만들기 위한 설계도 

- 클래스는 설계도이다. 인터페이스는 설계도(클래스)를 만들기 위한 설계도이다.

- 클래스보다 상위 개념이며 더 추상적이다.



2. 표준화를 위한 약속(규칙)

- 서로 다른 하드웨어가 연결될 때 연결되는 지점을 인터페이스라고 한다.

- 인터페이스는 표준화된 규격을 말한다.

- 인터페이스란 표준화된 약속이고 규칙이다.

- 문법이나 특징이 클래스와 같다.


3. 순수(완전) 추상클래스

- 100퍼센트 추상메서드만 가지고 있다.


<추상클래스>

- 추상메서드를 하나이상 가지고 있다.

- 인스턴스를 하나 이상 가지고 있다.

- 모든 것을 자신에게 상속하는 용도로만 쓰겠다.


4. 다중 상속 지원

- 클래스는 단일 상속만 지원하지만 인터페이스는 다중상속을 지원한다.


<인터페이스의 특징 3가지>

- 인터페이스 안에있는 변수는 기본적으로 static이 생략되어 있다.

- 인터페이스 안에있는 모든 변수는 final 상수이다.

- 인터페이스는 public이 포함되어 있다.


<인터페이스는 왜 다중상속을 해야하는가?>

- 일반상속 : 덩어리로 있으면 필요 없는 것도 물려줘야한다.

- 다중상속 : 필요한 것만 하나씩 상속 받아올 수 있다.


인터페이스는 추상클래스로만 이루어져 있기 때문에 다중상속을 할 수 있다.



ctrl + shift +o 

- import 추가하는 단축키


import 패키지명.*;

- 패키지 안에 있는 모든 클래스를 가져오라는 의미



extends (확장) 과 implements (구현)의 쓰임

extends (확장) 

- 서로 같은 것을 상속받을 때 사용한다.

- 원래있던 기능에서 덧붙힌다.


implements (구현) 

- 서로 다른 것을 상속 받을 때

- 클래스가 인터페이스로 부터 상속받을 때

- 원래 없던 것에서 하나를 더한다.


인터페이스는 클래스에게 상속을 해주는 것이다.


//패키지 안에 있는 모든 클래스를 가져오라는 의미

import Inter.*;

//인터페이스 안에있는 변수는 기본적으로 static이 생략되어 있다.

//Inter3를 상속받았기 때문에 Inter1, Inter2, Inter3의 변수를 모두 쓸 수 있다.

public class InterfaceTest implements Inter3 {

    

    public void inter1Method() {

        

    }

    

    public static void main(String[] args) {

        // TODO 인터페이스 문법 테스트

        System.out.println("inter1 : " + Inter1.a);

        

        //Inter1.a = 100; public static final

        

        System.out.println("inter1 : " + a);

        //상속을 받지 않을 때는 Inter2.b로 써야한다.

        System.out.println("inter2 : " + Inter2.b);

        //상속을 받았기 때문에 b만 쓴다.

        System.out.println("inter2 : " + b );

        System.out.println("inter3 : " + c);

    }

}



package Inter;

public interface Inter1 {

    int a = 10; //public static final

    

    //public이 생략이 되어 있다.

    void inter1Method();

       

}


package Inter;

public interface Inter2 {

    //상속받은 int a가 보이지 않지만 있다.

    int b = 20;

    

}


package Inter;

//인터페이스는 다중상속이 가능하다.

public interface Inter3 extends Inter1, Inter2{

    //상속받은 int a, b가 보이지 않지만 있다.

    int c = 30;

    

}


※ 결과값

inter1 : 10

inter1 : 10

inter2 : 20

inter2 : 20

inter3 : 30





'개발 > Java' 카테고리의 다른 글

[java] 컬렉션 Collection  (0) 2017.10.28
[java] java.util 패키지를 알아보자.  (0) 2017.10.27
[java] 패키지 package  (0) 2017.10.25
[java] 클래스 (Class) part.3 : 상속 (Inheritance )  (0) 2017.10.24
[java] 클래스 (Class) part.2  (0) 2017.10.24

패키지 package


- 꾸러미, 묶음


클래스도 묶음이다. 그렇다면 무엇을 묶어주는가?


1. 묶음 : 클래스

- 클래스를 묶어주는 것이 패키지이다.

- 클래스의 묶음은 다양한 기능을 쓸 수 있지만 패키지는 그냥 묶음이다.


2. 효과

 1) 사용의 편의

 2) 이름 충돌 방지



어떤 이가 대형 출판사에 전산실에 취업을 했다. 
도서관리 프로그램을 개발하려고 했다.
특정 기능을 개발해 달라고 협력사에 요청했다.
협력사 개발자가 개발을 한다고 생각해보자.

이 부분은 이클립스로 하지 말고 윈도우라면 직접 cmd 창을 열어 도스에서 확인해보자.

workspace에 패키지 폴더를 만들어 주고 그 안에 코딩 후 컴파일 해보자.




<예제>

class Book{
    private String title;
    private String author;
    private int year;
    
    
    Book(String title, String author, int year){
        this.title = title;
        this.author = author;
        this.year = year;
        }
    void display(){
        System.out.println("책제목:" + title);
        System.out.println("작가:" + author);
        System.out.println("출판년도:" + year);
    }

}



컴파일은 했지만 테스트를 위한 메인클래스가 필요하다.


class Book{

private String title;

private String author;

private int year;

Book(String title, String author, int year){

this.title = title;

this.author = author;

this.year = year;

}


void display(){

System.out.println("책제목:" + title);

System.out.println("작가:" + author);

System.out.println("출판년도:" + year);

}


public static void main(String[] args){

Book[] books = new Book[4];

//연도는 임의대로

books[0] = new Book("어린왕자", "생떽쥐베리",1900);

books[1] = new Book("홍길동전", "허균",1800);

books[2] = new Book("동의보감", "허준",1850);

books[3] = new Book("난중일기", "이순신",1870);

for(int i=0; i<books.length; i++){

books[i].display();

}

}

}





소스를 만들고 나서 완성되면 패키지로 묶어두어야한다.

자바에서는 소스를 패키지로 묶어두는 것이 예의이다.

클래스 안에서 패키지 선언을 해주면 된다.


package 패키지이름;



//폴더를 패키지로 인정해줘야한다.

package BookPack;

class Book{

    private String title;

    private String author;

    private int year;

    

    

    Book(String title, String author, int year){

        this.title = title;

        this.author = author;

        this.year = year;

        }

    void display(){

        System.out.println("책제목:" + title);

        System.out.println("작가:" + author);

        System.out.println("출판년도:" + year);

    }

    public static void main(String[] args){

        Book[] books = new Book[4];

        //연도는 임의대로

        books[0] = new Book("어린왕자", "생떽쥐베리",1900);

        books[1] = new Book("홍길동전", "허균",1800);

        books[2] = new Book("동의보감", "허준",1850);

        books[3] = new Book("난중일기", "이순신",1870);

    

        for(int i=0; i<books.length; i++){

                books[i].display();

        }

    }

}



하지만 실행이 안된다.


왜 그럴까?


<패키지의 특성>

1.패키지를 실행할 때에는 반드시 패키지 직속 상위폴더에서 실행해야한다.

2.패키지는 반드시 패키지이름과 클래스이름을 같이 명시해야한다.


//폴더를 패키지로 인정해줘야한다.

package BookPack;

class Book{

    private String title;

    private String author;

    private int year;

    

    

    Book(String title, String author, int year){

        this.title = title;

        this.author = author;

        this.year = year;

        }

    void display(){

        System.out.println("책제목:" + title);

        System.out.println("작가:" + author);

        System.out.println("출판년도:" + year);

    }

    public static void main(String[] args){

        Book[] books = new Book[4];

        //연도는 임의대로

        books[0] = new Book("어린왕자", "생떽쥐베리",1900);

        books[1] = new Book("홍길동전", "허균",1800);

        books[2] = new Book("동의보감", "허준",1850);

        books[3] = new Book("난중일기", "이순신",1870);

    

        for(int i=0; i<books.length; i++){

                books[i].display();

        }

    }

}




이렇게 프로그램을 만들어서 Test한 

main파일을 제외하고 패키지 채로 출판사로 넘겨주었다.

출판사에서는 협력사에서 만든 프로그램을 사용하기로 했다.

그래서 따로 BookTest라는 자바 파일을 만들었다.





다른 패키지에서 코드를 받아올 경우

패키지 내의 클래스를 쓸 수 있도록 public을 선언해줘야하고,

값을 받아오고자 하는 클래스 파일과 패키지 명을 함께 명시해준다.


BookTest.java 파일

// 값을 받아오고자 하는 클래스 파일과 패키지 명을 함께 명시

public class BookTest{

    public static void main(String[] args){

        //패키지 이름도 함께 명시

        BookPack.Book[] books = new BookPack.Book[4];

        //연도는 임의대로

        books[0] = new BookPack.Book("어린왕자", "생떽쥐베리",1900);

        books[1] = new BookPack.Book("홍길동전", "허균",1800);

        books[2] = new BookPack.Book("동의보감", "허준",1850);

        books[3] = new BookPack.Book("난중일기", "이순신",1870);

    

        for(int i=0; i<books.length; i++){

                books[i].display();

        }

    }

}



BookPack 패키지의 안의 Book.java 파일

//폴더를 패키지로 인정해줘야한다.

package BookPack;

//클래스마다 public 선언

public class Book{

    private String title;

    private String author;

    private int year;

    

    //클래스마다 public 선언

    public Book(String title, String author, int year){

        this.title = title;

        this.author = author;

        this.year = year;

        }

    //클래스마다 public 선언

    public void display(){

        System.out.println("책제목:" + title);

        System.out.println("작가:" + author);

        System.out.println("출판년도:" + year);

    }

}


그런데 패키지 이름을 하나하나 달기에는 너무나 불편하다.


이 때 import를 쓰면 패키지 이름을 생략 할 수 있다.



//import를 쓰면 패키지 이름을 생략 할 수 있다.

import BookPack.Book;

public class BookTest{

    public static void main(String[] args){

        

        Book[] books = new Book[4];

        //연도는 임의대로

        books[0] = new Book("어린왕자", "생떽쥐베리",1900);

        books[1] = new Book("홍길동전", "허균",1800);

        books[2] = new Book("동의보감", "허준",1850);

        books[3] = new Book("난중일기", "이순신",1870);

    

        for(int i=0; i<books.length; i++){

                books[i].display();

        }

        //java.lang은 기본 core 핵심 패키지이기 때문에 생략할 수 있다.

        //java.lang 이외에 다른 것은 생략 할 수 없다.

        java.lang.System.out.println("...");

    }

}


//폴더를 패키지로 인정해줘야한다.

package BookPack;

public class Book{

    private String title;

    private String author;

    private int year;

    

    

    public Book(String title, String author, int year){

        this.title = title;

        this.author = author;

        this.year = year;

        }

    public void display(){

        System.out.println("책제목:" + title);

        System.out.println("작가:" + author);

        System.out.println("출판년도:" + year);

    }

}




참고로 System.out.println(); 은 원래

java.lang.System.out.println(); dmfh Tjdigksmsep

java.lang은 기본 core 핵심 패키지이기 때문에 생략할 수 있다.

java.lang 이외에 다른 것은 생략 할 수 없다.



만약 BookTest를 따로 다른 폴더에 옮겨 실행한다면 어떨까?





실행해보면 실행이 안된다.

어떻게 해야할까?

이 때 환경변수를 설정한다.


패키지를 모아 놓은 것을 라이브러리라고 한다.

이렇게 위치를 바꿀 때마다 다시 위치설정을 해야한다면

라이브러리를 사용할 때 너무 불편할 것이다.


Path

- 실행파일을 어디서나 경로와 상관없이 실행할 수 있도록 설정


ClassPath

- Class를 어디서나 경로와 상관없이 실행할 수 있도록 설정

여기서 .은 현재위치 ; 은 연결



classpath 라는 환경변수를 설정하고

.; + 내가 쓰고자 하는 클래스의 상위폴더

를 쓴다.


 



그리고 실행을 해본다.



★ 압축파일 jar


jar라는 프로그램은 압축프로그램이다. jar로 압축을 하면 java에서 쉽게 쓸 수 있기 때문에 편하다.

jar 압축파일을 자바가상머신이 알아서 압축을 풀어주기 때문에 압축을 풀 필요가 없다.

jar라는 파일을 어디에서나 실행할 수 있는 이유는 java를 설치할 때 환경변수를 설치했기 때문이다.

java에 있는 jar 프로그램을 확인해보고 dos에서 실행해보자.





jar --를 치면 jar의 도움말과 옵션을 확인할 수 있다.


참고로 모든 프로그램은 압축까지 해야 마무리가 된다.


jar cvf 옵션을 찾아보자.

압축을 할 때 쓰는 옵션은 3가지 이다.

c : 압축파일을 실행해주는 옵션

v: 정보들을 보여주는 옵션

f : 내가 원하는 이름으로 압축 할 수 있음

jar로 압축을 하면 java에서 쉽게 쓸 수 있기 때문에 편하다.


압축할 때에는 이 세가지 옵션을 많이 쓴다.

압축을 풀 때에는 xvf 옵션을 쓴다.

하지만 압축을 푸는 것은 다른 프로그램으로 해도 괜찮다.


도스에서 압축을 해보자.


jar cvf bookpack.jar BookPack


BookPack이라는 이름의 폴더를 압축하겠다.



여기서 확장자 .jar은 바꾸어도 상관없지만 .jar로 쓰는 것을 추천한다.


압축한 bookpack을 환경변수 설정해보자.



이제 멀리 떨어진 BookTest파일을 실행해보자.




실행이 된다.


여기서 환경변수 설정을 수정하면 역시


실행이 안된다.



만든 BookPack 패키지 압축을 풀면 못 보던 폴더가 나오는데 jar가 압축을 위해 만든 파일이다.




또 다른 패키지를 만들어 보자.


//패키지가 길어지면 길어질 수록 매우 복잡하다.

package first.second.third.fourth.fifth;

class PackageTest{

    public static void main(String[] args){

        System.out.println("패키지 테스트");

    

    }

}


이런 경우 패키지가 길어지면 길어질 수록 패키지 폴더를 하나씩 직접 만들어야 해서 너무 귀찮다.

이런경우 어떻게 패키지를 만들어야 할까?


이럴 때는 실행하고자 하는 파일에서 도스창을 불러온 뒤


javac -d . PackageTest.java


라고 쓰면 된다.

여기서 -d 는 실행하고자 하는 폴더를 찾아주기도 하지만 패키지 폴더를 만들어주기도 하는 명령어이다.

. 은 현재위치를 말한 것이다.


이제 패키지를 배웠으니 다시 접근제어명시자를 살펴보자.


Protected

Protected는 밖에서는 클래스를 보호하면서 안에서는 쉽게 쓸 수 있도록 상속도 해준다.




//폴더를 패키지로 인정해줘야한다.

package BookPack;

public class Book{

    //public 외부로부터 접근가능

    public String title;

    //protected로 바꾸면 자식클래스에게 상속받으면서 외부 침입을 지킬 수 있다.

    protected String author;

    protected int year;

    

    //기본생성자는 항상 만들어줘라

    public Book(){}

    public Book(String title, String author, int year){

        this.title = title;

        this.author = author;

        this.year = year;

        }

    public void display(){

        System.out.println("책제목:" + title);

        System.out.println("작가:" + author);

        System.out.println("출판년도:" + year);

    }

}



import BookPack.Book;

class BookExt extends Book{

    private String pubName;

    

    public BookExt(String t, String a, int y, String p){

        

        title = t;

        author = a;

        year = y;

        pubName = p;

        /*

        //내가 저장할 능력이 없으므로 부모 생성자를 호출한다.

        super(t, a, y);

        pubName = p;

        */

        

    }

    public void display(){

        super.display();

        System.out.println("출판사명:"+pubName);

        System.out.println();

    }    

}


//import를 쓰면 패키지 이름을 생략 할 수 있다.

import BookPack.Book;

public class BookTest{

    public static void main(String[] args){

        

        BookExt[] books = new BookExt[4];

        //연도는 임의대로

        books[0] = new BookExt("어린왕자", "생떽쥐베리",1900, "영진");

        books[1] = new BookExt("홍길동전", "허균",1800, "정보문화사");

        books[2] = new BookExt("동의보감", "허준",1850, "홍익");

        books[3] = new BookExt("난중일기", "이순신",1870, "제이펍");

    

        for(int i=0; i<books.length; i++){

                books[i].display();

        }

        //java.lang은 기본 core 핵심 패키지이기 때문에 생략할 수 있다.

        //java.lang 이외에 다른 것은 생략 할 수 없다.

        System.out.println("...");

        

        books[0].title = "늙은왕자";

        books[0].display();

        

        books[0].author = "생쥐";

    }

}




★javaAPI 꼭 공부해야하는 패키지


java.base


1.java.lang : 기본 패키지 ★

2.java.util : 유용한 기능 ★



java.IO : 입출력


java.~ : 자바 초창기부터 있던 패키지

javax.~ : 나중에 추가된 패키지


https://docs.oracle.com/javase/9/docs/api/index.html?overview-summary.html



JAVA패키지를 출력할 때 두 가지 주의 할 점!

1. 패키지는 상위 폴더에서, 실행파일이 있는 곳에서 실행한다.

- 주로 bin 폴더이다.


2. 패키지 이름+클래스이름 을 함께 쓴다. 

예) java bitestream.ByteTest1



'개발 > Java' 카테고리의 다른 글

[java] java.util 패키지를 알아보자.  (0) 2017.10.27
[java] 인터페이스(InterFace)  (0) 2017.10.26
[java] 클래스 (Class) part.3 : 상속 (Inheritance )  (0) 2017.10.24
[java] 클래스 (Class) part.2  (0) 2017.10.24
[java] 배열 (Array)  (0) 2017.10.19

Class part.3 (Inheritance 상속)


객체지향 중에서 가장 복잡하고 새로운 기능이 많다.

상속은 소스 없이 기존의 프로그램을 그대로 가져다가 내가 원하는 기능만 추가할 수 있다.


<상황>

A회사에서 B회사에게 전체 프로그램 중에 일부 기능 프로그램을 외주제작 해달라고 맡겼다.

B회사에서는 프로그램을 만들어 주었지만 기존에 만든 기능 중에 

다른 기능을 더 추가 할 일이 생겼다. 어떻게 해야할까?



package prjClass3;

public class Cms {

    int no;

    String name;

    char level;

    

    //기본생성자 추가

    public Cms() {

        

    }

    //생성자 생성

    public Cms(int no, String name, char level) {

        super();

        this.no = no;

        this.name = name;

        this.level = level;

    }

    

    public void display() {

        System.out.println("고객번호 : " + no);

        System.out.println("고객이름 : " + name);

        System.out.println("고객이름 : " + level);

    }

}




package prjClass3;

//'extends Cms'는 Cms라는 클래스로 부터 상속을 받겠다는 뜻

//여기서 Cms는 부모클래스, CmsExt는 자식클래스이다.

//눈에 보이지는 않지만 Cms 소스가 그대로 복사가 되어있다.

// Cms에서 기본생성자가 없으면 에러가 난다.

public class CmsExt extends Cms{

    private String address;

    

    //기존 기능에서 adress를 추가해준다.

    public CmsExt(int no, String name, char level, String address) {

        this.no = no;

        this.name = name;

        this.level = level;

        this.address = address;

    }

    

    public void print() {

        // display라는 메소드가 이 클래스에는 없어도 Cms에 있었기 때문에 상속받아 쓸 수 있다.

        display();

        System.out.println("고객주소 : " + address);

    }

}




package prjClass3;

public class InheritanceTest {

    public static void main(String[] args) {

        // TODO 상속의 기본 개념

        Cms kim = new Cms(1, "김유신", 'C');

        kim.display();

        System.out.println("\n\n");

        CmsExt lee = new CmsExt(1, "김유신", 'C', "서울시 강남구");

        lee.print();

    }

}


※ 결과값

고객번호 : 1

고객이름 : 김유신

고객이름 : C


고객번호 : 1

고객이름 : 김유신

고객이름 : C

고객주소 : 서울시 강남구


** 용어정리

부모클래스 : 상속을 해주는 클래스 (Super Class)

자식클래스 : 상속받는 클래스 (SubClass)

[Ms (C, C++) 에서는 부모클래스를 베이스클래스, 자식클래스를 파생클래스 derived 라고 부른다.]



1. 상속 제외

1) 생성자

        - 생성자는 자식이다. 자식에게 부모를 달라고 할 수는 없다.


2) pivate

        - 중요하니까 보안을 해 놓은건데 상속이 되게 할 수는 없으므로

        - 엄밀히 말하면 상속이되지만 고려해야한다.

        - 부모클래스를 처음 만들 때는 변수를 private로 하고 고민한다. 


2. 부모의 생성자를 호출 할 수 있다.

- 부모생성자를 상속받고 싶지만 변수와 메서드가 private로 막혀있어서 어려울 때는

   super 메서드를 이용하여 부모에게 먼저 저장하고, 부모의 생성자를 호출한다.

- 반드시 생성자 안에서만 호출 가능하다.

- 부모의 생성자를 호출 할 때는 반드시 첫번째 줄에서 호출한다.


부모의 생성자를 호출

super()

super.변수, super.메서드()


자기 자신의 생성자를 호출

this()

this.변수, this.메서드()


- this()는 자주 쓰지 않지만, super는 자주 쓴다.



package prjClass3;

public class Cms {

    private int no;

    private String name;

    private char level;

    

    //기본생성자 추가

    public Cms() {

        

    }

    //생성자 생성

    public Cms(int no, String name, char level) {

        super();

        this.no = no;

        this.name = name;

        this.level = level;

    }

    

    public void display() {

        System.out.println("고객번호 : " + no);

        System.out.println("고객이름 : " + name);

        System.out.println("고객이름 : " + level);

    }

}

package prjClass3;

//'extends Cms'는 Cms라는 클래스로 부터 상속을 받겠다는 뜻이다.

//여기서 Cms는 부모클래스, CmsExt는 자식클래스이다.

//눈에 보이지는 않지만 Cms 소스가 그대로 복사가 되어있다.

// Cms에서 기본생성자가 없으면 에러가 난다.

public class CmsExt extends Cms{

    private String address;

    

    //기존 기능에서 adress를 추가해준다.

    public CmsExt(int no, String name, char level, String address) {

        /*

        //부모생성자를 상속받고 싶지만 private로 막혀있어서 어려움

        this.no = no;

        this.name = name;

        this.level = level;

        */

        //super 메서드를 이용하여 부모에게 먼저 저장하고, 부모의 생성자를 호출한다.

        //부모의 생성자를 호출 할 때는 반드시 첫번째 줄에서 작성한다.

        super(no, name, level);

        this.address = address;

    }

    

    public void print() {

        // display라는 메소드가 이 클래스에는 없어도 Cms에 있었기 때문에 상속받아 쓸 수 있다.

        display();

        System.out.println("고객주소 : " + address);

    }

}

package prjClass3;

public class InheritanceTest {

    public static void main(String[] args) {

        // TODO 상속의 기본 개념

        Cms kim = new Cms(1, "김유신", 'C');

        kim.display();

        System.out.println("\n\n");

        CmsExt lee = new CmsExt(1, "김유신", 'C', "서울시 강남구");

        lee.print();

    }

}


※ 결과값

고객번호 : 1

고객이름 : 김유신

고객이름 : C

고객번호 : 1

고객이름 : 김유신

고객이름 : C

고객주소 : 서울시 강남구



3. 생성자의 호출 순서


class A{

    A(){System.out.println("A생성자호출");}

}

//A를 상속받자

class B extends A{

    //보이지는 않지만 super(); 가 생략되어 있다.

    B(){System.out.println("B생성자호출");}

}

//B를 상속받자

class C extends B{

    

    C(){

        //생략되어있는 super(); 써도 된다.

        super();

        System.out.println("C생성자호출");}

}

public class CallOrderTest {

    public static void main(String[] args) {

        //TODO 생성자의 호출순서

        new C();

        

    }

    

}



※ 결과값

A생성자호출

B생성자호출

C생성자호출




class A{

}

//A를 상속받자

class B extends A{

    //부모클래스에 생성자를 만들경우 기본생성자가 없어지기 오류가 난다.

    B(int i){

        

    }

}

//B를 상속받자

class C extends B{

    //생성자에는 아래와 같은 기본 생성자인 super 코드가 숨겨져있다.

    C(){

        super();

    }

}

public class CallOrderTest {

    public static void main(String[] args) {

        //TODO 생성자의 호출순서

        new C();

        

    }

    

}


※ 결과값

Exception in thread "main" java.lang.Error: Unresolved compilation problem:

    The constructor B() is undefined

    at prjClass3.C.<init>(CallOrderTest.java:18)

    at prjClass3.CallOrderTest.main(CallOrderTest.java:25)


package prjClass3;

class A{

}

//A를 상속받자

class B extends A{

    

    //부모클래스에 생성자를 만들경우 기본생성자가 없어지기 오류가 나기 때문에 기본생성자를 만들어준다.

    B(){}

    B(int i){

        

    }

}

//B를 상속받자

class C extends B{

}

public class CallOrderTest {

    public static void main(String[] args) {

        //TODO 생성자의 호출순서

        new C();

        

    }

    

}


※ 결과값

(에러가 나지 않는다.)



4. 상속은 확장의 개념이다.

- 반드시 부모로 부터 물려 받은 것을 추가해야한다. 

  그렇게 하지 않고 물려받은 그대로 쓴다면 상속할 필요가 없다.

- 상속은 반드시 철저한 계획하에 해야한다.


5. 클래스 상속은 단일 상속만 지원한다.


<상속의 법칙>

- 상속은 중복기능이 있으면 안된다.

- 부모는 최소의 기능(공통으로 필요한 기능)만 갖는다.




<상속의 종류>

1.일반상속

    - 부모가 하나이다.

    - 일반적인 트리구조를 가지고 있다.

    - 추가 보완 할 수 있다.

    - 어떤 기능이 있는지 알려면 부모를 알면 된다. (안전하고 견고하다.)

=> java에서는 다중상속의 문제점 때문에 class에서는 일반상속만 한다.






2.다중상속

    - 부모가 여럿이다.

    - 다중상속은 중복된 기능이 있을 수 있을 가능성이 많다.

    - 다중상속은 처음부터 완벽한 설계아래 만들어야 해서 수정이 어렵다.

    - 다중상속은 어떤 기능을 가지고 있는지 알기 어렵다.

    (다중상속이 처음 받아들인 C++은 나중에 MFC라는 프로그램을 만들 때 다중상속을 없애버렸다.)


=> java에서는 인터페이스 등에서만 다중상속을 한다.




<상속의 설계>

- 부모로 갈 수록 최소의 기능, 공통적으로 필요한 기능만 갖는다.

- 자식은 조금더 복잡하다.




예) 자동차를 만들어 보자.



★ 상속 주제를 정해서 실제로 설계를 해보면 좋다. ★


6. 부모클래스와 자식클래스의 참조관계


package prjClass3;

class First{

    int a = 10;

    

    void display() {

        System.out.println("a : " + a);

    }

}

class Second{

    int b = 10;

    

    void print() {

        System.out.println("b : " + b);

    }

}

public class ReferenceTest {

    public static void main(String[] args) {

        // TODO 부모와 자식클래스의 참조 관계

        First f1 = new First();

        f1.display();

        

        Second s1 = new Second();

        s1.print();

        

        //First 는 First 끼리 주소를 참조한다.

        First f2 = f1;

        f2.display();

        

        

        

        // f2 = (First)s1; 서로다른 클래스들 끼리는 주소를 넘겨받을 수 없다.

    }

}


※ 결과값

a : 10

b : 10

a : 10



<부모클래스와 자식클래스의 참조관계의 특징>

1.서로다른 클래스는 주소를 참조할 수 없다.
2.서로다른 클래스는 주소 참조가 안되지만 부모 자식간의 관계에서는 주소 참조가 된다.
3.부모는 자식의 주소를 참조 할 수 없다. 자식만 부모의 주소를 참조가능하다.
4.부모가 부모 자신이 자식에게 물려준 것만 참조 가능하다. (자식이 추가한 것은 쓸 수 없다.)


package prjClass3;
class First{
    int a = 10;
    
    void display() {
        System.out.println("a : " + a);
    }
}
class Second extends First{
    int b = 10;
    
    void print() {
        System.out.println("b : " + b);
    }
}
public class ReferenceTest {
    public static void main(String[] args) {
        // TODO 부모와 자식클래스의 참조 관계
        First f1 = new First();
        f1.display();
        
        Second s1 = new Second();
        s1.print();
        
        //First 는 First 끼리 주소를 참조한다.
        First f2 = f1;
        f2.display();
        
        //f2 = (First)s1;
        f2 = s1;
        s1.a =11;
        //second에
        f2.display();
        
        
        
        // f2 = (First)s1; 서로다른 클래스들 끼리는 주소를 넘겨받을 수 없다.
        // 부모자식간의 관계에서는 참조 가능
    }
}


※ 결과값
a : 10
b : 10
a : 10
a : 11


부모가 자식의 주소를 참조할려고 할 경우 오류가 난다.

package prjClass3;

class First{
int a = 10;
void display() {
System.out.println("a : " + a);
}
}

class Second extends First{
int b = 10;
void print() {
System.out.println("b : " + b);
}
}


public class ReferenceTest {
public static void main(String[] args) {
// TODO 부모와 자식클래스의 참조 관계 
First f1 = new First();
f1.display();
Second s1 = new Second();
s1.print();
//First 는 First 끼리 주소를 참조한다.
First f2 = f1;
f2.display();
//f2 = (First)s1;
f2 = s1;
s1.a =11;
//second에 
f2.display();
//부모가 부모 자신이 자식에게 물려준 것만 참조 가능하다. (자식이 추가한 것은 쓸 수 없다.)
//f2.b=21;
//f2.print();
//자식만 부모의 주소를 참조가능, 부모는 자식의 주소를 참조 할 수 없다.
//Second s2 = (Second)f1;
//s2.display();
// f2 = (First)s1; 서로다른 클래스들 끼리는 주소를 넘겨받을 수 없다.
// 부모자식간의 관계에서는 참조 가능
// 자식만 부모의 주소를 참조가능, 부모는 자식의 주소를 참조 할 수 없다.
}

}

※ 결과값
a : 10
b : 10
a : 10
a : 11



하드웨어상 참조 순서가 정해져있기 때문에
자식은 부모의 주소를 저장할 수 있는 공간이 없다.
이는 캐스팅을 해도 안된다.

이런 부모자식간의 참조관계를 왜 알아야할까?

A a;
B b;
C c;

b = new B();
c = new C();

//인스턴스가 실행 중에 만들어 진다면 어떤 주소를 참조해야 할지 몰라서 쓰레기 값이 된다.
//그렇기 때문에 부모의 코드를 참조하면 어떤 자식 코드가 인스턴스로 만들어져도 오류가 나지 않는다.
//문제는 B에서 추가된 내용이나 C에서 추가한 내용은 쓸 수 없다.
a = new B();
a = new C();

...

//부모가 B의 주소를 대신 맡아서 쓸 경우 B의 기능을 다 쓸 수 없다.
//이럴경우 부모가 가지고 있는 자식의 주소를 다시 넘겨줘야 B의 기능을 다 쓸 수 있다.
//이처럼, 부모가 자식의 주소를 보관하고 있을 때만 다시 자식에게 넘겨줄 수 있다. 
B B1 = (B)a;


부모가 자식의 주소를 참조할 수 있다.

이는 부모가 잠시 가지고 있는 주소를 자식이 돌려줄 때만 가능하다.


이런 경우는 어떤 자식 클래스를 인스턴스로 생성할지 모를 때 유용하다.


또 하나의 예제를 들어보자.


A a;

B b;

C c;


B b1 = new B();

C c1 = new C();

B b2 = new B();

B b3 = new B();

C c2 = new C();


//부모클래스가 자식클래스의 주소값을 받을 수 있다.

A[] a = {b1, c1, b2, b3, c2, new B(), new C()};




사용 예제를 자꾸 보아야 이해가 가능하다.


package prjClass3;

class First{

    int a = 10;

    

    void display() {

        System.out.println("a : " + a);

    }

}

class Second extends First{

    int b = 20;

    

    void print() {

        System.out.println("b : " + b);

    }

}

public class ReferenceTest {

    public static void main(String[] args) {

        // TODO 부모와 자식클래스의 참조 관계

        First f1 = new First();

        f1.display();

        

        Second s1 = new Second();

        s1.print();

        

        //First 는 First 끼리 주소를 참조한다.

        First f2 = f1;

        f2.display();

        

        f2 = s1;

        s1.a =11;

        f2.display();

        

        //부모가 자식의 주소를 보관하고 있을 때만 다시 자식에게 넘겨줄 수 있다.

        Second s2 = (Second)f2;

        s2.b = 21;

        s2.print();

    }

}

※ 결과값

a : 10

b : 20

a : 10

a : 11

b : 21





이렇게 부모가 자식의 주소값(주소)를 받아 올 수 있는 이유는

자식 클래스가 생길 때부터 이미 부모클래스를 포함한 관계이기 때문이다.

이 때 부모클래스는 자식클래스의 부분집합이기 때문에 
자식의 주소값을 잠시 보관하는 것이 가능했다.



7. 메서드의 오버라이딩(Overrding) : 재정의


<오버로딩>

- 서로다른 메서드를 같은 이름으로 쓰는 것. (중복정의, 다형성을 지원)

- 어디에서나 사용가능


컴퓨터를 용도별로 컴퓨터로 산다면 얼마나 좋을까?

음악용, 작업용, 영화감상용...

이렇게 한다면 낭비가 너무 심할 것이다.

보통은 하나의 컴퓨터를 용도에 맞게 조금씩 고쳐서 쓴다.


오버라이딩은 하나의 메서드를 고쳐서 쓰는 것을 말한다.


여기서 오버라이딩은

부모로 부터 물려받은 메소드를 고쳐서 쓰는 것을 말한다.

조금 더 리소스를 절약하자는 측면에서 쓴다.

상속에서만 사용 가능하다.


오버라이딩

- 부모로 부터 물려받은 메소드를 고쳐쓰는 것

- 상속에서만 사용 가능

- UX (User eXperience) 부모클래스를 만든 사용자 경험을 그대로 쓸 수 있다는 장점이 있다.


1) 다형성지원 

2) 상속에서만 사용가능




package prjClass3;

public class Cms {

    private int no;

    private String name;

    private char level;

    

    //기본생성자 추가

    public Cms() {

        

    }

    //생성자 생성

    public Cms(int no, String name, char level) {

        super();

        this.no = no;

        this.name = name;

        this.level = level;

    }

    

    public void display() {

        System.out.println("고객번호 : " + no);

        System.out.println("고객이름 : " + name);

        System.out.println("고객이름 : " + level);

    }

}

package prjClass3;

//'extends Cms'는 Cms라는 클래스로 부터 상속을 받겠다는 뜻이다.

//여기서 Cms는 부모클래스, CmsExt는 자식클래스이다.

//눈에 보이지는 않지만 Cms 소스가 그대로 복사가 되어있다.

// Cms에서 기본생성자가 없으면 에러가 난다.

public class CmsExt extends Cms{

    private String address;

    

    //기존 기능에서 adress를 추가해준다.

    public CmsExt(int no, String name, char level, String address) {

        /*

        //부모생성자를 상속받고 싶지만 private로 막혀있어서 어려움

        this.no = no;

        this.name = name;

        this.level = level;

        */

        //super 메서드를 이용하여 부모에게 먼저 저장하고, 부모의 생성자를 호출한다.

        //부모의 생성자를 호출 할 때는 반드시 첫번째 줄에서 작성한다.

        super(no, name, level);

        this.address = address;

    }

    /*

    public void print() {

        // display라는 메소드가 이 클래스에는 없어도 Cms에 있었기 때문에 상속받아 쓸 수 있다.

        display();

        System.out.println("고객주소 : " + address);

    }

    */

    //부모가 물려준 display()메소드를 고쳐서 쓰겠다.

    //오버라이딩은 부모클래스 메서드와 똑같은 형식으로 해야 된다.

    //이름만 같고 타입이 다르면 오버로딩이 된다.

    //UX (User eXperience) 부모클래스를 만든 사용자 경험을 그대로 쓸 수 있다는 장점이 있다.

    public void display() {

        //부모가 가진 disply()호출한다는 의미로 super.을 써준다.

        //그래야 무한반복이 되지 않는다.

        super.display();

        System.out.println("고객주소 : " + address);

    }

    

}

package prjClass3;

public class InheritanceTest {

    public static void main(String[] args) {

        // TODO 상속의 기본 개념

        Cms kim = new Cms(1, "김유신", 'C');

        kim.display();

        System.out.println("\n\n");

        CmsExt lee = new CmsExt(1, "김유신", 'C', "서울시 강남구");

        //lee.print();

        //오버로딩을 사용하여 CmsExt 클래스에서 받아옴.

        lee.display();

    }

}


※결과값

고객번호 : 1

고객이름 : 김유신

고객이름 : C

고객주소 : 서울시 강남구



8. 추상클래스, 추상메서드


1) 추상메서드


- 내용은 없고 선언만 되어있는 메서드

- 자식이 가져다 쓸 수 있도록 부모가 빈 메서드를 선언 할 경우.

- 반드시 오버라이딩을 해야한다.

- 반드시 abstract 키워드를 사용

 

추상메서드를 이용한 부모클래스

   // 안에 내용이 없고 거쳐만 간다.

    void a(){


    }

    

    // 부모클래스에서 중괄호를 생략하여 적어 시행속도를 빠르게 한다.

    // 자시클래스에서는 중괄호를 펼친채로 사용한다.

    //자식은 반드시 오버라이딩 해야한다. 프로그래밍을 안전하게 할 수 있다.

    abstract void a();



2) 추상 클래스

    - 추상메서드를 1개 이상 가지고 있는 경우

    - abstract 키워드 사용

            abstract class 클래스명{

            }


    - 절대로 인스턴스를 생성할 수 없다.

     인스턴스가 없다 -> 실행할 수 없다. -> 직접일을 하지 않겠다.

     내가 가지고 있는 것을 자식에게 물려주는 용도로만 사용.

     자식을 위해 상속을 하는 의미로만 사용


     예)

     도형의 공통된 속성 A : 점, 선, 면적

     사각형 : A 상속

     원 : A 상속

     삼각형 : A 상속



package prjClass3;

//추상클래스를 만드려면 abstract를 해준다.

abstract class TwoDShape {

    private double width;

    private double height;

    private String name;

    

    //기본생성자를 미리 만들어 주는 것이 좋다.

    public TwoDShape() {}

    

    //private 변수를 쓸 수 있도록 생성자 호출

    public TwoDShape(double width, double height, String name) {

        super();

        this.width = width;

        this.height = height;

        this.name = name;

    }

    

    //상속법에 의해 자식에게 상속해 줄 수 있는 것은 getter메서드 하나이다.

    //private의 값을 입력할 수 있도록 getter 메서드를 만든다.

    public double getWidth() { return width; }

    public double getHeight() { return height;    }

    public String getName() { return name; }

    

    /*

    public double getArea() {

        //미리 면적을 구하기 어렵기 때문에 기본값으로    

        return 0.0;

    }

    */

    

    //추상메서드를 만든다.

    public abstract double getArea();

    

    

}//end class

//부모에게 getter메서드를 상속

class Triangle extends TwoDShape{

    public Triangle(double w, double h, String n) {

        //Triagle이 저장할 능력이 없어서 변수가 있는 부모에게 대신 저장한다.

        super(w, h, n);

        

    }    

        //부모로 부터 메소드를 물려받아 고쳐쓴다. 오버라이딩한다.

        public double getArea() {

            //부모에게 저장한 값을 꺼내온다.

            return getWidth() * getHeight() /2;

    }

}//end class

//부모에게 getter메서드를 상속

class Rectangle extends TwoDShape{

    public Rectangle(double w, double h, String n) {

        //Triagle이 저장할 능력이 없어서 변수가 있는 부모에게 대신 저장한다.

        super(w, h, n);

        

    }    

        //부모로 부터 메소드를 물려받아 고쳐쓴다. 오버라이딩한다.

        public double getArea() {

            //부모에게 저장한 값을 꺼내온다.

            return getWidth() * getHeight();

    }

    

}//end class

public class ShapeTest {

    public static void main(String[] args) {

        // TODO 2차원 도형을 기르기 위한 프로그램

        Triangle tr1 = new Triangle(5.0, 10.0, "정삼각형");

        Triangle tr2 = new Triangle(7.0, 15.0, "직각삼각형");

        Rectangle re1 = new Rectangle(3.0, 3.0, "정사각형");

        Rectangle re2 = new Rectangle(3.0, 6.0, "직사각형");

        System.out.println(tr1.getName() + " : " + tr1.getArea());

        System.out.println(tr2.getName() + " : " + tr2.getArea());

        

        //부모가 어떤 기능을 가졌는지 알아야 기능을 파악 할 수 있다.

        //부모가 자식의 주소를 한 번에 참조할 수 있다.

        TwoDShape[] t = {tr1, tr2, re1, re2,

                //배열 안에 바로 인스턴스 생성을 해서 추가할 수도 있다.

                new Rectangle(3.0, 4.0, "그냥사각형")};

        

        

        for(int i=0; i<t.length; i++) {

            System.out.println(t[i].getName()+" : "

                    + t[i].getArea());

            

        }

        

    }//end method

}//end class


※ 결과값

정삼각형 : 25.0

직각삼각형 : 52.5

정삼각형 : 25.0

직각삼각형 : 52.5

정사각형 : 9.0

직사각형 : 18.0

그냥사각형 : 12.0

    

9. final
- 변경 할 수 없다. 수정 할 수 없다.

1) 변수, 메서드, 클래스
------------------------------------------------
final int i =10;
i = 5;(에러)
---------------------------------------------------------

이때 final은 변수가 아니라 상수가 된다.

상수에는 두 가지 의미가 있다.
- literal : 실제값
- Constant : 변하지 않는 값

final은 변하지 않는 값 (Constant의 의미이다.)

변수에 final을 붙히는 2가지 이유
 ① 값을 끝까지 잘 보호하기 위해 
 ② 가독성, 코드가 쓰여진 의도를 분명히 알 수 있도록

---------------------------------------------------------
//변하지 않는 값의 의도를 분명히 알 수 있다.
final int MAX_AGE = 100;
for(int i =0; i<MAX_AGE; i++){
}
---------------------------------------------------------

*final을 쓸 때의 관례
- final을 사용하여 상수를 만들 때는 변수와 구별하기 위해 대문자로 만든다.


void 앞에 final을 붙이면 오버라이딩을 금지한다는 뜻이다.

final void 메서드명(){

        ...

}


class 앞에 final을 붙히면 상속을 금지한다는 뜻이다.

final class 클래스명{

        ...

}


(10) Object 클래스

- 모든 자바 클래스는 Object라는 클래스에서 상속을 받는다.

- 모든 자식을 참조 할 수 있지만, 너무 기본적인 클래스라 제한을 받는다.

- Java API에서 Object 클래스를 찾아보자 (javabase -> java.lang-> Object )

https://docs.oracle.com/javase/9/docs/api/index.html?overview-summary.html



'개발 > Java' 카테고리의 다른 글

[java] 인터페이스(InterFace)  (0) 2017.10.26
[java] 패키지 package  (0) 2017.10.25
[java] 클래스 (Class) part.2  (0) 2017.10.24
[java] 배열 (Array)  (0) 2017.10.19
[java] 클래스 (Class) part.1  (0) 2017.10.18

클래스 (Class) part.2


1. 접근제어 명시자 (Access Modifier)


- 변수, 메서드, 클래스 어디에나 사용이 가능하다.

- 클래스와 클래스들은 기본적으로 서로가 쉽게 접근 할 수 없다.


클래스는 누구는 접근 할 수 있도록 하고,

누구는 접근하지 못하게 할 수 있다.


클래스의 보안 기능을 살펴보자.


1) 종류

<접근허가>

1. default

- 접근제어명시자가 생략된 형태. 접근할 수 있도록 허가, 같은 폴더 안에 있는 class 안에서만 사용가능)

- 같은 파일 안에서는 public을 안붙여도 된다.

- 한 파일에 하나의 클래스만 있는 것이 원칙이다.

2. public 

- 다른 폴더나 같은 폴더나 어디서나 접근할 수 있는 허가권


<접근불가>

1. private

- 가장 강력한 접근거부

- 같은 클래스에서만 사용 가능

2. protected (class part3에서 다룸)

- defult와 성격이 비슷


<예제 1>

class EmpManager{

    public String name;

    int no;

    double pay;

    

}

public class AccessModifierTest {

    public static void main(String[] args) {

        // TODO 접근제어명시자 테스트

        EmpManager kim = new EmpManager();

        kim.name = "김유신";

        kim.no = 12;

        kim.pay=1000000;

        System.out.println(kim.name + " : " + kim.no + " : " + kim.pay);

        

    }

}


※결과값

김유신 : 12 : 1000000.0


여기서 pay값을 못 보게 하고 싶다면 private를 사용한다.


<예제2>


class EmpManager{

    public String name;

    int no;

    // 클래스 안에서만 작동하기 때문에 오류가 생긴다.

    private double pay;

    

}

public class AccessModifierTest {

    public static void main(String[] args) {

        // TODO 접근제어명시자 테스트

        EmpManager kim = new EmpManager();

        kim.name = "김유신";

        kim.no = 12;

        kim.pay=1000000;

        System.out.println(kim.name + " : " + kim.no + " : " + kim.pay);

        

    }

}


※결과값

Exception in thread "main" java.lang.Error: Unresolved compilation problems:

    The field EmpManager.pay is not visible

    The field EmpManager.pay is not visible

    at AccessModifierTest.main(AccessModifierTest.java:17)


문제는 이렇게 되면 EmpManager라는 클래스가 쓸모없어진다.


그렇다면 어떻게 하면 pay를 못보게 하면서 클래스를 사용할 수 있을까?


이럴 때는 메서드를 만들어주면 된다.


class EmpManager{

    public String name;

    int no;

    private double pay;

    //private 변수를 수정하고 저장 할 수 있는 메서드 (쓰고 저장하는 기능)

    //setter 메서드

    //이런 setter 메서드는 앞에 변수 이름을 set이라고 쓴다.

    // 값을 받아서 private 변수에 넣어준다.

    void setPay(int p) {

        //값에 대한 검증

        pay = p;

    }

    // getter 메서드

    // 값을 가져다가 읽어올 수 있게 해준다. (읽기 기능)

    // 이런 setter 메서드는 앞에 변수 이름을 get이라고 쓴다.

    double getPay() {

        return pay;

    }

    

}

public class AccessModifierTest {

    public static void main(String[] args) {

        // TODO 접근제어명시자 테스트

        EmpManager kim = new EmpManager();

        kim.name = "김유신";

        kim.no = 12;

        //kim.pay=1000000;

        kim.setPay(1000000);

        System.out.println(kim.name + " : " + kim.no + " : " + kim.getPay());

        

    }

}


※ 결과값

김유신 : 12 : 1000000.0


2) setter메서드, getter 메서드


위에 예시에서 보듯이

prive으로 선언될 때는 클래스 내부 기능을 

사용하기 위해서 반드시 메서드가 달려있다.

private 변수하나에 반드시 두 개의 메서드가 따라 다녀야 한다.

이 두 변수 이름을 getter 와 setter 메서드 라고 한다.


① setter 메서드

private 변수를 수정하고 저장 할 수 있는 메서드 (쓰고 저장하는 기능)

이런 setter 메서드는 앞에 변수 이름을 set이라고 쓴다.

값을 받아서 private 변수에 넣어준다.


② getter 메서드

값을 가져다가 읽어올 수 있게 해준다. (읽기 기능)

이런 setter 메서드는 앞에 변수 이름을 get이라고 쓴다.



지금까지 배운 내용을 바탕으로 메인 메서드를 다시 살펴보자.


public static void main(String[] args)

public 자바 가상머신이 어디에든 실행 할 수 있도록 한다.

void 리턴값이 없다. (가상머신이 main찾는데 가상머신에게 리턴하지 않는다.)

main 메서드도 시스템이 찾는 콜백메서드이다.

static (앞으로 배워야 할 것)

(String[] args)  명령행 인자를 위한 매개변수이다.


2. 메서드

- 메서드 때문에 클래스의 특징이 결정된다.

- 변수 값을 임시저장 할 뿐이다. 정말 중요한건 메서드가 한다.


1) 인자 전달 방식

메서드를 호출했을 때 인자를 전달하는 방법이 크게 두가지가 있다.


1. 직접 값을 줄 것인가?

2. 주소를 통해 전달해 줄 것인가?


메서드의 인자전달방식

① 값에 의한 전달 (call by value)

 - 지금까지 했던 모든 전달방식은 값에 의한 전달방식이었다.

    a. 소량의 데이터

    b. 잠깐 사용할 데이터

② 주소(참조)에 의한 전달(call by reference)

    a. 대량의 데이터

    b. 오랫동안 사용할 데이터


<인자 전달 방식>


public class CallByTest1 {

    void display(int a, int b, int c, int d, int e) {

        System.out.println(a + ", " + b + ", " + c);

        

    }

    

    public static void main(String[] args) {

        // TODO 값에 의한 인자 전달 방식

        // 일반변수는 stack을 사용하기 때문에 주소값을 저장할 수 없다.

        // hip에 저장을 해야 안전하게 쓸 수 있다.

        // 어떻하면 이 데이터를 안전하게 보관할 수 있을까? 답은 배열이다.

        int a=4, b=7, c=15, d=80, e=9;

        

        CallByTest1 call = new CallByTest1();

        call.display(a, b, c, d, e);

    }

}


※ 결과값

4, 7, 15


<주소(참조)에 의한 전달>

1.값이 많아 져도 괜찮다. 

2.안전한 저장이 가능하다.


인자와 매개변수는 타입이 똑같아야한다.


주소(참조)에 의한 전달 방법은 두 가지가 있다.


첫 번째, 배열로 묶어서 전달한다.

두 번째, 인스턴스 변수를 선언하여 주소에 저장한다.


첫번째, 배열로 묶어서 전달하는 방법


public class CallByTest1 {

    void display(int [] arr) {

        System.out.println(arr[0] + ", " + arr[1] + ", " + arr[2]);

        

    }

    

    public static void main(String[] args) {

        // TODO 값에 의한 인자 전달 방식

        // 배열로 주소에 의함 참조 방식을 쓴다. 값이 많아져도 된찮다.

        // 값이 많아 져도 괜찮다. 안전한 저장이 가능하다.

        //지역변수를 인스턴스 변수로 선언

        int [] arr = {4, 7, 15, 80, 9};

        

        CallByTest1 call = new CallByTest1();

        call.display(arr);

    }

}


※ 결과값

4, 7, 15


두번째, 인스턴스 변수를 선언하여 주소에 저장하는 방법


public class CallByTest1 {

    //인스턴스변수를 선언하여 주소에 저장한다.

    int a =4, b=7, c=15, d=80, e=9;

    

    void display() {

        System.out.println(a + ", " + b + ", " + c);

        

    }

    

    public static void main(String[] args) {

        // TODO 참조에 의한 전달 방식 2

        int a=4, b=7, c=15, d=80, e=9;

        

        CallByTest1 call = new CallByTest1();

        call.display();

    }

}    


※ 결과값

4, 7, 15



여기서 Stack 구조에 대해 잠깐 알아보자.


<Stack 구조>

LiFO 구조이다.

lest in first out 구조

마지막에 나온 것이 먼저 나온다.

Stack 구조를 이용해 여러가지의 데이터타입을 인스턴스 변수로 빼 줄 수 있다.








public class CallByTest1 {

    int i = 4;

    double d = 3.14;

    char c = '가';

    boolean b = true;

    String s = "문자열";

    

    

    void display() {

        System.out.println(i + ", " + d + ", " + c);

        

    }

    

    public static void main(String[] args) {

        // TODO 참조에 의한 인자 전달 방식

        

        CallByTest1 call = new CallByTest1();

        call.display();

    }

}


※ 결과값

4, 3.14, 가


아래와 같이 클래스를 따로 뺀다면 코드가 깔끔해진다.


class Data{

    int i = 4;

    double d = 3.14;

    char c = '가';

    boolean b = true;

    String s = "문자열";

}

public class CallByTest1 {

    void display(Data da) {

        System.out.println(da.i + ", " + da.d + ", " + da.c);

        

    }

    

    public static void main(String[] args) {

        // TODO 참조에 의한 인자 전달 방식

        

        CallByTest1 call = new CallByTest1();

        Data data = new Data();

        call.display(data);

    }

}


※ 결과값

4, 3.14, 가



★ 알고리즘과 디자인패턴 ★ 

어느정도 익숙해지면 알고리즘 공부를 해야한다.


디자인 패턴

- 똑같은 재료를 어떻게 쓸것인가?

- 같은 재료를 가지고 다양한 기능을 수행

- 개발자들의 시행 착오, 다양하게 쓰던 방법을 모아두었다.

- 짧은 시간에 비법을 알 수 있는 비급서


DTO패턴 (Data Object)

- DO(Data Object) VO(value Objec) DTO (Data To Object) 라고 함

Data Object  따로 따로 흩어진 다양한 변수로 묶어서 

쓰기 편하도록 하나의 클래스로 만들어주는 방법

위 예제와 같은 예문을 DTO 패턴이라고 한다.



반드시 주소(참조)에 의한 전달을 써야하는 경우는 어떻게 될까?

내가 원하는 위치에서 값이 바뀔 수 있는 방법.


배열로 전달한다.


public class CallByTest2 {

    void swap(int[] n) {        

        int temp = n[0];

        n[0] = n[1];

        n[1] = temp;

        

    }

    public static void main(String[] args) {

        // TODO 반드시 참조에 의한 전달을 사용해야하는 경우

        // 내가 원하는 위치에서 값이 바뀔 수 있도록 한다.

        // num1과 num2의 주소값을 전달한다.

        int[]num = {5,10};

        CallByTest2 call = new CallByTest2();

        call.swap(num);

        

        System.out.println("교환 후 ...");

        System.out.println(num[0] + ", " + num[1]);

    }

}


※결과값

교환 후 ...

10, 5


public class CallByTest2 {

    

    int num1=5, num2=10;

    

    void swap() {        

        int temp = num1;

        num1 = num2;

        num2 = temp;

        

    }

    public static void main(String[] args) {

        // TODO 반드시 참조에 의한 전달을 사용해야하는 경우

        // 내가 원하는 위치에서 값이 바뀔 수 있도록 한다.

        // num1과 num2의 주소값을 전달한다.

        CallByTest2 call = new CallByTest2();

        call.swap();

        

        System.out.println("교환 후 ...");

        System.out.println(call.num1 + ", " + call.num2);

    }

}


※ 결과값

교환 후 ...

10, 5


같은 클래스지만 main 클래스에서 메소드를 쓰려면 생성자를 써야하는데

이는 static 때문이다. static은 나중에 별도로 설명한다.


3. 데이터 저장방법


1)변수의 단점

- 값을 1개만 저장해야한다.


2) 배열의 단점

- 같은 데이터 타입만 사용 가능

- 크기를 지정해야해서 남는 메모리나 더 큰 메모리가 될 수도 있다.

- 데이터 중간에 삽입/삭제 가 매우 불편하다.

- 배열은 데이터를 한번 저장하고 보관하는 것이 가장 적절하다.


3) 클래스

- 배열의 단점을 해결하기 위한 방법으로도 클래스가 사용된다.

- 서로 다른 데이터를 묶을 수 있다. (배열의 불편함 중에 이 부분만 해결 가능)


★ 연결리스트(Linked List) 알고리즘

- 배열의 크기 지정해야하는 문제나 데이터 삽입/삭제 문제를 해결해준다.

- 알고리즘을 공부하면 배울 수 있다.

- 자바에서 클래스로 제공해준다.



우선 이클립스에서 privite 을 사용할 때 

getter setter와 생성자를 쉽게 만드는 방법을 알아보자.


★ getter setter 쉽게 만들기



★ 생성자 쉽게 만들기


그럼 학점 관리 프로그램을 만들어보자.



public class Sunjuk_v3 {

    public static void main(String[] args) {

        // TODO 클래스를 이용한 성적표

        //이는 인스턴스가 3개 만들어진 것이 아니라 인스턴스의 주소를 저장 할 참조변수가 3개 만들어 진 것이다.

        //new만들어갔다고 인스턴스가 생성된 것이 아니라는 점을 생각하자.

    

        Student students[] = new Student[3];

        //생성자가 호출되어야 인스턴스가 생성되기 때문에 생성자를 생성.

        students[0] = new Student("홍길동", 1, 98, 90);

        students[1] = new Student("임꺽정", 2, 76, 55);

        students[2] = new Student("신돌석", 3, 85, 73);

        

        // 총점 구하기

        for (int i = 0; i < students.length; i++) {

            students[i].setTot(students[i].getKor()

                    + students[i].getEng());

        }

        // 평균구하기

        for (int i = 0; i < students.length; i++) {

            students[i].setAvg(students[i].getTot()/2 );

        }

        // 학점 구하기

        for (int i = 0; i < students.length; i++) {

            if (students[i].getAvg() >= 90)

                students[i].setGrade('A');

            else if (students[i].getAvg() >= 80)

                students[i].setGrade('B');

            else if (students[i].getAvg() >= 70)

                students[i].setGrade('C');

            else if (students[i].getAvg() >= 60)

                students[i].setGrade('D');

            else

                students[i].setGrade('F');

        }

        

        

        

        // 등수 구하기

        System.out.println("***성적결과***");

        System.out.println("학번\t국어\t영어\t총점\t평균\t학점\t순위");

        System.out.println("---------------------------------------------");

        for (int i = 0; i < students.length; i++) {

            System.out.println(students[i].getNo()  + "\t"  +

                               students[i].getKor() + "\t"  +

                               students[i].getEng() + "\t " +

                               students[i].getTot() + "\t"  +

                               students[i].getRank()  + "\t" +

                               students[i].getGrade() + "\t" +

                               students[i].getAvg());

            }

            

            System.out.println("정렬 후.......");

            for (int row = 0; row < students.length-1; row++) {

                for (int col = row+1; col < students.length; col++) {

                    if (students[row].getAvg() < students[col].getAvg()) {

                        Student temp = students[row];

                        students[row] = students[col];

                        students[col] = temp;

                    }

                }

            }

            System.out.println("***성적결과***");

            System.out.println("학번\t국어\t영어\t총점\t평균\t학점\t순위");

            System.out.println("---------------------------------------------");

            for (int i = 0; i < students.length; i++) {

                System.out.println(students[i].getNo()  + "\t"  +

                                   students[i].getKor() + "\t"  +

                                   students[i].getEng() + "\t " +

                                   students[i].getTot() + "\t"  +

                                   students[i].getRank()  + "\t" +

                                   students[i].getGrade() + "\t" +

                                   students[i].getAvg());

        }

    }//main end

}//class end


//따로만든 Student 클래스

public class Student {

    //항상 클래스에 있는 변수는 private로 선언

    private String name;

    private int no;

    private int kor;

    private int eng;

    private int tot;

    private int avg;

    private int rank;

    private char grade;

    

    

    //생성자를 만들어준다.

    public Student(String name, int no, int kor, int eng) {

        this.name = name;

        this.no = no;

        this.kor = kor;

        this.eng = eng;

    }

    

    //getter와 setter를 만들어 준다.

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public int getNo() {

        return no;

    }

    public void setNo(int no) {

        this.no = no;

    }

    public int getKor() {

        return kor;

    }

    public void setKor(int kor) {

        this.kor = kor;

    }

    public int getEng() {

        return eng;

    }

    public void setEng(int eng) {

        this.eng = eng;

    }

    public int getTot() {

        return tot;

    }

    public void setTot(int tot) {

        this.tot = tot;

    }

    public int getAvg() {

        return avg;

    }

    public void setAvg(int avg) {

        this.avg = avg;

    }

    public int getRank() {

        return rank;

    }

    public void setRank(int rank) {

        this.rank = rank;

    }

    public char getGrade() {

        return grade;

    }

    public void setGrade(char grade) {

        this.grade = grade;

    }

    

    

}


//Student[] students = new Student[5];

//이렇게 배열로 만들면 크기를 지정해줘야해서 메모리 공간이 낭비될 수 있다.

//class를 배열처럼 다루자.

//이렇게 하는 것이 DTO 패턴이다.



※ 결과값

***성적결과***

학번    국어    영어    총점    평균    학점    순위

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

1    98    90     188    0    A    94

2    76    55     131    0    D    65

3    85    73     158    0    C    79

정렬 후.......

***성적결과***

학번    국어    영어    총점    평균    학점    순위

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

1    98    90     188    0    A    94

3    85    73     158    0    C    79

2    76    55     131    0    D    65



4. 재귀호출 (Recursive Call)


void func(){

    func();

}


-> func();


스스로를 호출하는 메소드 반복문과 같은 효과이다.

그러나 반복문 보다는 효과가 매우 떨어진다.


메소드이기 때문에 스택에 계속 임시저장을 하기 때문에 메모리를 엄청 사용한다.

그래서 재귀호출은 흐름상 반복을 돌려야 할 때를 제외하고는 쓰지 않는다.

재귀호출은 알고리즘을 배울 때 정리해두면 좋다.


5. static


1) 인스턴스와는 상관없이 따로 만들어지는 별도의 메모리

- 별도로 hip에 만들어지는 메모리

- 인스턴스는 클래스와 상관이 없다.

- 클래스의 소속이 아니기 때문에 인스턴스를 안만들어도 되지만 

  어느 클래스에 있는 변수인지 소속을 알려줘야한다.

- 변수 뿐만일 아니라 메서드도 마찬가지이다.


2) 여러 인스턴스들이 공유할 수 있는 메모리

- 인스턴스가 공통적으로 사용하는 메모리 (프로그램 실행하면 자동으로 만들어짐)


3) this 가 없다.

 - this란 인스턴스의 주소값.

 -  this를 인스턴스를 구별하기 위해 만든 것이다.

 - static은 인스턴스가 없기 때문에 인스턴스의 주소값이 없다.


4) 클래스 변수

 - static 변수는 반드시 클래스 안에서만 선언할 수 있다.

 - 메서드 안에서는 선언 할 수 없다.

 - 커뮤니케이션 오해가 없기 위해 클래스 변수라는 표현보다 static 변수라고 부르자.


5) static block

 - static 변수만을 모아서 초기화

 - 깔끔하게 관리할 수 있다.


예시)

static int i;

static double d;

static{

    i = 10;

    d = 3.14;


public static void main(String[] args)

public 자바 가상머신이 어디에든 실행 할 수 있도록 한다.

static main이 쉽게 호출 할 수 있도록 인스턴스를 생성하지 않고 어디서나 사용할 수 있는 static사용

void 리턴값이 없다. (가상머신이 main찾는데 가상머신에게 리턴하지 않는다.)

main 메서드도 시스템이 찾는 콜백메서드이다.

(String[] args)  명령행 인자를 위한 매개변수이다.



 static 사용 사례를 확인해보자.


class StaticDemo1{

    int a;

    int b;

    static int c;

}

//하지만 static의 소속은 해당클래스에 있기 때문에 접근제한자 private의 영향을 받는다.

public class StaticTest1 {

    

    //변수 static을 사용하면 어디서나 쓸 수 있다.

    static int d;

    

    //변수 뿐 아니라 메서드도 static이 붙으면 클래스와는 별도로 사용할 수 있다.

    static void method1() {

        System.out.println("난 메서드야...");

    }

    

    //main에 static을 만든 이유는 가상머신이 일일히 인스턴스를 생성해

    // main을 호출하여 프로그램을 실행하기 어렵기 때문이다.    

    public static void main(String[] args) {

        // TODO static이란 무엇인가?

        

        StaticDemo1.c = 100;

        //static은 인스턴스를 넣어도 쓸 수있지만 없어도 할 수 있다.

        StaticDemo1 demo1 = new StaticDemo1();

        StaticDemo1 demo2 = new StaticDemo1();

        System.out.println(demo1.c);

        System.out.println(demo2.c);

        

        demo2.c = 200;

        System.out.println(demo2.c);

        

        //static이 붙은건 인스턴스를 만들지 않는다.

        //StaticTest1.d 이지만 같은 클래스에 있기 때문에 생략해주었다.

        d = 300;

    }

}


※ 결과값

100

100



참고로, 인스턴스와 객체는 거의 비슷한 개념으로 보아도 좋다.


//스테틱과 인스턴스, 누가 더 빠를까?

public class StaticTest2 {

    StaticTest2(){

        System.out.println("생성자 호출됨 : 인스턴스 생성");

    }

    static double d1, d2;

    static {

        System.out.println("static 생성");

        //Math.은 수학계산을 도와주는 메서드이다.

        d1 = Math.sqrt(4.0);

        d2 = Math.sqrt(8.0);

    }

    

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        new StaticTest2();

        System.out.println(d1 + "," + d2);

    }

}


※ 결과값

static 생성

생성자 호출됨 : 인스턴스 생성

2.0,2.8284271247461903


static이 인스턴스생성보다 더 빠르다.

이를 통해 static은 인스턴스와 상관없이 움직인다는 것을 알 수 있다.


6. 중첩클래스

- 클래스도 반복문처럼 중첩을 할 수 있다.

- 전용으로 써야할 클래스가 있는 경우 중첩클래스를 사용하면 편하다.

- 클래스가 내부에 있으면(중첩하면) private에 접근할 수 있다.




1) 일반클래스

- 바깥에 있는 클래스의 인스턴스가 먼저 만들어 져야하고

  내부 클래스의 인스턴스가 또 생성이 되어야한다.

  바깥 클래스의 메모리 영역이 결정되어야 

  내부 클래스의 메로리를 쓸 수 있기 때문이다.


 - 안에있는 클래스는 바깥에 있는 클래스를 모두 쓸 수 있다. (변수, 메소드)


 - 바깥에 있는 클래스는 안에 있는 클래스를 접근 할 수 없다.





2) static 클래스

- static 클래스는 내부클래스가 되었을 때

  클래스 안에 있지만 바깥에 클래스와는 상관 없다.

  그렇기 때문에 인스턴스를 따로 생성해도 상관없다.


- static 클래스의 경우 일반 클래스와 다르게 

  별개의 메모리를 가지고 있기 때문에

  사용하기 위해서는 인스턴스를 매번 생성해야한다.

  그래서 중첩클래스는 대부분 일반클래스를 사용한다.




<static클래스의 경우>


public class OuterClass {

    private int outer;

    

    

    //클래스가 내부에 있으면(중첩하면) private에 접근할 수 있다.

    static class InnerClass{

        private int inner;

        

        void innerMethod() {

            System.out.println(inner);

            

            OuterClass obj2 = new OuterClass();

            obj2.outer = 200;

            System.out.println("outer=" + obj2.outer);

        }

    }

    

    public static void main(String[] args) {

        // TODO 중첩클래스 (내부클래스가 static일 경우)

        InnerClass obj1 = new InnerClass();

        obj1.innerMethod();

    }

}


※ 결과값

0

outer=200



<일반클래스의 경우>


public class OuterClass {

    

    //안에있는 클래스는 바깥에 있는 클래스를 모두 쓸 수 있다. (변수, 메소드)

    //바깥에 있는 클래스는 안에 있는 클래스를 접근 할 수 없다.

    private int outer;

    

    

    //클래스가 내부에 있으면(중첩하면) private에 접근할 수 있다.

    class InnerClass{

        private int inner;

        

        void innerMethod() {

            System.out.println(inner);

            

            OuterClass obj2 = new OuterClass();

            obj2.outer = 200;

            System.out.println("outer=" + obj2.outer);

        }

    }

    

    public static void main(String[] args) {

        // TODO 중첩클래스 (내부클래스가 일반클래스일 경우)

        //일반클래스는 바깥에 있는 클래스의 인스턴스가 먼저만들어져야 내부 클래스를 쓸 수 있다.

        //OuterClass out = new OuterClass();

        //InnerClass obj1 = out.new InnerClass();

        

        //같은 클래스에 있기 때문에 .OuterClass을 생략해도 되지만 바깥에서 불러올 때는

        //바깥 클래스의 인스턴스를 먼저 생성해야하기 때문에 OuterClass.을 반드시 써야한다.

        OuterClass.InnerClass obj1 = new OuterClass().new InnerClass();

        obj1.inner = 100;

        obj1.innerMethod();

    }

}


※ 결과값

0

outer=200


지금까지 배운 내용을 종합하여 디자인패턴을 하나 배워보자.


**Singleton

- 인스턴스를 단 하나만 쓸 수 있는 디자인패턴

- 하나만 있어도 충분한 인스턴스를 계속 만들어 메모리를 낭비하는 경우를 사전에 방지한다.

- private 은 class 앞에 못 쓴다.

- 기본 생성자에 private을 붙힌다.

- new가 있다고 해서 다 인스턴스가 만들어진다고 생각하지 말아라.

- 메서드만가지고 인스턴스가 만들어지는 경우는 모두 싱글턴이다.


싱글턴 패턴을 만들기 위해 필요한 것

- 재료 : 생성자, static, private

- 방법

    ①외부에서 절대를 인스턴스를 생성할 수 없게 한다.

    ②내부에서 단 하나의 인스턴스를 생성한다.

    ③그렇게 만들어진 인스턴스를 외부에서 사용 할 수 있게 한다.


class SingletonDemo{

    

    private int i;

    // 인스턴스를 하나 만들어준다.

    // 보호할 수 있도록 private 처리를 한다.

    // 단 하나만 만들어 질 수 있도록 static을 놓는다.

    private static SingletonDemo instance = new SingletonDemo();

    

    // 기본생성자에 private을 붙여서 인스턴스를 하나만 생성하도록 한다.

    private SingletonDemo() {

        

    }

    

    //외부에서 쓸 수 있도록 메서드를 사용한다.

    //리턴값이 SingletonDemo이기 때문에 void 자리에 클레스 타입을 쓴다.

    //인스턴스 없어도 호출할 수 있도록 static을 쓴다.

    public static SingletonDemo getInstance() {

        return instance;

    }

}

public class SingletonTest {

    public static void main(String[] args) {

        // TODO Singeton Patten

        

        /*

        SingletonDemo obj1 = new SingletonDemo();

        SingletonDemo obj1 = new SingletonDemo();

        */

        

        SingletonDemo obj1 = SingletonDemo.getInstance();

        SingletonDemo obj2 = SingletonDemo.getInstance();

        SingletonDemo obj3 = SingletonDemo.getInstance();

        

        System.out.println("주소 비교 : " + (obj1==obj2));

        System.out.println("주소 비교 : " + (obj2==obj3));

    }

}


※결과값

주소 비교 : true

주소 비교 : true


배열(Array)


1. 같은 이름으로 정의된 연속적인 공간이다.


변수는 1개의 데이터 밖에 저장하지 못한다.

배열을 이용하면 변수가 가진 약점을 보완할 수 있다.

많은 양의 데이터를 다룰 수 있도록 하기 위해서 배열을 쓴다.


2. 객체로 취급


객체로 취급한다는 것은 클래스로 만들어 놓았다는 이야기이다.

클래스는 변수와 메소드를 묶어준다.

메서드나 변수를 이미 만들었기 때문에 사용하기 편하다.


배열은 각각의 변수들을 하나로 묶어준 것이다.


똑같은 땅을 어떻게 효율적으로 쓸 수 있을까?

집을 지을 때 같은 평수에 단독주택을 지으면 1개

아파트 같은 다세대 주택을 지으면 여러명이 살 수 있다.


이처럼 배열은 마치 아파드 처럼 같은 공간을 효율적으로 사용하기 위한 방법이다.


이때 아파트가 동 호수가 있는 것처럼 배열도 공간마다 번호를 붙이는데 이를 index라고 한다.


그중에서 하나하나의 변수를 1줄로 붙여놓은 묶음을 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
public class Arraytest {
 
    public static void main(String[] args) {
 
        int no=1, kor=70, eng=55, mat=87;
 
        
 
        //인스턴스 생성 -> 변수가 있어야한다.
 
        //java에서는 배열을 객체로 취급하기 때문에 인스턴스를 생성한다.
 
        int [] first = new int[4];
 
        //[숫자]번째 방에 값이 들어간다.(초기화 작업)
 
        first[0]=1;
 
        first[1]=70;
 
        first[2]=55;
 
        first[3]=87;
 
        
 
        //변수는 반복문을 쓸 수 없지만, 배열은 규칙성이 있어서 반복문을 쓸 수 있다.
 
        for(int i=0; i<4; i++) {
 
            System.out.println(first[i]);
 
        }
 
    }
 
}
cs


※ 결과값

1

70

55

87



초기화를 조금 더 간단히 하는 방법은 없을까?


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
public class Arraytest {
 
    public static void main(String[] args) {
 
        int no=1, kor=70, eng=55, mat=87;
 
        /*
        //인스턴스 생성 -> 변수가 있어야한다.
        //java에서는 배열을 객체로 취급하기 때문에 인스턴스를 생성한다.
        int [] first = new int[4];
        //[숫자]번째 방에 값이 들어간다.(초기화 작업)
        first[0]=1;
        first[1]=70;
        first[2]=55;
        first[3]=87;
        */
 
        
 
        // 초기화를 조금 더 간단히 한다.
 
        //반드시 동시에 선언하자 마자 초기화를 해야한다.
 
   //여기서는 new가 생략된다. 
 
        int [] first = {1705587};
 
        
 
        //int [] second;
 
        //second = {2, 68, 44, 32}; 선언하자마자 초기화하지 않았기에 안된다.
 
        
 
        //변수는 반복문을 쓸 수 없지만, 배열은 규칙성이 있어서 반복문을 쓸 수 있다.
 
        for(int i=0; i<4; i++) {
 
            System.out.println(first[i]);
 
        }
 
    }
 
}
cs

※결과값

1

70

55

87


이처럼 배열 초기화에는 두가지 방법이 있다.


1. 인스턴스를 선언하고 초기화를 한다.

2. 인스턴스를 선언과 동시에 초기화를 한다. 


변수처럼 인스턴스를 선언하지 않고 나중에 값을 넣을 수는 없다.


3. 배열로 할 수 있는 대표적인 알고리즘


1) 검색

1. 순차검색 (sequential)

2. 이분검색 (binary)


2) 정렬

*선수알고리즘 : swap 알고리즘

1. 버블정렬

2. 선택정렬


<검색>

어떻게하면 더 빨리 원하는 것을 찾을까?

그 해법은 알고리즘에 있다.


<검색 방법>

1.순차검색(Sequential)

 - 처음부터 끝까지 차례대로 찾기


2.이분검색(bynary)

 - 전체데이터를 둘로 양분 후 원하는 데이터가 있는지 없는지를 찾고 이를 반복한다.

 - 이 이분 검색은 데이터가 정렬되어 있어야 한다는 조건이 있다.


<순차검색(Sequential)>

그럼 배열을 사용해 순차방식방법으로 간단한 검색기능 프로그램을 짜보자.


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
public class SequentialSearch {
 
    public static void main(String[] args) throws java.io.IOException {
 
        
 
        char [] data = {'a' , 'b' , 'c' , 'd' , 'e''f''g''h'};
 
        
 
        System.out.println("찾고자하는 문자 입력 : ");
 
        //반복을 통해서 하나씩 비교해보기
 
        char search = (charSystem.in.read();
 
        
 
        //data.length변수는 데이터 수 범위는 데이터 양만큼 지정한다.
 
        for(int i=0; i<data.length; i++) {
 
            //실제 저장된 데이터를 비교한다.
 
            if(search == data[i]) {
 
                System.out.println("찾았다.");
 
                break;
 
            }
 
            
 
        }
 
    }
 
}
cs


※결과값

찾고자하는 문자 입력 :

d

찾았다.



'못찾았다'를 입력하고 싶으면 어떻게 할까?


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
public class SequentialSearch {
 
    public static void main(String[] args) throws java.io.IOException {
 
        
 
        char [] data = {'a' , 'b' , 'c' , 'd' , 'e''f''g''h'};
 
        
 
        System.out.println("찾고자하는 문자 입력 : ");
 
        //반복을 통해서 하나씩 비교해보기
 
        char search = (charSystem.in.read();
 
        
 
        //data.length변수는 데이터 수 범위는 데이터 양만큼 지정한다.
 
        for(int i=0; i<data.length; i++) {
 
            //실제 저장된 데이터를 비교한다.
 
            if(search == data[i]) {
 
                System.out.println("찾았다.");
 
                break;
 
            }
 
            else {
 
                System.out.println("못찾았다.");
 
            }
 
            
 
        }
 
    }
 
}
 
 
cs


※결과값

찾고자하는 문자 입력 : ㅣ

못찾았다.

못찾았다.

못찾았다.

못찾았다.

못찾았다.

못찾았다.

못찾았다.

못찾았다.



그런데 '못찾았다'가 계속나온다.

if문이 계속 반복해서 돌기 때문이다.

이럴 때는 flag 기법을 쓴다.


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
public class SequentialSearch {
 
    public static void main(String[] args) throws java.io.IOException {
 
        
 
        char [] data = {'a' , 'b' , 'c' , 'd' , 'e''f''g''h'};
 
        
 
        System.out.println("찾고자하는 문자 입력 : ");
 
        //반복을 통해서 하나씩 비교해보기
 
        char search = (charSystem.in.read();
 
        
 
        //flag 변수를 지정해준다.
 
        boolean flag = false;
 
        //data.length변수는 데이터 수 범위는 데이터 양만큼 지정한다.
 
        for(int i=0; i<data.length; i++) {
 
            //실제 저장된 데이터를 비교한다.
 
            if(search == data[i]) {
 
                System.out.println("찾았다.");
 
                break;
 
            }
 
            else {
 
                flag = false;
 
            }
 
            
 
        }
 
        
 
        if(flag == true) {
 
            System.out.println("찾았다.");
 
        }
 
        else {
 
            System.out.println("못찾았다.");
 
        }
 
    }
 
}
cs


※ 결과값

찾고자하는 문자 입력 : o

o

못찾았다.



<이분검색(bynary)>

a, b, c, d, e, f, g, h, i

전체 데이터의 중간 위치를 선택한다.

중간 데이터가 찾는 데이터인지 비교(찾으면 다행)

찾고자 하는 데이터가 어느방향인지 선택 (왼, 오)

전체 데이터의 반을 검색하여 비교.

반씩 개수를 줄여나간다.

위의 과정을 반복


<정렬>

그렇다면 '정렬'은 어떻게 할 수 있을까?

방법은 여러가지다. 오름차순, 내림차순...

정렬은 알고리즘의 핵심개념 중의 하나로

방대한 데이터를 처리할 때 매우 중요하다.


보통 알고리즘에서 기초적으로 배우는 정렬은 

'버블정렬, 선택정렬, 삽입정렬'이다.

그 중에서 '버블정렬, 선택정렬'을 알아보자.


알고리즘과 정렬은 그림으로 그려가면서 이해해야 한다. 

정렬을 알아가기 그 이전에 먼저 알아야만 하는 알고리즘이 있다.

바로 swap 알고리즘 이다.


<swap 알고리즘>


두 개의 값을 교환해보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
int i = 10, j = 20;
System.out.println(i + ",  " + j);
/*    
//컴퓨터는 한 번에 하나씩 값을 처리하기 때문에 값을 교환할 수없다.
i = j;
j = i;
System.out.println(i + ", " + j);
*/
int k;
= i;
= j;
= k;
System.out.println(i + " , " + j);   
cs


swap 알고리즘이란

두 개의 값을 교환할 때는 결코 두개의 변수로만 할 수 없으며 

반드시 하나의 임시변수가 있어야 함을 말한다.


<버블정렬>

서로 이웃하는 것끼리 비교정렬


내림차순 : 큰 값이 뒤로가고 작은 값이 앞으로

오름차순 : 큰 값이 앞으로 오고 작은 값이 뒤로


아래숫자를 내림차순으로 정리해보자.

앞에 데이터와 뒤에 데이터를 

하나씩 비교하여 자리를 바꾸어 준다.


예를 들어


왼                       오

6        3        7      5  <첫번째 반복>

↓      ↓       ↓     ↓

3        6        7      5

↓      ↓       ↓     ↓

3        6        7      5

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

3        6        5      7   <두번째 반복>

↓      ↓       ↓     ↓

3        6        5      7

↓      ↓       ↓     ↓

3        5        6      7

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

3        6        5      7   <세번째 반복>

↓      ↓       ↓     ↓

3        5        6      7

↓      ↓       ↓     ↓

3        5        6      7   

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

3        5        6      7  <결과>


데이터의 갯수가 4개일 때 3번 비교해서 1번의 반복이 끝났다.


시간복잡도 = n^2


<데이터 비교횟수 구하기>

비교횟수 = 데이터의 개수 - 1


버블 소트의 이름은 왜 버블 소트일까?

아마도 버블처럼 값을 한 묶음씩 비교해서라고 추측한다.


public class BubbleSort {

    public static void main(String[] args){

        // TODO 버블정렬

        int data[] = {6, 3, 7, 5};

        

        //비교횟수 = 데이터의 개수 -1

        for(int row=0; row<data.length-1; row++) {

            for(int col=0; col<data.length-1; col++) {

                if(data[col]<data[col+1]) {

                    int temp = data[col];

                    data[col] = data[col+1];

                    data[col+1] = temp;

                }

            }

        }

        

        System.out.println("결과 : ");

        for(int i=0; i<data.length; i++) {

            System.out.print(data[i] + "\t");

        }

    }

}


※ 결과값

결과 :

7    6    5    3    



<선택정렬>

기준을 하나 정하고 비교대상과 비교정렬

기준점이 있으면 기준 이후 혹은 이전의 비교 대상들과 비교를 해서 

기준이 되는 자리에 원하는 값을 집어넣는다.


public class SelectionSort {

        public static void main(String[] args) {

            //TODO 선택정렬

            int data[] = {6, 3, 7, 5};

            

            //비교횟수 = 데이터의 개수 -1

            for(int row=0; row<data.length-1; row++) {

                for(int col=row+1; col<data.length; col++) {

                    if(data[row]<data[col]) {

                        int temp = data[row];

                        data[row] = data[col];

                        data[col] = temp;

                    }

                }

            }

            

            System.out.println("결과 : ");

            for(int i=0; i<data.length; i++) {

                System.out.print(data[i] + "\t");

            }    

            

        }

}



※ 결과값


결과 :

7    6    5    3    




<이클립스 팁!>

ctrl + space

sysout + ctrl + space = System.out.println();

alt + ↓ or ↑ = 소스코드 한 줄 이동


4. 다차원 배열 (2차원 배열 이상)


일차원 배열을 하나로 합친 것이 

이차원 배열이다.

이차원배열과 이차원 배열을 합친 것이 삼차원 배열이다.


행과 열의 위치로

차원 = 어떻게 묶어 나가는가?

1차원 + 1차원 = 2차원

2차원 + 2차원 = 3차원


[]대괄호 개수가 차원을 나타낸다.


public class MultiDimension {

    public static void main(String[] args) {

        

        

        // TODO 다차원 배열

        int[] arr1 = {1, 2, 3, 4, 5};

        int[] arr2 = {6, 7, 8, 9, 10};

        int[] arr3 = {11, 12, 13, 14, 15};

        

        //[]대괄호의 개수가 차원

        int[][]arr4 = new int[3][5];

        arr4[0][0] = 1;

        arr4[0][1] = 2;

        arr4[0][2] = 3;

        arr4[0][3] = 4;

        arr4[0][4] = 5;

        

        arr4[1][0] = 6;

        arr4[1][1] = 7;

        arr4[1][2] = 8;

        arr4[1][3] = 9;

        arr4[1][4] = 10;

        

        arr4[2][0] = 11;

        arr4[2][1] = 12;

        arr4[2][2] = 13;

        arr4[2][3] = 14;

        arr4[2][4] = 15;

        

        

        for(int row=0; row<3; row++) {

            for(int col=0; col<5; col++) {

                System.out.print(arr4[row][col] + "\t");

            }

            System.out.println();

        }

    }

}


※ 결과값

1    2    3    4    5    

6    7    8    9    10    

11    12    13    14    15    


초기화를 조금 더 편하게 하려면 어떻게 해야할까?


public class MultiDimension {

    public static void main(String[] args) {

        

        // TODO 다차원 배열

        int[] arr1 = {1, 2, 3, 4, 5};

        int[] arr2 = {6, 7, 8, 9, 10};

        int[] arr3 = {11, 12, 13, 14, 15};

        /*

        //[]대괄호의 개수가 차원

        int[][]arr4 = new int[3][5];

        arr4[0][0] = 1;

        arr4[0][1] = 2;

        arr4[0][2] = 3;

        arr4[0][3] = 4;

        arr4[0][4] = 5;

        

        arr4[1][0] = 6;

        arr4[1][1] = 7;

        arr4[1][2] = 8;

        arr4[1][3] = 9;

        arr4[1][4] = 10;

        

        arr4[2][0] = 11;

        arr4[2][1] = 12;

        arr4[2][2] = 13;

        arr4[2][3] = 14;

        arr4[2][4] = 15;

        */

        

        //다차원 배열은 배열의 수 만금 중괄호로 묶어주어야한다.

        //줄바꿈을 해주면 보기가 편하다.

        int[][]arr4 = {{1,2,3,4,5},

                       {6,7,8,9,10},

                       {11,12,13,14,15}};

        

        

        for(int row=0; row<3; row++) {

            for(int col=0; col<5; col++) {

                System.out.print(arr4[row][col] + "\t");

            }

            System.out.println();

        }

    }

}


※ 결과값

1    2    3    4    5    

6    7    8    9    10    

11    12    13    14    15    


삼차원 배열을 어떻게 해야할까?

삼차원 배열에서 부터는 입체감이 생긴다.

면의 개수가 하나씩 더 생긴다.


public class MultiDimension {

    public static void main(String[] args) {

        int[][] arr4 = { { 1, 2, 3, 4, 5 },

                         { 6, 7, 8, 9, 10 },

                         { 11, 12, 13, 14, 15 } };

        

        int[][] arr5 = { { 1, 2, 3, 4, 5 },

                         { 6, 7, 8, 9, 10 },

                         { 11, 12, 13, 14, 15 } };

        // int arr6[][][] = new int[2][3][5];

        int[][][] arr6 = { { { 1, 2, 3, 4, 5 },

                             { 6, 7, 8, 9, 10 },

                             { 11, 12, 13, 14, 15 } },

                           { { 1, 2, 3, 4, 5 },

                             { 6, 7, 8, 9, 10 },

                             { 11, 12, 13, 14, 15 } } };

        for (int a = 0; a < 2; a++) {

            for (int b = 0; b < 3; b++) {

                for (int c = 0; c < 5; c++) {

                    System.out.print(arr6[a][b][c] + "\t");

                }

                System.out.println();

            }

            System.out.println();

        }

    }

}


※ 결과값

1    2    3    4    5    

6    7    8    9    10    

11    12    13    14    15    

1    2    3    4    5    

6    7    8    9    10    

11    12    13    14    15    


<불규칙배열>

각 행마다 열의 길이를 다르게 할 수 있는 배열 

불필요한 공간을 줄일 수있다.

그러나 이 방법보다 더 좋은 방법이 나와서

잘 쓰지는 않기 때문에 개념만 알아두고 넘어간다.


char [] name1 = {'홍', '길', '동'};

char [] name2 = {'T', 'o', 'm'};

char [] name3 = {'J', 'o', 'h', 'n', 's', 'o', 'n'};

char [] name4 = {'J', 'a', 'n', 'e'};


//char[][] names = new char[4][7];


char[][] names = new char[4][];

...

names[0] = new char[3];

names[0][0] = '홍';

names[0][1] = '길';

naems[0][2] = '동';

...

names[1] = new char[3];





지금까지 배열 공부를 총 정리하며 신나게 학점을 구해봅시다.


public class Sunjuk_v1 {

    public static void main(String[] args) {

        // TODO 1차원 배열을 이용한 성적표

        // 번호, 국어,영어는 값을 입력함

        int[] no = { 1, 2, 3 };

        int[] kor = { 98, 76, 85 };

        int[] eng = { 90, 55, 73 };

        // 총점, 평균, 학년, 순위는 변수선언만 함.

        int[] tot = new int[3];

        int[] avg = new int[3];

        char[] grade = new char[3];

        int[] rank = new int[3];

        // 총점 구하기

        for (int i = 0; i < no.length; i++) {

            tot[i] = kor[i] + eng[i];

        }

        // 평균구하기

        for (int i = 0; i < no.length; i++) {

            avg[i] = tot[i] / 2;

        }

        // 학점 구하기

        for (int i = 0; i < no.length; i++) {

            if (avg[i] >= 90)

                grade[i] = 'A';

            else if (avg[i] >= 80)

                grade[i] = 'B';

            else if (avg[i] >= 70)

                grade[i] = 'C';

            else if (avg[i] >= 60)

                grade[i] = 'D';

            else

                grade[i] = 'F';

        }

        // 등수 구하기

        

        

        System.out.println("***성적결과***");

        System.out.println("학번\t국어\t영어\t총점\t평균\t학점");

        System.out.println("---------------------------------------------");

        for (int i = 0; i < no.length; i++) {

            System.out.println(no[i] + "\t" + kor[i] + "\t" + eng[i] + "\t"

                            + tot[i] + "\t " + avg[i] + "\t" + grade[i]);

            }

        

            System.out.println("정렬 후.......");

            for (int row = 0; row < no.length - 1; row++) {

                for (int col = row + 1; col < no.length; col++) {

                    if (avg[row] < avg[col]) {

                        int iTemp = no[row];

                        no[row] = no[col];

                        no[col] = iTemp;

                        iTemp = kor[row];

                        kor[row] = kor[col];

                        kor[col] = iTemp;

                        iTemp = eng[row];

                        eng[row] = eng[col];

                        eng[col] = iTemp;

                        iTemp = tot[row];

                        tot[row] = tot[col];

                        tot[col] = iTemp;

                        iTemp = grade[row];

                        grade[row] = grade[col];

                        grade[col] = (char) iTemp;

                    }

                }

            }

            System.out.println("***성적결과***");

            System.out.println("학번\t국어\t영어\t총점\t평균\t학점");

            System.out.println("---------------------------------------------");

            for (int i = 0; i < no.length; i++) {

                System.out.println(

                        no[i] + "\t" + kor[i] + "\t" + eng[i] + "\t" + tot[i] + "\t " + avg[i] + "\t" + grade[i]);

        }

    }

}


※결과값

***성적결과***

학번    국어    영어    총점    평균    학점

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

1    98    90    188     94    A

2    76    55    131     65    D

3    85    73    158     79    C

정렬 후.......

***성적결과***

학번    국어    영어    총점    평균    학점

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

1    98    90    188     94    A

3    85    73    158     65    C

2    76    55    131     79    D



★ 연습문제 ★


예제에 있는 버블 반복을 한 번씩 줄여본다.

학점구하기에서 등수 구해본다.



어제 만든 학점관리 프로그램을 바꾸어 보자

참고로 배열은 같은 형식만 묶을 수 있다.


public class Sunjuk_v2 {

    public static void main(String[] args) {

        // TODO 2차원 배열을 이용한 성적표

        

        //배열은 같은 형식 끼리만 묶을 수 있다.

        //3행 6열로 데이터를 배열해준다.

        int[][] sungjuk = {

            {1, 98, 90, 0, 0, 0},

            {2, 76, 55, 0, 0, 0},

            {3, 85, 73, 0, 0, 0}

        };

        char[] grade = new char[3];

        

        // 총점 구하기

        for (int i = 0; i < 3; i++) {

            sungjuk[i][3] = sungjuk[i][1] + sungjuk[i][2];

        }

        // 평균구하기

        for (int i = 0; i < 3; i++) {

            sungjuk[i][4] = (sungjuk[i][1] + sungjuk[i][2]) / 2;

        }

        // 학점 구하기

        for (int i = 0; i < 3; i++) {

            if (sungjuk[i][4] >= 90)

                grade[i] = 'A';

            else if (sungjuk[i][4] >= 80)

                grade[i] = 'B';

            else if (sungjuk[i][4] >= 70)

                grade[i] = 'C';

            else if (sungjuk[i][4] >= 60)

                grade[i] = 'D';

            else

                grade[i] = 'F';

        }

        // 등수 구하기

        

        System.out.println("***성적결과***");

        System.out.println("학번\t국어\t영어\t총점\t평균\t학점\t순위");

        System.out.println("---------------------------------------------");

        for (int i = 0; i < sungjuk.length; i++) {

            System.out.println(sungjuk[i][0] + "\t" + sungjuk[i][1] + "\t" + sungjuk[i][2] + "\t"

                            + sungjuk[i][3] + "\t " + sungjuk[i][4] + "\t" + grade[i] + "\t" + sungjuk[i][5]);

            }

            

            System.out.println("정렬 후.......");

            

            //2차원 배열은 값을 바꾸지 않고 행의 주소를 바꾸면 된다.

            for (int row = 0; row < sungjuk.length-1; row++) {

                for (int col = row+1; col < sungjuk.length; col++) {

                    if (sungjuk[row][4] < sungjuk[col][4]) {

                        int[] rowTemp = sungjuk[row];

                        sungjuk[row] = sungjuk[col];

                        sungjuk[col] = rowTemp;

                        

                        char gradeTemp = grade[row];

                        grade[row] = grade[col];     

                        grade[col] = gradeTemp;

                    

                    }

                }

            }

            System.out.println("***성적결과***");

            System.out.println("학번\t국어\t영어\t총점\t평균\t학점\t순위");

            System.out.println("---------------------------------------------");

            for (int i = 0; i < sungjuk.length; i++) {

                System.out.println(sungjuk[i][0] + "\t" + sungjuk[i][1] + "\t" + sungjuk[i][2] + "\t"

                                + sungjuk[i][3] + "\t " + sungjuk[i][4] + "\t" + grade[i] + "\t" + sungjuk[i][5]);

                

        }

    }//main end

}//class end


※ 결과값

***성적결과***

학번    국어    영어    총점    평균    학점    순위

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

1    98    90    188     94    A    0

2    76    55    131     65    D    0

3    85    73    158     79    C    0

정렬 후.......

***성적결과***

학번    국어    영어    총점    평균    학점    순위

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

1    98    90    188     94    A    0

3    85    73    158     79    C    0

2    76    55    131     65    D    0




2차원 배열은 배열명.length를 했을 때 행의 개수 만큼 돈다.

2차원 배열 부터는 비교 할 때 값을 바꿀 필요 없이 행의주소만 바꾸면된다.


배열에서는 문자열을 잘 쓰지 않는다.

문자열은 일일히 주소값을 저장해서불러오기 불편하기 때문이다.

그래서 배열은 숫자값만 이용한다.


그러면 어떻게 해야할까?


자바에서는 개발자가 문자열을 쓰기편하도록 

문자열 전용 클래스를 만들었는데 바로 그것이 string이다.


6. String


문자나 문자열은 배열처리하지말고 String 클래스를 이용한다.

string 클래스는 배열을 쉽게 쓸 수 있도록 클래스로 만든 하나의 1차원 배열 클래스이다


모든 클래스는 반드시 인스턴스가 있어야 한다.

그렇기 때문에 String클래스도 인스터스를 선언한다.


그럼 String클래스를 배열로 만들 수는 없을까?

결론적으로 할 수 있다.


다만, String 클래스가 원래 배열을 클래스로 만든 것이기 때문에

자바에서는 개발자가 복잡하지 않도록 String클래스를 

다른 배열과 마찬가지 형식으로 만들 수 있도록 했다.


public class StringTest {

    public static void main(String[] args) {

        // TODO String클래스의 기본 사용법

        //모든 클래스는 반드시 인스턴스가 있어야 한다.

        String str = new String();

        str= "홍길동";

        System.out.println(str);

        

        //클래스이기 때문에 이런 선언도 가능하다.

        String str2 = new String("임꺽정");

        System.out.println(str2);

        

        //바로 초기화도 가능하다.

        String str3 = "김유신";

        System.out.println(str3);

        

        //string 클래스를 배열로 만들기

        String[] names = new String[3];

        names[0] = "홍길동";

        names[1] = "임꺽정";

        names[2] = "김유신";

        

        for(int i=0; i <names.length; i++) {

            System.out.println(names[i]);

        }

        

    }

}


※ 결과값

홍길동

임꺽정

김유신

홍길동

임꺽정

김유신



String 클래스의 자세한 설명과 메소드는 Java API를 참조하자.

http://docs.oracle.com/javase/9/docs/api/index.html?overview-summary.html


(String 메서드와 사용법 API에서 어떤 메서드인지, 용례가 무엇인지 정리해보자)


그렇다면 String 클래스의 특징은 무엇일까?


1) 자바는 문자열을 객체로 취급한다.


객체로 만들어져있다는 것은 클래스로 만들어져 있다는 이야기고 

클래스로 만들어져 있다는 것은 변수나 메소드를 쓸 수 있다는 것이다.

문자열을 변수로 담아서 쓸 수도 있고, 문자열 자체에서 . 을 찍어 쓸 수도 있다.


String class 가 제공하는 메소드를 예제와 함께 살펴보자


public class StringTest2 {

    public static void main(String[] args) {

        // TODO String클래스가 제공하는 기능들

        

        String str1 = "java";

        String str2 = "java";

        

        //.equauls 는 String에서 값을 비교하는 메서드이다.

        System.out.println(str1.equals(str2));

        //자바는 문자열을 객체로 취급하기 때문에 . 으로 변수의 값을 가져올 수 있다.

        System.out.println("java is mylife".equals(str2));

        

        String str3 = "java is beautiful";

        String str4 = "java";

        

        //.compareTo는 앞의 문자열과 뒤의 문자열을 아스키코드값 숫자로 비교한다.

        //.compareTo는 리턴값이 세가지 있다. 양수, 0, 음수

        //음수가 나올 때는 뒤의 문자열이 크다는이야기다.

        //str3과 str4의 문자열이 달라지는 지점에서 아스키 코드의 차이를 비교해서 뺀 값을 저장한다.

        //.compareTo는 문자를 구별하는 게임에 넣어주면 재밌다.

        System.out.println(str3.compareTo(str4));

        

        //.charAt지정된 위치에서 한 글자를 추출하는 메서드

        //3번째 위치에 한 글자를 가져오겠다.

        System.out.println(str3.charAt(3));

        

        //.indexOf 문자, 문자열이 왼쪽부터 어느 위치에 있는지 찾아준다.

        //str3 문자열에서 is라는 문자가 어느 위치에 있는가?

        System.out.println(str3.indexOf("is"));

        System.out.println(str3.indexOf("a"));

        //.lastIndexOf 문자, 문자열이 가장 오른쪽 부터 어느위치에 있는지 순번은 왼쪽부터 센다.

        System.out.println(str3.lastIndexOf("a"));

        //찾고자 하는 단어가 없다면 -1이 나온다.

        //.indexOf는 주로 검색용도로 해당 단어가 있는지 없는지를 찾을 때 더 많이 나온다. 예)순차검색

        System.out.println(str3.lastIndexOf("love"));

        

        //.substring(시작위치, 끝위치) 은 문자의 일부분을 추출할 때 사용

        //첫번째 시작 위치는 0부터 시작하지만, 2번째 끝위치는 1부터 시작한다. 그래서 i만 나온다.

        System.out.println(str3.substring(5, 6));

        //이번에는 is가 모두 나온다.

        System.out.println(str3.substring(5, 7));

        //특정위치 구간에 있는 문자를 추출할 때 사용

        System.out.println(str3.substring(5));

        

    }

}


※ 결과값

true

false

13

a

5

1

10

-1

i

is



2) java.lang이라는 폴더에 있는 클래스이다.


3) 동일한 인스턴스를 중복해서 만들지 않는다.

    - 메모리 스캔으로 똑같은 값을 저장하지 않고 주소를 복사한다.


public class StringTest3 {

    public static void main(String[] args) {

        // TODO String클래스의 주요 특징

        //new를 쓰지 않으면 String 클래스는 중복값을 체크해 인스턴스를 만들지 않고 주소를 복사한다.

        String str1 = "java";

        String str2 = "java";

        

        //값이 같은지 체크

        System.out.println(str1.equals(str2));

        //주소가 같은지 체크

        System.out.println(str1 == str2);

        

        //new를 쓰면 강제로 인스턴스가 만들어진다.

        String str3 = new String("java");

        System.out.println(str3.equals(str2));

        System.out.println(str3 == str2);

    }

}


※ 결과값

true

true

true

false





4) 절대 수정 불가능 하다. (고칠 수 없다. 덮어 씌우는 것도 안된다.)


수정을 하면 인스턴스를 새로 만들고 기존의 값은 쓰레기 값이 된다.



public class StringTest3 {

    public static void main(String[] args) {

        // TODO String클래스의 주요 특징

        /*

        //new를 쓰지 않으면 String 클래스는 중복값을 체크해 인스턴스를 만들지 않고 주소를 복사한다.

        String str1 = "java";

        String str2 = "java";

        

        //값이 같은지 체크

        System.out.println(str1.equals(str2));

        //주소가 같은지 체크

        System.out.println(str1 == str2);

        

        //new를 쓰면 강제로 인스턴스가 만들어진다.

        String str3 = new String("java");

        System.out.println(str3.equals(str2));

        System.out.println(str3 == str2);

        */

        

        //String 클래스는 다른 문자열로 바꿔쓰면 인스턴스를 새로 만든다.

        //그러므로 기존 문자열은 쓰레기 값이 된다.

        String str1 = "javu";

        str1 = "java";

        

        //.concat 앞에 있는 문자열과 뒤에 있는 문자열을 연결해주는 메소드

        String str2 = str1.concat(" is number one");

        System.out.println(str2);

        System.out.println(str1 == str2);

        

        

    }

}


※ 결과값

java is number one

false



동일한 인스턴스를 중복해서 만들지 않고 수정이 

불가하다는 것은 메모리를 알뜰하게 쓴다는 면에서 좋다.


하지만, 인스턴스를 중복해서 만들지 않으려고 하기 때문에 

메모리 스캔을 해야해서 리소스가 많이 잡아먹고,

코딩을 하다보면 수정할 일이 생길 때가 있다.


이런 String클래스의 불편함을 해소하기위 해 나온 클래스가 있다.


5. StringBuffer, StringBuilder


- 수정이 가능하다. 문자열을 자주 수정되는 경우는 StringBuffer, StringBuilder를 사용하면 된다.

- 특히 StringBuffer는 예전부터 있었기 때문에 호환성이 더 좋다.

- 사용방법은 String과 같으나 사용할 수 있는 메서드가 String 보다는 제한적이다.

- 기본 데이터 타입은 캐스팅이 되지만 클래스는 캐스팅이 될 수 없다.



public class StringTest3 {

    public static void main(String[] args) {

        // TODO String클래스의 주요 특징

        

        //String 클래스는 다른 문자열로 바꿔쓰면 인스턴스를 새로 만든다.

        //그러므로 기존 문자열은 쓰레기 값이 된다.

        String str1 = "javu";

        str1 = "java";

        

        //.concat() 앞에 있는 문자열과 뒤에 있는 문자열을 연결해주는 메소드

        String str2 = str1.concat(" is number one");

        System.out.println(str2);

        System.out.println(str1 == str2);

        

        //기본 데이터 타입은 캐스팅이 되지만 클래스는 캐스팅이 될 수 없기 때문에 new로 인스턴스를 생성한다.

        StringBuffer sb1 = new StringBuffer("java");

        //.append()앞에 있는 문자열과 뒤에 있는 문자열을 연결해주는 메소드 (.concat 과 같음)

        StringBuffer sb2 = sb1.append("is number one" );

        //주소가 같다고 나오기 때문에 수정이 된 것이 증명됨.

        System.out.println(sb1 == sb2);

        

    }

}


※ 결과값

java is number one

false

true




java.util.Scanner scan = new java.util.Scanner();

입력을 받을 때 편하게 해주는 장치이다.


여기서 Scanner는 껍데기이다.

어떤 장치를 넣을 때 편하게 해주는 매개이다. (Scanner에 입력해야한다.)

키보드에서 입력을 할 때 편한 장치를 해줘야한다.

System.in 이라는 참조변수가 키보드의 주소값이다.

System.out모니터의 주소값



1차원, 2차원 배열을 이름과 점수를 입력받아 출력하는 프로그램을 만들어보자.



public class ScannerTest {

    public static void main(String[] args) {

        // TODO Scanner 클래스의 간단 사용법

        //java.lang. = 가장 기본적인 폴더. 생략해도 된다.

        //이외에 다른 폴더는 반드시 이름을 써야한다.

        java.util.Scanner scan = new java.util.Scanner(System.in);

        System.out.print("이름입력");

        

        String name = scan.next();

        System.out.println("당신의 이름은 " + name + " 이다.");

        //java.lang. = 가장 기본적인 폴더. 생략해도 된다.

        System.out.println("숫자를 마음껏 입력 : ");

        int num = scan.nextInt();

        System.out.println("입력한 숫자 : " + num);

        

        System.out.println("실수 입력 : ");

        double dnum = scan.nextDouble();

        System.out.println("입력한 실수 : " + dnum);

                

    }

}


※ 결과값

이름입력 마봉춘

당신의 이름은 마봉춘 이다.

숫자를 마음껏 입력 :

0416

입력한 숫자 : 416

실수 입력 :

503.65

입력한 실수 : 503.65


7. 명령행인자 (Command Line Argument)


- 명령행 : 사용자가 입력 할 수 있는 상태

- 인자 : 메소드가 호출 할 때 넘어가는 실제값

- 명령행 인자 : 메소드를 호출할 때 값을 넘겨주는 방법을 코드가 아닌 실행 할 때 하겠다.



사용자가 원하는 Dos 에서 값을 입력하면

단순히 프로그램만 실행하는 것이 아니라 인자값도 같이 넘겨준다.


그렇다면 이런 명령행인자는 인자값을 넘길 때 

실인자를 받아 줄 수 있는 매개변수는 어디에 있을까?

main 메서드의 args가 실행할 때 덤으로 넘어오는 명령행인자를 받아와서 처리한다.

ars는 String 배열로 되어있어 String[] args 가 된다.


public class CmdLineTest {

    public static void main(String[] args) {

        //TODO 명령행인자 테스트

        //첫번째 문자 출력

        //이클립스에서는 실행하기 복잡하기 때문에 Dos 창에서 실행해보자.

        System.out.println(args[0]);

        

        

    }

}




이클립스에서는 실행하기 복잡하기 때문에 Dos 창에서 실행해보자.

cmd 창에서 java 명령어를 이용해서 명령행 인자를 테스트하면,

인자를 두 개를 입력하는 방법은 없을까?


public class CmdLineTest {

    public static void main(String[] args) {

        //TODO 명령행인자 테스트

        //첫번째 문자 출력

        //이클립스에서는 실행하기 복잡하기 때문에 Dos 창에서 실행해보자.

        System.out.println(args[0]);

        System.out.println(args[1]);

        

    }

}



값을 주지 않으면 에러가 나지만, 인자를 두개를 입력하면 에러가 나지 않고 인자가 출력된다.

인자의 구분은 공백으로 한다.


그런데 내가 원하는 만큼 인자의 값을 입력하는 방법은 없을까?


public class CmdLineTest {

    public static void main(String[] args) {

        //TODO 명령행인자 테스트

        //첫번째 문자 출력

        //이클립스에서는 실행하기 복잡하기 때문에 Dos 창에서 실행해보자.

        //System.out.println(args[0]);

        //System.out.println(args[1]);

        

        for(int i=0; i<args.length;i++) {

            System.out.println(args[i]);

        }

    }

}



이렇게 명령행인자는 프로그램이 처음 실행될 때 한 번 입력을 받아 메인 메소드에 전달한다.

윈도우에서 실행할 때는 거의 해당이 없지만 도스에서는 해당이 된다. 


이런 기능이 있다는 것을 알아두자.


    //void : 리턴값이 없다. (가상머신이 main찾는데 가상머신에게 리턴하지 않는다.)

    //main 메서드도 시스템이 찾는 콜백메서드이다.

    //(String[] args)는 명령행 인자를 위한 매개변수이다.

   public static void main(String[] args)


<참고>


배열에서는 길이를 알아낼 때 length라는 변수를 썼지만,

String클래스는 .length()라는 메소드를 사용한다.


연산자를 이용해 데이터 암호화 및 복호화를 해보자.


public class Encode {

    public static void main(String[] args) {

        //TODO xor연산자를 이용한 데이터 암호화 및 복호화

        

        String original = "X맨은 홍길동이다.";

        //key값과 original을 일대일로 대응시켜 암호화한다.

        //key값이 모자르면 다시 처음으로 돌아와 비교할 수 있도록 한다.

        String key = "D$@?ab10";

        

        String encoding = " ";

        

        int keyCnt = 0;

        //문자 2진수는 정수형으로 바꿀 수 있지만 문자열은 바꿀 수 없다.

        //그러므로 배열로 하나씩 문자를 뽑아 암호로 바꾸어야 한다.

        //배열에서는 길이를 알아낼 때 length라는 변수를 썼지만,

        //String클래스는 .length()라는 메소드를 사용한다.

        for(int i=0; i<original.length(); i++) {

            //글자 하나씩 비교하여 암호화하는 작업을 계속 누적하여 연산하겠다.

            //문자로 바꿔서 캐스팅해준다.

            //key값이 original값과 길이가 다르기 때문에 반복을 따로 돌린다.

            encoding += (char)(original.charAt(i) ^ key.charAt(keyCnt));

            keyCnt++;

            //key는 encoding의 반복이 끝나도 초기화해서 계속 반복해줘야하기 때문에

            if(keyCnt == key.length()) {

                keyCnt = 0;

            }

        }

        

        System.out.println("암호화 : " + encoding);

        

        //복호화는 과제

    }

}



※결과값

암호화 :  만윀혬깚돨을늠




★ 연습문제 ★


간단한 개인정보관리 프로그램 PMS 을 만들어보자.


예) 


PhoneBook

---------

데이터 준비(배열)

홍길동, 111-1111, 서울시 종로구

임꺽정, 222-1111, 서울시 강남구

신돌석, 333-1111, 서울시 노원구



java PhoneBook 홍길동


전번 : 111-1111

주소 : 서울시 종로구


StringBuffur (StringBuilder)


- 반드시 new로 인스턴스를 생성

- 수정가능

- StringBuffur에서는 .eqals(), == 둘다 주소를 비교. 

- String 에서는 .eqals()는 주소비교, ==는 값을 비교. 

  (원래는 둘 다 주소를 비교하는 기능이지만 편의상 ==을 값 비교로 함.)

- .compareTo 만 값을 비교할 때 사용가능.




String 클래스에서 값 비교하기


String 입력 = abc

입력 == "abc" // 같다가 아니다. 주소값비교이다.

입력.equals("abc") //값을 비교해줄 때는 .equals 이다. 



클래스 (Class) part.1



Class를 배우기 전에...


java 는 JVM(Java Virtual Machine) 이 있다.

JVM(Java Virtual Machine)은 OS 이다.

이것은 어떤 의미일까?


C 나 C++등의 언어은 프로그램을 만들때 

운영체제가 가진 기능을 불러다가 쓸 수 있게 만드는 것이다.

이런 각각의 운영체제가 가진 조각들, 기능들을 API라고 말한다.


프로그램을 다른 운영체제에 

맞게끔 바꿔주는 것을 '포팅'이라고 말한다.

이런 포팅은 너무 번거롭고 비용이 많이든다.


그래서 생각해 낸 방법이 메모리에 프로그램 전용의 운영체제를 설치한다면 

이미 있는 운영체제가 무엇이든 상관없이 

똑같은 프로그램을 어디에서나 쓸 수 있도록 해줄 수 있을 것이다.

java의 자바가상머신 JVM(Java Virtual Machine) 이 바로 그런 역할을 한다.


도스에서 자바 파일을 컴파일 할 때 이런 명령어를 친다.


javac 파일 .java


이는 java로 만든 파일을 jvm이라는 

자바가상머신에서 실행할 수 있도록 컴파일 해주는 것이다.


c나 c++은 운영체제 안에서 바로 실행이 가능하지만

java는 가상 머신 안에있는 

실행파일을 운영체제로 실행할 수있도록 해줘야한다.

그게 java라는 프로그램이다. 



Class (Part.1)


1. 특징

1) 묶음 : 변수, 메서드 

2) 캡슐화 단위 : 편리, 보안, 최소 단위

3) 설계도(추상적) -> 인스턴스 : 실제 클레스가 사용할 수 있는 실행공간, 메모리 공간을 인스턴스라고 한다.

4) 데이터 타입의 역할도 한다.    


Loding 하드디스크에 파일을 메모리로 옮긴다.

메모리에 올라가서 실행할 수 있는 공간이 인스턴스이다.

자 이제 본격적으로 인스턴스를 알아보자.


<인스턴스 만들기>

new 옆에는 어떠한 이름으로 클래스(설계도)를 만들것인지 쓴다.

'new +클래스 이름'은 새로운 메모리 공간을 만들겠다는 뜻이다. 

new를 쓰면 계속 인스턴스로 만들어준다.


.은 접근연산자이다.


new ClassDemo1().iValue=10; 처럼 메모리만 만들어 놓고 어딘지 지정을 안해놓으면 안된다.

인스턴스는 ClassDemo1 area1 = new ClassDemo1(); 이런 식으로 

반드시 주소를 저장해놓아야 재사용이 가능하다.


class ClassDemo1{

    int iValue;

    double dValue;

}

public class ClassTest1{

    public static void main(String[] args){

        //인스턴스 만들기

        //new 새로운 메모리 공간을 만들겠다는 뜻이다. new를 쓰면 계속 인스턴스로 만들어준다.

        //new 옆에는 어떠한 이름으로 설계도를 만들것인지 쓴다.

        //.은 접근연산자이다.

        // new ClassDemo1().iValue=10; 처럼 메모리만 만들어 놓고 어딘지 지정을 안해놓으면 안된다.

        // 인스턴스는 반드시 주소를 저장해놓아야 재사용이 가능하다.

        // new를 쓰면 계속 인스턴스로 만들어준다.

        

        ClassDemo1 area1 = new ClassDemo1();

        area1.iValue = 10;

        area1.dValue = 3.14;

        

        System.out.println(area1.iValue + ", " + area1.dValue);

        

        ClassDemo1 area2 = new ClassDemo1();

        area2.iValue = 20;

        

        area1 = area2;

        area1.iValue = 100;

        System.out.println("area1.iValue=" + area2.iValue);

        //area1.Value = area2.iValue 같음

        

    }    

}


※결과값

10,3.14

area1.iValue=100



2. 변수의 종류


1) 선언된 위치에 따라서 구분

클래스 : 인스턴스 변수 (멤버변수 : 클래스안에 있는 실제 멤버, 재산)

메서드 : 변수 (지역변수)


2) 저장되는 내용에 따라서 구분    

- 값 : 변수 (기본 데이터 타입)

- 주소 : 참조 변수 (객체 데이터 타입)

※ 주소를 저장하는 변수에 값을 저장하는 변수를 사용할 수없고 값을 저장하는 변수에는 주소를 저장할 수 없다.



<객체와 Class>


객체지향은 왜 나왔을까?


객체 (Object)


OOP(객체지향 프로그래밍 언어 Object-Oriented Programming)


객체지향프로그래밍 이전에는?


구조적(절차적) 절차지향 프로그래밍으로 대표되는 C언어 등이 전부였다.

이런 절차지향 프로그램은 한덩어리로 프로그램을 짜야한다.

윈도우 나오기 전 DOS 시절에는 프로그램을 혼자 짜는 것이 가능했다.


그러나 윈도우 이후 프로그램의 덩치가 커진 이후는 

한 덩어리로 프로그램을 짜는 것이 어려워졌다.

객체지향 프로그램은 덩치가 커진 프로그램도 생산과 관리가 편리하도록 

각각의 기능을 따로 따로 분리해서 조립할 수 있도록 만들었다.


객체 안에 클래스가 포함되었다고 생각하면 좋지만,

처음에는 클래스와 객체를 같다고 인식하는 것이 편하다.


객체는 반드시 하나의 독립된 기능이 있어야하며, 

다른 곳에서도 분리해 쓸 수 있게끔 해야한다.


예를 들어 자동차의 문이나 타이어는 객체이지만,

자동차 유리파편 조금을 띁는 것은 객체가 아니다.


그렇다면 객체지향 프로그래밍의 특징은 무엇일까?


<객체지향 프로그램의 특징>

 1.Inheritance(상속성) 

    - 소스 없이 실행파일만 있어도 예전에 만든기능을 물려받아서 다시 쓸 수 있는 기능

    - 재사용, 비용절감, 시간절감

    - 가장 화려하고 어려움


 2.Polymorphism (다형성)

    -하나의 객체를 가지고 여러기능을 쓸 수 있도록 하는 것


 3.InCapSulation (캡슐화)

    - 편리함, 보안, 더 이상 쪼갤 수 없는 최소단위 


객체지향의 특징과 java에서 class의 특징과 같기 때문에 객체와 클래스가 같다고 소개한다.


3. 메서드


1) 메서드의 역할

동작(기능)을 구현합니다.


2) 만드는 방법

    리턴타입 메서드명(...){

          기능 구현

     }


3) 사용방법

메서드명(...)



메서드는 왜 쓸까?


public class MethodTest1{

    public static void main(String[] args){

        System.out.println("********************");

        System.out.println("채팅프로그램");

        System.out.println("********************");

        System.out.println("1.방만들기");

        System.out.println("2.나가기");

        System.out.println("입력 : ");

        System.out.println("********************");

        

    }

}


이런 코드가 있다. 

여기서 별을 관리하기 편하게하려면 어떻게 해야할까?


<인자가 없는 방식>

public class MethodTest1 {

    int iValue;

    

    //리턴타입을 알 수 없으면 void

    void line(){

        for(int cnt=0; cnt<20; cnt++){

        System.out.print("*");

        }

        System.out.println();

    }

    public static void main(String[] args){

        //line method를 사용하기 위해 인스턴스를 생성

        MethodTest1 test1 = new MethodTest1();

        

        //메소드 호출

        test1.line();

        System.out.println("채팅프로그램");

        //메소드 호출

        test1.line();

        System.out.println("1.방만들기");

        System.out.println("2.나가기");

        System.out.println("입력 : ");

        //메소드 호출

        test1.line();

        

    }

}


※ 결과값

     [java] ********************

     [java] 채팅프로그램

     [java] *************************

     [java] 1.방만들기

     [java] 2.나가기

     [java] 입력 :

     [java] ******************************


왜 메인 메소드는 인스턴스 하지 않을까?

메인 메소드는 특별한 메소드기 때문에 인스턴스 생성을 하지않는다. (추후에 다룬다)

class가 100개 1000개 있어도 메인메소드는 하나다.

main이라는 메소드는 따로 인스턴스하지 않아도 따로 메모리가 생성된다.


다른 클래스에 메소드 호출하여 특정기능을 쓰는 방식은 아래와 같이 진행된다. 




*메소드 호출 : 해당하는 메소드를 메모리 위치로 건너가 실행시켜준다. 요청했기 때문에 다른 쪽 메모리로 점프한다. 실행이 끝나면 현재 실행위치가 다시 원위치로 돌아간다.


*모듈화(module) : 클래스와 메소드를 분리해서 호출하듯 별도의 기능을 따로 분리하는 것을 모듈화라고 한다.


*인터럽트(interrupt) : 잠깐 하던 일을 방해받으므로 부탁받은 일을 하고 다시 하던일을 계속한다.

예) 라면을 끓이고 있는데 전화가 온다. 그럼 잠깐 전화를 받으면 서 라면을 끓인다.

인터럽트가 걸렸을 때 스택이라는 메모리로 잠시 쌀아 놓는다.


*매개변수(parameter)  : 인자를 받아주기 위한 목적으로 만든 변수


4) 호출방식

   a. 인자(인수)자 없는 방식

       - () 괄호할 때 무언가가 있는 방식

       - 괄호 안에 아무것도 없기 때문에 아무것도 다시들고 가지 않는다.


   b. 인자가 있는 방식

       - ()괄호안에 값을 실인자 혹은 인자라고 한다.

       - 실인자 혹은 인자는 호출할 때 무언가 넘어가는 값이다.

       - 인자있는 매개변수가 있는 경우 인자없는 매개변수를 사용 할 수 없다.

       - 매개변수는 실인자의 형식, 순서 갯수가 똑같이 맞춰서 사용해야한다.

        

   c. 리턴값(반환값)이 있는 방식

       - 돌아올 때 값이 있는 방식을 리턴값(반환이)있는 방식이라고 한다.



5) return

            - 값을 반환한다. 값을 반환할 때는 반드시 1개만 가능하다.

            - return에서 연산을 할 경우 연산된값 1개를 전달한다.

            - 메서드의 강제종료 (리턴을 메서드 중간에 쓰면 강제종료되어 값이 넘어간다.)

            - void 란 값이 없이 빈손으로 돌아간다는 뜻이다. 




<인자가 있는 방식>

public class MethodTest1 {

    int iValue;

    

    //리턴타입을 알 수 없으면 void

    //인자를 받아주기 위한 목적으로 만든 변수를 매개변수(parameter) 라고 하는데 메소드 괄호안에 넣어주며 끝맺음을 할 필요가 없다.

    void line(int count, char type){

        for(int cnt=0; cnt<count; cnt++){

        System.out.print(type);

        }

        System.out.println();

    }

    // 메인 메소드는 특별한 메소드기 때문에 인스턴스 생성을 하지않는다. (추후에 다룬다)

    //class가 100개 1000개 있어도 메인메소드는 하나다.

    public static void main(String[] args){

        //MethodTest1를 사용하기 위한 인스턴스 생성

        MethodTest1 test1 = new MethodTest1();

        

        //메소드 호출

        //인자(argument) 넣음

        test1.line(20, '*');

        System.out.println("채팅프로그램");

        //메소드 호출

        test1.line(25, '-');

        System.out.println("1.방만들기");

        System.out.println("2.나가기");

        System.out.println("입력 : ");

        //메소드 호출

        test1.line(30, '=');

        //매개변수는 실인자의 형식, 순서 갯수가 똑같이 맞춰서 사용해야한다.

        //test1.line(); 인자있는 매개변수가 있는 경우 인자없는 매개변수를 사용 할 수 없다.

        

    }

}



※ 결과값

     [java] ********************

     [java] 채팅프로그램

     [java] -------------------------

     [java] 1.방만들기

     [java] 2.나가기

     [java] 입력 :

     [java] ===========================




<리턴값이 있는 방식>


public class MethodTest2{

    //선언된 위치가 다르기 때문에 변수명을 다른 위치로 해도 상관없다.

    void calc(int num1, int num2){

        int sum = num1 + num2;

        System.out.println("결과 : " + sum);

    }    

    

    public static void main(String[] args){

        int num1=10, num2=15;

        

        System.out.println("두 수의 합계");

        MethodTest2 test = new MethodTest2();

        test.calc(num1, num2);

         

    

    }

}



여기서 메인에서 연산된 num1, num2의 값을 받고 싶어서 

위와 같이 코드를 바꾸어 보았다.

그러나 돌아오는 값이 없기 때문에 되지 않는다.



public class MethodTest2{

    //선언된 위치가 다르기 때문에 변수명을 다른 위치로 해도 상관없다.

    // 리턴하는 값이 있을 경우 돌아오는 형식(타입)을 맞춰 준다.

    

    //4) 메인에서 받은 (num1, num2)를 전달받아 계산

    int calc(int num1, int num2){

        int sum = num1 + num2;

        //'return + 값'은 돌아갈 때 무조건 리턴이 가진 값을 가져가는 것이다.

        //5) (int num1, int num2) 값을 다시 메인메소드로 돌려줌

        return sum;

    }    

    

    public static void main(String[] args){

        int num1=10, num2=15;

        

        System.out.println("두 수의 합계");

        //1) 메소드를 쓸 수 있도록 메모리를 할당하도록 인스턴스 선언

        MethodTest2 test = new MethodTest2();

        //2) num1, num2는 자체데이터이다.

        //3) (num1, num2)의 값을 calc로 보냄

        //6) return으로 받아온 (num1, num2의 값을) hap 변수에 저장

        int hap = test.calc(num1, num2);

        //7) 출력

        System.out.println("결과 : " + hap);

    

    

    }

}


※ 결과값

     [java] 두 수의 합계

     [java] 결과 : 25


코드를 좀 더 줄인다면 이렇게 만들 수 있다.


public class MethodTest2{

    //선언된 위치가 다르기 때문에 변수명을 다른 위치로 해도 상관없다.

    // 리턴하는 값이 있을 경우 돌아오는 형식(타입)을 맞춰 준다.

    

    //4) 메인에서 받은 (num1, num2)를 전달받아 계산

    int calc(int num1, int num2){

        //5) (int num1, int num2) 값을 다시 메인메소드로 돌려줌

        return (num1 + num2);

    }    

    

    public static void main(String[] args){

        int num1=10, num2=15;

        

        System.out.println("두 수의 합계");

        //1) 메소드를 쓸 수 있도록 메모리를 할당하도록 인스턴스 선언

        MethodTest2 test = new MethodTest2();

        //2) num1, num2는 자체데이터이다.

        //3) (num1, num2)의 값을 calc로 보냄

        //6) return으로 받아온 (num1, num2의 값을) test.calc(num1, num2)에서 출력

        System.out.println("결과 : " + test.calc(num1, num2))

    

    }

}



※결과값   

 두 수의 합계

 결과 : 25



<java에서의 메서드와 함수>


메서드 : 클래스 밖에 있는 기능

함수 : 클래스 안에 있는 기능


java에서는 클래스 안에 모든 함수가 있기 때문에 메서드라고 말한다.




4. 메서드의 오버로딩(Overloading) : 중복 정의


- 객체지향 프로그램에만 가지고 있는 특징이다.

- 사용자로 하여금 훨씬 편리한 환경을 제공해준다.

- 반드시 비슷한 기능끼리를 같은 이름으로 묶어줘야 효과가 극대화된다.

- print(), println() 도 오버로딩의 예이다. 오버로딩이 되어 있어 출력을 할 수 있었다.


1) 다형성을 지원

- 객체의 특징 중에 다형성을 지원하는 문법이다.

- 하나의 이름으로 여러개의 메서드, 기능을 수행할 수 있게 함.        


2) 매개변수

- 반드시 ()괄호에 들어간 매개변수로만 구별이 가능하다. (갯수,형식, 순서)

    

<예제>


public class OverloadTest{

    void display(){

        System.out.println("출력 내용이 없음");

        

    }    

    

    void display(int i){

        System.out.println(i);

    

    }    

    

    void display(int i, double d){

        System.out.println(i + ", " + d);

    

    }    

    void display(double d, int i){

        System.out.println(d + ", " + i);

    

    }        

    

    public static void main(String[] args){

        OverloadTest test = new OverloadTest();

        

        test.display(100);

        test.display();

        test.display(200, 3.14);

        test.display(4.5, 300);

    }

}


<결과>


100

출력 내용이 없음

200, 3.14

4.5, 300




5. 생성자 (Constructor)


생성자 메서드는 일회용이기 때문에 리턴타입 자체를 사용하지 않는다. 보내주면 끝이다. 이점을 유의하자.


1) 인스턴스를 생성 

- 메서드는 내가 원하는 기능을 만들 수 있는 반면, 생성자는 인스턴스를 생성하는 용도 밖에 없다.

- 인스턴스를 생성해주는 전용 메서드를 생성자 메서드라고한다.


2) 호출시점

- 인스턴스를 생성할 때(new를 사용할 때) 단 한번만 호출가능하다.

- 코드를 한 번만 쓸 수있다는 것이 아니다.
  처음에 인스턴스를 생성한 그 초기화한 값을 또 쓸 수 없다는 이야기이다.


3) 초기화전용

- 처음 초기화 할 때만 사용한다.


4) 작성방법


메서드명(...){

     초기화 기능

 }


5) 클래스이름과동일하게 메서드명 작성


생성자가 있어야지만 클래스의 인스턴스를 만들 수 있다.


6) 모든 클래스는 예외없이 기본생성자(default constructor)를 가지고있다. 


Q. 만약에 다른 생성자를 만들경우 기본생성자는 어떻게 되나요?


만약에 다른 생성자를 만들경우 더 이상 기본 생성자는 제공되지 않는다.  


기본생성자란 모든 클래스에 기본적으로 존재하는 생성자를 말한다.

기본생성자는 매개변수가 없는 모양으로 나타나 있다.


아무것도 없을 경우에는 기본생성자가 보이지 않지만 

다른 생성자를 만들면 기본 생성자가 사라진다. 

그러므로 다른 생성자를 만들 경우 기본 생성자도 만들어 주어야 한다.


모든 생성자는 인스턴스변수의 값을 0으로 초기화해준다.

그러므로 인스터스 변수의 초기값을 따로 설정하지 않아도 사용할 수 있다.

여기서 초기값은 문자는 '공백', 정수는 '0', 실수는 '0.0'으로 되어있다.


※ 클래스는 변수와 메서드를 묶어준다. 


변수에 바로 값을 넣는 것이 바람직하지 않은 이유는 두 가지이다.

1. 관리 : 값을 넣은 변수의 이름을 다 파악해야한다.


2. 보안 : 잘못된 값이 아닌지 검사 할 틈이 없다.


그렇기 때문에 메서드를 통해 우회적으로 값을 넣는다.


<예제1>

class ConsDemo1{

    int iValue;

    double dValue;

    

    //생성자 메서드는 리턴타입이 없고 클래스 이름이 같아야 한다.

    //생성자를 쓰면 별도로 따로 메서드를 쓸 필요가 없다.

    //1.iValue 와 dValue 의 값을 초기화한다.

    ConsDemo1(int i, double d){

        //검증

        iValue = i;

        dValue = d;    

    }

    

    void setValue(int i, double d){

        //검증

        iValue = i;

        dValue = d;

    }

    

    void print(){

        System.out.println(iValue + ", " + dValue);

    }    

}

public class ConsTest1{

    public static void main (String[] args){

        //2.인스턴스에서 생성자를 호출하여 초기화한 변수를 사용한다.

        ConsDemo1 demo1 = new ConsDemo1(10, 10.0);

        //demo1.iValue = 10;

        //demo1.dValue = 10.0;

        //처음 값을 넣어 초기화

        //demo1.setValue(10, 10.0);

        demo1.print();

        

        System.out.println(demo1.iValue + ", " + demo1.dValue);

        

        //demo1.setValue(20, 20.0);

        //3. 인스턴스에서

        ConsDemo1 demo2 = new ConsDemo1(20, 20.0);

        

    }

}


※ 결과값

10,10.0

10,10.0


<예제2>


class ConsDemo2{

    int iValue;

    /*

    눈에 보이지 않지만 생성자가 있다.

    ConsDemo2(){

    }    

    */

    

    //기본생성자는 별도의 생성자가 생기면 제공되지 않는다.

    ConsDemo2(int i){

        iValue = i;

    }    

    

}

public class ConsTest2{

    public void main(String[] args){

        //ConsDemo2 demo = new ConsDemo2();

                        //메서드 호출                        

        ConsDemo2 demo = new ConsDemo2(10);

    }

}


<예제3>

class ConsDemo2{

    // 변수의 특징 임시입력장소,선언할 때 초기화 해야

    int iValue;

    int dValue;

    //기본생성자는 별도의 생성자가 생기면 제공되지 않는다.

    ConsDemo2(int i){

        iValue = i;

    }    

    

    ConsDemo2(){

    }    

    

}


public class ConsTest2{

    public void main(String[] args){

        /*

        //ConsDemo2 demo = new ConsDemo2();                        

        ConsDemo2 demo = new ConsDemo2();

        //인스턴스에서도 인자값을 넣어 호출할 수 있다.

        ConsDemo2 demo = new ConsDemo2(10);

        */

        

        int i ;

        //System.out.println(i); 그냥하면 오류 남으로

        //ConsDemo2()생성자를 불러주는 인스턴스를 만든다.

        ConsDemo2 demo = new ConsDemo2();

        //생성자 값이 없는 경우 기본으로 변수의 값을 초기화해줘서

        //인스턴스 변수의 초기값은 자연스럽게 0이 된다.

        System.out.println(demo.iValue);

    }

}


※결과값

0


6. Garbage Collection


Garbage Collection은 왜 필요할까요?

인스턴스 : 설게도에 의해서 만들어진 실제 공간

Garbage : 불필요한 인스턴스 (메모리)

이런 Garbage은 메모리 상에 없어지지 않고 남는다.

Garbage Collection은 Garbage 모아서 메모리를 다시 쓸 수 있도록 하기위한 것이다.

메모리 관리는 프로그램에서 매우 중요하지만 개발자가 일일히 메모리를 관리하기란 매우 민감하고 골치아프다.

JVM(자바가상머신)에는 개발자 대신 메모리를 다시 쓸 수 있도록 하는 Garbage Collection 기능이 있다.

 JVM(자바가상머신)는 Garbage가 많이 쌓여있을 때 알아서 메모리 청소를 한다.


개발자가 Garbage Collection을 이용할 일은 없을까요?

개발자가 직접 판단해서 JVM(자바가상머신)에게 Garbage를 Garbage Collection하여 청소해달라고 할 때도 있다.

System.gc()는 JVM에게 Garbage Collection을 해달라고 요청하는 명령어이다. 

finalize()는 Garbage Collection과 가장 밀접한 메서드이다.

finalize()는 JVM이 알아서 Garbage Collection하기 전에 내가 미처 마무리하지 못한 작업들을 호출해준다. Garbage가 사라지기 직전에 호출되는 메서드이다. 

finalize()는 외형만 껍데기만 있는 메서드이며 개발자가 원하는 내용을 고쳐서 넣을 수 있다.


※ callback 메서드

- 개발자가 메서드를 호출하는 것이 아니라 시스템이 필요할 때 호출이 되는 메서드이다.


<예제>

class Fdemo{

    int count;

    

    Fdemo(int i){

        count = i;

    }

    //finalize메서드의 형식은 반드시 아래와 같이 해야한다.

    protected void finalize(){

        System.out.println("GC가동중 : " + count);

    }    

    

}

public class FinalizeTest{

        public static void main(String[] args){

        for(int i = 0; i<1000000; i++){

            new Fdemo(i);

        

        }

    }    

}


<결과값>


GC가동중 : 233221

GC가동중 : 235048

... (중략) ...

GC가동중 : 660742

GC가동중 : 775969


7. this


1) 현재 실행중인 인스턴스의 주소값을 저장

   - 매개변수의 이름과 인스턴스변수의 이름이 같은 경우 

주소값을 알려주기 위해 반드시 this. 를 써야한다.

2) 참조변수 : 인스턴스에 주소를 저장하는 변수

3) read only : 메모리가 할당된 주소값을 마음대로 할당할 수 없다.

4) this() : 현재 실행중인 생성자의주소


this의 사용 예제를 살펴보자


먼저, this를 생략할 수 있는 경우를 살펴보자



<예제>


class ThisDemo1{

    int iValue;

    double dValue;

    

    ThisDemo1(int i, double d){

        //여기서 this.은 인스턴스의 주소값을 가리킨다.

        iValue = i;

        dValue = d;

        /*

        this.iValue = i;

        this.dValue = d;

        */        

    }    

        

    void display(){

            System.out.println(iValue + ", " + dValue);

            //System.out.println(this.iValue + ", " + this.dValue); 처럼 this. 를 생략하고 쓸 수 있다.

    }    

}

public class ThisTest1{

    public static void main(String[] args){

        //눈에 보이지 않는 인자가 숨겨져있다. ((인스턴스의 주소값), 10, 10.0)

        //시스템이 알아서 넣어놓은 참조변수가 this이다. 눈에는 보이지 않는다.

        ThisDemo1 d1 = new ThisDemo1(10, 10.0);

        ThisDemo1 d2 = new ThisDemo1(20, 20.0);

        ThisDemo1 d3 = new ThisDemo1(20, 30.0);

        

        d1.display();

        d2.display();

        d3.display();

    }

}



결과값

10, 10.0

20, 20.0

20, 30.0



매개변수의 이름과 인스턴스변수의 이름이 같은 경우는 어떨까?


<예제>


class ThisDemo1{

    int iValue;

    double dValue;

    

    ThisDemo1(int iValue, double dValue){

        //여기서 this.은 인스턴스의 주소값을 가리킨다.

        //매개변수의 이름과 인스턴스변수의 이름이 같은 경우 주소값을 알려주기 위해 반드시 this. 를 써야한다.

            iValue = iValue;

            dValue = dValue;        

    }    

        

    void display(){

            System.out.println(this.iValue + ", " + this.dValue);

            //System.out.println(iValue + ", " + dValue); 처럼 this. 를 생략하고 쓸 수 있다.

    }    

}

public class ThisTest1{

    public static void main(String[] args){

        //눈에 보이지 않는 인자가 숨겨져있다. ((인스턴스의 주소값), 10, 10.0)

        //시스템이 알아서 넣어놓은 참조변수가 this이다. 눈에는 보이지 않는다.

        ThisDemo1 d1 = new ThisDemo1(10, 10.0);

        ThisDemo1 d2 = new ThisDemo1(20, 20.0);

        ThisDemo1 d3 = new ThisDemo1(20, 30.0);

        

        d1.display();

        d2.display();

        d3.display();

    }

}


※ 결과값

 0, 0.0

 0, 0.0

 0, 0.0



매개변수의 이름과 인스턴스변수의 

이름이 같기 때문에 주소값을 찾지 못하는 것이다.


이처럼 매개변수의 이름과 인스턴스 변수의 이름이 같은 경우 

주소값을 알려주기 위해 반드시 this. 를 써야한다.


<예제>

class ThisDemo1{

    int iValue;

    double dValue;

    

    ThisDemo1(int iValue, double dValue){

        //여기서 this.은 인스턴스의 주소값을 가리킨다.

        //매개변수의 이름과 인스턴스변수의 이름이 같은 경우 주소값을 알려주기 위해 반드시 this. 를 써야한다.

            this.iValue = iValue;

            this.dValue = dValue;        

    }    

        

    void display(){

            System.out.println(this.iValue + ", " + this.dValue);

            //System.out.println(iValue + ", " + dValue); 처럼 this. 를 생략하고 쓸 수 있다.

    }    

}

public class ThisTest1{

    public static void main(String[] args){

        //눈에 보이지 않는 인자가 숨겨져있다. ((인스턴스의 주소값), 10, 10.0)

        //시스템이 알아서 넣어놓은 참조변수가 this이다. 눈에는 보이지 않는다.

        ThisDemo1 d1 = new ThisDemo1(10, 10.0);

        ThisDemo1 d2 = new ThisDemo1(20, 20.0);

        ThisDemo1 d3 = new ThisDemo1(20, 30.0);

        

        d1.display();

        d2.display();

        d3.display();

    }

}


※ 결과값

     10, 10.0

     20, 20.0

     20, 30.0



[참고] JAVA API 문서 찾기


자주쓰는 java.lang.System.out.println() 구문을 살펴보자.


java.lang.System.out.println()

java      // '폴더 경로' 이다.

lang      // '폴더 경로(패키지)' 이다.

System  // 'class'

Out       // 인스턴스 변수이지만 Class 안에 있는 변수이다. 

       // 참조변수 역할을 할 수 있도록 한다. 

       // class 안에 있는 변수이기에 객체라고 말한다.  

println() // '메서드'

.           // 접근하기 위한 접근연산자


※ '참조변수'란?

인스턴스에 주소를 저장하는 변수



jdk java9 메뉴얼에서 System 을 찾아보자

http://docs.oracle.com/javase/9/docs/api/index.html?overview-summary.html


왼쪽 상단

java.base -> java.lang

왼쪽 하단

System

-> System 이 무엇을 의미하느지 알 수 있다.



[참고2] 이클립스를 사용할 때 알아두어야 할 것


워크스페이스 : 여러개의 프로젝트(프로그램)들을 묶어서 관리하는 가장 큰 단위

프로젝트(프로그램) : java 등등...



'개발 > Java' 카테고리의 다른 글

[java] 클래스 (Class) part.2  (0) 2017.10.24
[java] 배열 (Array)  (0) 2017.10.19
[java] 제어문(Control Statement) : 조건문과 반복문  (0) 2017.10.18
[java] Dos에서 Java 컴파일 하기  (0) 2017.10.18
[java] 연산자(Operator)  (0) 2017.10.18
제어문 (Control Statement)

1. 입력기능실습

아스키코드로 숫자 하나를 입력받아보자. 
read 함수는 키보드 하나갚을 받아 아스키코드로 변환해준다. 
input이라는 변수에 저장한다. 아스키코드로 받기 때문에 변수를 기본형 int로 쓴다.

아래 코드를 입력해보자.

class InputTest{
    public static void main(String[] args){
        int input = java.lang.System.in.read();
        System.out.println("입력받은 값 : " + input);
    }

}


이 오류메시지가 뜬다.

입력받을 때 조심해야한다는 오류메시지다. 

자바에게 대신 입력할 것을 검사해달라 코딩을 해본다. 

메인함수 옆에 throws java.io.IOException을 넣어보자


class InputTest{

    public static void main(String[] args) throws java.io.IOException{

        //read 함수는 키보드 하나갚을 받아 아스키코드로 변환해준다.

        //input이라는 변수에 저장한다.

        //아스키코드로 받기 때문에 변수를 기본형 int로 쓴다.

        int input = java.lang.System.in.read();

        System.out.println("입력받은 값 : " + input);

    }

}


※ 결과값

7

입력받은 값 : 55



아스키코드가 아닌 문자를 입력한 그대로 해주려면 캐스팅을 해주면 된다.


class InputTest{

    public static void main(String[] args)throws java.io.IOException{

        

        System.out.print("입력해주세요 : ");

           //read 함수는 키보드 하나갚을 받아 아스키코드로 변환해준다.

        //input이라는 변수에 저장한다.

        //아스키코드로 받기 때문에 변수를 기본형 int로 쓴다.

        int input = java.lang.System.in.read();

        //문자처리를 위해 char로 캐스팅해준다.

        System.out.println("입력받은 값 : " + (char)input);

    }

}


결과값

입력해주세요 : s

입력받은 값 : s



그러나 이경우 숫자를 입력하면 숫자가 아닌 계산할 수 없는 문자로 출력된다. 

다른 방법도 있지만 아직 깊이 배우지 않았기 때문에 꼼수를 써보자. 

아스키코드와의 차이 갚인 48을 빼는 것이다. 

적어도 한자리수의 경우는 제대로 계산할 수 있다.


class InputTest{

    public static void main(String[] args)throws java.io.IOException{

        

        System.out.print("숫자를 입력해주세요 : ");

//입력값에서 48을 빼준다.        

int input = java.lang.System.in.read()-48;

        System.out.println("입력받은 값 : " + input);

    }

}


※ 결과값

숫자를 입력해주세요 : 3

입력받은 값 : 3


그럼 이번에는 입력을 두번 해보자.

문자 출력과 숫자를 출력해보자.


class InputTest{

    public static void main(String[] args)throws java.io.IOException{

        

        System.out.print("입력해주세요 : ");

        //문자를 출력한다.

        int input = java.lang.System.in.read();

        System.out.println("입력받은 값 : " + (char)input);

        

        System.out.print("숫자를 입력해주세요 : ");

        //입력값에서 48을 빼준다.

        input = java.lang.System.in.read()-48;

        System.out.println("입력받은 값 : " + input);

    }

}


※ 결과값


입력해주세요 : 4

입력받은 값 : 4

숫자를 입력해주세요 : 입력받은 값 : -35



결과값이 이상하다. 

분명 코드를 두번 입력 받도록 짰는데 왜 입력을 두번 받지 못하는 것일까? 

이는 소프트웨어가 아닌 하드웨어 문제이다.


우리가 A라는 키보드에서 치는 순간 하드웨어에서는 

메모리(램)에 임시저장했다가 화면에 보여진다. 

이렇듯 램은 임시기억공간이다. 

임시기억공간이라는 측면에서 이는 마치 변수와 같다. 


똑같은 임시기억공간이지만 시스템이, 

컴퓨터가 필요에 의해서 만든 임시기억공간이기 때문에 

변수와 다르게 용어를 Buffer라고 하여구분한다. 


입력한 값은 임시로 저장하기 때문에 '입력 버퍼'라고 부른다.

프린터를 할 때 프로그램을 꺼도 프린트가 계속 되는 

이유도 이러한 임시저장공간인 입력버퍼에 들어가기 때문이다.

(참고로 프린터자체에서 사용하는 메모리를 spool이라고 한다.)


A를 키보드를 치는 그 순간 계속 임시기억장소인 버퍼에 모아둔다. 

버퍼가 있으면 수정을 할 수 있지만 버퍼가 없으면 수정이 불가능하다. 

바로 출력이 되기 때문이다.

이 버퍼라고 불리는 메모리에는 

어떤 위치에 입력값이 저장될지를 알려주는 포인터가 있다.


값이 입력되었을 때 포인터는 

한 칸씩 이동하면서 메모리 어디에 저장될지를 가리킨다.

A를 누를 때 포인터가 메모리에 빈 공간으로 이동한다.


그리고 엔터를 눌었을 때 포인터가 다음 포인터를 이동해야하는데

엔터를 치면 컴퓨터가 입력을 종료한 것으로 알기 때문에 

포인터가 다음으로 이동하지않는다.


엔터키값도 메모리에 저장되기 때문에 포인터가 거기에 머무는 것이다. 

그래서 위의 예제에서 값이 두가지가 입력되지 않았던 것이다.


그럼 이 문제를 어떻게 해결해야 할까?


첫째, 현재 위치에 메모리를 건드려 삭제한다.

둘째, 엔터키 값을 피해서 강제로 포인터를 이동한다.


C언어에서는 둘 다 할 수 있지만 java에서는 두번째 방법밖에 할 수 없다.

엔터키를 건너 뛰려면 자바의 최소단위인 2바이트를 건너뛰어야 한다.


class InputTest{

    public static void main(String[] args)throws java.io.IOException{

        

        System.out.print("입력해주세요 : ");

        //문자를 출력한다.

        int input = java.lang.System.in.read();

        System.out.println("입력받은 값 : " + (char)input);

        

        //메모리에서 엔터값을 피해 2바이트를 건너뛴다.

        System.in.skip(2);

        

        System.out.print("숫자를 입력해주세요 : ");

        //입력값에서 48을 빼준다.

        //똑같은 변수에는 타입을 또 선언하지 않는다.

        input = java.lang.System.in.read()-48;

        System.out.println("입력받은 값 : " + input);

    }

}


※ 결과값

입력해주세요 : r

입력받은 값 : r

숫자를 입력해주세요 : 1

입력받은 값 : 1


이처럼 모든 프로그램에서는 

하드웨어적 지식이 함께 있어야한다.

입력버퍼도 있지만 출력버퍼로 있다.


동일한 메모리지만 용도에 따라 구분이 된다. 

차차 자료구조, 알고리즘으로 나중에 써볼 예정이다.



2. 제어문 종류


- 제어문은 ( ) 괄호가 있다고 해서 함수(메서드)가 아니다.

- JAVA에서는 함수라는 말 대신에 메서드라는 말을 쓴다.


1) 조건문 (Conditional statement)

   - 조건은항상 참이라는 전제를 깔고간다.


A. if문 


<문법1>


1. 한 문장 일 때

 if(조건식)  // 만약에 괄호 안의 조건식이 참이라면

 문장;        // 이 문장을 실행해라 

        

2. 여러 문장 일 때            

if(조건식) {

문장;

문장;

...

}


     

예제를 보자


class IfTest {

        public static void main(String[] args)throws java.io.IOException{

            System.out.print("숫자 입력 : ");

            int num = System.in.read()-48;

            

            

            //입력받은 num변수의 값이 짝수인지 홀수인지

            if((num%2) == 0)

                System.out.println("짝수입니다.");

            //{}를 써도 괜찮고 안써도 괜찮다.

            if((num%2)!= 0) {

                System.out.println("홀수입니다.");

            }    

        }

}


※ 결과값

숫자 입력 : 3

홀수입니다.


첫번째 방법의 단점은 조건이 참이라는 

전제를 깔고들어가기 때문에 

조건이 거짓일 때는 또 if문을 한 번 더 써야한다.


 <문법2>


 if ~ else

if(조건식) {

문장;

문장;

  ...

}

   else {

  문장;

  문장;

         }       

 


짝수와 홀수를 구분하는 프로그램을 짜보자.


class IfTest {

        public static void main(String[] args)throws java.io.IOException{

            System.out.print("숫자 입력 : ");

            int num = System.in.read()-48;

            

            /*

            //if문 첫번째 방법

            //입력받은 num변수의 값이 짝수인지 홀수인지

            if((num%2) == 0)

                System.out.println("짝수입니다.");

            //{}를 써도 괜찮고 안써도 괜찮다.

            if((num%2)!= 0) {

                System.out.println("홀수입니다.");

            */

            

            if((num%2) == 0)

                System.out.println("짝수입니다.");

            else

                System.out.println("홀수입니다.");

        }

}


※ 결과값


숫자 입력 : 3

홀수입니다.


<문제>

입력받는 값이 'a', 'b', 'c'이면 "정답" 이라고 출력하고 

그렇지 않으면 "오답"이라고 출력하세요.


<문법 1의 경우>

class IfTest {

        public static void main(String[] args)throws java.io.IOException{

            System.out.print("정답 입력 : ");

            char result = (char) System.in.read();

            

            if(result == 'a' || result == 'b' || result == 'c'){

                System.out.println("정답");

            }else{

                System.out.println("오답");

            }    

        }

}


※ 결과값

정답 입력 : a

정답



<문법 2의 경우>

class IfTest {

        public static void main(String[] args)throws java.io.IOException{

            System.out.print("정답 입력 : ");

            char result = (char) System.in.read();

            

            if(result >= 'a' && result <= 'c'){

                System.out.println("정답");

            }else{

                System.out.println("오답");

            }    

        }

}




※ 결과값

정답 입력 : d

오답



일반적인 if문인 <문법1>과 <문법2>의 

경우 조건을 하나밖에 못쓴다는 단점이 있다.

그래서 이럴 때는 다중if문을 쓴다. 


<다중if문 문법>


if(조건식){

    문장;

    문장;

      ...

}

else if(조건식) {

    문장;

    문장;

}

else

문장;



<문제>

평균별로 성적을 A~F 까지 등급을 나누시오.


class IfTest {

        public static void main(String[] args)throws java.io.IOException{

            // 다중 if 문

            int avg = 78;

            

            char grade;

            if(avg >= 90)

                grade = 'A';

            else if(avg >=80)

                grade = 'B';

            else if(avg >=70)

                grade = 'C';

            else if(avg >=60)

                grade = 'D';

            else if(avg >=50)

                grade = 'E';

            else

                grade = 'F';

            

            System.out.println("당신의 성적 : " + grade);

            

        }

}


※ 결과값

당신의 성적 : C


여기서 else가 빠지면 오류가나는데 이유는 변수를 초기화를 시켜주지 않아서이다.


변수의 3가지 특징을 기억해보자.


변수의 3가지 특징


첫째, 임시기억장소다.


둘째, 반드시 선언을 해야한다.


셋째, 반드시 초기화를 해야한다.


초기화를 해주어 다시 써보면


class IfTest {

        public static void main(String[] args)throws java.io.IOException{

      

            // 다중 if 문

            int avg = 78;

            

            //변수 초기화

            char grade = 'F';

            if(avg >= 90)

                grade = 'A';

            else if(avg >=80)

                grade = 'B';

            else if(avg >=70)

                grade = 'C';

            else if(avg >=60)

                grade = 'D';

            System.out.println("당신의 성적 : " + grade);

            

        }

}


※ 결과값

당신의 성적 : C



<nested if문> (중첩된 if문)


   - if문 여러개를 합쳐서 사용 할 수있다.

   - if문이 아니라 switch 등 다른 것들도 합쳐서 사용할 수 있다.

   - 이는 문법이 아니라 활용 방법이다.


nested if문 문법


if(조건식) //이 조건식이 참이어야지만 else로 넘어가지 않고 내부 if문이 실행됨.

     문장;

     if(조건식)

         문장;

         else

              문장;

         else

               문장;

            if(조건식)

               문장;



<문제>

어디선가 데이터 3개를 구해왔다고 가정해보자.


<정답>


class IfTest{

    public static void main(String[] args) {

        int a=8, b=7, c=9;

        if(a>b) {

            if(a>c)

                System.out.println("a가 제일 크다");

            else

                System.out.println("c가 제일 크다");

        }

        else{

            if(b>c)

                System.out.println("b가 제일 크다");

            else

                System.out.println("c가 제일 크다");

    }

}


※ 결과값

c가 제일 크다



<문제>

아이디와 패스워드를 입력하면 구분하는 프로그램을 만들자


class IfTest2{

    public static void main(String[] args) throws java.io.IOException{

        //아이디 : 'X', 패스워드 : ?

        System.out.print("ID : ");

        char id =(char)System.in.read();

        

        System.in.skip(2);

        

        System.out.print("PassWord : ");

        char pass = (char)System.in.read();

        

        if(id != 'x') {

            if(pass != '7')

                System.out.println("둘 다 틀림");

            else

                System.out.println("아이디만 틀림");

        }

        else{

            if(pass != '7')

                System.out.println("패스워드만 틀림");

            else

                System.out.println("로그인 성공");

        }

        

    }

}    


※ 결과값

ID : x

PassWord : 7

로그인 성공



B. switch문


<문법>

    switch(변수 또는 수식){

            case 값 :

                  문장;

            case 값 :

                  문장;

            case 값 :

                   문장;

            ...

            [default : 문장;]

    }


    - 다중조건문과 같이 변수가 첫번째 case와 같을 경우 

  두번째 case와 같을 경우 세번째 case와 같을 경우를 비교한다.

    - case 값 사이에 '같다'는 조건식이 생략되어 있다.

    - if 문에 비해 불편하나 코드가 깔끔하여 많이 쓰인다.

    

    <예제>       

   class SwitchTest {

    public static void main(String[] args){

        int data = 1;

        

        switch(data){

            case 1:

                System.out.println("사과");

            case 2:

                System.out.println("배");

            case 3:

                System.out.println("포도");

            default:

                System.out.println("해당 과일 없음");

        }    

    }

}


※ 결과값

사과

포도

해당 과일 없음  

      


그런데 이렇게 코딩을 하면 원하는 

결과가 아니라 결과값이 case별로 모두 나온다. 

에러는 안나지만 원하는 결과가 아니다. 

이럴 때 break를 걸면 원하는 결과값에서 switch문을 멈출 수 있다.


<예제>

class SwitchTest {

    public static void main(String[] args){

        int data = 1;

        

        switch(data){

            case 1:

                System.out.println("사과");

                break;

            case 2:

                System.out.println("배");

                break;

            case 3:

                System.out.println("포도");

                break;

            default:

                System.out.println("해당 과일 없음");

        }    

    }

}    


※ 결과값

사과


switch문은 if문과 동일하지만 코드가 깔끔해서 많이 쓴다. 

switch문 안에 if문을 쓸 수도 있고 if문 안에 switch문을 쓸 수도 있다.  

switch문이 불편한 점이 하나 더 있다. 정수형만 사용이 가능하다.


<예제>

class SwitchTest {

    public static void main(String[] args){

        //실수형으로 할 경우

        double data = 1;

        

        switch(data){

            case 1:

                System.out.println("사과");

                break;

            case 2:

                System.out.println("배");

                break;

            case 3:

                System.out.println("포도");

                break;

            default:

                System.out.println("해당 과일 없음");

        }    

    }

}


※ 결과값

SwitchTest.java:5: error: incompatible types: possible lossy conversion from double to int

                switch(data){

                      ^

1 error



같은 정수형이여도 long은 안된다.


class SwitchTest {

    public static void main(String[] args){

        //실수형으로 할 경우

        long data = 1;

        switch(data){

            case 1:

                System.out.println("사과");

                break;

            case 2:

                System.out.println("배");

                break;

            case 3:

                System.out.println("포도");

                break;

            default:

                System.out.println("해당 과일 없음");

        }

    }

}


※ 결과값

SwitchTest.java:6: error: incompatible types: possible lossy conversion from long to int

                switch(data){

                      ^

1 error



<예제 : 학점 구해보기>

class SwitchTest {

    public static void main(String[] args){

        int avg = 78;

        switch(avg/10){

            case 10:

                System.out.println("grade =" + 'A');

                break;

            case 9:

                System.out.println("grade =" + 'A');

                break;                

            case 8:

                System.out.println("grade =" + 'B');

                break;

            case 7:

                System.out.println("grade =" + 'C');

                break;

            case 6:

                System.out.println("grade =" + 'D');

                break;

            case 4:

                System.out.println("grade =" + 'E');

                break;

            default:

                System.out.println("grade =" + 'F');

        }


※결과값

grade =C

        


★ 조건문 연습문제 ★

1.입력받은 값이 문자이면 "문자"라고 출력하고 그렇지 않으면 "기타"라고 출력하라


a~z비교



<풀이>


class IfHomeWork {

    public static void main(String[] args)throws java.io.IOException{

        System.out.print("문자인가요? : ");

        char result = (char) System.in.read();

        if((result >= 'a' && result <= 'z') || (result >= 'A' && result <= 'Z'))

            System.out.println("문자");

        else

            System.out.println("기타");

                    

    }

}






2.입력받은 값이 소문자이면 소문자라고 대문자이면 대문자라고 숫자이면 숫자라고 출력하라.

    그 외의 값은 기타라고 출력하라.



<풀이>


class IfHomeWork {

    public static void main(String[] args)throws java.io.IOException{

        System.out.print("어떤 글자인가요? : ");

        char result = (char) System.in.read();

        if(result >= 'a' && result <= 'z')

            System.out.println("소문자");

        else if (result >= 'A' && result <= 'Z')

            System.out.println("대문자");    

        else

            System.out.println("숫자");

    }

}

        



3.1~9까지 간단한 전자계산기 프로그램

    연산자 : + (*, -, /)

    숫자 1 : 2

    숫자 2 : 3

    결과 : 2 + 3 = 5


<풀이>


class IfHomeWork {

     public static void main(String[] args)throws java.io.IOException{

        System.out.print("첫번째 숫자");

        int num1 = System.in.read()-48;

        

        System.in.skip(2);

        

        System.out.print("두번째 숫자");

        int num2 = System.in.read()-48;


        System.out.println("덧셈 = " + (num1+num2));

        System.out.println("뺄셈 = " + (num1-num2));

        System.out.println("곱셈 = " + (num1*num2));

        System.out.println("나눗셈 = " + (num1/num2));

        System.out.println("나머지 = " + (num1%num2));

    }

}



2) 반복문(Loop)


반복문은 조심해서 써야한다.


<반복문 유의사항>

첫번째. 무한반복 될 수 있다.

두번째, 반복횟수가 다르면 결과값이 큰 차이가 있다.


<반복문의 기본적인 구조>

초기화 

조건식

카운터


카운터란?

- 반복문을 쓰면 카운터 변수가 따라다닌다. 카운터 변수는 반복문의 반복횟수를 세어준다.



<종류>

while


do~while


for



while문


<while문 문법>

while(조건식){

    문장;

      ...

}


<문제>

* 10개를 while 조건문을 사용해 출력해보자.


class LoopTest1{

    public static void main(String[] args){
        System.out.println("**********");
        
        //초기화 : 반복문의 초기값을 정해준다.
        //카운트하기 편하기 쉬운 숫자를 준다. 일반적으로 0을 준다.
        int cnt = 0;
        //조건식 : 반복횟수를 지정하는 역할을 한다.
        while(cnt<10){
            System.out.print("*");
            //카운터 : 반복문의 반복횟수를 세어준다.
            cnt++;
        }
      
    }
}


※ 결과값

**********
**********


<문제>

1~10까지의 합을 구해보자.
class LoopTest1{
    public static void main(String[] args){
        System.out.println("**********");
        
        //1-10합계를 구하시오.
        int cnt = 0, sum = 0;
        while(cnt<=10){
            //sum값은 누적된다.
            sum += cnt;//sum = sum + cnt;
            cnt++;
        }
        System.out.println("결과 : " + sum);    
        
        
    }
}

※결과값
**********
결과 : 55

<문제>
2의 10승을 구해보자!

class LoopTest1{
    public static void main(String[] args){
        System.out.println("**********");
             
        //2의 10승
        int cnt = 0,sum = 1;
        while(cnt <= 10){
            sum *= 2; // sum = sum * 2;
            cnt++;
        }
        System.out.println("결과 : " + sum);
    }
}

※ 결과값
**********
결과 : 2048 

여기서 카운터는 ++로 1씩 증가하는 것이 가장 안정적이고,
초기값은 0 혹은 1로 하는 것이 안정적이다.
무엇보다 어떻게 하는 것이 가장 실수를 덜할 수 있는지 고민해야한다.

<while문 무한반복 방법>
while(true){
    문장;
}


do while문

<do while 문법>
do {
      문장;
        ...
               }while(조건식);

do ~ while 형식과 기능은 while과 같다.
조건식을 뒤로 넣을 때 쓴다.
최소의 한 번 이상 실행해야 할 때는 do ~ while을 쓴다.
while 과 do ~ while 선택은 취향차이다.

for 문

융통성이 있는 문법이고 개발자들이 선호하는 문법이다.

<for 문법 - 1>
for(초기화; 조건식; 카운터)
    문장;
    
for문은 문장 순서에 유념해야 한다.

순서 : 초기화 > 조건식 > 문장 > 카운터 > 조건식 > 문장 > 카운터...

<예제>
class LoopTest1{
    public static void main(String[] args){
        System.out.println("**********");
        for(int cnt=0; cnt<10; cnt++)
            System.out.print("*");
    }
}


<for문의 구조>
초기화 : 처음 실행되면서 딱 1번만 실행된다.
조건식 : 조건이 거짓이면 1번도 실행 안하고 빠져나간다.
조건식 실행 후 문장까지 넘어간 후 카운터로 돌아간다.

순서 : 초기화 > 조건식 > 문장 > 카운터 > 조건식 > 문장 > 카운터...

class LoopTest1{
    public static void main(String[] args){
         int cnt;
        //조건문 안에 타입을 선언하면 에러가 나는데 이는 변수의 유효범위 때문이다.
        for(cnt=0; cnt<8; cnt++){
            cnt += cnt; // cnt = cnt +cnt;
        }    
        System.out.println("cnt = " + cnt);
            
    }
}

※결과값
**********
cnt = 15

<for 문법 - 2>
for (;조건식 ; 카운터)
       문장;

<for 문법 - 3>
초기화
for(;;카운터){
...
조건식
...
}

<for 문법 - 4>
초기화 
for(;;){
...
조건식
...
카운터
}

<for 문법 - 4>에서 (;;)은 무한반복이다.
무한반복을 해결하기 위해 조건식을 쓴다.
무한반복이 무조건 나쁜 것은 아니다. 
한 예로 서버의 경우는 무한반복이 필요하다.
반복 횟수가 몇 번인지 모를 때는 
반복문을 강제 종료를 해야하는데 어떻게 할까?

<반복문 강제 종료>
1) break; (완전종료)
2) continue; (일시종료)

break와 continue는 반드시 반복문 안에서만 사용해야한다.
swich 문법에서의 break와 continue는 
반복문 전용 문법에서 빌려온 것이기 때문에 예외로 한다.

<예제>
class LoopTest1{
    public static void main(String[] args){
       
        for(int cnt = 0; cnt<10; cnt++){
                if(cnt == 5)
                     break;
                
                System.out.println(cnt);
        }    
    }
}

※결과값
0
1
2
3
4

<예제>
class LoopTest1{
    public static void main(String[] args){
          for(int cnt = 0; cnt<10; cnt++){
                if(cnt == 5)
                     continue;
                
                System.out.println(cnt);
        }    
    }
}

※ 결과값
0
1
2
3
4
6
7
8
9


<반복문의 중첩>

반복문을 중첩해서 실행해보자.

<문제>
            **********
            **********
            **********
을 그려보자

class LoopTest2{
    public static void main(String[] args){
    /*
            **********
            **********
            **********
    */
    
        for(int row = 0; row<3; row++){
            for(int col = 0; col<10; col++){    
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

※ 결과값
**********
**********
**********

<문제>
*
**
***
****
*****

을 그려보자

class LoopTest2{
    public static void main(String[] args){
    
        for(int row = 0; row<5; row++){
            for(int col = 0; col<=row; col++){    
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

※ 결과값

*
**
***
****
*****


★ 반복문 연습문제 ★

1.갤런을 리턴으로 바꾸는 예제
1갤런부터 100갤런까지 리터에 대한 변환표를 작성
(단 10갤런마다 줄바꿈을 하도록 한다.)

2. 간단한 전자 계산기 프로그램
연산자 : +
숫자1 : 2
숫자2 : 3
결과 : 2+3 = 5
연산자 : *
숫자1 : 2
숫자2 : 3
결과 : 2*3 = 6
연산자 : x
종료...
3. 숫자를 입력받아 합계를 구하는 예제(0을 입력하면 종료)
숫자1:2
숫자2:1
숫자3:4
숫자4:7
...
숫자n:0
합계 : ?
4. 위의 문제를 응용해서 짝수의 합과 홀수의 합을 구하시오.
(단, 입력횟수를 미리 입력받는다.)
입력횟수 : 4
2
3
7
6
짝수의 합 : ?
홀수의 합 : ?
5. 간단한 문자 추측 게임 프로그램을 만드시오.
미리 정답을 정해 놓는다.(예를 들어 k)
a~z까지 생각한 문자 입력 : b
틀렸다.
a~z까지 생각한 문자 입력 : z
틀렸다.
(정답을 맞출때까지)
6. 간단한 도움말 시스템 구축
1. if
2. switch
3. for
4. 종료
번호 선택 : 1
if(조건식) 문장;
1. if
2. switch
3. for
4. 종료
번호 선택 : _
7. "."이 입력될 때까지 키보드 입력을 읽어서 입력된 공백의 갯수를 세고 그 합을 출력하시오.
dlksjf;al alsdjlas   sldkjflaksdj  sdalfjlkj.
8. 
    *
   ***
  *****
*******
*********

9.
    *
   ***
  *****
*******
*********
*******
  *****
   ***
    *


'개발 > Java' 카테고리의 다른 글

[java] 배열 (Array)  (0) 2017.10.19
[java] 클래스 (Class) part.1  (0) 2017.10.18
[java] Dos에서 Java 컴파일 하기  (0) 2017.10.18
[java] 연산자(Operator)  (0) 2017.10.18
[java] 변수(Variable)와 데이터타입(Data Type)  (0) 2017.10.17
Dos에서 Java 컴파일 하기


소스관리의 기본 : 기본소스와 실행파일을 따로 보관한다.
src -> 소스보관
binary의 약자 bin -> 컴파일 보관



-d <directory> 옵션 이용하여 원하는 위치에 컴파일 해보자

현재 자리에 하나의 소스 컴파일 하기 javac Op1.java
특정 폴더에 하나의 소스 컴파일하기 javac -d ..\bin Op1.java
특정 폴더에 전체 소스 컴파일하기 javac -d ..\bin *.java

classpath <path> 옵션 이용하여 원하는 위치에서 결과값은 출력해보자



연산자(Operator)


연산자 종류와 연사순서, 연산 순서를나타낸 표이다.

아래 순서는 연산자 단일경우이다. 연산자가 같이 있으면 경우에 따라 달라진다.

 



그럼 연산자의 종류부터 차근히 알아보자.


1. 종류


1) 산술연산자


- 이항연산자 : *,  /,  %,  +,  -

- 단항(증감)연산자 : ++,  --


단항(증감)연산자를 써보자.


<예제 1>


class Op1{

    public static void main(String[] args){

        int a = 10;

        a++; //후위연산자 a = a+1;

        ++a; //전위연산자

        System.out.println("a=" + a);

    }

}


※ 결과값

a=12


아래 두개의 예제를 비교하여 살펴보자.

<예제2>

class Op1 {


public static void main(String[] args) {

// TODO 연산자1

int a = 10, b;

b = ++a;

//b=a++;

System.out.println("a="+a);

System.out.println("b="+b);

}


}


※ 결과값

a=11

b=11


<예제 3>


class Op1{

    public static void main(String[] args){        

        int a = 10, b;

        //b = ++a;

        b = a++;

        System.out.println("a=" + a);

        System.out.println("b=" + b);

        

    }

}


※ 결과값

a=11

b=10


어떻게 이런 다른 결과가 나오는 것일까?


왜냐하면 연산자우선순위 때문에 a값이 증감되기 전에 b로 넘어가버렸기 때문이다.

이렇게 증감연산자을 계산식과 연동할 경우 오류를 찾기 어렵기 때문에

증감연산자는 될 수 있으면 계산식과 연동하지 말고 단독으로 쓰는 것이 좋다.


2) 비교연산자


>, <, >=, <=, ==(같다), !=(같지 않다)



3) 논리연산자 (단락회로 기능)


&&(and), ||(or), !(not)


t = true

f = fause


 a

b

a && b 

a || b 

!a 

a^b 

 t

 f 

 t

f

f

t

 f

t

t

 f

 f 



여기서 ! 는 스위치처럼 한 번씩 왔다갔다 반복을 하기 때문에 Toggle이라고 한다. (ex_바둑게임)



4) 대입(치환)연산자


대입연산자

 = (오른쪽에 있는 값은 왼쪽에 집어넣어라)

복합대입연산자

 +=, -=, *=, /=, .... 

(+= 는 '변수 = 변수 + 값'을 생략한 것이다.)

(다른 연산자와 조합해서 사용한다. 이는 누적 연산자라고 한다.)


class Op2{

    public static void main(String[] args){

        int a = 10;

        a = 5;

        a = 2;

        a = 3;

        System.out.println("a=" + a)

    }

}    


※ 결과값

3


변수는 아무리 다른 값을 집어넣어도 하나밖에 저장이 안되기 때문에 마지막에 집어 넣은 값이 출력값이 된다.

이렇듯 대입연산자는 값이 누적되지 않고 계속 덮어 씌어진다.


class Op2{

    public static void main(String[] args){

        /*

        int a = 10;

        a = 5;

        a = 2;

        a = 3;

        System.out.println("a=" + a)

        */

        

        int a = 10;

        a += 5; // a = a+5; 

        a += 2; // a = a+2;

        a += 3; // a = a+3;

        System.out.println("a=" +a);

    }

}    



※ 결과값

20


이 때 a의 값은 20이 된다. 누적되어서 계산 되었기 때문이다. 

대입연산자와 달리 복합대입연산자는 다른 연산자를 포함하고 있지만
생략하여 나타낸 연산자기 때문에 값이 누적되어 계산된다.


이렇듯 연산자에게 가장 중요한 것은 '우선순위'이다.

연산우선순서를 모두 외울 수 있지만 쉽지 않다.

연산자는 괄호()를 묶어 연산하는 습관을 기른다. 

정확하고 안전한 것이 가장 중요하다.


5) 비트연산자


& (and연산자), | (or연산자), ^ (exclusive-or, xor, 베타적인or, 데이터를 암호화 하거나 복구한다.), >>, >>> << ~, ...


프로그램의 성능을 올리기 위해 사용하는 연산자이다.

최근 하드웨어의 사향의 상향 평준화 되었기 때문에 

하드웨어를 다루지 않는이상 잘 쓰지는 않는다.


class Op3 {

    public static void main(){

        int a = 10, b = 5;

        

        System.out.println("a&&b" + a&&b);

    }        

}

// 논리 연산식은 참과 거짓으로만 판단할 수 있기 때문에 오류가 된다.


※ 결과값

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 

The operator && is undefined for the argument type(s) String, int


at operator.Op3.main(Op3.java:8)



class Op3 {

    public static void main(String[] args){

        int a = 10, b = 5;

        

        //System.out.println("a&&b" + a&&b);

        System.out.println("a>5&&b<3" + (a>5&&b<3));

    }        

}



※ 결과값

 a>5&&b<3false


변수의 값이 참인지 거짓인지를 물었기 때문에 값이 위와 같이 나온다.


비트연산자 & 는 논리연산자 &&와는 다르게 

숫자를 대변해도 값이 나온다. 비트연산자는 이진수를 계산하기 때문이다.


class Op3 {

    public static void main(String[] args){

        int a = 10, b = 7;

        

        //System.out.println("a&&b" + a&&b);

        System.out.println("a>5&&b<3" + (a>5&&b<3));

        

        System.out.println("a>5&b<3" + (a>5&b<3));

        System.out.println("a&b" + (a&b));

    }        

}

※ 결과값

a>5&&b<3false

a>5&b<3false

a&b2

 


논리연산자는 단락회로기능을 가지고 있다. '단락회로기능'이란 

이미 앞에서 계산된 것은 계산하지 않는 것을 말한다.


아래의 예제들을 비교하면서 생각해보자.


class Op3 {

    public static void main(String[] args){

        int a = 10, b = 7;

        

        //System.out.println("a&&b" + a&&b);

        System.out.println("a>5&&b<3" + (a>5&&b<3));

        

        System.out.println("a>5&b<3" + (a>5&b<3));

        System.out.println("a&b" + (a&b));

        

        System.out.println(a>12 && ++b>5);

        System.out.println(a + ", " + b);

    }        

}


※ 결과값

a>5&&b<3false

a>5&b<3false

a&b2

false

10, 7





class Op3 {

    public static void main(String[] args){

        int a = 10, b = 7;

        

        //System.out.println("a&&b" + a&&b);

        System.out.println("a>5&&b<3" + (a>5&&b<3));

        

        System.out.println("a>5&b<3" + (a>5&b<3));

        System.out.println("a&b" + (a&b));

        

        System.out.println(a<12 && ++b>5);

        System.out.println(a + ", " + b);

    }        

}


※ 결과값

a>5&&b<3false

a>5&b<3false

a&b2

true

10, 8


이 값의 변화는 논리연산자(&&, ||)가 가진 단락회로기능 때문이다.



^(exclusive-or, xor, 베타적인or, 데이터를 암호화 하거나 복구한다.

^는 서로의 값이 다르면 참 서로의 값이 같으면 거짓이다.

키값만 있다면 데이터를 암호화 할 수도, 복구 할 수도 있다.


<암호화>

   11010110

^ 11000011 (key)

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

    00010101


<복구>

   00010101 (key)

^ 11000011

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

    11010110




class Op4{

    public static void main(String[] args){

        int data = 34876;

        int key = 2986;

        

        int enc = data^key;

        System.out.println("암호화된 값 : " + enc);

        

        int dec = enc ^ key;

        System.out.println("복호화된 값 : " + dec);

    }

}


※ 결과값

암호화된 값 : 33686

복호화된 값 : 34876


비트연산자는 2진수로 연산함을 잊지말자!



6) 캐스팅 연산자 (강제형변환 연산자)


- 묵시적(암시적) : 작은 그릇을 큰 그릇에 넣었기 때문에 자동으로 캐스팅 된다.

- 명시적 : (data type) 변수


이 변수의 형식을 괄호 안에 있는 형식으로 강제로 바꾸겠다는 말이다.


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 오류가 난다.

        int i1 = d1 + d2;

    }

}


이를 캐스팅연산자를 사용하여 강제 형변환 해주면,


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.

        int i1 = (int)d1 + (int)d2;

        System.out.println("i1 = " + i1);

    }

}


※ 결과값

i1 = 5


위와 같은 결과가 나오는 이유는 강제형변환을 했기 때문에. 0.8을 손해보아서 이다. 

입력되는 숫자를 예측하기 어려운 경우에 많이 쓰인다.


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.

        int i1 = (int)d1 + (int)d2;

        System.out.println("i1 = " + i1);

        

        d1 = (double)i1;

        System.out.println("d1 =" +d1);

    }

}


※ 결과값

i1 = 5

d1 =5.0



이 경우 i1 값은 명시적 캐스팅을 헀고, d1의 경우

 작은그릇을 큰그릇에 넣을 수 있기 때문에 암시적 캐스팅이 되었다.


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.

        int i1 = (int)d1 + (int)d2;

        System.out.println("i1 = " + i1);

        

        d1 = (double)i1; //d1 = (double) i1;

        System.out.println("d1 =" +d1);

        

        byte b1 = (byte)i1;

        System.out.println("b1 = " + b1);

        

        b1 = 100 + 5;

        System.out.println("b1 =" + b1);

        

        b1 = b1 + 5;

        System.out.println("b1 =" + b1);

    }

}


※ 결과값

오류가 난다



이렇게 하면 오류가 난다. 

문법적으로는 문제가 없으나 이는 하드웨어적인 이해가 필요하다. 

작은 연산결과를 임시로 저장하는 곳을 레시스터라고 하는데 

그 때 임시로 저장되는 형식이 기본형인 int이다. 

int로 임시저장된 값을 bite로 다시 바꾸려고 하기 때문에 오류가 난다.


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.

        int i1 = (int)d1 + (int)d2;

        System.out.println("i1 = " + i1);

        

        d1 = (double)i1; //d1 = (double) i1;

        System.out.println("d1 =" +d1);

        

        byte b1 = (byte)i1;

        System.out.println("b1 = " + b1);

        

        b1 = 100 + 5;

        System.out.println("b1 =" + b1);

        

        //임시연산저장소에서 int로 저장된 값을 형변환 해준다.

        b1 = (byte)(b1 + 5);

        System.out.println("b1 =" + b1);

    }

}


※ 결과값


i1 = 5

d1 =5.0

b1 = 5

b1 =105

b1 =110



강제형변환을 하지 않는 방법은 복합치환연산자를 쓰는 것이다.


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.

        int i1 = (int)d1 + (int)d2;

        System.out.println("i1 = " + i1);

        

        d1 = (double)i1; //d1 = (double) i1;

        System.out.println("d1 =" +d1);

        

        byte b1 = (byte)i1;

        System.out.println("b1 = " + b1);

        

        b1 = 100 + 5;

        System.out.println("b1 =" + b1);

        

        //b1 = (byte)(b1 + 5);

        b1 += 5; // b1 = b1 + 5;

        System.out.println("b1 =" + b1);

    }

}



※ 결과값

i1 = 5

d1 =5.0

b1 = 5

b1 =105

b1 =110


이렇듯 복합치환연산자는 자동캐스팅기능이 포함이 되어있어 연산이 가능하다.


하드웨어 문제로 연산이 안되는 또다른 문제가 있다.


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.

        int i1 = (int)d1 + (int)d2;

        System.out.println("i1 = " + i1);

        

        d1 = (double)i1; //d1 = (double) i1;

        System.out.println("d1 =" +d1);

        

        byte b1 = (byte)i1;

        System.out.println("b1 = " + b1);

        

        b1 = 100 + 5;

        System.out.println("b1 =" + b1);

        

        //b1 = (byte)(b1 + 5);

        b1 += 5; // b1 = b1 + 5;

        System.out.println("b1 =" + b1);

        

        float f1 = 3.14;

        System.out.println("f1 =" + f1);

        

    }

}


※ 결과값

오류


컴퓨터는 2진수이기 때문에 정수처리를 한다. 실수처리를 잘 못한다. 

컴퓨터가 실수를 처리할 때는 정수부와 실수부를 따로 저장한다. 

정수부와 실수부를 따로 저장할 때 타입은 실수의 기본형인 double이다. 

이런 경우 역시 캐스팅으로 해결한다.


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.

        int i1 = (int)d1 + (int)d2;

        System.out.println("i1 = " + i1);

        

        d1 = (double)i1; //d1 = (double) i1;

        System.out.println("d1 =" +d1);

        

        byte b1 = (byte)i1;

        System.out.println("b1 = " + b1);

        

        b1 = 100 + 5;

        System.out.println("b1 =" + b1);

        

        //b1 = (byte)(b1 + 5);

        b1 += 5; // b1 = b1 + 5;

        System.out.println("b1 =" + b1);

        

        float f1 = (float)3.14;

        System.out.println("f1 =" + f1);

        

    }

}



※ 결과값


i1 = 5

d1 =5.0

b1 = 5

b1 =105

b1 =110

f1 =3.14



다른 방식으로 깔끔하게 표현을 바꾸어 보자.

강제형변환은 정수형 일 때만 한다. 그런데 실수형의 경우기 때문에 강제형변환 표현이 조금 지저분하다. 다른 방법으로 이를 표현하면 아래와 같이 된다.


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.

        int i1 = (int)d1 + (int)d2;

        System.out.println("i1 = " + i1);

        

        d1 = (double)i1; //d1 = (double) i1;

        System.out.println("d1 =" +d1);

        

        byte b1 = (byte)i1;

        System.out.println("b1 = " + b1);

        

        b1 = 100 + 5;

        System.out.println("b1 =" + b1);

        

        //b1 = (byte)(b1 + 5);

        b1 += 5; // b1 = b1 + 5;

        System.out.println("b1 =" + b1);

        

        //소문자나 대문자 f를 형변환 해야하는 값 옆에 써준다.

        float f1 = 3.14f;

        System.out.println("f1 =" + f1);

        

    }

}




문자의 경우는  어떻게 캐스팅이 될까?


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.

        int i1 = (int)d1 + (int)d2;

        System.out.println("i1 = " + i1);

        

        d1 = (double)i1; //d1 = (double) i1;

        System.out.println("d1 =" +d1);

        

        byte b1 = (byte)i1;

        System.out.println("b1 = " + b1);

        

        b1 = 100 + 5;

        System.out.println("b1 =" + b1);

        

        //b1 = (byte)(b1 + 5);

        b1 += 5; // b1 = b1 + 5;

        System.out.println("b1 =" + b1);

        

        //float f1 = (float)3.14;

        float f1 = 3.14f;

        System.out.println("f1 =" + f1);

        

        f1 = f1 + 2.5f;

         System.out.println("f1 = " + f1);

        

        //아스키코드기 때문에 숫자로 자동 형변환 해준다.

        int i2 = 'a';

        System.out.println("i2 = " + i2);

        

        //아스키코드기 때문에 문자로 자동 형변환 해준다.

        char c1 = 98;

        System.out.println("c1 = " + c1);

    }

}


※ 결과값

i1 = 5

d1 =5.0

b1 = 5

b1 =105

b1 =110

f1 =3.14

f1 = 5.6400003

i2 = 97

c1 = b



매우 큰 값의 경우는 어떨까?


class Op5{

    public static void main(String[] args){

        double d1 = 3.5, d2 = 2.3;

        

        //값을 담고 있는 그릇의 크기가 int이기 때문에 안된다.

        int i1 = (int)d1 + (int)d2;

        System.out.println("i1 = " + i1);

        

        d1 = (double)i1; //d1 = (double) i1;

        System.out.println("d1 =" +d1);

        

        byte b1 = (byte)i1;

        System.out.println("b1 = " + b1);

        

        b1 = 100 + 5;

        System.out.println("b1 =" + b1);

        

        //b1 = (byte)(b1 + 5);

        b1 += 5; // b1 = b1 + 5;

        System.out.println("b1 =" + b1);

        

        //float f1 = (float)3.14;

        float f1 = 3.14f;

        System.out.println("f1 =" + f1);

        

        f1 = f1 + 2.5f;

         System.out.println("f1 = " + f1);

        

        //아스키코드기 때문에 숫자로 자동 형변환 해준다.

        int i2 = 'a';

        System.out.println("i2 = " + i2);

        

        //아스키코드기 때문에 문자로 자동 형변환 해준다.

        char c1 = 98;

        System.out.println("c1 = " + c1);

        

        //i2 = 10000000000;

        

        //정수형으로 안되는 값이기 때문에 L이라는 꼬리표로 형변환시켜준다.

        long var = 10000000000L;

        

    }

}


7) 삼항연산자 (조건연산자)

<문법>
조건식 ? 참일 때 처리할 내용 : 거짓일 때 처리할 내용


class Op7{
    public static void main (String[] args) {
        int data = 8;
        
        // data란 변수가 5보다 크면 1에 저장하고 아니면 0에 저장한다.
        //
        int result = data > 5 ? 1 : 0;
        boolean result2 = data > 6 ? true : false;
        System.out.println("결과 : " + result + "\t" + result2);
        
    }

}



★ 연습문제 ★

https://gist.github.com/muyongseja/472f3c3a8f32a412d4cec00412e935ef


1. 리터를 갤런으로 바꿔보자.

두 개의 double변수를 이용해서 각각 갤런과 리터값을 저장하고

갤런값을 해당하는 리터값으로 바꿔보자.(1갤런은 3.7584리터이다.)


2. 달의 중력은 지구 중력의 17%정도이다.

달에서의 당신의 체중을 계산하는 프로그램을 작성하시오.


66퍼센트 감소하면?

답) 526.32


3. 번개가 얼마나 먼 곳에서 발생했나?

(번개 소리를 들은 사람이 번개가 치는 곳에서부터 몇 피트 정도 떨어져 있는가를 계산하라.

소리는 공기 중은 약 1,100피트/초의 속도로 진행한다.

- 번개를 본 시각과 천둥소리를 들은 시각 사이의 시간을 알면 거리를 계산할 수 있다.

여기서는 7.2초로 가정하자.)











Ⅰ. 변수(Variable)

변수의 3가지 특징


첫째, 임시기억장소이다.


둘째, 반드시 변수선언을 해야 한다. 


셋째, 반드시 초기화를 해야한다.


1. 임시기억(저장)공간

컴퓨터에서 임시기억 공간은 메모리(램, 주기억장치)를 의미한다.

+ (더하기) 는 숫자끼리 있을 때는 덧셈이고 문자끼리 있을 때는 문자화 된다.
문자가 있을 때 숫자를 연산해주려면 숫자끼리 괄호를 쳐 주면 된다.

class Var1{
    public static void main(String[] args){
        System.out.println("***급여관리 프로그램***");
        System.out.println("*****************");
        System.out.println("기본급 : " + 10000);
        System.out.println("세금 : " + 10);
        System.out.println("보너스 : " + 100);
        System.out.println("총급여 : " + (10000 - 10 + 100));
    }
}


이런 급여관리 프로그램이 있을 때 값이 변한다면 프로그래머는 항상 그 값을 바꾸어주어야 한다. 
유지보수와 관리가 어렵기 때문에 다른 방법을 생각해냈다.

'변수(variable)'는 프로그래밍에서 값을 임시로 저장하기 위한 공간이다.
절대로 변할 일이 없는 실제값 '상수(literal)'라면 변수를 쓰지 않는다.

class Var1{
    public static void main(String[] args){
        // 왼쪽에는 값을 저장할 수 있는 메모리가 와야하고 오른쪽에는 값이 나와야한다.
        // '=' 오른쪽에 있는 값을 왼쪽에 있는 창고에다가 대입하겠다.
        // 'pay' 변수, 저장창고
        int pay = 10000;
        
        System.out.println("***급여관리 프로그램***");
        System.out.println("*****************");
        System.out.println("기본급 : " + pay);
        System.out.println("세금 : " + 10);
        System.out.println("보너스 : " + 100);
        System.out.println("총급여 : " + (pay-10+100));
    }
}


2. 변수선언과 초기화

변수선언이란 ? 
메모리를 쓰겠다고 선언한 것.
변수선언을 해야만 메모리를 쓸 수 있다.

변수선언 신고양식

방법1.
데이터타입 변수명; 
변수명 = 값;

방법2.
데이터타입 변수명 = 값;

변수는 반드시 초기화해야한다.

초기화처음 변수에 어떤 값을 넣는 것을 의미한다.

초기값이란 변수가 태어나자 마자 가장 첫번째로 들어간 값이다.

class Var2{
    public static void main(String[] args){
        byte var;
        var=127;
        //var = 128; 에러확인
        
        char var2 = 'a';
        var2= '가';
        //var2 = "a";
        
    }
}

3. 반드시 변수가 선언된 곳에서만 사용할 수 있다.(유효범위)

변수의 유효점위는 변수가 선언된 곳이다.
변수가 선언된 범위 밖을 벗어난다면 변수를 사용 할 수 없다.

프로그램에서 가장 중요하게 염두해 두어야 할 것은 Data이다.
변수는 Data를 보관하기 위한 기본적인 방법이다. 그래서 매우 중요하다. 

Ⅱ. 데이터타입 Data Type

Data Type을 왜 쓸까?
만약에 누군가가 땅을 사려고 한다면 
땅 주인에게 두 가지는 말해주어야 한다.

1. 어떤 용도로 쓸 것인가?
2. 얼마만큼의 크기를 쓸 것인가? 

컴퓨터도 마찬가지이다.
Data Type은 컴퓨터에게 메모리 공간을 어떤 용도로 얼마나 쓸지 알려준다. 

변수에 타입을 선언한 뒤 해당 타입보다 
큰 값을 변수에 넣으면 컴파일 에러가 난다.

아래 '기본 데이터 타입표'를 보자.

1. 기본 Data Type (비객체 Data Type)

용도                           크기
--------                       --------
정수형                       byte (1byte)
                                short (2byte)
                                int(4byte) - default
                                long(8byte)
실수형                       
                                float (4byte)
                                double (8byte) - default
문자형                       
                                char(2byte)
논리형
                                boolean - true, false
                                (다른 값으로 대체할 수 없음. 오직 true, false 만 가능)

컴퓨터 정보표현 단위
bit(0,1) < byte(8bit) < kb(1024byte) < Mb(1024byte) < Gb(1024Mb) < Tb(1024Gb)

java의 최소단위, bite
컴퓨터에서 bit는 정보를 표현할 수있는 최소단위이다.
bit는 정보를 저장할 수 있는 단위가 아니라 표현할 수 있는 단위이다.
byte 부터가 정보를 저장할 수 있는 최소단위이다.
10byte는 영문자 10개를, 한글은 5개를 저장 할 수 있다.

C나 C++은 최소단위가 bit인데 반해, Java는 최소단위가 bite이다.
이는 영어를 제외한 다른 문자도 저장 할 수 있도록 한 것이다.

ASCⅡ(아스키코드)와 유니코드
ASCⅡ(아스키코드)는 영어 밖에 입력 할 수 없다.
아스키코드는 128개(a~z, A~Z, 특수문자)라는 
영미권에서 필요한 문자를 모아놓았다. 

ASCⅡ(아스키코드) + 1 byte = 유니코드
유니코드는 아스키코드에 1byte를 더 확장하여 
세상의 모든 문자를 담을 수 있는 코드방식이다.

C, C++아스키코드방식이고 Java유니코드방식이다.






2. 객체 Data Type
1. 객체 Data Type은 사용자 정의 데이터 타입이다.
2. 객체 Data Type은 class로 작성한다.
   - 이 때 class는 데이터타입을 만드는 용도로 사용한다.

'문자'와 '문자열'은 다르다!
문자 : 1문자, '  '
문자열 : 1문자 이상, '' "

왜 데이터타입을 써야 되는지 생각하자
변수를 선언하기 위해서 데이터타입이 필요하다. 

{ } 중괄호와 중괄호 사이를 '블럭'이라고 말한다.
이 { } 블럭은 데이터타입과 변수를 사용할 수 있는 범위를 지정해준다. 

class Var3{
    public static void main(String[] args){
        int a = 10;
        {
            int b = 20;
            {
                int c = 30;
                System.out.println("c=" + c);
                System.out.println("a=" + a);
                System.out.println("b=" + b);
            }
            System.out.println("b=" + b);
        }
        System.out.println("a=" + a);
        //System.out.println("b=" +b); 에러확인
    }

}

※ 결과값
c=30
b=20
b=20
b=20
a=10

여기에서 주석으로 표시된 System.out.println("b=" +b) 코드를 

주석을 풀고 실행하면 에러가 난다.

그 이유는 int b = 20; 가 해당하는블럭 {} 의 범위를 벗어났기 때문이다.

주석과 역슬래쉬(\)

JAVA에게 인사하는 느낌으로 코딩을 한 번 해보자.

class PrintTest{
    public static void main(String[] args){

        java.lang.System.out.println("안녕하세요.\n\n");
        java.lang.System.out.println("또\n만났군요.");
        //java.lang.System.out.println("100+5");
        //java.lang.System.out.println(100+5);
        //java.lang.System.out.println(3.14 + 3);
        java.lang.System.out.println();
        java.lang.System.out.println("안녕\t\t하세요.");
        java.lang.System.out.println("\\n 은 줄바꿈이 가능하다.");
        java.lang.System.out.println("\"\\t는 탭키를 제어하는 문자이다\"");
    }
}

여기에서 알 수 있는 것은?

\n 한 줄 줄바꿈
\t 탭키
\ 는 기존의 특수문자가 가지고 있는 특수한 기능을 없애준다.

        // 한줄만 주석
        
        /* 여기서부터는
           여러줄로
           주석
        */
        



위 코딩을 cmd 창에서 출력 해보자.
cmd 창은 윈도우에서 실행 창을 열고 cmd라고 쓰면 된다. cmd 창이 도스창과 같다.



프로그래밍과 알고리즘


프로그램을 잘 짜는 비결은 문법을 잘 아는게 아니라 논리적 사고방식과 알고리즘이다.
알고리즘을 알기 위해서는 일의 순서를 알아야한다.

프로그램이란 일의 순서를 말한다.
프로그램은 순서를 잘 알아야한다.
어떤 프로그램을 짤 때 우선 일의 순서를 먼저 계획하고 코딩을 한다.
알고리즘 공부는 문법이 익숙해 진다음에 한다.
'알고리즘'을 다른 말로 '자료구조'라고 말한다. 알고리즘을 학문적으로 표현한 것이 자료구조이다.

알고리즘을 효과적으로 공부하는 방법 : 정보올림피아드 문제를 초등학생문제부터 살펴본다.


[java] Java 처음 설치 & 환경변수 수정

- 프로그래밍 언어는 컴퓨터와 소통하기 위한 도구이다.
- 컴퓨터 언어는 C -> C++ -> C# 으로 발전했다.
- 택스트문서 ---- 문서(명령)해독---- 컴퓨터 (실행파일 = 이진파일)

해석방법 
1. 컴파일 : 텍스트문서에 있는 명령어를 모아놓았다가 해석한다. (일반적인 방법, 속도 ▲)
2. 인터프리터 : 텍스트문서에 있는 명령어를 한 줄 씩 실행한다. 대화하듯이 너 한 줄 나 한 줄. 
    (일반적이지 않음, 속도 ▼
)

- 컴파일러 : 내가 작성한 프로그램을 컴퓨터가 알아 들을 수 있도록 해독해주는 프로그램
- java  컴파일러 -> jdk 버전 (1.0, 1.1, 1.2, ... 1.5 -> 50, 1.6 -> 6.0)
- JRE

javaSE
javaSE (어플리케이션 제작용) = Java Mission Control(하드웨어 제작, MIrcro) + Java EE{Enterprise)
우리가 주로 배우는 것은 JAVAEE


Java를 설치 & JAVA API 문서 보기

1. 오라클 홈페이지에 들어가자


2. 메뉴옆에 사이드바 메뉴를 누르고 Developers > Developer Resource
 



3. 스크롤을 아래로 내려 가운데 See all Java 를 누릅니다.



4. 스크롤을 아래로 내려 Java SE 를 누릅니다.



5. Java SE Downloads 에서 JDK를 다운 받습니다.


6. Accept License Agreement 를 선택합니다.


7. 자신의 OS에 맞는 파일을 다운받습니다.

8. 여기서 JAVA API를 보려면 Downloads 옆 Documentation을 클릭합니다.

9. 책 모양의 JAVA SE Technical Documentation을 클릭합니다.

10. API Documentation을 클릭합니다.


11. API Documentation에서 FLAMES를 클릭하면 더 편하게 볼 수 있습니다.


12. API Documentation에서 원하는 정보를 봅니다. 


JAVA API 바로가기
https://docs.oracle.com/javase/9/docs/api/index.html?overview-summary.html


환경변수 설정 (window의 경우)

1. 고급시스템설정으로 간다.
제어판 - 시스템 및 보안 - 시스템 - 고급시스템설정

2. JAVA_HOME 변수 만들기
Java jdk 폴더 위치로 변수를 만든다.
'시스템 변수'에서 '새로 만들기'를 하여 변수 이름과 변수 값을 입력하다.
JAVA_HOME
C:\Program Files\Java\jdk1.80_144



3. Path 설정 변경
Path = 내가 원하는 실행파일을 어디에서나 원하는 위치에서 실행할 수 있도록 도와주는 환경설정
JAVA_HOME으로 이름을 쓰는 이유는JAVA를 쓰는 다른 프로그램에서 JAVA를 찾을 때 이 폴더를 찾음
;%JAVA_HOME%\bin; 을 친다. 여기서 %의 의미는 %% 사이의 변수를 가져다 쓴다는 의미다.




4. 환경변수 설정을 했음에도 잘 못 찾을 때는 ClassPath 수정한다.




Dos 설명

CUI 와 GUI
UNIX와 LINUX계열은 키보드를 사용한 명령에 의해 조작한다.
이것은 CUI(Character User Interface) 환경이 중심인 OS입니다.
GUI는 Graphic User Interface 라고해서 Windows나 Mac에서 
마우스를 사용해서 파일이나 폴더를 직접 조작한다


Dos는 Tree구조로 이루어져 있다.
간략하게 설명하면 거대한 구조로 이루어져 있는 공간에 방이 여러개 있고 
방에 들어가면 또 방이 있고 그 방에 데이터가 있고 그런 식으로 생각하면 좋다.
Tree구조에 대한 자세한 설명은 다음 블로그를 참조하자.


Windos에서 Dos를 가려면 실행 -> cmd 치면 된다.
그렇다면 Dos에서는 어떻게 이동할까? 

'cd 폴더명' 으로 이동
검색에서 'cmd'를 쳐서 들어간다.
폴더명이 직속 부모라면 'cd..'으로 하면 바로 위 상위폴더로 갈 수 있다.
'dir' 현재 위치에서 어떤 파일들이 있는지 확인할 수 있다.
' . (점하나)'는 현재 위치를 말한다.
' .. (점두개)'는 부모 위치를 말한다.
cd. = 현재위치
cd.. = 부모위치
cd\ = 맨 꼭대기로 점핑
Path = 내가 원하는 실행파일을 어디에서나 원하는 위치에서 실행할 수 있도록 도와주는 환경설정

  1. 파일 이름 복사
  2. 쉬프트 오른쪽 클릭 - > 명령 

C, C++, C#에서는 '이진파일'이라고 하지만 자바에서는 '바이트코드'라고 불리운다.
바이트코드는 이진수로 컴퓨터에게 명령하기 때문에 이름 붙혀졌다.

둥근괄호를 가지고 있으면 '함수(계산을 편리하게 도와주는 도구)'라고 부른다.
'Println()'는 출력을 담당한다.

; // 터미네이터 종결자

class PrintTest{
    public static void main(String[] args){
        // 한줄만 주석
        
        /* 여기서부터는
           여러줄로
           주석
        */
        
        java.lang.System.out.println("안녕하세요.");
        java.lang.System.out.println("또 만났군요.");
        java.lang.System.out.println("100+5");
        java.lang.System.out.println(100+5);
        java.lang.System.out.println(3.14 + 3);
        java.lang.System.out.println();
        java.lang.System.out.println("안녕하세요.");
    }
}



cmd 에서 javac PrintTest.java 로 컴파일 후 java PrintTest 로 출력해 보자.


+ Recent posts