Kathe sierra의 SCJP 6 책을 살펴보고 재정의 된 메서드에서 예외를 던지는이 설명을 발견했습니다. 나는 그것을 이해하지 못했다. 아무도 나에게 설명 할 수 있습니까?
재정의 메서드는 재정의 된 메서드에 의해 선언 된 것보다 새롭거나 광범위한 검사 된 예외를 throw해서는 안됩니다. 예를 들어 FileNotFoundException을 선언하는 메서드는 FileNotFoundException의 하위 클래스가 아닌 한 SQLException, Exception 또는 기타 비 런타임 예외를 선언하는 메서드로 재정의 할 수 없습니다.
답변
즉, 메서드가 주어진 예외를 throw하도록 선언하면 하위 클래스의 재정의 메서드는 해당 예외 또는 해당 하위 클래스 만 throw하도록 선언 할 수 있습니다. 예를 들면 :
class A {
public void foo() throws IOException {..}
}
class B extends A {
@Override
public void foo() throws SocketException {..} // allowed
@Override
public void foo() throws SQLException {..} // NOT allowed
}
SocketException extends IOException
,하지만 SQLException
그렇지 않습니다.
이것은 다형성 때문입니다.
A a = new B();
try {
a.foo();
} catch (IOException ex) {
// forced to catch this by the compiler
}
경우 B
던져하기로 한 SQLException
다음, 컴파일러는 당신의 인스턴스를 참조하고 있기 때문에 당신이 그것을 잡으려고 강요하지 수 B
는 슈퍼 클래스 – A
. 반면에의 모든 하위 클래스 IOException
는 다음을 처리하는 절 (catch 또는 throws)에 의해 처리됩니다.IOException
수퍼 클래스로 객체를 참조 할 수 있어야하는 규칙은 Liskov Substitution Principle입니다.
확인되지 않은 예외는 어디에서나 throw 될 수 있으므로이 규칙이 적용되지 않습니다. 원할 경우 문서 형식으로 throws 절에 확인되지 않은 예외를 추가 할 수 있지만 컴파일러는 이에 대해 어떤 것도 강제하지 않습니다.
답변
재정의 메서드는 재정의 된 메서드가 예외를 선언하는지 여부에 관계없이 확인되지 않은 (런타임) 예외를 throw 할 수 있습니다.
예:
class Super {
public void test() {
System.out.println("Super.test()");
}
}
class Sub extends Super {
@Override
public void test() throws IndexOutOfBoundsException {
// Method can throw any Unchecked Exception
System.out.println("Sub.test()");
}
}
class Sub2 extends Sub {
@Override
public void test() throws ArrayIndexOutOfBoundsException {
// Any Unchecked Exception
System.out.println("Sub2.test()");
}
}
class Sub3 extends Sub2 {
@Override
public void test() {
// Any Unchecked Exception or no exception
System.out.println("Sub3.test()");
}
}
class Sub4 extends Sub2 {
@Override
public void test() throws AssertionError {
// Unchecked Exception IS-A RuntimeException or IS-A Error
System.out.println("Sub4.test()");
}
}
답변
제 생각에는 Java 구문 설계의 실패입니다. 다형성은 예외 처리의 사용을 제한해서는 안됩니다. 실제로 다른 컴퓨터 언어는이를 수행하지 않습니다 (C #).
더욱이 메서드는 더 특수화 된 하위 클래스에서 재정의되므로 더 복잡하고 이러한 이유로 새 예외를 throw 할 가능성이 더 높습니다.
답변
재정의 메서드가 여기에 아무것도 던질 수 없다는 사실을 알려주는 대답이 없기 때문에 여기에이 대답을 제공합니다 . 재정의 메서드가 던질 수 있는 내용은 다음과 같습니다.
1) 동일한 예외 발생
public static class A
{
public void m1()
throws IOException
{
System.out.println("A m1");
}
}
public static class B
extends A
{
@Override
public void m1()
throws IOException
{
System.out.println("B m1");
}
}
2) 재정의 된 메서드의 throw 된 예외의 하위 클래스를 throw합니다.
public static class A
{
public void m2()
throws Exception
{
System.out.println("A m2");
}
}
public static class B
extends A
{
@Override
public void m2()
throws IOException
{
System.out.println("B m2");
}
}
3) 아무것도 던지지 않습니다.
public static class A
{
public void m3()
throws IOException
{
System.out.println("A m3");
}
}
public static class B
extends A
{
@Override
public void m3()
//throws NOTHING
{
System.out.println("B m3");
}
}
4) throws에서 RuntimeExceptions가 필요하지 않습니다.
throws에 RuntimeExceptions가 있거나 없을 수 있으며 컴파일러는 그것에 대해 불평하지 않습니다. RuntimeExceptions는 확인 된 예외가 아닙니다. 잡히지 않은 경우 확인 된 예외 만 throw에 나타나야합니다.
답변
이를 설명하기 위해 다음을 고려하십시오.
public interface FileOperation {
void perform(File file) throws FileNotFoundException;
}
public class OpenOnly implements FileOperation {
void perform(File file) throws FileNotFoundException {
FileReader r = new FileReader(file);
}
}
그런 다음 다음과 같이 작성한다고 가정합니다.
public class OpenClose implements FileOperation {
void perform(File file) throws FileNotFoundException {
FileReader r = new FileReader(file);
r.close();
}
}
r.close ()가 FileNotFoundException보다 광범위한 IOException을 발생시키기 때문에 컴파일 오류가 발생합니다.
이 문제를 해결하려면 다음을 작성하십시오.
public class OpenClose implements FileOperation {
void perform(File file) throws IOException {
FileReader r = new FileReader(file);
r.close();
}
}
perform (…) 오퍼레이션을 구현하고 있지만 인터페이스의 메소드 정의에 포함되지 않은 예외가 발생하므로 다른 컴파일 오류가 발생합니다.
이것이 왜 중요한가요? 인터페이스 소비자는 다음을 가질 수 있습니다.
FileOperation op = ...;
try {
op.perform(file);
}
catch (FileNotFoundException x) {
log(...);
}
IOException이 발생하도록 허용 된 경우 클라이언트의 코드가 더 이상 정확하지 않습니다.
확인되지 않은 예외를 사용하는 경우 이러한 종류의 문제를 피할 수 있습니다. (나는 당신이 할 것인지 말 것인지를 제안하는 것이 아닙니다. 그것은 철학적 문제입니다)
답변
인터뷰 질문을하겠습니다. 슈퍼 클래스에서 NullPointerException을 발생시키는 메서드가 있습니다. RuntimeException을 발생시키는 메소드로 재정의 할 수 있습니까?
이 질문에 답하려면 Unchecked 및 Checked 예외가 무엇인지 알려주십시오.
-
확인 된 예외는 기본 try-catch-finally 예외 처리에 설명 된대로 명시 적으로 포착되거나 전파되어야합니다. 확인되지 않은 예외에는이 요구 사항이 없습니다. 그들은 잡히거나 던져 질 필요가 없습니다.
-
Java에서 확인 된 예외는 java.lang.Exception 클래스를 확장합니다. 확인되지 않은 예외는 java.lang.RuntimeException을 확장합니다.
공용 클래스 NullPointerException은 RuntimeException을 확장합니다.
확인되지 않은 예외는 java.lang.RuntimeException을 확장합니다. 이것이 NullPointerException이 Uncheked 예외 인 이유입니다.
예를 들어 보겠습니다. 예 1 :
public class Parent {
public void name() throws NullPointerException {
System.out.println(" this is parent");
}
}
public class Child extends Parent{
public void name() throws RuntimeException{
System.out.println(" child ");
}
public static void main(String[] args) {
Parent parent = new Child();
parent.name();// output => child
}
}
프로그램이 성공적으로 컴파일됩니다. 예 2 :
public class Parent {
public void name() throws RuntimeException {
System.out.println(" this is parent");
}
}
public class Child extends Parent{
public void name() throws NullPointerException {
System.out.println(" child ");
}
public static void main(String[] args) {
Parent parent = new Child();
parent.name();// output => child
}
}
프로그램도 성공적으로 컴파일됩니다. 따라서 확인되지 않은 예외의 경우 아무 일도 일어나지 않음이 분명합니다. 이제 Checked 예외의 경우 어떤 일이 발생하는지 살펴 보겠습니다. 예제 3 : 기본 클래스와 자식 클래스가 모두 확인 된 예외를 throw하는 경우
public class Parent {
public void name() throws IOException {
System.out.println(" this is parent");
}
}
public class Child extends Parent{
public void name() throws IOException{
System.out.println(" child ");
}
public static void main(String[] args) {
Parent parent = new Child();
try {
parent.name();// output=> child
}catch( Exception e) {
System.out.println(e);
}
}
}
프로그램이 성공적으로 컴파일됩니다. 예제 4 : 기본 클래스의 동일한 메서드와 비교하여 자식 클래스 메서드에서 테두리 확인 예외가 발생하는 경우.
import java.io.IOException;
public class Parent {
public void name() throws IOException {
System.out.println(" this is parent");
}
}
public class Child extends Parent{
public void name() throws Exception{ // broader exception
System.out.println(" child ");
}
public static void main(String[] args) {
Parent parent = new Child();
try {
parent.name();//output=> Compilation failure
}catch( Exception e) {
System.out.println(e);
}
}
}
프로그램이 컴파일되지 않습니다. 따라서 Checked 예외를 사용할 때주의해야합니다.
답변
메서드 M1이 E1을 던지는 슈퍼 클래스 A와 메서드 M2가 M1을 재정의하는 A에서 파생 된 클래스 B가 있다고 가정합니다. M2는 E1과 다르거 나 덜 전문화 된 것을 던질 수 없습니다.
다형성 때문에 클래스 A를 사용하는 클라이언트는 B를 A 인 것처럼 취급 할 수 있어야합니다. Inharitance ===> Is-a (B is-a A). 클래스 A를 다루는이 코드가 예외 E1을 처리하고 있었다면, M1이 선언 한대로이 체크 된 예외를 던졌지 만 다른 유형의 예외가 던졌습니다. M1이 IOException을 던지는 경우 M2는 IOException이므로 FileNotFoundException을 던질 수 있습니다. A의 클라이언트는 문제없이 이것을 처리 할 수 있습니다. 던져진 예외가 더 넓다면, A의 클라이언트는 이것에 대해 알 기회가 없으므로 그것을 잡을 기회가 없을 것입니다.