Разница между объектом a = new Dog() vs Dog a = new Dog()
object a = new Dog();
против
Dog a = new Dog();
В обоих случаях a.GetType()
дает Dog
.
Оба ссылаются на тот же конструктор (с той же иерархией).
Тогда, пожалуйста, скажите мне разницу между этими двумя утверждениями?
Ответы
Ответ 1
Оба создают объект Dog. Только второй позволяет вам напрямую ссылаться на методы Собаки или иначе обращаться с ним как с собакой, например, если вам нужно передать объект методу в качестве параметра типа Dog
(или что-то в иерархии Собаки, которая является более конкретной чем просто object
).
object obj = new Dog();
// can only see members declared on object
var type = obj.GetType(); // can do this
Console.WriteLine(obj.ToString()); // also this
obj.Bark(); // Error! Bark is not a member of System.Object
Dog dog = new Dog();
// can do all of the methods declared for Object
dog.Bark(); // can finally use the method defined for Dog
Ответ 2
new Dog()
- это выражение, которое создает новый экземпляр Dog
. Он вызывает безразмерный конструктор класса Dog
.
a
- это переменная: ячейка памяти в памяти, которая содержит ссылку на экземпляр Dog
после назначения.
Разница в том, что переменная Dog
может содержать только ссылку на экземпляр Dog
(или экземпляр любого класса, который происходит от Dog
), в то время как переменная object
может содержать ссылку на object
экземпляр (или экземпляр любого класса, который выводится из object
), который имеет класс Dog
).
Если у вас есть переменная Dog
, вы можете вызвать любой метод, определенный классом Dog
(и его базовые классы) в ссылочном экземпляре. Когда у вас есть переменная object
, вы можете вызывать только методы класса object
в экземпляре.
Ответ 3
Ваша первая строка создает переменную типа object
.
Компилятор не позволит вам рассматривать это как Dog
.
Ответ 4
Оба оператора содержат объявление и вызов конструктора. Вызовы конструктора идентичны, поэтому вы получаете Dog
в обоих случаях. Объявления различны: в первом случае вы объявляете переменную типа object
, суперкласс из Dog
; во втором случае вы объявляете переменную типа Dog
. Разница в том, что в следующем коде вы можете вызывать методы Dog
без приведения только тогда, когда вы объявляете переменную как Dog
; если вы объявите его как object
, вам понадобится бросок.
Ответ 5
Оба оператора включают вызов конструктора по умолчанию Dog
, как вы сами указываете; поэтому очевидно, что в обоих случаях создается экземпляр Dog
. Это означает, что оба оператора завершают инициализацию переменной с идентичным экземпляром (это является частью инструкции после равных).
Однако в операторах также есть другая часть: объявление переменной (это часть выражения перед равными). В статически типизированных языках, таких как С#, каждая переменная - в общем, любое выражение - имеет статический тип:
object a = new Dog(); // static type: object / runtime type: Dog
Dog b = new Dog(); // static type: Dog / runtime type: Dog
Компилятор не позволит вам присваивать значение переменной, которую он не может доказать, имеет переменный статический тип, например. это не позволило бы
Cat c = new Dog(); // unless Dog derives from Cat, which we know isn't true
Поскольку все ссылочные типы неявно вытекают из System.Object
, присвоение переменной Dog
переменной статического типа object
ОК. Вы можете думать о "статическом типе" как о том, что объект "объявлен как". Вы всегда можете определить статический тип чего-либо, просто прочитав исходный код; это то, как это делает компилятор.
Затем также существует тип среды выполнения каждой переменной (выражение), о которой я говорил выше. В обоих случаях это одно и то же, потому что в обоих случаях мы создали Dog
. Вы можете думать о "типе времени выполнения" как о том, что на самом деле представляет собой объект. Тип времени выполнения не может быть определен только путем чтения источника; вы определяете его только во время работы программы, отсюда и название. В С# это делается путем вызова GetType
.
Должно быть очевидно, что тип времени выполнения - это то, что вы не можете сделать без 1; все должно "быть" в конце концов. Но зачем беспокоиться о том, чтобы изобрести понятие статического типа?
Вы можете думать о статических типах в качестве контракта между вами (программистом) и компилятором. Объявив статический тип b
Dog
, вы сообщаете компилятору, что вы не собираетесь использовать эту переменную для хранения чего-либо иного, кроме Dog
. Компилятор, в свою очередь, promises, чтобы вы не нарушили заявленную цель и не сделали ошибку, если попытаетесь это сделать. Это также предотвращает использование d
любым способом, который должен поддерживать не каждый тип Dog
.
Рассмотрим:
class Dog {
public void Woof();
}
Dog d = new Dog();
d.Woof(); // OK
object o = new Dog();
o.Woof(); // COMPILER ERROR
Последняя строка вызывает ошибку компилятора, так как она нарушает договор статической типизации: вы сказали компилятору, что o
может быть чем-либо, происходящим из System.Object
, но не все вещи, вытекающие из этого, имеют метод Woof
, Поэтому компилятор пытается защитить вас, сказав: "Что вы там делаете? Я не могу доказать, что все, что находится в o
, может woof! Что, если это был Cat
?".
Примечания:
¹ Это не означает, что каждый объект волшебным образом знает, что он "есть" на всех языках. В некоторых случаях (например, в С++) эта информация может использоваться при создании объекта, но затем "забывается", чтобы позволить компилятору больше свободы для оптимизации кода. Если это произойдет, объект все еще есть что-то, но вы не можете его высунуть и спросить его "кто вы?".
² На самом деле, в этом тривиальном примере это может доказать. Но он не захочет использовать эти знания, потому что соблюдение контракта статического типа - это целая точка.
Ответ 6
Это полезно, если вы хотите использовать полиморфизм, и вы можете использовать абстрактный метод, который реализуется в Dog. Следовательно, таким образом объект является Собакой, даже так есть Object. Поэтому вы можете использовать этот способ, когда хотите использовать полиморфизм.