Java and OOP related basics 1

sycho·2023년 9월 22일
0

Java

목록 보기
10/18

OOP paradigm의 장점은 생략
OOP 관련 기본 terminology들은 알고 있다고 가정.

making instance

  • Person이라는 class가 어떻게든 정의되어 있다고 해보자. attribute로 name이 있고 method로 printName이 있다고 해보자.

  • 기본형과는 다르게, Kotlin처럼 참조형을 저장하는 변수만 만드는게 가능하다. C++과 다르게 instance 자체를 저장하는 변수는 만드는게 안된다.

Person p1;
  • instance를 만들거면 new를 활용. C++과 동일하게 생성자의 이름이 class의 이름과 동일하다.
p1 = new Person();
  • field 접근, method 사용 전부 C++과 비슷하다.
p1.name = "Baekrang";
p1.printName();
  • C++과 다르게 class의 참조형을 저장하는 변수는 본인 type의 참조형만 저장이 가능하다.

  • 다음은 같은 이름(Baekrang)이 나올 것이다. 같은 참조자를 가리키기 때문. 같은 pointer을 저장하게 된거라고 생각해라.

p1 = new Person();
p2 = new Person();
p1.name = "Baekrang";
p2.name = "BlackRabbit";
p2 = p1;
System.out.println(p1.name);
System.out.println(p2.name);
  • instance의 배열은 String배열 처럼 reference들의 모음이다.

types of variable in class

  • C++이랑 매우 유사하다.
  • class variable : 동일 class instance들이 공유하는 변수. static으로 선언. 프로그램 실행동안에는 계속 존재. 접근은 class 이름을 가지고 한다.
  • instance variable : instance마다 가지는 변수. instance 사라지면 소멸. 접근은 instance를 가지고 한다.
  • local variable : method, constructor, init block 등에서 정의된 변수. 해당 영역 벗어나면 소멸. class 외부에서 접근 불가.
class MyClass
{
	int instance_variable;
    static int class_variable;
    
    void classMethod() 
    {
    	int local_variable;
    }
}
    	

defining function/method

  • C/C++이랑 유사하나 굳이 형태를 언급하자면
int method1(int x, int y)
{
	return x + y;
}
  • function은 function 내 지역변수랑 parameter만 접근이 가능.

  • 특정 class instance의 method는 (조건에 따라) instance variable 접근이 가능하며 그 외에도 parameter 선언된 local variable들 등이 가능. 자세한건 뒤에 배운다...만 C++이나 Kotlin을 써봤으면 뭔소린지 이미 알 것이다.

JVM memory structure

  • 사실 C/C++ program load시의 memory 구조랑 매우 유사핟.
  • heap : instance 생성 공간. C/C++ malloc area와 유사
  • call stack : C/C++ stack area와 유사한 역할
  • method area : class 정보 저장. class variable도 여기서 저장된다. C++ static area와 유사.
  • call stack의 작동 원리는 시스템 관련 내용을 이미 알고 있다고 가정하고 생략.

Primitive type and Reference type

  • 변수가 function/method에 parameter로 전달될때 그 변수의 type이 primitive type이면 값 자체가 전달되고, reference type이면 reference가 전달된다.
  • reference가 전달된 경우 그 안의 값을 변동시키면 외부에도 그 영향이 나타난다.
  • C++에서 reference를 전달한 경우, C/C++의 pointer을 전달한 경우가 Java의 reference를 전달한 경우랑 마찬가지라고 보면 된다. 크게 어렵진 않다.
  • primitive type은 String을 제외한 모든 기본 자료형들을 말한다. 나머지는 Reference type에 해당.
  • function/method에서 반환되는 것의 type이 primitive type인 경우 값 자체가, reference type이면 reference가 반환된다. parameter 전달과 마찬가지.
  • 이때 parameter의 할당 방식과 return하는 애들의 할당 방식에 대한 구체적인 원리는 C/C++과 유사하니 생략.

static method vs instance method

  • static method는 class들이 '공유'하는 method라고 생각하면 된다. static variable처럼.
  • instance variable들을 활용하는게 불가능하다. instance가 만들어지지 않아도 (static variable 처럼) class 정보가 들어간 순간, 즉 프로그램이 시작하면 static method 호출이 가능하기 때문에 이를 허용하면 문제가 생기기 때문.
  • 이와 대척되는, instance마다 고유로 가지는 method를 instance method라고 한다.
  • 할당 방식 + 메모리 접근 방식을 고려하면 이론적으로 static method가 더 빠르긴 해서 가능하면 static method를 사용하는게 좋으나, 실제로는 JVM측 최적화가 꽤 쎄서 생각보다 차이가 안 난다. 그래도 static이 손해일 일은 없으니 참고.
  • static method 선언 방식은 다음과 같다.
static void staticMethod() {
	return;
}
  • static method안에 static method 호출은 가능하고, instance method 안에 instance/static method를 호출하는것도 가능하나 static method에서 instance method 호출은 불가능하다. instance variable을 못 쓰는것과 같은 이유.

overloading

  • 같은 method, 다른 꼴.
  • method 이름은 동일한게 여러개가 존재하는게 가능하지만 parameter의 type및 개수까지 완전히 일치하는 형태의 overloading은 안된다. C++과 동일한 규칙.

varargs

  • C++ variadic argument와 유사한 문법이다.
  • type 이름 + ... + 변수 이름 형태로 사용.
public PrintStream printf(String format, Object... args) {...}
  • varargs는 무조건 마지막 parameter로 등장해야 한다. 중간이나 앞에 선언시 뒤의 parameter이 varargs에 속하는지를 모르기 때문.
  • varargs 영역에 아무것도 안 들어가도 되며, array를 사용해도 된다. 이는 semantic 상으로 varargs를 array로 취급하기 때문.
  • 이 때문에 varargs가 들어간 method는 호출할 때마다 array를 생성하는 것으로 성능에 좋지 않은 영향을 줄 수 있으니 유의.
  • 그냥 parameter을 array로 사용하는것보다 좋은 점은 인자가 null인 경우나 인자가 없는 경우의 edge case를 고려할 필요가 없기 때문이다. (varargs에선 이 경우 길이가 0인 array가 들어갔다고 생각하면 된다.)

varargs and overloading

  • varargs를 가지고 overloading을 하는데, overloading 형태 중에 varargs type으로만 이루어진 overloading이 존재시 오류를 일으킬 수 있다. 이는 어디까지가 varargs고 어디부터가 varargs가 아닌 parameter인지 판단이 불가능하기 때문.

constructor

  • 메모리 할당은 new, initialization은 constructor이 담당. C++과 동일.
  • constructor이 하나도 정의된게 없으면 default constructor이 자동으로 생성. C++과 동일.
  • constructor이 하나라도 정의되면 default constructor이 자동으로 생성 안됨. 수동으로 정의는 가능. C++과 동일.
  • constructor overloading 가능. C++과 동일.
  • 단 attribute initialize를 할 때 C++처럼 간략히 생성하는 initialization list 같은건 없고 block 내에서 일일이 다 값을 initialize해야 한다. (사실 이건 상황에 따라 block에서 initialize한거랑 다르지만 여튼) 대충 이런 식으로.
Person(String name) {
	myName = name;
}
  • 생성자 내에 다른 생성자 호출이 가능하나, 이 경우 생성자 이름이 아닌 this를 이름으로 사용해야 한다. 그리고 무조건 첫줄에서 호출해야 한다. 이유는 다른데서도 호출이 가능해지면 그 이전에, 호출을 한 constructor이 한 짓이 무의미할 수 있어서 이를 방지하기 위해 막아놓음.
Person(String name) {
	this();
	myName = name;
}
  • 말나온김에, 이 this() constructor은 그냥 constructor 내에서 constructor 호출 용도로 사용되는 것이며, this라는 reference variable과는 다르다.
  • 그리고 this라는 reference variable은 static method에서 사용하는게 불가능하다. 이유는 static method에서 instance method를 못쓰는...것과 같이 앞에서 얘기했던 내용과 똑같은 이유.
  • C++처럼 Java도 this parameter이 모든 instance method에 숨겨진 parameter로 존재한다.
  • 앞으로 class instance끼리 복사하는 방법을 많이 배울거지만, constructor을 가지고 일단 복사하는 방법은 그냥 constructor이 class type인 reference variable을 parameter로 가지게 하면 된다.

variable initialization

  • C++처럼 instance variable들은 따로 constructor에서 initialize를 안해도default값으로 initialize가 이루어진다.
  • local variable들은 당연히 사용 전에 initialize를 해야 하니 유의.
  • C++처럼 instance variable들이 default 말고 기본적으로 어떻게 initialize할지 explicit하게 나타내는 것도 가능한데, C++이랑 완전 동일하니 넘어가겠다.

initialization block

  • kotlin의 init 없는 init block과 동일하다고 생각하면 된다. 각 생성자별 공통된 초기화를 할 때 사용.
  • class initialization block도 만드는게 가능한데, initialization block 앞에 static을 붙이면 된다. class load되었을 때 딱 한번 발동. class variable들 초기화 용도.

initialization order

  • class variable : class load되었을 때 초기화. default -> explicit -> class initialization block
  • instance variable : instance 생성 되었을 때 초기화. default -> explicit -> instance initialization block -> constructor block
  • 이 점을 유의해서 무의미한 연산이 없도록 애써보자.
profile
안 흔하고 싶은 개발자. 관심 분야 : 임베디드/컴퓨터 시스템 및 아키텍처/웹/AI

0개의 댓글