복습 / 과제 설명
https://laker99.tistory.com/20?category=1065834
- Calendar 클래스 로 날짜 시간 요일 까지 출력
- 새로 만드는게 아니라 시스템으로부터 구해오는 클래스라서 Calendar 클래스는 new 연산자로 객체 못만듬

Calendar 객체 생성법
1. 

Calendar c1 = new GregorianCalendar


- 이미 형성된 상속관계, 자식 클래스인 GregorianCalendar 로 객체를 만들어서 왼쪽의 부모에게 전달 = 레퍼런스 형변환
- 자식 객체가 부모에게 전달 = 업캐스팅
- 세번째 형변환인 레퍼런스 형변환이며, 두 클래스 사이에 상속관계가 전제되어야만 가능함

2. 

Calendar c = Calendar.getInstance();


- Calendar 클래스 안의 정적메소드 getInstance() 메소드 사용해서 객체를 구해옴, Calnedar 객체를 받음 
* 객체 = 인스턴스

- 년월일시분초 -> Calendar의 정적필드를 이용해서 구해야함(API 문서)
- 클래스명.필드명 으로 필드 사용
- 연도 구해올땐 Calendar.YEAR 필드로 get함수써서 구함

 

int y = c.get(Calendar.YEAR);
int m = c.get(Calendar.MONTH) + 1; // 0~11 이므로 +1 해주기
int d = c.get(Calnedar.DATE);

int h1 = c.get(Calendar.HOUR); // 12시간
int h2 = c.get(Calendar.HOUR_OF_DAY); // 24시간

int ap = c.get(Calendar.AM_PM); // 오전 0 오후 1
int w = c.get(Calendar.DAY_OF_WEEK); //1~7 을 돌려줌

- 1,2,3,4,5,6,7 로 일정히 증가하므로 숫자를 요일로 변환시켜주기 위해서는 String[] 클래스 배열을 사용한다 

 

		int w = c.get(Calendar.DAY_OF_WEEK);//1~7
		System.out.println("w="+w);
		// 1:일, 2:월, 3:화, 4:수, 5:목, 6:금, 7:토
		String[] week={"일","월","화","수","목","금","토"};
		
		System.out.println(week[w-1]+"요일");

- 이렇게 배열인덱스와 맞춰주면 됨 
- "금" 은 6이 나오는데 String배열에는 인덱스 5번이므로 -1 해줌

 

문자열 처리 클래스 종류
- String, StringBuffer, StringTokenizer
1. String : 문자열을 저장함, 가장 빈도 높은 사용
2. StringTokenizer : 여러 문자들을 구분기호로 파싱할때 사용
3. StringBuffer - 가장 빈도 낮지만 알아야함

문자열 처리 클래스 차이
- 3개의 클래스가 기능이 조금씩 다르다.
- 메모리 상에서 데이터 처리하는데 차이가 있다
- String 클래스의 메소드 아주 많다

String 클래스와 메소드
- 자바에서 가장 사용빈도 높은 클래스
- java.lang 패키지 안, import필요 없다
- 지원되는 메소드 100개 넘음

 

String 클래스 예제1

- StringTest00.java

package p2022_07_01;

class StringTest00 {
	public static void main(String[] args) {
		String str1 = new String("Java Programming");
		String str2 = new String("Java Programming");

		if (str1 == str2) { // 주소 비교
			System.out.println("같다");
		} else {
			System.out.println("다르다"); // 다르다
		}
		String str3 = "Java Programming";
		String str4 = "Java Programming";

		if (str3 == str4) {
			System.out.println("같다"); // 같다
		} else {
			System.out.println("다르다");
		}

		if (str1.equals(str3)) { // 값 비교
			System.out.println("같은 값");
		} else {
			System.out.println("다른 값");
		}
	}
}
다르다
같다
같은 값

- String 클래스만 new를 써도 되고 그냥 String name = "mimi" 라고 할 수도 있다
- new연산자 쓸때마다 매번 힙메모리상에 새로운 공간을 생성하라는 표시
- 힙메모리상에 "Java Programming"을 저장하고 있다

 

- 여기서 str3와 str2의 주솟값이 같을까? 즉 같은 "Java Programming"일까?
-> 아니다 위에서든 밑에서든 new를 쓰면 그냥 단독으로 새로운 공간 가지는거임

- str3에서 힙에 Java Programming 만들어졌으므로
- String str4 = "Java Programming"; 하면 그냥 str4는 이미 str3때 만들어진 값의 주솟값을 리턴받음
-> str3 == str4 같다 (같은 주소다)

 

그림

 

참조형의 비교대상 2개
1. 비교연산자로 주솟값 비교
2. equals로 값을 비교

 

String 클래스 예제2
- ConnectString.java

package p2022_07_01;

public class ConnectString {
	
    public static void main( String[] args ) {
	// String 객체 선언
	String gemini = "gemini";
	String johnharu = "johnharu";
		
	// 두 String 객체를 "+" 연산 수행
	String tempString1 = gemini + johnharu;
	System.out.println( tempString1 );
	System.out.println( "gemini" + "johnharu" );

	// String + 정수형
	String tempString2 = tempString1 + 100;
	System.out.println( tempString2 );
    }
}
geminijohnharu
geminijohnharu
geminijohnharu100

 

위 예제 부분1

	String tempString1 = gemini + johnharu;
	System.out.println( tempString1 );

 

- 객체 + 객체 를 쓰면 주솟값이 아닌 가리키는 값들끼리를 연결해준다

 

위 예제 부분2

	System.out.println( "gemini" + "johnharu" );

- 이렇게해도 연결되어 출력된다

 

String형 자료형과 기본자료형 변수끼리 결합(위 예제 부분3)

	// String + 정수형
	String tempString2 = tempString1 + 100;
	System.out.println( tempString2 );

- String형 자료형과 기본자료형 변수끼리 산술적인 연산 +가 안된다
- 붙어서 geminijohnharu100이 출력되고 결과는 전체가 String형으로 바뀜

 

String 클래스 예제3(String과 메모리)

- StringTest01.java

package p2022_07_01;

// String 객체를 생성한 후에 메소드에 의해서 값의 변화가 일어나면
// 변경된 값을 힙메모리 영역에 다시 저장 한다.

// Garbage Collection 기능 (쓰레기 수집 기능)
// : 재사용할 수 없는 힙메모리 영역의 데이터를 모아서 지워주는 기능

class StringTest01 {

  public static void main(String[] args) {
    String str1 = "Java Programming";
    
	str1.toUpperCase();              // 대문자로 변환
    System.out.println(str1);      //메서드 호출 후에도  str1의 내용은 수정되지 않는다.(원래값출력)
	System.out.println(str1.toUpperCase()); //대문자 변환된 내용 출력

    String str2=str1.toUpperCase();  //메소드의 처리 결과를 str2에 저장
    System.out.println(str2);          //대문자 변환된 내용 출력
  }    
}
Java Programming
JAVA PROGRAMMING
JAVA PROGRAMMING

 

위 예제의 부분1

	str1.toUpperCase();              // 대문자로 변환
   	System.out.println(str1);      //메서드 호출 후에도  str1의 내용은 수정되지 않는다.(원래값출력)

- 왜 위의 예제에서 str1.toUpperCase() 하면 str1의 값을 출력했을때 대문자로 변환되어 출력되지 않을까?
- String class는 값의 변화가 일어나면 변경된 값을 힙메모리상에 저장시킴
- 하지만 이 변경된 값을 재사용하지 못할때는 가비지 콜렉터가 변경이 되더라도 지워버림
- 즉 대문자로 변경이 되었지만 가비지콜렉터 기능때문에 재사용을 못하기 때문에 그 값을 지워버리고 처음 원래의 값(소문자)을 출력시킴

 

- Java Pro 에서 str1.toUpperCase() 를 쓰면 바뀐 내용(대문자) 를 힙메모리상에 새로 저장해줌
(그림 있음 2번번호)
- 하지만 접근하는방법이 없고, 재사용이 안되기 때문에 가비지 콜렉터가 지워버림
- 그래서 str1을 출력하면 원래값을 출력함
- 힙메모리상에서 값의 변화가 일어나면 매번 그걸 힙메모리상에 따로 새로 저장하기 때문이다

 

위 예제의 부분2

System.out.println(str1.toUpperCase());

 

- 한번 대문자로 출력한 후 참조하는 방법이 없으므로 없어짐(그림 3번 표시)
- 이 이후 str1을 출력시 다시 Java Programming으로 나옴

 

변경된 값 재사용
- str2처럼 이 바뀐 결과를 저장하는 새로 힙에 생긴 공간의 주솟값을 저장을 해야함(그림 4번 표시)

위 예제의 부분3

    String str2=str1.toUpperCase();  //메소드의 처리 결과를 str2에 저장
    System.out.println(str2);

- 이 str2가 새로바뀐 결과가 저장된 힙메모리의 공간을 받아서 주솟값을 저장해야만 재사용가능하고 str2를 통해 그 바뀐 결과를 출력 할 수 있다
- 즉 가리켜주는 객체 없으면 값이 사라짐 재사용되지 않는 힙메모리 값은 가비지콜렉터가 지움

 

그림

 

값이 변할때 메모리 처리
- String 객체를 생성한 후에 메소드에 의해서 값의 변화가 일어나면 변경된 값을 힙메모리 영역에 다시 저장 한다.

 

Garbage Collection 기능 (쓰레기 수집 기능)
- 재사용할 수 없는 힙메모리 영역의 데이터를 모아서 지워주는 기능
- 자동 메모리 관리 기능임
- 개발자가 메모리 관리 신경 크게 안써도 됨

+ StringBuffer 클래스
- 메모리상에 문자열 저장하는건 공통적이지만 String과 달리 새로운 공간에 저장하진 않는다

 

변경된 값을 재사용하기

String original = "Java Programming"
String lowerCase = original.toLowerCase(); //java programming
String upperCase = original.toUpperCase(); //JAVA PROGRAMMING

- String은 이렇게 변경된 값의 공간의 주소를 저장할 변수가 있어야 재사용 가능하다.

 

String 클래스 메소드

 

String클래스의 toUpperCase() 메소드
- 문자열을 대문자로 바꿔주는 메소드

String클래스의 toLowerCase() 메소드
- 문자열을 소문자로 바꿔주는 메소드

String클래스의 length() 메소드
- 한글이든 영문이든 몇글자인지를 구해준다.
- 한칸 비어있는 공백도 1글자로 인식함
- 문자열의 길이를 구해준다. 글자수를 구해줌

String클래스의 length() 메소드 예제

- FindBlankIndex.java

package p2022_07_01;

public class FindBlankIndex {
    public static void main( String[] args ) {
		
	String message = "Java program creates many objects.";
	
	// message의 길이를 구함.
	// length() : 문자열의 길이를 구해준다. 글자수를 구해줌
	int len = message.length();

	System.out.println(len);  // len = 34;

	// message 중에서 ' '을 찾음
	for( int i=0 ; i<len ; i++ ) {
	    char c = message.charAt( i );
		if( c == ' ' ) { //공백의 인덱스 번호를 구해서 출력
		    System.out.println( "index = " + i );
		}
	}//for end
    }
}

- 공백이나 . 까지도 한글자로 포함
- 반환형 int, 문자열의 길이를 리턴
-  for문으로 루프 돌려서 0부터 len보다 작을때까지 즉 len 만큼 for문을 돌림

 

length vs length() vs size()
- 배열의 크기를 구해주는 length 속성 -> 속성이므로 ()가 없다
- String 자료가 몇글자인지 구해주는 length() 메소드 -> 메소드이므로 ()
- 자료구조에 저장된 원소의 개수를 구해주는 size() 메소드 -> 메소드이므로 ()

String클래스의 중 charAt() 메소드
- 매개변수 int 이고 안에 인덱스 번호가 들어감
- 리턴형은 char임 즉 인덱스를 받아서 거기에 해당하는 문자를 가져옴.
- 인덱스는 0번부터 시작

그림

String클래스의 중 charAt() 메소드 예제

package p2022_07_01;

public class FindBlankIndex {
	public static void main(String[] args) {

		String message = "Java program creates many objects.";

		// message의 길이를 구함.
		// length() : 문자열의 길이를 구해준다. 글자수를 구해줌
		int len = message.length();

		System.out.println(len); // len = 34;

		// message 중에서 ' '을 찾음
		for (int i = 0; i < len; i++) {
			char c = message.charAt(i);
			if (c == ' ') { // 공백의 인덱스 번호를 구해서 출력
				System.out.println("index = " + i);
			}
		} // for end
	}
}
34
index = 4
index = 12
index = 20
index = 25

- ' ' 즉 공백이 인덱스 몇변이 있는지 출력해줌 (공백을 찾아주는 코드)

 

String클래스의 indexOf() 메소드
- charAt과 반대기능의 메소드
- 특정 문자의 인덱스번호를 구해주는 메소드
- 찾고자하는 문자가 없을때는 -1을 리턴함
- API 문서에서 indexOf() 메소드 찾아보면 메소드 오버로딩 되어있다

String클래스의 indexOf() 메소드 예제1

	String message = "Java program creates many objects.";
	int index1 = message.indexOf( 'a' );

- 출력 : 1
- a란 문자의 index 번호를 구해와라
- a가 여러개 있을땐, 가장 먼저 나오는 a의 인덱스 번호를 구해라

 

String클래스의 indexOf() 메소드 예제2

	String message = "Java program creates many objects.";
	int index2 = message.indexOf( 97 );

- 출력 : 1
- 97은 10진수 아스키 코드값이므로 거기에 해당하는 영문자를 찾아줌
- 이 영문자를 찾아서 인덱스를 가져와줌
- 10진수 아스키코드(97) 에 해당되는 문자('a')의 인덱스 번호를 구함.
- 이 97을 65로 바꾸면? -> 'A'를 찾는데 찾고자하는 문자가 없으므로 -1을 리턴함

 

String클래스의 indexOf() 메소드 예제3(매개변수가 2개)

	String message = "Java program creates many objects.";

	//index번호 13번째 이후에서 'a'의 인덱스 번호를 구함
	int index3 = message.indexOf( 'a', 13 ); 
	System.out.println( index3 );

- index번호가 13번 이후에 가장 먼저나오는 'a' 의 인덱스 번호를 찾아라
- 즉 c(13) 부터 찾아라 그 'a' 는 16이 나옴
- 이렇게 위치가 지정될땐 그 이후의 문자를 찾고 위치 지정이 안되었을떈 아까의 예시처럼 가장 먼저나오는 문자의 인덱스값을 찾음

 

String클래스의 indexOf() 메소드 예제4(매개변수가 String)

	String message = "Java program creates many objects.";

	// 가장 먼저 나오는 'av'의 인덱스 번호를 구함
	int index4 = message.indexOf( "av" );
	System.out.println( index4 );

- 출력 : 1
- Java의 av 이므로 결과는 1
- 문자 한글자가 아니라 문자열이 들어가는 경우임
- 가장 먼저 나오는 av의 인덱스 번호를 구해라

 

String클래스의 indexOf() 메소드 예제5(매개변수가 2개)

	String message = "Java program creates many objects.";

	// index번호 12번 이후에 나오는 'man'의 인덱스 번호를 구함
	int index5 = message.indexOf( "man", 12 );
	System.out.println( index5 );

- 이렇게 위치가 지정될땐 그 이후의 문자열의 인덱스번호를 주고 위치 지정이 안되었을떈 아까의 예시처럼 가장 먼저나오는 문자의 인덱스값을 찾음

 

String클래스의 indexOf() 메소드 예제6(결과가 없는 경우)

	String message = "Java program creates many objects.";
	// 찾는 문자가 없는 경우에는 -1을 리턴한다.
	int index6 = message.indexOf( "java" );
	System.out.println( index6 );

- 출력 : -1
- 소문자 java가 없다 찾고자하는 결과없으면 -1 리턴한다
- 이 indexOf 메소드는 대소문자를 구분한다

 

String클래스의 trim() 메소드
- 문좌열 좌,우의 공백을 없애주는 역할

String클래스의 equals() 메소드
- boolean equals()
- 값을 비교하는 역할
- 가리키는 값들끼리 비교함

 

String클래스의 trim() 메소드 / equals() 메소드 예제

package p2022_07_01;

public class TrimTest {

    public static void main( String[] args ) {
    	
//    trim() : 문좌열 좌.우의 공백을 없애주는 역할
//    boolean equals() : 값을 비교하는 역할
	String str1 = new String( "gemini   " );
	String str2 = new String( "   gemini " );

	System.out.println( str1.equals( str2 ));
	System.out.println( str1.trim().equals( str2.trim()));
    }
}

- str1 가 가리키는 gemini 문자열 오른쪽에 공백이 있다
- str2 가 가리키는 gemini 문자열 왼쪽에 공백이있다
- 공백도 메모리상에 공간을 차지함

 

위 예제 부분1

	System.out.println( str1.equals( str2 )); //false

- 공백도 문자로 인식하므로 서로 다른 값으로 인식함.

 

위 예제 부분2

	System.out.println( str1.trim().equals( str2.trim()));

- 서로 같은값임. 
- str1.trim()은 str1이 가리키는 문자열 오른쪽 공백 없애줌(좌,우 모두)
- str2.trim()은 str2이 가리키는 문자열 왼 공백 없애줌(좌,우 모두)
- 둘다 gemini만 남게되고 값이 같으므로 true리턴

 

String클래스의 replace() 메소드
- 문자열에서 첫번째 매개변수 값을 두번째 매개변수 값으로 변환시켜줌
ex) replace("자바","JAVA") : "자바"를 "JAVA"로 치환

 

String클래스의 replace() 메소드 예제1
- ReplaceEx.java

package p2022_07_01;

public class ReplaceEx {

	public static void main(String[] args) {

	//p506
	//replace("자바","JAVA") : "자바"를 "JAVA"로 치환
		
		String oldStr = "자바는 객체지향 언어 입니다.";
		
		String newStr = oldStr.replace("자바", "JAVA");
		System.out.println(oldStr);
		System.out.println(newStr);
	}

}
자바는 객체지향 언어 입니다.
JAVA는 객체지향 언어 입니다.

 

String클래스의 replace() 메소드 예제2

 

		String oldStr = "자바는 객체지향 언어 입니다. 자바";
		
		String newStr = oldStr.replace("자바", "JAVA");
		System.out.println(oldStr);
		System.out.println(newStr);
자바는 객체지향 언어 입니다.
자바 JAVA는 객체지향 언어 입니다.JAVA

- "자바" 가 여러개 있어도 다 JAVA로 바꿈

 

+ String클래스는 메소드를 통해 값의 변화가 일어나면 매번 힙메모리상의 새로운공간에 바뀐값을저장함

 

String클래스의 substring() 메소드
- 일부 문자열만 추출
- 메소드 오버로딩되어있다
- 매개변수가 2개인 경우, 매개변수가 1개인 경우 추출하는 범위가 달라진다.

1. 매개변수 2개인경우
- 시작과 끝 인덱스를 지정한다
- 하지만 실제 우리가 추출하는건 하나 적게 추출함 즉 begInindex ~ endIndex-1까지 추출

2. 매개변수 1개인경우
- 시작 인덱스만 지정한다
- 시작 인덱스로부터 끝까지 추출하라는 의미

String클래스의 substring() 메소드 정리
- substring() : 전체 문자열에서 특정 범위의 문자를 추출하는 역할
- substring(n) : index번호 n번 부터 끝까지 추출
- substring(n1, n2) : index번호 n1번 부터 (n2-1)번 까지 추출

 

String클래스의 substring() 메소드 예제1(매개변수 1개)

	String message = "Java program creates many objects.";

	// 인덱스번호 13번 부터 끝까지 추출		
	String str1 = message.substring( 13 );
	System.out.println( str1 );
creates many objects.

- c가 13번 위치였다. 즉 13부터 모두 추출
- 13은 인덱스 번호 13번부터 끝까지 추출해서 결과를 str1 변수에 저장하고 출력시켜라는 의미

 

String클래스의 substring() 메소드 예제2(매개변수2개)

	String message = "Java program creates many objects.";

	// 인덱스번호 13번 부터 15번까지 추출
	String str2 = message.substring( 13, 16 );
	System.out.println( str2 );
cre

- c는 13, r은 14, e는 15 (15까지 추출)
- beginIndexNum이 13번 endIndexNum이 16인데 실제로는 13부터 15번까지 추출함

 

- 여기서 str1과 str2는 변경된 문자열을 가리킴(저장)
- 자바는 substring 메소드만 제공함

 

String클래스의 substring() 메소드 예제3
- SubstringEx.java
- substring() 이용해서 한글자 추출하기
- substring(그 글자 인덱스, 그 다음글자 인덱스)
+ string값 비교에 == 쓰지말고 equals쓰기

package p2022_07_01;

public class SubstringEx {

	public static void main(String[] args) {

//아래와 같이 주민번호가 있을때, 남자인지 여자인지 판별하는 프로그램을 작성하세요?

		String jumin = "900101-2233456"; // 2000년 이후 남자는 3번, 여자는 4번
		String gender = jumin.substring(7, 8);

		if (gender.equals("1") || gender.equals("3")) {
			System.out.println("남자");
		} else if (gender.equals("2") || gender.equals("4")) {
			System.out.println("여자");
		}
	}

}

- 문자끼리 비교하는거니 gender.equals("1") 라고 "1"이라고 문자를 넣어야지 숫자 1을 넣으면 안됨!
-  if-else로 해도 되지만 주민번호 첫자리 수 5(귀화한분들) 이런 경우도 있으므로 안전상 if-elseif로 해야한다

 

위 예제 부분1

		String gender = jumin.substring(7, 8);

- 이렇게 해야 7번 인덱스의 문자열을 가져옴

 

String클래스의 substring() 메소드 예제4

- 키보드로 주민번호를 입력받는다, 주민번호 문자로 받아야함(문자열 클래스로 이것저것 할 것 이므로)
- 앞자리 6자리가아니면 메세지 뿌림
- 뒷자리 7자리가아니면 메세지 뿌림 
- 이런걸 유효성 검사라고 한다
- 그리고 이 모든게 완벽한 값이면 입력한 주민번호가 남자인지 여자인지도 판별

package p2022_07_01;

import java.util.Scanner;

public class JuminCheck {

	public static void main(String[] args) {
// 키보드로 주민번호를 입력 받아서 남자인지 여자인지를 판별하는 프로그램을 작성하세요?
// 단, 주민번호 앞자리는 6자리, 뒷자리는 7자리 인지를 유효성 검사를 한다.

		// 키보드로 주민번호 입력받기
		Scanner sc = new Scanner(System.in);
		System.out.println("주민번호 앞자리를 입력 하세요?");
		String jumin1 = sc.nextLine();

		System.out.println("주민번호 뒷자리를 입력 하세요?");
		String jumin2 = sc.nextLine();

		// 남녀
		String g = jumin2.substring(0, 1); // 0번 인덱스 추출한다는 의미

		// 유효성 검사 & gender
		if (jumin1.length() != 6) {
			System.out.println("주민번호 앞자리 6자리를 입력하세요.");
		} else if (jumin2.length() != 7) {
			System.out.println("주민번호 뒷자리 7자리를 입력하세요.");
		} else if (g.equals("1") || g.equals("3")) {
			System.out.println("남자");
		} else if (g.equals("2") || g.equals("4")) {
			System.out.println("여자");
		} else {
			System.out.println("똑바로 입력 하세요.");
		}

	}
}

- if-elseif-else문 처리기때문에 처음 주민번호 앞자리 6자리가 아니면 더이상 아래쪽을 실행안함.
- 주민번호 앞자리 6자리인데 뒷자리 7자리 아니면 두번째에 걸림 아래 실행 안함
- 둘다 개수가 맞으면 이제야 남/녀 검사를함
- 주민번호는 6,7 다 맞는데 뒷자리 첫번째가 1234가 아니면 마지막인 else 구문에서 걸린다

 

+ String클래스의 split() 메소드
- 이후 뒤에서 자세히 설명함(StringTokenizer 클래스 공부 이후)
- 전체 문자에서 구분기호를 가지고 문자를 추출할때 사용함
- @ 나 / 등의 정규 표현식을 구분자로 해서 문자를 자름 이걸 파싱이라고함
- 결과를 돌려주는 자료형은 String형 1차원 배열로 돌려줌

 

+ Strping클래스의 split() 메소드는 은 StringTokenizer 와 비슷한 역할을 하지만 더 쓰기 편하다

+ String클래스의 split() 메소드 오버라이딩
- split(String regex)
- split(String regex, int limit)

 

String 클래스와 메모리 정리
- String 클래스는 메소드에서 값의 변화가 일어나면 변경된 값을 힙 메모리에 매번 새로운공간을 만들어서 사용함
- 재사용은 값을 받아주는 변수가 있을때만 사용가능하고 변경된정보에 접근이 불가능하면 가비지 콜렉터가 지움

사용빈도
String >>> StringTokenizer >>>>> StringBuffer 

 

String, StringTokenzier, StringBuffer

- 공통적 특징 : 힙메모리상에 문자를 저장함
- 하지만 메모리상에 데이터를 처리하는부분이 다름 (메모리상에 문자를 저장하는 방식이 다름)
- String : 메소드에서 값의 변화가 일어나면 변경된 값을 힙 메모리에 매번 새로운공간을 만들어서 사용함
- StringBuffer : 버퍼라는 기억장소를 쓰기때문에 값의 변화가 일어나더라도 새로운 공간에 값을 저장하지 않음. 시작 주소값이 바뀌지 않음. 값을 계속 누적하는 경우에 이 클래스 쓰는 경우가 있다

 

StringBuffer
- 사용빈도 낮음
- StringBuilder 와 비슷한 기능(이건 안함)
- StringBuffer도 java.lang에 있어서 import 안해도 됨
- Buffer라는 임시 기억공간에 문자열을 저장함, 기능적으로 String과 다르다

 

StringBuffer 생성자
- 매개변수가 int capacity로 된 생상자가 있다, 버퍼라는 임시기억장소의 크기를 생성하는 거임
- 크기를 지정하면 지정된크기로 만들어줌, 크기 설정 따로 안해도 버퍼라는 임시기억소 만듬
- 설정안하면 기본적으로 16characther임 16글자 저장하기위한 힙메모리상의 공간을 만들어줌

 

StringBuffer 예제
- StringBufferTest.java

package p2022_07_01;

public class StringBufferTest {
	public static void main(String[] args) {

		StringBuffer sb1 = new StringBuffer("gemini");
		System.out.println("sb1.length() : " + sb1.length());	//6
		System.out.println("sb1.capacity() : " + sb1.capacity());	//22

		sb1.append("A string buffer implements" + "a mutable sequence of characters");
		System.out.println("sb1.length() : " + sb1.length());	//64
		System.out.println("sb1.capacity() : " + sb1.capacity());	//64

		StringBuffer sb2 = new StringBuffer();
		System.out.println("sb2.length() : " + sb2.length());	//0
		System.out.println("sb2.capacity() : " + sb2.capacity());	//16
	}
}

 

위 예제 부분1(매개변수가 있는 생성자)

		StringBuffer sb1 = new StringBuffer("gemini");

- 매개변수가 있는 생성자로 객체를 생성하고 있다
- "gemini"가 힙메모리 상에 저장되고, sb1이 이 주소를 갖고 있다.

 

- length()메소드 지원 : 문자열길이를 구해줌
- capacity() 메소드 : 힙메모리상의 할당된 바이트 크기 알려줌 //22바이트
- append() 메소드 : 문자열을 추가함

 

- 동적으로 공간을 늘려주는 기능도 있다 자동으로 늘려줌
- 만약 22보다 큰 크기의 문자열을 넣으면 동적으로 공간을 늘려줌
- 다시 length()를 구했을때 64가 나옴
- 처음에 22바이트였던 공간을 64만큼 늘려줌

 

위 예제 부분2(기본생성자)

		StringBuffer sb2 = new StringBuffer();

- 기본생성자로 객체를 생성하고 있다
- 길이 length 는 0임
- 자동으로 16바이트(16글자공간 만들어줌) 로 만들어줌
- 아무것도 안가리키기 때문에 length()는 0

 

StringBuffer와 값의 변화
- StringBuffer는 값의 변화가 일어나더라도 시작주소값이 바뀌지 않는다
- String과 다른 특징

 

StringBuffer와 값의 변화 예제
- AppendStringBuffer.java

package p2022_07_01;

public class AppendStringBuffer {
    public static void main( String[] args ) {
		
	// StringBuffer 객체 생성
	StringBuffer sb1 = new StringBuffer( "gemini" );
	System.out.println( "sb1 = " + sb1 );

	// StringBuffer sb1에 문자열을 추가해 새로운 객체 생성
	StringBuffer sb2 = sb1.append( " is beautiful" );
	System.out.println( "sb2 = " + sb2 );
	System.out.println( "sb1 = " + sb1 );

	if(sb1 == sb2) {
		System.out.println("같은 주소"); //같은 주소
	}else {
		System.out.println("다른 주소");
	}

	// 정수형 데이타 형을 추가
	System.out.println( sb1.append( 1004 ));
	System.out.println( "sb1 = " + sb1 );
	System.out.println( "sb2 = " + sb2 );

	String str = new String(sb1); // StringBuffer를 String으로 변환
	System.out.println(str.toUpperCase());
    }
}
sb1 = gemini
sb2 = gemini is beautiful
sb1 = gemini is beautiful
같은 주소
gemini is beautiful1004
sb1 = gemini is beautiful1004
sb2 = gemini is beautiful1004
GEMINI IS BEAUTIFUL1004

 

위 예제 부분1

	// StringBuffer 객체 생성
	StringBuffer sb1 = new StringBuffer( "gemini" );
	System.out.println( "sb1 = " + sb1 );

- 힙메모리상에 "gemini"라는 값이 저장되고 그걸 sb1이 시작주소를 가지고 있다

 

위 예제 부분2

	// StringBuffer sb1에 문자열을 추가해 새로운 객체 생성
	StringBuffer sb2 = sb1.append( " is beautiful" );
	System.out.println( "sb2 = " + sb2 );
	System.out.println( "sb1 = " + sb1 );

- append() 함수 : 기존 문자열에 새로운 문자열을 이어 붙여줌 (String클래스엔 이 함수 지원안됨)
- 그리고 이걸 sb2가 주소를 가지게 함

 

위 예제 부분3

	if(sb1 == sb2) {
		System.out.println("같은 주소"); //같은 주소
	}else {
		System.out.println("다른 주소");
	}

- 출력 : 같은 주소
- 문자열이 변경되었지만 새로운 힙공간에 저장하지 않음 그러니 sb1과 sb2가 가리키는건 같음!
- 둘다 같은 문자열이 출력됨
- 즉 같은 주소, 같은 값 같은걸 가리키고 있음

그림

 

String vs StringBuffer 차이 정리
- String : 값의 변화 일어나면 새로운 공간에 그 결과 저장. 원래 값의 주솟값 != 바뀐 값의 주솟값
- StringBuffer : 값의 변화 일어나도 기존 공간에 적용, 변경된 값의 시작주솟값이 바뀌지 않음

 

위 예제 부분4

	// 정수형 데이타 형을 추가
	System.out.println( sb1.append( 1004 ));
	System.out.println( "sb1 = " + sb1 );
	System.out.println( "sb2 = " + sb2 );

	String str = new String(sb1); // StringBuffer를 String으로 변환
	System.out.println(str.toUpperCase());

- sb1에 append(1004) 함 
- 그 후에 sb1출력하나 sb2 출력하나 같은 gemini is beautiful1004 가 출력됨
- 같은주소를 리턴받았었기때문에 그렇다

 

StringBuffer로 저장된 문자열을 대문자로 바꾸기
- StringBuffer 클래스는 toUperCase() 메소드가 없어서 못쓴다 (langth()는 있음)
- String과 StringBuffer 사이는 상속관계 없으므로 String 클래스 안에 있는걸 StringBuffer가 상속받아 쓸수도 없음

 

-> String 클래스의 생성자를 활용해서 대문자로 바꿔주면 된다.
-> String 클래스 생성자를 찾아보면 매개변수가 StringBuffer인 생성자가 있다
- String(StringBuffer buffer) 생성자
- 이 생성자를 통해서 StringBuffer -> String 으로 변환 가능
- String 객체로 받아서 toUpperCase 해서 대문자 변환하기

 

StringBuffer로 저장된 문자열을 대문자로 바꾸기 예제
- InsertStringBuffer.java
- StringBuffer 클래스의 append() 메소드 : 기존 문자열에 끝 추가
- StringBuffer 클래스의 insert() 메소드 : 지정된 특정 위치에 문자열을 삽입 시킴

package p2022_07_01;

public class InsertStringBuffer {
	public static void main(String[] args) {

		StringBuffer sb1 = new StringBuffer("gemini is beautiful");
		System.out.println(sb1);

		// 인덱스 10번 위치에 very 문자를 삽입
		sb1.insert(10, "very");
		System.out.println(sb1);

		// 인덱스 0번 위치에 1004 를 삽입하라(숫자로 써도 문자가됨)
		sb1.insert(0, 1004);
		System.out.println(sb1);
	}
}
gemini is beautiful
gemini is verybeautiful
1004gemini is verybeautiful

- 처음엔 인덱스 10번위치에 "very"란 문자열을 삽입시켜라는 의미
- is beautiful 사이의 공백이 인덱스 10이다. 그 10번 뒤에 삽입 됨-> is verybeautiful
- 이후 인덱스 0번위치에 1004를 삽입하라는 의미

 

StringBuffer 클래스의 사용
- 문자열 처리 보통은 String 클래스로 다 처리가능함
- 값을 계속 누적시키거나 하는 특별한 경우들에만 StringBuffer를 사용함

 

+ 문자열 분리 방법 2가지
- 구분기호를 가지고 문자를 추출하는, 잘라서 토큰으로 추출하는 역할
1. java.util.StringTokenizer이용
2. String의 split() 메소드 활용

 

StringTokenizer 클래스
- 앞의 두 클래스와 기능이 좀 다름
- 특정 문자를 구분기호를 가지고 토큰을 구해오는 역할을 함
- 문자를 파싱해서 처리해주는 역할을 한다
- java.util 안에 있다

 

StringTokenizer 클래스 생성자
- 매개변수 1,2,3개인 3개의 생성자 중 StringTokenizer(String str, String delim) 을 주로 사용한다
- 첫번째 매개변수에는 전체 문자열 또는 그 문자열을 담은 변수명이 온다
- 두번째 매개변수에는 구분기호가들어간다, 구분기호는 @ # / 등이 될 수 있다.

 

StringTokenizer 클래스 예제1
- StringTest04.java

package p2022_07_01;

import java.util.*;

class StringTest04 {

	public static void main(String[] args) {
		StringTokenizer str = new StringTokenizer("이순신#을지문덕#강감찬#광개토대왕", "#");

//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken()); // 예외발생

		// 파싱된 문자열이 모두 몇 개인지 되는지 알려줌
		int cnt = str.countTokens();
		System.out.println("파싱할 문자열의 총갯수-> " + cnt);

//		System.out.println(str.nextToken());
		while (str.hasMoreTokens()) { // 토큰이 있으면
			System.out.print(str.nextToken() + "\t");// 차례대로 파싱된 문자열을 얻어온다.
		}

	} // main() end

}

 

StringTokenizer 클래스 사용예시(위 예제 부분1)

StringTokenizer str = new StringTokenizer("이순신#을지문덕#강감찬#광개토대왕", "#");

 

- 이렇게 쓰고 두번째 자리에는 구분기호가 들어감
- 이 #으로 전체문자열을 파싱 = 자른다
- 파싱을 하고 리턴되는 "이순신" "을지문덕" 등을 토큰이라고함
- nextTokens() 메소드 : 이 토큰들을 구해오는 메소드

		System.out.println(str.nextToken());

- 하면 첫번쨰 토큰인 이순신 이 출력됨

		System.out.println(str.nextToken());
		System.out.println(str.nextToken());

- 이렇게 더 하면 이순신, 을지문덕  출력됨
- nextToken()메소드는 String형으로 리턴한다

		StringTokenizer str = new StringTokenizer("이순신#을지문덕#강감찬#광개토대왕", "#");

		System.out.println(str.nextToken());
		System.out.println(str.nextToken());
		System.out.println(str.nextToken());
		System.out.println(str.nextToken());
이순신
을지문덕
강감찬
광개토대왕

- 가져올토큰 없는데 한번 더 nextToken() 메소드를 쓰면? 
- 예외가 발생해서 프로그램이 비정상적으로 멈추게됨

Exception in thread "main" java.util.NoSuchElementException
                 at java.util.StringTokenizer.nextToken(Unknown Source)
          at p2022_07_01.StringTest04.main(StringTest04.java:14)

- NoSuchElementException 예외 발생
* 예외 : 예상하지못했던 프로그램상 오류
-> 가져올 토큰이 있는지 없는지 판별을 해야함

 

가져올 토큰이 있는지 판별(위 예제 부분2)
- 가져올 토큰이있는경우에만 출력하기

		// 파싱된 문자열이 모두 몇 개인지 되는지 알려줌
		int cnt = str.countTokens();
		System.out.println("파싱할 문자열의 총갯수-> " + cnt); //4출력

- 토큰들 : 잘려진 부분들
- countTokens() 메소드 : 토큰의 개수를 구해주는 메소드
- 토큰이있을때만 가져오기위해서 처리하기 아래에

		while (str.hasMoreTokens()) { // 토큰이 있으면
			System.out.print(str.nextToken() + "\t");// 차례대로 파싱된 문자열을 얻어온다.
		}
이순신 을지문덕 강감찬 광개토대왕

- hasMoreTokens() 메소드 : 가져올 토큰이 있는지 없는지 판별하는 역할을 함
- 결과를 돌려주는 리턴자료형은 boolean, 가져올 토큰 있으면 true,없으면 false 리턴해서 while문 제어
-> 이러면 예외가 발생할 가능성이 없다

 

nextTokens()의 특징(위 예제 부분3)

		System.out.println(str.nextToken());
		while (str.hasMoreTokens()) { // 토큰이 있으면
			System.out.print(str.nextToken() + "\t");// 차례대로 파싱된 문자열을 얻어온다.
		}

- 이순신을 위에서 부르고 while문 에서는 을지문덕 감감찬 광개토대왕 만 나옴
- 한번 nextToken()쓰면 그건 끝난것, 그 뒤부터 출력됨

 

+ String 클래스의 split() 메소드가 이와 비슷한 역할을 한다.

 

StringTokenizer 클래스 예제2
- StringTokenizerTest1.java

package p2022_07_01;

import java.util.StringTokenizer;

public class StringTokenizerTest1 {

	public static void main(String[] args) {
	
		String source1="111-111|강원도|춘천시|퇴계동";
		StringTokenizer st1=new StringTokenizer(source1,"|");
		
		String zip=st1.nextToken();
		String dou=st1.nextToken();
		String si=st1.nextToken();
		String dong=st1.nextToken();

		System.out.println("우편번호:" +zip);
		System.out.println("도:" +dou);
		System.out.println("시:" +si);
		System.out.println("동:" +dong);
	}

}
우편번호:111-111
도:강원도
시:춘천시
동:퇴계동

- String 객체 source1에 문자열들이 있다
- - StringTokenzier 는 구분기호를 1개밖에 쓰지 못한다!
- "-" 같은거까지 더 구분 못함
- split()은 여러개 구분기호로 파싱 가능
- nextToken() 의 리턴형은 String
- nextToken() 으로 토큰 구해와서 String 객체에 저장했다.

 

StringTokenizer 클래스 예제3(매개변수가 3개)
- StringTokenizerTest2.java

package p2022_07_01;

import java.util.StringTokenizer;

public class StringTokenizerTest2 {

	public static void main(String[] args) {

		String source1 = "한국 미국 태국 중국 이란";
		StringTokenizer st1 = new StringTokenizer(source1, " ");
		while (st1.hasMoreTokens()) {
			System.out.println("st1.token:" + st1.nextToken());
		}

		System.out.println();
		System.out.println();

		String source2 = "푸들,삽살개,풍산개,진돗개";
		StringTokenizer st2 = new StringTokenizer(source2, ",");
		while (st2.hasMoreTokens()) {
			System.out.println("st2.token:" + st2.nextToken());
		}

		System.out.println();
		System.out.println();

		// true : 구분기후(,)를 토큰으로 처리해준다.
		StringTokenizer st3 = new StringTokenizer(source2, ",", true);
		while (st3.hasMoreTokens()) {
			System.out.println("st3.token:" + st3.nextToken());
		}

	}

}

 

위 예제 부분1

		String source1="한국 미국 태국 중국 이란";
		StringTokenizer st1=new StringTokenizer(source1," ");

- 국가명 사이에 공백이 들어가있으니 공백으로 파싱하자
- 첫번째 매개변수에는 문자열 또는 문자열이 저장된 변수가 들어간다
- 두번쨰 매개변수에는 구분기호가 들어가는데 여기선 " " 공백으로 파싱

 

위 예제 부분2

		while(st1.hasMoreTokens()){
			System.out.println("st1.token:"+st1.nextToken());
		}

- hasMoreTokens() : 가져올 토큰이 있는지 판별
- while문 안에 가져올 토큰이있을때만 true를 리턴해서 while문 돌려서 모두 출력함
- 가져올 토큰이 없으면 false리턴

 

위 예제 부분3

		String source2="푸들,삽살개,풍산개,진돗개";
		StringTokenizer st2=new StringTokenizer(source2,",");
		while(st2.hasMoreTokens()){
			System.out.println("st2.token:"+st2.nextToken());
		}

 

매개변수 3개인 StringTokenizer(위 예제 부분4)

		//true : 구분기후(,)를 토큰으로 처리해준다.
		StringTokenizer st3=new StringTokenizer(source2,",",true);
		while(st3.hasMoreTokens()){
			System.out.println("st3.token:"+st3.nextToken());
		}
st3.token:푸들
st3.token:,
st3.token:삽살개
st3.token:,
st3.token:풍산개
st3.token:,
st3.token:진돗개

- 첫번째, 두번쨰 매개변수에 넣어야하는건 위와 같다 
- 하지만 3번째 매개변수가 boolean형이다 즉 true나 false값을 써야함
- 세번째 매개변수에 true가 오면, 그 구분기호도 파싱될 토큰으로 처리하라는 의미
- 그래서 여기는 , 도 토큰기호로 인식해서 nextToken()하면 푸들 다음의 토큰으로 , 라는 토큰이옴
- false넣으면 다른 위의 예제들과 같게 구분기호는 토큰으로 인식 안함. 

 

String클래스의 split() 메소드
- StringTokenzier과 비슷한 역할하는 "메소드"
- 기능적으로 보면 split()이 쓰기가 더 편하고 여러개의 구분기호 가지고 있어도 파싱 가능함

- String[] Split(String regex)
- 이 매개변수에 구분기호가 온다
- 이 파싱된 결과를 왼쪽의 String 1차열 배열로 리턴
- 첫번째 토큰은 0번방, 두번째 토큰은 1번방, 세번째 토큰은 2번방...

 

String클래스의 split() 메소드 예시1

- 주민번호앞자리-주민번호뒷자리 를 - 로 파싱하자

		String jumin = "900101-1234567";
		String[] j = jumin.split("-");

- 구분기호를가지고 잘라서 결과를 왼쪽의 j (String형 배열) 로 전달
- "900101"인 첫번째 토큰이 j[0], "1234567" 인 두번째 토큰은 j[1]로 들어감

 

String클래스의 split() 메소드 예제1
- SplitEx.java

package p2022_07_01;

public class SplitEx {

	public static void main(String[] args) {

// String[] split(String regex) 메소드
		
		String jumin = "900101-1234567";
		String[] j = jumin.split("-");
		
		System.out.println("주민번호 앞자리 : " + j[0]);
		System.out.println("주민번호 앞자리 : " + j[1]);
		
		for (int i = 0; i < j.length; i++) { //향상된for문
			System.out.println("주민번호 " + j[i]);
		}

	}

}
주민번호 앞자리 900101
주민번호 뒷자리 1234567
주민번호 900101
주민번호 1234567
900101
1234567

+ 나중에 배열의 크기를 잘 모르는 경우에 length속성을 꼭 써야한다

 

String클래스의 split() 메소드 예제2

		String tel = "010-1234-5678";
		String[] t = tel.split("-");
		
		for (int i = 0; i < t.length; i++) {
			System.out.println(t[i]);
		}
010
1234
5678

 

String클래스의 split() 메소드 예제3

		// @를 구분기호로 아이디명과 도메인명 파싱하기
		String email = "totoro@naver.com"; //정해진 형식이 있다.
		String[] e = email.split("@");
		
		System.out.println("아이디 : " + e[0]);
		System.out.println("도메인 : " + e[1]);
아이디 : totoro
도메인 : naver.com

 

구분기호 여러개로 파싱하기(split() 메소드 예제4)

- 구분기호 여러개 섞여있어도 파싱하는게 가능하다

		String[] names = text.split("$|,|-");

- 구분기호를 연결해서서 | (파이퍼) 로 연결하면 또는 이런 구분기호들을 이용해 파싱하겠다는 의미
- 이런건 StringTokenizer 가 지원하지 못하는 기능임

 

- SplitEx1.java

package p2022_07_01;

public class SplitEx1 {

	public static void main(String[] args) {
// p512
//		String[] split(String regex); 메소드
		
		String text = "홍길동&이수홍,박연수,김자바-최명호";
		
		String[] names = text.split("&|,|-");
		
//		for (int i = 0; i < names.length; i++) {
//			System.out.println(names[i]);
//		}
//		System.out.println();
		
		for(String name : names) {
			System.out.println(name);
		} //향상된for문
		
	}

}
홍길동
이수홍
박연수
김자바
최명호

+ | 는 구분기호로 쑬 수 없다

 

문자열 파싱하는 방법 정리
1. StringTokenizer 클래스
2. String의 split() 메소드

복습

변수
1. 지역변수
2. 멤버변수
3. 정적 멤버변수 (= 정적필드, 나중에 공부)

객체모델링
속성 -> 필드
동작 -> 메소드

- 클래스(설계도) -> 객체
- 대부분의 클래스는 객체 생성시 new연산자 사용

필드
- 메소드 바깥쪽에 정의되는 변수
- 힙메모리에 저장되고 자동초기화된다.
- 할당시점 : new연산자로 객체 생성시 힙메모리상에 할당

생성자
- 클래스명과 동일, 앞에는 접근제어자만옴, 필드값을 초기화 시키는 역할

메소드
- 객체의 동적인 것 표현

기본자료형인 필드
- 객체생성시 힙메모리할당되며
- 자동으로 초기화
정수형 : 0
실수형 : 0.0
논리형 : false

참조형인 필드
- null , 참조하는 주소가 없다.

생성자 호출
- 생성자 매개변수에 맞는값 넣어서 생성

생성자 오버로딩
- 한개 클래스 안에 동일한 이름으로 만든 여러 생성자

this
this. : 필드 생성자 메서드 안에서 멤버변수와 매개변수 이름이 같을때사용
this() : 같은 클래스내의 생성자 호출하라는 의미

과제풀이(Lotto.java) 설명
https://laker99.tistory.com/17

- 새로 발생된 난수값과 이전의 난수값들을 비교하기 위해 중첩 for문 사용
- i-- 한 뒤 괜히 더 돌아가는걸 막기위해 break 해주는게 좋다 
- 하나 중복을 발견하면 다음꺼부터는 중복일리가 없다, 이전에 이미 다 처리되었기 때문에
- 오름차순 적용

1. num[0] = 5, num[1] = 5 일때, 안의 for문이 돌아가면서  num[0] 과 num[1]을 비교해서 같으므로 i--시킴
2. 그럼 i=0이 되고 break 되어 나옴 이해 바깥 for문에 의해 ++ 되며 i=1 이 됨
3. 다시 num[1]값을 랜덤으로 받는것

오름차순하기
- 정렬알고리즘 통해서 (버블정렬 = 자신의 옆자리에 있는 것과 비교)
- Arrays 클래스의 sort()함수이용해서 num 배열이름 넘겨주면 오름차순 정렬해줌(java.util.Arrays)

필드 = 멤버변수
- 메소드 바깥쪽에 정의됨
- 기본자료형은 초기화가 됨

파일 생성
- 메인메소드를 가진 클래스만 public class가 될 수 있다!
+ 생성자의 접근제어자 주로 public 이다.

클래스 실행하기
1. 클래스 안에 메인메소드 넣기(독립적실행가능)
2. 메인 메소드가 있는 클래스에서 실행시켜주기

 

필드로 직접 접근하기 예제

class Korean{
	//필드
	String nation = "대한민국";
	String name;
	String ssn; //전화번호
	
	public Korean(String name, String ssn) {
		this.name = name;
		this.ssn = ssn;
	}
	
	
}

public class KoreanEx {

	public static void main(String[] args) {

		Korean k1 = new Korean("박자바","011225-1234567");
		System.out.println("k1.name : " + k1.name);
		System.out.println("k1.ssn : " + k1.ssn);
		
		Korean k2 = new Korean("김자바","930525-0654321");
		System.out.println("k2.name : " + k2.name);
		System.out.println("k2.ssn : " + k2.ssn);
	}

}

- k1객체 만든 후 k1. 통해서 필드로 접근
- k2객체 만든 후 k2. 통해서 필드로 접근
- 필드 name, ssn을 private으로 바꾸게 되면 KoreanEx클래스에서  k1.name k2.ssn 해서 접근 불가(출력 불가)
다른 클래스라서, 다이렉트 접근을 막는다

 

필드값
- nation은 "대한민국"으로 초기화
- name과 ssn은 객체를 생성할때 생성자를 통해 전달된 값으로 각각 초기화됨

할당 시점
- new연산자로 힙메모리에 새로운 공간 생성할때 힙메모리상에 새로운 공간 할당받음(참조형은 다 마찬가지)
- 자료형이 String이라서(필드값) null로 자동초기화되지만 여기선 객체생성시 생성자호출시 받는 값으로 초기화 (name,ssn)
- 주소를가진 레퍼런스 변수 : k1, k2
- 필드들 nation, name, ssn 의 접근제어자가 default이므로 같은 패키지 내는 모두 접근 가능. 그래서 다른 클래스에서 k1.ssn 가능

 

그림


자바의 접근 제어자 정리

접근제어자   자신의클래스   같은패키지                하위클래스       다른패키지

private                    O                    X                                X                    X
생략(default)          O                    O                                X                    X
protected                O                   O                                O                    X
public                      O                   O                                O                   O

+ 같은 클래스 내 : 접근 제어자 의미 없다. 뭐든 접근 된다.
- private : 오직 같은 클래스에서만 됨 , 다른 클래스에서 접근하는걸 허용하지 않음, 가장 좁은 접근허용
- public : 가장 넓은 접근 허용함, 다른 패키지(폴더) 안의 클래스까지 접근가능
- default : 중간정도 접근 범위, 같은 패키지(폴더) 내에선 다 가능
- protected : 상속관련, 상속 배우고 난후 공부

접근제어자 범위 비교
가장넓음 public > default > protected > private 가장좁음

생성자 오버로딩
- 생성자 여러개 생성
- 구분되는 점이 있어야함

생성자 오버로딩 구분
1. 매개변수 자료형
2. 매개변수 개수
3. 매개변수 순서

메소드
- 언어에 따라 함수라고도 한다
- 쓰는 이유 : 객체의 동작 + 여러개 코드를 모아두고 한번 메소드가 정의되면 호출을 통해 재사용하기 위해서

메소드 만드는법
ex) public static void main(){}
1. 접근제어자 
2. static (특별한 경우에만 쓴다,공유 원할때)
3. 자료형 / void
4. 메소드이름 + ()

+ 자바에는 정적 클래스는 없다. 
+ 정적 메소드는 흔하지 않다.

 

접근제어자 예제

 

package p2022_06_29;

class Calculator {
	// 메소드
	void powerOn() {
		System.out.println("전원을 켭니다.");
		return;
	}

	int plus(int x, int y) { // 지역변수 : x, y, result
		int result = x + y;
		return result;
//		System.out.println("test");
	}
//return문 : plus() 메소드를 호출한 곳에 값을 돌려주는 역할
//return문은 메소드 가장 마지막 줄에 사용해야한다.
	double divide(int x, int y) {
		double result = x / (double) y;
		return result;
	}
	
	void powerOff() {
		System.out.println("전원을 끕니다.");
		return;
	}

}

public class CalculatorEx {
//p217 ~ 218
	public static void main(String[] args) {

		Calculator cal = new Calculator();
		cal.powerOn();
		
		int result1 = cal.plus(5, 6);
		
		byte x = 10;
		byte y = 4;
		double result2 = cal.divide(x,y);
		System.out.println("result2 : " + result2);
		
		cal.powerOff();
	}

}

- Calculator 클래스 앞에 private 쓰면 CalculatorEx 클래스에서 객체를 만들 수 없음(클래스 접근 불가)
- Calculator 클래스의 메소드 powerOff 앞에 private쓰면 cal.powerOn() 을 할 수 없음(메소드 접근 불가)

패키지 = 폴더
- 같은 폴더 안 = 같은 패키지 안
- 서로 다른 폴더 안 = 서로 다른 패키지 안 = public만 접근가능


위 예제의 부분1

	int plus(int x, int y) { // 지역변수 : x, y, result
		int result = x + y;
		return result;
		//System.out.println("test"); 오류남
        }

+ return문 : plus() 메소드를 호출한 곳에 값을 돌려주는 역할
+ return문은 메소드 가장 마지막 줄에 사용해야한다.
- 메소드가 실행되는동안 필요한 값들을 매개변수로 전달해줌(매개변수 = 지역변수)
- 메소드 실행되는동안만 스택에 값 존재, return되면 자동으로 지워짐
- 그래서 메모리 관리 크게 신경안써도 된다.

위 예제의 부분2

	cal.powerOn();

- 메인 메소드 안에서 객체 생성하며 생성자 호출후 메소드 호출
- 필드처럼 메소드에 접근할때도 객체.메소드() 로 호출함 (정적메소드가 아닌경우)

위 예제의 부분3

	int result1 = cal.plus(5, 6);


- Call by Value로 값 전달하며 메소드 호출
- plus()는 결과를 리턴자료형 int로 돌려줌 그래서 int result1으로 받아야하는것

위 예제의 부분4 (주의)

	double divide(int x, int y) {
		double result = x / (double) y;
		return result;
	}


- 리턴자료형이 double이므로 double형 값을 돌려준다
- int형인 x와 int형인 y를 산술연산시 int형으로 처리됨
ex) x = 10 , y = 4 이면 다 잘리고 2만 나온다. (손실 발생)
- 손실 발생을 막기 위해서 (double)을 붙여줘서 강제 형변환 -> 2.5
- 그걸 double로 return 시켜줌
- (double) 을 빠뜨리면 자동형변환되어서 2 -> 2.0 이 나옴(손실발생)
- 10/4 는 2.5이므로 살리려면 (double)해서 강제형변환시켜서 값이 double로 처리되도록 해야함.

위 예제의 부분5(CalculatorEx의 main 메소드 내부)

		byte x = 10;
		byte y = 4;
		double result2 = cal.divide(x,y);
		System.out.println("result2 : " + result2);


+ byte는 1바이트 정수형 자료형
- cal.divide에서 매개변수로 byte를 넘김 -> 근데 devide 메소드의 매개변수는 int 형 4바이트 이다. 
- 4바이트짜리 변수에 1바이트 짜리 값을 할당 => 컴파일러가 자동형변환시켜줌. 큰자료형으로 작은값으로 들어가므로
- 자동형변환되어서 위 코드 가능함

+ plus와 divide 메소드의 매개변수 이름들이 같지만 그 메소드 내에서만 사용되는 지역변수이므로 충돌이 발생하지 않음

메소드의 매개변수에 참조형이 오는 예제
- 값이 아닌 주솟값을 전달해야한다.
- sum1은 배열에 전달된 값들의 합을 돌려주는 함수

package p2022_06_29;

//p220 ~ 221
class Computer {
	// 주솟값 전달에 의한 메소드 호출(Call by Reference 방식)

	int sum1(int[] values) {
		int sum = 0;
		for (int i = 0; i < values.length; i++) {
			sum += values[i];
		}
		return sum;
	}

	// vargus : 전달된 값은 배열로 받음
	int sum2(int... values) {
		int sum = 0;
		for (int i = 0; i < values.length; i++) {
			sum += values[i];
		}
		return sum;
	}

}

public class ComputerEx {

	public static void main(String[] args) {

		Computer com = new Computer();
		
		int[] values1 = { 1, 2, 3 };
		int result1 = com.sum1(values1); // sum1() 메소드 호출 , 주솟값을 가진 values1을 넘김
		System.out.println("result1 : " + result1);

		int result2 = com.sum1(new int[] { 1, 2, 3, 4, 5 }); // sum1() 메소드 호출 , 배열을 만들어서 그 주소를 넘김
		System.out.println("result2 : " + result2);

		int result3 = com.sum2(1, 2, 3); // sum2() 메소드 호출 ,
		System.out.println("result3 : " + result3);

		int result4 = com.sum2(1, 2, 3, 4, 5); // sum2() 메소드 호출 ,
		System.out.println("result4 : " + result4);

	}

}

- "같은 int형 배열"의 주소값을 써서 메소드를 호출해야함
- Computer 클래스의 참조형변수인 int[] values는 아직 주솟값이 없는 상태 , new를 써서 int형 배열을 만들어 주솟값을 가진 걸 넘겨줘야함
- 그래서 main쪽에 int형 1차원배열을 만들어줌
- sum1에서 참조형이 매개변수로 왔으므로 같은 int형 배열의 주솟값을 넘겨야함
- new연산자를 아직 안썼으므로 아직 int[] values는 가리키는게 없음 
- 주솟값 전달에 의한 메소드 호출임
+ 값전달보다 주솟값 전달이 더 효율적이고 빠른 방식임

 

vargus (...)
- ...은 vargus 라고 함
- 전달된 값들은 1개일수도 여러개일수도 있지만 전달되는 값들은 모두 배열로 받음
- 매개변수가 있으면 매개변수의 개수대로 메소드 호출시 써줘야하지만 ... 은 int값을 1개 전달하든 여러개 전달하든 모두 배열로 처리됨

 

Call by Reference
- values1 int형 배열 힙메모리상에 4바이트 공간 3개 만들어지고 1,2,3이 들어가있고, 그 걸 values1이 그 스택에서 그 배열의 주소를 가지고 있음

 

	int result1 = com.sum1(values1)

- 에서 주솟값을 담고있는 values1을 전달 = 주소를 전달 = Call by Reference
- 주솟값이 없었던 Computer 클래스의 sum1의 values는 주솟값을 전달받아서 Computer 클래스의 values는 이제 이 {1,2,3} 배열을 가리키게됨
- 합을 구해서 리턴형 int로 result1에 값을 돌려줌

- 매개변수 중에서 참조형이 오는 경우 중 클래스/인터페이스가 가장 많다(배열은 많진 않다)
- API 제공 클래스 + 사용자 정의 클래스 => 이것들도 자료형이다
- 참조형변수는 주솟값을 가진다

 

매개변수에 주소값을 전달하는 법(위 예제 부분)

int[] values1 = { 1, 2, 3 };
int result1 = com.sum1(values1); // sum1() 메소드 호출 , 주솟값을 가진 values1을 넘김
System.out.println("result1 : " + result1);

int result2 = com.sum1(new int[] { 1, 2, 3, 4, 5 }); // sum1() 메소드 호출 , 배열을 만들어서 그 주소를 넘김
System.out.println("result2 : " + result2);

1.이렇게 values1 처럼 만들어진 배열공간의 주소값을 전달하는방법이 있다.
- values1이 가진 주솟값을 전달 


2.(new int[] { 1, 2, 3, 4, 5 } 처럼 오른쪽의 new연산을 써서 새로운 공간을 만들어서 그것의 주솟값을 넘겨줄 수도 있음
- 기억공간이 만들어지고 그거의 주솟값이 sum1 메소드의 매개변수로 넘어감
- 값을 받는 변수가 없기 때문에 이건 재사용이 안된다. 이후 가비지 콜렉터가 이 힙메모리상 배열을 지워버린다.
- 더이상 이 힙메모리에 접근할수없을때 해제된다.
- 할당시점은 new를 썼을때 할당된다

 

그림

 

+ 배열 생성

int[] score = {80,90,100} // new안쓰지만 힙메모리에 데이터 개수만큼 공간 만들어짐
int[] score = new int[]{80,90,100}

 

+ 배열등의 참조형을 매개변수로 쓰는이유
- 매개변수가 100개라면?
- 값들은 힙메모리에 저장시켜놓고 주솟값만 매개변수로 전달하는게 훨씬 효율적

 

vargus(위 예제 부분)

	// vargus : 전달된 값은 배열로 받음
	int sum2(int... values) {
		int sum = 0;
		for (int i = 0; i < values.length; i++) {
			sum += values[i];
		}
		return sum;
	}

- 메소드의 매개변수가 2개면 2개 전달 1개면 1개 전달 해야했었다.
- but vargus쓰면 1개 전달하든 2개전달하든 3개전달하든 모두 매개변수로 받을 수 있다
- 전달된 값은 모두 배열로 처리됨
ex) 첫번째 전달된값은 0번방 두번째 전달된 값은 1번방...
- 다만 자료형은 맞춰줘야함 int ... values 면 몇개이든 int형 값을 전달해야함

 

		int result3 = com.sum2(1, 2, 3); // sum2() 메소드 호출 ,
		System.out.println("result3 : " + result3);

- 1,2,3을 sum2로 전달하면 values가 1,2,3 을 배열로 저장함
- 전달된값들은 "같은 int형 배열"로 처리됨
- 자주쓰는 기능은 아님

 

		int result4 = com.sum2(1, 2, 3, 4, 5); // sum2() 메소드 호출 ,
		System.out.println("result4 : " + result4);

- 로 하면 1,2,3,4,5를 넘기고 배열로 받아서 처리해줌

 

메소드안에서 다른 메소드를 호출하기
- 여태껏은 메인메소드안에서만 메소드를 호출했었다
- 이젠 main 메소드가 아닌 일반 메소드안에서 다른 메소드를 호출해보자

 

package p2022_06_29;

// p227
// 클래스 내부에서 메소드 호출 : 메소드 안에서 다른 메소드 호출
class Calculator1 {
	int plus(int x, int y) {
		int result = x + y; //17
		return result;
	}

	double avg(int x, int y) {
		double sum = plus(x, y); // plus() 메소드 호출
		double result = sum / 2;
		return result;
	}

	void execute() {
		double result = avg(7, 10); //avg() 메소드 호출
		println("실행결과 : " + result); //println() 메세지 호출
	}

	void println(String message) {
		System.out.println(message);
		return;
	}
}

public class CalculatorEx1 {

	public static void main(String[] args) {

		Calculator1 mycal = new Calculator1();
		mycal.execute(); // execute() 메소드 호출
//		execute(); //오류발생
	}

}

1. 메인메소드에서 메소드 호출시
- 객체.메소드() 해서 메소드를 호출해야함

ex)

		Calculator1 mycal = new Calculator1();
		mycal.execute(); // execute() 메소드 호출
//		execute(); //오류발생

 

2. 일반메소드에서 메소드 호출시(같은 클래스 내부)
- 객체.메소드() 가 아니라 객체없이 그냥 메소드() 만으로 호출 가능하다!

ex)

		double result = avg(7, 10);

- avg() 메소드 호출 그냥 avg(7,10)만으로 호출했음

 

위 예제 흐름
- JVM이 main메소드 실행 -> mycal.execute() 호출함-> execute()이 실행됨
-> 그 메소드에서 avg메소드를 호출하면서 매개변수를 7, 10 넘겨줌
-> avg 매개변수의 x에 7, y에 10이 들어감, avg에서 다시 plus() 메소드를 7,10을 넘겨주며 호출
-> plus() 메소드에서 합을 구해서 합을 result 해서 plus()를 "호출"한곳에 값을 돌려줌 즉 avg로 돌아감
-> 그걸 avg의 sum이 받아서 %2 한뒤 돌려줌
- (주의) plus()가 돌려줄땐 int형인 17을 돌려줌, 근데 sum을 double로 받았으므로 17.0 해서 /2 해서 8.5가 result가 됨
-> 그 8.5 값을 avg를 호출한 execute()에 돌려줌, 그걸 println()메소드에 결과값을 넘겨서
-> println()이 출력시킴

+ 자바는 객체지향언어라서 호출할 메소드가 뒤에있어도 상관없다
+ execute() 아래 println() 있지만 execute()에서 println() 호출가능
+ 일반 메소드끼리는 메소드 이름만으로 서로를 호출한다

 

메소드 오버로딩(Method Overloading)
- 1개의 클래스 안에 동일한 이름을 가진 메소드를 여러개 정의하는 것.
- 생성자 오버로딩 처럼 메소드도 한개의 클래스 안에 동일한 이름의 클래스 여러개 정의할 수 있다

메소드 오버로딩 구분하는 법
1. 매개변수 자료형
2. 매개변수 개수
3. 매개변수들의 순서

- 한가지를 이상을 만족해서 구분이 되어야만 올바르게 메소드 오버로딩 시킨것임
* 나중에 메소드 오버라이딩과의 차이를 알아야 한다. 완전히 다른 개념
+ 메소드 오버라이딩 : 두 클래스 사이에 상속이 정의되어야만 사용가능

String 클래스 (API 문서)
- 필드 생성자 메소드 순
- 필드 : 메서드 바깥쪽에 정의되는 변수

- 생성자 : 클래스명과 동일, 형식상 괄호가 반드시 있다
- 매개변수가 없는 생성자는 기본생성자
- 나머지는 클래스명과 동일하게 생성자가 만들어지는데 구분이 되도록 정의됨
-> 생성자 오버로딩

- 메소드도 똑같은 이름을 가진 메소드들이 있다
ex) copyValueOf(char[] data) 와 copyValueOf(char[] data, int offset, int count)
- equlas 메소드, format 메소드들은 같은이름인 메소드가 여러개다 -> 메소드 오버로딩

 

메소드 오버로딩

class Calculator2{
	//정사각형의 면적을 구해주는 메소드
	double areaRectangle(double width) {
		return width * width;
	}
	//직사각형의 면적을 구해주는 메소드
	double areaRectangle(double width, double height) {
		return width * height;
	}
}

- 메소드가 같은 이름이다
- 매개변수가 1개인 areaRectangle 과 매개변수가 2개인 areaRectangle
- 매개변수의 개수가 다르므로 올바르게 메소드 오버로딩 되었음
- 매개변수 1개 전달하면 매개변수 1개인 areaRectangle() 이 호출되고 2개 전달하면 매개변수 2개인 areaRectanble()이 호출됨
- 메소드 오버로딩은 아무 언어나 되는게 아니라 객체지향언어만됨(c++,java는 되고 c는 안됨)

 

앞으로 공부할 내용

1. static이 붙은 정적 필드(정적변수)
2. static이 붙은 정적 메소드

변수
지역변수
멤버변수
정적변수
중에서 정적변수를 하는 것이다

3. 상수를 만드는 법 (Constant)
- final을 붙이거나 static final 을 붙인다
- 기존 변수에 final 붙이면 상수가 되는것
- final을 클래스, 필드, 메소드 에 붙일 수 있다-> 어디에 붙이냐에 따라 의미가 달라짐
4.접근제한자와 패키지 의 관계
5. getter와 setter 메소드

 

정적 필드 (정적 변수)

- static 이 붙은 변수 

ex)

static int a; // 그냥 변수앞에 static을 붙이면 정적변수가 됨

- static : 공유를 목적으로 해서 누구나 쉽게 접근하도록 만들때만 static 붙인 정적 필드형태로 만듬
- API 보면 클래스들 정적필드, 메소드들 정적메소드들 엄청 많다


ex) Math 클래스안엔 정적필드랑 정적메소드뿐
- 정적 필드는 클래스명.필드 로 사용
- 누구나 쉽게 생성할수있도록 따로 객체생성없이 클래스명.필드로 사용함

 

ex) 

int n = Integer.parseInt(String s);

- 에서 parseInt는 정적메소드라서 이렇게 클래스명.parseInt()로 사용함
- 세번째 변수인 정적멤버변수(정적 필드)
- 정적 필드 = 정적 멤버변수 = 정적 변수
- 메모리상에 할당되는 시점과 저장되는 영역이 (지역변수,멤버변수, 정적변수) 다 다르다(잠시 후 공부)

 

Math 클래스(정적 필드/메소드 예시)
- 내부에 정적 필드 뿐이다
- 정적필드 정적메소드 뿐
- 정적필드 E , PI 는 Math.E 로 접근가능
- 정적 메소드 , 정적 필드뿐이라 객체 생성할 필요가 없음
- math클래스는 생성자가 아무것도 없다 -> 생성자 자체를 못씀
- random() 메소드의 타입은 static double이다. 즉 정적메소드이고 리턴값이 double
- 정적 메소드 이므로 Math.random()으로 사용할수있다

 

정적변수의 메모리 할당 시점/장소
- 할당 시점 : 정적 멤버변수는 클래스가 메모리에 로딩되면(실행될때) 할당됨 
- 초기화 : 자동으로 설정되고 (정수형 0 실수형 0.0 논리형 false)
- 값 유지 : 프로그램이 종료될때까지 값을 유지한다
- 저장 영역 : 메모리의 static영역 (공유영역)에 자동으로 할당됨
- 저장 영역 : 공유영역 = 메소드영역 = static 영역 <->힙,스택과 다름
- 주의 : 장 오래 메모리에 상주하므로 많이쓰면 메모리가 부족해짐, 특별한경우아니면 만들지 않음

+ 특별한 경우, 반드시 정적멤버변수 만들어야하는 경우
- 싱글톤 : 객체생성을 1번만 하는 것, 이 경우엔 정적필드를 만들어야함

자동초기화
- 정적멤버변수는 자동초기화 된다.
- 배열과 마찬가지로 int는 0 , double 은 0.0, boolean은 false로 초기화 된다.
- 메소드영역에 값을 저장하고 한번 저장된값은 프로그램이 완전히 종료될때까지 값을 유지

정적 멤버변수에 접근하는 방법
- 정적 변수를 가지고 있는 클래스명으로 직접 접근 할 수 있다.

class StaticTest{
satic int a;

public static void main(String[] args) {
	System.out.println(StaticTest.a)
	}
}

- 정적메소드 사용시 클래스명.메소드()

 

정적 필드 / 정적 메소드 정리
- 정적 필드 = static이 붙은 변수
- 정적 메소드 = static이 붙은 메소드
- static이 붙은 필드를 가진 클래스가 로딩이 되면 이 정적필드는 메소드 영역에 저장이되고
자료형에 따라 기본자료형 변수들은 자동초기화됨

 

정적 멤버변수 만드는 법

- static 붙이기
- 예제 : NoneObject.java/UseNoneObject.java / UseNoneObject.java에만 메인메소드 있음

package p2022_06_29;

public class NoneObject {
    static int number = 3; // 정적 필드
    
    public static void printNumber() { // 정적 메소드
        System.out.println("number = " + number);
    }
}

- 메인메소드없으므로 독립적 실행은 안됨,
- 정적필드하나 정적메소드 하나 있는 NoneObject 클래스
- 이 클래스의 필드에 접근하고 메소드를 호출해보자

package p2022_06_29;

public class UseNoneObject {

    public static void main( String[] args ) {
    
//이 방식 잘 안쓴다
    NoneObject no = new NoneObject();
    System.out.println("no.number = " + no.number);
    no.printNumber();
    
//아래방식을 주로 쓴다
    System.out.println("NoneObject.number = " + 
					NoneObject.number);
    NoneObject.printNumber();
    
    }
}
출력
no.number = 3
number = 3
NoneObject.number = 3
number = 3

- NoneObject 클래스는 정적필드와 정적메소드를 가지고 있다
- UseNoneObject 클래스에서 접근할때 객체를 생성한 후 필드와 메소드를 사용할 수도 있지만
- 정적 필드와 정적메소드이므로 이렇게 안쓴다 (가능은 하지만 안쓴다)
- 필드 접근/메소드 호출하는 법 : NoneObject 클래스에서 .을 찍어서 정적필드, 정적메소드 로 접근

 

정적 필드 / 정적 메소드 접근 정리
- 누구나 쓸수있도록 하려고 static 붙인거임-> 객체생성해서 접근하지 않는다
- 결론 : 정적필드 , 정적메소드는 클래스명.필드, 클래스명.메소드() 해서 접근해라

정적 필드의 자동초기화
- 예제 : NoneObject.java 파일

package p2022_06_29;

public class NoneObject {
    static int number = 3; // 정적 필드
    
    public static void printNumber() { // 정적 메소드
        System.out.println("number = " + number);
    }
}

- 에서 static int number 에 3 초기화 안시킨다면?
- 자동으로 0으로 초기화시켜주므로 UseNoneObject 에서 실행해보면 0으로 출력됨

정적 멤버변수의 메모리 할당/해제(위 예제)
- NoneObject클래스가 로딩되자마자 number는 공유영역에 저장되면서 int형이니 0으로 초기화됨
- number의 값은 프로그램 종료시까지 계속 메모리에 상주함
- static 정적 필드 많이쓰면 메모리 부족

객체를 생성해서 정적필드/정적메소드에 접근(위 예제 부분)

//이 방식 잘 안쓴다
    NoneObject no = new NoneObject();
    System.out.println("no.number = " + no.number);
    no.printNumber();

- 가능은 하다
Q. 그럼 이때 new를 쓰면 정적필드는 어디로 저장될까? (질문하기) -> 그래도 메소드 영역

 

메모리 정리
- 힙 메모리에 저장 : JVM 시작할때 생성, 객체와  배열 저장, 가비지 콜랙터가 참조되지 않는 즉, 사용될수 없는 객체 제거
- 메소드영역 메모리 : static이 붙은 필드를 가진 클래스가 로딩이 되면 이 정적필드는 메소드 영역에 저장이됨.

 

static 필드의 의미(그 안의 값)

정적 필드 값의 유지 예시1 : StaticCount.java, Shared.java / 메인메소드는 Shared 클래스에만 있다

package p2022_06_29;

public class StaticCount {
    static int number = 3;
}

- 정적 필드 하나만 있다. 프로그램 종료까지 값을 계속 유지함
- 정적필드는 싱글톤을 만들때만 주로 쓴다. 객체를 1개만 생성해서 공유를 한다는 개념인 싱글톤

package p2022_06_29;

public class Shared {
    public static void main( String[] args ) {
    
        StaticCount sc1 = new StaticCount();
        System.out.println("sc1.number = " + sc1.number); //3
        
        sc1.number++;
        System.out.println("sc1.number = " + sc1.number); //4
        
        StaticCount sc2 = new StaticCount();
        System.out.println("sc2.number = " + sc2.number); //4
        
        sc2.number++;
        System.out.println("sc2.number = " + sc2.number); //5

        StaticCount.number ++;
        System.out.println("StaticCount.number = " + StaticCount.number); //6
    }
}
출력
sc1.number = 3
sc1.number = 4
sc2.number = 4
sc2.number = 5
StaticCount.number = 6

- 에서 StaticCount 클래스로 sc1라는 객체를 만들었음 
- (정적필드, 정적메소드 가진 클래스로 객체 만드는건 자주안하지만 가능하긴 함)
- sc1을 통해서 접근 된다!

 

값의 변화(값이 유지됨)
1. 처음 sc1.number 출력했더니 3 을 출력함 = 초기값이 3임
2. sc1.number++; 해서 sc1통해서 증가시킴 
3. sc1.number 출력시 4를 출력함

- 그 후 같은 StaticCount로 sc2 라는 새로운 객체도 만듬

4. 근데 힙메모리 영역이 아니라 메소드 영역이라는 공유영역이기 떄문에 sc2.number로 sc2에 접근해서 출력해도 number는 3이 아닌 가장 마지막에 저장한 값 4를 출력시킴
5. sc2.number 로 또 접근해서 ++ 증가시킴
6. sc2.number 출력시 5를 출력

- 마지막엔 객체가 아닌 StaticCount.number 로, 즉 클래스 명으로 접근한다 
6. StaticCount.number 를 ++
7. 출력하면 6이 나옴

 

정적 필드 값의 유지 예시2 : StaticTest01.java

package p2022_06_29;

class StaticTest {
	static int a = 10; // 정적 필드 : 메소드영역(공유영역) 에 저장
	int b = 20; // 인스턴스 멤버변수 : heap 메모리에 저장
}

class StaticTest01 {
	public static void main(String[] args) {
		System.out.println("StaticTest.a->" + StaticTest.a);
		StaticTest s1 = new StaticTest();
		StaticTest s2 = new StaticTest();

		System.out.println("s1.a->" + s1.a + "\t  s2.a->" + s2.a);
		System.out.println("s1.b->" + s1.b + "\t  s2.b->" + s2.b);

		s1.a = 100;
		System.out.print("s1.a->" + s1.a);
		System.out.println("\t  s2.a->" + s2.a + "  ");
		System.out.println(StaticTest.a);

		s1.b = 200;
		System.out.print("s1.b->" + s1.b);
		System.out.println("\t  s2.b->" + s2.b);
	}
}

- StaticTest01이 메인메소드가지고 있다
- StaticTest 클래스에는 static 정적 변수 1개, 일반적인 필드 1개 이렇게 있다
- 이런 일반적인 필드 는 instance 변수 또는 instance 필드 라고 부름
- 즉 a는 정적필드 b는 인스턴스필드

정적필드와 인스턴스 필드 비교
- StaicTest.a 는 정적필드기 때문에 클래스명. 으로 접근 가능
- 이때 초기값이 10으로 있기떄문에 10으로 출력됨

- 그 후 StaticTest 클래스로 new해서 객체 2개를 생성함 s1, s2
- new연산자로 할떄마다 힙메모리상에 새로운 공간을 할당받음
- 그래서 인스턴스 멤버변수인 b는 힙 메모리상에 할당받음
- 정적 변수인 a는 그대로 공유 영역에 있음

현재 상태
     a=10     //정적 멤버변수
 (공유영역)

s1             ------->  b=20
s2             ------->   b=20
                               
(Stack영역)                 (Heap영역)    


초기 상태
- b는 s1의 b, s2의 b 각각 있고, 힙메모리 상에 20으로 각각 있다.
- 이 값의 주소를 s1, s2가 스택메모리에서 갖고 있음

- a는 정적멤버변수라서 공유영역(메소드영역) 에 초기값 10을 저장하고 있는 상태
- 그래서 s1.a, s2.a는 10으로 출력됨 s1.b나 s2.b는 20으로 출력됨

변화
- s1.a 에 접근해서 값을 100으로 수정함
- s1.b 에 접근해서 값을 200으로 수정함

    a=100     //정적멤버변수
 (공유영역)

s1             ------->  b=200
s2             ------->   b=20
                               
(Stack영역)                 (Heap영역)   

변화된 상태
-  s1.a 와 s2.a 모두 출력시 100이 나옴
- 또한 클래스명으로 접근한 StaticTest.a  해도 100이 출력됨
- 즉 a는 가장 마지막으로 저장된 값이 공유됨

- s1.b만 200으로 수정됨(공유 안됨)
- s1.b를 출력하면 200, s2.b를 출력하면 20이 나옴

정적필드와 인스턴스 필드의 비교
- 정적 필드들은 마지막에 저장된 값을 계속 공유함
- 인스턴스 필드들은 클래스를 가지고 객체 생성할때마다 힙 공간 할당받으며 각각 초기값을 가지게 됨

정적 필드와 접근제어자 예제 : StaticTest02,03,04

StaticTest02.java
 
package p2022_06_29;

class StaticTest2 {
	private static int a = 10; // 정적 필드
	private int b = 20; // 인스턴스 필드

	public static void setA(int new_a) { // 정적 메소드
		a = new_a;
	}

	public static int getA() { // 정적 메소드
		return a;
	}
}

public class StaticTest02 {
	public static void main(String[] args) {
		//  System.out.println(StaticTest2.a); //a가 private으로 선언되어서 컴파일 에러 발생 
		System.out.println(StaticTest2.getA());

		StaticTest2 s1 = new StaticTest2();
		StaticTest2 s2 = new StaticTest2();

		s1.setA(10000);
		int res1 = s1.getA();
		System.out.println(res1);
		System.out.println(s2.getA());
	}
}
출력
10
10000
10000

- StaticTest2.a 로 접근이 안된다. 
- 이유 : 아무리 정적필드라도 외부클래스의 접근을 허용하지 않는 private 이 a 앞에 붙어서 다른 클래스인 StaticTest02 에서 접근시 에러 생김

 

private static int a = 10;

 

- 모순이 발생한다
- static은 공유를 하겠다는거고 private은 보호를 하는거라서 컴파일상 오류를 발생시키며 접근이 불가능하다.
- 결과적으로는 클래스명으로 접근하는 것이 허용되지 않음

 

private인 static 필드값 가져오는 방법
- getA() 메소드를 이용해서 접근한다
- getA() 메소드는 정적 메소드이고 public 이라 클래스명으로 접근가능하다\
ex)

System.out.println(StaticTest2.getA());

- 가능하다, 10이 출력됨

 

private인 static 필드값 설정하는 방법 (위 예제 부분)

		StaticTest2 s1 = new StaticTest2();
		StaticTest2 s2 = new StaticTest2();

		s1.setA(10000);
		int res1 = s1.getA();
		System.out.println(res1);
		System.out.println(s2.getA());

- StaticTest2로 새로운 객체 2개  s1, s2 생성함
- setA 메소드는 public static 이라 호출 가능하다. 클래스명으로 접근 가능하지만 이렇게 s1.setA(10000)처럼 객체로 접근도 되긴함
- s1.set(10000)으로 a값을 10000으로 셋팅
- s1.getA() 해서 접근도 되고, s2.getA() 해서도 됨 둘다 출력시 10000 됨

정적 필드와 접근제어자 결론
- private static하면 모순이 생겨서 결국은 다른 클래스에서 접근 못하는 필드임
- 그래서 StaticTest2.a가 에러생김(다른 클래스에서 호출하였기 떄문에)
-> private이 붙으면 정적 static 필드라도 다른 클래스에서 접근이 불가능함

정적 필드와 접근제어자 주의
- 정적 메소드 안에는 정적 필드만 사용가능함 (중요)
- 정적 메소드 안에 일반적인 필드 쓰면 오류발생 (저장영역과 기능이 다르기 떄문에)
- 정적메소드와 일반메소드는 기능이 다름

 

정적 필드 / 정적 메소드 주의 예제1 : StaticTest03

package p2022_06_29;

class StaticTest3 {
	private static int a = 10; // 정적 필드
	private int b = 20;

	public static void printA() { // 정적 메서드에서는 this를 사용하지 못함
		System.out.println(a);
		// System.out.println(b); //정적메소드 안에는 일반적인 필드 사용불가
		// System.out.println(this.a); //컴파일 에러 발생

	}

	public void printB() { // this는 인스턴스 메서드에서 여러 객체에 의해서
		System.out.println(b); // 메서드가 호출될 때 이를 구분하기 위해서 사용된다.
	}
}

public class StaticTest03 {
	public static void main(String[] args) {
		StaticTest3.printA();
		StaticTest3 s1 = new StaticTest3();
		StaticTest3 s2 = new StaticTest3();
		s1.printB();
		s2.printB();
	}
}

정적메소드를 쓸 때 주의사항


1. 정적 메소드에서는 this 레퍼런스 변수를 사용할 수 없다.
- this.는 힙메모리의 주소를 참조하는게 this.이고, this.는 개별적인 객체에 대한 주소를 가진 레퍼런스 변수라서 정적메소드 안에선 this. 를 사용할 수 없다


2. 정적 메소드에서는 일반적인 변수(인스턴스 필드)를 사용할 수 없다.
- 정적 메소드에서는 정적멤버변수만 사용가능함
- 일반적인 필드 = 힙메모리 이고,  정적필드 = 메소드 메모리(영역) 이라서 영역이 다르기 때문


3. 정적 메소드는 메소드 오버라이딩되지 않는다.
- static이 붙은 정적메소드는 메소드 오버라이딩이 되지 않는다.

 

+ 메소드 오버라이딩 : 두 클래스 사이 상속관계가 있을때, 부모로부터 상속되는 필드와 메소드 중, 메소드를 상속받을때, 이름과 형식은 똑같이 하면서 내부 내용은 다르게 쓰는 것.

정적 필드 / 정적 메소드 주의 예제2 : StaticTest04

package p2022_06_29;

class StaticTest4 {
	private static int a = 10; // 정적필드
	private int b = 20;

	public static void printA() {
		System.out.println(a);
//    System.out.println(b);   //컴파일 에러 발생 : 정적메소드 안 일반필드
	}

	public void printB() {
		System.out.println(b);
	}
}

public class StaticTest04 {
	public static void main(String[] args) {
		StaticTest4.printA();
		StaticTest4 s1 = new StaticTest4();
		StaticTest4 s2 = new StaticTest4();
		s1.printB();
		s2.printB();
	}
}

- 정적메소드 안에는 정적필드만 사용가능하다
- 일반 메소드 안에서만 일반필드 사용가능
- 정적 메소드 , 정적 필드는 클래스명. 해서 사용함 !    StaticTest4.printA();  
- 하지만 객체를 만들어서 객체.메소드 해서도 메소드 호출가능, 객체.필드 해서 필드 접근하는것도 가능

    StaticTest4 s1 = new StaticTest4();
    StaticTest4 s2 = new StaticTest4();
    s1.printB();
    s2.printB();

 

Math 클래스 (API 문서)

- 모두 정적필드 뿐
- 모두 정적메소드 뿐
- Math 클래스를 가지고 정적 필드와 정적메소드를 사용해보자

Math의 정적필드 2개
- E
- PI

Math의 생성자
- 생성자 자체가 없다
- 생성자는 제공되지 않는데 쓸수없다 Math 클래스로 new해서 객체생성하면 오류발생

Math의 메소드
- 모두 static 붙은 정적 메소드 -> 굳이 객체를 생성할 필요도 없다
- 그냥 Math.E , Math.random() 으로 쓰면됨

Math 클래스의 필드 사용 예제
+ Math라는 이름으로 사용자 지정 클래스 생성할 수 없다. 라이브러리에 이미 쓰고 있는 이름이라서

		System.out.println("E = " + Math.E);
		System.out.println("PI = " + Math.PI);

- Math클래스는 생성자가 제공되지 않기때문에 Math 클래스로 직접 객체를 생성할 수 없다
- 하지만 Math 클래스 = 정적 필드 + 정적 메소드 뿐이라서 객체 없어도 아무 문제 없음

Math 클래스 메소드 사용 예제(다양한 메소드 사용)

 

1. abs() 메소드
- 절대값을 구해서 결과를 돌려줌 
- abs() 메소드 여러개임 (메소드 오버로딩) , int, double, long, float등 타입별로 존재

	System.out.println("abs() = " + Math.abs(-10)); //절대값 , 결과는 10

 

2. ceil() 메소드
- 안에있는 소수점 이하 값을 무조건 올려버림 (올림) , 소수 첫째자리에서 올림함

	System.out.println("ceil() = " + Math.ceil(3.14)); //올림, 출력은 4.0

 

3. round() 메소드
- 반올림을 해주는 메소드
- 소수첫째자리에서 반올림해주고 결과는 long으로 돌려줌 11이 나옴 
- 매개변수 double, 반환은 long

	System.out.println("round() = " + Math.round(10.5)); //반올림, 출력은 11

 

4. floor() 메소드
- 무조건 내림을 해주는 메소드
- 소수점 이하는 다 버림, 매개변수 double, 반환은 double 
- 10.9 -> 10.0

	System.out.println("floor() = " + Math.floor(10.9)); //내림, 출력은 10.0

 

5. max() 메소드
- 최대값을 구해주는 메소드
- 메소드 오버로딩이 되어있다

ex) max(int a, int b) , max(double a, double b) 등
- 2개짜리 매개변수 있는 메소드들만 있다
- 자바에는 2개짜리만 제공함 -> 3개 이상이 필요하면 내가 만들어서 써야함 (파이썬은 제한 없음)
- 10과 20중 큰 값을 return 구문으로 돌려줌

		System.out.println("max() = " + Math.max(10, 20)); // 최대값 , 출력은 20

 

5. min() 메소드
- 최솟값을 구해주는 메소드
- 메소드 오버로딩이 되어있다
- min메소드도 2개짜리 매개변수 있는 메소드들만 있다

		System.out.println("min() = " + Math.min(10, 20)); // 최솟값, 출력 : 10

 

6. pow() 메소드
- 지수를 구할때 사용한다.
ex) 2의 3승 구할때 쓰는 메소드 Math.pow(2,3);
- pow(double a, double b) 이고 리턴은 double 형

		System.out.println("pow() = " + Math.pow(2,3)); // 2의 3승 , 출력은 8.0

 

7. random() 메소드
- 양수값으로 0.0보다 크거나같고 1.0보다 작은 범위의 실수형태의 난수 리턴
- 0.0 <= Math.random() < 1.0 범위의 난수 발생
- double형으로 리턴

		System.out.println("random() = " + Math.random());

 

8. sqrt() 메소드
- 제곱근을 구해주는 메소드
- 루트를 씌운값을 돌려줌
- 리턴은 double
ex) 루트5를 구할때 쓰는 메소드 Math.sqrt(5);

		System.out.println("sqrt() = " + Math.sqrt(5)); //루트5(제곱근5) , 출력은 2.23606...

 

우리가 쓰는 println() 의 구조

System.out.println("");

- System 클래스의 필드를보면 모두 정적필드
- 객체생성안하고 System.out으로 썼었던 이유 : 정적필드 중 out 이 있다
- out이 정적필드이기때문에 System.out을 쓴다

- 이 out이란 필드의 결과를 돌려주는 자료형이 PrintStream 이 리턴형이다 (객체로서 리턴)
- 즉 System.out은 자료형이 PrintStream이라는 자료형
- 이 PrintSteram 클래스를 찾아보면 println / print / printf 메소드가 들어있다(정적 메소드 아님)

+ void println()이 메소드 오버로딩되어있다. ex) void println(int i), void println(char x) 등

우리가 쓰는 Scanner 객체 생성하고 안에 System.in 썼던 이유
- Scanner 클래스를 찾아보면 Scanner(InputStream source)라는 생성자 가 있다.
- Scanner 생성자의 매개변수가 InputStream 타입이라서
- Scanner 객체 생성할때 생성자의 매개변수가 System.in 이었다
- System.in의 리턴형을 보면 InputStream 이다
+ in은 static이 붙은 정적필드라서 System.in 이라고 쓴다.

자료형과 메모리

- 기본자료형 && 지역변수 -> 스택에 저장됨, 자동으로 초기값이 설정되지 않음.
- 기본자료형 && 멤버변수/정적변수 -> 아직 안함
- 참조형 -> 값은 힙메모리에 저장됨
- 기본자료형이라도 참조형이면 자료형에 따라 자동 초기화
- 클래스들도 필드들이 자동 초기화됨

 

new 연산자

- String 클래스를 제외한 클래스, 배열, 인터페이스는 필수적으로 new 연산자 사용함
- 힙에 새로운 공간을 형성하라는 표시

 

참조형

- 클래스, 배열, 인터페이스, 열거타입(잘 쓰지 않음)
- 값이 힙메모리에 저장됨, 그 값이 저장된 영역의 시작주소를 스택메모리에서 가짐
- 힙메모리 : 동적으로 계속 공간을 늘릴 수 있는 특징

 

메모리 영역

- 스택 메모리 영역
- 힙 메모리 영역
- 메소드 메모리 영역

 

참조형

+ 인터페이스(자료구조)
- 대표적인게 List

 

배열 정리

- 동일한 자료형만 저장가능한 정적인 자료구조
- 정적 자료구조 = 크기가 딱 정해져 있음. new int[3] 하면 딱 3개만 생성
- 배열이름.length 속성 : 배열의 크기 = 배열 방의 개수 

 

배열 매개변수 예시1
- 메소드의 매개변수가 기본자료형이 아니라 참조형 중 배열일때

 

public static void main(String[] args) {

		int[] scores; // 여기 int[] scores ; 는 아직 주소를 가지지 않은 상태

		scores = new int[] { 83, 90, 87 };

		// int[] scores = new int[] {83,90,87}

		int sum1 = 0;
		for (int i = 0; i < 3; i++) {
			sum1 += scores[i];
		}
		System.out.println("총합 : " + sum1);

		// add 메소드를 호출해서, 리턴된 총합을 sum2에 저장
		int sum2 = add(new int[] { 83, 90, 87 });
		System.out.println("총합 : " + sum2);

	} // main() end

	// 사용자 정의 메소드 : 합을 구해주는 메소드 : 배열을 매개변수로
	public static int add(int[] scores) {
		int sum = 0;
		for (int i = 0; i < scores.length; i++) {
			sum += scores[i];
		}
		return sum;
	}

- int[] scores 는 주솟값을 가지지 못한 형태다
- 메소드의 매개변수가 참조형 중 배열이다.
- 이땐 배열의 주솟값을 전달해야함
- Call by Reference 방식으로 호출해야한다.
- 이 int 형 배열의 주솟값을 전달하자
- 매개변수자리에 클래스, 배열, 인터페이스 다 올 수 있다.

 

배열 매개변수 주의(위 예제의 부분)

 

	public static int add(int[] scores) {
		int sum = 0;
		for (int i = 0; i < scores.length; i++) {
			sum += scores[i];
		}
		return sum;
	}


	public static void main(String[] args) {

		int[] scores; // 여기 int[] scores ; 는 아직 주소를 가지지 않은 상태
	}

- main의 int[] scores 는 주솟값을 가지지 못한 형태다
- new 연산자를 써야만 새로운 공간을 힙메모리에 할당받는데 아직 안썼으므로
아직 주솟값이 없는 상태
- add함수로 전달하는 건 주솟값을 전달해야함 = Call by Reference

 

	public static void main(String[] args) {
		int sum2 = add(new int[] { 83, 90, 87 });
	}

- 이 경우엔 리턴받는게 없으니 이 공간은 재사용을 못한다
- 이렇게 해서 new를 써서 add 메소드로 주솟값을 전달함
- 힙 메모리 상에 있는 "같은 자료형 "(여기선 int형) 배열의 주솟값을 전달해야함
- new를 쓸때마다 새 공간이므로 이 sum2가 가리키는 new의 공간이랑 맨 위에 scores 이 가리키는 공간은 다른 주소이다
- 힙메모리상에 불필요하게 공간을 사용하는건 Garbage Collector 프로그램이 주소를 전달한 뒤 자동으로 지워버림 = 재사용 불가

 

+ 값 전달하는거보다 주솟값을 전달하는게 처리가 빠르다
+ C언어에선 이걸 포인터로 전달함

 

참조형인 매개변수 정리
- 주솟값을 할당받기 위해선 반드시 new 연산자가 있어야함
- String s= "자바" 가 가능하므로 String s 가 매개변수로 올때만 예외적으로 바로 check("자바") 로 호출 가능
- 또는 String s = new String("파이썬") 도 가능하므로 check(new String("파이썬") 으로 호출해도 된다.
- 다른 참조형 변수는 99% new를 써야함

메소드 정리
- 메소드 앞에는 return 자료형이 반드시 와야함
- 정적메소드이기 때문에 클래스명.add 또는 같은 클래스 내에선 .add 로 생략하고도 쓸수있다
- 정적메소드 아니면 객체를 생성후 호출해야한다.

배열 초기화 정리
- int뿐아니라 정수형 배열들은 다 0 으로 초기화 됨(char제외)
- 실수는 float 는 0.0f double 은 0.0
- 클래스/인터페이스/배열은 null로 초기화
* null : 주솟값이 없다는 의미


확장 for문 = 향상된 for문
- 순차적인 자료구조인 배열, 리스트같은 곳의 원소를 끄집어낼때 사용함
- 배열에 있는 값을 원소값이 더이상 없을떄까지 하나씩 왼쪽의 변수로 옮김
- 간결하기때문에 자주 씀

 

for( 타입 변수 : 순차적인 자료구조(배열,컬렉션)) {
             실행문 ;
}

* 타입변수 : 전달 받을 값 
* 컬렉션 = 자료구조(여기선 순차적인 자료구조를 의미), 대표적인게 리스트

 

확장 for문 예제

		int[] score = { 95, 71, 84, 93, 87 };


		// 확장 for문
		int sum1 = 0;
		for(int s : score) {
			sum1 += s;
		}

- 값을 받는 변수 s 도 배열의 자료형과 같은 int 형으로 받아야함
- score 배열에 들은 원소(값)들을 왼쪽의 s변수에 하나씩 전달, 이걸 원소값이 없을때까지 반복한다
- 전달된 값을 sum1 변수에 누적 

+ 순차적인 자료구조 :List, Vector
+ stack은 순차적인 자료구조 아님 다른 방식

 

main 메소드의 매개변수

- public static void main(String[] args){}
- JVM에서 여태껏 main 실행할때 아무 값 전달하지 않았음
- 하지만 전달 할 수도 있다.
- 전달시 args[0]에 첫번째 값이, args[1]에 두번째 값이 들어감
- String 자료형이므로 숫자를 적어도 문자로 처리됨

 

main 메소드의 매개변수 활용

package p2022_06_27;

public class ArrayEx07 {

	// 절대값을 구해주는 메소드
	static int abs(int data) {
		if (data < 0)
			data = -data;
		return data;
	}

	public static void main(String[] args) {

	// args[0] = "-10", args[1] = "-20"
		System.out.println("args[0] : " + args[0]);
		System.out.println("args[1] : " + args[1]);
	// args[0] = "-10" ---> -10 : 형변환(int로)
		int num = Integer.parseInt(args[0]);
		System.out.println("절대값 : " + abs(num));
	}

}

- 이 코드를 그냥 실행시 오류
- main 메소드 통해서 값을 전달할땐 그냥 실행시 오류가 생김
- 실행시키는 방법이 다름 ! (자주 쓰는건 아니지만 알아두기)

 

이클립스로 실행법
1. RUN 초록 화살표 버튼 마우스 대고 있으면  Run Configuration  메뉴 잇다
2. 두번째 탭인 arguments 선택
3. 위칸 program arguments 에서 -10 -20 을 입력(뛰어쓰기로 args[0] args[1] 값 구분)

- args[0]에 -10, args[1]에 -20 이 전달됨
- (-10)을 써도 String[] 이 매개변수이므로 문자인 "-10" 인것임
+이클립스가 아닌 콘솔창 자바 가상머신에서 실행시

java ArrayEx07 -10 -20

- 이렇게 실행함


의미 설명

1. java : 자바 가상머신 JVM
2. ArrayEx07 :ArrayEx07.class 란 바이트 코드를 실행함
3. -10 -20 이렇게 구분해서 입력

 

- args[0]에 -10, args[1]에 -20 이 전달됨
- (-10)을 써도 String[] 이 매개변수이므로 문자인 "-10" 인것임

 

자료형 변환

- 형변환된 값을 abs 메소드에 전달해야하는데 abs는 매개변수가 int 형이므로 그래서 문자를 숫자로 일단 변경하고 메소드 호출해야함.
-이걸 절대값 구할때는 args[]에 들은 데이터는 String은 문자열 이므로 int 로 바꿔야함
- "-10"을 숫자 -10 으로 바꿀땐 

int num = Integer.parseInt(args[0]); // 자주씀 외우기

- 자바의 3가지 자료형 변환 중 두번째 자료형 변환 방법임

 

Wrapper 클래스 (자료형 변환 원리)

- 기본자료형마다 Wrapper 클래스가 있다 .
- Integer 는 int 의 wrapper 클래스임
- 그래서 Integer.parseInt("20") 을 사용해서 문자 20을 숫자 20으로 변환
- Wrapper 클래스를 쓰면 기본자료형과 참조형 사이의 자료형 변환이 가능하다 (ex) string <-> int)
- 모두 java.lang 패키지안에 있어서 import 필요없다
-  Wrapper 클래스 쓰면 다른 자료형으로 쉽게 변환 가능

 

Wrapper Class

- boolean 은 Boolean
- byte 는 Byte
- char 은 Character
- int는 Integer

 

Wrapper 클래스를 이용한 변환 방법 2가지
1.

 int num = Integer.parseInt("20")


- pasreInt는 정적메소드라서 따로 객체 생성없이 클래스명. 으로 호출 parse() 안에는 String 자료형
2. 

Integer in01 = new Integer("20");
int num01 - int01.intValue();


- 언박싱

wrapper클래스의 주요 2가지 기능
1. String -> int (이게 거의 대부분임)
2. int -> String ex) String s - String.valueOf(20);

Integer 클래스 구조 (api 문서)
java.lang.Object
java.lang.Number
java.lang.Integer
- 최상위 클래스 = 슈퍼클래스는 Object
- 부모 클래스는 Number
- 상속 관계가 이미 다 형성되어있다.


1. Integer 의 필드(변수, 상수 의 개념)
- MAX_VALUE 쓰면 int형 변수가 가질 수 있는 최대값을 구해줌(정적필드) 약 +21억
- MIN_VALUE 스면 int형 변수가 가질 수 있는 최솟값을 구해줌


2. Integer 의 생성자
- 2개뿐


3. Integer의 메소드
- 메소드 중 pasreInt 는 2개가 있다 = 메소드 오버로딩
* 메소드 오버로딩 에서 이름은 같아도 매개변수등 구분이 되어야 잘 사용한것
- parseInt (String s) : 우리가 쓴 메소드 . 타입은 static int다 정적메소드이므로 Integer.parseInt로 사용하고, int 형 변수에 결과를 저장해서 돌려줌 매개변수 안엔 String 형만 들어가야함
- parseInt (String s, int radix) 도 있다.

+ 오라클등의 DB 연동할때 java.lang.Class 클래스 사용


배열을 복사하기
- 여러 방법 있다
1. for문
2. System.arrayCopy() 메소드
3. Arrays 클래스 이용

 

for문으로 배열 복사하기

public class ArrayEx08 {

	public static void main(String[] args) {

	//p167~p168
	//배열 복사 : for문으로 배열 복사
		
		int[] oldArray = {10,20,30}; //원본 배열
		int[] newArray = new int[5]; //새로운 배열
		
		for (int i = 0; i < oldArray.length; i++) {
			newArray[i] = oldArray[i]; //배열 복사
		}
		
		//복사된 배열 출력
		for(int i : newArray) {
			System.out.print(i + "\t");
		}
	}

}

- newArray는 배열이므로 0으로 다 초기화 된 상태
- oldArray -> newArray 로 복사할때 for문돌아가면서 10이 newArray[0] 으로 20이 newArra[1]으로 30이 newArray[2]로 복사됨
- 한줄 엔터키를 안쓰고 그냥 띄우기나 \t를 쓸때는 println이 아니라 print인점 주의

 

위 예제 그림

2차원 배열 정의방법 2가지

1.

int[][] score = new int[5][3];

- 메모리상에 값 저장위한 기억공간만 생성하고 그 값이 아직 뭔지 모를때 사용
- 2차원배열은 [][]처럼 2개임, [][]가 score 뒤에 가도 됨
- new란 연산자를 쓰는 형식
- 왼쪽, 오른쪽 자료형 같은걸로 맞추기
- 첫번째 괄호에 들어가는건 행의 수 (가로방향)
- 두번째 괄호에 들어가는건 열의 수 (세로방향)
- 4바이트짜리 기억공간을 행 5, 열 3으로 15개 생성하라는 뜻. 5행 3열짜리 기억공간 생성 

 

그림

2.

int[][] score = {{0,0,0},{0,0,0},{0,0,0}};

- 값이 고정되어있을때 쓰는 방식

 

예시

 

int [][] score = { { 85,  60,  70},      //0 행
	            { 90,  95,  80},       //1 행
	            { 75,  80, 100},       //2 행
                    { 80,  70,  95},       //3 행
	            {100,  65,  80} };     //4 행

- 0행 0열에 85, 4행 2열에 80이 들어감

 

2차원 배열 인덱스
- 행 = row = 가로번호
- 열 = colume = 세로번호
- 행 번호는 가로번호 의미
- 배열에 인덱스는 0번부터니까

배열 인덱스 예시

score[0][0] = 85; //0행0열에 85점을 할당하라
score[4][2] = 80; //4행2열에 80점을 할당하라

 

2차원 배열 입력/출력

 

public class Arr04 {

  public static void main(String[] args) {
   
    int [][]score = { { 85,  60,  70},   //0 행 = 1번학생
			{ 90,  95,  80},   //1 행 = 2번학생
			{ 75,  80, 100},   //2 행 = 3번학생  
                        { 80,  70,  95},   //3 행 = 4번학생
			{100,  65,  80}    //4 행 = 5번학생
					};
    int [] subject = new int[3]; //과목총점 저장할 1차원 배열
    int [] student = new int[5]; //학생의 총점 저장
        //    subject[0]=0, student[0]=0;
    int  r, c;  
	    
    System.out.println("각 과목별 총점구하기 "); //열방향으로 다 합쳐야
    for(c = 0; c < 3 ; c++){ // 과목         
      for(r = 0; r < 5 ; r++){ //학생      
        subject[c] += score[r][c];   
      }//subject[c]=subject[c]+score[r][c];
      System.out.println(subject[c]);  
    }

    System.out.println("학생별 총점구하기");
    for(r = 0; r < 5 ; r++){    //학생      
      for(c = 0; c < 3 ; c++){  //과목    
        student[r] += score[r][c];  
      }//student[r]=student[r]+score[r][c];
      System.out.println(student[r]);
    }

  }//main() end
}// class end

- 행 열을 따로 처리해야하므로 중첩 for문을 쓴다
- 행번호는 0~4이기 때문에 for문으로 0부터 시작해서 <5까지 즉 4까지 함, == 학생수는 5명
- 그 학생 당 과목 성적을 위해서 안쪽 for문으로 0부터 2까지 3번 돌림 == 과목수 3개(국영수)
- 행과 열이 만나는 곳의 점수를 출력하면 score[row][col]
- 더 빨리 바뀌는 부분이 for문의 안쪽에 와야함 나중에 움직이는 부분이 바깥쪽에
- 과목 총점 구하기는 [0][0] [1][0] [2][0] ... 을 더해야하고 ->과목은 열이기 때문에 for문 안쪽에 r 가 와야함
- 학생별 총점 구하기는 [0][0] [0][1] [0][2] ... 를 더해야함 -> 학생은 행이기 때문에 for문 안쪽에 c가 와야함
- int [] subject = new int [3] 이나 int [] student = new int[5]; 는 자동초기화 0 이므로 sum = 0 같은
번거로운일 할 필요 X

 


객체지향언어

 

클래스
- 클래스도 자료형이다
- 배열과 메모리상 처리는 거의 비슷함

String 클래스
- 클래스 중에서 쉽게 이해할 수 있는 String 클래스로 예시들어서 설명
- 클래스 중 사용빈도 가장 높음

String 클래스와 메모리
- String 클래스로 String 객체를 만든다
- 객체를 만들면 배열과 마찬가지로 문자열 " " 들은 모두 힙메모리상에 저장됨(참조형이 가지는 공통적인 특징)
- 그 메모리의 시작주소값을 변수가 스택에서 가지고 있다

 

String name;
name = "신용권"

- 그냥 이름을 저장하는것같아 보이지만 "신용권"은 힙의 공간에 저장, 그 주소를 가진 name은 스택에서 주소를 가지고 있다.

 

String 클래스와 메모리2
- String 클래스의 경우에는 문자를 바로 할당해도 되고 new 연산자를 사용해도 된다
- 이 두가지 되는건 String 밖에 없다
- 보통의 클래스는 new 연산자를 써서만 객체 만들어야함
- 하지만 new 연산 썼을때와 쓰지 않았을때 메모리에 차이가 있다.

String name1 = "신용권";
String name2 = "신용권";

- new 연산자를 쓰지 않고 만들면 처음 한번은 "신용권"을 저장한 기억공간을 힙메모리에 만듬
- 두번째의 경우에는 새로운 공간 만들지 않고 이미 "신용권"이 저장된 공간의 주솟값을 리턴받음
- name1 == name2 주솟값이 같다

 

String name1 = new String("신용권");
String name2 = new String("신용권");

- new 연산자를 쓰면 매번 새로운 공간을 힙메모리에 생성하라는 명시적인 표시
- new 연산자를 2번 썼기 때문에 새로운 공간이 2번 만들어짐
- 그림을 보면 힙 메모리상에 공간이 따로 따로 만들어짐
- name1 != name2 주소가 다르다

 

참조형의 비교

- 참조형들은 비교대상이 2개다
- name1 == name2 처럼 비교연산자로 주솟값을 비교
- equals() 란 메소드로 값들끼리 비교

 

주솟값 비교 예시

		String str1 = "자바";
		String str2 = "자바";

		if (str1 == str2) { //비교연산자(==)로 참조하는 주소를 비교
			System.out.println("같은 주소"); //같은 주소
		} else {
			System.out.println("다른 주소");
		}



		String str3 = new String("자바");
		String str4 = new String("자바");
		
		if (str3 == str4) { //비교연산자(==)로 참조하는 주소를 비교
			System.out.println("같은 주소"); //같은 주소
		} else {
			System.out.println("다른 주소");
		}

- 비교연산자(==)로 참조하는 주소를 비교

 

그림

값 비교 예시

		if(str1.equals(str2)){ // 참조하는 값(데이터)을 비교
			System.out.println("같은 값"); //같은 값
		}else {
			System.out.println("다른 값");
		}

- 값비교 equals() 메소드를 사용
- 같으면 true를 반환

 

참조형의 비교 정리

- 비교연산자(==) : 참조하는 주소를 비교
- equals() : 참조하는 값(데이터)을 비교

 

+ 메소드를 찾는 법
ex) equals() 메소드를 어디서 찾아야할까
1. 1차적으로 api에서 equals() 메소드가 어디 붙어있는지 보자 -> String
2. String클래스 찾아야
3. String클래스 안에 없으면 그거 조상들 클래스를 찾아야
- String의 경우엔 부모가 java.lang.Object가 최상위 클래스 , 자기 부모 클래스 임. 
- String 안에 없더라도 조상이 그 메소드를 가지고 있으면 상속 받아 string 객체에서도사용할 수 있다.
- 만약 String클래스도 String의 부모클래스에도 equals()없다면 그건 없는 것임.

+ 클래스 구조
- 필드 1개 있고 생성자있다
- 생성자 : 객체를 생성할때 자동으로 호출되는 메서드, 클래스와 같은 이름이다.

 

String 클래스 구조 생성자
- 우리는 매개변수가 String으로 된 생성자를 호출해왔었음 String(String original) 을 써왔던것

 

String str3 = new String("자바")

- 에서 오른쪽은 String은 생성자를 호출하는 것임
- 생성자는 없으면 못씀 제공되는것만 쓸 수 있다

 

String 클래스 구조 메소드
- String 클래스 안 메소드 많다(기능 많다 )
- equals() 메소드의 리턴타입은 boolean, 값이 같으면 true, 다르면 false를 리턴해줌
- 그래서 이 메소드 자체를 if문 안에 넣었던 것

 

Object 클래스와 equals()

- equals() 메소드의 매개변수는 Object
- 자바의 가장 최상위 클래스가 Object임 = 슈퍼클래스= 최상위 부모 클래스
- 패키지가 엄청 많지만 그게 뭐든지 가장 위는 Object 
- 즉, Object 는 모든 클래스의 최상위 부모, 조상
- equals() 메소드 매개변수가 equals(Object anObject) 
- 값을 비교할때 Object의 자식들은 다 equals 안에 들어갈 수 있다. 모든 클래스 다 들어갈 수 있다.
- 즉, equals() 괄호 안에 int, boolean, String등 다 들어갈 수 있다
- String뿐만 아니라 Object의 자식들은 모두 비교 equals로 비교가능, 즉 모든 자료형 다 비교 가능

 

예시1

		boolean b = "자바".equals("파이썬");
		if(b) {
			System.out.println("같은 값");
		}else {
			System.out.println("다른 값");
		}

- 가능함
- 3번째 자료형형변환 방법, 레퍼런스 관련이 있다

 

예시2

		if(new Integer(30).equals(30)){
			System.out.println("같은 값");
		}else {
			System.out.println("다른 값");			
		}

- int형끼리 비교도 가능하다.
- int, double, boolean 등 모든 걸 equals 로 비교 가능
- wrapper 클래스 , 오토박싱,오토언박싱 등의 개념 앞으로 공부하는것과 연관

 

객체배열
- 객체의 주소를 참조하는(저장하는) 배열
- C++은 많이 쓰지만 String은 많이 쓰진 않음 객체배열보다 성능 좋은 list등이 있기 때문에

 

ex) String객체를 3개 저장하기 위한 배열 = 객체배열

		String[] strArray = new String[3]; // 객체배열
		strArray[0] = "Java";
		strArray[1] = "Java";
		strArray[2] = new String("Java");

- 이렇게 객체 생성시시에 2가지 방법 써서 가능
- 0번방, 1번방 가리키는 "Java"는 같은 곳임
- 0번방, 2번방 가리키는 "Java"는 서로 다른 곳음

		System.out.println(strArray[0] == strArray[1]); //주소값을 비교, true
		System.out.println(strArray[0] == strArray[2]); //주소값을 비교, false
		System.out.println(strArray[0].equals(strArray[2])); //값을 비교, true

 

사용자 정의 클래스
- String 클래스와 비슷한 방식으로 메모리상 처리가 됨

객체 지향 프로그래밍(OOP)
- 부품 객체를 먼저 만들고 이것들을 하나씩 조립해 완성된 프로그램을 만드는 기법

객체
- 물리적으로 존재하는 모든게 객체가 될 수 있다 ex) 자동차, 사람, 책
- 추상적인 것도 객체가 될 수 있다 ex) 회사, 날짜
- 현실세계에선 사람이란 객체가 있을때 사람에 대한 속성이 있다 ex)나이, 이름 => 속성
- 사람이란 객체가 있을때 있는 동작 ex) 달린다, 걷는다 => 메소드

객체 모델링
- 자바같은 객체지향언어에선 객체 모델링이란 작업을 수행한다
- 사람이란 객체의 속성을 표현할때는 '필드'라는걸가지고 속성을 나타남
- 메소드 바깥쪽에 쓰는 변수 = 멤버변수 = 필드 변수 = 객체의 속성 나타냄
- 메소드를 가지고 객체의 동작을 표현함

현실세계의 자동차 객체
- 필드를 가지고 객체의 속성에 대한 것들을 표현
- 속성 : 색상, 속도 -> '필드' 로 표현함, 필드는 쉽게 말하면 멤버변수임
- 필드는 메소드 바깥쪽에 정의되는 변수로서 멤버변수라고 불린다. 자바에선 필드라고 불림
- 동작 : 메소드를 가지고 표현. 달린다 멈춘다 등의 동작을 메소드로 표현

객체 지향 프로그래밍이 가지는 특징
1. 캡슐화
- 한개의 클래스가 만들어져 있을때 외부클래스에서 접근하지 못하도록 캡슐로 보호를 한다.
- 캡슐화위해선 접근제어자로 접근을 허용을 하기도하고 허용을 하지않기도 한다.
ex) private 써서 외부로부터 접근 막음 = 캡슐화로 안전하게 안의 정보를 보호함

2. 상속
- api에서 제공되는 클래스는 이미 상속관계 정의 다 된 상태임.
- 상속을 함으로서 중복적인 코드를 많이 줄일 수 있다
- 또 유지보수를 편리하게 해주는 기능을 제공하기때문에 상속을 많이 사용함.

ex) 부모 클래스가 있고 자식 클래스가 있을떄
- 클래스 = 필드, 메소드, 생성자 로 구성
- 상속이 되는건 2가지 뿐! 필드와 메소드만 상속이 되고! 생성자는 상속되지 않음!

3. 다형성(Polymorphism)
- 부모로부터 상속받은 것들을 다양한 형태로 바꿔서 쓴다는 것

객체와 클래스
- 설계도 역할을 하는게 클래스다
- 현실세계 : 설계도 -> 객체  를 만들어냄 (ex)설계도로 자동차를만들어냄)
- 자바 : 클래스 -> 객체. 설계도역할하는게 클래스, 클래스 가지고 객체를 무한히 많이 만들어 낼수 있다.

클래스 이름
- 하나이상의 문자로 이루어져야
- 변수명과 마찬가지로 첫번째 글자는 숫자올수없다 ex) Car 3Car (x)
- $나 _ 외의 특수문자 사용불가
- 자바 키워드는 사용할 수 없다
- 변수명,함수명,클래스명등은 한글명으로 클래스 명 쓰는건 바람직하지 않다. 웹으로 가면 여러 문제 발생!

클래스와 소스파일
- 이클립스에서 클래스를 만들면 소스파일이 생성됨 클래스이름.java 가 생성됨
- 이걸 javac.exe가 컴파일 해줘서 클래스이름.class 생성됨
- 앞으로는 한개의 .java 파일에 클래스가 여러개가 들어가는 소스파일 .java 을 만들것
- 소스 파일 당 public class 는 1개만 사용가능함! 이 public 을 가진 클래스와 파일명을 일치시켜야함
- 클래스명과 파일명이 일치되어야하는데 단, 이때 메인메소드를 가진 클래스명과 파일명을 일치 시켜야함
- 컴파일이 되면 파일 안의 여러개 클래스가 각각 따로 따로 .class 파일들로 만들어짐(클래스 수만큼)

객체 생성

new 클래스();

- 클래스와 동일한 이름의 생성자를 호출하라는 코드
- 생성된 객체는 힙메모리상에 객체가 생성됨
- new 연산자는 객체를 생성후 객체 생성 주솟값을 리턴하므로, 왼쪽의 변수가 그 주솟값을 갖고있게됨

 

객체 생성 방법 2가지

1.

클래스 변수;
변수 = new 클래스();

2.

클래스 변수 = new 클래스();

- 한줄

 

클래스 구성 멤버와 역할
- 필드 : 변수기때문에 메모리상의 값을 저장하는 역할
- 생성자 : 객체가 생성시 호출되며 필드값을 초기화하는 역할
- 메소드 : 객체의 동작적인 걸 표현하는 역할

사용자 정의 클래스
- api 에 있는 클래스를 모방하여 생성
- 메소드 바깥쪽에 사용되는 변수 = 필드 = 멤버변수, 변수기때문에 값을 저장함, 속성을 표현
- 생성자는 클래스명과 동일한 이름으로 만들어야함. 객체가 생성될때 생성자가 호출되며
필드값을 초기화시키는게 생성자의 역할
- 메소드는 객체에 대한 동작을 나타냄, ex) public void static main

 

정리
메인 메소드 안의 변수 = 지역변수 = 스택메모리 = 메소드종료시 삭제
메소드 밖의 변수 = 멤버변수 = 필드 = 전역변수 = 힙 메모리 = 초기화

 

사용자정의 클래스 만들기 예시

 

public class Animal {
//Animal 은 사용자 정의 클래스(자료형)

	
	int age; //자바에선 멤버변수, 필드(field) 라고 한다. C에선 전역변수라고 부른다.
		// : 메소드 바깥쪽에 정의되는 변수
	
	public static void main(String[] args) {

	}

}

- age는 메소드 바깥에 있고, 이 클래스 전역에 사용 가능
- 멤버변수= 필드 = 전역변수 는 메모리 중 힙메모리 상에 저장됨!
- 클래스도 참조형이기 때문에 int age; 는 힙메모리상의 공간을 할당받고 초기화 0 으로 자동초기화됨

 

* JAVA구조 : 클래스 내에 메소드가 있다

 

생성자
- 멤버 함수 중 하나
- 반드시 클래스명과 동일한 이름으로 생성해야함.
- () 괄호가 반드시 있어야한다.
- 생성자명앞에는 접근제어자만 올 수 있다.

기본생성자(default constructor)
- 생성자 중 매개변수가 없는 생성자

 

	int age; 
	public Animal() {
		System.out.println("생성자 호출 성공");
	}

 

사용자 정의 클래스와 클래스의 구조 3가지

 

public class Animal {
//Animal 은 사용자 정의 클래스(자료형)

	
	int age; //필드
	public Animal() { //생성자
		System.out.println("생성자 호출 성공");
	} 
	
	public static void main(String[] args) {  //메소드
		
		int a = 10;

	}

}

- 필드, 생성자, 메소드가 다 있는형태
- 생성자는 주로 객체생성과 동시에 필드값의 초기화를 설정하기 위한 용도로 객체가 생성될때 호출되면서 실행
+ a는 지역변수, stack 메모리 영역에 저장, 이 메소드 안에서만 사용가능
+ 지역변수와 멤버변수는 스택과 힙 이라는 다른 공간에 저장되는것 뿐만 아니라 메모리상에 저장되는 영역과 할당되는 시점이 다름

 

	public static void main(String[] args) {

		int a = 10; //지역변수
		String str = new String("자바");
		Animal a1 = new Animal();
	}

+ 이 main메소드는 Animal 클래스 내부임. Animal 클래스 내부에 Animal 클래스로 객체 만들어도 된다.

 

그림

필드 접근

    Animal     a1         =   new       Animal();
// 클래스 레퍼런스변수 연산자 생성자호출

- 이렇게 객체를 생성시 4바이트짜리 Animal 클래스의 '필드'를 저장하기 위한 기억공간을 힙에 생성함
- 그 필드는 age (=0 , 자동초기화) 이다. 그 주솟값을 a1이 가지고 있는 상태
- a1이 age가 저장된 힙메모리상의 시작주솟값을 가지고 있다.
- 이 a1으로 접근해야지만 이 age에 접근가능하다!

 

System.out.println(age); // 불가능
System.out.println(a1.age); // 로 해야함

- 반드시 a1이 가진 주소 이용해서 a1.age로 접근해야함!
- 객체 생성될때마다 새로운 age만들어지므로 어느 영역에 있는 age인지 알 수 없기 떄문이다

- age의 값을 수정하고 싶을때도  a1.age로 접근해서 수정해야한다

		a1.age = 5;
		System.out.println(a1.age); //5가 출력됨

 

생성자 호출

- 오른쪽의 Animal() 은 생성자를 호출하라는 코드임

	public Animal() {
		System.out.println("생성자 호출 성공");
	}

- 출력이 됨

 

생성자를 안쓴다면?
- 기본으로 알아서 생성해줌 

 

객체 생성2

ex) 이번에는 Animal 클래스로 다시 new 연산자로 다시 객체 생성해보자

		Animal a2 = new Animal();
		System.out.println(a2.age);

- 이러면 힙메모리상에 새로운 공간이 또 생성됨!

- 그림 참고

 

그림

- a1이 가진 주소와 a2가 가진 주소를 비교해보자

		if (a1 == a2) {
			System.out.println("같은 주소");
		} else {
			System.out.println("다른 주소");
		}
출력 : 다른 주소

- new로 힙메모리에 새로운 공간을 만들었기 때문이다

복습

char 자료형

- 영문자 1글자는 1바이트
- 한글자 1글자는 2바이트

 

- 하지만 char 안에는 모두 한글자만 가능

char c1 = 'k'
char c2 = '안'

 

참조형

- 기본 자료형과 달리 값 저장 방법이 다르다.

- 값은 힙에 주소는 스택에 저장된다.

 

자바의 구조, api 문서

- jre의 패키지는 비슷한 클래스끼리 묶여져 있다.
- 바이트 코드를 가져와서 import해서 사용하는것이다.
- 바이트 코드 = 기계어
- 그것의 설명서가 api문서

 

필드 : 쉽게 말하면 멤버변수

생성자

- 여기서 제공되는 생성자중 하나를 선택해서 써야함.
- 클래스명과 반드시 동일한 이름으로 되어있고, 메소드라 무조건 괄호가 있는 형태

 

if~else if~else 문

- 가장 먼저 만족한 하나만 실행하고 조건문 나간다.

 

if (score >= 90)
grade = 'A';
else if (score >= 80)
grade = 'B';
else if (score >= 70)
grade = 'C';
else if (score >= 60)
grade = 'D';
else
grade = 'F';

- 가장 먼저 해당하는 것의 문장을 실행하고 if문 전체를 나간다

ex) 90점이면 60점이상이므로 아래 else if 도 만족하지만 첫번째에서 걸리므로 'A'만 출력된다.

 

난수발생 공식

- 난수 = (정수화)(Math.random() * (상한값 - 하한값  + 1)) + 하한값;

 

난수발생 공식 설명

0.0 <= Math.random() < 1.0

- 실수형태의 난수 발생시킴.

* 자세한 설명은 아래에서

 

난수발생 예시

 

// 주사위 번호 뽑기 : 1 ~ 6
		int num = (int) (Math.random() * 6) + 1; // 1~6
		System.out.println("num = " + num);

		if (num == 1) {
			System.out.println("1번");
		} else if (num == 2) {
			System.out.println("2번");
		} else if (num == 3) {
			System.out.println("3번");
		} else if (num == 4) {
			System.out.println("4번");
		} else if (num == 5) {
			System.out.println("5번");
		} else {
			System.out.println("6번");
		}

 

난수 발생 2가지 방법

1. Math 라는 클래스 중 random()이란 '메소드'를 사용. Math.random()
2. Random 이라는 클래스를 import 하고 랜덤 객체를 생성해서 난수 발생

 

// 난수 발생
// 0.0 <= Math.random() < 1.0
//  1         ~            6

 

Math 클래스 (by API 문서)

- java.lang의 클래스이므로 import필요없다.

 

java.lang.Object
java.lang.Math

- Object 클래스가 자기 부모이다(상속관계)

 

1. Math 클래스의 필드 = 멤버변수

* 직접 클래스를 우리가 만들떈 필드를 변수 형태로 만들게 됨.
- E는 자연로그 2.7xx , PI는 파이(원주율) 3.14xx

- static 이 붙은 변수(필드) = 정적 필드
- E는 자료형이 static double
- PI도 자료형이 static double

+ 정적 필드
- 정적 필드 들은 객체를 따로 만들지 않고 클래스명.필드 로 접근해서 바로 해당 필드 값 사용가능
ex) Math.E , Math.PI 하면 값이 나옴

 

		System.out.println("E = " + Math.E); //E값
		System.out.println("PI = " + Math.PI); //PI값
		System.out.println(Math.random()); //난수 발생

 

2. Math 클래스의 생성자

- Math 클래스는 객체를 생성할 필요가 없으므로 (static) 생성자가 없다.

ex) Math m = new Math(); 라는 식으로 사용 불가!
- Math 클래스는 아무 생성자도 제공이 안된다
- 즉, 생성자 자체가 없기때문에 new를 쓰면 오류가 남. 

 

3. Math 클래스의 메소드
- 정적 메소드 = static이 붙은 메소드
- Math는 전부 static이 붙은 정적메소드 뿐이다.
- Math의 메소드도 객체를 생성해서 사용하지 않고 클래스명.메소드 해서 바로 사용함
- Math 메소드 중 random() 메소드가 난수 발생 시켜주는 메소드

 

+ random() 메소드 : 
- Type : static double
- double 형이니 실수값으로 처리됨, 양수로 double 형 값을 리턴한다.
- 0.0 보다 크거나 같고, 1.0 보다 작은 범위의 난수를 리턴 
- double이 return 되므로 정수로 값을 받고 싶으면 (int) 강제 형변환

 

Math.random() 난수 공식의 이해

- 공식 : 난수 = (정수화)(Math.random() * (상한값 - 하한값  + 1)) + 하한값;
ex) int num = (int) (Math.random() * 6) + 1; // 1~6

- 0.0 <= Math.random() < 1.0

 

1. 1.0 미만 이니 1.0 이 포함되지 않는다.
2. Math.random() * 6 을 하면 0.0 <= 난수 < 6 까지 난수발생
- 즉 5.99999..까지 난수가 발생되지 6이 발생될 수 없다.
3. 그래서 +1 을 시키는 것
4. 난수값이 0.0 <= 난수 이므로 0.0 이 나온다면 6을 곱해도 0.0 이다.
- 이걸 int로 형변환하면 0이 된다.
5. 그래서 + 하한값 을 해주는 것

 

예시1
- 1~45사이의 난수 발생

int random;
random = (int) (Math.random() * 45 + 1);
System.out.println("난수 = " + random);


예시2
// 5~70사이의 난수 발생
int r;
r = (int) (Math.random() * 66) + 5;

- 일단 5부터가 아니라 0 부터의 기준으로 생각해야한다
- 그러면 5 ~70까지 몇개의 숫자가 있는지 생각 (70-5+1)
- 그다음 5부터 시작한다 생각해서 5를 더해주면 된다.

 

switch~case문

 

  switch(변수){

	case1: 실행될 문장;
		break;
	case2: 실행될 문장;
		break; 
	default: 위의 case를 만족하지 않을때
	            실행될 문장;
     }

- case를 빠져나가려면 반드시 break;를 써야한다.
- break;를 안쓰면 밑으로 내려간다.
- 아무것도 만족 안하면 아래의 default값을 실행한다.

 

break

- 반복문, 조건문(switch~case 만)에서 빠져나갈 때 break;
- break문은 현재 위치에서 가장 가까운 switch문 또는 반복문을 벗어나는데 사용된다.
- 주로 if문과 함께 사용되어 특정 조건을 만족하면 반복문을 벗어나도록 한다.

 

switch~case문 사용법

- 그냥 case 값: 이라 적고 그걸 만족하면 그 아래있는 case 가 실행됨

		switch (score/10) {
		case 10 : 
		case 9 : 
			grade = 'A';
			break;
		case 8 :
			grade = 'B';
			break;

+ score/10 == 10일때, case 9의 문장 실행됨, 즉 100점일때 break문이 없기때문에 내려감

 

switch~case문 단점

- 100~90 이런 범위값 처리위해서 위의 예제처럼 나누기하는등의 처리가 필요함

 

 

반복문 : 반복적인 걸 할 때 사용

- for , while, do~while

 

for문

for(초기값,조건식,증감식){
	반복 실행할 문장;
}

- 초기값이 있어야함
- 비교연산자로 조건식을 씀
- 증감연산자로 증감식을 씀
- 조건식을 만족하는 경우에만 안의 식들을 수행함
- 만족안하는 경우엔 수행 안함

 

자바의 if 초기값 설정 2가지 방법

1. 선언하면서 초기화
2. 선언은 위에하고 for문 ()안에서 초기화

- 자바는 두가지 방법 다 가능하다
- C등의 언어는 2번 방법만 가능 

if문 작동원리 예시1

for (int i = 1; i <= 10; i++) { 
	System.out.println(i + "사랑해요.");
}


1. i=1로 설정된다.
2. i<=10을 만족한다
3. 1사랑해요 출력
4. i++해서 i==2가 된다
5. i<=10 만족한다
6. 2사랑해요 출력
7. i++해서 i==3이 된다.
8. ...
9. 10이 되면 <=10 만족하기떄문에
10. 10사랑해요 출력하고
11. i++되어 11이 되면
12. <=10만족하지 않기 때문에 
13. 출력안하고 나가게됨!

 

지역변수
- 지역변수는 초기화가 자동이 안됨. ->  초기화는 필수!
- 선언된 {}안에서만 사용가능
- 스택이란 메모리 영역에 공간을 할당받음
- 메소드가 실행될때 할당받고 종료되면 자동으로 지워진다
+ 멤버변수(클래스 변수, 인스턴스 변수)와 배열의 초기화는 자동(기본값으로)


if문 작동원리 예시2

int sum = 0;
for(int i = 1; i<=3; i++)
{
	sum = sum + i;
}

 

변수값 변화

변수     sum  = sum + i
                        0        1
1차           1
                        1       2
2차           3
                        3        3
3차           6
                              4 (조건 불만족) -> 끝. sum은 6이고 i는 4인 상태로 끝

- 지역변수 이므로 int sum = 0 라고 초기화를 꼭해줘야함
- 덧셈일땐 영향이 없는 0으로 초기화
+ int 형 i 도 for 문안의 지역변수 이기 때문에 for문 안에서만 사용 가능하다.
+ for문 밖에서 i를 사용하면 오류가 생김 


지역변수 정의
1. 메소드 안에서 정의되는 변수 (그 안에서만 사용가능 sum은 메인 메소드의 지역변수
2. 매개 변수
3. 블럭문(조건문, 반복문) 안에서 사용되는 변수 i는 for문 안의 지역변수

* 증감식 영역에서 i++, ++i, i=i+1, i+=1 다 가능함
+ \t는 탭키만큼 간격벌림, print("\t") 라고 하면 된다.

 

while문

while(조건문){
	반복 실행할 문장;
}


- 비교연산자로 조건문을 작성하고 조건이 참일때만 반복수행함.
- 초기값이 조건식에 안맞으면 아예 실행 안됨


while문 주의
- for문은 조건식, 증감식, 초기값 자리가 있지만 while은 조건식 외는 내가 설정해야한다
- 일반적으로, 초기값은 while문 밖 위에
- 일반적으로, 증감식은 보통 while문 맨 밑에 
- 증감식 안쓰면 항상 참이라서 무한루프가 돌아감

do~while문

do{
	반복 실행할 문장;
}while(조건식);


- 조건식이 거짓이라도 최소 1번은 실행됨
- 끝에 세미콜론 기억하기!!

do~while문 예시

int i = 1;
do {
	System.out.println(i + "사랑해요");
	i++;
}while(i<=10);


- i 초기값이 11이어도 11사랑해요 가 출력된다.
- i 가 10일때, 10사랑해요를 마지막으로 i는 11이 되어 조건 불만족하여 빠져나가게된다

do~while문 예제

System.out.println("메세지를 입력하세요?");
System.out.println("프로그램을 종료하려면 q를 입력하세요");

Scanner sc = new Scanner(System.in);
String input;

do {
	System.out.println(">");
	input = sc.nextLine();  //문자로 입력을 받는다.
	System.out.println("입력문자 : " + input);
}while(!input.equals("q"));

System.out.println("프로그램 종료");
sc.close();


- String을 입력받기 위해 .nextLine() 메소드로 입력받는다.
- do while은 최소 1번은 실행하므로 실행 하자마자 >가 출력되며 입력할 수 있음
- 그 뒤 q를 입력시 do while을 더이상 못하고 나간다
- scanner 함수를 안전하게 close()로 닫아주는게 좋다.


+ input.equals("q") 메소드
- 값을 비교할때 사용하는 메소드, 값이 일치하면 true인데 앞에 NOT연산자 !를 붙여서 q일땐 false를 만들어서 반복문을 빠져나오게 한다.

+ nextLine() 메소드
- 문자열을 받을때 nextLine() 사용
- 결과는 String 타입 자료형에 저장한다.
- 뛰어쓰기 있어도 된다. 
- 사용자가 입력한 한 줄을 통째로 받음.

지역변수 정리
- 메소드 안에서 사용되는 지역변수 = 매개변수 = 스택에 저장됨 = 메소드 종료시 삭제됨
- 블럭문 안에서 사용되었던 i 같은것도 지역변수

+ Recent posts