자바로 표현하는 자료구조1

jadive study·2022년 10월 12일
0

출처-네이버 부스트코스

객체의 메모리 할당 방법

아래와 같이 new를 사용하여 객체(인스턴스) student를 만들면 Java 가상 머신은 코드를 읽고 메모리가 얼마나 필요한지 계산하고 그만큼의 공간을 힙에 할당한다. 그리고 힙에 있는 공간을 가리키는 4바이트짜리 포인터를 하나 만든다
Student s = new student();

상속

여러 개의 객체가 있으면 상속을 활용하여 객체 간의 관계를 나타낸다. 대학에 있는 People, Student, Undergraduate 클래스를 만들어봅시다.
Person: 대학에 있는 여러 사람입니다. 변수는 redid(빨간색 ID 카드), name, email입니다.
Student: 대학생들입니다. 변수는 GPA, 지금까지 들은 수업들입니다.
Undergraduate: 학부생들입니다. 변수는 year입니다.

이렇게 3개의 클래스를 구성하면, 학생이 사람에 속하게 되고 학부생이 학생에 속하게 되면 학부생도 사람에 속하게 됩니다. 이러한 관계를 나타내기 위해 상속을 사용한다. 클래스를 정의할 때, 아래와 같이 extends를 사용하여 나타낸다

public class Person{
}
public class Student extends Person{
}
public class Undergraduate extends Student{
}
Student 클래스를 만들면 Java 가상 머신은 이 클래스가 Person을 상속-> Person 클래스에 있는 변수와 메소드를 모두 가져온다. 마찬가지로, Undergraduate 클래스를 만들면 Student 클래스에 있는 변수와 메소드를 모두 가져온다.

특징 1. Java에서 각각의 클래스는 하나의 클래스만 상속받을 수 있습니다.
Java와 여러 다른 프로그래밍 언어에서는 다중 상속을 허용하지 않습니다.

특징 2. 상속받는 클래스의 정보만 갖고 있습니다. 즉, 트리를 올라갈 수만 있습니다.

특징 3. 상속받는 클래스의 공간을 함께 할당한다.

Undergraduate u = new Undergraduate();
상속을 받은 상태로, 새로운 객체 Undergraduate u를 정의하면, u에는 4바이트가 할당된다. 그리고 이 포인터가 가리키는 힙에는 Undergraduate에 맞는 공간이 할당된다.
 Undergraduate에 있는 year, Student 클래스에 들어 있는 모든 변수, Person 클래스에 들어 있는 redid, name, email 등의 변수도 힙에 들어간다.
 
Student s = new Undergraduate();
위와 같이, s라는 이름의 Student를 만들 수도 있다.  
Undergraduate 객체에 필요한 만큼 공간을 할당받고 Person의 변수, Student의 변수, Undergraduate의 변수를 모두 알 수 있다. 따라서, Student 클래스의 변수를 파악하고 메모리를 계산할 수 있다.
 
Undergraduate u = new Student();
하지만 반대로 할 수는 없습니다.
힙에 할당되는 공간은 Student에 해당하는 만큼이다. 
 하지만 이렇게 되면 Student에 포함된 내용과 Person에 포함된 내용만 알 수 있다.
Undergraduate 클래스의 내용은 접근할 수 없기 때문에, 이 코드는 컴파일되지 않는다.

Override

String one = "hello world";
String two = "hello world";
// 문자열 비교
if(one.equals(two))
	System.out.println("they are the same");
one의 hello world와 two의 hello world를 비교하는 Java 코드이다.
두 개의 문자열을 비교하기 때문에 equals 메소드는 두 변수가 같다고 할 것이다.
 
Object one = "hello world";
Object two = "hello world";

// 객체 비교

if(one.equals(two))
	System.out.println("they are the same");

이번에는 hello world를 저장한 두 개의 객체가 있다고 해 보자. 이 때 equals 메소드는 두 개의 메모리 주소를 비교하게 될 거다. 따라서 두 개의 객체는 일치하지 않다
이처럼, 객체 클래스의 equals는 메모리 주소를 비교하지만, 문자열 클래스의 equals를 오버라이드하면 메모리 주소 대신 문자열을 비교하게 만들 수 있다.

Comparable 인터페이스

객체에서 원하는 자료형으로 비교하기 위해, Comparable 인터페이스를 활용한다.
그리고 Comparable 인터페이스는 같은 자료형의 다른 객체 하나를 인자로 받아와 비교하는 compareTo 함수를 사용한다. a.compareTo(b)는  a가 b보다 작을 때는 0보다 작은 수, a와 b가 같으면 0, a가 b보다 크면 0보다 큰 수를 반환한다.

if(((Comparable<T>) data).compareTo(obj)==0)

위와 같이 Comparable 인터페이스를 만들면 자료형에 알맞은 데이터가 들어와 compareTo 함수를 통해 같은 자료형의 데이터를 비교할 수 있다.

제너릭 프로그래밍

제너릭 프로그래밍은 다양한 자료형의 객체에 대해 작성한 코드를 재사용한다는 객체 지향 기법이다.

// 정렬 알고리즘 예시

public class ss{
	public int[] superSort(int[] array){
		// ...sort...
		return array;
	}
}
 

위와 같은 정렬 알고리즘이 있다고 하자.
이 정렬 함수를 int 외의 다른 자료형에 대해 사용하려면 어떻게 해야 할까?
제너릭 프로그래밍이 없었다면 int를 String, Person 등 문자열, 원하는 객체로 바꿔야 했을 것이다.
제너릭 프로그래밍의 목표는 1가지의 코드만 작성해서 이를 다른 자료형에 대해 재사용할 수 있게 만든다.

매개변수화 타입

제너릭 프로그래밍을 구현하기 위한 방법으로 매개변수화 타입을 사용할 수 있다. 꺾쇠괄호<> 안에 Type Parameter를 넣어 컴파일 시 구체적인 타입이 결정되도록 하는 방법

이렇게 매개변수화 타입을 사용하려면 클래스, 함수를 정의할 때 아래와 같이 고쳐주어야 합니다. 다만, 생성자의 경우 예외적으로 E를 사용하지 않는다.

// 클래스
public class LinkedList
public class LinkedLilst<E>

// 함수
public void addFirst(String S)
public void addFirst(E obj)

public String removeFirst()
public E removeFirst()

예시로, 매개변수화 타입을 사용하여 어떤 자료형이든 담을 수 있는 제너릭 노드를 만들면 다음과 같다. 아래 코드에서 E는 모두 같은 자료형을 의미한다.

// 제너릭 노드
class Node<E>{
	E data;
	Node<E> next;
	public Node(E obj){
		data=obj;
		next=null;
	}
}

배열의 경우, 다음과 같이 정의한다
// 배열

E[] storage = (E[]) new Object[size];
아래 코드처럼 정의하면 컴파일이 되지 않는다.
// 배열 (컴파일 X)
E[] storage = new E[size];
 

Autoboxing

byte, short, int, char 등의 기본 자료형에 대해서 Java 가상 머신은 정확하게 필요한 만큼의 메모리를 할당합니다. 하지만 객체에 대해서는 이 객체를 가리키는 4바이트짜리 포인터와 힙의 공간을 할당한다

따라서 기본 자료형은 객체가 아니고 이것들은 객체 메소드를 상속받지 않는다.
하지만 Java에는 기본 자료형뿐만 아니라 래퍼 클래스(Wrapper Class)가 존재한다.
래퍼 클래스는 객체 버전의 기본 자료형입니다. byte는 Byte, short는 Short, int는 Integer, char는 Char로 바꾸면 된다.
이 둘 사이에서 Java는 autoboxing을 이용해서 이 둘을 적절하게 서로 바꾼다.

예외 상황 설정하기

 
// Exception 클래스 상속
public class FileFormatException extends Exception{
	public FileFormatException (){
		// super 호출
		super();
	}
	public FileFormatException (String s){
		super(s);
	}
}

// 예외 상황이 발생하면 throw

throw new FileFormatException("Your file is not well formatted")

위 코드에서와 같이 Exception 클래스를 상속받고 생성자를 만든 후, 생성자 안에서 super를 호출하면 예외 상황에 대한 클래스를 만들 수 있다. (super는 만약 어떤 것을 상속받았을 때 상속받은 클래스의 생성자를 호출한다는 의미이다.)

이후 예외 상황이 발생하였을 때 throw를 사용하면, 그 예외 상황의 이름으로 에러가 발생하게 된다.
출처: 네이버 부스트 코스


자바문법을 배우면서 자료구조를 같이 배우고 있는데 확실히 파이썬보다 문법이 긴것같다는 느낌을 받았다.
하지만 자료구조는 c나자바로 입문하는것이 좋다고 해서 메모리 할당방법과 같이 공부하니 이해가 쉬워지는것 같다

profile
개발 메모창고

0개의 댓글