티스토리 뷰
클래스란 무엇일까?
클래스는 어떠한 객체들에 대한 분류이다.
- 분류, 집합, 같은 속성과 기능을 가진 객체들을 총칭하는 개념이다.
- 클래스는 해당 객체가 무엇인지 판단할 수 있는 일종의 식별 타입이 된다.
클래스의 구성요소
-
변수 : 클래스의 Scope = { } 안에서 존재하는 변수를 말한다.
-
객체 변수 : 접근 제어자와 변수 타입, 변수 명을 가지는 일반적인 상태 변수를 말한다.
- 해당 변수는 클래스 정보에서 초기화되지 않고, 해당 타입을 가지는, 상속받은 객체가 생성되었을 때 Scope에 맞게 가시 된다. (공유된다)
-
클래스 변수 : 위의 요소를 가지면서, static 이 작성된 상태 변수를 말한다.
- 클래스가 로드되는 시점에 Class 정보가 저장되는 영역에서 해당 정보가 등록, 초기화 되기 때문에 이러한 명칭을 가진다. (Perm Gen, Meta space)
- 모든 영역에서 가시되는 성질을 가진다.
-
-
메서드 : 이것도 클래스의 Scope = { } 안에서 존재한다.
-
객체 메서드 : 접근 제어자와 반환 타입, 메서드 명, 매개변수를 가지는 메서드를 말한다.
- 인스턴스 변수와 마찬가지로 객체가 생성되었을 때 Scope에 맞게 가시 된다.
-
클래스 메서드 : 위의 요소를 가지면서, static이 작성된 상태 변수를 말한다.
- 클래스 변수와 마찬가지로 클래스 로드 시에 등록, 초기화된다.
- 클래스를 생성하는 메서드인 팩토리 메서드를 정의할 때 static을 사용한다.
- 어떠한 기능을 사용하기 위해 해당 타입의 객체를 생성하는 것이 무리가 있을 때, (유틸 성 기능의 필요함으로) static을 적용한다.
- 예 : String.valueOf(), String.join(), String.format() 등
-
-
생성자 : 당연히.. 클래스의 { } 안에 있다.
- 객체를 생성할 때 사용되는 특별한 메서드를 말한다.
- 별도의 생성자를 작성하지 않을 경우 인자가 없는 생성자가 자동으로 생성된다.
- 생성 시점부터 필요한 상태 변수가 있을 경우 매개 변수를 가지는 생성자를 이용한다.
- 객체를 생성할 때 사용되는 특별한 메서드를 말한다.
클래스의 생성 방법
Public final class FullName {
// 어떠한 분류(클래스 타입)에 속하는 객체들이 가지는 상태 변수 : 객체의 상태
private final String firstName;
private final String lastName;
// 객체가 가지는 상태 값을 조작, 제공하는 메서드 : 객체의 행위이자 책임이다.
// 메서드 선언부 public String getFirstName() : 객체가 수행해야할 책임
// -> 인터페이스 구현, 추상 클래스의 상속을 통한 추상적인 책임은 무조건 구현하여햐 한다.
// 메서드 구현부 { } : 객체가 해당 책임을 수행하는 방법. (객체의 자율적인 행위)
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
// 객체를 생성할 때 사용되는 생성자 : 인자 값을 통한 초기화를 진행하거나, 별도 로직을 수행한다.
public FullName(String first, String last) {
this.firstName = first;
this.lastName = last;
}
public FullName() {
this("dev","lob");
}
}
클래스에서 사용될 수 있는 수식자
-
접근 제어자 : 적용된 키워드에 따라 해당 객체, 메서드가 가시 될 범위를 결정한다.
- public : 모든 클래스에서 해당 클래스를 참조 가능하다.
- package-private : 해당 클래스가 포함된 패키지 내에서만 참조 가능하다. (지정이 없는 경우)
- protect : 서브, 하위 클래스와 동일 패키지 내부에 존재하는 클래스만 참조 가능하다.
- private : 자기 자신인 객체 내부에서만 참조 가능하다. (인터페이스도 JDK9부터 사용 가능)
-
abstract : 해당 클래스, 메서드에서 구현부를 가지지 않고 상속 시 구현을 강제하는 지정 방식이다.
- 추상 클래스, 인터페이스에서 사용된다.
-
static : 해당 클래스가 인스턴스화 되어있지 않아도 사용 가능하다는 지정 방식이다.
- 위에서도 언급하였지만 생성 방식과 시점이 다르다.
-
final : 해당 지정자가 작성된 것에 대해 상속이나 변경을 금지한다는 의미이다.
→ 일종의 관례로써 전역적으로 사용되는 static 요소들은 final을 붙인다고 한다.
→ 하지만 private가 지정된 메서드나 final class에 대해선 명시하지 않아도 된다.
-
객체 변수 : 그 필드의 값이 변경되는 것을 금지한다.
→ 값을 해당 필드에서 초기화하지 않는다면, 생성자를 통한 초기화가 강제된다.
-
객체 메서드 : 해당 클래스 타입을 상속받는 서브, 하위 클래스에서 오버라이드를 금지한다.
-
클래스 자신 : 해당 클래스의 상속을 금지한다. (String, Integer.... 등)
-
-
transient : 객체 직렬화 시에 직렬화 대상에서 제외한다. (이 경우 null로 처리된다.)
-
volatile : 해당 지정자가 붙은 변수에 대해서는 스레드가 값을 캐시하지 않고, 메인 메모리에서 처리한다.
-
시간에 따라서 각 쓰레드가 참조하는 값이 달라지는 것을 방지한다.
-
하나의 쓰레드가 값을 증가시키고, 여러 쓰레드가 값을 읽는 경우 항상 최신의 값을 제공하기 위해서는 해당 지정자를 사용하는 것이 좋다.
→ 여러 쓰레드가 값을 증가시키고, 읽는다면 Atomic Variable을 사용하자.
-
-
sysnchronized : 해당 지정자가 붙은 메서드와 스코프에 스레드 간 동기화를 진행한다는 의미이다.
- (이후에 멀티 쓰레딩이라는 주제가 있으니 그때 알아보자.)
-
native : 해당 지정자가 붙은 메서드는 Java 가 아닌 네이티브 코드를 사용하는 것을 의미한다.
- C/C++ 등으로 작성된 DDL이나 JNI에서 제공하는 코드를 말한다.
-
strictfp : 해당 지정자가 붙은 Double, Float에 대하여서 IEEE 754 규격을 적용한다는 의미이다.
- 인터페이스나 메서드에 지정할 수 있다.
객체를 생성하는 방법?
객체를 생성하는 방법은 new 키워드를 사용하는 것이다.
// public static void main 함수나 그외 메서드 영역, 클래스에서 사용한다.
// 클래스 타입, 인스턴스(레퍼런스) 변수명 = new 키워드 생성자(인자...); 의 형태를 가진다.
// new 를 이용한 객체의 생성을 인스턴스화라고 한다.
FullName fullName = new FullName("babo", "Lob");
객체를 생성하면, 해당 객체는 바로 Heap 영역에서 생성된다. 이때 final을 제외한 모든 변수는 초기화되지 않은 상황이 되는데, 이 경우 초깃값을 가지게 된다.
- char = "\u0000"
- byte, short, int = 0
- long = 0L
- float = 0.0F
- double = 0.0D
- boolean = false
- 배열, 레퍼런스 변수 = null
올바른 객체지향 시점 (내가 매번 복기하는 3가지 문장)
- 클래스는 객체지향의 핵심이 아니다. 클래스는 객체를 구현하는 메커니즘이자 설계도일 뿐이다.
- 클래스는 결국 비슷한 특징을 가지는 객체들의 분류를 의미한다.
- 클래스는 어떠한 값을 담는 것이 중요한 게 아니다. 객체가 되었을 때, 제공할 행위가 중요하다.
메서드를 정의하는 방법?
메서드 시그니처?
메서드 정의 시에 메서드의 이름과 매개 변수들을 의미한다.
다음 주제에서 정리해야 될 것으로 예상되는 오버 로딩을 제공하기 위함이다.
// {public, private} {static, strictfp, sysnchronized} {Types, void} 메서드명 (인자들) {}
public String getFirstName() {
return this.firstName;
}
메서드의 기본적인 동작
반환될 값의 타입이 존재한다면 (void 가 아니라면) return을 통한 값 전달이 강제된다.
- return을 통한 값 전달은 쉽게 생각하면, 메서드가 호출된 곳에 값을 주는 것이다.
생성자를 정의하는 방법?
생성자에 대해서도 메서드 시그니처가 적용된다. 이는 점층적 생성자 패턴을 통해 알 수 있다.
전달하는 인자에 의해서 호출되는 생성자가 달라진다.
- 점층적으로 생성되는 생성자가 5개 이상으로 늘어난다면 코드가 복잡해진다.. 이때에는 빌더 패턴을 고려해보자. (이펙티브 자바)
public SomeClass() {
}
SomeClass some = new SomeClass();
public SomeClass(String a) {
this.aa = a;
}
SomeClass some = new SomeClass(a, b);
public SomeClass(String a, String b, String c) {
this.aa = a;
this.bb = b;
this.cc = c;
}
SomeClass some = new SomeClass(a, b, c);
......
this 키워드 이해하기
this 참조 변수는 객체가 자기 자신을 참조하는 데 사용하는 키워드이다.
즉 this는 해당 객체의 참조 값 (hashcode 값)을 가지고 있는 것이다.
@Test
public void helloThis(){
Animal animal = new Animal();
animal.showThis();
System.out.println(animal);
}
public class Animal {
public Animal() {
}
public void showThis() {
System.out.println(this);
}
}
notefive.oop.Animal@4eb7f003
notefive.oop.Animal@4eb7f003
결과를 보면 System.out.println(this), System.out.println(animal)가 동일한 결과를 출력함을 알 수 있다.
객체를 println으로 출력할 때는 인스턴스를 출력할 경우 toString()을 호출한다는 것은 알 것이라고 생각한다.
재정의가 되지 않았을 경우, Object의 toString()을 호출한다.
문자를 Bold 처리한 부분을 보면 출력되는 정보에 뒷부분에 hashCode()를 사용함을 볼 수 있다.
// Object의 toString
public String toString() {
return getClass().getName() + "@" + **Integer.toHexString(hashCode());**
}
this는 언제 사용하는가?
- 객체 변수와 같은 이름을 가진 다른 것이 존재할 때 객체 변수를 가리키고 있음을 명확히 한다.
String name;
public void someMethod(String name) {
this.name = name;
}
- 생성자에서 다른 클래스의 생성자를 호출하는 데 사용할 수 있다.
// 해당 코드는 밑의 생성자를 호출한다.
public SomeClass() {
this("someString");
}
public SomeClass(String a) {
this.aa = a;
}
- 현재 Java 객체를 매개 변수로 전달하는 데 사용한다.
public void SomeClassA{
public void run() {
SomeClassB someClassB = new SomeClassB();
someClassB.getClass(this);
}
}
public void SomeClassB{
public void getClass (SomeClassA some){
// Do SomeThing
}
}
- 현재 객체를 반환하는 데 사용할 수 있다. 해당 코드는 빌더 패턴에서 볼 수 있다.
public Builder name(int val) {
name = val; // 사용되는 변수명이 다르므로 this를 생략 가능하다.
return this; // 객체 자기 자신을 반환함으로써 참조 연산자 . 을 이용한 체이닝이 가능하다.
}
5주 차 과제 BinaryTree 구현하기
트리 (Tree)
- 나무의 형태를 뒤집은 것 같은 형태의 자료구조이며, 각 노드는 M개만큼의 자식 노드를 가지게 된다. 루트 노드부터 시작하여 각 노드는 단반향 간선을 통해서 연결되어 있으며, 하위 레밸에서도 트리가 반복되는 모습을 보이게 되어있다.
- 트리의 길이는 출발한 노드부터 목적지 노드까지의 거쳐야 하는 가짓수를 의미한다.
- 트리의 깊이는 루트 노드부터 특정 노드까지의 길이를 의미한다.
이진트리 (Binary Tree)
- 모든 노드의 자식 노드가 최대 2개까지인 트리를 말한다.
Binary Tree의 종류
-
이진 탐색 트리 (Binary Search Tree)
- Root 노드의 값을 기준하여 좌, 우측에 값을 나누어 저장하는 반 정렬 상태의 이진트리이다.
- 기본적으로 좌측의 서브 트리, 노드들은 Root 노드보다 작으며, 우측은 크다.
- 중복된 값을 허용하지 않는다.
-
정 이진트리 (Full Binary Tree)
- 마지막 래벨의 노드(리프 노드)를 제외한 모든 노드가 두 자식을 가지고 있는 트리를 말한다.
-
완전 이진트리
- 마지막 레밸을 제외하고는 모든 레밸이 완전히 채워져 있는 상태의 트리를 말한다.
- 마지막 레밸의 노드를 채울 때에는 가장 왼쪽부터 채우게 된다.
int 값을 가지고 있는 이진트리를 나타내는 Node라는 클래스를 정의하세요.
- int value, Node left, right를 가지고 있어야 합니다.
public class Node {
private int element;
private Node left;
private Node right;
public Node(int element) {
this.element = element;
left = right = null;
}
public Node(int element, Node left, Node right) {
this.element = element;
this.left = left;
this.right = right;
}
public int getElement() {
return element;
}
public Node getLeft() {
return left;
}
public Node getRight() {
return right;
}
}
BinrayTree라는 클래스를 정의하고 주어진 노드를 기준으로 출력하는 bfs(Node node)와 dfs(Node node) 메서드를 구현하세요.
- DFS는 왼쪽, 루트, 오른쪽 순으로 순회하세요.
public class BinaryTree {
public void dfs(Node node) {
if (node == null) {
return;
}
dfs(node.getLeft());
System.out.print(node.getElement() + " ");
dfs(node.getRight());
}
public void bfs(Node node) {
if (node == null) {
return;
}
Queue<Node> queue = new ArrayDeque<>();
queue.offer(node);
while (!queue.isEmpty()) {
traverse(queue);
}
}
private void traverse(Queue<Node> queue) {
Node poll = queue.poll();
if (poll != null){
System.out.print(poll.getElement() + " ");
getChild(queue, poll.getLeft());
getChild(queue, poll.getRight());
}
}
private void getChild(Queue<Node> queue, Node child) {
if (child != null) {
queue.add(child);
}
}
}
테스트 코드
참고자료
- Holub on Patterns - 실전 코드로 배우는 실용주의 디자인 패턴
- 스프링 입문을 위한 자바 객체지향의 원리와 이해
- http://opendatastructures.org/versions/edition-0.1e/ods-java/6_1_BinaryTree_Basic_Binary.html#sec:bintree:traversal
- https://www.youtube.com/watch?v=_hxFgg7TLZQ&ab_channel=엔지니어 대한민국
'Live Study' 카테고리의 다른 글
Live Study_Week 07. 패키지 (0) | 2020.12.28 |
---|---|
Live Study_Week 06. 상속 (0) | 2020.12.21 |
Live Study_Week 04. 제어문 + 과제 (0) | 2020.12.01 |
Live Study_Week 03. 연산자 (0) | 2020.11.24 |
Live Study_Week 02. 자바 데이터 타입, 변수 그리고 배열 (1) | 2020.11.16 |
- Total
- Today
- Yesterday
- rabbitmq
- spring
- Global Cache
- JDK Dynamic Proxy
- configuration
- AMQP
- HTTP
- RESTful
- 소비자 관점의 api 설계 패턴과 사례 훑어보기
- RPC
- spring AOP
- JVM
- 게으른 개발자 컨퍼런스
- Cache Design
- Data Locality
- 게으른개발자컨퍼런스
- URI
- 근황
- Local Cache
- THP
- Url
- hypermedia
- URN
- mybatis
- Distributed Cache
- JPA
- java
- lambda
- Switch
- cglib
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |