본문 바로가기
학원수업/12월

12/26 국비학원 자바수업 21회차

by 코딩마스터^^ 2022. 12. 26.

드디어 한달이 지났다. 5주차도 화이팅

오라클 설치(노션 참조)

토드 설치

Maven Repository에서 

외부 임포트 했을때 그레이들 문서에 등록할 경우

보기-명령파레트-java clean workspace-reload -view project

꼭 해줘야한다.

 

package dev_java.oracle;

import java.sql.Connection;
import java.sql.DriverManager;
/*
 * 변수 이름 앞에 final이 붙으면 상수가 됨.
 * 상수는 다른 값으로 재정의 불가함.
 */
public class JDBCTest {
	//이 클래스를 읽어야 오라클 제품인것을 확인가능함.
	public static final String _DRIVER 
						= "oracle.jdbc.driver.OracleDriver";
	//물리적으로 떨어져 있는 오라클 서버에 URL정보 추가
	public static final String _URL 
						= "jdbc:oracle:thin:@127.0.0.1:1521:orcl11";
	public static String _USER = "scott";
	public static String _PW = "tiger";
	//물리적으로 떨어져 있는 오라클 서버와 연결통로를 만들 때 사용
	Connection con = null;
	java.sql.PreparedStatement pstmt = null;
	//오라클에 살고 있는 커서를 조작하는 클래스를 제공함.
	//커서 위치에 로우가 존재하면 true,  조회된 결과가 없으면 false리턴
	//java.lang폴더를 제외하고는 모두 다 import해주어야 JVM이 그 클래스를 찾음.
	java.sql.ResultSet rs = null;
	public String currentTime() throws Exception{
		Class.forName(_DRIVER);//오라클 제조사 정보를 가지고 있어요.
		String sql = "select to_char(sysdate,'HH24:MI:SS') from dual";
		//아래 메소드가 호출되면 오라클 서버와 연결통로를 갖게됨.
		//이 연결통로를 통해서 select문을 전령 클래스가 가지고 들어가야 함.
		con = DriverManager.getConnection(_URL, _USER, _PW);
		pstmt = con.prepareStatement(sql);
		rs = pstmt.executeQuery();//오라클 서버에게 처리를 요청함.
		if(rs.next()) {
			return rs.getString(1);
		}
		return "15:09:49";
	}
	public static void main(String[] args) throws Exception{
		//java.lang패키지에 클래스는 모두 찾지만 그 외 패키지는 찾을 수 없다.
		//Scanner scan = new Scanner(System.in);
		JDBCTest jt = new JDBCTest();
		String ctime = jt.currentTime();
		System.out.printf("현재 시간은 %s 입니다.\n",ctime);
	}
}

scott을 열어준다.

 

		
public abstract class Duck {//추상클래스
	FlyBehavior flyBehavior;	
	QuackBehavior quackBehavior;	
	public Duck(){}	//생성자
	public abstract void display();//추상메소드 구분법? ;으로 끝나면 추상메소드이다.
	public void performFly(){ //일반 메소드	
		flyBehavior.fly(); //실행문. 호출. 
	}	
	public void performQuack(){	
		quackBehavior.quack();
	}	
	public void swimming(){	
		System.out.println("모든 오리는 물위에 뜬다");
	}   	
}

추상 메소드

기능을 결정 하지 않았다. 미정이다.

왜냐하면 디바이스 마다 기능이 다르므로 정할 수 없는 추상 메소드를 사용했다.

 

추상 메소드는 ; 로 끝난다. 호출이 아님.

 

자바에서는 같은 이름의 메소드를 중복 정의 가능하다.

 

메소드 오버로딩

1.메소드 이름이 같다.

2. 파라미터 갯수가 다르다.

3. 파라미터 타입이 다르다.

4. 접근제한자, 예외처리, 리턴타입은 관계없다.

 

메소드 오버 라이딩

메소드 오버라이딩은 자식 클래스가 부모 클래스에 존재하는 메소드와 동일한 파라미터를 갖는 메소드를 재정의하여 부모 클래스의 메소드를 감추는 현상이다.

 

메소드의 원형을 훼손하면 안된다.

선언문을 변경하면 안된다.

리턴타입 바꾸면 안된다. 

추상메소드와 인터페이스는 반드시 구현체 클래스가 필요하다.

반드시 상속관계 이거나 인터페이스에 구현체 클래스여야 한다.

선언부에 오는 타입과 생성부의 타입이 다를 수 있다.

타입1 a = new 타입2();

인터페이스는 생성자를 가질 수 없다.

추상클래스는 일반 메소드와 추상 메소드를 둘 다 가질 수 있다.

 

DB연동하는 것은 다 인터페이스이다.

인터페이스는 메소드 선언을 가질 수 있다.

오로지 추상 메소드만 가질 수 있다.

 

Q. 추상클래스와 인터페이스 중에 더 추상적인것은 무엇일까요?

인터페이스. 추상메소드만 가질수있으므로. 생성자도 못가짐.

인터페이스에서는 벡터를 써야된다.

추상클래스란?

추상클래스는 일반 클래스와 별 다를 것이 없습니다. 단지, 추상 메서드를 선언하여 상속을 통해서 자손 클래스에서 완성하도록 유도하는 클래스입니다. 그래서 미완성 설계도라고도 표현합니다. 상속을 위한 클래스이기 때문에 따로 객체를 생성할 수 없습니다.

class 앞에 "abstract" 예약어를 사용하여 상속을 통해서 구현해야한다는 것을 알려주고 선언부만 작성하는 추상메서드를 선언할 수 있습니다.

abstract class 클래스이름 {
    ...
    public abstract void 메서드이름();
}

인터페이스란?

추상클래스가 미완성 설계도라면 인터페이스는 기본 설계도라고 할 수 있습니다. 인터페이스도 추상클래스처럼 다른 클래스를 작성하는데 도움을 주는 목적으로 작성하고 클래스와 다르게 다중상속(구현)이 가능합니다.

interface 인터페이스이름 {
    public static final 상수이름 = 값;
    public abstract void 메서드이름();
}

출처 : https://myjamong.tistory.com/150

 

[JAVA] 추상클래스 VS 인터페이스 왜 사용할까? 차이점, 예제로 확인 :: 마이자몽

추상클래스 인터페이스 왜... 사용할까? 우리는 추상클래스와 인터페이스에 대해서 알고 있냐고 누가 물어본다면 알고 있다고 대답을 하고있습니다. 그런데 이론적인 내용 말고 정작 "왜 사용하

myjamong.tistory.com

 

다형성

다형성은 객체지향의 특징 중 하나이다.

선언부 타입과 생성부 타입이 다를 때 사용 가능하다.

 

Vector<String> nameList = new Vector<>(); //다형성을 누릴 수 없다.

List<String> nameList = new Vector<>();//다형성을 기대 할 수 있다.

List는 interface이다.

공통된 기능에 대해 정의하고 있다.

실제 메소드에 대한 (오버라이딩은) 구현은 Vector, ArrayList가 하고 있다.

이것을 권장함

똑같은 메소드를 호출하는데 어떤 객체를 구현했지는에 따라 기능이 달라짐.

인터페이스 중심의 코딩을 전개하는것

클래스간의 결합도를 낮춰주니까 재사용성 높아진다.

단위 테스트도 가능하다.

그러니 인터페이스 중심으로 설계하는것이 좋다.

 

FlyBehavior flyBehavior; //인터페이스-날다, 날지못한다.
QuackBehavior quackBehavior; //인터페이스-MuteQuack무음(나무), 삐익(고무오리)Squeak, 청둥(꽥꽥)Quack 기능이 다르다. 다형성

소리내는 기능이 다르다. 다형성이다.

 

구현체 클래스가 뭐지????????잘모르겠다.

package dev_java.thread1;

import javax.swing.JFrame;

public class JFrameTimerClose extends JFrame {
  public JFrameTimerClose() {
    super("JFrame테스트-5초 후 창닫기");
    this.setSize(500, 500);
    this.setVisible(true);
    // 대기
    try {
      Thread.sleep(5000);// 5초
    } catch (InterruptedException ie) {
      ie.printStackTrace();
    }
    setVisible(false);// 5초후에 사라짐
  }

  public static void main(String[] args) {
    new JFrameTimerClose();// 생성자 호출하기
  }
}

super와 this

https://crazykim2.tistory.com/551

 

[JAVA] this와 super 정의 및 사용법

안녕하세요 자바 프로그래밍을 하다보면 자식생성자와 부모생성자의 변수 혹은 메서드의 이름이 같은 경우 구분을 해줘야합니다 구분을 할 때 this와 super를 사용하여 구분을 지을 수 있습니다

crazykim2.tistory.com

 

network3>TalkServer

스레드라는 클래스를 구현체로 사용하면 슬립 혹은 일드 혹은 조인 같은 여러가지 메소드를 받는다.

대기하는 기능이다.

화면 그리는 스레드

서버는 스레드가 여러기능을 하고있다.

talkClient는 싱글스레드 즉 메인스레드가 화면도 구현하고 다른거도 한다.

스레드가 스케줄링을 하는 역할인듯...?

그런 순서대로 하는 안정성을 보장받으려면 스레드

런에다가 하는건 뭐지? 새치기 하지말라고.... 

 

 

TalkSever

1. 메인 스레드가 동작

2.Run()이 동작- 서버 소켓을 생성하고있다.

 

TalkClient

클라이언트 소켓이 서버 소켓을 사용하였다.

사람들 여러명이다

사람하나하나 소켓이 다르다.

서버소켓을 경유해서 서버에 접근한다.

닉네임을 적는다.

여러명을 관리하기위해서 벡터를 쓴다. 벡터에 쓰레드를 담는다.

  List<TalkServerThread> globalList = null;

서버쪽에서는 벡터가 필요하다. 동시에 여러사람이 접속 하니까.

한사람 한사람을 따로 관리해야된다.

 

서버측에는 소켓이 두개필요하다.

서버소켓은 손님을 응대한다.

일하는 소켓은 그냥 소켓이다.

 

클라이언트가 말한다. 이벤트. 나 입장했어요.

말하는것의 처리는 액션 퍼폼드에서 한다. 말한다.

스레드가 없다. 런메소드가 없다. 경합이 안벌어진다. 말만 하니까. 싱글스레드이다. 각자 폰 하나씩가지고 채팅한다.

 

서버는 들은걸 말한다.

 

톡클라이언트스레드메소드는 듣기이다. 22명을 들어야한다. 경합이 벌어진다. 런메소드에서

//자바는 단일상속만 가능함
//자바는 단일상속의 단점을 보완하기 위해 인터페이스는 다중으로 처리가능함(구현체클래스)
public class TalkServer extends JFrame implements Runnable, ActionListener {

extend다음에 하나만 올수있다.

오버라이드=재정의

 

오버라이드에 앞에 타입이나 파라미터 넣으면 안된다.

추상메소드이기때문에

선언문을 건드리면 안된다.

 

순서를 따질때는 쓰레드가 필요하다

스레드 쓰는방법

1. 상속받는다.

2. 임플리멘츠한다. 인터페이스라서....상속을 이미 받음...

 

//200#토마토#오늘스터디할까?-프로토콜 설계! StringTokenizer=new StringTokenozer("", "#");
//st.nextToken();String-200
//st.nextToken();String-토마토-닉네임
//st.nextToken();String-오늘 스터디할까?-메세지

 

package dev_java.network3;


import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
//선언과 생성을 분리하는 코딩 전개
//자바는 단일상속만 가능함
//자바는 단일상속의 단점을 보완하기 위해 인터페이스는 다중으로 처리가능함(구현체클래스)
//상속을 받거나 implements하면 부모클래스나 인터페이스가 정의하고있는 메소드를 재정의=오버라이딩 할 수 있다.
//Overriding - 선언부는 완전 일치해야함
//인터페이스는 오로지 추상메소드만 갖는다. Runnable도 인터페이스이니까 추상메소드 있다.
//그게 run메소드이다.
public class TalkServer extends JFrame implements Runnable, ActionListener {
	// 선언부
	//클라이언트측에서 new Socket하면 그 소켓정보를 받아서 쓰레드로 넘김
	TalkServerThread tst = null;
	//동시에 여러명이 접속하니까 List - Vector<>(); 멀티스레드 안전, 속도  느림
	List<TalkServerThread> globalList = null;
	ServerSocket server = null;
	Socket socket = null;
	JTextArea jta_log = new JTextArea(10, 30);
	JScrollPane jsp_log = new JScrollPane(jta_log, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
			JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
	JButton jbtn_log = new JButton("로그저장");

	// 생성자
	public TalkServer() {
		//initDisplay();//시점문제- 스케쥴링
	}

	// 화면그리기
	public void initDisplay() {
		jbtn_log.addActionListener(this);
		this.add("North", jbtn_log);
		this.add("Center", jsp_log);
		this.setSize(500, 400);
		this.setVisible(true);
	}
	//스레드가 두 개 이므로 화면요청과 start()순서를 바꾸더라도 각자 처리가 됨
	public static void main(String[] args) {//메소드 자체도 메인 스레드이다. 엔트리 포인트이다. 우선순위가 있다.
		TalkServer ts = new TalkServer();
		ts.initDisplay();//화면요청
		//내안에 run메소드가 재정의(오버라이드) 되어 있으니까
		Thread th = new Thread(ts);//스레드 생성시 파라미터로 TalkServer객체를 넘긴다. 내안에 런메소드가 오버라이드(재정의) 되어있으니까
		//스레드풀에있는 스레드 중에서 우선순위를 따지고 차례대로 입장한다.(ready상태)
		th.start();//52번 호출됨 - 지연발생함 - 클라이언트가 접속할때까지 기다림...
	}

	// 서버소켓과 클라이언트 소켓을 연결. 추상메소드
	@Override
	public void run() {
		//서버에 접속해온 클라이언트 스레드 정보를 관리할 벡터 생성하기 
		//벡터는 멀티 스레드라 안전하다-서버에 동시 접속자 수가 여러명이니까
		//그래서 벡터 안에는 클라이언트를 관리하는 스레드를 추가해야한다.
		//그 스레드는 메세지를 듣고(청취하고) 들은 내용을 그대로 클라이언트측에 내보냄
		//200#토마토#오늘스터디할까?-프로토콜 설계! StringTokenizer=new StringTokenozer("", "#");
		//st.nextToken();String-200
		//st.nextToken();String-토마토-닉네임
		//st.nextToken();String-오늘 스터디할까?-메세지
		globalList = new Vector<>();//멀티스레드안전해서 ArrayList대신 사용함
		boolean isStop = false;
		//try-catch블록. 네트워크는 항상 장애가 발생할 수 있다.-예외처리를 한다.
		//try-catch사이에는 예외가 발생할 가능성이 있는 코드를 넣는다.
		//콜백 함수란? 시스템에서 필요할때 대신 호출해주는 메소드
		//언제 호출 되나요? 스레드 인스턴스 변수.start();요청하면
		//왜이렇게 호출하나요?-여러 스레드가 존재하고 경합이 벌어지므로 우선순위를 따져가며 호출함
		//어떻게 호출 하나요?
		//왜 반드시 run매소드를 제정의 해야 하나요?
		try {
			server = new ServerSocket(3000);//서버포트번호 설정하기
			jta_log.append("Server Ready.........\n");//대기 탐 - 멈춤 - wait
			while(!isStop) {//언제 while문 안으로 진입하지?->new Socket(ip-서버의, port)
				socket = server.accept();
				jta_log.append("client info:"+socket+"\n");				
				jta_log.append("client info:"+socket.getInetAddress()+"\n");			
				TalkServerThread tst = new TalkServerThread(this);
				tst.start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}//////////////////////// [[ end of run ]] /////////////////////////

	@Override
	public void actionPerformed(ActionEvent e) {
		//로그를 파일로 저장하기
		
	}
}

/*
 * 채팅서버 구축하기
 * 
 * 클라이언트 측에서 접속하면 접속해온 정보를 서버측 화면에서 볼 수 있다.(JFrame을 상속했다.)
 * 자바는 단일 상속만 가능하다.-이러한 약점을 인터페이스로 지원하고있다. -그래서 다중 인터페이스 구현체는 가능하다.
 * 스레드를 구현하는 방법에는 
 * 1. 스레드를 상속하기
 * 2. Runnalbe 인터페이스를 implements하기
 * 현재의 TalkSever는 JFrame을 상소받고있어서 Runnable을 
 */

 

package dev_java.network3;
​

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;​
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.awt.GridLayout;
import java.awt.BorderLayout;

public class TalkClient extends JFrame implements ActionListener {
  // 선언부
  //////////////// 통신과 관련한 전역변수 추가 시작//////////////
  Socket socket = null;
  ObjectOutputStream oos = null;// 말 하고 싶을 때
  ObjectInputStream ois = null;// 듣기 할 때
  String nickName = null;// 닉네임 등록
  //////////////// 통신과 관련한 전역변수 추가 끝 //////////////
  JPanel jp_second = new JPanel();
  JPanel jp_second_south = new JPanel();
  JButton jbtn_one = new JButton("1:1");
  JButton jbtn_change = new JButton("대화명변경");
  JButton jbtn_font = new JButton("글자색");
  JButton jbtn_exit = new JButton("나가기");
  String cols[] = { "대화명" };
  String data[][] = new String[0][1];
  DefaultTableModel dtm = new DefaultTableModel(data, cols);
  JTable jtb = new JTable(dtm);
  JScrollPane jsp = new JScrollPane(jtb);
  JPanel jp_first = new JPanel();
  JPanel jp_first_south = new JPanel();
  JTextField jtf_msg = new JTextField(20);// south속지 center
  JButton jbtn_send = new JButton("전송");// south속지 east
  JTextArea jta_display = new JTextArea(15, 38);
  JScrollPane jsp_display = new JScrollPane(jta_display, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
      JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
  // 생성자


  // 소켓 관련 초기화
  public void init() {
    try {
      // 서버측의 ip주소 작성하기
      // socket = new Socket("192.168.0.244",3000);
      // new ServerSocket(3000)이 받아서 accept()통해서 client소켓에 저장됨.
      socket = new Socket("127.0.0.1", 3000);
      oos = new ObjectOutputStream(socket.getOutputStream());
      ois = new ObjectInputStream(socket.getInputStream());
      // initDisplay에서 닉네임이 결정된 후 init메소드가 호출되므로
      // 서버에게 내가 입장한 사실을 알린다.(말하기)
      oos.writeObject(100 + Protocol.separator + nickName);
      // 서버에 말을 한 후 들을 준비를 한다.
      TalkClientThread tct = new TalkClientThread(this);
      tct.start();
    } catch (Exception e) {
      // 예외가 발생했을 때 직접적인 원인되는 클래스명 출력하기
      System.out.println(e.toString());
    }
  }

  // 말하기 - 서버에 전달 - List<TalkServerThread> -> 반복문 -> 전송
  @Override
	public void actionPerformed(ActionEvent e) {
		Object obj = e.getSource();
		String msg = jtf_msg.getText();
		if(jtf_msg==obj) {
			try {
				oos.writeObject(Protocol.MESSAGE
						   +Protocol.separator+nickName
						   +Protocol.separator+msg);
				jtf_msg.setText("");
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}//end of 다자간 대화
		else if(jbtn_one == obj){
			//상대를 선택
			int row = jtb.getSelectedRow();
			if(row == -1){//-1=> end of file
				JOptionPane.showMessageDialog(this, "귓속말 상대를 선택하세요.","info",JOptionPane.INFORMATION_MESSAGE);
				return;
			}else{
				String name = (String)dtm.getValueAt(row, 0);
				if(nickName.equals(name)){
					JOptionPane.showMessageDialog(this, "다른 상대를 선택하세요.","info",JOptionPane.INFORMATION_MESSAGE);
					return;
				}
				//귓속말 입력받기
				String msg1 = 
				JOptionPane.showInputDialog(name+"님에게 보낼 메시지를 입력");
				try {
					oos.writeObject(Protocol.WHISPER+Protocol.separator+nickName+Protocol.separator+name+Protocol.separator+msg1);
				} catch (Exception e2) {
					e2.printStackTrace();
				}
			}
			//선택된 귓속말 상대 초기화 - 선택해제
			jtb.clearSelection();	
		}//end of 귓속말
		else if(jbtn_change == obj) {
			String afterName = JOptionPane.showInputDialog("변경할 대화명을 입력하세요.");
			if(afterName == null || afterName.trim().length()<1) {
				JOptionPane.showMessageDialog(this
				, "변경할 대화명을 입력하세요"
				, "INFO", JOptionPane.INFORMATION_MESSAGE);
				return;
			}
			try {
				oos.writeObject(Protocol.CHANGE
						   +Protocol.separator+nickName
						   +Protocol.separator+afterName
						   +Protocol.separator+nickName+"의 대화명이 "+afterName+"으로 변경되었습니다.");
			} catch (Exception e2) {
				// TODO: handle exception
			}
		}//end of 대화명 변경		
		else if(jbtn_exit == obj) {
			try {
				oos.writeObject(Protocol.TALK_OUT+Protocol.separator+this.nickName);
				//자바가상머신과 연결고리 끊기
				System.exit(0);
			} catch (Exception e2) {
				// TODO: handle exception
			}
		}//end of 나가기		

	}

  // 메인
  public static void main(String[] args) {
    TalkClient tc = new TalkClient();
    tc.initDisplay();
    tc.init();
  }
  

  // 화면그리기
  public void initDisplay() {
    jbtn_change.addActionListener(this);
    jbtn_one.addActionListener(this);
    jtf_msg.addActionListener(this);
    jbtn_exit.addActionListener(this);
    // 사용자의 닉네임 받기
    nickName = JOptionPane.showInputDialog("닉네임을 입력하세요.");
    this.setLayout(new GridLayout(1, 2));
    jp_second.setLayout(new BorderLayout());
    jp_second.add("Center", jsp);
    jp_second_south.setLayout(new GridLayout(2, 2));
    jp_second_south.add(jbtn_one);
    jp_second_south.add(jbtn_change);
    jp_second_south.add(jbtn_font);
    jp_second_south.add(jbtn_exit);
    jp_second.add("South", jp_second_south);
    jp_first.setLayout(new BorderLayout());
    jp_first_south.setLayout(new BorderLayout());
    jp_first_south.add("Center", jtf_msg);
    jp_first_south.add("East", jbtn_send);
    jta_display.setLineWrap(true);
    jp_first.add("Center", jsp_display);
    jp_first.add("South", jp_first_south);
    this.setTitle(nickName);
    this.add(jp_first);
    this.add(jp_second);
    this.setSize(800, 550);
    this.setVisible(true);
  }
}

댓글