관리자 글쓰기
'Java 정리'에 해당되는 글 4건
  1. 가비지 컬렉션 2016.12.19
  2. CH2_ 올바른 값의 반환 2016.06.16
  3. CH2_참조 변수 Casting 2016.06.16
  4. 오버라이딩과 오버로딩 2016.06.15
가비지 컬렉션
2016. 12. 19. 02:17 - Daybreak0_0

가비지 컬렉터 : 메모리 관리를 자동으로 해줌 

메모리의 스택, 힙 영역에서 객체들이 존재하는 힙영역에서 행해진다. ==> 가능한 많은 여유 메모리를 갖도록 관리함


가비지 컬렉터는 언제 실행될까?

JVM 제어 하에 있으며, 실행 시기도 JVM이 결정한다. 

사용 가능한 메모리가 적다고 감지될 때, JVM이 가비지 컬렉터를 실행시킨다.


객체가 가비지 컬렉션 대상이 되도록 만드는 코드


1. 참조를 null로 만들기


1
2
3
4
5
6
7
8
9
public class Garbage{
    public static void main(String[] args){
        StringBuffer sb = new StringBuffer("hello");
        System.out.println(sb);
        
        sb = null;
        // 이제 가비지 컬렉터의 대상이된다.
    }
}
cs


sb는 StringBuffer 객체의 유일한 참조이므로 sb가 null이 되면 StringBuffer 객체는 가비지 컬렉션의 대상이 된다.


2. 참조 변수를 다시 지정하기


1
2
3
4
5
6
7
8
9
10
public class Garbage{
    public static void main(String[] args){
        StringBuffer s1 = new StringBuffer("hello");
        StringBuffer s2 = new StringBuffer("goodbye");
        System.out.println(s1);
        
        s1 = s2; // s1의 참조 값을 변경한다.
        // "hello" StringBuffer 객체는 이제 가비지 컬렉터의 대상이된다.
    }
}
cs


** 메서드가 호출되면, 메서드가 실행되는 동안만 존재하는 지역 변수가 생긴다. 

메서드 실행이 끝나고 복귀되면, 그 메서드 내에서 생성된 객체는 가비지 컬렉션의 대상이 된다.


예외! 만일 메서드가 객체를 반환한다면, 그 객체의 참조를 갖는 참조 변수가 호출된 메서드에 존재할 것이므로, 가비지 컬렉션의 대상이 되지 않는다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.Date;
 
public class GarbageFactory {
 
    public static void main(String[] args) {
        Date d = getDate(); // Date 객체를 반환하는 메서드 
        System.out.println("d =" + d);
    }
    
    /*
     * 이 메서드는 Date, StringBuffer 두가지 객체를 생성
     * Date 객체를 반환하므로, 메서드의 실행이 끝나고 복귀하더라도 메서드에서 생성한 Date 객체는 가비지 컬렉션의 대상이 아님.
     * 반면, StringBuffer 객체는 now 참조 변수에 null을 넣지 않더라도 가비지 컬렉션의 대상이 된다.
     * */
    public static Date getDate(){
        Date d2 = new Date();
        StringBuffer now = new StringBuffer(d2.toString());
        System.out.println(now);
        return d2;
    }
 
}
 
cs


3. 참조를 고립시키기


적법한 참조를 갖고 있는 객체조차도 가비지 컬렉션의 대상이 될 수 있는 방법이 있다.

클래스의 인스턴스 변수는 같은 클래스의 다른 인스턴스를 참조하는 참조 변수이다. 

이 클래스 인스턴스는 두 개 있고, 상호 간에 참조를 한다고 해보자. 

만일 이 두개의 인스턴스를 참조하는 모든 다른 참조가 제거된다면, 두 인스턴스가 상호 참조를 갖고 있더라고 살아있는 스레드에서 두 인스턴스에 접근할 방법이 없으므로

가비지 컬렉터의 제거 대상이 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Island{
    Island i;
    
    public static void main(String[] args){
        
        Island i2 = new Island();
        Island i3 = new Island();
        Island i4 = new Island();
        
        i2.i = i3; // i2는 i3를 참조
        i3.i = i4; // i3는 i4를 참조
        i4.i = i2; // i4는 i2를 참조
        
        i2 = null;
        i3 = null;
        i4 = null;
        
        // i2, i3, i4는 가비지 컬렉션의 대상이 된다.
    }
    
}
cs



** 문제


1. 다음 코드에서 가비지 컬렉션의 대상이 되는 객체는 몇개인가?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
public class CardBoard {
 
    Short story = 200;
    private CardBoard go(CardBoard cb) {
        cb = null;
        return cb;
    }
    
    public static void main(String[] args) {
        CardBoard c1 = new CardBoard();
        CardBoard c2 = new CardBoard();
        CardBoard c3 = c1.go(c2);
        c1 = null;
    }
 
}
 
cs


답: 2개 . c1이 가비지 컬렉션 대상이 되고, 그 객체는 Short 래퍼 객체를 갖고 있으므로, 이 객체도 가비지 컬렉션의 대상이 된다.


2. main() 메서드에서 생성된 객체 수와 가비지 컬렉션의 대상이 되는 객체 수는?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Dozens {
    int[] dz = {1,2,3,4,5,6,7,8,9,0};
}
 
public class Eggs {
    
    public static void main(String[] args) {
        Dozens[] da = new Dozens [3];
        da[0= new Dozens();
        Dozens d = new Dozens();
        da[1= d;
        d = null;
        da[1= null;
    }
 
}
 
cs


답:

5 객체 / 2개의 객체가 GC의 대상이된다.

da는 Dozens 객체를 저장하는 배열 참조이다. 각각의 Dozens객체는 int 값을 저장하는 배열을 갖고 있다.

따라서, 생성된 객체 수는 5개 ( da 배열 객체 1개, Dozens 객체 2개,  각 Dozens 객체들이 가지는 int배열 객체 두개)

가비지 컬렉션 대상이 되는 객체는 2개 ( d가 참조했던 Dozens객체 한개, 그 객체가 갖는 int 배열 객체 한개)


3. 가비지 컬렉션의 대상이 되는 객체는 몇개?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Beta {} 
class Alpha {
    static Beta b1;
    Beta b2;
}
 
public class Tester {
 
    public static void main(String[] args) {
        Beta b1 = new Beta();
        Beta b2 = new Beta();
        
        Alpha a1 = new Alpha();
        Alpha a2 = new Alpha();
        
        a1.b1 = b1;
        a1.b2 = b1;
        a2.b2 = b2;
        a1 = null;
        b1 = null;
        b2 = null;
        
    }
 
}
 
cs


답 : 1개. 

a2가 참조하는 Alpha 객체 참조는 아직 살아 있고, a1만 null값이므로, a1이 참조하는 Alpha 객체만 가비지 컬렉션의 대상이 된다.

'Java 정리' 카테고리의 다른 글

CH2_ 올바른 값의 반환  (0) 2016.06.16
CH2_참조 변수 Casting  (0) 2016.06.16
오버라이딩과 오버로딩  (0) 2016.06.15
CH2_ 올바른 값의 반환
2016. 6. 16. 15:44 - Daybreak0_0

목표 . 주어진 코드를 보고 오버라이딩이나 오버로딩이 잘 되었는지 판단하기 

        메서드 반환 타입이 적합한지 확인

        반환 타입과 실제 반환되는 값의 두 가지 관점을 본다. 

        반환 타입에 관련해서 오버로딩과 오버라이딩 시에 다른 점을 알아본다.


반환 타입의 선언


## 오버로딩된 메서드의 반환 타입


메서드 오버로딩은 메서드 이름을 같은 것으로 재사용할 수 있음을 말한다. 

오버로딩된 메서드는 기본 메서드와 전혀 다른 메서드이다. 이름만 같다 ! 


따라서, 슈퍼 클래스에서 상속받은 메서드를 서브 클래스에서 오버로딩하면, 오버라이딩과는 달리 반환 타입의 제약이 없다.

메서드를 오버로딩하려면 메서드 인가를 다르게 해야 한다는 것을 잊지 말자 ! 


1
2
3
4
5
6
7
8
9
10
11
12
public class Foo {
    void go() {}
}
 
public class Bar extends Foo [
    
    // Foo 클래스의 go() 메서드를 오버로딩 한 것이다.. 
    // 반환 타입이 달라도 상관이 없다 
    String go(int x) {
    return null;
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
public class Foo {
    void go() {}
}
 
public class Bar extends Foo [
    
    // Foo 클래스의 go() 메서드를 오버라이딩 한 것이다. (인자 값이 같으므로)
    // 반환 타입이 다르면 안된다. 에러가 생길 것이다.
    String go( ) {
    return null;
}
 
cs



## 오버라이딩과 반환타입 


서브클래스에서 슈퍼클래스의 메서드를 오버라이딩할 때는 메서드 시그니처 ( 메서드 이름, 인자, 반환 타입) 이 정확히 같아야 한다.

jdk 1.5 이후에는 서브 클래스의 오버라이딩 메서드에 선언한 반환 타입이 슈퍼 클래스 메서드에서 반환 하는 타입의 서브 타입이라면 써도 된다.



1. 객체 참조 경우 null 반환 가능


2. 배열도 반환 가능


1
2
3
public String[] go() {
    return new String[] {"Fred""Barney""Wilma"};
}
cs


3. 기본값 반환 경우 메서드에서 선언한 반환 타입으로 묵시적 변환이 가능하면 다 가능


1
2
3
4
public int foo() {
    char c = 'c';
    return c;
}
cs

4. 3번 처럼 기본형 값을 반환하는 경우, 메서드에서 선언한 반환 타입으로 명시적 변환이 가능하다면 다 가능

1
2
3
4
public int foo() {
    float f = 32.5f;
    return (int) f;
}
cs


5. 반환 타입이 void 이면 아무 값도 변환할 수 없다.


6. 객체 참조를 반환하는 경우 메서드에서 선언한 반환 타입으로 묵시적 변환이 가능하다면, 다 가능


1
2
3
public Animal getAnimal(){
    return new Horse(); // Horse가 Animal의 서브클래스라면 가능
}
cs


7. 인터페이스를 반환 타입으로 선언한 메서드에서 그 인터페이스를 구현한 클래스의 객체를 반환할 수 있다.


public interface Chewable {   }

public class Gum implements Chewable {  }


public class TestChewable {

// 인터페이스를 반환 타입으로 하는 메서드

public Chewable getChewable() {

return new Gum(); // 반환 객체의 참조 타입은 Chewable 인터페이스로 업캐스팅됨

}

}


'Java 정리' 카테고리의 다른 글

가비지 컬렉션  (0) 2016.12.19
CH2_참조 변수 Casting  (0) 2016.06.16
오버라이딩과 오버로딩  (0) 2016.06.15
CH2_참조 변수 Casting
2016. 6. 16. 11:40 - Daybreak0_0

목표. 객체 참조의 캐스팅이 언제 필요한지 결정하고, 객체참조의 캐스팅에 관련되는 컴파일 에러와 런타임 에러를 파악한다.

.


1
2
3
4
class Animal {
    void makeNoise() {System.out.println("generic noise"); }
}
 
cs

1
2
3
4
5
class Dog extends Animal {
    void makeNoise() {System.out.println("bark"); }
    void playDead() {System.out.println("roll over");}
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
class CastTest2 {
    public static void main(String[] args) {
        Animal[] a = {new Animal(), new Dog(), new Animal()};
        for(Animal animal : a){
            animal.makeNoise();
            if(animal instanceof Dog) {
                animal.playDead(); // Dog에만 있는 메서드 호출하려고함 
            }
        }
    }
}
cs


animal 참조변수를 통해서 Dog 클래스에만 있는 메서드를 호출하려고 하면? 


위의 코드에서는 컴파일 에러가 발생한다. 

"Animal 클래스에는 playDead() 메서드가 없어서 찾을 수 없다는 것" 


if(animal instanceof Dog) {

Dog d = (Dog) animal; // 참조 변수의 타입을 다운캐스팅한다.

d.playdead();

}


다운 캐스팅 하는 이유는? 

클래스 상속 구조의 아래쪽에 있는 서브 클래스의 메서드를 호출하기 위함

컴파일러에게 " Dog 객체를 참조하는 것이 확실하므로 참조 변수 타입을 Dog으로 하라" 라고 알려주는 것이다. 



if(animal instanceof Dog) {

Dog d = (Dog) animal; // 참조 변수의 타입을 다운캐스팅한다.

d.playdead();

}


이 코드를 쓰지 않고 바로 다운캐스팅하면? 


1
class Animal {  }
cs
1
class Dog extends Animal{  }
cs
1
2
3
4
5
6
class DogTest{  
    public static void main(String[] args){
        Animal animal = new Animal();
        Dog d = (Dog) animal; // 컴파일은 되지만 런타임 에러가 생긴다.
    }
}
cs

java.lang.ClassCastException 런타임 오류가 발생한다.

Dog도 Animal 타입의 한 종류인데 왜 animal 참조변수로 참조 할 수 없는 것인가?
컴파일할 때는 클래스 상속 구조를 참조하여 타입간의 관계만을 확인하므로, 다운캐스팅 코드가 정상적이지만,
실행 시에는 객체의 실제 타입을 기준하여 다운캐스팅하므로 런타임 에러가 발생한다. 
즉, 서브 클래스 객체는 슈퍼 클래스 타입이 될 수 있지만 슈퍼클래스 객체는 서브 클래스 타입이 될 수 없다.

## 정리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package animal;
 
public class DogTest {
 
    public static void main(String[] args) {
        
        Animal animal = new Animal();
        // animal 참조변수를 Dog 타입으로 다운캐스팅 한다해도 실행 시에 객체의 실제 타입을 
        // 기준으로 다운캐스트하므로 런타임 에러가 발생한다.
        Dog d2 = (Dog) animal;
        d2.makeNoise();
        
        Dog d = new Dog();
        Animal a1 = d;
        Animal a2 = (Animal) d;
        // 런타임시 하위 클래스인 Dog의 메소드가 호출된다.
        // 참조 타입에는 자신의 타입클래스보다 상위 클래스만 올 수 있다.. 
        a1.makeNoise();
        a2.makeNoise();
        
        
    }
 
}
cs


런타임 오류

1
2
3
Exception in thread "main" java.lang.ClassCastException: animal.Animal cannot be cast to animal.Dog
    at animal.DogTest.main(DogTest.java:13)
 
cs


'Java 정리' 카테고리의 다른 글

가비지 컬렉션  (0) 2016.12.19
CH2_ 올바른 값의 반환  (0) 2016.06.16
오버라이딩과 오버로딩  (0) 2016.06.15
오버라이딩과 오버로딩
2016. 6. 15. 11:49 - Daybreak0_0

method overriding


1
2
3
4
5
public class Animal {
    public void eat() {
        System.out.println("Generic Animal Eating Generically");
    }
}
cs

1
2
3
4
5
class Horse extends Animal  {
    public void eat() {
        System.out.println("Horse eating hay, oats, " + "and horse treats");
    }
}
cs

- 슈퍼 클래스로부터 추상 메서드를 상속받은 실체 서브 클래스의 경우 그 메서드를 오버라이딩하여 실행할 코드를 구현해야 한다.
  그렇지 않으면 서브 클래스에서도 추상 메서드를 갖는 것이 되어 서브 클래스가 추상 클래스가 된다. 
  ** 추상 메서드는 반드시 오버라이딩 해야한다. 


- Animal의 모든 서브 클래스들은 각자 자신의 오버라이딩된 eat() 메서드를 가져야한다. 

- Animal 서브 클래스의 인스턴스를 슈퍼 클래스인 Animal 타입의 참조 변수로 참조하면, 그 참조를 통해 eat() 메서드를 호출했을 때,

  그 인스턴스가 속하는 서브 클래스의 eat() 메서드가 다형적으로 실행된다. 


1
2
3
4
5
6
7
8
class TestAnimals  {
    public static void main(String[] args) {
        Animal a = new Animal();
        Animal b = new Horse(); // Animal타입이지만 Horse 객체이다.
        a.eat(); // Animal의 eat()를 실행
        b.eat(); // Horse의 eat()을 실행
    }
}
cs


- Animal 타입의 참조를 통해서 Horse 객체의 메서드를 호출한다. 

- Animal 타입의 참조를 사용할 때는 Animal 클래스에 있는 메서드만 호출이 가능하다 ** 

- 컴파일러는 인스턴스 자신의 타입이 아닌 참조의 타입을 살피며, 런타임 시에는 인스턴스의 타입에 맞는 메서드가 다형적으로 실행된다.

  슈퍼 타입의 참조를 사용해서 그 슈퍼 타입의 서브 타입 인스턴스를 참조할 수 있다.

- 서브 클래스에서 오버라이딩된 메서드의 접근 변경자는 슈퍼 클래서 메서드의 접근 변경자보다 접근 범위가 같거나 더 넓어야 한다. (좁아질수 x)

  예, 슈퍼클래스의 메소드 접근 변경자가 public이면 서브 클래스에서 오버라이딩된 메서드의 접근 변경자를 protected로 할 수 x


## 오버라이딩한 메서드의 슈퍼 클래스 버전을 호출하고 싶다면?

- super 키워드 사용
- super 키워드는 인스턴스 메서드만 호출이 가능하다 (static 메서드는 오버라이드 할 수 없음)

## 오버라이딩을 잘못한 예

잘못 오버라이딩한 코드 

코드의 문제

private void eat() {   } 

슈퍼 클래스의 메서드보다 접근 변경자 범위가 좁다. 

public void eat( ) throws IOException {   } 

슈퍼 클래스 메서드에 선언하지 않은 checked 예외를 선언했다.

public void eat(String food) {  }

인자 목록이 다르므로 오버라이딩이 아닌 오버로딩이 되었다. 

public string eat( ) {   }

반환 타입이 다르므로 오버라이딩이 아니며, 인자 목록이 같으므로 오버로딩도 아니다. 



method overloading


- 하나의 클래스에서 같은 이름의 메서드들을 여러개 가질 수 있는데, 메서드 인자들은 달라야 한다. (반환타입은 같아도 되고 달라도 된다.)

- 인자들의 타입이나 개수가 다르면 컴파일러가 이름이 같더라도 알수 있기 때문이다. ==> 오버로딩된 메서드는 오버라이딩 메서드와 달리 실행할 메서드가 컴파일 시점에서 결정된다. 

- 인자의 타입이나 개수가 달라야 하지만, 타입과 개수가 같으면 순서만 달라도 된다.

- 오버로딩된 메서드들의 접근 변경자도 상관없다. (같든 다르든)


같아야 되는 것 

달라야 되는 것 

상관없음 

메서드 이름

인자의 타입 

반환 타입 

인자 개수

접근 변경자 

 

checked 예외



1
pubic void changeSize(int size, String name, float pattern) {  }
cs


1
2
3
public void changeSize(int size, String name) {  }
public int changeSize(int size, float pattern) {  }
public void changeSize(float pattern, String name) throws IOException {  }
cs





1
2
3
4
5
public class Animal {
    public void eat() {
        System.out.println("Generic Animal Eating Generically");
    }
}
cs

1
2
3
4
5
6
7
8
class Horse extends Animal  {
    public void eat() {
        System.out.println("Horse eating hay");
    }
    public void eat(String s) {
        System.out.println("Horse eating " + s);
    }
}
cs


## 오버로딩을 잘못한 예

오버로딩한 코드 

출력 결과

Animal a = new Animal(); 

a.eat();

Generic Animal Eating Generically

Horse h = new Horse(); 

h.eat(); 

Horse eating hay

Animal ah = new Horse(); 

ah.eat();

Horse eating hay

다형성이 구현된다.

- 참조 타입 (Animal)이 아닌

실제 객체 타입 (Horse)를 기준으로 메서드가 결정됨

Horse h3 = new Horse(); 

h3.eat("apples");

Horse eating hay

Animal a2 = new Animal();

a2.eat("apples");

컴파일 에러!

String을 받는 eat( ) 메서드가 Animal 클래스에 없다.

Animal a3 = new Horse();

a3.eat("Carrot");

컴파일 에러!
컴파일러는 참조 타입을 기준으로, 

String을 인자로 받는 eat() 메서드가 Animal 클래스에 있는지 찾는다. 없으므로 에러. 


## 오버라이딩과 오버로딩의 차이점


 

오버라이딩 

오버로딩 

 인자

반드시 같아야 한다.

반드시 달라야 한다. 

반환 타입

같아야 한다. 

같거나 다를 수 있다. 

예외

슈퍼 클래스의 오버라이딩되는 메서드에 선언한 예외보다 범위가 좁은 예외는 가능, 예외를 추가하거나 범위가 큰 예외를 선언할 수 없다. 

같거나 다를 수 있다. 

접근 변경자

범위가 더 좁은 접근 변경자를 지정할 수 없다. 

같거나 다를 수 있다. 

호출

해당 객체의 타입을 기준으로 런타임 시 결정 

참조 타입을 기준으로 컴파일 시에 결정 


'Java 정리' 카테고리의 다른 글

가비지 컬렉션  (0) 2016.12.19
CH2_ 올바른 값의 반환  (0) 2016.06.16
CH2_참조 변수 Casting  (0) 2016.06.16