배움 __IL/TIL 1기

TIL : 47번째- 230208 [2-1-수]

Mo_bi!e 2023. 2. 8. 20:08

I. 자바 객체지향

1. 다형성

(1) 의의

다형성은 코드 일부분 분리했다가, 바꿔끼움으로서 다양한 형태를 가지게 하는 것이다.

인자를 일부분 바꾸려고 하지만, 타입이 한정되어있어서 못바꾼다.

그렇다면 이러한 인자를 포함하는 상위타입을 두고, 이를넘겨주면 가능하다.

(2) 문제점

1)

<Program.java>

package com.newlecture.web.poly;

public class Program {
	
	//원래는 다른 곳에 jar 파일로 있는곳이고, 재사용하는 것이다. 
	static void printIntro(ICTBanner banner){
		
		System.out.println("┌───────────────────────┐");
		//특정 교육센터 이름이 들어간 부분을 분리하자 
		banner.print();
//		System.out.println("   뉴 렉 처 교육 프로그램     ");
		
		System.out.println("메인 메뉴 항목들...");
	}
	
	

	public static void main(String[] args) {
		ICTBanner banner = new ICTBanner();
		printIntro(banner);
	}
}

이 기본 형태를 두고,

banner.print()로 그때 그때 바꿔 끼우는 방식이다.

 

<ICTBanne.javar> 

package com.newlecture.web.poly;

public class ICTBanner {

	public void print() {
		
		System.out.println("    ICT 교육센터    ");
		
	}
}

 

 

2)

ICTBanner 클래스로 분리를 했는데, 세가지를 다 분리했다 그런데 다른회사에도 또 팔수있을까?

불가능하다 printIntro의 인자의 타입은 한정되어있기 때문에, 가능한 인자는 하나에 불과하다 -> 이거는 다형성이 아니다.

 

다형성은 인자의 상위의 자료형을 써야한다.

향후 구현할 녀석의 스펙만 구현해야한다. -> 인터페이스

 

목록을 구현한 녀석만 넣을수 있게끔 

 

2. 다형성 만들기

4가지 방법 : 인터페이스 / 내부클래스 / 익명클래스 /람다표현식

(1) 인터페이스 

1)

'Banner 의 인터페이스'에다가 ICTBanner 을 implements 이다.

package com.newlecture.web.poly;

public interface Banner {
	
	void print();
}

interface를 만들고,

package com.newlecture.web.poly;

public class ICTBanner implements Banner{

	public void print() {
		
		System.out.println("    ICT 교육센터    ");
		
	}
}

이렇게 되면 Banner를 구현한다.

 

2)

package com.newlecture.web.poly;

public class Program {
	
	public static void main(String[] args) {
		Banner banner = new ICTBanner();
		Exam.printIntro(banner);
	}
}

main함수가 있는 Program 에다가 상위의 자료형 Banner 의 인스턴스를 만들고, 그 인스턴스를 printIntro 의 매개변수로 넣는다

package com.newlecture.web.poly;

public class Exam {
	
	//원래는 다른 곳에 jar 파일로 있는곳이고, 재사용하는 것이다. 
	static void printIntro(Banner banner){
		
		System.out.println("┌───────────────────────┐");
		//특정 교육센터 이름이 들어간 부분을 분리하자 
		banner.print();
//		System.out.println("   뉴 렉 처 교육 프로그램     ");
		
		System.out.println("메인 메뉴 항목들...");
	}

}

그러고 printIntro 의 인수는 ICTBanner 이 아니라 인터페이스인 Banner 클래스를 인수로 받는다

3)

package com.newlecture.web.poly;

public class Program {
	
	public static void main(String[] args) {
		Banner banner = new ICTBanner();
		Banner banner2 = new NewlecBanner();
		Banner banner3 = new gongseong();
		
		Exam.printIntro(banner);
		Exam.printIntro(banner2);
		Exam.printIntro(banner3);
	}
	
}

이렇게 배너 2, 3 ,4 등 다양한 곳에 배너의 제목을 출력할 수있다.

 

 

4)

implements의 구현과 달리 extends 의 방식은 재정의 이다.

클래스로서의 banner가 아니라, 약속으로서의 banner가 자바로 들여온게 인터페이스이다.

 

약속이란 print 구현하면 돼 정도의 약속을 의미하고 이게 interface이다

약속만 정의할수있고, 정의하고, 약속만가지고 있는 새로운 자료형이다.

 

이경우 interface는 조심해야한다 

publice, private 등이 안나온다 왜냐하면 약속의 정의에 불과한거지 구체적으로 보호에 대해서 정의 할수는 없다.

interface 에다가 int x 등의 멤버 를 정의할 수없다

여기는 향후에 구현해야 할 약속만 있다.

그래서 목록만 있어야한다.

 

(2) 내부클래스

1)

약속 에서 형상화 할 때

 

약속을 정의하면 약속을 이용할 때, 약속을 구현하는 클래스가 추가되어야 하고, 이를 객체화해서 넣는것이 불편하다 (무려 3단계)

JDK 4 까지는 이렇게 했어야했다 꼼수가 있었다. (구현위해 클래스 만드는 것에 불과 함)

여러명이서 개발 시 클래스명 충돌문제 와 클래스 파일을 매번 만들어서 설계에 영향을 주거나

 

2)

결국 내부 클래스를 만들어서 가능하다

banner라는 약속을 구현할 클래스만 필요하기 때문에 이렇게도 가능하다

package com.newlecture.web.poly;

public class Program {
	
	
	public static void main(String[] args) {
    
		//        2. 내부 클래스
//        내부 클래스가 생긴 이유는 설계에 영향을 주지 않으면서 인터페이스를 구현한 클래스를
//        사용해야하는 상황이 있을 경우에 사용하기 위해 생김

        class InnerBanner implements Banner{
            @Override
            public void print() {
                System.out.println(" 내부 클래스 배너 ");
            }
        }
        Exam.printIntro(new InnerBanner());
		
	}
	
	
}

메소드안에 클래스라니?? 당황스러움 

전체 아키텍처를 위한것이 아니라, 인터페이스 구현을 위해서만 사용을 하자가 되었다. (남발 하면안돼)

 

(3) 익명클래스

1) (인터페이스인데 new 못하는게 무슨상관?????)

interface구현약속불과하지 new를 할수없다 말도안된다 

그러면 구현하려면 클래스가 있어야지, 그런데 클래스를 꼭 만들어야해? 비효울적인데?

 

즉각클래스? 바로쓰는 클래스 어떨까? 인터페이스인데 구현블럭 만들어준다.

이러면 클래스없이, 클래스명 지정해줄필요없이 banner를 구현해서 한번 생성해서 넘겨주면된다 -> 괜찮네!!!

익명클래스를 하자!

//        3. 익명 클래스
//        1번 쓸 클래스인데 클래스에 이름까지 줄 필요가 있을까?
//        그냥 생성할 때 바로 대입하면 되지

        Banner anonymousBanner = new Banner() {
            @Override
            public void print() {
                System.out.println(" 익명 클래스 배너 ");
            }
        };
        
        Exam.printIntro(anonymousBanner);

        Exam.printIntro(new Banner() {
            @Override
            public void print() {
                System.out.println(" 익명 클래스2 배너 ");
            }
        });

2) 익명 클래스 1, 2차이??

 

--

 

(4) 람다 표현식

1)

그런데,,,, 이거도 비효율성이 커!

객체 생성이라는거 자체도 사실은 의미가 없을수있다.

좀더 쉽게 사용하는법은? 람다표현식

 

자바는 바로위에있는 코드와 동일함

Exam.printIntro(()->{
    System.out.println("람다 클래스 ICT 교육센터");
});

람다는 자바에서는 메소드 에서 결합되는 약속에서만 쓰라고 하고있다.

그런데 람다는 구현할 약속이 함수하나 일때가 좋지, 2개이상일 때는 이것을 이용할 수없다

즉 람다가 나온것은 리턴값이 있는것을 쉽게 전달하기 위해서 추가되었다.

 

람다 중괄호 없애면 리턴값 표현이 가능하다

 

2)

List list = new ArrayList();
list.add(new Exam2(1,3,2));
list.add(new Exam2(10,20,30));
list.add(new Exam2(60,50,40));
list.add(new Exam2(3,4,5));
//Comparator 도 람다로 구현해서 대입
list.sort((x,y)->((Exam2)x).getKor()-((Exam2)y).getKor());

System.out.println(list);

lamda 를 설명하기 위한 방법

list 는 기본형 참조형 변수가 있음

 

기본형 변수는 별도로 지정하지 않아도, add, sort의 기준이 있음

참조형 변수는 넣어주는 인수에 대해서 별도로 지정해주어야 하고 이럴 때 나오는 것이 Comparator 이다

원래는 앞서 본 Interface 방식으로 해야하지만 번거롭기때문에 위 소스코드 처럼 lamda표현식으로 가능하다

 

 

II. 서블릿

(1) doget 에 DB 연동하기

1)

package com.newlecture.web.controller.menu;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet("/menu/list")
public class ListController extends HttpServlet{

	
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		
		PrintWriter out = resp.getWriter();
		out.print("hello");
		
		String query = "";
        String sql = String.format("select * from member where nicname like '%s'", "%"+query+"%") ;
		
				
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			String url = "jdbc:oracle:thin:@oracle.newlecture.com:1521/xepdb1";
			Connection con = DriverManager.getConnection(url, "NEWLEC", "rland");
			
			Statement st = con.createStatement();
			ResultSet rs = st.executeQuery(sql);
			
			// 필터링, 집계, 정렬
			while(rs.next())	// 서버의 커서를 한칸 내리고 그 위치의 레코드를 옮겨 오는 것. -> 레코드 하나가 저장되는 공간은?
			{
				int id = rs.getInt("id");
				String name = rs.getString("name");
				String nicName = rs.getString("nicname");
				String format = String.format("id:%d, name:%s, nicname:%s\n" , id, name, nicName);
				System.out.println(format);
			}
			
			con.close();
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		
		
	}

		
}

2)

오라클 JDBC드라이버 사실은 없다

클래스파일은 실제로 톰캣이라는 것이 있고, 개발할때 사용하는것이지 톰캣이 있는 위치배포가된다.

 

실제로는 여기에다가 올라가게된다

 

프로젝트가 있는 곳에서 실행(JRE)이 아니라 여기(톰캣)에다가 실행이된다

 

이경우 오라클 드라이버는 같이가야할까? 아니면 링크를 달아주어야할까? : 같이 가야한다

WEB으로 만든 프로젝트는 같이가야한다. 그래서 그 라이브러리를 톰캣에 저장해서 배포해야한다.

이렇게 콘솔로 출력이 가능하다

 

(2) doget 콘솔출력을 넘어 브라우저에 출력하기

1)

while(rs.next())	// 서버의 커서를 한칸 내리고 그 위치의 레코드를 옮겨 오는 것. -> 레코드 하나가 저장되는 공간은?
{
    int id = rs.getInt("id");
    String name = rs.getString("name");
    String nicName = rs.getString("nicname");
    String format = String.format("id:%d, name:%s, nicname:%s\n" , id, name, nicName);
    System.out.println(format);


    out.println(format);


}

out.println 을 해주면된다.

이렇게 하면 웹으로 표현이가능

 

 

2)

그런데 한글이 깨진다.

왜그럴까? : 인코딩의 문제가 아니라 해석에 대한 차이이다. 

즉 서버에서 브라우저로 응답보내고, 브라우저가 읽을 때 내가 보낸 인코딩방식으로 매칭시켜서 읽어야한다.

 

EUC-KR 되긴하는데,,, 했다고 좋은게 아니다. 다국어 표현할수있 있게끔 UTF표현이 바람직하다

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException {
    // TODO Auto-generated method stub

    //이건 인코딩 방식 , 내가 인코딩 해서 브라우저로 보내는 것 
//		resp.setCharacterEncoding("UTF-8");

    //브라우저에게 너 이렇게 읽어 라고 하는것
    resp.setContentType(LEGACY_DO_HEAD);

내가 UTF보냈으니까, 브라우저에게 UTF 로 읽으라고 해야한다.
사실 브라우저에게 어떤 인코딩으로 읽으라고 한적이없다.

 

브라우저

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		
		//이건 인코딩 방식 , 내가 인코딩 해서 브라우저로 보내는 것 
//		resp.setCharacterEncoding("UTF-8");
		
		//브라우저에게 너 이렇게 읽어 라고 하는것
		resp.setContentType("text/txt; Charset=utf-8");

이렇게 채워주면 잘 출력이 된다.

 

 

 

 

(3) 테이블 형태로 출력하기

1)

테이블형태로 하고싶은데 

<table> 

out.println("<table>");
out.println("<tr>");

out.println(format);

out.println("</tr>");

글자 자체가 아니라 태그로 이해해야한다.

 

 


1. 보충

(1) 읽기

https://liketh.tistory.com/entry/PrintWriter-out-responsegetWriter-%EB%84%8C-%EC%99%9C-%EC%84%A0%EC%96%B8%EB%90%9C%EA%B1%B0%EB%8B%88

 

 

(2) 다형성은 왜?

 

 

 

(3) 람다 list 관련

 

 

 

2. 회고 

1)

오늘 낯선것들이 나와서 혼동이 컸다. 그래도 수업을 마치고 도움을 받아서 이렇게 까지 그나마 정리가 가능했던것 같다 참 다행이다.

서블릿 자체가 가장 지금 낯설다 얘부터 좀 익숙해지면 좋겠다.

'배움 __IL > TIL 1기' 카테고리의 다른 글

TIL : 50번째- 230214 [2-2-화]  (0) 2023.02.14
TIL : 49번째- 230213 [2-2-월]  (0) 2023.02.13
TIL : 46번째- 230207 [2-1-화]  (0) 2023.02.07
TIL : 45번째- 230206 [2-1-월]  (1) 2023.02.06
TIL : 44번째- 230203 [1-5-금]  (0) 2023.02.03