Answers:
类型安全性意味着编译器将在编译时验证类型,如果尝试将错误的类型分配给变量,则会引发错误。
一些简单的例子:
// Fails, Trying to put an integer in a string
String one = 1;
// Also fails.
int foo = "bar";
这也适用于方法参数,因为您要将显式类型传递给它们:
int AddTwoNumbers(int a, int b)
{
return a + b;
}
如果我尝试使用以下方式致电:
int Sum = AddTwoNumbers(5, "5");
编译器将引发错误,因为我传递的是字符串(“ 5”),并且期望使用整数。
在一种松散类型的语言(例如javascript)中,我可以执行以下操作:
function AddTwoNumbers(a, b)
{
return a + b;
}
如果我这样称呼它:
Sum = AddTwoNumbers(5, "5");
Javascript自动将5转换为字符串,并返回“ 55”。这是由于javascript使用+号进行字符串连接。要使其具有类型意识,您需要执行以下操作:
function AddTwoNumbers(a, b)
{
return Number(a) + Number(b);
}
或者,可能:
function AddOnlyTwoNumbers(a, b)
{
if (isNaN(a) || isNaN(b))
return false;
return Number(a) + Number(b);
}
如果我这样称呼它:
Sum = AddTwoNumbers(5, " dogs");
Javascript自动将5转换为字符串,并将其附加,以返回“ 5条狗”。
并非所有动态语言都像javascript一样宽容(实际上,动态语言并不隐含暗示使用松散类型的语言(请参阅Python)),其中一些实际上会在无效类型转换时给您带来运行时错误。
尽管它很方便,但是它使您容易陷入很多错误,而这些错误只有通过测试正在运行的程序才能发现。就个人而言,我更愿意让编译器告诉我是否犯了这个错误。
现在,回到C#...
C#支持称为covariance的语言功能,这基本上意味着您可以将基本类型替换为子类型,而不会引起错误,例如:
public class Foo : Bar
{
}
在这里,我创建了一个新类(Foo),该类继承了Bar。我现在可以创建一个方法:
void DoSomething(Bar myBar)
并使用Foo或Bar作为参数来调用它,两者都将起作用而不会引起错误。之所以可行,是因为C#知道Bar的任何子类都将实现Bar的接口。
但是,您不能做相反的事情:
void DoSomething(Foo myFoo)
在这种情况下,我无法将Bar传递给此方法,因为编译器不知道Bar实现Foo的接口。这是因为子类可以(并且通常会)与父类大不相同。
当然,现在我已经走了很远,超出了原始问题的范围,但是所有要了解的好东西:)
类型安全不应与静态/动态类型或强/弱类型混淆。
类型安全的语言是一种只能对数据执行的操作是数据类型所允许的操作。也就是说,如果您的数据属于类型X
并且X
不支持操作y
,那么该语言将不允许您执行y(X)
。
这个定义并不在制定规则时,这个被选中。它可以在编译时(静态类型)或在运行时(动态类型),通常通过异常。两者可能有点:某些静态类型化的语言允许您将数据从一种类型转换为另一种类型,并且必须在运行时检查转换的有效性(假设您尝试Object
将a转换Consumer
为a-编译器没有知道是否可以接受的方式)。
类型安全性也不一定意味着强类型化-某些语言臭名昭著地弱类型化,但仍然可以说是类型安全的。以Javascript为例:它的类型系统虽然很弱,但仍然严格定义。它允许在正确定义的规则内自动转换数据(例如,将字符串转换为整数)。据我所知,没有一种情况会导致Javascript程序以未定义的方式运行,并且如果您足够聪明(我不是),您应该能够预测读取Javascript代码时会发生什么。
类型不安全的编程语言的一个示例是C:根据规范,在数组范围之外读取/写入数组值具有未定义的行为。无法预测会发生什么。C是具有类型系统但不是类型安全的语言。
类型安全性不仅是编译时约束,而且是运行时约束。我觉得即使经过了所有这些时间,我们仍可以对此进行进一步的说明。
有两个与类型安全有关的主要问题。内存**和数据类型(及其相应的操作)。
甲char
通常需要每个字符1个字节,或8位(取决于需要16个比特的语言,Java和C#存储Unicode字符)。An int
需要4个字节或32位(通常)。
视觉上:
char: |-|-|-|-|-|-|-|-|
int : |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
类型安全的语言不允许在运行时将int插入到char中(这会引发某种类强制转换或内存不足异常)。但是,使用一种类型不安全的语言,您将在内存的另外3个相邻字节中覆盖现有数据。
int >> char:
|-|-|-|-|-|-|-|-| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?|
在上述情况下,右边的3个字节将被覆盖,因此任何期望获得可预测的char值的指向该内存的指针(例如3个连续的char)现在都将具有垃圾。这会导致undefined
程序中的行为(或更糟糕的是,可能会在其他程序中,具体取决于操作系统如何分配内存-如今极不可能)。
** 尽管第一个问题从技术上讲并不是关于数据类型的,但类型安全语言从本质上解决了该问题,并且它向那些不了解内存分配“外观”的人直观地描述了该问题。
更细微和直接的类型问题是两种数据类型使用相同的内存分配。取一个int vs一个未签名的int。两者均为32位。(就像一个char [4]和一个int一样容易,但是更常见的问题是uint vs. int)。
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
一种类型不安全的语言允许程序员引用正确分配的32位跨度,但是当将无符号int的值读入int的空间时(反之亦然),我们仍然有undefined
行为。想象一下这可能在银行程序中引起的问题:
“老兄!我透支了30美元,现在我剩下65,506美元!!”
当然,银行程序使用更大的数据类型。;) 大声笑!
正如其他人已经指出的那样,下一个问题是对类型的计算操作。这已经被充分覆盖。
如今,除非使用了C或C ++之类的东西,否则当今大多数程序员都不必担心这些事情。这两种语言都允许程序员在运行时轻松地违反类型安全性(直接内存引用),尽管编译器已尽最大努力将风险降到最低。但是,这还不是全部。
这些语言计算速度如此之快的一个原因是,它们不会在运行时操作(例如Java)中验证类型兼容性而负担沉重。他们认为开发人员是一个很好的理性者,不会将字符串和int一起添加,为此,开发人员将获得速度/效率的回报。
此处的许多答案将类型安全与静态类型和动态类型相结合。动态类型语言(如smalltalk)也可以是类型安全的。
一个简单的答案:如果没有一种操作导致未定义的行为,则该语言被视为类型安全的。许多人认为必须对语言进行严格类型化才能使用显式类型转换,因为自动转换有时会导致定义明确但出乎意料/不直观的行为。
if no operation leads to undefined behavior
。
来自文科专业而不是自然科学专业的解释:
当人们说某种语言或某种语言功能具有类型安全性时,这意味着该语言将帮助您防止例如将非整数的内容传递给需要整数的某些逻辑。
例如,在C#中,我将函数定义为:
void foo(int arg)
然后,编译器将阻止我执行此操作:
// call foo
foo("hello world")
在其他语言中,编译器不会阻止我(或没有编译器...),因此会将字符串传递给逻辑,然后可能会发生错误。
类型安全的语言会尝试在“编译时”捕获更多信息。
不利的一面是,在使用类型安全语言的情况下,当您拥有像“ 123”这样的字符串并且想要像int一样对其进行操作时,您必须编写更多代码以将字符串转换为int,或者当您拥有int例如123,并且想在“答案是123”之类的消息中使用它,则必须编写更多代码才能将其转换/转换为字符串。
为了更好地理解,请观看下面的视频,该视频以安全语言(C#)类型而不是安全语言(javascript)演示代码。
http://www.youtube.com/watch?v=Rlw_njQhkxw
现在为长文本。
类型安全意味着防止类型错误。当一种类型的数据类型被未知地分配给另一种类型时,会发生类型错误,并且我们会得到不希望的结果。
例如,JavaScript不是一种类型安全的语言。在下面的代码中,“ num”是数字变量,“ str”是字符串。Javascript允许我执行“ num + str”,现在GUESS可以执行算术或串联运算。
现在,对于下面的代码,结果为“ 55”,但重要的是混淆造成了它将执行何种操作。
发生这种情况是因为javascript不是一种类型安全的语言。它允许无限制地将一种数据类型设置为另一种数据类型。
<script>
var num = 5; // numeric
var str = "5"; // string
var z = num + str; // arthimetic or concat ????
alert(z); // displays “55”
</script>
C#是一种类型安全的语言。不允许将一种数据类型分配给另一种数据类型。以下代码不允许对不同数据类型使用“ +”运算符。
类型安全意味着以编程方式,变量,返回值或自变量的数据类型必须符合特定条件。
实际上,这意味着7(整数类型)与“ 7”(字符串类型的带引号的字符)不同。
PHP,Javascript和其他动态脚本语言通常是弱类型的,因为如果您尝试添加“ 7” + 3,它们会将(字符串)“ 7”转换为(整数)7,尽管有时您必须这样做显式(并且Javascript使用“ +”字符进行串联)。
C / C ++ / Java不会理解这一点,或者会将结果串联为“ 73”。类型安全性通过明确类型要求来防止代码中的此类错误。
类型安全性非常有用。上面的“ 7” + 3的解决方案是键入强制转换(int)“ 7” + 3(等于10)。
请尝试以下解释...
TypeSafe意味着在编译时会静态检查变量是否适当分配。例如,考虑字符串或整数。这两种不同的数据类型不能交叉分配(即,您不能将整数分配给字符串,也不能将字符串分配给整数)。
对于非类型安全行为,请考虑以下因素:
object x = 89;
int y;
如果您尝试这样做:
y = x;
编译器将引发错误,提示它无法将System.Object转换为Integer。您需要明确地执行此操作。一种方法是:
y = Convert.ToInt32( x );
上面的分配不是类型安全的。类型安全分配是类型可以直接彼此分配的位置。
在ASP.NET中,存在大量非类型安全的集合(例如,应用程序,会话和视图状态集合)。关于这些集合的好消息是(最小化了多个服务器状态管理注意事项)您可以在这三个集合中的任何一个中放置几乎任何数据类型。坏消息:由于这些集合不是类型安全的,因此在取回它们时需要适当地强制转换值。
例如:
Session[ "x" ] = 34;
工作良好。但是要分配整数值,您需要:
int i = Convert.ToInt32( Session[ "x" ] );
阅读有关泛型的内容,以帮助您轻松实现类型安全的集合。
C#是一种类型安全的语言,但请注意有关C#4.0的文章。有趣的动态可能性隐约可见(C#本质上实现Option Strict:Off ...这将是一件好事)。
类型安全意味着可以分配给程序变量的一组值必须符合定义良好且可测试的条件。类型安全的变量会导致程序更健壮,因为操作变量的算法可以相信该变量将只使用一组定义良好的值。保持这种信任可确保数据和程序的完整性和质量。
对于许多变量,可以在编写程序时定义可以分配给变量的一组值。例如,可以允许一个名为“ colour”的变量取值“ red”,“ green”或“ blue”,而不能取其他任何值。对于其他变量,这些条件可能会在运行时更改。例如,一个名为“ colour”的变量只能被允许采用关系数据库中“ Colours”表的“ name”列中的值,其中“ red”,“ green”和“ blue”是三个值“颜色”表中“名称”的名称,但是计算机程序的其他部分可能可以在程序运行时添加到该列表中,并且变量在将新值添加到“颜色”表中后可以采用新值。
许多类型安全语言通过坚持严格定义变量的类型并仅允许为变量分配相同“类型”的值来给人“类型安全”的假象。这种方法存在两个问题。例如,一个程序可能具有一个变量“ yearOfBirth”,即一个人的出生年份,因此很容易将其类型转换为一个短整数。但是,它不是短整数。今年,该数字小于2009并且大于-10000。但是,随着程序的运行,此集合每年增加1。将其设置为“ short int”是不够的。确保此变量类型安全的是运行时验证功能,该功能可确保该数字始终大于-10000且小于下一个日历年。
使用动态类型(或鸭子类型或清单类型)的语言(例如Perl,Python,Ruby,SQLite和Lua)没有类型变量的概念。这迫使程序员为每个变量编写运行时验证例程,以确保其正确或承受无法解释的运行时异常的后果。以我的经验,使用诸如C,C ++,Java和C#之类的静态类型语言的程序员经常会陷入沉闷,他们认为,静态定义类型是他们从类型安全中获得好处所要做的全部工作。对于许多有用的计算机程序而言,这根本不是事实,并且很难预测对于任何特定计算机程序而言是否如此。
多头与空头...。您想要类型安全吗?如果是这样,则编写运行时函数以确保在为变量分配值时,它符合定义明确的条件。不利的一面是,对于大多数计算机程序而言,域分析确实非常困难,因为您必须为每个程序变量明确定义条件。