자바-5(클래스)

dragonappear·2021년 3월 14일
0

Java

목록 보기
5/22

# 학습

0. 클래스와 객체:

클래스는 객체지향 프로그래밍에서 객체를 생성하기 위해 상태와 행동을 정의하는 일종의 설계도이다. 여기서 객체란 어플리케이션의 기능을 구현하기 위해 서로 협력하는 개별적인 실체로써 물리적일수도있고 개념적일수도있다

1. 클래스 정의하는 방법

  • 객체란?
    - 객체란 주변에 존재하는 모든 사물, 생명체를 의미한다.
    - 객체를 이루는것은 데이터와 기능이다.
    - 객체를 생성하기 위해서는 객체를 생성을 위한 틀이 필요하다.
  • 클래스란?
    - 객체 생성을 위한 틀이다.
    - 클래스는 객체 생성을 위한 설계도로 볼수있다.
    - 클래스의 구조는 변수와 그에 따른 메소드로 이루어져있다.
  • 인스턴스란?
    - 클래스를 설계도로 본다면, 인스턴스는 설계도로 구현한 구체적인 제품이라고 보면된다.
    - 인스턴스에 따라 들어가있는 변수가 다르기때문에, 변수에 따른 행위가 메소드가 된다.
  • 클래스의 구성요소:
class Class {               // 클래스
    String constructor;
    String instanceVar;     // 인스턴스 변수
    static String classVar; // 클래스 변수

    static {                // 클래스 초기화 블록 (클래스 변수 초기화에 사용된다.)
        classVar = "Class Variable";
    }

    {                       // 인스턴스 초기화 블록(인스턴스 변수 초기화에 사용된다) -> 클래스에서 인스턴스 초기화 블록이 생성자 초기화보다 먼저 진행된다.
        instanceVar = "Instance Variable";
    }

    Class() {                // 생성자
        constructor = "Constructor";
    }

    void instanceMethod() {       // 인스턴스 메서드
        System.out.println(instanceVar);
    }

    static void classMethod() {   // 클래스 메서드
        System.out.println(classVar);
    }
}
    1. 필드:
      - 객체의 고유의 데이터가 저장되는 곳이다.
      - 선언 형태는 변수 선언과 비슷하지만, 변수는 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 실행종료되면 자동 소멸된다.
      - 하지만 필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재한다. 클래스 선언 바로 밑에서 선언되며, 생성자와 메소드보다 위에서 선언된다.
    1. 메소드:
      - 메소드는 해당 객체의 행동을 나타내며, 보통 필드의 값을 조정하는데 쓰인다.
      - 인스턴스 메소드:
      인스턴스 변수와 연관된 작업을 하는 메소드이다. 인스턴스를 통해 호출할수있으므로 반드시 먼저 인스턴스를 생성해야 한다.
      - 클래스 메소드:
      정적 메소드라고 한다. 일반적으로 인스턴스와 관계없는 메소드를 클래스 메소드라고 정의한다.
    1. 생성자:
      -생성자는 객체가 생성된 직후에 클래스의 객체를 초기화하는데 사용되는 코드 블록이다.
      -클래스엔 최소 한개 이상의 생성자가 존재해야 한다.
      -생성자는 인스턴스 생성시 딱 한번 호출되는 메소드이다.
      -생성자 메소드는 인스턴스 변수의 초기화를 목적으로 정의되어야한다.
      -클래스의 이름과 동일한 이름의 메소드이여야한다.
      -반환형이 선언되어 있지 않으면서, 반환하지 않는 메소드이다.
      -반환형이 선언되어 있지 않다는것은 void마저 없다는 것이고, return도 정의되어 있지 않다.
      -인스턴스 생성문과 생성자를 호출하는 호출문은 겹쳐있다. (Number num = new Number())
      -자바의 인스턴스 생성시에는 반드시 생성자가 호출되어야 한다.
      -초기화된변수는 call by reference로 수행된다.
      -this로 전역변수에 대한 값을 초기화시켜준다.
 class Calculator{
 	int left,right;
    
    public Calculator (int left,int rigt){
    	this.left = left;
        this.right = right;
    }
 }
    1. public vs private:
      -pulic, private, protected는 접근제어자의 역할은 한다.
      -접근제어자는 클래스,메소드,필드 모두에 붙을수있다.
      -public class: 모든 package에서 해당 class로 접근이 가능하다.
      -private class: 자신을 포함한 package에서만 해당 class로 접근이 가능하다.
      -protected class: 상속받은 class에서만 해당 class로 접근이 가능하다.
      -public method: 모든 class에서 해당 메소드로 접근이 가능하다.
      -private method: 자신이 포함된 class에서만 해당 메소드로 접근이 가능하다.
      -protected method: 상속받은 class와 자신이 속한 class에서만 접근이 가능하다.
      -public field: 모든 class에서 해당 필드에 접근이 가능하다.
      -private field: 자신이 포함된 class에서만 접근이 가능하다.
      -protected 필드: 상속받은 클래스와 자신이 속한 클래스에서만 접근이 가능하다.

    1. static vs non- static:
      1. 필드

      - 일반적으로 만든 class는 static 영역에 생성되고, new 연산을 통해 생성한 객체는 heap 영역에 생성된다.
      - 객체의 생성시에 할당된 heap영역의 메모리는 Garbage Collector를 통해 수시로 관리를 받는다.
      - 하지만 Static 키워드를 통해 static영역에 할당된 메모리는 모든 객체가 공유하는 메모리라는 장점을 지니지만, GC의 관리 영역밖에 존재하므로 static을 자주 사용하면 프로그램의 종료시까지 메모리가 할당된 채로 존재하므로 자주 사용하게 되면 시스템의 퍼포먼스에 악영향을 주게된다.
      - static 변수는 클래스 변수이다.
      - 객체를 생성하지 않고도 static 자원에 접근이 가능하다.
      - static 변수와 static 메소드는 static 메모리 영역에 존재하므로 객체가 생성되기 이전에 이미 할당이 되어있어서 객체의 생성없이 바로 접근(사용이 가능하다.)
package week5;

public class Example2 {
    public static String appName = "MyExample";

    public static int add(int x, int y){
        return x+y;
    }
    public static int min(int x,int y){
        return x-y;
    }

    public static void main(String[] args) {
        System.out.println(Example2.add(1,2));
        System.out.println(Example2.min(1,2));

    }
}
  • static(정적)변수는 메모리에 고정적으로 할당되어, 프로그램이 종료될때 해제되는 변수이다.
  • static 변수는 메모리에 한번 할당되어 프로그램이 종료될때 해제되는 변수로, 메모리에 한번 할당된다.
  • 메모리에 할당될때 여러 객체가 해당 메모리를 공유하게 된다.
  • 예를 들어, 세상 모든 사람의 이름이 'YYH'인 세상에 살고 있다고 가정하면 아래와 같인 클래스를 만들수있다.
package week5;

public class Person {
    public static String name = "YYH";

    public void printName(){
        System.out.println(this.name);
    }
}
  • 위와 같은 클래스를 통해 100명의 Person 객체를 생성하면 yyh라는 같은 값을 갖는 메모리가 100개나 중복해서 생성된다.
  • 일반적으로 static은 상수의 값을 갖는 경우가 많으므로 public으로 선언을 하여 사용한다.
  • 또한 yyh이라는 이름은 결코 변하지 않는 값으로 final 키워드를 사용한다
  • 이러한 이유로, 일반적으로 static변수는 public 및 final과 함께 사용된다.
    2. 메소드:
    static 메소드:
    클래스에 소속된 메소드이며, 클래스의 인스턴스에는 속하지않는다.
    메모리에 클래스로딩이 될때 생성되기 때문에, 객체가 생성된후 만들어지는 인스턴스 변수에 접근할수없고, static 변수에 대해서만 접근이 가능하다.
    객체를 생성하지 않고도 메소드를 실행할수있다.
    non-static 메소드:
    객체가 생성되고 만들어지는 메소드이므로, static 멤버,메소드와 non static 멤버에 대한 접근이 가능하다.
package week5;

public class Example3 {
    public static int a;
    public int b;
    
    public static int c1(){
        a=5; // ok
        b=5; // x
    }
    
    public int c2(){
        a=5; // ok
        b=5; // ok
    }
}
    1. final:
      - 클래스 앞에 붙으면 해당 클래스는 상속될수없다.
    • 변수 또는 메소드 앞에 붙으면 수정되거나 오버라이딩 될수없다.
    1. abstract:
      - 클래스 앞에 붙으면 추상 클래스가 되어 객체 생성이 불가능하고, 접근을 위해서는 상속받아야한다.
    • 변수 앞에 지정할수없다.
    • 메소드 앞에 붙는 경우는 오직 추상 클래스 내에서의 메소드 밖에 없으며, 해당 메소드는 선언부만 존재하고 구현부는 상속한 클래스 내 메소드에 의해 구현되어야한다.

2. 객체 만드는 방법 (new 키워드 이해하기)

package week5;

public class Example3 {
   private int x =1;
   private int y= 2;

   Example3(){}

   Example3(int x,int y){
       setX(x);
       setY(y);
   }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}
package week5;

public class Example4 {
    public static void main(String[] args) {
        Example3 e1= new Example3();
        Example3 e2= new Example3(3,4);
        System.out.println(e1.getX());
        System.out.println(e1.getY());
        System.out.println(e2.getX());
        System.out.println(e2.getY());
        e1.setX(3);
        e1.setY(4);
        System.out.println(e1.getX());
        System.out.println(e1.getY());

    }
}

-> new 키워드는 새 객체에 메모리를 할당하고 해당 메모리에 대한 참조값을 반환하며 클래스를 인스턴스화한다. 일반적으로 객체가 메모리에 할당되면 인스턴스라고 부른다.

3. 메소드 정의하는 방법

public int getX() {
    return x;
}

public int getY() {
    return y;
}

public void setX(int x) {
    this.x = x;
}

public void setY(int y) {
    this.y = y;
}

접근제어자 및 기타 제어자: 해당 메소드에 접근할수있는 범위를 명시하거나 위에서 업근했듯이 부가적인 의미도 부여할수있다.

반환타입: 메소드가 모든 작업을 수행한뒤에 반환할 타입을 명시한다.

메소드 이름: 메소드명은 동사여야하고, lowerCamelCase를 따르며 뜻이 명확해야한다.
위의 메서드는 getter/setter 메소드이다.

매개변수 리스트: 메소드에서 사용할 매개변수들을 명시한다.

메소드 시그니처: 컴파일러는 메소드 시그니처를 보고 오버로딩을 구별한다.

4. 생성자 정의하는 방법

Point() {} // 기본 생성자

Point(int x,int y){
	setX(x);
    setY(y);
}

생성자를 명시하지 않으면 컴파일러가 자동으로 기본 생성자를 생성한다. 하지만 기본 생성자가 아닌 다른 형태의 생성자만 명시했다면 기본 생성자는 컴파일시에 생성되지 않는다.

5. this 키워드 이해하기

public void setX(int x) {
    this.x = x;
}

public void setY(int y) {
    this.y = y;
}

this 키워드는 인스턴스 자신을 가르킨다. 위 코드에서 this를 사용함으로써 지역변수 x,y와 구분할수있다. 클래스 메소드에서는 this를 사용할수없다. 왜냐하면 인스턴스가 생성되지 않기때문이다.

this()는 해당 클래스 생성자를 호출할수있다. 그렇기 때문에 생성자를 재사용하는데 사용된다.(생성자 체이닝)

public class Point {
    int x;
    int y;
    int z;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    Point(int x, int y, int z) {
        this(x, y);
        this.z = z;
    }
}

과제

1. int 값을 가지고 있는 이진 트리를 나타내는 Node 라는 클래스를 정의하세요.

2. int value, Node left, right를 가지고 있어야 합니다.

3. BinrayTree라는 클래스를 정의하고 주어진 노드를 기준으로 출력하는 bfs(Node node)와 dfs(Node node) 메소드를 구현하세요.(DFS는 왼쪽, 루트, 오른쪽 순으로 순회하세요.)

package week5;

public class Node {
    private int value;
    private Node left;
    private Node right;

    Node(int value){
        this.value = value;
        this.left=null;
        this.right=null;
    }

    public Node addLeftNode(int value) {
        Node newNode = new Node(value);
        this.left = newNode;
        return newNode;
    }

    public Node addRightNode(int value){
        Node newNode = new Node(value);
        this.right = newNode;
        return newNode;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }
}
package week5;

import java.util.*;

public class BinaryTree {
    public List<Integer> bfsList = new ArrayList<>();
    public List<Integer> dfsList = new ArrayList<>();

    public void bfs(Node node) {
        Queue<Node> queue = new LinkedList<>();
        queue.offer(node);
        while (!queue.isEmpty()) {
            Node n = queue.poll();
            bfsList.add(n.getValue());
            if (n.getLeft() != null) {
                queue.offer(n.getLeft());
            }
            if (n.getRight() != null) {
                queue.offer(n.getRight());
            }
        }
    }

    public void dfs(Node node) {
        if (node == null) return;
        if (node.getLeft() != null) {
            dfs(node.getLeft());
        }
        dfsList.add(node.getValue());
        if (node.getRight() != null) {
            dfs(node.getRight());
        }
    }
}
package week5;

import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
import java.util.*;

class BinaryTreeTest {
    static BinaryTree tree;
    static Node root;

    @BeforeAll
    static void createBinaryTree() {
        tree = new BinaryTree();
        root = new Node(1);

        Node temp = root.addLeftNode(2);
        temp.addRightNode(6);
        temp = temp.addLeftNode(3);
        temp.addLeftNode(4);
        temp.addRightNode(5);

        temp = root.addRightNode(7);
        temp.addLeftNode(8);
        temp.addRightNode(9);
    }

    @Test
    void bfs() {
        tree.bfs(root);
        List<Integer> answer = Arrays.asList(1, 2, 7, 3, 6, 8, 9, 4, 5);
        assertArrayEquals(answer.toArray(), tree.bfsList.toArray());
    }

    @Test
    void dfs() {
        tree.dfs(root);
        List<Integer> answer = Arrays.asList(4, 3, 5, 2, 6, 1, 8, 7, 9);
        assertArrayEquals(answer.toArray(), tree.dfsList.toArray());
    }
}

0개의 댓글