9 장. 생성자와가비지컬렉션 학습목표 스택과힙지역변수와인스턴스변수객체생성과생성자객체제거 ( 가비지컬렉션 )
객체의삶과죽음 그리고그가말했어. 다리에감각이없어! 그리고내가말했지. 조! 정신차려조! 하지만이미너무늦었어. 가비지컬렉터가나타났고그는죽고말았지. 내가만나본가장좋은객체였는데말야
스택과힙 스택 (stack) 메소드호출과지역변수가사는곳 지역변수는스택변수라고도부릅니다. 힙 (heap) 모든객체가사는곳 인스턴스변수는객체안에들어있습니다. go() dostuff() main() Dog 객체 Snowboard 객체 Button 객체
인스턴스변수와지역변수 인스턴스변수 (instance variable) 클래스내에서선언한변수 그변수가속한객체안에서삽니다. public class Duck { int size; 지역변수 (local variable) 메소드내에서선언한변수 매개변수도지역변수에포함됩니다. public void foo(int x) { int i = x + 3; boolean b = true;
스택과메소드 메소드를호출하면메소드는호출스택 (call stack) 맨위에올라갑니다. 스택맨위에있는메소드는그스택에서현재실행중인메소드입니다. 메소드는그끝을나타내는중괄호에다다를때까지스택에머무릅니다. foo() 라는메소드에서 bar() 라는메소드를호출하면 bar() 메소드가 foo() 위에얹힙니다. bar() foo() s x i b
스택과메소드 public void dostuff() { boolean b = true; go(4); public void go(int x) { int z = x + 24; crazy(); public void crazy() { char c = a ; dostuff() b go() x z dostuff() b crazy() go() c x z dostuff() b go() x z dostuff() b
지역변수로쓰이는객체는? 원시변수가아닌변수에는객체에대한레퍼런스가들어있습니다. 지역변수가객체레퍼런스인경우에는변수 ( 레퍼런스 ) 만스택에들어갑니다. 객체자체는여전히힙안에들어있습니다. public class StackRef { public void foof() { barf(); public void barf() { Duck d = new Duck(24); barf() foof() d Duck 객체
바보같은질문은없습니다 이런내용을왜배우는거죠? 변수영역, 객체생성문제, 메모리관리, 스레드, 예외처리등을이해하는데있어서스택과힙에관한내용은필수적입니다. 특정 JVM, 플랫폼에서스택과힙을구현하는방법은몰라도됩니다. 일단스택과힙에대해이해하고나면다른내용을이해하는것이한결수월해집니다.
핵심정리 자바에서우리가관심을가져야할메모리공간에는힙과스택, 이렇게두가지가있습니다. 클래스안에서, 하지만메소드밖에서선언된변수는인스턴스변수입니다. 메소드안에서선언된변수, 또는매개변수는지역변수입니다. 모든지역변수는스택에들어있으며그변수를선언한메소드에해당하는프레임안에들어있습니다. 객체레퍼런스변수도지역변수라면스택에저장됩니다. 모든객체는힙에저장됩니다.
인스턴스변수는어디에? x y int long public class CellPhone { private Antenna ant; CellPhone 객체 public class CellPhone { private Antenna ant = new Antenna(); ant Antenna CellPhone 객체 ant Antenna Antenna 객체 CellPhone 객체
객체선언, 생성, 대입 Duck myduck = new Duck(); 1. 레퍼런스변수선언 Duck myduck = new Duck(); myduck Duck 레퍼런스
객체선언, 생성, 대입 Duck myduck = new Duck(); 2. 객체생성 Dog myduck = new Duck(); Duck 객체
객체선언, 생성, 대입 Duck myduck = new Duck(); 3. 객체와레퍼런스연결 Dog mydog = new Dog(); myduck Duck 객체 Duck 레퍼런스
메소드? 생성자! Dog myduck = new Duck(); 생성자 (Constructor) 객체를생성할때실행되는코드가들어있습니다. 모든클래스에생성자가있습니다. 직접만들지않아도컴파일러에서자동으로생성자를만들어줍니다. public Duck() { // 생성자코드가들어갈자리
생성자예제 public class Duck { public Duck() { System.out.println( Quack ); public class UseADuck { public static void main(string[] args) { Duck d = new Duck(); % java UseADuck Quack
객체의상태를초기화하는방법 객체의상태를초기화하는작업은대부분생성자에서처리합니다. public Duck() { size = 34; Duck 을사용하는프로그래머가오리의크기를결정하도록하려면? public class Duck { public Duck() { System.out.println( Quack ); public void setsize(int newsize) { size = newsize; public class UseADuck { public static void main(string[] args) { Duck d = new Duck(); d.setsize(34);
바보같은질문은없습니다 컴파일러에서자동으로만들어주는데왜생성자를따로만들어야하나요? 객체초기화작업및각종준비작업이필요하다면생성자를따로만들어야합니다. 객체를완전히만들기전에사용자로부터뭔가를입력받는다거나하는경우에는생성자가반드시필요합니다. 상위클래스생성자문제로인해초기화및준비작업이필요하지않은경우에도생성자를만들어야할수도있습니다.
바보같은질문은없습니다 메소드와생성자를어떻게구분할수있나요? 그리고클래스와이름이같은메소드를만들수있나요? 가능합니다. 클래스와같은이름을가지고있다고해서무조건생성자가되는것은아닙니다. 생성자와메소드는리턴유형유무로구분합니다. 생성자에는리턴유형이없어야하고메소드에는리턴유형이있어야만합니다. public Duck() { public int Duck() {
바보같은질문은없습니다 생성자도상속되나요? 상위클래스에서만생성자를만들고하위클래스에서생성자를만들지않으면기본생성자대신상위클래스의생성자가쓰이나요? 아닙니다. 생성자는상속되지않습니다. 이와관련된내용은잠시후에살펴보겠습니다.
생성자를이용한초기화 인스턴스변수가초기화되기전까지객체를사용해선안된다면생성자에서초기화하면됩니다. public class Duck { int size; public Duck(int ducksize) { System.out.println( Quack ); size = ducksize; System.out.println( size is + size); public class UseADuck { public static void main(string[] args) { Duck d = new Duck(42); % java UseADuck Quack size is 42
인자가없는생성자 인자가있는생성자만있으면사용하기가불편합니다. 기본크기가자동으로정해지는인자가없는 Duck 생성자를만들면편하지않을까요? public class Duck { int size; public Duck(int newsize) { if (newsize == 0) { size = 27; else { size = newsize; public class Duck2 { int size; public Duck2() { size = 27; public Duck2(int ducksize) { size = ducksize; Duck2 d = new Duck2(15); Duck2 d = new Duck2();
인자가없는생성자 인자가없는생성자는컴파일러에서자동으로만들어주지않나요? 아닙니다. 컴파일러에서는생성자가전혀없는경우에만생성자를자동으로만들어줍니다. 인자가있는생성자를만들었을때인자가없는생성자도필요하다면인자가없는생성자도직접만들어야합니다. 한클래스에생성자가두개이상있으면각생성자의인자목록은반드시서로달라야합니다.
생성자오버로딩 두개이상의생성자가필요하다면생성자오버로딩을사용하면됩니다. 각생성자의인자목록은서로달라야만합니다. Public class Mushroom { public Mushroom(int size) { public Mushroom( ) { public Mushroom(boolean ismagic) { public Mushroom(boolean ismagic, int size) { public Mushroom(int size, boolean ismagic) {
핵심정리 인스턴스변수는그변수가들어있는객체안에저장됩니다. 인스턴스변수가레퍼런스변수인경우에는레퍼런스와객체가모두힙에저장됩니다. new 키워드를사용할때실행되는코드를생성자라고합니다. 생성자명은반드시클래스명과같아야하며리턴유형은없어야합니다. 생성자를이용하여객체의상태 ( 인스턴스변수 ) 를초기화할수있습니다. 클래스에생성자가없으면컴파일러에서기본생성자를만듭니다. 기본생성자에는인자가없습니다. 생성자를하나라도만들면컴파일러에서기본생성자를만들어주지않습니다.
핵심정리 인자가없는생성자를만들고싶은데인자가있는생성자가따로있다면인자가없는생성자도손수만들어야합니다. 가능하면인자가없는생성자도만드는것이좋습니다. 생성자오버로딩을활용하면한클래스에두개이상의생성자를만들수있습니다. 오버로드된생성자들의인자목록은반드시서로달라야합니다. 인자목록이똑같은생성자가두개이상있을수없습니다. 인스턴스변수에는자동으로기본값이지정됩니다. 원시유형의기본값은 0/0.0/false 이며객체에대한레퍼런스의기본값은 null 입니다.
바보같은질문은없습니다 기본값을지정할수없기때문에인자가없는생성자를만들지않아야하는경우는없나요? 물론적당한기본값이없는경우에는인자가없는생성자를만드는것이무의미할수도있습니다. 예 ) Color 클래스 Color c = new Color(3, 45, 200); Color c = new Color(); cannot resolve symbol : constructor Color() location: class java.awt.color Color c = new Color(); ^ 1 error
생성자에대해반드시알아야할네가지 1. 생성자는누군가가어떤클래스유형에대해 new 를쓸때실행되는코드입니다. Duck d = new Duck(); 2. 생성자명은반드시클래스명과같아야하며리턴유형은없습니다. public Duck(int size) { 3. 클래스를만들때생성자를만들지않으면컴파일러에서기본생성자를자동으로추가해줍니다. 기본생성자는언제나인자가없는생성자입니다. public Duck() {
생성자에대해반드시알아야할네가지 4. 인자목록만다르면한클래스에생성자를여러개만들수도있습니다. 한클래스에두개이상의생성자가있으면오버로드된생성자가있다고말합니다. public Duck() { public Duck(int size) { public Duck(String name) { public Duck(String name, int size) { public Duck(int size, String name) {
바보같은질문은없습니다 생성자는반드시 public 이어야하나요? 아닙니다. 생성자도 public, private, default 로지정할수있습니다. private 생성자는어떤용도로쓰나요? 아무도그생성자를호출할수없으면그생성자를가지고새로운객체를만들수없지않나요? 그렇진않습니다. 클래스 밖에서 접근할수없을뿐입니다. 즉같은클래스안에있는코드에서는그생성자를사용할수있습니다.
상위클래스와상속, 생성자사이의관계 Object Foo a; int b; int c; equals() getclass() hashcode() tostring() x y z a b c Snowboard Foo x; Foo y; int z; turn() shred() getair() losecontrol() Object Snowboard Snowboard 객체
상위클래스생성자의역할 Object x y k s v Animal a b c Object Hippo Animal Hippo Hippo 객체 생성자연쇄 (constructor chaining)
생성자연쇄 public class Animal { public Animal() { System.out.println( Making an Animal ); public class Hippo extends Animal { public Hippo() { System.out.println( Making a Hippo ); % java TestHippo Starting Making an Animal Making a Hippo public class TestHippo { public static void main(string[] args) { System.out.println( Starting ); Hippo h = new Hippo(); Hippo() Animal() Hippo() Object() Animal() Hippo() Animal() Hippo()
상위클래스생성자호출방법 public class Duck extends Animal { int size; public Duck(int newsize) { Animal(); size = newsize; public class Duck extends Animal { int size; public Duck(int newsize) { super(); size = newsize;
상위클래스생성자 1. 생성자를만들지않은경우컴파일러에서다음과같은내용을추가합니다. public ClassName() { super(); 생성자를만들긴했는데 super() 를호출하지않은경우컴파일러에서 super() 를자동으로추가해줍니다. super();
super() 호출선언문의위치 자식이있으려면반드시부모가먼저있어야합니다. 마찬가지로상위클래스생성이끝나야만하위클래스생성이끝날수있습니다. super() 를호출하는선언문은모든생성자의첫번째선언문이어야합니다. public Boo() { super(); public Boop(int i) { super(); size = i; public Boop() { public Boop(int i) { size = i; public Boop(int i) { size = i; super();
인자가있는상위클래스생성자 public abstract class Animal { private String name; public String getname() { return name; public Animal(String thename) { name = thename; public class Hippo extends Animal { public Hippo(String name) { super(name); public class MakeHippo { public static void main(string[] args) { Hippo h = new Hippo( Buffy ); System.out.println(h.getName()); Animal private String name Animal(String n) String getname() Hippo Hippo(String n) (Hippo 용메소드 ) % java MakeHippo Buffy
오버로드된생성자호출방법 같은클래스에있는다른생성자를호출할때는 this() 를쓰면됩니다. this() 는생성자에서만호출할수있으며반드시그생성자의첫번째선언문이어야만합니다. super() 와 this() 를동시에호출할수는없습니다. class Mini extends Car { Color color; public Mini() { this(color.red); public Mini(Color c) { super( Mini ); color = c; public Mini(int size) { this(color.red); super(size); % javac Mini.java Mini.java:16: call to super must be first statement in constructor super(); ^
객체의생존기갂 지역변수 그변수를선언한메소드안에서만살수있음 public void read() { int s = 42; 인스턴스변수 객체가살아있는동안살수있음 public class Life { int size; public void setsize(int s) { size = s;
지역변수의삶과영역 삶 (life) 지역변수는스택프레임이스택에들어있는한계속살아있습니다. 영역 (scope) 지역변수의영역은그변수를선언한메소드내로제한됩니다. public void dostuff() { boolean b = true; go(4); public void go(int x) { int z = x + 24; crazy(); public void crazy() { char c = a ; crazy() c go() x z go() x z go() x z dostuff() b dostuff() b dostuff() b dostuff() b
레퍼런스변수의삶 마지막레퍼런스가사라지면그객체는가비지컬렉션대상이됩니다. 객체레퍼런스제거방법 void go() { Life z = new Life(); 레퍼런스가영역을벗어남 Life z = new Life(); z = new Life(); 다른객체대입 Life z = new Life(); z = null; 레퍼런스를 null 로설정
숙제 본문을꼼꼼하게읽어보세요. 본문에들어있는연필을깎읍시다, 두뇌운동등을전부여러분힘으로해결해보세요. 연습문제를모두풀어보세요. 퍼즐도해보는것이좋습니다.