Java 언어의 장단점
장점
- 운영체제에 독립적이다.
- JVM에서 동작하기 때문에, 특정 운영체제에 종속되지 않는다.
- 객체지향 언어이다.
- 객체지향적으로 프로그래밍 하기 위해 여러 언어적 지원을 하고 있다.(캡슐화, 상속, 추상화, 다형성 등)
- 객체지향 패러다임의 특성상 비교적 이해하고 배우기 쉽다.
- 자동으로 메모리 관리를 해준다.
- JVM에서 Garbage Collector라고 불리는 데몬 스레드에 의해 GC(Garbage Collection)가 일어난다. GC로 인해 별도의 메모리 관리가 필요 없으며 비즈니스 로직에 집중할 수 있다.
- 오픈소스이다.
- 정확히 말하면 OpenJDK가 오픈소스이다.
- 많은 Java 개발자가 존재하고 생태계가 잘 구축되어 있다. 덕분에 오픈소스 라이브러리가 풍부하며 잘 활용한다면 짧은 개발 시간 내에 안정적인 어플리케이션을 쉽게 구현할 수 있다.
- 멀티 스레드를 쉽게 구현할 수 있다.
- Java는 스레드 생성 및 제어와 관련된 라이브러리 API를 제공하고 있기 때문에 실행되는 운영체제에 상관없이 머리 스레드를 쉽게 구현할 수 있다.
- 동적 로딩(Dynamic Loading)을 지원한다.
- 어플리케이션이 실행될 때 모든 객체가 생성되지 않고, 각 객체가 필요한 시점에 클래스를 동적 로딩해서 생성한다. 또한 유지보수 시 해당 클래스만 수정하면 되기 때문에 전체 어플리케이션을 다시 컴파일할 필요가 없다. 따라서 유지보수가 쉽고 빠르다.
단점
- 비교적 속도가 느리다.
- Java는 한번의 컴파일링으로 실행 가능한 기계어가 만들어지지 않고 JVM에 의해 기계어로 번역되고 실행하는 과정을 거치기 때문에 C나 C++의 컴파일 단계에서 만들어지는 완전한 기계어보다는 속도가 느리다. 그러나 하드웨어의 성능 향상과 바이트 코드를 기계어로 변환해주는 JIT 컴파일러 같은 기술 적용으로 JVM의 기능이 향상되어 속도의 격차가 많이 줄어들었다.
- 예외처리가 불편하다.
- 프로그래머 검사가 필요한 예외가 등장한다면 무조건 프로그래머가 선언을 해줘야 한다.
Java의 접근 제어자의 종류와 특징
- public
- 표시: +
- 특징: 어떤 클래스의 객체에서든 접근 가능
- private
- 표시: -
- 특징: 이 클래스에서 생성된 객체들만 접근 가능
- protected
- 표시: #
- 특징: 이 클래스와 동일 패키지에 있거나 상속 관계에 있는 하위 클래스의 객체들만 접근 가능
- package
- 표시: ~
- 특징: 동일 패키지에 있는 클래스의 객체들만 접근 가능
Java의 데이터 타입
기본 데이터 타입(Primitive Data Type)
- 정수형: byte, short, int, long
- 실수형: float, double
- 논리형: boolean(true/false)
- 문자형: char
- 기본 타입의 크기가 작고 고정적이기 때문에 메모리의 Stack 영역에 저장된다.
참조 타입(Reference Data Type)
- 참조 타입의 종류는 class, array, interface, Enumeration이 있다.
- 기본형을 제외하고는 모두 참조형이다.
- new 키워드를 이용하여 객체를 생성하여 데이터가 생성된 주소를 참조하는 타입이다.
- String, StringBuffer, List, 개인이 만든 클래스 등
- String과 배열은 참조 타입과 달리 new 키워드 없이 생성이 가능하지만 기본 타입이 아닌 참조 타입이다.
- 참조 타입의 데이터의 크기가 가변적, 동적이기 때문에 동적으로 관리되는 Heap 영역에 저장된다.
- 더 이상 참조하는 변수가 없을 때 Garbage Collection에 의해 파괴된다.
- 참조 타입은 값이 저장된 곳의 주소를 저장하는 공간으로 객체의 주소를 저장한다.(Call-By-Value)
OOP의 4가지 특징
[OOP 참고]
- 추상화(Abstraction)
- 구체적인 사물들의 공통적인 특징을 파악해서 이를 하나의 개념(집합)으로 다루는 것.
- 캡슐화(Encapsulation)
- 정보 은닉(Information Hiding): 필요가 없는 정보는 외부에서 접근하지 못하도록 제한하는 것.
- 일반화 관계(Inheritance, 상속)
- 여러 개체들이 가진 공통된 특성을 부각시켜 하나의 개념이나 법칙으로 성립시키는 과정.
- 다형성(Polymorphism)
- 서로 다른 클래스의 객체가 같은 메시지를 받았을 때 각자의 방식으로 동작하는 능력.
객체지향과 절차지향 프로그래밍의 차이
절차지향 프로그래밍
- 실행하고자 하는 절차를 정하고, 이 절차대로 프로그래밍하는 방법이다.
- 목적을 달성하기 위한 일의 흐름에 중점을 둔다.
객체지향 프로그래밍
- 실제 세상의 물체를 객체로 표현하고, 이들 사이의 관계, 상호 작용을 프로그램으로 나타낸다.
- 객체를 추출하고 객체들의 관계를 결정하고 이들의 상호작용에 필요한 함수와 변수를 설계 및 구현한다.
- 객체 지향의 핵심은 연관되어 있는 변수와 메소드를 하나의 그룹으로 묶어서 그룹핑하는 것이다.
- 사람의 사고와 가장 비슷하게 프로그래밍을 하기 위해서 생성된 기법
- 하나의 클래스를 바탕으로 서로 다른 상태를 가진 인스턴스를 만들면 서로 다른 행동을 하게 된다. 즉, 하나의 클래스가 여러 개의 인스턴스가 될 수 있다는 점이 객체 지향이 제공하는 가장 기본적인 재활용성이라고 할 수 있다.
Java의 non-static 멤버와 static 멤버의 차이
non-static 멤버
- 공간적 특성: 멤버는 객체마다 별도로 존재한다.
- 시간적 특성: 객체 생성 시에 멤버가 생성된다.
- 객체가 생길 때 멤버도 생성된다.
- 객체 생성 후 멤버 사용이 가능하다.
- 객체가 사라지면 멤버도 사라진다.
- 공유의 특성: 공유되지 않는다.
static 멤버
- 공간적 특성: 멤버는 클래스당 하나가 생성된다.
- 멤버는 객체 내부가 아닌 별도의 공간에 생성된다.
- 클래스 멤버라고 부른다.
- 시간적 특성: 클래스 로딩 시에 멤버가 생성된다.
- 객체가 생기기 전에 이미 생성된다.
- 객체가 생기기 전에도 사용이 가능하다.(즉, 객체를 생성하지 않고도 사용할 수 있다.)
- 객체가 사라져도 멤버는 사라지지 않는다.
- 멤버는 프로그램이 종료될 때 사라진다.
- 공유의 특성: 동일한 클래스의 모든 객체들에 의해 공유된다.
Java의 main 메소드가 static인 이유
static
키워드
static
멤버는 클래스 로딩(프로그램 시작) 시 메모리에 로드되어 인스턴스를 생성하지 않아도 호출이 가능하다.
main 메소드가 static
인 이유
public static void main(String[] args){...}
- 위와 같은 형식은 Java에서의
main()
관례이다. 위와 같은 시그니처를 가진 메소드가 없으면 실행되지 않는다.
- JVM은 인스턴스가 없는 클래스의
main()
을 호출해야하기 때문에 static
이어야 한다.
JVM과 static
- 코드를 실행하면 컴파일러가
.java
코드를 .class
(byte code)로 변환한다.
- 클래스 로더가
.class
파일을 메모리 영역(Runtime Data Area)에 로드한다.
- Runtime Data Area 중 Method Area(=Class Area =Static Area)라고 불리는 영역에 Class Variable이 저장되는데,
static
변수 또한 여기에 포함된다.
- JVM은 Method Area에 로드된
main()
을 실행한다.
Java의 final 키워드
final 키워드
- 개념: 변수나 메소드 또는 클래스가 변경 불가능하도록 만든다.
- 원시(Primitive) 변수에 적용 시
- 참조(Reference) 변수에 적용 시
- 참조 변수가 힙(Heap) 내의 다른 객체를 가리키도록 변경할 수 없다.
- 메소드에 적용 시
- 클래스에 적용 시
- 해당 클래스의 하위 클래스를 정의할 수 없다.
클래스, 객체, 인스턴스의 차이
클래스(Class)
- 객체를 만들어 내기 위한 설계도 혹은 틀
- 연관되어 있는 변수와 메소드의 집합
객체(Object)
- 소프트웨어 세계에 구현할 대상
- 클래스에 선언된 모양 그대로 생성된 실체
- 클래스의 인스턴스라고도 부른다.
- 객체는 모든 인스턴스를 대표하는 포괄적인 의미를 갖는다.
- OOP의 관점에서 클래스의 타입으로 선언되었을 때 객체라고 부른다.
인스턴스(Instance)
- 설계도를 바탕으로 소프트웨어 세계에 구현된 구체적인 실체
- 즉, 객체를 소프트웨어에 실체화 하면 그것을 "인스턴스"라고 부른다.
- 실체화된 인스턴스는 메모리에 할당된다.
- 인스턴스는 객체에 포함된다고 볼 수 있다.
- OOP의 관점에서 객체가 메모리에 할당되어 실제 사용될 때 "인스턴스"라고 부른다.
- 추상적인 개념과 구체적인 객체 사이의 관계에 초점을 맞출 경우에 사용한다.
- "~의 인스턴스" 의 형태로 사용된다.
- 객체는 클래스의 인스턴스이다.
- 즉, 인스턴스라는 용어는 반드시 클래스와 객체 사이의 관계로 한정 지어서 사용할 필요는 없다.
- 인스턴스는 어떤 원본으로부터 "생성된 복제본"을 의미한다.
public class Animal {
...
}
public class Main {
public static void main(String[] args) {
Animal cat, dog;
cat = new Animal();
dog = new Animal();
}
}
오버로딩과 오버라이딩의 차이
오버로딩(Overloading)
- 두 메소드가 같은 이름을 갖고 있으나 인자의 수나 자료형이 다른 경우
오버라이딩(Overriding)
- 상위 클래스의 메소드와 이름과 이름과 용례(signature)가 같은 함수를 하위 클래스에 재정의하는 것
- 상속 관계에 있는 클래스 간에 같은 이름의 메소드를 정의
Call by Value와 Call by Reference의 차이
Call by Value (값에 의한 호출)
- 함수가 호출될 때, 메모리 공간 안에서 함수를 위한 별도의 임시 공간이 생성된다.
- 함수 호출시 인자로 전달되는 변수의 값을 복사하여 함수의 인자로 전달한다.
- 복사된 인자는 함수 안에서 지역적으로 사용되는 local value의 특성을 가진다.
- 따라서 함수 안에서 인자의 값이 변경되어도, 외부의 변수의 값은 변경되지 않는다.
Call by Reference (참조에 의한 호출)
- 함수가 호출될 때, 메모리 공간 안에서 함수를 위한 별도의 임시 공간이 생성된다.
- 함수 호출시 인자로 전달되는 변수의 Reference를 전달한다.(해당 변수를 가리키는 주소값)
- 따라서 함수 안에서 인자의 값이 변경되면, 인자로 전달된 변수의 값도 함께 변경된다.
Java는 항상 Call by Value이다.
- 여기서 value란?
- 기본 자료형의 값 또는 객체에 대한 Reference
- 기본 자료형의 경우 해당하는 변수의 값을 복사해서 전달한다.
- 참조 자료형의 경우 해당하는 변수가 가지는 값이 Reference이므로 인자로 넘길 때 Call by Value에 의해 변수가 가지고 있는 Reference가 복사되어 전달된다.
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "name is " + this.name;
}
}
public class FunctionCallTest {
public static void assignNewPerson(Person p) {
p = new Person("park");
}
public static void changeName(Person p) {
p.setName("park");
}
public static void main(String[] args) {
Person p = new Person("kim");
assignNewPerson(p);
System.out.println(p);
changeName(p);
System.out.println(p);
}
}
public class FunctionCallTest2 {
public static void changeContent(int[] array) {
array[0] = 10;
array[1] = 11;
}
public static void changeRef(int[] array) {
array = new int[2];
array[0] = 20;
array[1] = 21;
}
public static void main(String[] args) {
int[] array = new int[2];
array[0] = 0;
array[1] = 1;
changeContent(array);
for(int item: array) {
System.out.print(item + " ");
}
changeRef(array);
for(int item: array) {
System.out.print(item + " ");
}
}
}
추상 클래스와 인터페이스의 차이
추상 메소드 (Abstract Method)
abstract
키워드와 함께 원형만 선언되고, 코드는 작성되지 않은 메소드
public abstract String getName();
public abstract String fail() { return "Fail"; }
추상 클래스 (Abstract Class)
abstract
키워드로 선언된 클래스
- 추상 메소드를 최소 한개 이상 가지고
abstract
로 선언된 클래스
- 최소 한개의 추상 메소드를 포함하는 경우 반드시 추상 클래스로 선언해야 한다.
- 추상 클래스의 구현
- 서브 클래스에서 슈퍼 클래스의 모든 추상 메소드를 오버라이딩하여 실행가능한 코드로 구현한다.
- 추상 클래스의 목적
- 객체를 생성하기 위함이 아니며, 상속을 위한 부모 클래스로 활용하기 위한 것이다.
- 여러 클래스들의 공통된 부분을 추상화하여 상속받는 클래스에게 구현을 강제화하기 위한 것이다.
- 즉, 추상 클래스의 추상 메소드를 자식 클래스가 구체화하여 그 기능을 확장하는 데 목적이 있다.
abstract class Shape {
Shape() { ... }
void edit() { ... }
abstract public void draw();
}
class Circle extends Shape {
public void draw() { System.out.println("Circle"); }
void show() { System.out.println("Show Circle"); }
}
인터페이스 (Interface)
- 추상 메소드와 상수만을 포함하며,
interface
키워드를 사용하여 선언한다.
- 인터페이스의 구현
- 인터페이스를 상속받고, 추상 메소드를 모두 구현한 클래스를 작성한다.
implements
키워드를 사용하여 구현한다.
- 인터페이스의 목적
- 상속받을 서브 클래스에게 구현할 메소드들의 원형을 모두 알려주어, 클래스가 자신의 목적에 맞게 메소드를 구현하도록 하는 것이다.
- 구현 객체의 같은 동작을 보장하기 위한 목적이 있다.
- 즉, 서로 관련이 없는 클래스에서 공통적으로 사용하는 방식이 필요하지만 기능을 각각 구현할 필요가 있는 경우에 사용한다.
- 인터페이스의 특징
- 인터페이스는 상수 필드와 추상 메소드만으로 구성된다.
- 모든 메소드는 추상 메소드로서,
abstract public
속성이며 생략 가능하다.
- 상수는
public static final
속성이며, 생략하여 선언할 수 있다.
- 인터페이스를 상속받아 새로운 인터페이스를 만들 수 있다.
interface MobilePhone extends Phone { ... }
interface Phone {
int BUTTONS = 20;
void sendCall();
abstract public void receiveCall();
}
class FeaturePhone implements Phone {
public void sendCall() { ... }
public void receiveCall() { ... }
public int clickButton() { ... }
}
추상 클래스와 인터페이스의 공통점
- 객체는 생성할 수 없다.
- 선언만 있고 구현 내용은 없다.
- 서브 클래스가 메소드의 구체적인 동작을 구현하도록 책임을 위임한다.
추상 클래스와 인터페이스의 차이점
- 서로 다른 목적을 가지고 있다.
- 추상 클래스는 추상 메소드를 서브 클래스가 구체화하여 그 기능을 확장하는 데 목적이 있다.(상속을 위한 슈퍼 클래스)
- 인터페이스는 서로 관련이 없는 클래스에서 공통적으로 사용하는 방식이 필요하지만 기능을 각각 구현할 필요가 있는 경우에 사용한다.(구현 객체의 같은 동작을 보장)
- 추상 클래스는 클래스이지만 인터페이스는 클래스가 아니다
- 추상 클래스는 단일 상속만 되지만 인터페이스는 다중 상속이 가능하다.
- 추상 클래스는 "is a kind of", 인터페이스는 "can do this"