我已经看到几个资源谈论静态类型和动态类型之间的区别,以及类型和类之间的区别。然而,与静态类型和动态类进行对话要么是另一回事,要么就是根据我已经知道的事情,我没有足够的概念来解决它。
要给出具体案例,请参考代码
public interface I {}
public class C {}
public class E extends C implements I {}
public class F extends E {}
Object a = new E();
C b = new E();
C c = new F();
正如我目前所理解的那样,静态类型总是由类型注释给出,因此a
具有类型Object而其他类型为C.动态类我不太了解,但我最好的猜测是它始终基于new
类型。因此a
和b
具有动态类E,而c
具有F.我非常感谢任何见解或更正。
答案 0 :(得分:5)
静态类型和动态类型之间的区别
粗略地说,静态类型的语言是那些在编译时已知类型的语言。 动态类型语言是在运行时检查类型的语言。这里有第三类,无类型语言,如forth或assembly。但我们并没有谈论它们。 Java和kotlin是JVM的静态类型语言的示例。 groovy是动态类型的。在这里,阅读有关编程语言类型的this article。
所以,没有"动态类型"在谈论Java时。在程序执行之前,所有类型都已知。你可能被欺骗的是polymorphism。它只是意味着" Car"可以是"卡车"或者" Minivan",动物可以是" Cat"," Dog",甚至是" Snake"。可以有中间类型,例如"哺乳动物"或者"蜥蜴"。但这意味着所有这些事情都有一些共同之处。即"汽车"有轮子(至少截至2017年底,没有太多的飞行汽车)并在道路上行驶。 "动物" ......好吧,"动物"可能是一个坏的,非常通用的例子,但它们的细胞中都含有碳。 "哺乳动物"有热血和蜥蜴" - 冷。你明白了。类型的特定越多,它指定的属性就越多。子类型可以覆盖并指定超类型的属性和方法。在层次结构的最后,有一些具体的可实例化的类,例如" DeLorean DMC-12"或者"阿比西尼亚猫"。
让我们考虑一下汽车。可能存在这样的层次结构:
public interface Car {
String manufacturer();
}
public interface PassengerCar {
Integer numberOfSeats();
}
public interface TimeMachine {
void travelTo(Date destination);
}
public class DMC12 implements PassengerCar {
@Override
public String manufacturer() { return "DeLorean Motor Company"; }
@Override
public Integer numberOfSeats() { return 2; }
}
pubblic class DeLoreanTimeMachine extends DMC12 implements TimeMachine {
private FluxCapacitor fluxCapacitor = new FluxCapacitor();
@Override
public void travelTo(Date destination) { fluxCapacitor.travelTo(destination); }
}
即使在课程下面也有对象。对象是类的具体实例。回到我们的例子,可能有"博士。 Emmett Brown的时间机器",DeLoreanTimeMachine
的实例:
final DeLoreanTimeMachine docsCar = new DeLoreanTimeMachine();
但是,我们知道DeLoreanTimeMachine
仍然是DMC12
汽车,TimeMachine
,PassengerCar
,最后是Car
,所以这些表达式也是有效的:
final DMC12 dmc12 = new DeLoreanTimeMachine();
final TimeMachine timeMachine = new DeLoreanTimeMachine();
final PassengerCar passengerCar = new DeLoreanTimeMachine();
final Car car = new DeLoreanTimeMachine();
区别在于您可以通过此类引用访问的方法集。在静态类型语言中,编译已知的car
类型只是Car
,因此您只需car.manufacturer()
即可。即使它是功能强大的磁通电容器的全功能时间机器,可以帮助您前往1985年,您不能使用(没有额外的技巧)该功能。多么浪费!同样,您只能通过passengerCar
参考知道座位数,只能通过timeMachine
来计算时间等等。
可能有其他类(以及对象)实现和扩展这些接口。在不同的组合。 TARDIS是时间机器,但不是Car
。 Optimus Prime是Car
,Truck
和Transformer
(这些类不在我们的等级中),但他无法穿越时间(可以吗?)。
但是你说的那个伎俩是什么?嗯,他们中的一大堆,用一个术语 reflection 联合起来。你可以用反射做什么?
你可以知道真正的运行时类型并进行演员表演! E.g。
passengerCar instanceOf Car
passengerCar instanceOf TimeMachine
passengerCar instanceOf DMC12
passengerCar instanceOf DeLoreanTimeMachine
一切都是真的!因为实际上我们示例中的passengerCar
是Doc的汽车。即使编译已知的类型是PassengerCar
,它也不允许您从其他类/接口调用方法,您将能够执行此操作:
((DeLoreanTimeMachine) passengerCar).travelTo("Oct. 26, 1985 1:21 A.M");
哇!你只是拆开连续体并前往1985年!快点,上车,注意Lybian恐怖分子!
但这些会因ClassCastException
而失败:
((PassengerCar) tardis).numberOfSeats(); // you'd expect it to be 1 or what?
((TimeMachine) optimusPrime).travelTo("Oct. 26, 1985 1:21 A.M"); // wrong universe, pal
在这里,我们遇到了另一种打字"尺寸"。 强 vs 弱。请记住,Java是强烈(和静态)类型的,并且不允许您这样做(为了您自己的利益)。但是在Groovy中,你可以覆盖methodMissing
并对任何类的任何调用做出回应。也就是说,打字很弱。
关于Java中的类型还有一件事。你应该知道type erasure。它适用于generic types,只是意味着在运行时,对象的类型可以被剥离到Object
(或众所周知的上限),因此,使得变量类型无类型。但是编译器会在泛型的情况下生成一些额外的类型检查和强制转换,这样你就可以了。
类型和类之间的区别
它们几乎相同,但在Java中,您还有primitives,它们是类型,但不是类。但是,它们可以自动包装到相应的类中。有些语言,如ruby将所有内容视为对象,因此具有类类型(无基元)。但是不要过多关注这些概念,并记住它们可以互换使用。
正如我目前所理解的那样,静态类型总是由类型注释
给出动态类我不太了解,但我最好的猜测是它始终基于
new
类型
嗯,是的,我理解你的意思。只需替换"静态类型"类似"编译时间类型"和"动态课"使用"运行时类型"并且你将100%正确。
总结一下:编译时类型是编译器已知的类型,它限制了您可以在源代码中调用的方法集。运行时类型可能不同,但它始终应该是编译时类型的子类型。您可以从运行时类型执行强制转换和访问方法,但可能不安全。类型擦除从字节码中删除泛型类型,但编译器足够智能以插入安全转换和类型检查。