레이블이 Java인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Java인 게시물을 표시합니다. 모든 게시물 표시

2014년 1월 14일 화요일

[10-5] final 이 붙은 지역변수?

Q. 지역클래스에서 외부클래스의 인스턴스멤버와 static멤버에 모두 접근할 수 있지만,
지역변수는 final이 붙은 상수만 접근할 수 있는 이유는 무엇인가?


A. 메서드가 수행을 마쳐서 지역변수가 소명된 시점에도, 지역클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할수 있기 때문이다.

Q. 그렇다면 final이 붙은 지역변수는 소멸이 안되나?

A. 지역변수는 final 로 지정하면 JVM constant pool 에서 따로 변수를 관리한다.
따라서 지역클래스를 포함하고 있는 메서드와 메서드 안의 'final' 지역변수는 생명주기가 달라진다. 이 이유로 메서드가 가비지 컬렉터에 반납되어도 메서드 안의 final 지역변수는 constant pool에서 계속 보관하고 있기 때문에 이를 참조하고 있는 지역클래스의 인스턴스는 문제없이 동작할 수 있다.

Q. constant pool(상수 풀)이란? (추가내용)

방금 생각남 : String 도 변경할수 없었지? final 도 상수로 지정할때 쓰고...
                    '상수 풀'에 관리되니까 String 도...

String클래스의 intern메서드와 constant pool (상수풀)
Java에서 쓰이는 모든 String 객체는 상수풀에서 관리됩니다상수풀은 클래스와 같은Heap Permanent area(고정 영역)에 생성되어 Java 프로세스의 종료까지 그 생을 함께 합니다.
String new로 생성하지 않고 "" 리터럴을 사용하여 생성할경우내부적으로 new String() 메소드 호출 이후에 String.intern()이라는 메소드가 호출되어 고유의 인스턴스를 공유하도록 interned됩니다.  이것은 생성한 String Constant pool에 등록하는(만약 이전에 같은 char sequence의 문자열이 이미 상수풀에 있다면 문자열을 힙에서 해제하고 그 상수풀의 레퍼런스를 반환작업을 수행하지요.
같은 패키지의 같은 클래스 내에서는 정수(literal)스트링들은 동일한 String 객체를 참조한다.
)
String a = "JAVA";
String b = "JAVA";
의 경우 a == b  true
String a = new String( "JAVA" );
String b = "JAVA"
의 경우 a == b  false
String a = new String( "JAVA" );
a = a.intern();
String b = "JAVA";
의 경우 a == b  true
일반적으로 문자열들을 비교하기 위해서 equals메서드를 사용하지만, equals메서드로 문자열의 내용을 비교하는 것보다는 등가비교연산자(==)를 이용해서 주소(4 byte)를 비교하는 것이 더 빠르다.
명시적인 new String() 생성자를 호출했기 때문에 각각의 문자열이 상수풀에 intern되는 과정 없이 제각각의 heap 주소에 생성된 것입니다.
수형(int)값을 String으로 변환하는 두 가지 방법
1) String클래스의 valueOf메서드
2) 덧셈연산자(+)를 사용

2014년 1월 13일 월요일

[9-11]

class Exercise9_11{

public static void main(String[] args) {

try {

int start = (int)Integer.parseInt (args[0]);
int end = (int)Integer.parseInt (args[1]);

if (args.length != 2) {
throw new Exception ("시작 단과 끝 단, 두개의 정수를 입력해주세요.");
}

if ( !( (start >=2) && (end <= 9) ) ) {
throw new Exception ("단의 범위는 2와 9사이 입니다.");
}

for (int i = start; i <= end; i++ ) {
for (int j=1; j <= 9; j++) {
System.out.println (start + " * " + j + " = " + start*j);
}
start++;
System.out.println ();
System.out.println ();
}
}

catch (Exception e) {
System.out.println (e.getMessage () );
// System.exit(0);
}
}
}

2014년 1월 12일 일요일

[9-10] 정렬

class Exercise9_10 {
 public static String format (String str, int length, int alignment) {
  if ( length < str.length () ) {
   return str.substring (0, length);
  } else {
   char [] c = new char [length];
   for (int i=0; i < length; i++) {
    c[i] = ' ';
   }
   switch ( alignment ) {
    case 0:
     System.arraycopy (str.toCharArray (), 0, c, 0, str.length() );
     break;
   
    case 1:
     System.arraycopy (str.toCharArray (), 0, c, str.length ()/2, str.length() );
     break;
    case 2:
     System.arraycopy (str.toCharArray (), 0, c, str.length ()/2 * 2, str.length() );
     break;
   }
   return new String (c);
  }
 }
 public static void main (String [] args) {
  String str = "가나다";
  System.out.println( format (str, 7, 0) );
  System.out.println( format (str, 7, 1) );
  System.out.println( format (str, 7, 2) );
 }
}

2014년 1월 11일 토요일

[9-9] 뻘짓

class Exercise9_9 {

public static String delChar (String src, String delCh) {
//-------------------내가 행했던 슈퍼 뻘짓거리----------------------------------
/*
StringBuffer sb = new StringBuffer(src.length()); // src.length() 만큼의 문자를 담을 수 있는 Buffer 생성
int i = 0;
// for (int i=0; i < delCh.length(); i++) {
// if ( src.indexOf( delCh.charAt (i) ) != -1) {
// System.out.println(src.indexOf(delCh.charAt (i)));
// System.out.println(src.indexOf ( delCh.charAt (i) ));
if(src.indexOf ( delCh.charAt (i) ) >= 0 ) {
sb.deleteCharAt( src.indexOf ( delCh.charAt (i) ) );


// sb.deleteCharAt(1);
//}
// }
return sb.toString();
*/        //
//--------------------------------------------------------------------------------

StringBuffer sb = new StringBuffer(src.length());

for (int i=0; i < src.length(); i++) {
char ch = src.charAt(i);
//ch가 delCh에 포함되있지 않으면 (indexOf () 로 못찾으면) sb에 추가
if ( delCh.indexOf (ch) == -1 ) {
sb.append (ch);
}
}
return sb.toString();
}
public static void main(String[] args) {

System.out.println (" (1!2@3^4~5) "+" -> "
+ delChar (" (1!2@3^4~5)", "~!@#$%^&*()" ) );

System.out.println (" (1  2    3     4\t5) "+"  -> "
+ delChar (" (1  2      3    4\5) ", "  \5") );

}
}

2014년 1월 10일 금요일

[9-6] String 을 char[] 로 뽑아내기

class Exercise9_6 {

public static String fillZero (String src, int length) {


if (src == null || src.length() == length) {
return src;

} else if (length <= 0){
return " ";

} else if (src.length() > length) {
return src.substring (0, length);

} else {
char[] c = new char[length];

for (int i=0; i<c.length; i++){
c[i] = '0'; // 문자니까 'c'
}

System.arraycopy (src.toCharArray(), 0, c, length-src.length(), src.length() );
// src의 문자배열을 뽑아내서 생성한 배열에 복사

return new String (c); // 생성한 배열을 String 으로 반환
}


}
public static void main(String[] args) {
String src = "12345";
System.out.println(fillZero (src, 10) );
System.out.println(fillZero (src, -1) );
System.out.println(fillZero (src, 3) );
}
}

[9-5] 문자열 검색

class Exercise9_5 {
public static int count (String src, String target) {
int count = 0; // 찾은 횟수
int pos = 0; // 찾기 시작할 위치
/*
(1) 반복문을 사용해서 아래의 과정을 반복한다.
1. src에서 target을 pos의 위치부터 찾는다.
2. 찾으면 count의 값을 1 증가 시키고,
   pos의 값을 target.length 만큼 증가시킨다.
3. indexOf 의 결과가 -1이면 반복문을 빠져나가서 count를 반환한다.

*/
do {
if ( ( pos = src.indexOf (target, pos) ) != -1) {
count++;
pos = pos + target.length();
} else {
break;
}
}
while (true);

return count;


}

public static void main (String [] args) {
System.out.println (count ("12345AB12AB345AB", "AB") );
System.out.println (count ("12345","AB") );
}
}

2014년 1월 9일 목요일

[9-3] String클래스의 메서드 활용

class Exercise9_3 {
public static void main (String[] args) {
String fullPath = "c:\\jdk1.5\\work\\PathSeparateTest.java";
String path = " ";
String fileName = " ";

path = fullPath.substring (0, fullPath.lastIndexOf ('\\') );
fileName = fullPath.substring(fullPath.lastIndexOf ('\\')+1);


System.out.println("fullPath : "+fullPath);
System.out.println("path : "+path);
System.out.println("fileName : "+fileName);
}
}

[9-2] equals ()&toString 오버라이딩

class Exercise9_2 {
public static void main(String[] args) {
Point3D p1 = new Point3D (1,2,3);
Point3D p2 = new Point3D (1,2,3);

System.out.println(p1);
System.out.println(p2);
System.out.println("p1==p2?"+(p1==p2) );
System.out.println("p1.equals (p2) ?"+(p1.equals(p2) ) );

}
}

class Point3D {
int x, y, z;

Point3D (int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;

}

Point3D () {
this (0,0,0);
}

public boolean equals (Object obj) {
if (obj instanceof Point3D) {
Point3D p = (Point3D)obj;
return x == p.x && y == p.y && z == p.z;
}
return false;
}

public String toString () {
return "["+x+","+y+","+z+"]";
}
}

2014년 1월 8일 수요일

[9-1] equals () 오버라이딩

class Exercise9_1 {
public static void main (String[] args) {
SutdaCard c1 = new SutdaCard (3, true);
SutdaCard c2 = new SutdaCard (3, true);

System.out.println("c1="+c1);
System.out.println("c2="+c2);
System.out.println("c1.equals (c2) : "+c1.equals (c2) );
}
}

class SutdaCard {
int num;
boolean isKwang;

SutdaCard () {
this (1, true);
}

SutdaCard (int num, boolean isKwang) {
this.num = num;
this.isKwang = isKwang;
}

public boolean equals (Object obj) {
if (obj instanceof SutdaCard) {
SutdaCard s = (SutdaCard)obj;
return num == s.num && isKwang == s.isKwang;
}
return false;
}

public String toString () {
return num + (isKwang ? "K":" ");
}
}

2014년 1월 7일 화요일

[8-10] 예외 되던지기(re-throwing)

class Exercise8_10 {
public static void main(String[] args) {
try {
method1(); // 예외 발생!!!
System.out.println(6); // 예외가 발생해서 실행되지 않는다.
}catch (Exception e) {
System.out.println(7);
}
}

static void method1 () throws Exception {
try{
method2 ();
System.out.println(1);
}catch (NullPointerException e) {
System.out.println(2);
throw e; // 예외를 다시 발생시킨다. 예외 되던지기(re-throwing)
}catch (Exception e) {
System.out.println(3);
} finally {
System.out.println(4);
}

System.out.println(5);
}

static void method2 () {
throw new NullPointerException (); //NullPointerException 을 발생시킨다.
}
}

[결과]--------------------
2
4
7
---------------------------

[8-8]유효성 검사

import java.util.*;

class Exercise8_8 {
public static void main(String[] args) {
// 1~100 사이의 임의의 값을 얻어서 answer 에 저장한다.
int answer = (int)(Math.random() * 100) + 1;
int input = 0; // 사용자입력을 저장할 공간
int count = 0; // 시도횟수를 세기 위한 변수
//----------------------------나의 답----------------------------------
/* do {
try {
count++;
System.out.print("1과 100사이의 값을 입력하세요 : ");

input = new Scanner(System.in).nextInt();

if (answer > input) {
System.out.println("더 큰 수를 입력하세요. ");
} else if (answer < input) {
System.out.println("더 작은 수를 입력하세요. ");
} else {
System.out.println("맞췄습니다. ");
System.out.println("시도횟수는 "+count+"번입니다.");
break; // do-while 문을 벗어난다.
}

} catch (InputMismatchException i) {
System.out.println("유효하지 않는 값입니다. 
                                                                               +다시 값을 입력해주세요. ");
}
}
//----------------------------------------------------------------------
while (true); // 무한반복문 */
//----------------------------모범답안--------------------------------------------
do {

count++;
System.out.print("1과 100사이의 값을 입력하세요 : ");

try {
input = new Scanner(System.in).nextInt();
}  catch (InputMismatchException i) {
System.out.println("유효하지 않는 값입니다. 
                                                                                    +다시 값을 입력해주세요. ");

continue;
}

if (answer > input) {
System.out.println("더 큰 수를 입력하세요. ");
} else if (answer < input) {
System.out.println("더 작은 수를 입력하세요. ");
} else {
System.out.println("맞췄습니다. ");
System.out.println("시도횟수는 "+count+"번입니다.");
break; // do-while 문을 벗어난다.
}
}
}
}
//-------------------------------------------------------------------------------



사용자로부터 값을 입력받는 경우에는 유효성검사를 철저하게 해야 한다.

입력받는 부분을 try-catch 구문으로 예외처리를 해주기만 하면 된다.

[8-7] 코드 수행결과

class Exercise8_7 {
static void method(boolean b) {
try {
System.out.println(1);
if(b) System.exit(0);
System.out.println(2);
}catch (RuntimeException r) {
System.out.println(3);
return;
}catch (Exception e) {
System.out.println(4);
return;
} finally {
System.out.println(5);
}

System.out.println(6);
}

public static void main(String[] args) {
method(true);
method(false);
} // main
}

[결과]--------
1
--------------

[해설]--------
변수 b의 값이 true 이므로 System.exit(0); 이 수행되어 프로그램이 즉시 종료된다.
이럴 때는 finally 블럭이 수행되지 않는다.

[8-6] 코드 수행결과

class Exercise8_6 {
public static void main(String[] args) {
try {
method1 ();
}catch (Exception e) {
System.out.println(5);
}
}

static void method1 () {
try{
method2 ();
System.out.println(1);
} catch (ArithmeticException e) {
System.out.println(2);
} finally {
System.out.println(3);
}

System.out.println(4);
}

static void method2 () {
throw new NullPointerException ();
}
}

[결과]------------
3
5
------------------

[해설]--------------------------------
method2() 에서 'NullPointerException' 발생. try-catch 문이 없어서 메서드 종료.
이를 호출한 method1() 로 되돌아갔는데 여기도 'NullPointerException'을 처리해줄 블럭이 없으로므 메서드 종료.
이를 호출한 main 메서드로 돌아간다. 이 때 finally 블럭은 수행이 되므로 '3' 출력.
main 메서드에는 모든 예외를 처리할 Exception 이 선언된 catch 블럭이 있으므로 '5' 출력.
---------------------------------------

[8-5] 코드 수행결과 분석

class Exercise8_5 {
static void method (boolean b) {
try {
System.out.println(1);
if(b) throw new ArithmeticException();
System.out.println(2);
} catch (RuntimeException r) {
System.out.println(3);
return;    // 메서드를 빠져나간다. (finally 블럭을 수행한 수에)
} catch (Exception e) {
System.out.println(4);
return;
} finally {
System.out.println(5);
}

System.out.println(6);
}

public static void main(String[] args) {
method(true);
method(false);
} // main
}

[결과]-------------------------
1
3
5
1
2
5
6
-------------------------------


[해설]---------------------

예외가 발생하면            1, 3, 5가 출력
예외가 발생 안하면        1, 2, 5, 6 출력

ArithmeticException 은 RuntimeException 의 자손이므로 RuntimeException 이 정의된
catch 블럭에서 처리된다. 이 블럭에는 return 문이 있으므로 메서드를 종료하고 빠져나가게 된다. 이 때 finally 블럭이 수행된다.
















[8-4] 예외처리 때 주의할점.


try {
method();
} catch (Exception e) { //컴파일 에러 발생!!!!!

} catch (NumberException e) {

}

발생한 예외의 종류와 일치하는 catch 블럭을 찾을 때, instanceof 로 검사를 하기 때문에
모든 예외의 최고조상인 Exception 이 선언된 catch 블럭은 모든 예외를 다 처리할 수 있다.

다만, Exception 을 처리하는 catch 블럭은 모든 catch 블럭 중 제일 마지막이 있어야 한다.
그렇지 않으면 컴파일 에러 발생!!

[8-3]Excepion 오버라이딩

[해설]
 오버라이딩(overrriding)을 할 때, 조상 클래스의 메서드보다 
  많은 수의 예외를 선언할 수 없다.

단, 여기서 주의할 점은 단순히 선언된 예외의 개수의 문제가 아니라는 것이다.


Class Child extends Parent {
   void parentMethod() throws Exception {
       //......
   }
}

만일 위와 같이 오버라이딩을 하였다면, 분명히 조상클래스에 정의된 메서드보다 적은 개수의 예외를 선언한 것처럼 보이지만 Exception은 모든 예외의 최고 조상이므로 가장 많은 개수의 예외를 던질 수 있도록 선언한 것이다.

2014년 1월 6일 월요일

[8-2] 메서드 호출순서

java.lang.ArithmeticException : / by zero
   at ExceptionEx18.method2 (ExceptionEx18.java:12)
   at ExceptionEx18.method1 (ExceptionEx18.java:8)
   at ExceptionEx18.main (ExceptionEx18.java:4)

[해설]

예외의 종류는 ArithmeticException 이고 0으로 나눠서 발생하였다. 예외가 발생한
곳은 method2이고 Exception18.java 의 12번째 줄이다.

<예외가 발생했을 당시의 호출스택>

| method2 |     호출스택은 맨 위에 있는 메서드가 현재 실행중인 메서드이다.
| method1 |     아래  있는 메서드가 바로 위의 메서드를 호출한 것이다.
| main       |     순서 : main -> method1 -> method2

[8-1] 예외처리의 정의와 목적

[8-1] 예외처리의 정의와 목적

---------나의 답-------------------------------------
예외처리란, 프로그램 실행중에 발생할수 있는
예외, 에러를 잡아줌으로써 프로그램의 안정성을 높혀준다.
-----------------------------------------------------

2014년 1월 5일 일요일

[7-14] final 붙은 인스턴스 변수의 초기화

/*
[7-14] 문제 7-1 에 나오는 섯다카드의 숫자와 종류는 사실 변하면 안되는 값이다.
  이러한 문제가 안생기도록 SutdaCard 를 수정하시오. */


class SutdaCard {
final int num;
final boolean isKwang;

SutdaCard() {
this(1, true);
}

SutdaCard(int num, boolean isKwang) {
this.num = num;
this.isKwang = isKwang;
}

//info() 대신 Object클래스의 toString() 을 오버라이딩했다.
public String toString() {
return num + ( isKwang ? "K":"");
}
}


class Exercise7_1 {
public static void main(String[] args) {
SutdaDeck deck = new SutdaDeck();

for (int i=0; i < deck.cards.length; i++) {
System.out.print(deck.cards[i] + ", ");
}
}
}

/*
원래 변수 앞에 final을 붙일 때는 선언과 초기화를 동시에 해야 한다.

final int MAX_VOLUME = 100;

그러나 인스턴스변수의 경우, 선언시에 초기화 하지 않고 생성자에 초기화할 수 있다.
생성할 때 지정된 값이 변하지 않도록 할 수 있는 것이다. 상수이므로 한번 초기화한             이후로는 값을 바꿀 수 없다.

*/

[7-24] 인터페이스를 사용하는 이유와 그 장점

[7-24] 인터페이스를 사용하는 이유와 그 장점

1. 개발시간을 단축시킬 수 있다.

일단 인터페이스가 작성되면, 이를 사용해서 프로그램을 작성하는 것이  가능하다. 메서드를 호출하는 쪽에서는 메서드를 내용에 관계없이 선언부만 알면 되기 때문이다.
그리고 동시에 다른 한 쪽에서는 인터페이스를 구현하는 클래스를 작성하도록 하여,
인터페이스를 구현하는 클래스가 작성될 때까지 기다리지 않고도 양쪽에서 동시에 개발을 진행할 수 있다.

2. 표준화가 가능하다.

프로젝트에 사용되는 기본 틀을 인터페이스로 작성한 다음, 개발자들에게 인터페이스를 구현하여 프로그램을 작성하도록 함으로써 보다 일관되고 정형화된 프로그램의 개발이 가능하다.

3. 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.

서로 상속관계에 있지도 않고, 같은 조상클래스를 가지고 있지 않은 서로 아무런 관계도 없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계를 맺어 줄 수 있다.

4. 독립적인 프로그래밍이 가능하다.

인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제구현에 독립적인 프로그램 작성하는 것이 가능하다. 클래스와 클래스간의 직접적인 관계를 인터페이스를 이용해서 간접적인 관계로 변경하면, 한 클래스의 변경이 관련된 다른 클래스에 영향을 미치지 않는 독립적인 프로그래밍이 가능하다.