[출처] 자바의 정석 3판 연습문제 Chapter 7

 

 

정답)

Product 클래스의 기본 생성자를 추가해줘야 한다.

Product() {} 추가

 

풀이)

Product를 상속 받은 Tv클래스의 기본 생성자에서 Product의 기본생성자를 호출하게 되는데 Product는 이미 기본생성자 외에 다른 생성자가 존재하므로 컴파일러가 자동으로 기본생성자를 생성해주지 않는다.

따라서 Product의 기본생성자가 존재하지 않아 에러가 발생한다.

그러므로 Product의 기본생성자를 추가해줘야 문제가 해결된다.

 

정답)

Child() -> Child(int x) -> Parent() -> Parent(int x) -> Object()의 순서로 호출된다.

생성자의 첫 줄에 다른 생성자를 호출하지 않으면 조상의 기본 생성자를 호출하기 때문에 Child(int x)의 생성자 첫 줄에 super(); 이 추가되어 실행된다.

ParentChild의 조상이므로 super(); Parent()를 호출하게 되어 Parent(int x)를 실행하게 되는데 Parent(int x)도 첫 줄에 생성자가 없으므로 super(); , Object()를 추가하게 되어 실행하게 된다.

 

이제 x의 값을 따져보면,

Child(1000)에서 Child 클래스의 인스턴스변수 x1000이 되고 Parent 클래스의 인스턴스변수 x200이 된다.

getX()는 조상인 Parent클래스에 정의된 것이라서, getX()에서 xParent클래스의 인스턴스변수 x를 의미하게 되어 c.getX()를 출력하게 되면 200이 나온다.

 

정답)

class MyTv2 {
private boolean isPowerOn;
private int channel;
private int volume;
private int prevchannel;
final int MAX_VOLUME = 100;
final int MIN_VOLUME = 0;
final int MAX_CHANNEL = 100;
	final int MIN_CHANNEL = 1;
	
public void setChannel(int channel) {
	if(channel<MIN_CHANNEL || channel>MAX_CHANNEL)
		return;
	prevchannel = this.channel;
	this.channel=channel;
}
public int getChannel() {
	return channel;
}
public void setVolume(int volume) {
	if(volume<MIN_VOLUME || volume>MAX_VOLUME)
		return;
	this.volume=volume;
}
public int getVolume() {
	return volume;
}
public void gotoPrevChannel() {
	setChannel(prevchannel);
}

}
public class Practice {
	
	public static void main(String[] args) {
		MyTv2 t = new MyTv2();

		t.setChannel(10);
		System.out.println("CH:"+t.getChannel());
		t.setChannel(20);
		System.out.println("CH:"+t.getChannel());
		t.gotoPrevChannel();
		System.out.println("CH:"+t.getChannel());
		t.gotoPrevChannel();
		System.out.println("CH:"+t.getChannel());

	
	}

}

풀이)

 

 

이전 채널의 값을 저장할 멤버변수 prevchannel을 정의하고

 

기존 setChannel 메소드에서 채널을 바꾸기 전에 이전 채널을 저장하는 코드를 추가해줌.

prevchannel = this.channel; 를 추가

 

 

그리고 MyTv2 클래스에 다음의 메소드를 추가함

public void gotoPrevChannel() {
	setChannel(prevchannel);
}

 

 

정답)

p.x = 100;

Child Method

c.x = 200;

Child Method

 

풀이)

타입은 다르지만 참조변수 p, c 모두 Child 인스턴스를 참조하고 있다.

메소드인 method()의 경우 참조변수의 타입에 관계없이 항상 실제 인스턴스의 타입인 Child클래스에 정의된 메소드(오버라이딩 된 메소드)가 호출된다.

하지만 멤버변수의 경우 참조변수의 타입에 따라 달라진다.

 

따라서 p.xParent에 정의된 x의 값을 출력하게 되고 c.xChild에 정의된 x의 값을 출력하게 된다.

메소드는 동일하게 오버라이딩 된 메소드를 호출하게 된다.

 

 

정답)

class Circle extends Shape {
	double r;
	double calcArea() {
		return r*r*Math.PI;
	}
	Circle (double r) {
		this (new Point(0,0), r);
	}

	Circle (Point p, double r) {
		super(p);
		this.r=r;
	}
}
class Rectangle extends Shape {
	double width;
	double height;
	double calcArea() {
		return width*height;
	}
	boolean isSquare() {
		boolean a = width==height ? true : false;
		return a;
	}
	Rectangle (double width, double height) {
		this(new Point(0,0), width, height);
	}
	Rectangle(Point p, double width, double height) {
		super(p);
		this.width=width;
		this.height=height;
	}
}

풀이)

생성자를 만드는데 유의할 점이 있다.

일단 생성자의 첫 줄에는 반드시 생성자를 호출해야 하며, 만약 생성자를 호출하지 않으면 자동으로 컴파일러가 super();를 추가하게 된다는 점이다.

그리고 조상의 멤버는 조상의 생성자를 호출해서 초기화를 해줘야 한다.

 

그래서 매개변수로 조상의 멤버인 p를 초기화 시키기 위해 두 메소드 다 조상의 생성자를 호출해서 따로 p를 초기화 시켜주었다.

 

 

정답)

class Outer {
	class Inner {
		int iv=100;
	}
}

public class Practice {
	
	public static void main(String[] args) {
		Outer o = new Outer();
		Outer.Inner a = o.new Inner();
		System.out.println(a.iv);

	}

}

풀이)

내부 클래스(인스턴스 클래스)의 인스턴스를 생성하기 위해서는 먼저 외부클래스의 인스턴스를 생성해야 한다. (인스턴스 멤버를 사용하기 위해서 인스턴스를 생성하듯이)

외부클래스의 인스턴스를 만든 후, 이제 내부클래스의 인스턴스를 생성하여 iv를 출력하면 된다.

 

(간단한 문제지만 나중에 보면 문법을 헷갈릴 것 같은 문제)

 
 

 

정답)

class Outer {
	static class Inner {
		int iv=200;
	}
}

public class Practice {
	
	public static void main(String[] args) {
		Outer.Inner a = new Outer.Inner();
		System.out.println(a.iv);

	}

}

 

풀이)

내부 static 클래스는 외부클래스의 인스턴스를 생성하지 않고도 사용할 수 있다.

따라서 내부 static 클래스의 인스턴스만 만들어서 iv를 출력하면 된다.

 

(간단한 문제지만 나중에 보면 문법을 헷갈릴 것 같은 문제)

 

 

 

정답)

 

class Outer {
	int value=10;
	class Inner {
		int value=20;
		void method1() {
			int value=30;
			System.out.println(value);
			System.out.println(this.value);
			System.out.println(Outer.this.value);
			}
	} // Inner클래스의 끝
	
} // Outer클래스의 끝

public class Practice {
	
	public static void main(String[] args) {
		Outer o = new Outer();
		Outer.Inner inner = o.new Inner();
		
		inner.method1();
	}

}

풀이) 외부 클래스와 내부 클래스 및 내부 클래스의 메소드에 선언된 같은 이름의 변수를 어떻게 구별하는가에 대한 문제이다.

 

내부 클래스의 메소드에 사용된 value는 일반적인 상황처럼 value 그대로 사용하면 된다.

내부 클래스에 정의된 변수 valuethis.value로 접근하면 되고

외부 클래스에 정의된 변수 valueOuter.this.value로 접근할 수 있다.

 

 

(간단한 문제지만 나중에 보면 문법을 헷갈릴 것 같은 문제)

 

정답)

import java.awt.*;
import java.awt.event.*;

public class Practice {
	public static void main(String[] args) {
		Frame f = new Frame();
		f.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				e.getWindow().setVisible(false);
				e.getWindow().dispose();
				System.exit(0);
			}
		});
	}

}

풀이)

익명 클래스를 사용하는 방법을 알아야 한다.

 

조상 클래스나 구현 인터페이스의 이름을 빌려서 정의함과 동시에 인스턴스를 만들어 사용한다.

문제에서 보면 EventHandler 클래스의 조상이 WindowAdapter임을 알 수 있으므로

WindowAdapter의 인스턴스를 생성하면서 바로 멤버도 정의하면 된다.

 

 

 

 

 

 

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

 

정답) 지역 변수는 메소드가 종료되면 같이 사라지지만 상수는 메소드가 종료되어도 constant pool에 저장되어 있기 때문에 계속 사용할 수 있어서,

지역 클래스의 인스턴스에서 사용하기 위해 상수를 사용한다.

 

[출처] 자바의 정석 3판 연습문제 Chapter 7

 

+ Recent posts