“类型安全”是什么意思?
当前回答
类型安全意味着在编程上,变量、返回值或参数的数据类型必须符合特定的标准。
实际上,这意味着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;
编译器抛出一个错误,表示它不能转换一个系统。对象转换为整数。你需要明确地这样做。一种方法是:
y = Convert.ToInt32( x );
上面的赋值不是类型安全的。类型安全赋值是指类型可以直接相互赋值。
非类型安全的集合在ASP。NET(例如,应用程序、会话和视图状态集合)。关于这些集合的好消息是(尽量减少多个服务器状态管理方面的考虑),您可以在这三个集合中的任何一个中放入几乎任何数据类型。坏消息是:因为这些集合不是类型安全的,所以在取回值时需要适当地强制转换。
例如:
Session[ "x" ] = 34;
工作很好。但是要将整数值赋回,你需要:
int i = Convert.ToInt32( Session[ "x" ] );
阅读泛型,了解该工具帮助您轻松实现类型安全集合的方式。
c#是一种类型安全语言,但请关注有关c# 4.0的文章;有趣的动态可能性正在逼近(c#实际上得到了严格的选项:关闭,这是一件好事吗?我们将会看到)。
类型安全意味着编译器将在编译时验证类型,如果试图将错误的类型赋值给变量,则抛出错误。
一些简单的例子:
// 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#支持一种叫做协方差的语言特性,这基本上意味着你可以用基类型替换子类型,而不会导致错误,例如:
public class Foo : Bar
{
}
在这里,我创建了一个新类(Foo),它是Bar的子类。我现在可以创建一个方法:
void DoSomething(Bar myBar)
并使用Foo或Bar作为参数调用它,两者都不会引起错误。这是因为c#知道Bar的任何子类都将实现Bar的接口。
然而,你不能做相反的事情:
void DoSomething(Foo myFoo)
在这种情况下,我不能将Bar传递给这个方法,因为编译器不知道Bar实现了Foo的接口。这是因为子类可以(而且通常会)与父类有很大不同。
当然,现在我已经走得太远了,超出了最初问题的范围,但知道这些都是好事:)
类型安全不仅是编译时约束,也是运行时约束。我觉得即使过了这么久,我们也可以进一步明确这一点。
与类型安全相关的主要问题有两个。内存**和数据类型(与其对应的操作)。
内存* *
一个字符通常需要每个字符1个字节,或者8位(取决于语言,Java和c#存储unicode字符需要16位)。 int需要4个字节,或32位(通常)。
视觉:
字符 : |-|-|-|-|-|-|-|-|
int : |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
类型安全语言不允许在运行时将int类型插入到char类型中(这会抛出某种类型的类强制转换或内存溢出异常)。但是,在一种类型不安全的语言中,您将覆盖现有数据的相邻内存多3个字节。
Int >> char:
|-|-|-|-|-|-|-|-| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?|
在上面的例子中,右边的3个字节被覆盖,所以任何指向该内存的指针(比如3个连续的字符),希望得到一个可预测的char值现在都是垃圾。这将导致您的程序中出现未定义的行为(或者更糟,可能会在其他程序中出现,这取决于操作系统如何分配内存——目前不太可能)。
**虽然第一个问题在技术上不是关于数据类型的,但类型安全语言固有地解决了这个问题,并且它向那些不知道内存分配“看起来”如何的人直观地描述了这个问题。
数据类型
更微妙和直接的类型问题是两种数据类型使用相同的内存分配。取int型和unsigned int型。两者都是32位。(也可以是char[4]和int,但更常见的问题是uint vs. int)。
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
类型不安全语言允许程序员引用正确分配的32位span,但当将无符号整型的值读入整型的空间时(反之亦然),我们再次遇到未定义的行为。想象一下这可能会给银行项目带来的问题:
“伙计!我透支了30美元,现在我还剩65,506美元!!”
...当然,银行程序使用更大的数据类型。,)哈哈!
正如其他人已经指出的,下一个问题是对类型的计算操作。这一点已经得到了充分的讨论。
速度vs安全
今天的大多数程序员都不需要担心这些事情,除非他们使用的是C或c++之类的东西。这两种语言都允许程序员在运行时轻易地违反类型安全(直接内存引用),尽管编译器尽最大努力将风险降至最低。然而,这也不全是坏事。
这些语言计算速度如此之快的一个原因是它们不需要像Java那样在运行时操作期间验证类型兼容性。他们认为开发人员是一个很理性的人,不会把字符串和int放在一起,因此,开发人员获得了速度/效率的奖励。
“类型安全”的编程语言意味着以下几点:
不能从未初始化的变量中读取 数组的索引不能超出它们的边界 不能执行未检查的类型强制转换
类型安全意味着在编程上,变量、返回值或参数的数据类型必须符合特定的标准。
实际上,这意味着7(整数类型)不同于"7"(字符串类型的引号字符)。
PHP, Javascript和其他动态脚本语言通常是弱类型的,因为它们将转换(字符串)如果您尝试将“7”+ 3添加为“7”到(整数)7,尽管有时您必须显式地这样做(Javascript使用“+”字符进行连接)。
C/ c++ /Java不会理解,或者会将结果连接到“73”中。类型安全通过明确类型需求来防止代码中出现这些类型的错误。
类型安全非常有用。上述“7”+ 3的解决方案是类型转换(int)7 + 3(等于10)。