C#中string内存分配在内存中是如何表示的

Char类是C#提供的字符类型,String是C#提供的字符串类型。
  Char类在C#中表示一个Unicode字符。
  Char类只定义一个Unicode字符。
  Char类常用的方法及说明如下:
指示指定的Unicode字符是否属于控制字符类别
指示某个Unicode字符是否属于十进制数字类别
IsHighSurrogate
指示指定的Char对象是否为高代理项
指示某个Unicode字符是否属于字母类别
IsLetterOrDigit
指示某个Unicode字符是属于字母类别还是属于十进制数字类别
指示某个Unicode字符是否属于小写字母类别
IsLowSurrogate
指示指定的Char对象是否为低代理项
指示某个Unicode字符是否属于数字类别
IsPunctuation
指示某个Unicode字符是否属于标点符号类别
IsSeparator
指示某个Unicode字符是否属于分隔符类别
IsSurrogate
指示某个Unicode字符是否属于代理项字符类别
IsSurrogatePair
指示两个指定的Char对象是否形成代理项对
指示某个Unicode字符是否属于符号字符类别
指示某个Unicode字符是否属于大写字母类别
IsWhiteSpace
指示某个Unicode字符是否属于空白类别
将指定字符串的值转换为它的等效Unicode字符
将Unicode字符的值转换为它的小写等效项
ToLowerInvariant
使用固定区域性的大小写规则,将Unicode字符的值转换为其小写等效项
将此实例的值转换为其等效的字符串表示
将Unicode字符的值转换为它的大写等效项
ToUpperInvariant
使用固定区域性的大小写规则,将Unicode字符的值转换为其大写等效项
将指定字符串的值转换为它的等效Unicode字符
  可以看到Char提供了非常多的实用方法,其中以Is和To开头的比较重要。以Is开头的方法大多是判断Unicode字符是否为某个类别,以To开头的方法主要是转换为其他Unicode字符。
例001 &Char类的使用
创建一个控制台应用程序,演示如何使用Char类提供的常见方法,代码如下。
C#采用字符&\&作为转义字符。例如,定义一个字符,而这个字符是单引号,如果不使用转义字符,则会产生错误。
转义字符就相当于一个电源变换器,电源变换器就是通过一定的手段获得所需的电源形式,例如交流变成直流、高电压变为低电压、低频变为高频等。转义字符也是,它是将字符转换成另一种操作形式,或是将无法一起使用的字符进行组合。
转义符\(单个反斜杠)只针对后面紧跟着的单个字符进行操作。
1 static void Main(string[] args)
char a = 'a';
//声明字符a
char b = '8';
//声明字符b
char c = 'L';
//声明字符c
char d = '.';
//声明字符d
char e = '|';
//声明字符e
char f = ' ';
//声明字符f
//使用IsLetter方法判断a是否为字母
Console.WriteLine("IsLetter方法判断a是否为字母:{0}", Char.IsLetter(a));
//使用IsDigit方法判断b是否为数字
Console.WriteLine("IsDigit方法判断b是否为数字:{0}", Char.IsDigit(b));
//使用IsLetterOrDigit方法判断c是否为字母或数字
Console.WriteLine("IsLetterOrDigit方法判断c是否为字母或数字:{0}", Char.IsLetterOrDigit(c));
//使用IsLower方法判断a是否为小写字母
Console.WriteLine("IsLower方法判断a是否为小写字母:{0}", Char.IsLower(a));
//使用IsUpper方法判断c是否为大写字母
Console.WriteLine("IsUpper方法判断c是否为大写字母:{0}", Char.IsUpper(c));
//使用IsPunctuation方法判断d是否为标点符号
Console.WriteLine("IsPunctuation方法判断d是否为标点符号:{0}", Char.IsPunctuation(d));
//使用IsSeparator方法判断e是否为分隔符
Console.WriteLine("IsSeparator方法判断e是否为分隔符:{0}", Char.IsSeparator(e));
//使用IsWhiteSpace方法判断f是否为空白
Console.WriteLine("IsWhiteSpace方法判断f是否为空白:{0}", Char.IsWhiteSpace(f));
Console.ReadLine();
说明:大多数重要的正则表达式语言运算符都是非转义的单个字符。转义符\(单个反斜杠)通知正则表达式分析器反斜杠后面的字符不是运算符。例如,分析器将r视为字符,而将后跟r的反斜杠(\r)视为回车功能。
为了避免转义序列元素转义,可以通过以下两种方式避免。
1、& 通过@符实现。
2、& 通过逐字指定字符串字面值(两个反斜杠)实现。
首先理解string,String,StringBuilder的概念和区别:
  string
  string,msdn给出的解释就是,string 是C#中的关键字,并且是引用类型, string 类型表示零或更多 Unicode 字符组成的序列。string 是 .NET Framework 中 String 的别名。但定义相等运算符(== 和 !=)是为了比较 string 对象(而不是引用)的值(后面给出示例解释这点)。
  String:
  String是类,表示文本,即一系列 Unicode 字符。String 对象是不可改变的。每次使用 System.String 类中的方法之一时,都要在中创建一个新的字符串对象,这就需要为该新对象分配新的空间。如:当我们实例化一个String的对象后,在内存中为此对象分配一个空间。如下:String str = &hello&;当我们修改str的值的时候,如:str = &hello world&;此时,系统会为str重新分配一个空间。这样原来的内存空间就被浪费掉了,只能等待垃圾回收器回收。在需要对字符串执行重复修改的情况下,与创建新的 String对象相关的系统开销可能会非常昂贵。
  String与string的区别:
  string 是 .NET Framework 中 String 的别名,string是C#基元类型(primitive),简单来说就是编译器直接支持的数据类型。基元类型要直接映射到Framework类库(FCL)中的类型,例如,C#中一个基元类型int直接映射到System.Int32类型,这里int是基元类型,System.Int32是FCL类型。而String是FCL类型的,所以在C#的编译时,会自动的把string转化为System.String。所以string与String实质上没什么区别,只是在使用string要做一次转换,转换为String。因此,在编码时我们推荐使用String。
  string虽然为引用类型,但是(== 和 !=)是为了比较 string 对象(而不是引用)的值。
使用string类时,表面来看能够修改字符串的所有方法实际上并不能修改,实际上它们返回一个根据所调用的方法修改的新的string对象,如果要修改string字符串的实际内容,可以使用StringBuilder类。
各种字符串操作方法:
  (1)Compare:
      Int Compare(string strA,string sreB)
      Int Compare(string strA,string sreB,bool ingorCase)
      注:ingorCase若为true那么就忽略大小写。
      返回值:一个32位有符号的整数。
  (2)CompareTo:
      (以实例对象本身与指定的字符串作比较)
      public int CompareTo(string strB)
      返回值:一个32位有符号的整数。
  (3)Equals
      public bool Equals(string value)
      public static bool Equals(string a,string b)
  2.格式化字符串
      public static string Format(string format,object obj)
      format:指定的格式
      obj:被格式化的对象
格式字符&&&&&&&&&&&&
关联属性/说明
d&&&&&&&&&&&&&&&&&&&&&&&&&
ShortDatePattern
D&&&&&&&&&&&&&&&&&&&&&&&
LongDatePattern
f&&&&&&&&&&&&&&&&&&&&&&&&&
完整日期和时间(长日期和短时间)
F&&&&&&&&&&&&&&&&&&&&&&&&
FullDateTimePattern(长日期和长时间)
g&&&&&&&&&&&&&&&&&&&&&&&&&
常规(短日期和短时间)
G&&&&&&&&&&&&&&&&&&&&&&&&
常规(短日期和长时间)
m、M&&&&&&&&&&&&&&&&&
MonthDayPattern
r、R&&&&&&&&&&&&&&&&&&&
FC1123Pattern
s&&&&&&&&&&&&&&&&&&&&&&&&&
使用当地时间的
t&&&&&&&&&&&&&&&&&&&&&&&&&
ShortTimePattern
T&&&&&&&&&&&&&&&&&&&&&&&&
LongTimePattern
u&&&&&&&&&&&&&&&&&&&&&&&&&
UniversalSortableDateTimePattern
U&&&&&&&&&&&&&&&&&&&&&&&&
使用通用时间的完整日期和时间(长日期和长时间)
y、Y&&&&&&&&&&&&&&&&&&&
YearMonthPattern
  3.截取字符串
    public string Substring(int startIndex,int length)
    startIndex:子字符串起始位置的索引
    length:子字符串中的字符数
  4.分割字符串
&&&&&   public string[] split(params char[] separator);
&&&&&   separator:一个数组包含分隔符
&&&&&   返回值:一个数组,其元素包含此实例中的子字符串,这些字符串由separator中的一个或多个字符分隔。
  5.插入和填充字符串
    插入字符串:
      public string Insert(int startIndex, string value);
    填充字符串:
      public string PadLeft(int totalWidth,char paddingChar);
      totalWidth:结果字符串中的字符数,等于原始字符数加上任何其他填充字符
      paddingChar:填充字符
      返回值左对齐
      public string PadRight(int totalWidth,char paddingChar);
      返回值右对齐
    复制字符串:
      Copy:public static string Copy(string str);
      CopyTo:public void CopyTo(int sourceIndex,char[ ]destination,int destinationIndex,int count);
      sourceIndex:需要复制字符串的起始位置
      destination:目标字符数组
      destinationIndex:指定目标数组中的开始存放位置
      count:指定要复制的字符个数
    替换字符串:
      public string Replace(char Ochar,char NChar);
      public string Replace(string Ovalue,string NValue);
      Ochar:待替换的字符
      Nchar替换后的新字符
    删除字符串:
      public string Remove(int startIndex);
      public string Remove (int startIndex,int count);
    可变字符串:
      public StringBuilder();
      public StringBuilder(int capacity);
      public StringBuilder(string value);
      public StringBuilder(int capacity,int maxCapacity);
      public StringBuilder(string value,int capacity);
      public StringBuilder(string value,int startIndex,int length,int capacity);
      capacity: StringBuilder对象的建议起止大小
      value:字符串,包含用于初始化StringBuilder对象的子字符串
      maxCapacity:当前字符串可包含的最大字符数
      startIndex:起始位置
      length:字符串中的字符数
1、&&&&&&&& Append&方法可用来将文本或对象的字符串表示形式添加到由当前 StringBuilder 对象表示的字符串的结尾处。
2、&&&&&&&& AppendFormat&方法将文本添加到 StringBuilder 的结尾处,而且实现了 IFormattable 接口,因此可接受格式化部分中描述的标准格式字符串。
3、&&&&&&&& Insert&方法将字符串或对象添加到当前 StringBuilder 中的指定位置。
4、&&&&&&&& 可以使用 Remove&方法从当前 StringBuilder 中移除指定数量的字符,移除过程从指定的从零开始的索引处开始。
5、&&&&&&&& 使用 Replace&方法,可以用另一个指定的字符来替换 StringBuilder 对象内的字符。
阅读(...) 评论()C#中string在内存中是如何表示的_C#应用_动态网站制作指南
C#中string在内存中是如何表示的
来源:人气:804
不知道你是否有过和我一样的疑问,不同编码的字符串是如何存储在运行时的内存中的呢,计算机在操作string类型的对象时,如何知道这个string是什么编码呢?和文本文件那样有类似BOM的东东在string对象里?
答案是,内存中是无关编码的。统一使用UCS2(注意,这里为什么不说是UTF16,见下文)编码(大小端应该是和计算机CPU有关,intel的应该是小端)存放在内存中。
string对象和IO交互时,分别根据方法中的Encoding去处理来自IO的字节,或者转换成Encoding所指示的编码的字节流作为IO输出。
另外,上文提到内存中使用的是UCS2而不是UTF16,意思是,对于Unicode编码值大于0xFFFF的编码,C#和一样,是转换成&代理对&(2*2字节)表示的。所以,如果string中含有类似emoji那样的&大&字符时,string的Length方法返回的字符串长度是不正确的。解决方案是,使用StringInfo类中的LengthInTextElements。
&PS:System.Text.Encoding中的Unicode和BigEndianUnicode实际是UTF16,微软一定有它的道理。只是我不清楚。
优质网站模板转自:http://www.cnblogs.com/instance/archive//2056091.html
刚开始学习C#的时候,就听说CLR对于String类有一种特别的内存管理机制:有时候,明明声明了两个String类的对象,但是他们偏偏却指向同一个实例。如下:
String s1 = "Hello";
String s2 = "Hello";
//s2和s1的实际值都是“Hello”
bool same = (object) s1 == (object) s2;
//这里比较s1、s2是否引用了同一个对象实例
//所以不能写作bool same = s1 == s2;
//因为String类重载了==操作符来比较String对象包含的实际值
这里的same会被赋值为true。也就是说s1真的和s2引用了同一个String对象。当然,应该注意到的是s1和s2都被统一赋值为同一个字符串“Hello”,这才是出现上述情况的原因。
现在我们初步得出结论,当有多个字符串变量包含了同样的字符串实际值时,CLR可能不会为它们重复地分配内存,而是让它们统统指向同一个字符串对象实例。(这里我说了“可能”,是因为某些情况下,确实也会发生同一个字符串实际值在内存中有多份副本同时存在。请继续往下看。)
我们知道,String类有很多特别的地方,其中之一就是它是“不会改变的”(immutable)。这说明在我们每次对一个String对象进行操作时(比如说使用Trim,Replace等方法),并不是真的对这个String对象的实例进行修改,而是返回一个新的String对象实例作为操作执行的结果。String对象的实例一经生成,到死都不会被改变了!
基于String类这样的特性,CLR让表示相同的字符串实际值的变量指向同一个String事例,就是完全合理的了。因为利用任何一个对String实例的引用所进行的修改操作都不会切实地影响到该实例的状态,也就不会影响到其他所有指向该实例的引用所表示的字符串实际值。CLR如此管理String类的内存分配,可以优化内存的使用情况,避免内存中包含冗余的数据。
为了实现这个机制,CLR默默地维护了一个叫做驻留池(Intern Pool)的表。这个表记录了所有在代码中使用字面量声明的字符串实例的引用。这说明使用字面量声明的字符串会进入驻留池,而其他方式声明的字符串并不会进入,也就不会自动享受到CLR防止字符串冗余的机制的好处了。这就是我上文提到的“某些情况下,确实也会发生同一个字符串实际值在内存中有多份副本同时存在”的例子。请看这个例子:
StringBuilder sb = new StringBuilder();
sb.Append("He").Append("llo");
string s1 = "Hello";
string s2 = sb.ToString();
bool same = (object) s1 == (object) s2;
这时same就不是true了,因为虽然s1,s2表示的是相同的字符串,但是由于s2不是通过字面量声明的,CLR在为sb.ToString()方法的返回值分配内存时,并不会到驻留池中去检查是否有值为“Hello”的字符串已经存在了,所以自然不会让s2指向驻留池内的对象。
为了让编程者能够强制CLR检查驻留池,以避免冗余的字符串副本,String类的设计者提供了一个名为Intern的类方法。下面是该方法的一个示例:
StringBuilder sb = new StringBuilder();
sb.Append("He").Append("llo");
string s1 = "Hello";
string s2 = String.Intern(sb.ToString());
bool same = (object) s1 == (object) s2;
好了,same又是true了。Intern方法接受一个字符串作为参数,它会在驻留池中检查是否存在参数所表示的字符串。如果存在,则返回那个驻留池中的字符串的引用;否则向驻留池中加入一个新的表示相同值的字符串,并返回这个字符串的引用。不过要注意的是,就算Intern方法在驻留池中找到了相同值的字符串,也不能让您省却一次字符串内存分配的操作,因为作为参数的字符串已经被分配了一次内存了。而使用Intern方法的好处在于,如果Intern方法在驻留池中找到了相同值的字符串,此时虽然在内存中存在两份该字符串的副本(一份是参数,一份是驻留池中的),但是随着时间的流逝,参数所引用的那个副本会被垃圾回收掉,这样对于该字符串内存中就不存在冗余了。
当您的程序中存在某个方法,可以根据不同的上下文环境创建并返回一个很长的字符串,而在程序运行的过程中它有会经常返回同样的字符串时,您可能就要考虑考虑使用Intern方法来提高内存的利用率了。
不过同样值得注意的是,使用Intern方法让一个字符串存活于驻留池中也有一个副作用:即使已经不存在任何其它引用指向驻留池中的字符串了,这个字符串仍然不一定会被垃圾回收掉。也就是说即使驻留池中的字符串已经没有用处了,它可能也要等到CLR终结时才被销毁。当您使用Intern方法的时候,也应该考虑到这个特殊的行为。
C#中stringBuilding类的使用总结
StringBuilder到底是是什么。我这里先不说,先说说咱们熟悉的string。
String就是我们常说的字符串类。但是string类是不可变的,据官方报道,对string类的任何改变,都会...
关于String内存分配的深入探讨 (转)
public class Test {public static final String MESSAGE=&taobao&;public static void main(String[] args...
c# string 基于内存的使用策略
最近在写的一个程序中要求对与一个string变量不断地更新。
我们知道,在C#中一个字符串一旦被确定,就是不可改的
string str = &a&;
str = &b&;
【编程语言】C#中字符串的内存分配
C++中的共享内存作为一枚C++程序员,了解到在早期的版本中STL为了提高性能,在std::string中曾一度使用过共享内存的技术,在目前的版本中string已经不支持共享内存,其中一个原因是由于线...
字符串及垃圾回收机制
字符串有两个特性:字符串常量的暂存池特性和不可变性
字符串常量的暂存池:对于相同的字符串常量,每次使用时并不会重新创建一个内存来储存,而是在第一次创建的时候将字符串作为键,将字符串的地址作为值,下次...
String会出现在哪些地方
方法内的局部string
类内的字段String
static string
容器中存储的string
String数组
那么String的位置会影响其存储方...
String的存储方式,StringBuffer与StringBuilder的区别
一、String类
想要了解一个类,最好的办法就是看这个类的实现源代码,来看一下String类的源码:
public final class String
implements...
字符串对象在创建的时候有两种方式:String str1 = &abc&;
String str2 = new String(&abc&);123这两种方式都...
字符常量是用单引号括起来的一个字符
例如:'a'、'b'、'='、'+'、'?'
o字符常量只能用单引号括起来,不能用双引号或其他括号。
o字符常量只能是单个...
没有更多推荐了,浅谈C#中堆和栈的区别(附上图解)
转载 &更新时间:日 09:01:35 & 投稿:hebedich
C#中栈是编译期间就分配好的内存空间,因此你的代码中必须就栈的大小有明确的定义;堆是程序运行期间动态分配的内存空间,你可以根据程序的运行情况确定要分配的堆内存的大小
线程堆栈:简称栈 Stack
托管堆: 简称堆 Heap
使用.Net框架开发程序的时候,我们无需关心内存分配问题,因为有GC这个大管家给我们料理一切。如果我们写出如下两段代码:
public int AddFive(int pValue)
result = pValue + 5;
public class MyInt
public int MyV
public MyInt AddFive(int pValue)
MyInt result = new MyInt();
result.MyValue = pValue + 5;
问题1:你知道代码段1在执行的时候,pValue和result在内存中是如何存放,生命周期又如何?代码段2呢?
要想释疑以上问题,我们就应该对.Net下的栈(Stack)和托管堆(Heap)(简称堆)有个清楚认识,本立而道生。如果你想提高程序性能,理解栈和堆,必须的!
本文就从栈和堆,类型变量展开,对我们写的程序进行庖丁解牛。
C#程序在CLR上运行的时候,内存从逻辑上划分两大块:栈,堆。这俩基本元素组成我们C#程序的运行环境。
一,栈 vs 堆:区别?
栈通常保存着我们代码执行的步骤,如在代码段1中 AddFive()方法,int pValue变量,int result变量等等。而堆上存放的则多是对象,数据等。(译者注:忽略编译器优化)我们可以把栈想象成一个接着一个叠放在一起的盒子。当我们使用的时候,每次从最顶部取走一个盒子。栈也是如此,当一个方法(或类型)被调用完成的时候,就从栈顶取走(called a Frame,译注:调用帧),接着下一个。堆则不然,像是一个仓库,储存着我们使用的各种对象等信息,跟栈不同的是他们被调用完毕不会立即被清理掉。
如图1,栈与堆示意图
栈内存无需我们管理,也不受GC管理。当栈顶元素使用完毕,立马释放。而堆则需要GC(Garbage collection:垃圾收集器)清理。
二,什么元素被分配到栈?什么被分配到堆?
当我们程序执行的时候,在栈和堆中分配有四种主要的类型:值类型,引用类型,指针,指令。
在C#中,继承自System.ValueType的类型被称为值类型,主要有以下几种(CLR2.0中支持类型有增加):
引用类型:
以下是引用类型,继承自System.Object:
* interface
* delegate
在内存区中,指向一个类型的引用,通常被称为“指针”,它是受CLR( Common Language Runtime:公共语言运行时)管理,我们不能显示使用。需要注意的是,一个类型的引用即指针跟引用类型是两个完全不同的概念。指针在内存中占一块内存区,它本身只代表一个内存地址(或者null),它所指向的另一块内存区才是我们真正的数据或者类型。如图2:
后文对指令再做介绍。
三,如何分配?
我们先看一下两个观点:
观点1,引用类型总是被分配在堆上。(正确?)
观点2,值类型和指针总是分配在被定义的地方,他们不一定被分配到栈上。(这个理解起来有点难度,需要慢慢来)
上文提及的栈(Stack),在程序运行的时候,每个线程(Thread)都会维护一个自己的专属线程堆栈。
当一个方法被调用的时候,主线程开始在所属程序集的元数据中,查找被调用方法,然后通过JIT即时编译并把结果(一般是本地CPU指令)放在栈顶。CPU通过总线从栈顶取指令,驱动程序以执行下去。
下面我们以实例来详谈。
还是我们开篇所列的代码段1:
public int AddFive(int pValue)
result = pValue + 5;
当AddFive方法开始执行的时候,方法参数(parameters)则在栈上分配。如图3:
注意:方法并不在栈中存活,图示仅供参考。
接着,指令指向AddFive方法内部,如果该方法是第一次执行,首先要进行JIT即时编译。如图4:
当方法内部开始执行的时候,变量result被分配在栈上,如图5:
方法执行完毕,而且方法返回后,如图6所示:
在方法执行完毕返回后,栈上的区域被清理。如图7:
以上看出,一个值类型变量,一般会分配在栈上。那观点2中所述又做何理解?“值类型和指针总是分配在被定义的地方,他们不一定被分配到栈上”。
原因就是如果一个值类型被声明在一个方法体外并且在一个引用类型中,那它就会在堆上进行分配。
还是代码段2:
public class MyInt
public int MyV
public MyInt AddFive(int pValue)
MyInt result = new MyInt();
result.MyValue = pValue + 5;
当线程开始执行AddFive方法的时候,参数被分配到栈上,如图8所示:
由于MyInt是一个引用类型,所以它被分配到堆上,并且在栈中生成一个指针(result),如图9:
AddFive方法执行完毕时的情况如图10:
栈上内存被清理,堆中依然存在,如图11:
当程序需要更多的堆空间时,GC需要进行垃圾清理工作,暂停所有线程,找出所有不可达到对象,即无被引用的对象,进行清理。并通知栈中的指针重新指向地址排序后的对象。现在我们应该知道,了解栈和堆,对我们开发出高性能程序的重要性。当我们使用引用类型的时候,一般是对指针进行的操作而非引用类型对象本身。但是值类型则操作其本身。
接下来,我们用例子说明这一点。
public int ReturnValue()
int x = new int();
int y = new int();
执行结果为3,稍作修改:
public class MyInt
public int MyV
public int ReturnValue2()
MyInt x = new MyInt();
x.MyValue = 3;
MyInt y = new MyInt();
y.MyValue = 4;
return x.MyV
执行结果为4。
我们来分析下原因,其实例1的跟以下代码所起效用一样:
public int ReturnValue()
int x = 3;
如图12所示,在栈上x和y分别占用一块内存区,互不干扰。
而例2,与以下代码所起效用一样:
public int ReturnValue2()
x.MyValue = 3;
y.MyValue = 4;
return x.MyV
如图13所示,
栈上的指针x和y指向堆上同一个区域,修改其一必会改变堆上的数据。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具C#里氏替换原则,is 和 as,有关于内存的一些知识 - 简书
C#里氏替换原则,is 和 as,有关于内存的一些知识
里氏替换原则(LSP):
原则上来讲,子类对象可以赋给父类对象,也可以说子类替换父类,并且出现在父类能够出现的任何地方。 反过来说,父类对象是不能替换子类对象的,这种特性称为里氏替换原则 1.子类可以隐式的转换为父类 2.父类必须强转子类class Person{public void Say(){Console.WriteLine ("父类说");}}class Zhang:Person{public new void Say(){Console.WriteLine ("张说");}}class Li:Person{public new void Say(){Console.WriteLine ("李说");}}class MainClass{public static void Main (string[] args){//
Person p = new Zhang ();//
p.Say ();//
Person p1 =//编译通过//
Zhang p2 = p1;//编译不通过,因为父类必须强转为子类,也就是说将p1强制转换为Zhang类型//
Zhang z1 = new Zhang ();//
Li l1 = new Li ();//
z1 = (Zhang)l1;//编译不能通过}}is&&as
is : 相当于判断,A is B
A是不是B或者A是不是B的子类? as :先判断,在转换。(它比传统的强制转换相对来说要安全一点,因为传统的强制转换, 一旦转换失败的话,程序就会崩溃,那么使用as关键字,如果转换不成功,就转换成空类型)关于内存
public void MethodF(){
Console.WriteLine ("A.F");
public virtual void MethodG(){
Console.WriteLine("A.G");
public new void MethodF(){
Console.WriteLine ("B.F");
public override void MethodG ()
Console.WriteLine ("B.G");
class MainClass
public static void Main (string[] args)
b = new B ();
a.MethodF ();
b.MethodF ();
a.MethodG ();
b.MethodG ();
这里将涉及到关于使用new关键字之后,内存中的一些变化
B b:定义栈上的引用变量b,此时为空引用,也就是null.存于栈,用来保存将来引用对象的地址.
b = new B:通过new关键字创建B类的对象,对象的实例保存在托管堆,CRL在建立实例实例对象的时候,
还会创建它的类型对象.对象实例在堆中的内存包括,字段,类型对象指针,同步索引块.类型对象指针指向的
是类型对象
类型对象在堆中的内存包括类型对象指针,索引块,静态字段,方法列表.
A a = b:声明一个类型为A的引用变量a,并将其实际地址指向b所指的那个对象实例
a.MethodF():
当调用一个方法的时候,会直接检查这个对象a的类型,首先找到堆中的类型对象,查看其实否有该方法,
如果有,直接调用.如果没有,则通过类型对象的类型对象指针向上继续查找,直到找到该方法.
找到了该方法之后,它会先检查该方法是否为virtual,如果非虚直接调用.如果是虚方法,即有virtual
修饰的关键字,则引用变量a去找对象的实例类B,查找该方法是否有重新实现了该虚方法,如果有,执行.
没有继续向上查找.直到找到为止.
由于MethodG为虚方法,则会找到实例B,又由于B重写了MethodG,因此直接输出.
LSP:里氏替换原则 * 原则上来讲,子类对象可以赋给父类对象,也可以说子类替换父类,并且出现在父类能过出现的任何地方 * * 反过来说,父类对象时不能替换子类对象的,这种特性称为里氏替换原则 * 1.子类可以隐士的转换为父类对象 * 2.父类必须强转子类 * *
Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式...
MVC模式数据模型-&显示视图
视图模型Observer模式Composite模式,都是控件Strategy模式Factory模式 项目文件夹Domain只有属性的类控制序列化:XmlElementXmlArrayXmlArrayItem 不好的代码(1) 重复dupli...
1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io的语法,虚拟机方面的语法。 1、一个&.java&源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个publ...
1. [C#语言基础]请简述拆箱和装箱。 答: 装箱操作: 值类型隐式转换为object类型或由此值类型实现的任何接口类型的过程。 1.在堆中开辟内存空间。 2.将值类型的数据复制到堆中。 3.返回堆中新分配对象的地址。 拆箱操作: object类型显示转换为值类型或从接口...
1、Error running app: Instant Run requires 'Tools | Android | Enable ADB integration' to be enabled. 2、打正式包时出现:Avoid non-default construct...
盼君归/张书云 久为天涯客, 归期遥遥。 为前程, 四海为家。 君何时荣归故里? 我望眼欲穿! 每日孤单丽影, 孤灯一盏。 得家书, 如得万金。 情意绵绵, 如同昨日。 盼君归, 诉相思。 聊一夜不知天明!
太阳和黑夜同是死的 早晨起床的理想是死的 晚间枕过的梦魇是死的 手里一半的玫瑰是死的 谈论的婚嫁是死的 笔墨和纸同是死的 写出的诗是幼稚的亦是死的 沙漠里的水是死的 河流的沙碛是死的 从前的未来是死的 种下的承诺是死的 刻下的时间是死的 榕树前许的愿望是死的 我是死的 与你...
数据存储一般包括字符串,多媒体数据。字符串数据的类型只有字符串,但是结构有很多: xml,json,md5,base64 普通字符串多媒体数据的类型:图片(jpg,png,gif...)音频(mp3,aif...)视频(mp4,mpv) 通常用数据库来存储字符串文本类型的数...
初看《大师的背影》这本书,不由得有些疑惑,既然写大师,可以有很多写的内容,为什么要写背影呢? 时代的“背影” 书中所讲述的是七十年代,一拔文化大师下放到河南辉县发生的事,辉县当年处在大发展的年代,“愚公移山专业队”在县委书记郑永和的带领下,在太行山下创造一个又一个的奇迹。“...}

我要回帖

更多关于 手机内存释放空间 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信