본문 바로가기
IT 이야기/Java

[Java Study] 5일차 클래스, 메소드 (class ,method)

by Dblog 2020. 12. 14.
728x90

학습할 내용

  • 클래스 정의하는 방법
  • 객체 만드는 방법 (new 키워드 이해하기)
  • 메소드 정의하는 방법
  • 생성자 정의하는 방법
  • this 키워드 이해하기

클래스

더보기

객체 지향 프로그래밍(OOP, Object Oriented Programming)은 세상 모든 데이터를 객체로 취급합니다. 객체들의 행동과 상태를 구체화하는 형태의 프로그래밍을 객체 지향 프로그래밍이라 합니다.

Java에서 클래스(Class)는 객체를 정의하는 도구로 사용 됩니다. Java에서는 여러 객체를 정의해서 프로그램에 사용하게 됩니다.

클래스를 정의할때는 보통 유사한 특징을 가진 항목들을 정의합니다. 그 때문에 대부분 책에서 클래스를 설명할 때 붕어빵틀, TV, 동물 등의 예시를 많이 사용합니다.

Java 의 클래스는 몇가지 종류와 특징을 가지고 있습니다.

 

클래스 정의하는 방법
  • 클래스(Class)

예제 코드

더보기
Class A {
	// method
    // variable
}

 

  • 내부 클래스(Inner Class)
    • 코드의 캡슐화 증가
    • 코드 복잡성 감소

예제 코드

더보기
Class Outer {
	int val = 0;
	Class Inner {
    	int val = 1;
	}
    
    public static void main(String[] args){
    	Outer out = new Outer();
        Outer.Inner inner = outer.new Inner();
        
        System.out.println(out.val);    // 0
        System.out.println(inner.val);  // 1
    }
}

 

  • 익명 클래스(Anoymous Class)
    • 이름을 가지지 않는 클래스
    • 클래스 선언과 동시에 객체 생성
    • 일회용 클래스로 생성자 선언이 불가능하다
    • 하나의 인터페이스를 상속받거나 구현할 수 있음

예제 코드

더보기
Class Men extends Person {
	// 익명 클래스
	Person p = new  Person() {
    	String name = "kim";
      		void chat() {
        		System.out.println("person class"+name);
		}
	};
    p.chat(); //  "person class  kim"
    
};

 

  • 지역 클래스(Local Class)
    •  외부 클래스의 메소드나 초기화 블록에 선언된 클래스
    • 선언된 블록, 내에서만 사용할 수 있음

 

  • 정적 클래스(Static Class)
    • static 와 함께 선언되는 클래스
    • outer class의 메소드에 사용될 목적으로 정의됨

 

 

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

객체를 만드다는 행위는 클래스를 사용할 준비가 되었다는 뜻과 같다고 생각합니다. 

객체가 생설될때 생성자 또한 같이 생성되어 객체를 초기화 하는데 new 키워드는 객체를 만들어 내고 또한 생성자를 만들어 냅니다.

객체가 생성되면 힙(heap) 영역에 객체를 생성하고 객체의 주소를 변수에 리턴합니다. 객체는 변수로 사용할 수 있습니다.

예제 코드

더보기
class NewClass {
	
    void NewClass{} // 생성자
    
    public static void main(String[] args) {
    	NewClass inits = new NewClass(); // 생성자 선언
    }
}



class NewClass {
	
    
    public static void main(String[] args) {
    	NewClass inits = new NewClass(); // 생성자를 선언하지 않았지만 위 코드와 동일하게 작동
    }
}

 

메소드 정의하는 방법

메소드를 호출하는 방법으로 크게 두가지로 나눌수 있습니다.

  • Call by value
  • Call by reference

먼저 Java는 항상 Call by value 입니다

더보기

아래 예시를 통해 확인할 수 있듯 함수의 인자값을 변형해도 실질적으로 값은 바뀌지 않습니다.

public class Call {
	int val = 10;
	public static void change(int val) {
		val = 30;
	}
    
    public static void main(String[] args) {
    	Call callBy = new Call();
        callBy.change(val);
        System.out.println(val);  // 10
    }
}

change 함수에  val을 넣어서 10으로 선언된 val을 30으로 바꾸려 시도하지만 변하지 않습니다. 

만약 이처럼 파라미터에 값을 넣어서 값을 바꿔도 객체 내부의 값을 변경한 것이지 받은 파라미터 값을 변경한 것이 아닙니다.

public class Call {
	int val = 10;
	public static void change(Call val) {
		val.val = 30;
	}
    
    public static void main(String[] args) {
    	Call callBy = new Call();
        change(val);
        System.out.println(val);  // 30
    }
}

 

Call by value, Call by reference를 Java에서 나누는 것은 무의미 해 보입니다. 아마 C에서 부터 내려온 흔적이 아닐까 생각합니다.

 

Method는 return값의 유무, 타입, 접근제어자, 파라미터, 등의 옵션을 사용하여 다양하게 활용할 수 있습니다.

Method의 구조를 나누면 파라미터, 리턴의 유무에 따라 4가지로 나눌 수 있습니다.

파라미터 리턴
O O
O X
X O
X X

또한 메소드의 구조는 아래와 같습니다.

public 리턴자료형 메소드명(입력자료형1 입력변수1, 자료형2 변수2, ...){
	// 처리내용
    return ;
}

구조에 따라 4가지 형태의 구조를 사용할 수 있습니다.

더보기
  • 입력과 리턴이 모두 있는 메소드
public String Method(String text) {
	text = "output";
	return text;
}

 

  • 입력과 리턴이 모두 없는 메소드
public String Method() {
	String text = "output";
}

 

  • 입력은 없고 리턴은 있는 메소드
public String Method() {
	String text = "output";
	return text;
}

 

  • 입력은 있고 리턴은 없는 메소드
public String Method(String text) {
	text = "output";
}

 

 

메소드는 오버라이딩, 오버로딩 될수 있고 인터페이스에서 사용할 메소드의 이름과 타입을 미리 정의 할 수 있습니다.

더보기
  • 인터페이스

인터페이스에 미리 함수를 정의하면 추후에 클래스를 생성할때 일정한 틀에 맞춰서 개발할 수 있습니다.

public interface Inter {
	public String M1();
	public String M2(String text);
}

 

  • 오버라이딩, 오버로딩

상속의 개념인 오버라이딩, 오버로딩 또한 메소드를 활용한 예시중 하나입니다.

public superClass  implements Inter{

	@Override
	public String M1() {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public String M2(String text) {
		// TODO Auto-generated method stub
		return null;
	}
    
    // overload
	public String M2(String text, String text2) {
		// TODO Auto-generated method stub
		return null;
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		superClass testCase = new superClass();
	}

}

 

 

 

생성자 정의하는 방법

생성자

new 연산자를 통해 객체를 생성할때 반드시 호출되고 먼저 실행되는 함수입니다.

생성자는 인스턴스를 생성할때 반드시 호출됩니다. 생성자는 다른 메서드와는 다르게 인스턴스의 변수를 초기화 시키는 역할을 합니다. 또한 직접 선언하지 않아도 기본 생성자가 선언되어 사용되며 반환값이 없으므로 void나 자료형을 같이  사용할 수 없습니다.

예시

더보기
public class Default() {

	/* 선언 하지 않아도 기본 생성자가 생성됩니다. 
    public Default() {    
    }
    */

	public static void main(String[] args) {
    	Default testCode = new Default();
    }
}
public class Default() {
	int a;
    int b;

    public Default() {}
    
    public Default(int a, int b) {
    	this.a = a;
        this.b = b;
    }

	public static void main(String[] args) {
    	Default testCode = new Default();
        Default testCode2 = new Default(1,2);
        // 기본 생성자가 선언되어 변수 초기화가 안됨
        System.out.println(testCode.a);   // 0  
        System.out.println(testCode.b);   // 0
        // 인스턴스의 a,b 값이 초기화 되어 1,2로 출력
        System.out.println(testCode2.a);  // 1
        System.out.println(testCode2.b);  // 2
    }
}

 

this 키워드 이해하기

this

Java에서 this는 자기자신 즉, 자신의 객체를 말합니다. 생성자에서 변수를 초기화 할때 this.a는 객체가 가지고 있는 int a를 뜻하고 = 뒤에 a는 파라미터 값 a를 의미합니다.

public class Default() {
    int a;
    int b;

    public Default(int a, int b) {
    	this.a = a;
        this.b = b;
    }
}

 

 

 


  • int 값을 가지고 있는 이진 트리를 나타내는 Node 라는 클래스를 정의하세요.
  • int value, Node left, right를 가지고 있어야 합니다.
  • BinrayTree라는 클래스를 정의하고 주어진 노드를 기준으로 출력하는 bfs(Node node)와 dfs(Node node) 메소드를 구현하세요.
  • DFS는 왼쪽, 루트, 오른쪽 순으로 순회하세요.

(추가 요구사항)

  • Full 2진트리인지 확인
  • 전,후,중위 탐색

 

트리

예시 코드

더보기
class Node {
	Node root;
	Node leftChild;
	Node rightChild;
	int data;
	
	public int getData() {
		return data;
	}
	
	public Node(int data) {
		this.data = data;
	}	
	
	public Node getLeft() {
		return leftChild;
	}
	
	void setLeft(Node left) {
		this.leftChild = left;
	}
	
	public Node getRight() {
		return rightChild; 
	}
	
	void setRight(Node right) {
		this.rightChild = right;
	}
	
    void bfs(Node root) {
		Queue que = new LinkedList();
		Node node = root;
		que.add(root);
		while(que.size() != 0) {
			Node data = (Node) que.poll();
			System.out.println(data.data);
			if (data.leftChild != null) {
				que.add(data.leftChild);
			}
			if (data.rightChild != null) {
				que.add(data.rightChild);
			}
		}
	}
	
	void dfs(Node root) {
		Stack stack = new Stack();
		Node node = root;
		stack.add(node);
		while (stack.size() != 0) {
			Node data = (Node) stack.pop();
			System.out.println(data.data);
			if (data.rightChild != null) {
				stack.add(data.rightChild);
			}
			if (data.leftChild != null) {
				stack.add(data.leftChild);
			}
		}
	}
    
}

// Test code
public class BianryTree {
	
	public static void main(String[] args) {
		Node root = new Node(1);
		Node node2 = new Node(2);
		Node node3 = new Node(3);
		Node node4 = new Node(4);
		Node node5 = new Node(5);
		Node node6 = new Node(6);
		Node node7 = new Node(7);
		
		root.setLeft(node2);
		root.setRight(node3);
		
		node2.setLeft(node4);
		node2.setRight(node5);
		
		node3.setLeft(node6);
		node3.setLeft(node7);
        
        
        // bfs
		System.out.println("BFS");
		root.bfs(root);
		
		//dfs
		System.out.println("DFS");
		root.dfs(root);

	}
}

 

 

트리를 만들고 테스트 코드를 작성하면서 입력에 상당한 불편을 느꼈습니다.

입력을 조금 편하게 만들고, 전위, 후위, 중위 순열 출력 까지할 수 있는 함수를 만들어 보기로 했습니다.

 

 

728x90

댓글