Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ganesh_JavaSE7_Programming_1z0-804_study_guide.pdf
Скачиваний:
94
Добавлен:
02.02.2015
Размер:
5.88 Mб
Скачать

Chapter 3 Java Class Design

// override toString method as well public String toString() {

return super.toString() + ", z = " + zPos;

}

// to test if we extended correctly, call the toString method of a Point3D object public static void main(String []args) {

System.out.println(new Point3D(10, 20, 30));

}

}

In the class Point2D, the class members xPos and yPos are private, so you cannot access them directly to initialize them in the Point3D constructor. However, you can call the superclass constructor using super keyword and pass the arguments. Here, super(10, 20); calls the base class constructor Point2D(int, int). This call to the superclass constructor should be the first statement; if you call it after zPos = z;, you’ll get a compiler error:

public Point3D(int x, int y, int z) { zPos = z;

super(10, 20);

}

Point3D.java:19: call to super must be first statement in constructor super(10, 20);

Similarly, you can invoke the toString() method of the base class Point2D in the toString() implementation of the derived class Point3D using the super keyword.

Type Conversions

Java is a strongly-typed language: it performs strict type checking to ensure that you are doing only valid conversions. If you perform some obvious invalid casts, the compiler will give a compiler error. If the compiler doesn’t catch an invalid cast, it will result in a runtime problem or exception. As a result, you need to be careful when performing type conversions.

Upcasts and Downcasts

You can assign derived objects to base type references without performing any explicit casts: this is upcasting. Conversely, if you need to put it back to the derived ones, you will need an explicit cast: this is downcasting. Let’s examine these two types of casts in detail using simple examples.

In Java, every class derives from the Object base class. Therefore, you can put any object into an Object reference and it will never fail.

String str1 = "Hello world";

Object obj = str1; // no explicit cast needed – such conversions will never fail

But if you convert from the Object reference to some derived type—say String—it can fail. Why? Because, in general, an Object reference can hold an object of any type and it might not be the type you are downcasting to.

String str2 = obj;

74

Chapter 3 Java Class Design

For this statement, you’ll get this error:

compiler error - incompatible types found : java.lang.Object required: java.lang.String

To fix this, you need to use an explicit downcast to String, like so:

String str2 = (String) obj;

When you are performing such explicit type casts (downcasts), it is your responsibility to ensure that the downcast is valid. Otherwise, you’ll get a runtime exception. Consider the program in Listing 3-19. Can you tell its output?

Listing 3-19.  Downcast.java

// Code to understand how downcast can fail class Downcast {

public static void main(String []args) { Integer i = new Integer(10);

//upcast - its fine and will always succeed Object obj = i;

//downcast - will it succeed? What will happen when it fails? String str = (String) obj;

}

}

This program crashes with a runtime exception of

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

at Downcast.main(Downcast.java:6)

In this program, you first made the Integer variable i to point to a variable obj of type Object. Such a type conversion is an upcast, so it is fine because such a conversion will always succeed. Now, when you try to convert the Object type variable to String type, it is a downcast. The compiler does not know about the dynamic type of the object pointed to by the obj variable (you know that the dynamic type of the variable pointed to by obj is of type Integer). With an explicit typecast, you force the compiler to make the conversion from Object type to String type.

Because an Integer type cannot be converted to String type, the downcast fails by throwing a ClassCastException.

Upcasts will always succeed, so you don’t have to worry about them. However, downcasts may fail with runtime exception, so you need to be careful when downcasting.

Unlike downcasts, invalid casts can be detected by the compiler itself. We’ll discuss this topic next.

75

Chapter 3 Java Class Design

Casting Between Inconvertible Types

Both String and StringBuffer inherit from Object class. But you cannot directly cast from String to StringBuffer and vice versa. For example, someone can write a code like the following by mistake:

Object obj = new StringBuffer("Hello"); String str2 = (String) obj;

The compilation succeeds, but this cast fails at runtime:

'Exception in thread "main" java.lang.ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.String'.

In this case, you first put a StringBuffer object into an Object type and then tried casting back to String. How about a direct conversion from StringBuffer to String? Will it lead to a compiler error/warning or a runtime exception?

String str = (String) new StringBuffer("Hello");

You get a compiler error because it is not possible to cast from StringBuffer to String:

Cast.java:4: inconvertible types found : java.lang.StringBuffer required: java.lang.String

Now how about this statement where the target type is StringBuffer but the intermediate cast is String?

StringBuffer str = (String) new StringBuffer("Hello");

You still get the same compiler error because it is not possible to cast from StringBuffer to String. This brings us to an important question. How do you know if an invalid cast results in a compiler error or a runtime exception?

If the compiler can use only the static type information of the source and target types and thus infer it as an invalid cast, it becomes a compiler error. If the success/failure of the cast depends on the dynamic type of the object, the compiler cannot predict the result of the cast. In those cases, it becomes a runtime exception.

Using “instanceof” for Safe Downcasts

If a ClassCastException is thrown while executing a program, and if there are no exception handlers for that, the program will terminate. So, how about providing an exception handler like this?

try {

StringBuffer str = new StringBuffer("Hello"); Object obj = str;

String strBuf = (String) obj;

}

catch(ClassCastException e) {

// ignore exception – we don't want program to crash because of this!!!

}

Yes, this will work and the program will not crash. But this is a really bad idea! There are two main problems in this code.

76

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]