web-dev-qa-db-ja.com

Java)での動的型と静的型の割り当ての違い

次のクラス階層がある場合、次のステートメントの動的タイプと静的タイプは何ですか?

クラス階層:

_class Alpha {}

class Beta extends Alpha {}

class Gamma extends Alpha {}

class Epsilon extends Alpha{}

class Fruit extends Gamma{}

class Golf extends Beta {}

class Orange extends Fruit{}
_

次の各ステートメントについて、静的タイプ?動的タイプ?:

_Fruit f = new Fruit();
Alpha a = f;
Beta b = f;
a = b;
Gamma g = f;
_

私の答え/質問
Fruit f = new Fruit()が静的タイプと動的タイプの両方のFruitになることを理解しています。
_Alpha a = f;_コンパイル時(静的)ではAlphaタイプ、実行時(動的)ではFruitタイプになります。
_Gamma g = f;_コンパイル時(静的)はガンマ型、実行時(動的)はフルーツ型になります。
しかし、私は他の2つの答えを知りません。 Beta b = fは、同じスーパークラスの2つのサブクラスが互いに割り当てられているインスタンスであるため、コンパイル時にBetaタイプかAlphaタイプかはわかりません(静的)。そして、a = bは宣言後の割り当てなので、その答えがどうなるかはわかりません。誰かが私を助けてくれてありがとう!

10
user3088470

私は急いでこれを入力しているので、plsはタイプミスを許します(機会があれば後で修正します)。

Fruit f = new Fruit()は、静的タイプと動的タイプの両方のフルーツになることを理解しています。

_static and dynamic_型という用語をコンパイル時および実行時型と少し混同していると思います(またはC++のように、A型のオブジェクトのアドレスをB型のポインターに割り当て、BがAの親クラス。)

リフレクションのトリックを除けば、Javaには動的型付けはありません。すべてがコンパイル時に静的に型付けされます。実行時のオブジェクトのタイプは、コンパイルされたオブジェクトのタイプと同じです。

何が起こっているのかというと、オブジェクト参照(a、b、c、f)を、ヒープ内でインスタンス化された実際のオブジェクト(newで作成されたもの)と混同しているということです。

Javaでは、fはオブジェクト参照であり、オブジェクト自体ではありません。さらに、fの参照型は_Fruit and sub-classes of it_です。割り当てたオブジェクト(new Fruit())は、たまたまタイプFruitです。

これで、サンプルコード内の他のすべての参照は、タイプ_reference to A and sub-classes of it_です。 bはタイプ_reference to B and sub-classes of it_です。などなど。

非常に重要なので、これを覚えておいてください。

アルファa = f;コンパイル時(静的)はAlphaタイプ、実行時(動的)はFruitタイプになります。

aはタイプ 'Aおよびサブクラスへの参照'です。 fは、タイプ 'フルーツおよびサブクラス'への参照です。

Fが指すオブジェクトは「Fruit」タイプです。 「a = f」と言うときは、「f」を「a」に割り当てていません。あなたは「aはfが現在参照しているものを参照する」と言っています。

それで、その割り当ての後、aは何を参照していますか?タイプFruitのオブジェクトオブジェクト参照fは割り当て時に指していました。

A、b、g、f、これらはオブジェクトではないことを忘れないでください。これらは、new演算子を使用して何らかの方法で作成されたオブジェクトへの参照またはハンドルです。

A、b、fなどの参照変数は、newで作成されたオブジェクトとは異なる獣です。しかし、前者が後者を指すことができるのはたまたまです。

実行時にnewで作成されたオブジェクトのタイプは、コンパイル時に決定されたものと同じです。

ガンマg = f;コンパイル時(静的)はガンマタイプ、実行時(動的)はフルーツタイプになります。

同上。変数gは、タイプ_reference to type Gamma and sub-classes_のオブジェクト参照です。この割り当てでは、gは、fが指す同じオブジェクトを指すように作成されます。そのオブジェクトのタイプは何ですか?コンパイル時に与えられたものと同じ:Fruit。

しかし、私は他の2つの答えを知りません。 Beta b = fは、同じスーパークラスの2つのサブクラスが互いに割り当てられているインスタンスであるため、コンパイル時にBetaタイプかAlphaタイプかはわかりません(静的)。

bのタイプは_reference to type Beta and sub-classes of it_です。割り当て_b = f_の後に指すオブジェクトは、コンパイル時に持っていたタイプであるFruitタイプです。

  1. オブジェクト参照のタイプa、b、g、およびfは、コンパイル時に決定されます。それらは静的に型付けされ、実行時に変更されません。

  2. newで作成されたオブジェクトのタイプも、コンパイル時に決定されます。また、静的に型付けされ、実行時に変更されません。

  3. オブジェクト、stuffオブジェクトが参照するa、b、g、およびfは、実行時を指します。これは、ステートメントがコンパイラーによって有効であるかどうかによって決定されます。割り当ては変更できますが、それはオブジェクト参照またはオブジェクト自体が静的に型指定されているか動的に型指定されているかとは関係ありません。

動的型付けと静的型付けを明確に区別したい場合は、次のことを考慮してください。

_// Java, statically typed.
int x = 3;
x = 5; // good
x = "hi"; // compiler error

## Ruby, dynamically typed
x = 3 # ok
x = 5 # ok
x = "hi" # still ok
_

次に、強く型付けされた言語と弱く/ダック型の言語(どちらも動的に型付けできます)には違いがあります。この主題に関する文献はたくさんあります。

それが役に立てば幸い。

13
luis.espinal

次のステートメントの動的型と静的型

えーと、ステートメントには型がありません。少なくともJava言語仕様にはそのような概念はありません。仕様では2つの異なる種類の型が定義されています:宣言された型変数、フィールド、またはパラメータの、およびランタイムクラスオブジェクトの。

名前が示すように、変数、フィールド、またはパラメーターの宣言されたタイプは、宣言で言及するタイプです。たとえば、宣言Foo bar;は、タイプbarFooという名前の変数を宣言します。

オブジェクトのランタイムクラスは、オブジェクトの構築に使用されたクラスインスタンスまたは配列作成式によって決定され、そのオブジェクトの存続期間を通じて同じままです。

したがって、コード:

Integer i = 1;
Number n = i;
Object o = n;

タイプIntegerNumber、およびObjectの3つの変数を宣言します。これらはすべて、ランタイムクラスIntegerを持つ単一のオブジェクトを参照します。

3
meriton

fの具体的な実行時タイプはFruitです(質問で正しく述べたように)。

したがって、Beta b = f;は、宣言されたコンパイル時の型がBetaで、実行時の型がFruitである変数を初期化します。ただし、fのコンパイル時の型はFruitであり、FruitはBetaのサブクラスではないため、これはコンパイルされません。したがって、fをBeta型の変数に割り当てることはできません。 。

a = b;では、ランタイムタイプがFruit(上記を参照)であるbが、Alpha aとして宣言された変数aに割り当てられます。したがって、aのコンパイル時の型はAlphaであり、実行時型はFruitです。

2
JB Nizet

最初に「参照変数」タイプを明確にします。

Object obj;

何も指さず、参照変数objはNOタイプになります。今

Object obj = new String();
System.out.println(obj.getClass());//prints class Java.lang.String

objは文字列を指し、参照変数objのタイプはStringです。

ポイントはJavaは静的に型付けされた言語であり、すべての参照型変数にはコンパイル時に割り当てられた型があります。参照変数objは、Objectのサブクラスである限り、他のオブジェクトを指すことができます。 。この場合、ほとんど何でも。

Object obj = new String();
System.out.println(obj.getClass());//prints class Java.lang.String
Number num = new Byte((byte)9);
obj = num;
System.out.println(obj.getClass());//prints class Java.lang.Byte

実行時、コンパイル時と同じように、参照変数objの型はByteです。

私にとって、オブジェクトの静的/動的タイプは継承と関係があります。より具体的には、オーバーライドメカニズム。動的ポリモーフィズムおよび遅延バインディングとも呼ばれます。

クラスObjectのequals()をオーバーライドすることを検討してください。

public class Types {

    @Override
    public boolean equals(Object obj){
        System.out.println("in class Types equals()");
        return false;//Shut-up compiler!
    }

    public static void main(String[] args){
        Object typ = new Types();
        typ.equals("Hi");//can do this as String is a subclass of Object
    }
}

これで、参照変数typのタイプがTypesであることがわかりました。

Object typ = new Types();

それになると

typ.equals("Hi");

これがコンパイラの考え方です。

Equals()が

1.静的で最終的なものではありません。

2.基本クラスから参照されます(これについてはすぐに詳しく説明します)。

次に、コンパイラはどのメソッドがJVMに呼び出されるかを延期します。呼び出される正確なメソッドは、メソッドを呼び出す変数のDynamic Type(もっとすぐに)によって異なります。この場合、参照変数はtypです。これは、動的メソッド呼び出しとして知られています。

基本クラスから参照されるようになりました:上記のコードから

Object typ = new Types();
typ.equals("Hi");

Type Objectは、typの基本型と見なすことができます。これは参照変数のStatic Typeとも呼ばれ、equals()は基本から参照されます。タイプ、この場合はオブジェクト。

私たちが持っていた場合

Types typ = new Types();

基本タイプからの参照がないため、動的メソッド呼び出しはありません。

次に、参照変数の動的タイプに移ります。

Object typ = new Types();
typ.equals("Hi");

TypのDynamic TypeはTypesであり、Dynamic Method Invocationによれば、クラスTypesのequals()は実行時に呼び出されます。

また、Typesを拡張する別のクラスTypesSubClassがあったとしましょう。また、TypesSubClassにはオーバーライドされたequals()もありました。次に

Object typ = new TypesSubClass();
typ.equals("Hi");

TypのTypesSubClassのDynamic Typeが作成され、TypesSubClassのequals()が実行時に呼び出されます。

正直なところ、私は個人的になぜこれらすべてが必要なのかわからず、これに関する質問を投稿しました。小切手

Javaのような静的に型付けされた言語での動的メソッド解決の背後にある理由は何ですか

2
Clive Ferreira

この記事をご覧ください: http://www.sitepoint.com/typing-versus-dynamic-typing/

静的型付けとは、言語が変数の初期化を必要としない場合です。

例えば。

/* C code */ 
static int num, sum; // explicit declaration 
num = 5; // now use the variables 
sum = 10; 
sum = sum + num;

動的型付けとは、言語で変数の初期化が必要な場合です。

例えば。

/* Python code */ 
num = 10 // directly using the variable
0
Adjit