1. 🔥 JAVA 2D!(도형 그리기)

  • JAVA2D란?
    • 광범위한 그래픽 객체를 그릴 수 있다.
    • 도형 내부를 그라디언트나 무늬로 채울 수 있다.
    • 문자열을 출력할 때 폰트와 렌더링 과정을 세밀하게 조정할 수 있다.
    • 이미지를 그릴 수 있고 필터링 연산을 적용할 수 있다.
    • 그래픽 객체들의 충돌을 감지할 수 있는 메커니즘을 제공한다.
    • 렌더링 중간에 객체들을 조합하거나 변형할 수 있다.
    • 화면과 프린터에 같은 방법으로 그릴 수 있다.

지금까지 Graphics g를 사용하여 그림을 그렸다면 완벽한 객체지향의 성격을 가지기 힘들다

  • 내가 원하는 도형 그리고 싶다면 해당 메서드를 새로 파야지 새로운 도형을 그릴 수가 있다..!
  • -> 만약 도형이라는 추상 클래스가 존재한다면 해당 클래스를 재정의하면 좀 더 객체 지향적 성격을 지님

각각의 도형은 순서대로 그려져야 그림의 성격을 유지할 수 있다. 위 처럼 메서드로 관리하게 되면 이것이 불가능..

1.1. 실습 - 객체지향의 성격

import javax.swing.JFrame;
import javax.swing.JPanel;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Ellipse2D;

class Graphics2DPanel extends JPanel{
    Graphics2DPanel(){
        setBackground(Color.ORANGE);
    }
    @Override
    // !중요! 원래 인자로 들어오는 Graphics g는 Graphics2D g객체이다 부모인 Graphics로 업 캐스팅해서 받게된 것
    public void paintComponent(Graphics g){ // g는 호출되는 클래스 ex) JPanel에서 호출된다.
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D)g; // 다시 다운 캐스팅
        
        //shape클래스를 부모로 가지는 미리 정의된 자식 클래스들
        Rectangle2D.Double rect = new Rectangle2D.Double(100,100,200,100);
        Ellipse2D.Double elps = new Ellipse2D.Double(100,100,200,100);

        //그리기, 채우기
        g2.draw(rect);
        g2.fill(elps);
    }
}

public class App extends JFrame{

    App(){
        setTitle("2D");
        setSize(500,500);

        add(new Graphics2DPanel());

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }
    public static void main(String[] args) {
        new App();
    }
}

위 처럼 객체지향의 성격을 지닌 방식의 코딩이 가능해진다..! (JAVA2D)

  • 자바의 버전이 올라가면서 paintComponent로 받는 객체 g가 원래는 Graphics였지만 10년도 부터는 Graphics를 상속 받는 자식 클래스 Graphics2D로 바뀌었다.
    • 하지만 Graphics g를 Graphics2D g처럼 바꾸게 되면 많은 사용자가 원래 개발된 프로그램을 이용하지 못하니 업캐스팅을 통해 유지보수하게 된다.
    • 사용하고 싶으면 다운 캐스팅을 통해 확장 메서드에 접근 가능..!

1.2. 실습 - 객체지향 확장++

class Graphics2DPanel extends JPanel{
    ArrayList<Shape> shapes = new ArrayList<>();

    Graphics2DPanel(){
        setBackground(Color.ORANGE);

        shapes.add(new Rectangle2D.Double(100,100,200,100));
        shapes.add(new Ellipse2D.Double(100,100,200,100));
    }
    @Override
    public void paintComponent(Graphics g){ 
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D)g;

        g2.setColor(Color.RED);
        for(Shape s : shapes){
            g2.draw(s);
        }
    }
}

ArrayList, Shape를 사용하여 좀 더 객체지향적 코딩이 가능해진다.

1.3. 실습 - 안티에얼리싱, 투명도 조절, 선 굵기, 그라디언트

class Graphics2DPanel extends JPanel{
    ArrayList<Shape> shapes = new ArrayList<>();

    Graphics2DPanel(){
        setBackground(Color.ORANGE);

        shapes.add(new Rectangle2D.Double(100,100,200,100));
        shapes.add(new Ellipse2D.Double(150,150,200,100)); 
    }
    @Override
    public void paintComponent(Graphics g){ 
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D)g;
        // 안티에얼리싱 기능 사용
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(Color.RED); // 색 설정
        // 투명도 조절 
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
        // 선 굵기 조정
        g2.setStroke(new BasicStroke(3));
        // 그라디언트 설정
        GradientPaint gp = new GradientPaint(0,0, Color.RED, getWidth(),0,Color.BLUE);
        g2.setPaint(gp);
        for(Shape s : shapes){
            g2.fill(s);
        }
    }
}

1.4. 실습 - 이미지 그리기

class Graphics2DPanel extends JPanel{
    Image img = null; // 이미지 클래스 객체 레퍼런스 변수 필드로 생성

    Graphics2DPanel(){
        setBackground(Color.ORANGE);

        // 간접?적인 참조를 위해 ImageIcon사용
        ImageIcon imageIcon = new ImageIcon("images/flower.jpg");
        // JLabel label = new JLabel(imageIcon); label에 이미지를 붙여서 띄우기 잘 사용하지 않음
        // add(label);
        img = imageIcon.getImage(); //ImageIcon로 부터 이미지를 받아서 Image 레퍼런스 변수에 연결
    }
    @Override
    public void paintComponent(Graphics g){ 
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D)g;

        //g2메서드로 이미지를 그림 
        g2.drawImage(img, 0,0,getWidth(),getHeight(),null);
    }
}

1.5. 실습 - 이미지 그리기++ 확장

class Graphics2DPanel extends JPanel{
    BufferedImage img = null; //BufferedImage클래스 레퍼런스 변수 설정

    Graphics2DPanel(){
        setBackground(Color.ORANGE);
        
        URL url = getClass().getResource("flower.jpg"); // url로 주소값 저장
        try { // 이미지가 없을 경우도 있기 때문에 try/catch문 사용
            img = ImageIO.read(url);  // 이미지 저장
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void paintComponent(Graphics g){ 
        super.paintComponent(g);     

        Graphics2D g2 = (Graphics2D)g;

        g2.drawImage(img, 0,0,getWidth(),getHeight(),null);
    }
}

좀 더 자주 사용되는 방식이다.

1.6. 정리

지금까지 메서드를 통해 도형을 그렸다면..! 이제는 도형 객체를 만들어서 사용한다.

Shape rect = new Rectangle2D.Double(100,100,200,200); g2.draw(rect)

동적 바인딩 같은 느낌으로 객체지향의 꽃인 다형성을 실현 가능하다.

  • JAVA 2D 도형
    • Point2D.Double: 점 클래스
    • Line2D.Double: 직선 클래스
    • Ellipse2D.Double: 타원 클래스
    • Arc2D.Double: 원호 클래스
    • QuandCurve2D.Double: 2차 곡선 클래스
    • CubicCurve2D.Double: 3차 곡선 클래스
  • Shape클래스(JAVA2D)를 통해 객체지향의 개념을 확립할 수 있다.
    • g2.draw()등등..
  • setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);로 안티에얼리싱 기능 사용가능
    • 선이 부드러워 진다.
  • g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));로 투명도 조절 가능
    • AlphaComposite.SRC_OVER: 도형 위에 0.5f만큼 칠한다는 의미.
  • g2.setStroke(new BasicStroke(3));로 굵기 조정 가능
  • GradientPaint gp = new GradientPaint(0,0, Color.RED, getWidth(),0,Color.BLUE);로 그라디언트 설정가능
    • GradientPaint라는 클래스로 객체를 생성
    • 각 x,y좌표 설정 후 지정 색 -> 지정 색까지 그라디언트 설정
    • g2.setPaint(gp);로 입혀준다.
  • 이미지 그리기
    • Image클래스를 사용하여 그릴 수 있음
    • g2.drawImage(이미지, 시작 위치x,시작위치y,너비,높이,null); 좀 더 다양한 인자값이 존재

2. 🔥 Multi-Threading

하나의 프로그램(프로세스)은 여러개의 쓰레드(일꾼)이 존재할 수 있다.

그렇다면 프로세스가 여러개가 존재한다면 현재 컴퓨터내에서 한글, vscode, 크롬을 실행중인것은 뭐라고 할까..?

멀티 프로세싱..!(멀티 태스킹)

멀티 쓰레드의 예) 크롬에서 파일을 다운 받을 때는 아래에 다운 받는 쓰레드가 생성되고 이후에 다른 작업을 해도 전혀 영향이 없음..게임 등등

내부에서는 스케쥴링이라는 방법으로 여러가지 작업들을 하나의 cpu즉, 코어가 번갈아 가며 진행한다. 하지만 사용자에 눈에는 너무 빨라서 동시에 진행하는 것 처럼 보임

  • 멀티 태스킹: 여러개의 애플리케이션을 동시에 실행하여서 컴퓨터의 성능을 높이기 위한 기법
  • 쓰레드: 하나의 프로그램이 동시에 여러가지 작업을 할 수 있도록 하는 것

  • 쓰레드와 프로세스
    • 프로세스는 자신만의 데이터를 가진다.
    • 쓰레드는 동일한 데이터를 공유한다.
    • 즉, 프로세스내에서 동작하는 쓰레드는 각각의 정보를 공유하지만 컴퓨터에서 동작하는 프로세스들은 데이터를 공유하지 못함
    • 정리하자면 프로세스는 하나의 응용프로그램이고 쓰레드는 해당 프로세스내에서 존재한다. 프로세스는 메모리공유가 불가능, 쓰레드는 메모리 공유가 가능하다.

멀티쓰레딩에서 발생하는 문제점: 다중 쓰레드가 하나의 메모리에 동시에 접근한다면 중복의 가능성이 존재

클라이언트와 서버의 통신에서도 최소 0.001초 정도 sleep을 걸어줌

자바는 1990년 윈도우의 등장과 함께 생겨 언어적으로 멀티쓰레딩을 지원한다.

2.1. 실습 - 쓰레드 기초

class MyThread extends Thread{
    MyThread(String str){ // 기본적으로 이름을 받는 생성자가 있음 
        super(str); // super로 호출한다.
    }
    @Override
    public void run(){
        System.out.println(getName()+"쓰레드 출근!"); 
        for(int i = 0; i <= 100000;i++){} //지연용
        System.out.println(getName()+"쓰레드 퇴근!");
    }
}

public class App{
    public static void main(String[] args) {

        System.out.println("Main 쓰레드 출근!");

        MyThread t1 = new MyThread("t1"); //Thread클래스(상속) 객체 생성
        MyThread t2 = new MyThread("t2");
        t1.start(); //main이 쓰레드를 하나 만들어서 실행함
        t2.start();

        System.out.println("Main 쓰레드 퇴근!");
    }
}

자바

  • 기본적으로 Thread를 지원하기 때문에 따로 import하지 않는다.

사진과 같이 독립적으로 비동기 실행하는 모습을 볼 수 있다.

Thread.activeCount() 로 현재 쓰레드가 몇개 존재하는지 확인 가능(static메서드로 Thread로 존재)

2.2. 실습 - 쓰레드++

class MyRunClass implements Runnable{
    String name;
    MyRunClass(String str){
        name = str;
    }
    @Override
    public void run() {
        System.out.println(name+"쓰레드 출근!");
        for(int i = 0; i <= 100000;i++){}
        System.out.println(name+"쓰레드 퇴근!");
    }
    
}

public class App{
    public static void main(String[] args) {

        System.out.println("Main 쓰레드 출근!");

        // 인터페이스 상속
        Thread t3 = new Thread(new MyRunClass("인터페이스 상속"));
        t3.start();

        // 무명 클래스
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("무명 클래스 쓰레드 출근!");
                for(int i = 0; i <= 100000;i++){}
                System.out.println("무명 클래스 쓰레드 퇴근!");
            }  
        });
        t4.start();

        // 람다식
        Thread t5 = new Thread( ()->{
            System.out.println("람다식 쓰레드 출근!");
            for(int i = 0; i <= 100000;i++){}
            System.out.println("람다식 쓰레드 퇴근!");
        });
        t5.start();

        System.out.println("Main 쓰레드 퇴근!");
    }
}

좀 더 다양한 방법으로 쓰레드를 생성하고 실행할 수 있다.!!

2.3. 실습 - sleep

public class App{
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() { 
            //인터페이스 활용, 무명클래스
            @Override
            public void run() {//run 재정의 1~10까지 출력
                for(int i = 0; i < 10; i++){
                    System.out.println(i);
                    try {
                        // 해당 쓰레드를 1초마다 정지
                        Thread.sleep(1000); 
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 비동기 실행이기 때문에 앞서 말한 동시접근 문제 때문에 try,catch문으로 묶어야함
                } 
            } 
        });
        t.start(); //실행
    }
}

해당 초마다 실행 주기를 결정할 수 있음..

2.4. 정리

  • 쓰레드를 생성 방법
    • Thread클래스를 상속 받은 뒤 run()메서드를 재정의 한다.
    • Runnable인터페이스를 구현하는 뒤 run()메서드 재정의 후 Thread클래스의 생성자로 전달한다.

일반적으로 인터페이스를 활용한다.

태그: ,

카테고리:

업데이트:

댓글남기기