从C#到Java入门指引之二——类
首发:http://www.eoeandroid.com/thread-233275-1-1.html
eoe社区索引大集合:
http://www.eoeandroid.com/portal.php?mod=topic&topicid=5
android 翻页卷曲效果(内含源码)
http://www.eoeandroid.com/thread-232572-1-1.html
Android两侧推出导航菜单的实现
http://www.eoeandroid.com/thread-232567-1-1.html
-----------------帖子正文--------------------
对于一种面向对象语言来说,类是它的核心。这一讲,我们就来说说Java的类吧。
忘掉struct,Java只有class
在C#中,我们常常把比较小的数据结构声明成结构体(struct),这样生成的对象会分配在堆栈上(注),属于值类型,传递时会复制对象。
在Java中,一切自定义的数据结构都是类(class),它们被分配在堆上,属于引用类型,传递时仅传递引用。
我们可以画一个表:
Java的枚举和C#的不一样。C#的枚举是对整数类型(可以byte、short、int、long等等,char除外)的简单封装,而Java的枚举是一个完整功能的类。
注:如果结构体是某个类的成员变量,那么它还是会被分配在托管堆上。
访问修饰符
哈哈,还是发现用表格最直观
可以看出,C#中访问修饰符的使用细节更繁琐,但两者实现的功能基本一致。
其中需要注意的区别是,对于类内部的成员,当缺省访问修饰符时,C#认为这是私有,而Java认为这是包内可访问。就这一点,个人感觉像C#这样把缺省处理成私有更自然一些。
不一样的关键字,不一样的表示符号
既然是两种语言嘛,总有些符号和关键字的的用法不怎么一样:
藏起来的virtual
Java的代码里似乎没见过virtual吧?
的确是如此,因为Java认定所有方法缺省就是virtual,与基类具有相同签名的方法缺省就是override。
那不想做成虚方法怎么办?那就加上final关键字。
有时候,想override的时候,没写对方法的整个签名,比如返回类型明明是int写成long了。这时候编译器不会报错,而是默默地生成了一个新的方法。
为了杜绝这种状况,Java
5添加了@Override注解,用来标明重写的方法。如果这个方法没有正确重写基类中的方法,编译器会报一个错。
public class SomeCollection{ @Override public String toString(){ return super.toString(); } }
失落的运算符重载
这个C++都有的特性,Java居然没有...我能不能吐槽...罢了,不加入运算符重载这个特性,也是有利有弊:
利:Java语法更简单、易读。
弊:Java语言的表达能力更弱,灵活性更差。比如C#重载了字符串的==运算符,保证了语义上的一致性;C#中的列表和字典都是可以使用[]的,使代码变得更直观,而Java中只有数组才能这么写。
Java把这个特性砍掉,还是蛮可惜的。像字符串的判等、列表的随机访问这些事儿在Java中只是稍微麻烦一些。但如果你尝试在Java中封装一个矩阵类,并使用它来实现某个算法,我敢肯定你会为各种小括号的嵌套而抓狂的。
既然不让重载运算符,那么字符串之间为啥又可以用+连起来?
这个问题问得好!
真相是,你只要把不能加的对象用+连起来,编译器会自动把它们给toString了,然后放到StringBuilder里连上!
关于Object
在C#中,object是除指针外所有类型的基类;而在Java中,Object是除基本类型外所有类型的基类。
两者的设计差不多,有这么几个公开的方法,可以一一对应。除了取得第一个,其他几个方法都可以被重写:
类内的初始化块
刚从C#转过来的同学可能会被类内部“莫名其妙”出现的大括号给弄糊涂了,“这段代码时干神马的呢”
public class SomeCollection{ private int[] mArray; { mArray = new int[10]; for(int i=0; i<10; i++){ mArray[ i] = i; } } public SomeCollection{ } }
那是Java的初始化块,它会在构造方法执行之前执行。
如果有一个字段的初始化不能在=右边用一句话搞定,并且所有构造方法都需要用的话,可以考虑提取出来弄成初始化块。
另外,针对静态字段也有对应的静态初始化块,在前面的大括号前加上“static”就行啦。