Javaでオブジェクトをキャストすることの意味について混乱しています。
あなたが持っていると言う...
Superclass variable = new Subclass object();
(Superclass variable).method();
ここで何が起きてるの?変数のタイプは変化しますか、それとも変化する変数内のオブジェクトですか?非常に混乱。
このサンプルをご覧ください:
public class A {
//statements
}
public class B extends A {
public void foo() { }
}
A a=new B();
//To execute **foo()** method.
((B)a).foo();
スーパークラスFruitとサブクラスBananaがあり、メソッドaddBananaToBasket()があるとします
このメソッドはgrapesを受け入れないため、バスケットにバナナを追加していることを確認する必要があります。
そう:
Fruit myFruit = new Banana();
((Banana)myFruit).addBananaToBasket();
⇐これはキャストと呼ばれます
参照している例は、Javaでのアップキャストと呼ばれます。
スーパークラス変数を指すサブクラスオブジェクトを作成します。
変数は変化せず、スーパークラスの変数のままですが、サブクラスのオブジェクトを指します。
たとえば、MachineとCameraの2つのクラスがあるとします。カメラはMachineのサブクラスです
class Machine{
public void start(){
System.out.println("Machine Started");
}
}
class Camera extends Machine{
public void start(){
System.out.println("Camera Started");
}
public void snap(){
System.out.println("Photo taken");
}
}
Machine machine1 = new Camera();
machine1.start();
上記のステートメントを実行すると、それを指すMachineクラスの参照を使用してCameraクラスのインスタンスが作成されます。したがって、出力は "Camera Started"になります。変数はまだMachineの参照ですクラス。 machine1.snap();
を試みると、コードはコンパイルされません。
ここでのポイントは、CameraはMachineのサブクラスですが、すべてのMachineはCameraではないため、CameraはすべてMachineです。したがって、サブクラスのオブジェクトを作成し、スーパークラスの参照を指すことができますが、スーパークラスの参照にサブクラスオブジェクトのすべての機能を実行するよう要求することはできません(この例ではmachine1.snap()
はコンパイルしません)。スーパークラス参照は、スーパークラスが知っている関数(この例ではmachine1.start()
)のみにアクセスできます。マシンリファレンスにスナップを依頼することはできません。 :)
Superclass variable = new subclass object();
これは、サブクラス型のオブジェクトを作成するだけですが、スーパークラス型に割り当てます。すべてのサブクラスのデータは作成されますが、変数はサブクラスのデータ/関数にアクセスできません。つまり、メソッドを呼び出したり、サブクラスに固有のデータにアクセスしたりすることはできず、スーパークラスのものにのみアクセスできます。
ただし、スーパークラス変数をサブクラスにキャストし、そのメソッド/データを使用できます。
クラスAをスーパークラス、クラスBのサブクラスとして持っているとしましょう。
public class A {
public void printFromA(){
System.out.println("Inside A");
}
}
public class B extends A {
public void printFromB(){
System.out.println("Inside B");
}
}
public class MainClass {
public static void main(String []args){
A a = new B();
a.printFromA(); //this can be called without typecasting
((B)a).printFromB(); //the method printFromB needs to be typecast
}
}
時々、引数として親参照を受け取りたいと思うでしょう、そして、あなたはおそらく子供に特定の何かをしたいでしょう。
abstract class Animal{
public abstract void move();
}
class Shark extends Animal{
public void move(){
swim();
}
public void swim(){}
public void bite(){}
}
class Dog extends Animal{
public void move(){
run();
}
public void run(){}
public void bark(){}
}
...
void somethingSpecific(Animal animal){
// Here you don't know and may don't care which animal enters
animal.move(); // You can call parent methods but you can't call bark or bite.
if(animal instanceof Shark){
Shark shark = (Shark)animal;
shark.bite(); // Now you can call bite!
}
//doSomethingSharky(animal); // You cannot call this method.
}
...
上記の方法では、SharkまたはDogのいずれかを渡すことができますが、次のようなものがある場合はどうなりますか:
void doSomethingSharky(Shark shark){
//Here you cannot receive an Animal reference
}
そのメソッドは、サメの参照を渡すことによってのみ呼び出すことができます。したがって、Animal(そして、それは深くShark)を持っている場合、次のように呼び出すことができます:
Animal animal...
doSomethingSharky((Shark) animal)
一番下の行は、親参照を使用できます。通常、親の実装を気にせず、キャストを使用して特定のオブジェクトとして子を使用すると、まったく同じオブジェクトになりますが、参照はそれを知っています、キャストしない場合、参照は同じオブジェクトを指しますが、どの種類のAnimalであるかはわかりません。そのため、既知のメソッドを呼び出すことしかできません。
この例では、スーパークラス変数は、サブクラスオブジェクトにスーパークラスのメソッドを実装するように指示しています。これは、Javaオブジェクト型のキャストの場合です。ここで、method()関数は元々スーパークラスのメソッドですが、スーパークラス変数は、スーパークラスに存在しないサブクラスオブジェクトの他のメソッドにアクセスできません。
たとえば、AnimalスーパークラスとCatサブクラスがあるとします。サブクラスにspeak()があるとしましょう。方法。
class Animal{
public void walk(){
}
}
class Cat extends Animal{
@Override
public void walk(){
}
public void speak(){
}
public void main(String args[]){
Animal a=new Cat();
//a.speak(); Compile Error
// If you use speak method for "a" reference variable you should downcast. Like this:
((Cat)a).speak();
}
}
場合によっては、コレクション内またはコレクション内に存在する要素またはオブジェクトの型を保証できない場合があります。検索の強制時に型キャストを実行する必要があります。そうしないと、コンパイル時エラーが発生します。
配列は常にタイプセーフです。つまり、配列内に存在する要素のタイプを保証できます。型の安全性を実現するには、型キャストを使用する必要があります。