Now Loading ...
-
-
자바의 인터페이스
목적
자바의 인터페이스에 대해 학습하세요.
학습할 것
인터페이스 정의하는 방법
인터페이스 구현하는 방법
인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
인터페이스 상속
인터페이스의 기본 메소드 (Default Method), 자바 8
인터페이스의 static 메소드, 자바 8
인터페이스의 private 메소드, 자바 9
인터페이스란
인터페이스는 일종의 추상 클래스로 추상클래스보다 추상화 정도가 높아 일반 메서드 또는 멤버변수 (몸통)을 가질 수 없다 오직 추상메서드와 상수만 멤버로 가질 수 있다. 비유하자면 밑그림만 그려져있는 기본 설계도 라 할수있다.
1. 인터페이스 정의하는 방법
interface 인터페이스 이름{
public static final 타입상수이름 = 값;
public abstract 메서드이름(매개변수 목록);
}
인터페이스는 클래스랑 달리 제약사항이 있다.
모든 멤버변수는 public static final 이어야 하며, 이를 생략할 수 있다.
모든 메서드는 public abstract 이어야 하며 생략할 수 있다. (static 메서드와 default 메서드 예외)
위의 static 메서드와 default 메서드는 JDK 1.8에서 지원한다.
2. 인터페이스 구현하는 방법
인터페이스는 그 자체로 생성할 수 없고, 자신의 몸통을 만들어줘야 한다.
public interface Player{
public void move(int x, int y);
public void shoot(int x, int y);
}
class NBAPlayer implements Player{
public void move(int x, int y){
System.out.println("x, y 좌표로 이동");
}
public void shoot(int x, int y){
System.out.println("x, y 방향으로 슛!");
}
}
인터페이스의 메서드 중 일부만 구현하고 싶다면 abstract 붙여서 추상클래스로 선언해야 한다.
abstract class RunningPlayer implements Player{
public void move(int x, int y);
}
3. 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
문제의 뜻을 잘 이해하지 못했는데 일단 내가 해석한 것은 main에서 인터페이스 같은경우 어떻게 선언하는 것인지 같아 적어본다.
public static void main(String[] args){
Player Lebron = new NBAPlayer();
lebron.move();
lebron.shoot();
}
x, y 좌표로 이동
x, y 방향으로 슛!
NBAPlayer()라는 클래스는 Player라는 인터페이스를 참조하고 있으므로 인터페이스 변수 선언에 참조된 클래스를 생성하여 사용할 수 있다.(?)
4. 인터페이스 상속
인터페이스는 인터페이스로부터만 상속받을 수 있으며 클래스와는 달리 다중상속, 여러개의 인터페이스로부터 상속받는 것은 불가능하다.
interface Moving{
void move(int x, int y);
}
interface Shooting{
void shoot(int x, int y);
}
interface Player extends Moving, Shooting{}
클래스의 상속과 마찬가지로 자손 인터페이스는 조상인터페이스에 정의된 멤버를 모두 상속받아 Player 인터페이스는move와 shoot을 다 가진 인터페이스가 된다.
5. 인터페이스의 기본 메소드(Default Method) 자바 8
조상클래스에 메서드 추가는 쉽지만 인터페이스는 어렵다. 인터페이스에 메서드 추가는 그 인터페이스를 참조하는 모든 클래스들이 새로 추가된 메서드를 구현해야 하기 때문이다. 그래서 디폴트 메서드가 나왔으며 이는 추상 메서드의 기본적 구현을 제공하는 메서드로 참조중인 클래스를 변경하지 않아도 된다.
interface MyInterface{
void method();
default void newMethod();
}
대신 이때 기존 메서드와 디폴트 메서드가 이름이 중복되어 충돌할 수도 있다.
여러 인터페이스의 디폴트 메서드 간의 충돌
인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.
디폴트 메서드와 조상 클래스의 메서드 간의 충돌
조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.
라는 규칙이 있는데 간단히 필요한 쪽의 메서드와 같은 내용으로 오버라이딩 해버리면 된다.
6. 인터페이스의 static 메소드, 자바8
static 메소드 같은 경우는 인스턴스와 관계가 없는 독립적 메서드로 인터페이스에 추가하면 된다.
그리고 인터페이스의 static메서드 역시 접근 제어자가 항상 public이며 생략할 수 있다.
7. 인터페이스의 private 메소드, 자바 9
java 8에서는 default, static method는 기본으로 public 만 가능했고 java 9 버전부턴 private 메서드를 지원한다.
이는 인터페이스가 내부적으로 처리하는 문제를 외부에서 사용하지 못하게 만들어준다.
결과적으로 인터페이스에 캡슐화시켜준다 할 수 있다.
Reference
남궁성. Java의 정석
-
자바의 패키지
목적
자바의 패키지에 대해 학습하세요.
학습할 것
package 키워드
import 키워드
클래스패스
CLASSPATH 환경변수
-classpath 옵션
접근지시자
1. package 키워드
패키지
패키지는 클래스랑 인터페이스의 모음이며 관련된 클래스끼리 그룹단위로 모아 효율적인 관리를 할 수 있다.
패키지가 다르면 클래스명이 같아도 구분할 수 있다.
클래스가 물리적으로 하나의 클래스파일(.class).인 것과 같이 패키지는 물리적으로 하나의 디렉토리이다.
하나의 소스파일에 첫 번째 문장으로 단 한 번의 패키지 선언만을 허용한다.
모든 클래스는 반드시 하나의 패키지에 속해야 한다.
패키지는 점(.)을 구분자로 하여 계층구조를 구성할 수 있다.
패키지는 물리적으로 클래스 파일(.class)을 포함하는 하나의 디렉토리이다.
패키지 선언
패키지 선언은 아래 한 줄을 맨 첫번째 줄에 적어주면 된다.
package 패키지명;
2. import키워드
import문
다른 패키지의 클래스를 사용하려 한다면 패키지명이 포함된 클래스 이름을 사용해야 한다. import의 역할은 컴파일러에게 소스파일에 사용된 클래스의 패키지에 대한 정보를 제공하는 것이다. 이클립스에서 Ctrl + Shift + o 누르면 자동으로 import 해준다.(근데 자동완성에 익숙해져서 잘 안쓸거 같다.)
import문 선언
import 패키지명.클래스명; //한 클래스만 사용할 때
import 패키지명.*; // 패키지 안에 여러클래스를 사용할 때
패키지명.*; 을 사용한다 하면 그안의 모든 클래스들을 로드해 필요없는 클래스도 import 할거라 생각하지만, 실행시 성능에 이상이 없다.
static import문
static import는 static 멤버를 호출할 때 클래스 이름을 생략하게 해준다. 예로
import static java.lang.Math.random;
선언 시,
Math.random(); -> random();
처럼 바꿔준다.
3. 클래스패스
간단히 말해서 클래스를 찾기 위한 경로이다.
우리는 프로그램을 실행하면 메모리를 할당받고 JVM을 동작시킨다.
컴파일러를 실행하게 되면 JVM이 동작하게 된다. JVM은 .java 파일들을 클래스 파일들을 찾는데 그때의 파일 경로의 기준이 된다. 그리고 이를 지정해주는 방법은 classpath 환경변수, -classpath 옵션 두가지가 있다.
4. CLASSPATH 환경변수
JVM 클래스 로더는 classpath 경로를 찾아가 그 안에 정의된 class들을 가져온다.
이 것을 지정해주는 법은 os의 시스템 변수 부분 Path의 값에 %JAVA_HOME%/bin 이라는 값을 추가해주면 등록된다.
5. -classpath 옵션
자바에서 컴파일 할 때 classpath를 정해서 갈 수 있다.
java c -classpath '경로' java파일명
이라는 명령어를 통해서 classpath의 옵션을 지정한다.즉, 다른 클래스에 의존하는 클래스 파일을 컴파일 하기 위해 그 클래스의 경로를 직접 매핑해준다.
6. 접근지시자 (접근제어자)
멤버 또는 클래스에 사용되며, 해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.
접근제어자가 사용될 수 있는 곳 - 클래스, 멤버변수, 메서드 생성자
제어자
같은 클래스
같은 패키지
자손클래스
전 체
public
O
O
O
O
protected
O
O
O
(default)
O
O
private
O
public : 접근제한이 전혀 없다.
private : 같은 클래스 내에서만 사용하도록 제한
default : 같은 패키지 내의 클래스에서만 접근 가능
protected : 패키지에 관계없이 상속관계에 있는 자손클래스에서 접근할 수 있도록 하는 것이 제한목적이지만, 같은 패키지내에서도 접근이 가능하다. 결과적으로 protected가 default보다 접근범위가 더 넓다.
접근 제어자를 이용한 캡슐화
접근제어자를 왜 사용하냐 : 클래스 내부에 선언된 데이터를 보호하기 위해서이다. 데이터가 유효한 값을 유지하도록, 비밀번호와 같은 데이터를 외부에서 함부로 변경하지 못하도록 하기 위해서이며 이것을 데이터 감추기라 부르기도 한다.
외부에는 불필요한, 내부적으로만 사용되는 부분을 감추기 위해서도 사용된다.
예를들어
public class Time{
public int hour;
public int minute;
public int second;
}
클래스가 있고 인스턴스 생성 후 멤버변수에 직접 접근하면 값을 변경할 수 있다.
Time t = new Time();
t.hour = 25;
위 코드처럼 hour에 25라는 잘못된 값을 지정한다 해도 막을 방법이 없다.
이럴 때는 private나 protected로 제한하고 값을 읽고 변경할 수 있는 public 메서드를 제공함으로써 간접적으로 멤버변수의 값을 다룰 수 있도록 한다.
public void set Hour(int hour){
if (hour < 0 || hour > 23){
return ;
}
this.hour = hour;
}
만일 상속을 통해 확장될 것이 예상되는 클래스라면, 멤버에 접근 제한을 주되 자손 클래스에서 접근하는 것이 가능하도록 하기 위해 private 대신 protected를 사용한다.
생성자의 접근 제어자
생성자에 접근 제어자를 사용함으로 인스턴스 생성을 제한할 수도 있다.
생성자의 접근 제어자를 private 로 지정하면 외부에서 인스턴스를 생성할 수 없게 된다.
class SingleTon{
private SingleTon() {
}
}
대신 인스턴스를 생성해서 반환해주는 public 메서드를 제공해 외부에서 이 클래스의 인스턴스를 사용할 수 있도록 할 수 있다. 이 메서드는 public 인 동시에 static 이어야 한다.
class Singleton(){
private static Singleton s = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return s;
}
}
또 생성자가 private인 클래스는 다른 클래스의 조상이 될 수 없다. 자손클래스가 인스턴스를 생성할 때 조상클래스의 생성자를 호출해야 하는데 private는 같은 클래스 내에서만 가능하기 때문이다. 따라서 클래스 앞에 final을 더 추가해 상속할 수 없는 클래스인 것을 알려주는 것이 좋다.
제어자의 조합
대 상
사용 가능한 제어자
클래스
public, (default), final, abstract
메서드
모든 접근 제어자, final, abstract, static
멤버변수
모든 접근 제어자, final, static
지역변수
final
메서드에 static과 abstract를 함께 사용할 수 없다.
static 메서드는 구현된 메서드에서만 사용할 수 있기 때문에
클래스에 abstract와 final을 동시에 사용할 수 없다.
클래스에서 사용되는 final은 확장을 없애는 의미이고 abstract는 상속을 통해서 완성되기에 모순된다.
abstract메서드의 접근 제어자가 private일 수 없다.
abstract 메서드는 자손 클래스를 구현해주어야 하는데 접근 제어자가 private 이면 자손에 접근할 수가 없다.
메서드에 private가 final을 같이 사용할 수 없다.
접근 제어자가 private인 메서드는 오버라이딩 될 수 없다.
Reference
남궁성. Java의 정석
-
자바의 상속
목적
자바의 상속에 대해 학습하세요.
학습할 것
자바 상속의 특징
super 키워드
메소드 오버라이딩
다이나믹 메소드 디스패치 (Dynamic Method Dispatch)
추상 클래스
final 키워드
Object 클래스
1. 자바 상속의 특징
자바의 상속 전, 상속이란, 기존 클래스를 재사용하여 새로운 클래스를 작성하는 것이다. 이는 코드의 재사용성을 높이고 중복을 제거하여 생산성과 유지성에 크게 기여한다.
단일 상속
다른 객체지향 언어인 C++ 에서는 여러 조상 클래스로부터 상속받는 것이 가능한 ‘다중상속’을 허용하지만, 자바는 오직 단일 상속만 허용한다. 만약 다중 상속을 허용하게 된다면 클래스 내 인스턴스 메서드를 구별할 방법이 없다. 이처럼 명확하고 신뢰성 있는 코드를 위해 다중 상속의 장점을 포기하며 단일 상속을 지원한다.
상속 횟수 제한 X
자바에서는 상속에 제한을 두지 않는다.
최상의 클래스
자바에서는 모든 상속계층도의 최상위에 Object 클래스가 위치한다. 따라서 Object 클래스에 정의된 멤버들을 사용할 수 있다.
2. super 키워드
super란 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수이다.
멤버변수와 지역변수의 이름이 같을 때 this를 붙여서 구별했듯이, 상속받은 멤버와 자신의 멤버가 같을 떈 super를 붙여서 구별한다.
조상 클래스 멤버와 자손 클래스의 멤버가 중복 정의되어 서로 구별해야 하는 경우에만 super를 사용하는 것이 좋다.
super는 static 메서드에선 사용할 수 없다.
조상 클래스에서 선언된 멤버변수와 같은 이름의 멤버변수를 가진 자손 클래스엔 중복되게 정의가 가능하며 super를 사용해 구별해준다.
메서드 역시 super를 사용하여 호출할 수 도있다.
ex) super.getName();
생성자에서는 super()는 생성자이고 조상 클래스의 생성자를 호출하는데 사용된다. 그리고 자손 클래스의 멤버가 조상 클래스의 멤버를 사용할 수 있으므로 조상의 멤버가 먼저 초기화 되어야 한다. (super() 가 가장 먼저 선언되어야 하는 이유) 혹시나 적어놓지 않았으면 컴파일러가 자동으로 추가해준다.
만약 조상 클래스의 값들을 가지고 생성자를 호출하고 싶다면 super(변수, 변수 …) 이런 식으로 호출하면 된다.
3. 메소드 오버라이딩
오버라이딩이란 상속받은 메서드의 내용을 변경하여 사용하는 것이다. 자손 클래스에 맞게 변경해야 하는 경우가 많고 이럴 때 오버라이딩을 사용한다.
오버라이딩의 조건을 성립시키기 위해선 3가지 조건이 맞아야 한다.
이름이 같아야 한다.
매개변수가 같아야 한다.
반환타입이 같아야 한다.
요약하면 선언부가 일치해야 한다고 말할 수 있고 접근 제어자와 예외같은 경우는 제한된 조건이 있다.
접근 제어자는 조상 클래스 메서드보다 좁은 범위로 변경할 수 없다.
예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
인스턴스메서드와 static 메서드를 서로 변경해서 사용할 수 없다.
(static 같은 경우는 오버라이딩이 아니라 그냥 static 메서드를 정의 한 것이다. )
4. 다이나믹 메소드 디스패치
다이나믹 메소드 디스패치에 대한 정보가 안나와서 나름 다른 분들의 글과 인터넷 검색을 통해서 찾아 보았고 정확한 정보를 알 순 없었다.
허나 일단 글대로 적자면,
다이나믹 메소드 디스패치는 오버라이딩 되어있는 메소드를 실행할 때 런타임 시점에서 어떤 메소드를 실행할 지 결정하려는 것이다.
인터페이스를 참조한 2개의 자식 클래스가 있고, 이에 인터페이스를 생성하여 그 안의 함수를 실행시켰을 때, 과연 2개의 자식 클래스 중 누가 호출되는 것인 지를 컴파일러가 알 수 없는 것이다.
5. 추상 클래스
추상 클래스는 클래스에 정의할 내용을 추상적으로 적어놓은, 즉 설계도의 틀 이라고 생각하면 좋다. 추상클래스는 상속을 통해서 자손 클래스에 의해서만 완성될 수 있다. 추상 클래스는 클래스 앞에 abstract를 붙이면 된다. 긜고 상속을 통해 구현해주면 완성된다. 또한 추상클래스에서도 생성자가 있으며, 멤버변수와 메서드도 가질 수 있다.
abstract class 클래스이름 {
}
스포츠를 예시로 들자면 축구 농구 배구 등이 있고 축구 선수 배구 선수 농구 선수가 있는데 이 3명의 선수는 스포츠 선수라는 타이틀을 가지고 있고 추상화를 통해 스포츠 선수를 정의할 수 있다.
abstract class Player{
boolean pause;
int currentPos;
Player(){
pause = false;
currentPos = 0;
}
abstract void play();
abstract void stop();
}
6. final 키워드
변경될 수 없는 의미를 가지고 있는 의미이며 선언시 변경할 수 없는 상수가 된다.
메서드에 사용 시엔 오버라이딩을 할 수 없고 클래스에 사용하면 자손 클래스를 정의하지 못하게 된다.
final 사용 구간은 클래스, 메서드, 멤버변수, 지역변수 이다.
final이 붙은 변수는 상수이므로 선언과 초기화를 동시에 하지만, 인스턴스 변수의 경우 생성자에서 초기화 되도록 할 수 있다. 클래스 내에 매개변수를 갖는 생성자를 선언하여, 인스턴스를 생성할 때 final이 붙은 멤버변수를 초기화하는데 필요한 값을 생성자의 매개변수로부터 제공받는 것이다. 이를 통해 각 인스턴스마다 final이 붙은 멤버변수가 다른 값을 갖도록 하는 것이 가능하다. 이것이 불가능 하다면 final이 붙은 인스턴스 변수는 모든 인스턴스에서 같은 값이 되어야만 한다.
7. Object 클래스
Obejct 클래스는 모든 클래스의 최상위 위치에 있는 조상 클래스이다.
class Study extends Object{
}
모든 클래스들은 Object 클래스를 상속받고 있다. 이를 통해 모든 클래스는 Object 클래스에 정의된 멤버, 함수들을 사용할 수 있다.
Object 클래스의 메서드
설 명
protected Object clone()
객체 자신의 복사본을 반환한다.
public boolean equals(Object obj)
객체 자신과 객체 obj가 같은 객체인지 알려준다.(같으면 true)
protected void finalize()
객체가 소멸될 때 가비지 컬렉터에 의해 자동적으로 호출된다. 이 때 수행되어야하는 코드가 있을 때 오버라이딩 한다.(거의 사용 안함)
public Class getClass()
객체 자신의 클래스 정보를 담고 있는 Class인스턴스를 반환한다.
public int hashCode()
객체 자신의 해시코드를 반환
public String toString()
객체 자신의 정보를 문자열로 반환
public void notify()
객체 자신을 사용하려고 기다리는 쓰레드를 하나만 깨운다.
public void notifyAll()
객체 자신을 사용하려고 기다리는 모든 쓰레드를 깨운다.
public void wait() public void wait(long timeout) public void wait(long time, int nanos)
다른 쓰레드가 notify()나 notifyAll()을 호출할 떄까지 현재 쓰레드를 무한히 또는 지정된 시간(timeout, nanos)동안 기다리게 한다.
-
자바의 Class
목적
자바의 Class에 대해 학습하세요.
학습할 것
클래스 정의하는 방법
객체 만드는 방법 (new 키워드 이해하기)
메소드 정의하는 방법
생성자 정의하는 방법
this 키워드 이해하기
1. 클래스 정의하는 방법
클래스란, 객체를 정의해놓은 것, 또는 객체의 설계도 라고 정의할 수 있다. 그리고 클래스는 객체를 생성하는데 사용된다.
클래스를 구성하는 요소들은 필드들과 메소드, 생성자로 되어있다.
public class Account{
private Long id;
private String name;
private String email;
private String password;
/* 생성자는 default 하게 만들 수 있지만 생성자에서 파라미터로 값을 받아서 작성 시, 반드 시 작성해주어야 한다.
*/
public Account(String email, String password){
this.email = email;
this.password = password;
}
public String getEmail(){
return Email;
}
public void changePassword(String password){
this.password = password;
}
}
2. 객체 만드는 방법(new 키워드 이해하기)
클래스로부터 객체를 만드는 과정을 인스턴스화 라고 하며 만들어진 객체를 그 클래스의 인스턴스라고 한다. 그리고 객체는 속성과 기능 두 종류의 구성요소로 이루어져 있으며 이들은 그 객체의 멤버라고 한다. 속성과 기능 같은 경우, 속성은 멤버변수, 기능은 메소드 라고 말한다.
클래스명 변수명; // 선언
변수명 = new 클래스명(); // 생성
기본적으로 인스턴스 생성( 객체 만들기 )는 위 코드처럼 정의하며 위 클래스를 예시로 들었을 땐,
Account account;
account = new Account(); // 기본 생성자
account = new Account("dmstjd1024@naver.com", "password") // 파라미터 있는 생성자
이런 식으로 구성된다.
3. 메소드 정의하는 법
반환타입 메서드이름 (타입 변수명, 타입변수명, ... )
{
//메서드 호출 시 수행될 코드
}
ex)
int add (int a, int b)
{
int result = a + b;
return result;
}
4. 생성자 정의하는 방법
컴파일 시 소스파일에 생성자가 하나도 정의되지 않은 경우, 컴파일러는 자동적으로 아래와 같은 내용의 기본 생성자를 추가하여 컴파일 한다.
클래스이름() {}
조심해야 할 점은 클래스 내에 생성자가 하나도 없을 때 이므로 혹시나 뜬금없이 파라미터를 가진 생성자만 적어놓으면 에러가 난다.
클래스 클래스명{
변수
변수
생성자(파라미터 파라미터명){
// 에러 발생
}
}
5. this 키워드 이해하기
생성자 간에도 서로 호출이 가능한다. 허나 2가지 조건이 필요한다.
생성자의 이름으로 클래스이름 대신 this를 사용
한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서만 호출이 가능
ex)
Car (String color){
door = 5;
Car(color, "auto", 4); // X 생성자에서 다른 생성자를 호출 => this(color ....) 생성 O
}
첫줄에서만 호출 가능한 이유는 생성자 내에서 ㅗ기화 작업 도중, 다른 생성자를 호출하게 되면, 호출된 다른 생성자 내에서도 멤버변수들의 값을 초기화를 할 것이므로 다른 생성자를 호출하기 이전의 초기화 작업이 무의미해질수 있기 떄문이다.
그리고 this같은 경우는
Car(){
this("white", "auto", 4); // 처럼 깔끔하게 적는 것이 보기 더 좋다.
}
또한 this를 이용해서 인스턴스변수에 접근할 수 있다. 허나 this는 인스턴스 변수에만 접근할 수 있다. static 메서드에서는 인스턴스를 사용할 수 없는 것처럼, this 역시 사용할 수 없다. static 메서드는 인스턴스를 생성하지 않고도 호출될 수 있기 때문이다.
정리하자면
this 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있따. 모든 인스턴스메서드에 지역변수로 숨겨진 채로 존재한다.
this(), this(매개변수) 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.
Reference
남궁성. Java의 정석
-
제어문
목적
자바가 제공하는 제어문을 학습하세요
학습할 것
선택문
반복문
1. 선택문
Switch
if 같은 조건문은 참, 거짓밖에 없기 때문에 경우가 많아질 수록 else if를 계속 추가해야하며 else if 에 있는 조건식들을 일일히 다 계산하며 내려가야 하므로 처리 시간이 늘어난다. 이를 해결하기 위해 switch(선택)문이 있고 하나의 조건식으로 많은 수를 처리할 수 있으며 표현도 간결해 가독성이 높다.
switch문은 조건식을 먼저 계산한 다음, 결과랑 일치하는 case 문으로 이동한다. 그리고 case 문의 내용을 수행하며 break를 만났을 때 switch문을 빠져나오게 된다.
또한 조건식의 결과와 일치하는 case 문이 없는 경우, default 로 지정한 문을 찾아가 내용을 수행한다. 그렇기 때문에 default를 기마지막에 놓는다. (이렇게 하면 break문이 필요 없음)
책에서는 break문을 사용해 권한 주는 코드로도 활용할 수 있다 한다. (ex )
swich (level){
case 3 :
grantDelete();
case 2 :
grantWrite();
case 1 :
grantRead();
break;
}
간단히 말해서 case에 break를 주지 않음으로 아래 권한 부여 함수들을 다 실행시킬 수 있다는 것이다.
switch 제약조건
조건식의 결과값은 반드시 정수 또는 문자열여야 한다.
중복되지 않아야 한다.
case문의 값은 반드시 상수이어야 한다.
※ tip switch 안에 switch로 중첩이 가능한다.-> break문 으로 탈출 조심!
2. 반복문
반복문은 반복적으로 수행될 때 사용되며, for, while, do - while이 있다.
1. for
for문은 반복 횟수를 알고 있을 때 정확한다. 구조가 복잡하지만, 직관적이라 오히려 이해하기 쉽다.
for문의 구조와 수행순서
for(초기화; 조건식; 증감식){
수행문장
}
① 초기화 -> ② 조건식 -> ③ 증감식 -> ④ 수행될 문장 순서대로 진행한다.
초기화
변수 초기화 하는 부분이며 처음 한번만 수행한다. ‘,’ 를 통해서 두 개 이상의 변수를 초기화 가능하다.(단 변수 타입은 같아야 한다.)
조건식
참이면 반복하고 거짓이면 반복 멈춘다. (무한루프에 빠지지않게 조건식을 잘 세워야 한다.)
증감식
반복문 제어 변수를 증감시키는 식이다. ex) i++, i==, i+=2, i* = 3
쉼표를 이용해서 두 문장 이상을 하나로 연결해 쓸 수 있다. ex) for( ~~; ~~; i++, j– )
for문에서는 for(;;){} 을 사용하면 계속 참으로 간주되어 무한 루프로 돌릴 수 있다. (break로 탈출)
항상된 for문
JDK 1.5부터 배열과 컬렉션에 저장된 요소에 접근할 때 편리한 방법의 문법이 추가되었다.
for( 타입 변수명, 배열 또는 컬렉션) {
수행문장
}
위 for문을 사용할 때는 배열, 컬렉션 만 가능하고 안에 저장된 값들을 하나씩 읽어와 변수에 저장해 반복문이 돌아간다.
예시
for (int i=0; i < arr.length; i++) -> for(int tmp : arr)
2. while
while은 for문과 다르게 구조가 간단하며 참인동안 반복될 문장들을 적어놓는다.
while(조건식){
반복될 문장
}
for문과 while문 비교
for문은 초기화, 조건식, 증감식을 한 곳에 모아놓은 것일 뿐 while문과 다르지 않아 항상 서로 형변환이 가능하다. 초기화나 증감식이 필요하지 않는 경우면 while문이 더 적합하다.
while문의 조건식은 생략 불가
때문에 while문의 조건식이 항상 참이 되도록 하려면 안에 true를 넣어주면 된다.
3. do - while
while문의 변형으로 조건식과 불럭의 순서를 바꿔놓은 것이다. 따라서 블럭이 먼저 수행한 후에 조건식을 평가한다.
do {
수행될 문장
}while(조건식);
따라서 최소한 한번은 수행될 것을 보장한다.
4. 부가적
1.break 문
break문은 switch에서 설명 했는데 일단은 실질적인 의미로 break문은 자신이 포함된 가장 가까운 반복문을 벗어나는 문이다. 주로 if문과 함께 사용되어 특정 조건을 만족하면 반복문을 벗어나도록 한다.
2.continue 문
반복문 내에서만 사용될 수 있으며, 반복 중 continue를 만나게 되면 가장 가까운 반복문의 끝으로 이동하여 다음 반복문으로 넘어간다.
3.이름 붙은 반복문
break와 continue 같이 가장 가까운 반복문 외에 중첩되어 있는 반복문들 중에서 지정된 위치로 탈출하고 싶다 하면 break, continue문에 이름을 지정해 반복을 옮겨다닐 수 있다.
ex)
outer :
while (true) {
...
for(;;) {
...
if(num == 0)
break;
if(num == 99)
break outer;
...
} // for(;;)
} // while(true)
num에 0을 입력하면 break;가 실행되면서 다시 for문 안의 문장들을 실행할 수 있고, num에 99를 입력했을 때는 for문에서 break outer;를 통해 for문과 while문 모두를 벗어날 수 있게 된다.
Reference
남궁성. Java의 정석
-
연산자
목적
자바가 제공하는 다양한 연산자를 학습하세요.
학습할 것
산술 연산자
비트 연산자
관계 연산자
논리 연산자
instanceof
assignment(=) operator
화살표(->) 연산자
3항 연산자
연산자 우선 순위
(optional) Java 13. switch 연산자
산술 연산자
산술 연산자는 사칙연산을 다루는 기본적이면서도 가장 많이 사용되는 연산자 이다.
산술 연산자는 [ +, -, *, /, % ] 5가지가 있고 연산 순서는 { *, /, % } -> { +, - } 이다.
사칙연산자
사친 연산자 같은 경우는 산술 연산자 중 { +, -, *, / } 로 나타낼 수 있다.
그리고 사칙 연산자에선 예시로 int 형의 연산 중 10 / 4 같은경우 우리는 2.5라 생각하지만 2라고 나온다. int타입은 소수점을 정희하지 못하으몰 정수만 남고 소수점 이하는 버려진다. 그래서 올바른 연산을 위해선 한 쪽을 실수형의 값으로 바꿔 결과를 가져야 한다.
피 연산자가 정수형인 경우, 나누는 수를 0으로 사용할 수 없다. -> 컴파일 시엔 정상적이지만 실행 시 오류가 발생
이때 0을 실수형 0 인 0.0으로 나누는 것은 가능하지만 실행 시(ArthmeticException) 오류가 난다.
또 byte형 같은 경우는 연산을 시행하면 int형보다 작기 때문에 byte를 int형으로 바꿔서 연산을 수행해야 한다.
byte a = 10;
byte b = 20;
byte c = a + b;
때문에 byte c 같은 경우 int형으로 바뀐 값을 넣으려 하니 에러가 발생한다.
나머지 연산자
왼쪽 피연산자를 오른쪽 피연산자로 나누고 난 나머지 값을 결과로 반환하는 연산자로 오른쪽 피연산자를 0으로 사용할 수 없다. 주로 짝, 홀, 배수 검사등에 사용한다.
비트 연산자
비트 연산자는 피연산자를 비트단위로 논리 연산한다. 피 연산자를 이진수로 표현했을 때 각 자리를 규칙에 따라 연산을 수행하며 피 연산자로 실수는 허용하지 않는다. 정수만 허용된다.
x
y
x | y
x & y
x ^ y
1
1
1
1
0
1
0
1
0
1
0
1
1
0
1
0
0
0
0
0
(OR 연산자) : 피연산자 중 한쪽 값이 1이면, 1의 결과를 얻는다.
& (AND 연산자) : 양쪽이 1이여야 1을 결과로 얻는다.
^ (XOR 연산자) : 피연산자의 값이 서로 다를 때만 1을 결과로 얻는다.
~(전환 연산자) : 피연산자를 2진수로 표현했을 때, 0은 1로 1은 0으로 바꾼다. (보수를 얻을 때 사용)
«, » (쉬프트 연산자) : 피연산자의 각 자리(2진수를 표현했을 때)
관계 연산자
관계 연산자는 비교 연산자라 부를 수 있으며 주로 조거눔ㄴ과 반복문 조건식에 사용되며 결과는 true 아니면 false 뿐이다.
대소비교 연산자
[ <, >, <=, >= ] 두 피연산자의 값의 크기를 비교하는 연산자이다. boolean을 제외한 자료형에 다 사용할 수 있지만, 참조형에는 사용할 수 없다.
등가비교 연산자
[ ==, != ] 두 피연산자의 값이 같은지 또는 다른지 비교하는 연산자이다. 모든 자료형에 사용할 수 있고 참조형의 경우엔 객체의 주소값을 저장하기 때문에 두 개의 피연산자가 같은 객체를 가리키고 있는 지 알 수 있다.
기본형과 참조형은 서로 형변환이 가능하지 않기 때문에 등가비교 연산자(==, !=) 로 기본형과 참조형을 비교할 수 없다.
그리고 두 문자열을 비교할 땐 비교 연산자 대신 equals() 라는 메서드를 사용해야 한다. 문자열의 내용이 같은 지 비교하기 위해서이다.
논리연산자
논리 연산자는 두개의 조건이 결합된 경우는 [ &&,
] 을 사용하여 나타낸다.
x
y
x || y
x && y
true
true
true
true
true
false
true
false
false
true
true
false
false
false
false
false
논리연산자의 장점은 효율적인 연산을 한다는 것이다.OR 연산자를 예로 들면 두 피연산자 중 한쪽만 참이면 참이 되기 때문에 다른 쪽은 평가하지 않는다.
논리부정연산자
[ ! ] 이 연산자는 반대로 결과를 반환한다. 따라서 전원버튼이나 토글 버튼을 논리적으로 구현할 수 있다.
instance of
참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof 연산자를 사용한다. 주로 조건문에 사용되며 식은 ( 참조변수 instanceof 클래스명) 이 피연산자로 위치한다. 어떤 타입에 대한 instanceof연산의 결과가 true라는 것은 검사한 타입으로 형변환이 가능하다는 것을 뜻한다.
그리고 자신의 조상 타입의 경우에도 true라는 결과를 얻는다.
Assignment(=) operator (할당 연산자)
할당 연산자는 대입 연산자랑 같은 말이며 변수와 같은 저장공간에 값 또는 수식의 연산결과를 저장하는데 사용된다.
할당 연산자는 연산자들 중에서 가장 낮은 우선순위를 가지고 있기 때문에 식에서 제일 나중에 수행된다. 그리고 연산 진행방향이 오른쪽에서 왼쪽이다.
그리고 연산자는 단순할당 연산자랑 복합 할당 연산자로 나뉘어져 있는데 단순 할당 연산자는 우리가 아는 = 이것이고 복합 대입 연산자는 나머지를 의미한다.
할당 연산자의 종류
= : 오른쪽 피연산자의 값을 왼쪽 피연산자에 저장합니다.
+= : 오른쪽 피연산자의 값을 왼쪽 피연산자와 더해서 왼쪽 피연산자에 저장합니다.
-= : 오른쪽 피연산자의 값을 왼쪽 피연산자에서 빼서 왼쪽 피연산자에 저장합니다.
*= : 오른쪽 피연산자의 값을 왼쪽 피연산자와 곱해서 왼쪽 피연산자에 저장합니다.
/= : 왼쪽 피연산자를 오른쪽 피연산자로 나눠서 왼쪽 피연산자에 저장합니다.
%= : 왼쪽 피연산자에서 오른쪽 피연산자로 나눈 나머지(모듈러스)를 왼쪽 피연산자에 저장합니다.
«= : 오른쪽 피연산자 값의 비트수만큼 왼쪽 피연산자를 왼쪽으로 이동해서 왼쪽 피연산자에 저장합니다.
»= : 오른쪽 피연산자 값의 비트수만큼 왼쪽 피연산자를 오른쪽으로 이동해서 왼쪽 피연산자에 저장합니다.
&= : 왼쪽, 오른쪽 피연산자의 비트 AND를 구해서 왼쪽 피연산자에 저장합니다.
**
=** : 왼쪽, 오른쪽 피연산자의 비트 OR를 구해서 왼쪽 피연산자에 저장합니다.
^= : 왼쪽, 오른쪽 피연산자의 비트 XOR를 구해서 왼쪽 피연산자에 저장합니다.
대입 연산자에 대한 정리 글
화살표 연산자
화살표 연산자 같은 경우는 람다에서 주로 사용되며 식별자 없이 실행가능한 함수를 가리킬 때? 매개변수들이 무엇인지 가리켜? 주려고 사용한다.
Print print = new Print(i){
System.out.println(i);
};
//윗 부분을 아래처럼 나타낼 수 있다.
Print print = (i) -> System.out.println(i);
이렇게 쓰면 장점이 가독성이 높아진다는 것입니다.
3항 연산자
3항 연산자의 경우에는 조건식 1, 2, 모두 세 개의 피연산자를 필요로 하는 삼항 연산자이며, 조건 연산자 중 하나뿐이다.
조건식 ? 식1 : 식2
조건 연산자의 결과가 true이면 식1이, false 이면 식2가 연산결과가 된다.가독성을 높이기 위해 괄호를 사용하기도 한다.
일단 이것의 장점은 if문에 있어 조건연산자가 간략하다는 것이다.
연산자 우선순위
산술 > 비교 > 논리 >대입, 대입은 제일 마지막에 수행된다.
단항(1) > 이항(2) > 삼항(3), 단항의 연산자의 우선순위가 이항 연산자보다 높다.
단항 연산자와 대입 연산자를 제외한 모든 연산의 진행방향은 왼쪽에서 오른쪽이다.
종류
결합규칙
연산자
우선순위
단향 연산자
<—
++, –, +, =, ~, ! (type)
높음
산술 연산자
—>
*, /, %
—>
+, -
—>
«, »
비교연산자
—>
<, >, <=, >=, instanceof
—>
==, !=
논리연산자
—>
&
—>
^
—>
|
—>
&&
—>
||
삼항연산자
—>
? :
대입 연산자
<—
=, +=, -=, *=, /=, %=, «=, »=, &=, ^=, |=
낮음
-
primitive 타입, 변수, 배열
목적
자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.
프리미티브라는 한글말만 보고 커피에 타먹는 가루 용어인가 그래서 어원 비슷하게 쓰는가 생각했는데.. 검색해보니 ‘primitive = 기본적인, 원시적인’ 이라는 뜻이라니.. 잠깐 누구도 보지 않았는데 영어가 부족한 내가 부끄러운 순간이었다..
학습할 것
프리미티브 타입 종류와 값의 범위 그리고 기본 값
일단은 정신을 다잡고 primitive 타입을 알아보기 전 일단 변수의 타입에 대해서 알아보자
우리가 사용하는 값은 문자와 숫자로 나뉘어지고 값의 종류에 따라 저장될 공간의 크기와 저장형식을 정의한 것이 자료형이다. 자료형에는 문자형, 정수형, 실수형이 있으며 가장 알맞은 자료형을 변수의 타입으로 선택하면 된다.
자료형은 기본형(프리미티브 타입)과 레퍼런스 타입으로 나뉘는데 이 둘의 비교는 나중에 하고 프리미티브 타입에 대해서 알아보자
프리미타입은 모두 8개의 타입이 있으면 논리형, 문자형, 정수형 실수형으로 구분된다.
프리미티브 타입 종류, 기본값
분류
타입
논리형
booleantrue와 false 둘 중 하나의 값으로 갖으며 조건식과 논리적 계산에 사용된다.
문자형
char문자를 저장하는 데 사용되며 변수에 하나의 문자만 저장
정수형
byte, short, int, long정수를 저장하는데 사용되며 주로 int가 사용된다. byte는 이진 데이터 다룰 때 사용되며, short는 C언어와 호환을 위해서 추가되었다.
실수형
float, double실수를 저장하는데 사용되며, 주로 double이 사용된다.
Primitive type 범위
1byte
2byte
4byte
8byte
논리형
boolean
문자형
char
정수형
byte
short
int
long
실수형
float
double
값의 범위
자료형
저장 가능한 값의 범위
bit
byte
boolean
false, true
8
1
char
‘\u0000’ ~ ‘\uffff’ (0 ~ 2^16 -1, 0 ~ 65535)
16
2
byte
-128 ~ 127 (-2^7 ~ 2^7-1)
8
1
short
-32,768 ~ 32,767 (-2^15 ~ 2^15 -1)
16
2
int
-2147483648 ~ 2147483647
32
4
long
-9223372036854775808 ~ 9223372036854775807
64
8
float
3.4E-38(-3.410^38) ~ 3.4E+38(3.410^38)
32
4
double
1.79E-308(-1.7910^308) ~ 1.79E+308(1.7910^308)
64
8
프리미티브 타입과 레퍼런스 타입
프리미티브가 기본형이라고 하면 레퍼런스는 그래도 참조형이라고 알고 있다! 여튼 위에 프리미티브 타입에 대해 적었기 때문에 레퍼런스 타입에 대해서 이야기 하자면, 레퍼런스 타입은 어떤 값이 저장되어 있는 주소(memory address)를 값으로 갖는다. 즉 주소를 따라가 적혀있는 값을 사용한다고 생각하면 된다.
참조형 변수를 선언할 때는 변수의 타입을 클래스로 사용해 클래스 이름이 참조변수의 타입이 된다. 즉 새로운 클래스는 새로운 참조형을 추가한다 봐도 된다.
Date today = new Date();
여기서 이 코드의 뜻은 Date 객체를 생성해서 그 주소를 today에 저장이라고 하면 된다.
그리고 참조변수 today를 통해 생성된 객체를 사용할 수 있게 된다.
여기서 프리미티브랑 레퍼런스 차이를 조금 더 추가해서 이야기 하자면, 프리미티브는 date type을 쓰며 레퍼런스의 참조형은 항상 객체의 주소(4byte 정수)를 저장하여 객체의 종류에 의해 구분되므로 type이라는 용어로 사용한다. 허나 타입이 자료형보다 포괄적 의미이므로 굳이 구분할 필요는 없다.
리터럴
리터럴은 일단 상수랑 비교해야 하는데 상수는 프로그래밍에선 값을 한번 저장하면 변경할 수 없는 고유 값이라고 생각하면 된다. ex) final int WIDTH = 20;
그래서 리터럴이 무엇이냐 하면 데이터 그 자체를 말한다. 즉, 위 WIDTH 예시에서 20의 값을 final로 넣은 WIDTH는 상수이고 저 20 이라는 값은 우리가 20이라는 뜻을 세상을 바꾸지 않는 한 변하지 않는 값이 ‘리터럴’이라고 말할 수 있다.ex) 1L (Long타입으로 지정하는 숫자 1)
재미있는건 리터럴의 타입은 저장될 변수의 타입과 일치하는 것이 보통이지만, 타입이 달라도 저장 범위가 넓은 타입에서 좁은 타입으로 저장은 허용된다는 것이다. ex) int i = ‘A’;
변수 선언 및 초기화하는 방법
일단 변수에 대해 뜻을 한번 적어보자면 ‘단 하나의 값을 저장할 수 있는 메모리 공간’ 이라고 정의한다. (그냥 일단 적어봤다)
변수 선언
int age;
이렇게 코드에 적어주면 변수를 선언했다고 말한다.
저기서 int 라고 적어 준 것이 변수 타입이며 저장하고자 하는 값에 맞게 타입을 선택해서 적어주면 된다. 그다음 age 라고 적어 준 것이 변수 이름이며 뜻에 적어놓은 메모리 공간에 붙여준 이름이라고 생각하면 된다. 저 age로 가져오고 저장하는 일을 할 수 있다.
변수의 초기화
변수의 초기화란, ‘변수를 사용하기 전에 처음으로 값을 저장하는 것’ 이며, 뜻 처럼 변수를 선언한 후엔 변수 사용을 할 수 있으나 그 전에 변수를 초기화 해주어야 한다. 메모리는 여러 프로그램에 의해 저장된, ‘알 수없는 값’이 남아 있을 수 있기 떄문이다.
int age = 25;
변수의 종류에 따라 초기화를 생략할 순 있지만, 사용되기 전엔 값을 초기화 시켜주는 것이 좋다.
변수 의 스코프와 라이프타임
스코프
스코프란 뜻은 잘 몰라서 검색해보니 영역이라는 뜻을 가지고 있다. 영역이면 흠.. 백기선님이 말한 변수의 스코프 = 변수의 영역 이면 변수가 쓰이는 공간.. 그러면 한 공간에서 쓰이는 변수의 공간, 영역이면 기본 클래스를 배울 때 class에 선언한 변수는 class 안의 함수에서 쓸 수 있지만, class 내 method 에 선언한 변수는 클래스 밖으로 가져 올 수없다. 이런건가 라고 생각한다.
그리고 이젠 검색해서 찾아보면, 예상이랑 비슷하게 자바 변수가 가질 수 있는 활동 영역이 있고 이걸 스코프라 부른다. 스코프의 종류는 메소드 스코프랑 클래스 스코프로 나뉜다.
메소드 스코프 : 메소드 내에서 선언해 메소드 내에서만 돌아다니는 영역
클래스 스코프 : 클래스 내부에 있는 곳을 전부 다 돌아다닐 수 있는 영역
예를 들어 account 클래스가 있고 생성자를 만들어 주려고 한다. (이름을 넣어주는 생성자)
public Class Account{
String name;
public Account(String name){
name = name;
}
}
이런 식으로 되어 있으면 생성자 내에 있는 name = name; 부분을 보자. 앞의 name은 사실 우리가 원하는 Account 클래스 내의 name에 파라미터로 받아온 값을 클래스 스코프의 name에 넣고 싶은데 저렇게 쓰면 name을 쓰면 파라미터에 파라미터를 넣게 되어버린다. 왜냐면 같은 메소드 스코프 내에서의 name에 name 을 넣겠다는 뜻이기 때문에
우리는 이때 써야할 것은 this가 있다. 이 this라는 것은 자기 자신 객체를 가리키는 키워드로써
this.name = name;
라고 적어주면 우리가 원하는 방식대로 name을 넣을 수 있다.
라이프타임
라이프타임은 내가 구글링이 부족한 지 정보를 잘 알아 낼 수 없어 남들이 올린 과제를 좀 읽어보기로 했다. (센세.. 나 잘하고 있는거 맞죠?) 일단은 여러 글들을 읽어보니 데이터가 살아 있는 시간, 즉 가비지 컬렉터가 돌아가기 전까지의 시간이라고 써져있다. 그리고 라이프 타임이 적용되는 3가지 변수가 있는데 인스턴스 변수, 클래스 변수, 지역변수가 있다.
변수
범위
생성시기
종료시기
클래스 변수
클래스
클래스 메모리 선언시
프로그램 종료 시
인스턴스 변수
클래스
인스턴스 생성
GB 실행 시
지역 변수
메서드, 생성자, 블럭
변수 실행
선언된 범위 넘어갈 때
타입 변환, 캐스팅 그리고 타입 프로모션
타입변환
‘하나의 타입을 다른 타입으로 바꾸는 것’ 이라고 한다. 자바에서는 논리형 boolean을 제외한 나머지 기본 타입 간 타입변환이 자유롭게 된다.
여기서 하나 주의할 것은 다른 타입끼리의 연산을 수행할려고 하면 피 연산자들을 같은 타입으로 만들어 진행합니다. 그래서 메모리에 할당받은 바이트 크기가 상대적으로 작은 타입에서 큰 타입으로 변경은 생략할 수 있다. 허나 반대인 경우에는 큰 것을 작은 것에 넣다 보니 데이터 손실이 일어난다는 것이다. 따라서 이 때는 자바 컴파일러가 오류를 발생시킨다.
캐스팅
프로그래밍시 가른 타입간의 연산을 수행해야 하는 경우가 있는데, 이때 타입을 일치시켜야 하는데 이거를 캐스팅(형변환)이라고 한다.
방법은 간단히 ‘(타입)피연산자’ 로 정의하며 피 연산자를 타입형으로 바꿨을 땐 값만 변해서 읽을 뿐, 변화는 없다.
그리고 기본형과 참조형은 서로 형변환을 할 수 없다.
타입 프로모션
타입 프로모션.. 이럴수록 영어에 대해 참 막막해질 때가 있다. 처음엔 오 새로운건가 했다가 자동 형변환이라는 해석을 듣고 당황;; 허나 일단은 이걸 적어놓으면 담엔 안헷갈리겠지 하며 적는다.
타입 프로모션은 한국말로 자동 형변환라고 불리며 편의상의 이유로 형변환을 생략하는데 진짜 생략이 아니라 컴파일러가 생략된 형변환을 자동으로 추가해준다.
근데 재밌는건 명시적으로 형변환 해줬을 경우는 의도적인 것을 알고 컴파일러는 에러를 발생시키지 않는다.
char ch = (char)1000;
일단 컴파일러는 자동적으로 더 넓은 타입으로 형변환 해준다.
즉 타입 프로모션의 규칙은 ‘기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환 해준다.’ 이다.
1차 및 2차 배열 선언하기
배열은 같은 타입의 여러 변수를 하나의 묶음으로 다루는 것 이라고 나온다.
그리고 1차원 선언 방법은
타입[] 변수이름; //배열 선언(배열을 다루기 위한 참조변수 선언)
변수이름 = new 타입[길이]; // 배열을 생성( 실제 저장공간 생성)
2차원 선언 방법은
타입[][] 변수이름; // int[][] score;
타입[] 변수이름[]; // int[] score[];
타입 변수이름[][]; // int score[][];
초기화는 첫번째 [ ] 은 ‘행’ 이고 두번째 [] 은 ‘열’ 이다.
int[][] score = new int[4][2];
타입 추론, var
타입 추론이란, 코드 작성 당시엔 타입이 정해져 있지 않았지만, 컴파일러가 그 타입을 유추하는 것이다.
이는 곧 타입을 명시하지 않아도 되며 가독성을 높일 수 있다.
그리고 var 이거 자바스크립트에서 보던 것인데 java에서 보인다 ( 아직 난 개발자가 되려면 멀었나 보다..)
찾아보니깐 java 10 에서부터 지원하는 변수로 선언할 수 있게 되었다. 그리고 11부터 이를 이용한 람타타입 지원도 생겼다 한다. 그리고 javascript에서 var랑 비슷하면서 다른데 java에서의 var는 종속적인 강타입으로 관리하기 때문이라고 한다. 또한 var는 선언과 동시에 초기화 해줘야 한다. 나는 var 같은 경우는 클래스 타입이 제네릭으로 해서 길거나 값이 복잡해지면 var 쓰고 설명만 잘해놓으면 괜찮게 사용할 수 있다 생각한다. (근데 여긴 내 생각 쓰는데가 아닌데;;) 일단은 백기선님 스터디 들으면서 var에 대한 설명이 나오면 잘 들어봐야겠다.
-
자바의 애노테이션
목적
자바의 애노테이션에 대해 학습하세요.
학습할 것
애노테이션 정의하는 방법
@retention
@target
@documented
애노테이션 프로세서
1. 애노테이션 정의하는 방법
애너테이션이란
프로그램의 소스코드 안에 다른 프로그램의 위한 정보를 미리 약속된 형식으로 포함시킨 것
프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공하는 장점
작성법
@interface 애너테이션이름 {
타입요소 이름();
...}
@애너테이션이름 -> 애너테이션
애너테이션이름 -> 애너테이션 타입
애너테이션 내에 선언된 메서드를 애너테이션의 ‘요소’ 라고 하며 요소들을 통해 값을 정의할 수 있다.
요소들은 반환값이 있고 매개변수가 없는 추상 메서드 형태이며, 상속을 통해 구현하지 않아도 된다.
다만 요소들의 값은 빠짐없이 지정해줘야 한다. (default를 옆에 붙여주면 기본 값을 가질 수 있다.)
@interface TestInfo{
String[] testTools() default {"test1", "test2", ""}
}
@TestInfo(testTools = {"aaa", "bbb", "ccc"})
class or method { ~~ }
만약 이름의 요소가 value 이면 요소이름 생략 가능
java.lang.annotation.Annotation
애너테이션은 상속이 허용되지 않으므로, 명시적으로 Annotation을 조상으로 지정할 수 없다.
2. @retention
애너테이션이 유지되는 기간을 지정하는데 사용한다.
유지정책
의미
SOURCE
소스파일에만 존재. 클래스파일에는 존재하지 않음
CLASS
클래스파일에 존재. 실행시에 사용불가. 기본값
RUNTIME
클래스파일에 존재. 실행시에 사용가능.
컴파일러가 사용하는 애너테이션은 유지 정책이 SOURCE이다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override { ...}
SOURCE : 컴파일러가 사용하는 애너테이션, 직접작성할 것 아니면 이 유지정책은 필요 없다.
RUNTIME : , 실행 시 리플랙션을 통해 클래스파일에 저장된 애너테이션 정보를 읽어서 처리할 수 있다.
CLASS : 클래스 파일에 저장할 수 있게는 하지만 클래스파일이 JVM 로딩될 때는 정보가 무시되어 애너테이션 정보를 얻을 수 없다.
3. @target
애너테이션이 적용가능한 대상을 지정하는데 사용.
대상타입
의미
ANNOTATION_TYPE
애너테이션
CONSTRUCTOR
생성자
FIELD
필드
LOCAL_VARIABLE
지역변수
METHOD
메서드
PACKAGE
패키지
PARAMETER
매개변수
TYPE
타입
TYPE_PARAMETER
타입 매개변수
TYPE_USE
타입이 사용되는 모든 곳
TYPE은 타입을 선언할 때 붙일 수 있고, TYPE_USE는 해당 타입의 변수를 선언할 때 붙일 수 있다.
FIELD는 기본형에, TYPE_USE는 참조형에 사용된다.
4. @documented
애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다. 자바에서 제공하는 기본 애너테이션 중, @Override, @SuppressWarnings를 제외하고는 이 메타 애너테이션이 붙어있다.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface{}
5. 애노테이션 프로세서
어노테이션을 프로세싱 즉, 내가 보았던 것은 lombok이 대표적이며, 이 외에 이것을 어떻게 작성해야 될 지 모르겠다. 그래서 강의를 들으면서 작성하려고 한다.
Reference
남궁성. Java의 정석
-
JVM, 자바 코드 실행 과정
목적
자바 소스 파일(.java)을 JVM으로 실행하는 과정 이해하기
남궁성님이 출판하신 JAVA의 정석를 기반으로 작성하려고 한다.
학습할 것
JVM이란 무엇인가
JVM이란 java를 실행하기 위한 가상 머신이다. 여기서 ‘가상머신’ 대신 ‘가상 컴퓨터’라고 부르는게 이해하기 좋다.
자바로 작성된 애플리케이션은 모두 이 가상 컴퓨터에서 실행되기 때문에 Java Application이 실행되기 위해선 반드시 JVM이 필요하다.
일반 Application의 코드는 OS만 거쳐 하드웨어로 전달되는데 Java Application은 JVM을 한 번 더 거치며 실행 될 때 하드웨어에 맞게 컴파일을 진행한다.
그렇다고 JVM 하나로 통합되는게 아니라 각 OS에 맞는 JVM이 실행된다 (ex : Window용 JVM, Macintosh용 JVM, Linux용 JVM )
이래서 자바는 Write once, run anywhere (한번 작성시 어디서든 실행된다.) 라는 장점이 있다.
컴파일 하는 방법
개발 툴을 이용해 .java 파일을 생성하고 build시 java Compiler의 javac라는 명령어를 사용해 .class 파일을 생성합니다. (이 .class는 파일은 아직은 어셈블리어가 아닌 자바 바이트 코드 입니다)
이 파일은 클래스 로더에 의해서 JVM 내로 로드되고 Execution Engine에 의해 기계어로 해석되어 메모리에 배치되게 됩니다. 그리고 Stack Area, Method Heap Area, PC Register Area 에 올라간 파일들은 클래스 메소드 호출이 발생하면 영역의 Method들 정보를 읽어 매개변수, 지역변수 리턴값등이 Stack에 의해 처리되게 됩니다. 그리고 메소드 실행 끝나면 Stack영역에서는 자동으로 제거됩니다. 이후 Garbage Collector가 실행되어 메모리를 정리해주게 됩니다.
바이트코드란 무엇인가
자바의 바이트 코드란 JVM이 이해할 수 있는 언어로 변환된 자바 소스 코드이며, 자바 컴파일러에 의해 변환되는 코드의 명령어 크기가 1바이트라서 자바 바이트 코드라고 불리고 있다.
바이트 코드의 확장자는 .class이며 가상머신만 설치되어 있다면, 어떤 운영체제에서라도 실행될 수 있습니다.
JIT 컴파일러란 무엇이며 어떻게 동작하는지
일단 JIT(Just In Time) 컴파일러란 동적 번역 이라 할 수 있으며 실제로 프로그램을 실행하는 기점에서 기계어로 번역하는 컴파일러이다.
여기서 원래 컴퓨터 프로그램을 만드는 방법은 2가지가 있는데 인터프리트 방식과 컴파일 방식으로 나눌 수 있다.
Interpreter는 실행 중 프로그래밍 언어를 읽어가면서 해당 기능에 대응하는 기계어 코드를 실행한다.
반명 정적 compile은 실행하기 전에 프로그램 코드를 기계어로 번역한다.
여기서 JIT는 두가지를 혼합한 방식이라고 볼 수 있는데 실행시점에서 Interpreter 방식으로 기계어 코드를 생성하면서 그 코드를 ‘캐싱’하여 같은 함수가 여러번 불릴 때 캐싱된 데이터를 사용해 매번 기계어 코드를 생성하는 것을 방지한다.
이래서 한번만 실행되는 코드는 Interpreter 방식이 유리하며 JVM은 메소드가 얼마나 자주 수행되는 지를 체크하여 컴파일을 수행한다.
JVM 구성 요소
JVM은 ClassLoader, Execution Engine, RuntimeData Areas로 구성된다.
ClassLoader 란
JVM 내로 클래스 파일을 load하고 link를 통해 배치를 수행하는 모듈로 Runtime 시에 동적으로 클래스를 로드한다.
자바는 동적코드, 컴파일 타임이 아니라 런타임에 참조한다.
즉 ,클래스를 처음으로 참조할 때 해당 클래스를 load하고 link한다.
Execution Engine 란
class loader를 통해 배치된 클래스를 실행시킨다.
클래스 파일(바이트 코드)은 비교적 인간이 보기 쉬운 형태이기 때문에 기계가 실행할 수 있는 형태로 변경시키는데 이때, JIT와 Interpreter 두가지 방식을 사용한다.
Garbage Collector
동적으로 할당된 메모리 중 사용되지 않은 메모리를 반환하다.
실행 시기는 JVM이 OS에 메모리를 추가적으로
Runtime Data Area
Excution Engine에게 해석된 프로그램은 Runtime Data Area에 배치되어 돌아간다. 이 때 Runtime Data Area는 3가지 구조를 갖는다.
Method Area : 클래스영역으로 인터페이스, 클래스, 메소드, 필드 등의 모든 정보가 들어가 있다. 여기는 모든 쓰레드들이 공유하며 new를 통해 동적으로 생성 시 저장되므로 Garbage Collector 의 대상이다.
Heap : 생성된 인스턴스가 있는 공간으로 Garbage Collector의 대상이며 Heap 정렬을 통해 사용빈도가 높은 인스턴스를 Root Node로 올려서 히트율을 올리는 방식이다. 모든 쓰레드들이 공유한다.
JVM Stacks : 호출스택이라 불리며 메소드가 실행 시 필요한 공간을 제공, 매개변수나 지역변수 등의 임시데이터를 저장한다. 메소드가 끝나면 메모리공간은 반환된다. 쓰레드마다 1개 씩 갖는다.
PC Registers : 일종의 스택으로서 Thread 생성될 때의 공간으로 Thread가 어떠한 명령을 실행하게 될지에 대한 부분을 기록한다. Java는 Stacks-Base 방식으로 작동하는데 JVM은 CPU에 직접 Instruction을 수행하지 않고 Stack에서 Operand를 뽑아내 이를 별도의 메모리 공간에 저장하는 방식을 취하는데 이 공간을 PC라고 한다.
JDK와 JRE의 차이
JDK
자바 개발을 위해 필요한 도구, JRE에서 제공하는 실행 환경뿐만 아니라 자바 개발에 필요한 여러가지 명령어 그리고 컴파일러를 포함했다.
JRE
Java Runtime Environment 의 약자로 자바 실행환경이다. JRE는 자바 프로그램을 동작시킬 때 필요한 라이브러리 파일, java 명령, 및 기타 인프라를 포함하여 컴파일된 Java 프로그램을 실행하는데 필요한 모든 패키지
-
Touch background to close