본문 바로가기

STUDY/Java

<자바의 신> 6장 제가 조건을 좀 따져요

6장 제가 조건을 좀 따져요

if문

if-else 구문은 보통 두가지 이상의 값을 비교하거나, 단순히 true, false 여부만 확인하고자 할 때 많이 사용

 

1. if 구문

if(boolean값) boolean 값이 true일 때 처리문장; // 소괄호 안의 값이 true일 경우 처리문장을 실행

2. if-else 구문

if(조건) 처리문장1; // 조건이 true이면 처리문장 1을
else 처리문장2; // 조건이 false면 처리문장 2를 실행

3. if-elseif 구문

int point = 85;

if(point > 90){              // 90점 초과일 경우
	System.out.println("A");
} else if(point > 80){       // 80점 초과 90점 이하일 경우
	System.out.println("B");
} else if(point > 70){       // 70점 초과 80점 이하일 경우
	System.out.println("C");
} else{                      // 70점 초과가 아닌 모든 경우
	System.out.println("F");
}

 

4. if의 조건이 여러 개

if(age > 25 && isMarried){  // age가 25 초과이면서 isMarried가 true
	...
}

if(age > 25 || isMarried){  // age가 25 초과이거나 isMarried가 true
	...
}

 

&&: 두 조건이 모두 true여야 true

|| : 두 조건 중 하나만 true여도 true

*&&일 때 처음 조건이 false이면 다음 조건들은 점검하지 않고 false

*||일 때 처음 조건이 true이면 다음 조건들을 점검하지 않고 true

5. ? : 연산자

String result = point>90 ? "A" : point>80 ? "B" : point>70 ? "C" : "F";
System.out.println(result);

조건이 true일 때 ? 뒤에 작업을, false일 때 : 뒤에 작업을 수행



switch문

하나의 값이 여러 범위에 걸쳐서 비교되어야 할 때는 하나의 값으로 분기하여 비교하는 switch구문을 사용하는 것이 좋다
switch(비교대상변수){
    case 점검값1:
    처리문장1;
    ...
    break;

    case 점검값2:
    처리문장2;
    ...
    break;

    ...

    default:     // 앞에 있는 조건에 맞지 않는 경우 
    기본처리문장;
    ...
    break;
}

*비교대상변수는 long을 제외한 정수형, Enum, String, 참조 자료형(Character, Byte, Short, Integer만)만 사용 가능

*switch문장에서는 조건을 통과하면 그 다음에 break가 올때까지 어떤 case가 오든지 상관 안하고 실행하기 때문에 case에 대한 처리가 끝나면 break;를 붙여주어야 한다



while문

while(boolean조건){
    처리문장;
    ...
}

조건 값이 true일 경우에만 중괄호 안에 있는 내용들이 수행되고

중괄호가 끝나면 다시 위로 올라가 boolean 조건을 확인한 후 true이면 안의 내용을 수행


*while문에서 break 사용

int loop = 0;
while(loop < 12){
    loop++;
    System.out.println(loop);
    if(loop==6) break; // loop가 6이면 현재 수행중인 중괄호에서 빠져 나간다
}

*while문에서 continue 사용

int loop = 0;
while(loop < 12){
    loop++;
    if(loop==6) continue; // loop가 6이면 그 뒤에 있는 문장은 건너 뛰고 다시 조건문으로
    System.out.println(loop);
}

단, 무한 루프를 조심하기



do-while문

do{
    처리문장;
    ...
} while(boolean 조건);

*적어도 한 번은 반복문장이 실행되는 while문



for문

for(초기화; 종료조건; 조건값증가){
    반복문장
}
  1. 초기화: 변수를 초기화
  2. 종료조건: boolean 조건, true이면 for 루프 내의 반복 문장이 수행되고 그렇지 않으면 for 문 종료
  3. 반복문장이 종료되면 조건 값 증가가 수행
  4. 종료조건이 맞는 지 다시 확인 후 true일 경우 반복문장을 다시 수행
  5. 종료조건이 false일 경우 for 루프는 끝

 

label

두 개 이상의 for나 while 루프가 있을 때 사용
for(int level=2; level<10; level++){
    for(int unit=1; unit<10; unit++){
        if(unit==4) break;
        System.out.println(level + " * " + unit + " = " + level*unit + " ");
    }
    System.out.println();
}

startLabel:
for(int level=2; level<10; level++){
    for(int unit=1; unit<10; unit++){
        if(unit==4) continue startLabel;
        System.out.println(level + " * " + unit + " = " + level*unit + " ");
    }
    System.out.println();
}
  1. unit이 4일 때 break; 이면 안 쪽 for문만 벗어남
  2. unit이 4일 때 label을 사용하면 안 쪽 for문을 벗어나고 바깥 쪽 for문의 시작점으로 이동

 


 

 

7장 여러 데이터를 하나에 넣을 수는 없을까요?

 

배열

한 가지 타입에 대해서 하나의 변수에 여러 개의 값을 넣을 수 있는 자료구조 중 하나

*자료구조: 데이터를 저장하기 위한 구조

ex) List, Queue, Map, LinkedList 등



배열 선언

int [] lottoNumbers = new int[7]; // 7이라는 배열 크기를 지정
int lootoNumbers[] = new int[7];

int [] lottoNumbers = {5, 12, 23, 25, 38, 41, 2}; 
/* 
1. 중괄호를 사용하여 초기화를 할 때는 반드시 한번에 변수 선언 및 초기화를 해야 한다
2. 보통은 배열에 들어가는 값이 계속 바뀔 수 있으므로 절대 변하지 않는 값을 지정할때 사용한다
*/
  • int: 기본 자료형
  • lottoNumbers는 new 예약어를 사용했기 때문에 int를 배열로 만든 참조 자료형
  • 배열도 참조 자료형
  • 배열의 위치는 0부터 시작 → 0~6까지의 7개 공간
lottoNumbers[7] = 9;

// Exception 발생
Exception in thread "main" java.lang.ArrayIndexOUtOfBoundsException: 7

0~6까지의 index를 가지기 때문에 존재하지 않는 7번째 자리에 값을 할당하려고 하면 예외가 발생한다



 

배열의 기본 값

기본 자료형 배열의 기본값은 각 자료형의 기본값과 동일
      byte, short, int, long    float, double    char      boolean
  byte, short, int, long float, double char boolean
기본값 0 0.0 \u0000 false

 

참조 자료형의 기본 값은 new로 초기화하지 않으면 null

→ 참조 자료형 배열의 각각의 값은 반드시 각각의 값을 초기화해야 null이 되지 않음

String [] strings = new String[2];
System.out.println("strings=" + new String[0]);

// 결과
strings=[Ljava.lang.String;@1540e19d]
  • [L : “[”는 해당 객체가 배열이라는 의미, “L”은 해당 배열은 참조자료형이라는 의미
  • java.lang.String; : 해당 배열이 어떤 타입의 배열인지 (String 타입)
  • @1540e19d: 해당 배열의 고유 번호


*기본 자료형의 객체를 출력하면 해당 타입을 대표하는 문자가 출력됨

byteArray = [B@14ae5a5]
intArray = [I@6d6f6e28]
...
boolean byte char double float int long short
Z b C D F I J S

 




2차원 배열

배열의 배열

 

2차원 배열 선언

int [][]twoDim;
twoDim = new int[2][3];

// twoDim[0] =  int 배열
// twoDim[0][0] = int 값
twoDim0  twoDim0  twoDim0 
twoDim1  twoDim1  twoDim1 

 

// 선언 가능
twoDim = new int[2][3];
twoDim = new int[2][];

// 선언 불가능
twoDim = new int[][];
twoDim = new int[][2];



배열의 길이

int[] oneDim = new int[3];
int[][] twoDim = new int[4][2];
System.out.println(oneDim.length);
System.out.println(twoDim.length);

System.out.println(twoDim[0].length);

// 결과
3
4
2
  • .length: 1차원의 경우 int 타입으로 된 배열 크기를 리턴
  • 2차원의 경우 1차원의 크기를 리턴
  • 2차원 배열의 크기를 알고 싶다면 각 1차원 배열에 .length를 붙여야 함

*.length와 같이 점을 찍어서 기능을 호출하거나 계산을 할 때는 참조 자료형만 가능



for 루프

JDK 5부터는 Collection이라는 자료 구조를 처리할 때 for 루프를 보다 쉽게 사용 가능
for(타입이름 임시변수명 : 반복대상객체){
...
}

예제

int [][]twoDim = {{1,2,3}, {4,5,6}};
for(int[] dimArray : twoDim){ // twoDim의 1차원 값은 배열이므로 int[] dimArray
    for(int data : dimArray){
        System.out.println(data);
    }
}

 


 

8장 참조 자료형에 대해서 더 자세히 알아봅시다

  • 참조 자료형: new를 사용해서 객체를 생성
  • new 없이도 객체를 생성할 수 있는 참조 자료형은 오직 String

 

기본 생성자

자바는 생성자를 만들지 않아도 자동으로 만들어지는 기본 생성자가 존재
public class ReferenceDefault{
    public static void main(String[] args){
        ReferenceDefault reference = new ReferenceDefault(); // ReferenceDefault(): 생성자
    }
}

 

아무런 매개 변수가 없는 ReferenceDefault()라는 생성자는 다른 생성자가 없을 경우 기본으로 컴파일 할 때 생성됨

  public ReferenceString() {} // 기본 생성자 작성
  public ReferenceString(String arg){ } // String을 매개변수로 받는 생성자

  public static void main(String args[]){
      ReferenceString reference = new ReferenceString();
  }

 

*메소드와 생성자의 차이: 생성자는 리턴 타입이 없고 클래스 이름으로 생성한다

다른 생성자가 없을 경우 기본 생성자가 컴파일할 때 생성되므로 다른 생성자가 있으면 자동으로 만들어지지 않음
→ 매개변수가 없는 생성자를 사용하고 싶으면 기본 생성자를 작성해 컴파일하면 됨

  // 인스턴스 변수 
  String instanceVariable;

  // 생성자
  public ReferenceString() {}
  public ReferenceString(String arg) {} 

  // 메소드 
  public static void main(String args[]){
  ...
  }
  public String getString(){
      return instanceVariable;
  }



DTO (Data Transfer Object)

  • 어떤 속성을 갖는 클래스를 만들고, 그 데이터를 다른 서버로 전달하기 위한 목적
  • VO(Value Object): DTO와 형태는 동일하지만, 데이터를 담아 두기 위한 목적 
public class MemberDTO{
	public String name;
	public String phone;
	public String email;

	// 생성자: 아무 정보도 모를 때
	public MemberDTO(){ }    
                     
	// 생성자: 이름만 알 때
	public MemberDTO(String name){                
		this.name = name;
	} 

	// 생성자: 이름, 전화번호만 알 때
	public MemberDTO(String name, String phone){  
		this.name = name;
		this.phone = phone;
	}

	// 생성자: 모든 정보를 알 때
	public MemberDTO(String name, String phone, String email){  
		this.name = name;
		this.phone = phone;
		this.email = email;
	}
}

 

// MemberDTO를 리턴 타입으로 선언하고 객체를 리턴 가능
public MemberDTO getMemberDTO(){
	MemberDTO dto = new MemberDTO();
	...
	return dto;
}
  • 자바의 생성자는 매개 변수 개수의 제한은 없고, 몇 개를 만들어도 상관 없다
  • 필요한 생성자만 만드는 게 좋다

 

this

객체의 변수와 매개 변수를 구분하기 위한 this 예약어
public class MemberDTO{
    public String name;
    public String phone;
    public String email;

// 생성자: 이름만 알 때
    public MemberDTO(String name){                
        this.name = name;
    } 
}
  • 인스턴스 변수인 name과 매개 변수인 name을 구분하기 위해 this를 사용
  • this.name: 객체의 name (인스턴스 변수인 name)을 의미

 

메소드 overloading

  • 메소드 이름은 같지만 매개 변수가 다를 때 다른 메소드로 인식

ex) 매개 변수의 개수가 같아도 타입의 순서가 다르면 다른 메소드처럼 인식

  • 매개 변수의 타입이 같고 변수 이름이 같으면 같은 메소드로 인식

→ “같은 역할을 하는 메소드는 같은 메소드 이름을 가져야 한다”



메소드 return

  • 메소드 종료 조건
    1. 메소드의 모든 문장이 실행되었을 때
    2. return 문장에 도달했을 때
    3. 예외가 발생(throw)했을 때
  • 자바에서는 모든 타입을 한 개만 리턴 타입으로 넘길 수 있다
  • 메소드 이름 앞에 변수의 타입을 지정하고, return이라는 예약어를 사용하여 return
public class ReferenceReturn{
    public static void main(String args[]){
        ReferenceReturn reference = new ReferenceReturn();
        System.out.println(reference.intReturn());
    }
    public int intReturn(){
        int returnInt = 0;
        return returnInt;
    }

// 결과
0

 

  • 여러 개를 넘겨주고 싶다면?
    → DTO 사용
  • 리턴 타입이 void인 메소드에서 더이상 실행하고 싶지 않다면?
      ...
      if(flag) return; // flag가 true이면 메소드 수행을 종료
      ...
    }
  • public void wantToStopInTheMiddel(boolean flag){



 

static 메소드 vs 일반 메소드

  • static 메소드: 객체를 생성하지 않아도 메소드를 호출할 수 있는 메소드
  • 리턴 타입 앞에 static 명시
  • static 메소드는 클래스 변수만 사용 가능 (static이 붙어있지 않은 인스턴스 변수는 사용 불가능)

static 블록

static {
// 딱 한번만 수행되는 코드
}
  • 객체가 생성되기 전에 한 번만 호출되고, 그 이후에는 호출 불가능
  • 클래스 내에 선언되어야 하며 메소드 내에서는 선언 불가
  • 인스턴스 변수나 클래스 변수와 같이 어떤 메소드나 생성자에 속해있을 수 없음
  • static 블록은 여러개를 선언 가능하지만 선언된 순서대로 블록들이 호출되므로 유의
  • static 블록은 기본 생성자가 호출되기 전에 먼저 호출되므로 클래스를 초기화할 때 꼭 수행되어야 하는 작업이 있을 경우 유용
  • static 블록 안에서는 static한 것들만 호출 가능

 

Pass by value: 값만 전달한다

기본 자료형은 무조건 Pass by Value로 데이터를 전달한다

public class ReferencePass{
    public static void main(String args[]){
        ReferencePass reference = new ReferencePass();
        reference.callPassByValue();
    }
    public void callPassByValue(){
        int a=10;
        System.out.println("a: " + a);
        passByValue(a);
        System.out.println("a: " + a);
    }
    public void passByValue(int a){
        a = 20;
        System.out.println("passByValue a: " + a);
    }
}

// 결과
a: 10
passByValue a: 20
a: 10
  • passByValue를 호출하기 전과 후에 데이터가 변경되지 않는다

 

Pass by reference: 객체에 대한 참조가 넘어간다

참조 자료형은 Pass by Reference로 데이터를 전달한다

public class ReferencePass{
    public static void main(String args[]){
        ReferencePass reference = new ReferencePass();
        reference.callPassByReference();
    }
    public void callPassByReference(){
        String b="z";
        MemberDTO member = new MemberDTO("Jiyoon");
        System.out.println("b: " + b);
        System.out.println("name: " + member.name);
        passByReference(b, member);
        System.out.println("b: " + b);
        System.out.println("name: " + member.name);
    }
    public void passByReference(String b, MemberDTO member){
        b = "b"; // b = new String("z");
        member.name = "Babo";
        System.out.println("passByReference b: " + b);
        System.out.println("passByReference name: " + member.name);
    }
}

// 결과
z
Jiyoon
b
Babo
z
Babo
  • b = “b”; 는 new를 사용하여 객체를 생성한 것 이므로 passByReference 호출 전 후의 데이터가 변경되지 않음
  • member는 다른 객체로 처리한 것이 아니라 매개 변수로 받은 값을 수정했기 때문에 메소드 호출 후 데이터가 변경됨 (참조 자료형이라서)

 

타입…변수명

매개 변수가 지정되어 있지 않은 임의 개수의 매개변수를 넘겨주기 위해 사용

public void calculateNumbers(int...numbers){ }

ex) printf()

printf(String format, Object... args)

 


 

9장 자바를 배우면 패키지와 접근 제어자는 꼭 알아야 해요

 

패키지 package

클래스들을 구분 짓는 폴더

 

패키지 선언문

package 패키지명;
  • 소스의 가장 첫 줄에 있어야만 한다
  • 소스 하나에는 하나만 있어야 한다
  • 패키지명은 java로 시작할 수 없다
  • 패키지 이름은 모두 소문지로 지정해야 한다
  • 자바의 예약어를 사용할 수 없다

 

import

자바에서는 같은 패키지에 있는 클래스들과 java.lang 패키지에 있는 클래스들만 접근 가능

다른 패키지에 있는 클래스에 접근하려면?

import 패키지명.클래스명;

static한 변수(클래스 변수)와 static 메소드를 사용하려면?

import static 패키지명.클래스명.메소드명;
import static 패키지명.클래스명.클래스변수;

*import 하지 않아도 되는 패키지

  • java.lang 패키지 ex) Stirng, System
  • 같은 패키지

 

 

접근 제어자 Access modifier

  1. public : 누구나 접근 가능
  2. protected : 같은 패키지 내에 있거나 상속받은 경우에만 접근 가능
  3. package-private(접근제어자 없음) : 같은 패키지 내에 있을 때만 접근 가능
  4. private : 해당 클래스 내에서만 접근 가능

 

접근 제어자 사용

  • 메소드
  • 인스턴스 변수
  • 클래스 변수
  • 클래스 선언문

*public으로 선언된 클래스가 소스 내에 있다면, 그 소스 파일의 이름은 public인 클래스 이름과 동일해야 한다

 


 

10장 자바는 상속이라는 것이 있어요

 

extends

public class Child extends Parent{ }
// Parent 클래스에 선언되어 있는 public 및 protected로 선언되어 있는 모든 변수와 메소드를 사용가능

extends 클래스명 → 클래스를 상속받는다

Child → Parent

 

상속

  • 부모 클래스에서는 기본 생성자를 만들어 놓는 것 이외에는 상속을 위해서 아무런 작업을 할 필요는 없다
  • 자식 클래스는 클래스 선언시 extends 다음에 부모 클래스 이름을 적어준다
  • 자식 클래스의 생성자가 호출되면, 자동으로 부모 클래스의 매개 변수 없는 생성자가 실행된다
  • 자식 클래스에서는 부모 클래스에 있는 public, protected로 선언된 모든 인스턴스 및 클래스 변수와 메소드를 사용할 수 있다
  • 자바는 다중 상속이 불가능하다

부모 클래스에 기본 생성자가 없다면?

  1. 부모 클래스에 “매개 변수가 없는” 기본 생성자를 만든다
  2. 자식 클래스에서 부모 클래스의 생성자를 명시적으로 지정하는 super()를 사용한다
super(); // 부모 클래스의 생성자를 호출
  • 부모 클래스에 매개 변수가 있는 생성자만 있을 경우에는 super()를 이용해 부모 생성자를 꼭 호출해야 함
  • 자식 클래스의 생성자에서 super()를 명시적으로 지정하지 않으면, 컴파일시 자동으로 super()가 추가됨
  • super()는 자식 클래스의 생성자에서 가장 첫줄에 선언되어야 한다

 

 

메소드 overriding

자식 클래스에서 부모 클래스에 있는 메소드와 동일하게 선언하는 것
접근 제어자, 리턴 타입, 메소드 이름, 매개 변수 타입 및 개수가 모두 동일해야 함
public class Parent{
    public Parent(){ }
    public void printName(){
        System.out.println("Parent");
    }
}

public class Child extends Parent{
    public Child(){ }
    public void printName(){
        System.out.println("Child");
    }
}

public class InheritanceOverriding{
    public static void main(String[] args){
        Child child = new Child();
        child.printName();
    }
}

// 결과
Child
  • 부모 클래스에 선언되어 있는 메소드와 동일하게 선언되어 있는 메소드를 자식 클래스에 선언하면 자식 클래스의 메소드만 실행된다
  • 부모 클래스에 있는 메소드는 자식 클래스에서 리턴 타입을 마음대로 바꿀 수 없다
  • 부모 클래스에 있는 메소드는 자식 클래스에서 접근 제어자를 축소되는 방향으로 바꿀 수 없다

ex) 부모 클래스에서 public으로 선언한 것을 자식 클래스에서 private으로 선언할 수 없음

부모 클래스에서 private으로 선언한 것은 자식 클래스에서 모든 접근 제어자로 선언 가능



Overloading vs Overriding

  • Overloading: 확장 (메소드의 매개 변수들을 확장)
  • Overriding: 덮어쓰기 (부모 클래스가 가지고 있는 메소드를 자식 클래스가 재정의)

 

참조 자료형의 형 변환

  • 자식 클래스인 Child에서는 부모 클래스인 Parent에 있는 메소드와 변수들을 사용 가능
  • 부모 클래스인 Parent에서는 자식 클래스인 Child에 있는 모든 메소드와 벼수들을 사용 불가능
  • 자식 클래스의 타입을 부모 클래스의 타입으로 형 변환: 자동
Parent parent = new Parent();
Child child = new Child();

Parent parent2 = child; // 정상
Child child2 = parent; // error 발생
Child child2 = (Child)parent; // 예외 발생

Child child2 = (Child)parent2; // 정상
  • parent2: Parent 클래스의 객체인 것처럼 보이지만 Child 클래스의 객체
  • parent2를 Child 클래스로 형 변환은 가능 (명시적 형 변환)

 

instanceof 객체의 타입 확인

if(객체 instanceof 클래스(타입){ } // 객체가 해당 클래스타입인지 확인

*instanceof를 사용하여 타입을 점검할 때는 가장 하위에 있는 자식 타입부터 확인

→ 부모 타입도 true를 반환하기 때문에



 

다형성 Polymorphism

형 변환을 하더라도, 실제 호출되는 것은 원래 객체에 있는 메소드가 호출된다