㈠ c#中的ulong在java里對應哪個類型
JAVA核心庫里好像沒有對應C#里ulong的類型
long都溢出,你用BigInteger吧,網路一下一大堆
㈡ java與c#的異同點
一.值類型
1.基本數據類型
Java有八種基本數據類型:boolean,byte,char,short,int,long,float,double
C#的數據類型會多一些,java中的數據類型都是有符號的,而C#中還定義了相應的無符號數據類型:bool,(byte,sbyte),char,(short,
ushort) ,( int, uint) , (long, ulong),float,double,decimal
注意一下,我們會發現C#多了一個decimal,這個decimal類型屬於C#的值類型,但不是基本類型,它其實是一個結構類型,java中沒有結構的概念。
2.結構
在C#中的結構使用struct關鍵字定義,與類的區別如下;
類和結構都是創建對象的模板。
都可以包含欄位和方法。
都需要用new實例化。
類中可以初始化非常量欄位值,但是結構中不可以初始化非常量欄位值。
結構是值類型,使用結構可以提高性能,類是引用類型。
結構不支持繼承
在java和C#中String都屬於類類型,但是String和其它類類型不同的是String屬於值傳遞而不是引用傳遞。
3. 可空值類型
空值類型是在.NET 2.0發布的時候被引入的。使用泛型(Generics),任何值類型都可以被包裝成空類型,從而可以有空值。
聲明一個boolean,必須賦給true或false值,聲明一個可空boolean,則還可以賦為null值, 如 bool b = null;
C#引入空值類型是為了更好的對關系資料庫進行操作,在表中遇到未寫內容的列是很常見的,而.net中的LINQ語言的實現目標就是在程序中直接操縱資料庫。
二.引用類型
所有的類類型(除了String)都是引用類型
在一個值類型轉換為相應的類類型時,java和C#都有自動裝箱機制,感覺C#做的更進一步,比如,我們要將一個int數值轉為一個String:
Java :int num = 100; C# :int num = 100;
num.ToString();
//出錯 num.ToString(); //自動裝箱
Integer n = num; //自動裝箱
n.toString();
按照封裝原則,一個類的屬性應該是私有的,在java中需要暴露一個屬性通常用set/get方法,在C#中也一樣,不過C#還提供了一個單獨的語法來做這個工作:
Public class MyClass{
private string name;
public string
Name {
get { return name; }
set { name = value}
}
}
在Java中一個類文件只能有一個公有類,且類名必須與文件名相同,但在C#中沒有這種限制,一個文件可以有多個公有類,一個類還可以分散放在多個文件中。
Java的類方法一般用小寫字母開頭,而C#的類方法一般用大寫字母開頭。
三.常量
Java的常量用final來定義
C#中有兩個關鍵字:const和readonly,
readonly可以在聲明時賦值也可以在構造器中賦值,const必須在聲明的同時賦值;readonly可以是實例域也可以是靜態域,const只能是靜態域。
四.枚舉
Java:enum Status {Start, Stop, Rewind,
Forward};
enum Status { Start (20), Stop (40), Rewind (60) ,
Forward (80)};
C#: enum Status {Start, Stop, Rewind, Forward};
enum
Status { Start = 20, Stop = 40, Rewind = 60, Forward = 80};
五.運算符
Java和C#基本相同,只是Java多了一個位運算符
>>>
右移,左邊空出的位以0填充
六.流程式控制制
Java和C#基本相同,唯一的一點區別是在做遍歷時的寫法:
Java: for (int i : numArray) C#: foreach (int i in
numArray)
七.數組
Java: int[][]
d; C#: int[][] d; 還有一種寫法:int[,] d;
八.包(C#叫命名空間)
Java:package
harding.compsci.graphics;
import harding.compsci.graphics.*;
C#:
namespace Harding.Compsci.Graphics {}
using Harding.Compsci.Graphics;
Java常用包:
java.lang : 這個基礎的基礎
java.util : 工具庫
java.net :
網路通信用協議包
java.io:輸入輸出管道
java.awt : 基本圖型工具包
javax.swing : 高級圖型工具包
java.math : 數學括展包
java.sql : 用來訪問DB的包
.net常用命名空間(這里沒用C#是因為.net平台的幾種語言都是共用的一個framework):
System.Collections
:集合相關,比如列表,隊列,數組,哈希表等
System.IO : 數據流
System.Text :
包含了一些表示字元編碼的類型及字元串的操作和格式化
System.Reflection :反射相關
System.Threading :多線程
System.Drawing :繪圖
System.Data :數據訪問
System.Net :網路通信
九.繼承和介面
Java和C#的繼承與介面實現機制是一樣的,兩者都只能單繼承,可以實現多介面
Java的繼承用extends關鍵字,介面用implements 關鍵字,
C#中都是用:如
public class MyClass
: ParantClass, Interface1,Interface2 {}
public class MyClass extends
ParantClass implements Interface1,Interface2 {}
㈢ int uint ,long ulong 在java中常用嗎
int, long 是java中的基本類型。
uint,ulong不是。
希望對你有所幫助
㈣ 比較C++、java、vb、C#的異同
C#和java都是需要運行環境的,
java可以跨平台,而C#暫時不能
C++和vb都是編譯後直接生成.exe文件的。可直接在操作系統運行。C++和vb都不能跨平台
㈤ 現在學C# 好,還是Java比較好
華山論劍:C#對Java
(仙人掌工作室 2001年06月29日 17:01)
C#(C-Sharp)是Microsoft的新編程語言,被譽為「C/C++家族中第一種面向組件的語言」。然而,不管它自己宣稱的是什麼,許多人認為C#更像是Java的一種克隆,或者是Microsoft用來替代Java的產品。事實是否是這樣的呢?
本文的比較結果表明,C#不止是Java的同胞那麼簡單。如果你是一個Java開發者,想要學習C#或者了解更多有關C#的知識,那麼本文就是你必須把最初10分鍾投入於其中的所在。
一、C#、C++和Java
C#的語言規范由Microsoft的Anders Hejlsberg與Scott Wiltamuth編寫。在當前Microsoft天花亂墜的宣傳中,對C#和C++、Java作一番比較總是很有趣的。考慮到當前IT媒體的輿論傾向,如果你早就知道C#更接近Java而不是C++,事情也不值得大驚小怪。對於剛剛加入這場討論的讀者,下面的表1讓你自己作出判斷。顯然,結論應該是:Java和C#雖然不是孿生子,但C#最主要的特色卻更接近Java而不是C++。
表1:比較C#、C++和Java最重要的功能
功能 C# C++ Java
繼承 允許繼承單個類,允許實現多個介面 允許從多個類繼承 允許繼承單個類,允許實現多個介面
介面實現 通過「interface」關鍵詞 通過抽象類 通過「interface」關鍵詞
內存管理 由運行時環境管理,使用垃圾收集器 需要手工管理 由運行時環境管理,使用垃圾收集器
指針 支持,但只在很少使用的非安全模式下才支持。通常以引用取代指針 支持,一種很常用的功能。 完全不支持。代之以引用。
源代碼編譯後的形式 .NET中間語言(IL) 可執行代碼 位元組碼
單一的公共基類 是 否 是
異常處理 異常處理 返回錯誤 異常處理。
了解表1總結的重要語言功能之後,請繼續往下閱讀,了解C#和Java的一些重要區別。
二、語言規范的比較
2.1、簡單數據類型
簡單數據類型(Primitive)在C#中稱為值類型,C#預定義的簡單數據類型比Java多。例如,C#有unit,即無符號整數。表2列出了所有C#的預定義數據類型:
表2:C#中的值類型
類型 說明
object 所有類型的最終極的基類
string 字元串類型;字元串是一個Unicode字元的序列
sbyte 8位帶符號整數
short 16位帶符號整數
int 32位帶符號整數
long 64位帶符號整數
byte 8位無符號整數
ushort 16位無符號整數
uint 32位無符號整數
ulong 64位無符號整數
float 單精度浮點數類型
double 雙精度浮點數類型
bool 布爾類型;bool值或者是true,或者是false
char 字元類型;一個char值即是一個Unicode字元
decimal 有28位有效數字的高精度小數類型
2.2、常量
忘掉Java中的static final修飾符。在C#中,常量可以用const關鍵詞聲明。
public const int x = 55;
此外,C#的設計者還增加了readonly關鍵詞。如果編譯器編譯時未能確定常量值,你可以使用readonly關鍵詞。readonly域只能通過初始化器或類的構造函數設置。
2.3、公用類的入口點
在Java中,公用類的入口點是一個名為main的公用靜態方法。main方法的參數是String對象數組,它沒有返回值。在C#中,main方法變成了公用靜態方法Main(大寫的M),Main方法的參數也是一個String對象數組,而且也沒有返回值,如下面的原型聲明所示:
public static void Main(String[] args)
但是,C#的Main方法不局限於此。如果不向Main方法傳遞任何參數,你可以使用上述Main方法的一個重載版本,即不帶參數列表的版本。也就是說,下面的Main方法也是一個合法的入口點:
public static void Main()
另外,如果你認為有必要的話,Main方法還可以返回一個int。例如,下面代碼中的Main方法返回1:
using System;
public class Hello {
public static int Main() {
Console.WriteLine("Done");
return 1;
}
}
與此相對,在Java中重載main方法是不合法的。
2.4、switch語句
在Java中,switch語句只能處理整數。但C#中的switch語句不同,它還能夠處理字元變數。請考慮下面用switch語句處理字元串變數的C#代碼:
using System;
public class Hello {
public static void Main(String[] args) {
switch (args[0]) {
case "老闆":
Console.WriteLine("早上好!我們隨時准備為您效勞!");
break;
case "雇員":
Console.WriteLine("早上好!你可以開始工作了!");
break;
default:
Console.WriteLine("早上好!祝你好運!");
break;
}
}
}
與Java中的switch不同,C#的switch語句要求每一個case塊或者在塊的末尾提供一個break語句,或者用goto轉到switch內的其他case標簽。
2.5、foreach語句
foreach語句枚舉集合中的各個元素,為集合中的每一個元素執行一次代碼塊。請參見下面的例子。
using System;
public class Hello {
public static void Main(String[] args) {
foreach (String arg in args)
Console.WriteLine(arg);
}
}
如果在運行這個執行文件的時候指定了參數,比如「Hello Peter Kevin Richard」,則程序的輸出將是下面幾行文字:
Peter
Kevin
Richard
2.6、C#沒有>>>移位操作符
C#支持uint和ulong之類的無符號變數類型。因此,在C#中,右移操作符(即「>>」)對於無符號變數類型和帶符號變數類型(比如int和long)的處理方式不同。右移uint和ulong丟棄低位並把空出的高位設置為零;但對於int和long類型的變數,「>>」操作符丟棄低位,同時,只有當變數值是正數時,「>>」才把空出的高位設置成零;如果「>>」操作的是一個負數,空出的高位被設置成為1。
Java中不存在無符號的變數類型。因此,我們用「>>>」操作符在右移時引入負號位;否則,使用「>>」操作符。
2.7、goto關鍵詞
Java不用goto關鍵詞。在C#中,goto允許你轉到指定的標簽。不過,C#以特別謹慎的態度對待goto,比如它不允許goto轉入到語句塊的內部。在Java中,你可以用帶標簽的語句加上break或continue取代C#中的goto。
2.8、聲明數組
在Java中,數組的聲明方法非常靈活,實際上有許多種聲明方法都屬於合法的方法。例如,下面的幾行代碼是等價的:
int[] x = { 0, 1, 2, 3 };
int x[] = { 0, 1, 2, 3 };
但在C#中,只有第一行代碼合法,[]不能放到變數名字之後。
2.9、包
在C#中,包(Package)被稱為名稱空間。把名稱空間引入C#程序的關鍵詞是「using」。例如,「using System;」這個語句引入了System名稱空間。
然而,與Java不同的是,C#允許為名稱空間或者名稱空間中的類指定別名:
using TheConsole = System.Console;
public class Hello {
public static void Main() {
TheConsole.WriteLine("使用別名");
}
}
雖然從概念上看,Java的包類似於.NET的名稱空間。然而,兩者的實現方式不同。在Java中,包的名字同時也是實際存在的實體,它決定了放置.java文件的目錄結構。在C#中,物理的包和邏輯的名稱之間是完全分離的,也就是說,名稱空間的名字不會對物理的打包方式產生任何影響。在C#中,每一個源代碼文件可以從屬於多個名稱空間,而且它可以容納多個公共類。
.NET中包的實體稱為程序集(Assembly)。每一個程序集包含一個manifest結構。manifest列舉程序集所包含的文件,控制哪些類型和資源被顯露到程序集之外,並把對這些類型和資源的引用映射到包含這些類型與資源的文件。程序集是自包含的,一個程序集可以放置到單一的文件之內,也可以分割成多個文件。.NET的這種封裝機制解決了DLL文件所面臨的問題,即臭名昭著的DLL Hell問題。
2.10、默認包
在Java中,java.lang包是默認的包,它無需顯式導入就已經自動包含。例如,要把一些文本輸出到控制台,你可以使用下面的代碼:
System.out.println("Hello world from Java");
C#中不存在默認的包。如果要向控制台輸出文本,你使用System名稱空間Console對象的WriteLine方法。但是,你必須顯式導入所有的類。代碼如下:
using System;
public class Hello {
public static void Main() {
Console.WriteLine("Hello world from C#");
}
}
2.11、面向對象
Java和C#都是完全面向對象的語言。在面向對象編程的三大原則方面,這兩種語言接近得不能再接近。
繼承:這兩種語言都支持類的單一繼承,但類可以實現多個介面。所有類都從一個公共的基類繼承。
封裝與可見性:無論是在Java還是C#中,你都可以決定類成員是否可見。除了C#的internal訪問修飾符之外,兩者的可見性機制非常相似。
多態性:Java和C#都支持某些形式的多態性機制,且兩者實現方法非常類似。
2.12、可訪問性
類的每個成員都有特定類型的可訪問性。C#中的訪問修飾符與Java中的基本對應,但多出了一個internal。簡而言之,C#有5種類型的可訪問性,如下所示:
public:成員可以從任何代碼訪問。
protected:成員只能從派生類訪問。
internal:成員只能從同一程序集的內部訪問。
protected internal:成員只能從同一程序集內的派生類訪問。
private:成員只能在當前類的內部訪問。
2.13、派生類
在Java中,我們用關鍵詞「extends」實現繼承。C#採用了C++的類派生語法。例如,下面的代碼顯示了如何派生父類Control從而創建出新類Button:
public class Button: Control { . . }
2.14、最終類
由於C#中不存在final關鍵詞,如果想要某個類不再被派生,你可以使用sealed關鍵詞,如下例所示:
sealed class FinalClass { . . }
2.15、介面
介面這個概念在C#和Java中非常相似。介面的關鍵詞是interface,一個介面可以擴展一個或者多個其他介面。按照慣例,介面的名字以大寫字母「I」開頭。下面的代碼是C#介面的一個例子,它與Java中的介面完全一樣:
interface IShape { void Draw(); }
擴展介面的語法與擴展類的語法一樣。例如,下例的IRectangularShape介面擴展IShape介面(即,從IShape介面派生出IRectangularShape介面)。
interface IRectangularShape: IShape { int GetWidth(); }
如果你從兩個或者兩個以上的介面派生,父介面的名字列表用逗號分隔,如下面的代碼所示:
interface INewInterface: IParent1, IParent2 { }
然而,與Java不同,C#中的介面不能包含域(Field)。
另外還要注意,在C#中,介面內的所有方法默認都是公用方法。在Java中,方法聲明可以帶有public修飾符(即使這並非必要),但在C#中,顯式為介面的方法指定public修飾符是非法的。例如,下面的C#介面將產生一個編譯錯誤。
interface IShape { public void Draw(); }
2.16、is和as操作符
C#中的is操作符與Java中的instanceof操作符一樣,兩者都可以用來測試某個對象的實例是否屬於特定的類型。在Java中沒有與C#中的as操作符等價的操作符。as操作符與is操作符非常相似,但它更富有「進取心」:如果類型正確的話,as操作符會嘗試把被測試的對象引用轉換成目標類型;否則,它把變數引用設置成null。
為正確理解as操作符,首先請考慮下面這個例子中is操作符的運用。這個例子包含一個IShape介面,以及兩個實現了IShape介面的類Rectangle和Circle。
using System;
interface IShape {
void draw();
}
public class Rectangle: IShape {
public void draw() {
}
public int GetWidth() {
return 6;
}
}
public class Circle: IShape {
public void draw() {
}
public int GetRadius() {
return 5;
}
}
public class LetsDraw {
public static void Main(String[] args) {
IShape shape = null;
if (args[0] == "rectangle") {
shape = new Rectangle();
}
else if (args[0] == "circle") {
shape = new Circle();
}
if (shape is Rectangle) {
Rectangle rectangle = (Rectangle) shape;
Console.WriteLine("Width : " + rectangle.GetWidth());
}
if (shape is Circle) {
Circle circle = (Circle) shape;
Console.WriteLine("Radius : " + circle.GetRadius());
}
}
}
編譯好代碼之後,用戶可以輸入「rectangle」或者「circle」作為Main方法的參數。如果用戶輸入的是「circle」,則shape被實例化成為一個Circle類型的對象;反之,如果用戶輸入的是「rectangle」,則shape被實例化成為Rectangle類型的對象。隨後,程序用is操作符測試shape的變數類型:如果shape是一個矩形,則shape被轉換成為Rectangle對象,我們調用它的GetWidth方法;如果shape是一個圓,則shape被轉換成為一個Circle對象,我們調用它的GetRadius方法。
如果使用as操作符,則上述代碼可以改成如下形式:
using System;
interface IShape {
void draw();
}
public class Rectangle: IShape {
public void draw() {
}
public int GetWidth() {
return 6;
}
}
public class Circle: IShape {
public void draw() {
}
public int GetRadius() {
return 5;
}
}
public class LetsDraw {
public static void Main(String[] args) {
IShape shape = null;
if (args[0] == "rectangle") {
shape = new Rectangle();
}
else if (args[0] == "circle") {
shape = new Circle();
}
Rectangle rectangle = shape as Rectangle;
if (rectangle != null) {
Console.WriteLine("Width : " + rectangle.GetWidth());
}
else {
Circle circle = shape as Circle;
if (circle != null)
Console.WriteLine("Radius : " + circle.GetRadius());
}
}
}
在上面代碼的粗體部分中,我們在沒有測試shape對象類型的情況下,就用as操作符把shape轉換成Rectangle類型的對象。如果shape正好是一個Rectangle,則shape被轉換成為Rectangle類型的對象並保存到rectangle變數,然後我們調用它的GetWidth方法。如果這種轉換失敗,則我們進行第二次嘗試。這一次,shape被轉換成為Circle類型的對象並保存到circle變數。如果shape確實是一個Circle對象,則circle現在引用了一個Circle對象,我們調用它的GetRadius方法。
2.17、庫
C#沒有自己的類庫。但是,C#共享了.NET的類庫。當然,.NET類庫也可以用於其他.NET語言,比如VB.NET或者JScript.NET。值得一提的是StringBuilder類,它是對String類的補充。StringBuilder類與Java的StringBuffer類非常相似。
2.18、垃圾收集
C++已經讓我們認識到手工管理內存是多麼缺乏效率和浪費時間。當你在C++中創建了一個對象,你就必須手工地拆除這個對象。代碼越復雜,這個任務也越困難。Java用垃圾收集器來解決這個問題,由垃圾收集器搜集不再使用的對象並釋放內存。C#同樣採用了這種方法。應該說,如果你也在開發一種新的OOP語言,追隨這條道路是一種非常自然的選擇。C#仍舊保留了C++的內存手工管理方法,它適合在速度極端重要的場合使用,而在Java中這是不允許的。
2.19、異常處理
如果你聽說C#使用與Java相似的異常處理機制,你不會為此而驚訝,對吧?在C#中,所有的異常都從一個名為Exception的類派生(聽起來很熟悉?)另外,正如在Java中一樣,你還有熟悉的try和catch語句。Exception類屬於.NET System名稱空間的一部分。
三、Java沒有的功能
C#出生在Java成熟之後,因此,C#擁有一些Java(目前)還沒有的絕妙功能也就不足為奇。
3.1、枚舉器
枚舉器即enum類型(Enumerator,或稱為計數器),它是一個相關常量的集合。精確地說,enum類型聲明為一組相關的符號常量定義了一個類型名字。例如,你可以創建一個名為Fruit(水果)的枚舉器,把它作為一個變數值的類型使用,從而把變數可能的取值范圍限制為枚舉器中出現的值。
public class Demo {
public enum Fruit {
Apple, Banana, Cherry, Durian
}
public void Process(Fruit fruit) {
switch (fruit) {
case Fruit.Apple:
...
break;
case Fruit.Banana:
...
break;
case Fruit.Cherry:
...
break;
case Fruit.Durian:
...
break;
}
}
}
在上例的Process方法中,雖然你可以用int作為myVar變數的類型,但是,使用枚舉器Fruit之後,變數的取值范圍限制到了Applet、Banana、Cherry和Durian這幾個值之內。與int相比,enum的可讀性更好,自我說明能力更強。
3.2、結構
結構(Struct)與類很相似。然而,類是作為一種引用類型在堆中創建,而結構是一種值類型,它存儲在棧中或者是嵌入式的。因此,只要謹慎運用,結構要比類快。結構可以實現介面,可以象類一樣擁有成員,但結構不支持繼承。
然而,簡單地用結構來取代類可能導致慘重損失。這是因為,結構是以值的方式傳遞,由於這種傳遞方式要把值復制到新的位置,所以傳遞一個「肥胖的」結構需要較大的開銷。而對於類,傳遞的時候只需傳遞它的引用。
下面是一個結構的例子。注意它與類非常相似,只要把單詞「struct」替換成「class」,你就得到了一個類。
struct Point {
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
3.3、屬性
C#類除了可以擁有域(Field)之外,它還可以擁有屬性(Property)。屬性是一個與類或對象關聯的命名的特徵。屬性是域的一種自然擴展――兩者都是有類型、有名字的類成員。然而,和域不同的是,屬性不表示存儲位置;相反,屬性擁有存取器(accessor),存取器定義了讀取或者寫入屬性值時必須執行的代碼。因此,屬性提供了一種把動作和讀取、寫入對象屬性值的操作關聯起來的機制,而且它們允許屬性值通過計算得到。
在C#中,屬性通過屬性聲明語法定義。屬性聲明語法的第一部分與域聲明很相似,第二部分包括一個set過程和/或一個get過程。例如,在下面的例子中,PropertyDemo類定義了一個Prop屬性。
public class PropertyDemo {
private string prop;
public string Prop {
get {
return prop;
}
set {
prop = value;
}
}
}
如果屬性既允許讀取也允許寫入,如PropertyDemo類的Prop屬性,則它同時擁有get和set存取過程。當我們讀取屬性的值時,get存取過程被調用;當我們寫入屬性值時,set存取過程被調用。在set存取過程中,屬性的新值在一個隱含的value參數中給出。
與讀取和寫入域的方法一樣,屬性也可以用同樣的語法讀取和寫入。例如,下面的代碼實例化了一個PropertyDemo類,然後寫入、讀取它的Prop屬性。
PropertyDemo pd = new PropertyDemo();
pd.Prop = "123"; // set
string s = pd.Prop; // get
3.4、以引用方式傳遞簡單數據類型的參數
在Java中,當你把一個簡單數據類型的值作為參數傳遞給方法時,參數總是以值的方式傳遞――即,系統將為被調用的方法創建一個參數值的副本。在C#中,你可以用引用的方式傳遞一個簡單數據類型的值。此時,被調用的方法將直接使用傳遞給它的那個值――也就是說,如果在被調用方法內部修改了參數的值,則原來的變數值也隨之改變。
在C#中以引用方式傳遞值時,我們使用ref關鍵詞。例如,如果編譯並運行下面的代碼,你將在控制台上看到輸出結果16。注意i值被傳遞給ProcessNumber之後是如何被改變的。
using System;
public class PassByReference {
public static void Main(String[] args) {
int i = 8;
ProcessNumber(ref i);
Console.WriteLine(i);
}
public static void ProcessNumber(ref int j) {
j = 16;
}
}
C#中還有一個允許以引用方式傳遞參數的關鍵詞out,它與ref相似。但是,使用out時,作為參數傳遞的變數在傳遞之前不必具有已知的值。在上例中,如果整數i在傳遞給ProcessNumber方法之前沒有初始化,則代碼將出錯。如果用out來取代ref,你就可以傳遞一個未經初始化的值,如下面這個修改後的例子所示。
using System;
public class PassByReference {
public static void Main(String[] args) {
int i;
ProcessNumber(out i);
Console.WriteLine(i);
}
public static void ProcessNumber(out int j) {
j = 16;
}
}
經過修改之後,雖然i值在傳遞給ProcessNumber方法之前沒有初始化,但PassByReference類能夠順利通過編譯。
3.5、C#保留了指針
對於那些覺得自己能夠恰到好處地運用指針並樂意手工進行內存管理的開發者來說,在C#中,他們仍舊可以用既不安全也不容易使用的「古老的」指針來提高程序的性能。C#提供了支持「不安全」(unsafe)代碼的能力,這種代碼能夠直接操作指針,能夠「固定」對象以便臨時地阻止垃圾收集器移動對象。無論從開發者還是用戶的眼光來看,這種對「不安全」代碼的支持其實是一種安全功能。「不安全」的代碼必須用unsafe關鍵詞顯式地標明,因此開發者不可能在無意之中使用「不安全」的代碼。同時,C#編譯器又和執行引擎協作,保證了「不安全」的代碼不能偽裝成為安全代碼。
using System;
class UsePointer {
unsafe static void PointerDemo(byte[] arr) {
.
.
}
}
C#中的unsafe代碼適合在下列情形下使用:當速度極端重要時,或者當對象需要與現有的軟體(比如COM對象或者DLL形式的C代碼)交互時。
3.6、代理
代理(delegate)可以看作C++或者其他語言中的函數指針。然而,與函數指針不同的是,C#中的代理是面向對象的、類型安全的、可靠的。而且,函數指針只能用來引用靜態函數,但代理既能夠引用靜態方法,也能夠引用實例方法。代理用來封裝可調用方法。你可以在類裡面編寫方法並在該方法上創建代理,此後這個代理就可以被傳遞到第二個方法。這樣,第二個方法就可以調用第一個方法。
代理是從公共基類System.Delegate派生的引用類型。定義和使用代理包括三個步驟:聲明,創建實例,調用。代理用delegate聲明語法聲明。例如,一個不需要參數且沒有返回值的代理可以用如下代碼聲明:
delegate void TheDelegate();
創建代理實例的語法是:使用new關鍵詞,並引用一個實例或類方法,該方法必須符合代理指定的特徵。一旦創建了代理的實例,我們就可以用調用方法的語法調用它。
3.7、包裝和解除包裝
在面向對象的編程語言中,我們通常使用的是對象。但為了提高速度,C#也提供了簡單數據類型。因此,C#程序既包含一大堆的對象,又有大量的值。在這種環境下,讓這兩者協同工作始終是一個不可迴避的問題,你必須要有一種讓引用和值進行通信的方法。
在C#以及.NET運行時環境中,這個「通信」問題通過包裝(Boxing)和解除包裝(Unboxing)解決。包裝是一種讓值類型看起來象引用類型的處理過程。當一個值類型(簡單數據類型)被用於一個要求或者可以使用對象的場合時,包裝操作自動進行。包裝一個value-type值的步驟包括:分配一個對象實例,然後把value-type值復制到對象實例。
解除包裝所執行的動作與包裝相反,它把一個引用類型轉換成值類型。解除包裝操作的步驟包括:首先檢查並確認對象實例確實是給定value-type的一個經過包裝的值,然後從對象實例復制出值。
Java對該問題的處理方式略有不同。Java為每一種簡單數據類型提供了一個對應的類封裝器。例如,用Integer類封裝int類型,用Byte類封裝byte類型。
【結束語】本文為你比較了C#和Java。這兩種語言很相似,然而,說C#是Java的克隆或許已經大大地言過其實。面向對象、中間語言這類概念並不是什麼新東西。如果你准備設計一種面向對象的新語言,而且它必須在一個受管理的安全環境內運行,你難道不會搞出與C#差不多的東西嗎?
㈥ C寫的一個演算法 想轉成用java寫的
^^
privatelongGetcrc;
voidmy_crc32(Stringdata,longlen,longpoly)
{
inti,j;
longtemp=0;
longcrc=0xffffffff;
//ULONGpoly=0xEDB88320;
for(i=0;i<len;i++)
{
temp=(crc^data.toCharArray()[i])&0xff;
for(j=0;j<8;j++)
{
if((temp&1)==1)
temp=(temp>>1)^poly;
else
temp=temp>>1;
}
crc=(crc>>8)^temp;
}
crc=crc^0xffffffff;
Getcrc=crc;
// returncrc;
}
㈦ JAVA和C#相比哪個更好學它們各用於什麼領域的軟體開發
JAVA多用於大型網站的開發,安全,靈活,框架較多,方便.但學起來比較難.
C# 一般用於製作中小型網站(ASP.NET)和 各種Windows應用程序
簡單,方便,繼承微軟一貫作風,可視化,什麼東西都能拖拉拽出來.
但是不靈活,一切東西都是給你做好的,你要是想改一下那是相當費勁.並且微軟有沒有在你編譯好的程序里加了什麼爛七八糟的東西你也不知道
有什麼資格考試我不知道..
㈧ 與java相關的技術有哪些
一、JAVA相關技術點概覽:
RMI: java自身提供的用在分布時對象之間的通信機制。(類似於RPC)
RMI-IIOP: RMI的可移植擴展,可以實現JAVA與CORBA的集成。
JDBC: 用於資料庫訪問的通用介面。
JTA,JTS: 用於提供事務處理的支持。
JMS: java消息服務。可以連接已有的面向消息的中間件,例如:MQSeries,MSMQ。
Java Servlet: 用來擴展Web伺服器功能的網路組件。基於請求/響應機制。
JSP: Java與HTML混合編程,類似於ASP。
JavaIDL: Java對COBRA的實現,允許與其他預言集成。且能讓分布式對象利用CORBA提供的全面服務。所以J2EE與CORBA完全兼容。
Java Mail: 平台無關,協議無關地發送郵件。
J2EE連接器架構: 自動管理現有系統和中間件之間的諸多細節。
JAXP: Java操作XML。
JAAS: Java的用戶認證支持。
EJB: J2EE中最重要的部分,實現組件式開發的基礎。可以在多層的分布式環境中部署的伺服器端軟體組件。
JNI: (Java Native Interface)
聲明Native代碼,用C/C++實現它。可以實現:
1、 使用標准JAVA不支持的功能,例如訪問Win32API。
2、 重用其他語言編寫的庫或應用程序。例如大量的C庫。
3、 需要用低級語言編程時,例如匯編。
Oracle所實現的C底層代碼與Java的無縫集成,就是JNI技術的很好例證。Oracle不單使用Java界面,還支持Java編寫的存儲過程。
JNDI: 用於訪問命令和目錄系統。
JNDI為底層命名或目錄服務提供統一的API。可支持任何伺服器名稱,標准服務有:LDAP,NDS,CORBA,LDAP活動目錄等。
J2EE終,可用JNDI發布下列組件:EJB,數據源(資料庫),JMS消息隊列。
㈨ Java能不能實現後台鍵盤監聽
可以實現。
需要到http://java.net/projects/jna/downloads下載jna.jar和platform.jar(參考http://my.oschina.net/penngo/blog/12356):
packagejna_test;
importcom.sun.jna.platform.win32.*;
importcom.sun.jna.platform.win32.WinUser.*;
importcom.sun.jna.platform.win32.WinDef.HMODULE;
importcom.sun.jna.platform.win32.WinDef.LRESULT;
importcom.sun.jna.platform.win32.WinDef.WPARAM;
importcom.sun.jna.platform.win32.WinUser.HHOOK;
importcom.sun.jna.platform.win32.WinUser.KBDLLHOOKSTRUCT;
importcom.sun.jna.platform.win32.WinUser.LowLevelKeyboardProc;
importcom.sun.jna.win32.WinUser.Mouse.LowLevelMouseProc;
importcom.sun.jna.win32.WinUser.Mouse.MOUSEHOOKSTRUCT;
publicclassMouseLLHook{
//滑鼠鉤子函數里判斷按鍵類型的常數
publicstaticfinalintWM_LBUTTONUP=514;
publicstaticfinalintWM_LBUTTONDOWN=513;
publicstaticfinalintWM_RBUTTONUP=517;
publicstaticfinalintWM_RBUTTONDOWN=516;
publicstaticfinalintWM_MOUSEHWHEEL=526;
publicstaticfinalintWM_MOUSEWHEEL=522;
publicstaticfinalintWM_MOUSEMOVE=512;
staticHHOOKmouseHHK,keyboardHHK;//滑鼠、鍵盤鉤子的句柄
;//滑鼠鉤子函數
;//鍵盤鉤子函數
//安裝鉤子
staticvoidsetHook(){
HMODULEhMod=Kernel32.INSTANCE.GetMoleHandle(null);
mouseHHK=User32.INSTANCE.SetWindowsHookEx(WinUser.WH_MOUSE_LL,mouseHook,hMod,0);
keyboardHHK=User32.INSTANCE.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL,keyboardHook,hMod,0);
}
//卸載鉤子
staticvoinhook(){
User32.INSTANCE.UnhookWindowsHookEx(keyboardHHK);
User32.INSTANCE.UnhookWindowsHookEx(mouseHHK);
}
publicstaticvoidmain(String[]args){
keyboardHook=newLowLevelKeyboardProc(){
@Override
//該函數參數的意思參考:http://msdn.microsoft.com/en-us/library/windows/desktop/ms644985(v=vs.85).aspx
publicLRESULTcallback(intnCode,WPARAMwParam,KBDLLHOOKSTRUCTlParam){
intw=wParam.intValue();
//按下alt鍵時w=.WM_SYSKEYDOWN;按下其他大部分鍵時w=WinUser.WM_KEYDOWN
if(w==WinUser.WM_KEYDOWN||w==WinUser.WM_SYSKEYDOWN)
System.out.println("keydown:vkCode="+lParam.vkCode);
elseif(w==WinUser.WM_KEYUP||w==WinUser.WM_SYSKEYUP)
System.out.println("keyup:vkCode="+lParam.vkCode);
//如果按下'q'退出程序,'q'的vkCode是81
if(lParam.vkCode==81){
unhook();
System.err.println("programterminated.");
System.exit(0);
}
returnUser32.INSTANCE.CallNextHookEx(keyboardHHK,nCode,wParam,lParam.getPointer());
}
};
mouseHook=newLowLevelMouseProc(){
@Override
//該函數參數的意思參考:http://msdn.microsoft.com/en-us/library/windows/desktop/ms644986(v=vs.85).aspx
publicLRESULTcallback(intnCode,WPARAMwParam,MOUSEHOOKSTRUCTlParam){
switch(wParam.intValue()){
caseWM_MOUSEMOVE:
System.out.print("mousemoved:");
break;
caseWM_LBUTTONDOWN:
System.out.print("mouseleftbuttondown:");
break;
caseWM_LBUTTONUP:
System.out.print("mouseleftbuttonup");
break;
caseWM_RBUTTONUP:
System.out.print("mouserightbuttonup:");
break;
caseWM_RBUTTONDOWN:
System.out.print("mouserightbuttondown:");
break;
caseWM_MOUSEWHEEL:
System.out.print("mousewheelrotated:");
break;
}
System.out.println("("+lParam.pt.x+","+lParam.pt.y+")");
returnUser32.INSTANCE.CallNextHookEx(mouseHHK,nCode,wParam,lParam.getPointer());
}
};
System.out.println("press'q'toquit.");
setHook();
intresult;
MSGmsg=newMSG();
//消息循環
//實際上while循環一次都不執行,這些代碼的作用我理解是讓程序在GetMessage函數這里阻塞,不然程序就結束了。
while((result=User32.INSTANCE.GetMessage(msg,null,0,0))!=0){
if(result==-1){
System.err.println("errorinGetMessage");
unhook();
break;
}else{
User32.INSTANCE.TranslateMessage(msg);
User32.INSTANCE.DispatchMessage(msg);
}
}
unhook();
}
}
2.[代碼]以上代碼如果有兩個類找不到(不知什麼原因,我當時下載的版本就可以),那就只好自己寫了:
importcom.sun.jna.Structure;
importcom.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
importcom.sun.jna.platform.win32.WinDef.HWND;
importcom.sun.jna.platform.win32.WinDef.LRESULT;
importcom.sun.jna.platform.win32.WinDef.WPARAM;
importcom.sun.jna.platform.win32.WinUser.HOOKPROC;
importcom.sun.jna.platform.win32.WinUser.POINT;
{
LRESULTcallback(intnCode,WPARAMwParam,MOUSEHOOKSTRUCTlParam);
}
{
Structure.ByReference{
};
publicPOINTpt;
publicHWNDhwnd;
publicintwHitTestCode;
publicULONG_PTRdwExtraInfo;
}
㈩ C#和java有什麼不同
C#(C-Sharp)是Microsoft的新編程語言,被譽為「C/C++家族中第一種面向組件的語言」。然而,不管它自己宣稱的是什麼,許多人認為C#更像是Java的一種克隆,或者是Microsoft用來替代Java的產品。事實是否是這樣的呢?
本文的比較結果表明,C#不止是Java的同胞那麼簡單。如果你是一個Java開發者,想要學習C#或者了解更多有關C#的知識,那麼本文就是你必須把最初10分鍾投入於其中的所在。
一、C#、C++和Java
C#的語言規范由Microsoft的Anders Hejlsberg與Scott Wiltamuth編寫。在當前Microsoft天花亂墜的宣傳中,對C#和C++、Java作一番比較總是很有趣的。考慮到當前IT媒體的輿論傾向,如果你早就知道C#更接近Java而不是C++,事情也不值得大驚小怪。對於剛剛加入這場討論的讀者,下面的表1讓你自己作出判斷。顯然,結論應該是:Java和C#雖然不是孿生子,但C#最主要的特色卻更接近Java而不是C++。
表1:比較C#、C++和Java最重要的功能
功能 C# C++ Java
繼承 允許繼承單個類,允許實現多個介面 允許從多個類繼承 允許繼承單個類,允許實現多個介面
介面實現 通過「interface」關鍵詞 通過抽象類 通過「interface」關鍵詞
內存管理 由運行時環境管理,使用垃圾收集器 需要手工管理 由運行時環境管理,使用垃圾收集器
指針 支持,但只在很少使用的非安全模式下才支持。通常以引用取代指針 支持,一種很常用的功能。 完全不支持。代之以引用。
源代碼編譯後的形式 .NET中間語言(IL) 可執行代碼 位元組碼
單一的公共基類 是 否 是
異常處理 異常處理 返回錯誤 異常處理。
了解表1總結的重要語言功能之後,請繼續往下閱讀,了解C#和Java的一些重要區別。
二、語言規范的比較
2.1、簡單數據類型
簡單數據類型(Primitive)在C#中稱為值類型,C#預定義的簡單數據類型比Java多。例如,C#有unit,即無符號整數。表2列出了所有C#的預定義數據類型:
表2:C#中的值類型
類型 說明
object 所有類型的最終極的基類
string 字元串類型;字元串是一個Unicode字元的序列
sbyte 8位帶符號整數
short 16位帶符號整數
int 32位帶符號整數
long 64位帶符號整數
byte 8位無符號整數
ushort 16位無符號整數
uint 32位無符號整數
ulong 64位無符號整數
float 單精度浮點數類型
double 雙精度浮點數類型
bool 布爾類型;bool值或者是true,或者是false
char 字元類型;一個char值即是一個Unicode字元
decimal 有28位有效數字的高精度小數類型
2.2、常量
忘掉Java中的static final修飾符。在C#中,常量可以用const關鍵詞聲明。
public const int x = 55;
此外,C#的設計者還增加了readonly關鍵詞。如果編譯器編譯時未能確定常量值,你可以使用readonly關鍵詞。readonly域只能通過初始化器或類的構造函數設置。
2.3、公用類的入口點
在Java中,公用類的入口點是一個名為main的公用靜態方法。main方法的參數是String對象數組,它沒有返回值。在C#中,main方法變成了公用靜態方法Main(大寫的M),Main方法的參數也是一個String對象數組,而且也沒有返回值,如下面的原型聲明所示:
public static void Main(String[] args)
但是,C#的Main方法不局限於此。如果不向Main方法傳遞任何參數,你可以使用上述Main方法的一個重載版本,即不帶參數列表的版本。也就是說,下面的Main方法也是一個合法的入口點:
public static void Main()
另外,如果你認為有必要的話,Main方法還可以返回一個int。例如,下面代碼中的Main方法返回1:
using System;
public class Hello {
public static int Main() {
Console.WriteLine("Done");
return 1;
}
}
與此相對,在Java中重載main方法是不合法的。
2.4、switch語句
在Java中,switch語句只能處理整數。但C#中的switch語句不同,它還能夠處理字元變數。請考慮下面用switch語句處理字元串變數的C#代碼:
using System;
public class Hello {
public static void Main(String[] args) {
switch (args[0]) {
case "老闆":
Console.WriteLine("早上好!我們隨時准備為您效勞!");
break;
case "雇員":
Console.WriteLine("早上好!你可以開始工作了!");
break;
default:
Console.WriteLine("早上好!祝你好運!");
break;
}
}
}
與Java中的switch不同,C#的switch語句要求每一個case塊或者在塊的末尾提供一個break語句,或者用goto轉到switch內的其他case標簽。
2.5、foreach語句
foreach語句枚舉集合中的各個元素,為集合中的每一個元素執行一次代碼塊。請參見下面的例子。
using System;
public class Hello {
public static void Main(String[] args) {
foreach (String arg in args)
Console.WriteLine(arg);
}
}
如果在運行這個執行文件的時候指定了參數,比如「Hello Peter Kevin Richard」,則程序的輸出將是下面幾行文字:
Peter
Kevin
Richard
2.6、C#沒有>>>移位操作符
C#支持uint和ulong之類的無符號變數類型。因此,在C#中,右移操作符(即「>>」)對於無符號變數類型和帶符號變數類型(比如int和long)的處理方式不同。右移uint和ulong丟棄低位並把空出的高位設置為零;但對於int和long類型的變數,「>>」操作符丟棄低位,同時,只有當變數值是正數時,「>>」才把空出的高位設置成零;如果「>>」操作的是一個負數,空出的高位被設置成為1。
Java中不存在無符號的變數類型。因此,我們用「>>>」操作符在右移時引入負號位;否則,使用「>>」操作符。
2.7、goto關鍵詞
Java不用goto關鍵詞。在C#中,goto允許你轉到指定的標簽。不過,C#以特別謹慎的態度對待goto,比如它不允許goto轉入到語句塊的內部。在Java中,你可以用帶標簽的語句加上break或continue取代C#中的goto。
2.8、聲明數組
在Java中,數組的聲明方法非常靈活,實際上有許多種聲明方法都屬於合法的方法。例如,下面的幾行代碼是等價的:
int[] x = { 0, 1, 2, 3 };
int x[] = { 0, 1, 2, 3 };
但在C#中,只有第一行代碼合法,[]不能放到變數名字之後。
2.9、包
在C#中,包(Package)被稱為名稱空間。把名稱空間引入C#程序的關鍵詞是「using」。例如,「using System;」這個語句引入了System名稱空間。
然而,與Java不同的是,C#允許為名稱空間或者名稱空間中的類指定別名:
using TheConsole = System.Console;
public class Hello {
public static void Main() {
TheConsole.WriteLine("使用別名");
}
}
雖然從概念上看,Java的包類似於.NET的名稱空間。然而,兩者的實現方式不同。在Java中,包的名字同時也是實際存在的實體,它決定了放置.java文件的目錄結構。在C#校�錮淼陌�吐嘸�拿�浦�涫峭耆�擲氳模�簿褪撬擔��瓶占淶拿�植換岫暈錮淼拇虯�絞講��魏斡跋臁T贑#中,每一個源代碼文件可以從屬於多個名稱空間,而且它可以容納多個公共類。
.NET中包的實體稱為程序集(Assembly)。每一個程序集包含一個manifest結構。manifest列舉程序集所包含的文件,控制哪些類型和資源被顯露到程序集之外,並把對這些類型和資源的引用映射到包含這些類型與資源的文件。程序集是自包含的,一個程序集可以放置到單一的文件之內,也可以分割成多個文件。.NET的這種封裝機制解決了DLL文件所面臨的問題,即臭名昭著的DLL Hell問題。
2.10、默認包
在Java中,java.lang包是默認的包,它無需顯式導入就已經自動包含。例如,要把一些文本輸出到控制台,你可以使用下面的代碼:
System.out.println("Hello world from Java");
C#中不存在默認的包。如果要向控制台輸出文本,你使用System名稱空間Console對象的WriteLine方法。但是,你必須顯式導入所有的類。代碼如下:
using System;
public class Hello {
public static void Main() {
Console.WriteLine("Hello world from C#");
}
}
2.11、面向對象
Java和C#都是完全面向對象的語言。在面向對象編程的三大原則方面,這兩種語言接近得不能再接近。
繼承:這兩種語言都支持類的單一繼承,但類可以實現多個介面。所有類都從一個公共的基類繼承。
封裝與可見性:無論是在Java還是C#中,你都可以決定類成員是否可見。除了C#的internal訪問修飾符之外,兩者的可見性機制非常相似。
多態性:Java和C#都支持某些形式的多態性機制,且兩者實現方法非常類似。
2.12、可訪問性
類的每個成員都有特定類型的可訪問性。C#中的訪問修飾符與Java中的基本對應,但多出了一個internal。簡而言之,C#有5種類型的可訪問性,如下所示:
public:成員可以從任何代碼訪問。
protected:成員只能從派生類訪問。
internal:成員只能從同一程序集的內部訪問。
protected internal:成員只能從同一程序集內的派生類訪問。
private:成員只能在當前類的內部訪問。
2.13、派生類
在Java中,我們用關鍵詞「extends」實現繼承。C#採用了C++的類派生語法。例如,下面的代碼顯示了如何派生父類Control從而創建出新類Button:
public class Button: Control { . . }
2.14、最終類
由於C#中不存在final關鍵詞,如果想要某個類不再被派生,你可以使用sealed關鍵詞,如下例所示:
sealed class FinalClass { . . }
2.15、介面
介面這個概念在C#和Java中非常相似。介面的關鍵詞是interface,一個介面可以擴展一個或者多個其他介面。按照慣例,介面的名字以大寫字母「I」開頭。下面的代碼是C#介面的一個例子,它與Java中的介面完全一樣:
interface IShape { void Draw(); }
擴展介面的語法與擴展類的語法一樣。例如,下例的IRectangularShape介面擴展IShape介面(即,從IShape介面派生出IRectangularShape介面)。
interface IRectangularShape: IShape { int GetWidth(); }
如果你從兩個或者兩個以上的介面派生,父介面的名字列表用逗號分隔,如下面的代碼所示:
interface INewInterface: IParent1, IParent2 { }
然而,與Java不同,C#中的介面不能包含域(Field)。
另外還要注意,在C#中,介面內的所有方法默認都是公用方法。在Java中,方法聲明可以帶有public修飾符(即使這並非必要),但在C#中,顯式為介面的方法指定public修飾符是非法的。例如,下面的C#介面將產生一個編譯錯誤。
interface IShape { public void Draw(); }
2.16、is和as操作符
C#中的is操作符與Java中的instanceof操作符一樣,兩者都可以用來測試某個對象的實例是否屬於特定的類型。在Java中沒有與C#中的as操作符等價的操作符。as操作符與is操作符非常相似,但它更富有「進取心」:如果類型正確的話,as操作符會嘗試把被測試的對象引用轉換成目標類型;否則,它把變數引用設置成null。
為正確理解as操作符,首先請考慮下面這個例子中is操作符的運用。這個例子包含一個IShape介面,以及兩個實現了IShape介面的類Rectangle和Circle。
using System;
interface IShape {
void draw();
}
public class Rectangle: IShape {
public void draw() {
}
public int GetWidth() {
return 6;
}
}
public class Circle: IShape {
public void draw() {
}
public int GetRadius() {
return 5;
}
}
public class LetsDraw {
public static void Main(String[] args) {
IShape shape = null;
if (args[0] == "rectangle") {
shape = new Rectangle();
}
else if (args[0] == "circle") {
shape = new Circle();
}
if (shape is Rectangle) {
Rectangle rectangle = (Rectangle) shape;
Console.WriteLine("Width : " + rectangle.GetWidth());
}
if (shape is Circle) {
Circle circle = (Circle) shape;
Console.WriteLine("Radius : " + circle.GetRadius());
}
}
}
編譯好代碼之後,用戶可以輸入「rectangle」或者「circle」作為Main方法的參數。如果用戶輸入的是「circle」,則shape被實例化成為一個Circle類型的對象;反之,如果用戶輸入的是「rectangle」,則shape被實例化成為Rectangle類型的對象。隨後,程序用is操作符測試shape的變數類型:如果shape是一個矩形,則shape被轉換成為Rectangle對象,我們調用它的GetWidth方法;如果shape是一個圓,則shape被轉換成為一個Circle對象,我們調用它的GetRadius方法。
如果使用as操作符,則上述代碼可以改成如下形式:
using System;
interface IShape {
void draw();
}
public class Rectangle: IShape {
public void draw() {
}
public int GetWidth() {
return 6;
}
}
public class Circle: IShape {
public void draw() {
}
public int GetRadius() {
return 5;
}
}
public class LetsDraw {
public static void Main(String[] args) {
IShape shape = null;
if (args[0] == "rectangle") {
shape = new Rectangle();
}
else if (args[0] == "circle") {
shape = new Circle();
}
Rectangle rectangle = shape as Rectangle;
if (rectangle != null) {
Console.WriteLine("Width : " + rectangle.GetWidth());
}
else {
Circle circle = shape as Circle;
if (circle != null)
Console.WriteLine("Radius : " + circle.GetRadius());
}
}
}
在上面代碼的粗體部分中,我們在沒有測試shape對象類型的情況下,就用as操作符把shape轉換成Rectangle類型的對象。如果shape正好是一個Rectangle,則shape被轉換成為Rectangle類型的對象並保存到rectangle變數,然後我們調用它的GetWidth方法。如果這種轉換失敗,則我們進行第二次嘗試。這一次,shape被轉換成為Circle類型的對象並保存到circle變數。如果shape確實是一個Circle對象,則circle現在引用了一個Circle對象,我們調用它的GetRadius方法。
2.17、庫
C#沒有自己的類庫。但是,C#共享了.NET的類庫。當然,.NET類庫也可以用於其他.NET語言,比如VB.NET或者JScript.NET。值得一提的是StringBuilder類,它是對String類的補充。StringBuilder類與Java的StringBuffer類非常相似。
2.18、垃圾收集
C++已經讓我們認識到手工管理內存是多麼缺乏效率和浪費時間。當你在C++中創建了一個對象,你就必須手工地拆除這個對象。代碼越復雜,這個任務也越困難。Java用垃圾收集器來解決這個問題,由垃圾收集器搜集不再使用的對象並釋放內存。C#同樣採用了這種方法。應該說,如果你也在開發一種新的OOP語言,追隨這條道路是一種非常自然的選擇。C#仍舊保留了C++的內存手工管理方法,它適合在速度極端重要的場合使用,而在Java中這是不允許的。
2.19、異常處理
如果你聽說C#使用與Java相似的異常處理機制,你不會為此而驚訝,對吧?在C#中,所有的異常都從一個名為Exception的類派生(聽起來很熟悉?)另外,正如在Java中一樣,你還有熟悉的try和catch語句。Exception類屬於.NET System名稱空間的一部分。
三、Java沒有的功能
C#出生在Java成熟之後,因此,C#擁有一些Java(目前)還沒有的絕妙功能也就不足為奇。
3.1、枚舉器
枚舉器即enum類型(Enumerator,或稱為計數器),它是一個相關常量的集合。精確地說,enum類型聲明為一組相關的符號常量定義了一個類型名字。例如,你可以創建一個名為Fruit(水果)的枚舉器,把它作為一個變數值的類型使用,從而把變數可能的取值范圍限制為枚舉器中出現的值。
public class Demo {
public enum Fruit {
Apple, Banana, Cherry, Durian
}
public void Process(Fruit fruit) {
switch (fruit) {
case Fruit.Apple:
...
break;
case Fruit.Banana:
...
break;
case Fruit.Cherry:
...
break;
case Fruit.Durian:
...
break;
}
}
}
在上例的Process方法中,雖然你可以用int作為myVar變數的類型,但是,使用枚舉器Fruit之後,變數的取值范圍限制到了Applet、Banana、Cherry和Durian這幾個值之內。與int相比,enum的可讀性更好,自我說明能力更強。
3.2、結構
結構(Struct)與類很相似。然而,類是作為一種引用類型在堆中創建,而結構是一種值類型,它存儲在棧中或者是嵌入式的。因此,只要謹慎運用,結構要比類快。結構可以實現介面,可以象類一樣擁有成員,但結構不支持繼承。
然而,簡單地用結構來取代類可能導致慘重損失。這是因為,結構是以值的方式傳遞,由於這種傳遞方式要把值復制到新的位置,所以傳遞一個「肥胖的」結構需要較大的開銷。而對於類,傳遞的時候只需傳遞它的引用。
下面是一個結構的例子。注意它與類非常相似,只要把單詞「struct」替換成「class」,你就得到了一個類。
struct Point {
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
3.3、屬性
C#類除了可以擁有域(Field)之外,它還可以擁有屬性(Property)。屬性是一個與類或對象關聯的命名的特徵。屬性是域的一種自然擴展――兩者都是有類型、有名字的類成員。然而,和域不同的是,屬性不表示存儲位置;相反,屬性擁有存取器(accessor),存取器定義了讀取或者寫入屬性值時必須執行的代碼。因此,屬性提供了一種把動作和讀取、寫入對象屬性值的操作關聯起來的機制,而且它們允許屬性值通過計算得到。
在C#中,屬性通過屬性聲明語法定義。屬性聲明語法的第一部分與域聲明很相似,第二部分包括一個set過程和/或一個get過程。例如,在下面的例子中,PropertyDemo類定義了一個Prop屬性。
public class PropertyDemo {
private string prop;
public string Prop {
get {
return prop;
}
set {
prop = value;
}
}
}
如果屬性既允許讀取也允許寫入,如PropertyDemo類的Prop屬性,則它同時擁有get和set存取過程。當我們讀取屬性的值時,get存取過程被調用;當我們寫入屬性值時,set存取過程被調用。在set存取過程中,屬性的新值在一個隱含的value參數中給出。
與讀取和寫入域的方法一樣,屬性也可以用同樣的語法讀取和寫入。例如,下面的代碼實例化了一個PropertyDemo類,然後寫入、讀取它的Prop屬性。
PropertyDemo pd = new PropertyDemo();
pd.Prop = "123"; // set
string s = pd.Prop; // get
3.4、以引用方式傳遞簡單數據類型的參數
在Java中,當你把一個簡單數據類型的值作為參數傳遞給方法時,參數總是以值的方式傳遞――即,系統將為被調用的方法創建一個參數值的副本。在C#中,你可以用引用的方式傳遞一個簡單數據類型的值。此時,被調用的方法將直接使用傳遞給它的那個值――也就是說,如果在被調用方法內部修改了參數的值,則原來的變數值也隨之改變。
在C#中以引用方式傳遞值時,我們使用ref關鍵詞。例如,如果編譯並運行下面的代碼,你將在控制台上看到輸出結果16。注意i值被傳遞給ProcessNumber之後是如何被改變的。
using System;
public class PassByReference {
public static void Main(String[] args) {
int i = 8;
ProcessNumber(ref i);
Console.WriteLine(i);
}
public static void ProcessNumber(ref int j) {
j = 16;
}
}
C#中還有一個允許以引用方式傳遞參數的關鍵詞out,它與ref相似。但是,使用out時,作為參數傳遞的變數在傳遞之前不必具有已知的值。在上例中,如果整數i在傳遞給ProcessNumber方法之前沒有初始化,則代碼將出錯。如果用out來取代ref,你就可以傳遞一個未經初始化的值,如下面這個修改後的例子所示。
using System;
public class PassByReference {
public static void Main(String[] args) {
int i;
ProcessNumber(out i);
Console.WriteLine(i);
}
public static void ProcessNumber(out int j) {
j = 16;
}
}
經過修改之後,雖然i值在傳遞給ProcessNumber方法之前沒有初始化,但PassByReference類能夠順利通過編譯。
3.5、C#保留了指針
對於那些覺得自己能夠恰到好處地運用指針並樂意手工進行內存管理的開發者來說,在C#中,他們仍舊可以用既不安全也不容易使用的「古老的」指針來提高程序的性能。C#提供了支持「不安全」(unsafe)代碼的能力,這種代碼能夠直接操作指針,能夠「固定」對象以便臨時地阻止垃圾收集器移動對象。無論從開發者還是用戶的眼光來看,這種對「不安全」代碼的支持其實是一種安全功能。「不安全」的代碼必須用unsafe關鍵詞顯式地標明,因此開發者不可能在無意之中使用「不安全」的代碼。同時,C#編譯器又和執行引擎協作,保證了「不安全」的代碼不能偽裝成為安全代碼。
using System;
class UsePointer {
unsafe static void PointerDemo(byte[] arr) {
.
.
}
}
C#中的unsafe代碼適合在下列情形下使用:當速度極端重要時,或者當對象需要與現有的軟體(比如COM對象或者DLL形式的C代碼)交互時。
3.6、代理
代理(delegate)可以看作C++或者其他語言中的函數指針。然而,與函數指針不同的是,C#中的代理是面向對象的、類型安全的、可靠的。而且,函數指針只能用來引用靜態函數,但代理既能夠引用靜態方法,也能夠引用實例方法。代理用來封裝可調用方法。你可以在類裡面編寫方法並在該方法上創建代理,此後這個代理就可以被傳遞到第二個方法。這樣,第二個方法就可以調用第一個方法。
代理是從公共基類System.Delegate派生的引用類型。定義和使用代理包括三個步驟:聲明,創建實例,調用。代理用delegate聲明語法聲明。例如,一個不需要參數且沒有返回值的代理可以用如下代碼聲明:
delegate void TheDelegate();
創建代理實例的語法是:使用new關鍵詞,並引用一個實例或類方法,該方法必須符合代理指定的特徵。一旦創建了代理的實例,我們就可以用調用方法的語法調用它。
3.7、包裝和解除包裝
在面向對象的編程語言中,我們通常使用的是對象。但為了提高速度,C#也提供了簡單數據類型。因此,C#程序既包含一大堆的對象,又有大量的值。在這種環境下,讓這兩者協同工作始終是一個不可迴避的問題,你必須要有一種讓引用和值進行通信的方法。
在C#以及.NET運行時環境中,這個「通信」問題通過包裝(Boxing)和解除包裝(Unboxing)解決。包裝是一種讓值類型看起來象引用類型的處理過程。當一個值類型(簡單數據類型)被用於一個要求或者可以使用對象的場合時,包裝操作自動進行。包裝一個value-type值的步驟包括:分配一個對象實例,然後把value-type值復制到對象實例。
解除包裝所執行的動作與包裝相反,它把一個引用類型轉換成值類型。解除包裝操作的步驟包括:首先檢查並確認對象實例確實是給定value-type的一個經過包裝的值,然後從對象實例復制出值。
Java對該問題的處理方式略有不同。Java為每一種簡單數據類型提供了一個對應的類封裝器。例如,用Integer類封裝int類型,用Byte類封裝byte類型。
【結束語】本文為你比較了C#和Java。這兩種語言很相似,然而,說C#是Java的克隆或許已經大大地言過其實。面向對象、中間語言這類概念並不是什麼新東西。如果你准備設計一種面向對象的新語言,而且它必須在一個受管理的安全環境內運行,你難道不會搞出與C#差不多的東西嗎?