标签 程序员 下的文章

Everything is an object

读过《Thinking in Java》中著名的一章“Everything is an object”,而且不止一遍,不过经过今天和Dreamhead的探讨,才发现我对Java中的“Everything is an object”的理解还是那么的不到位。

我和Dreamhead谈到我在研究Java 5.0时遇到的问题:

String[] s = {“Hello” ,
              “Tiger”,
              “!”};

现在我想用传统的for loop来打印出字符串数组内的每一个字符串,我的问题是我该如何获取这个数组内的元素个数。我便查询一下jdk的doc,发现String类有一个length()方法,我就在s上使用了,结果编译器提示“can not find the method”,我就很奇怪了,为什么查到了String类下有概method,而compiler却提示找不到呢?后来我也使用了s.length,编译也通过了,执行也正确了。但是我心中的疑惑一直没有解开。今天和Dreamhead讨论下一步项目的工作计划时提到了这个问题,Dreamhead首先就说出了“Everything is an object”,String s是一个object ,同样String[] s也是一个object,也就是说我应该将String[] 放在一起看作一个类型,而不仅仅认为这是个String 类型的静态数组。这样length作为String[]类型的一个field就顺理成章了,我也就茅塞顿开了。也许上面的问题对于java老手来说很easy或者说根本不屑一提,但是对于我这个由C++过渡到java的选手来言,理解这个是很重要的。

最后还是牢记“Everything is an object in java”。是不是我的题目有些大呀^_^。

“我们不仅仅是小小程序员,我们还是普通人。”—– Darwin_yuan

Java 5.0新特性研究(一)

DreamHead计划使用"Java 5.0 Tiger"来开发我们的Dominoo,理由是:2-3年后"Tiger" will be mature。

我们对刚刚发布不久的"Tiger"了解的不多,晚上我们几个group member坐了下来,听DreamHead讲解"Tiger"的新特性。回到寝室自己做了些实验,有了些体会。

通过对"Tiger"的讨论和研究,得知Sun推出"Tiger"目的就是为了简化Java程序员的开发工作。在下面的详细解释及代码例子中你会深刻的体会到这一点。

1、Auto-boxing and auto-unboxing conversion

Problem:
─ Conversion between primitive types and wrapper objects (and vice-versa)
─ Needed when adding primitives to a collection

Java 5.0给我们的解决方案就是:Let the compiler(Javac) do it。事实上javac真的是这么做的么,耳听为虚,眼见为实,看代码吧!

我使用IntelliJ-Idea4.5.2写的代码(现在IntelliJ4.5已经可以支持jdk5.0的语法了,今早看了一下Eclipse的网站,Eclipse要到3.1才支持jdk5.0新加入的特性)[注]:在IntelliJ4.5中"File"—〉"Setting"—〉左下角"Classic View"最下面的"Language level for project"选择5.0即可。

/*
 * test auto-boxing and auto-unboxing
 */
//old 1.4 style
Integer intObj1 = new Integer(22);
int i = intObj1.intValue();
System.out.println(i);      //output: 22

//new 1.5 style
Integer intObj2 = 23;  //auto-boxing
int j = intObj2;      //auto-unboxing
System.out.println(j); //output: 23

//old 1.4 style
ArrayList al1 = new ArrayList();
al1.add(new Integer(24)); //or al1.add(Integer.valueOf(24))

//new 1.5 style
ArrayList al2 = new ArrayList();
al2.add(24);   // auto-boxing conversion   

编译为.class模块后,我们使用DJ Java Decompiler重新反编译得到以下代码(只写出对应上面代码的):
Integer intObj1 = new Integer(22);
int i = intObj1.intValue();
System.out.println(i);

Integer intObj2 = Integer.valueOf(23);
int j = intObj2.intValue();
System.out.println(j);

ArrayList al1 = new ArrayList();
al1.add(new Integer(24));

ArrayList al2 = new ArrayList();
al2.add(Integer.valueOf(24));

从上面代码中我们也可以看出,javac的确帮了我们的忙,它把繁重的活都揽去了,给我们留下了清闲,哦,忘说了,俺也是懒人^_^。

2、Generics in java
Problem: Collection element types
– Can not be checked at compile time
– Assignment must use cast
– Can cause runtime exception or errors(ClassCastException)

解决方案:
–Tell the compiler what type your collection is
– Compiler can fill in casts for you
还是那个原则,告诉编译器你的collection中需要什么类型,编译器为你完成一切(类型检查,转型等)。看代码:

ArrayList strArrayList = new ArrayList();
strArrayList.add("Hello");
System.out.println(strArrayList.iterator().next());  //output:Hello
System.out.println(strArrayList.getClass());        //output:class java.util.ArrayList

反编译后代码:
ArrayList strArrayList = new ArrayList();
strArrayList.add("Hello");
System.out.println((String)strArrayList.iterator().next());
System.out.println(strArrayList.getClass());

实际上包括转型等都是javac帮我们做了。 从上面的代码中我们还能看出问题:看紫色标记的代码,我们打印strArrayList的类型,该变量在声明的时候是ArrayList类型的,我们的头脑里会认为打印出的应该是"class java.util.ArrayList",可实际打印出的信息告诉我们collection中的元素的类型信息被丢弃了。也就是说ArrayList和ArrayList本不该是同一类型,不过我们看到的实际情况却是他们是同一类型。由于java中的generic只是在compiler一级得到支持,在jvm一级是不知道有generic这回事的,也许sun可能在不久的将来修正这一缺陷,别忘了java的强大的竞争对手C# 在2.0中已经在vm中加入对generic的支持。

这里要提一下DreamHead对java模板的理解,挺逗的,蛮有启发性。DreamHead用 "剧本  电影版本"来理解java generic:

射雕剧本  83版射雕 = new  射雕剧本();
射雕剧本  03版射雕 = new  射雕剧本();

Java generic与其他预言generic的简单比较,Java在compiler一级加入generic,导致的后果就是丢掉了类型信息,我们知道C++模板是不会丢掉类型信息的,但是会使可执行文件大小发生膨胀。C#2.0由于有VM的支持,所以既拥有类型信息,又不会使可执行文件的体积膨胀,但是总体来言,C++的generic最强大,也最成熟,当然和它支持的比较早也不无关系。

[注] 在《Adding Generics to the Java Programming Language:Participant Draft Specification》一文中关于上述问题有以下说明:

A parameterized class or interface declaration defines a set of types, one for each possible instantiation of the type parameter section. All parameterized types share the same class or interface at runtime.

For instance, the code:
Vector x = new Vector();
Vector y = new Vector();
return x.getClass() == y.getClass();

will yield true.

3、Enhanced for loop(foreach)
C#早已引入foreach这个关键字,C++也提供foreach算法(如果要弄懂这个需要学习的东西就比较多了^_^),java从jdk5.0开始引入这种高级for-loop机制,不过java的设计者还是很聪明的,java并没有引入新的关键字,因为要是这样做的话,需要进行的改动工作就太多了。Java利用原有的for关键字和一个":"就把这个完成了,不过java引入这一机制也只是方便程序员开发,这一机制也都是由javac来支持的,jvm一级并不知道foreach这一机制的存在。我们看看代码吧!

Vector strVec = new Vector();
strVec.add("Hello");
strVec.add("Tiger");
strVec.add("!");

//old 1.4 style – dynamic container
for (Iterator i = strVec.iterator(); i.hasNext(); ){
    System.out.println(i.next());
}

//new 1.5 style – dynamic container
for ( String str1 : strVec ){
    System.out.println(str1);
}

String [] strArray = {
    "Java 2",
    "Platform",
    "Standard",
    "Edition",
    "1.5"};
//old 1.4 style – static container
for(int i = 0 ; i < strArray.length ; ++i){
    System.out.println(strArray[i]);
}

//new 1.5 style – static container
for(String str2 : strArray){
    System.out.println(str2);
}
我们还是来看看反编译后的代码:
for(Iterator iterator1 = vector.iterator(); iterator1.hasNext(); System.out.println(s))
s = (String)iterator1.next();

String args2[] = args1;
int j = args2.length;
for(int k = 0; k < j; k++)
{
    String s1 = args2[k];
    System.out.println(s1);
}
注:上面对应颜色的代码相对应。

可以看出javac又在帮我们的忙。紫色部分我们看到仅用3行代码就搞定,而编译器得辛苦生成那么多代码。

4、Type safe Enumerations
Java不支持enum是java程序员抱怨较多的,这次sun终于在java5.0中加入了对enum的支持,不过还是如上面几个new features一样,只是在java compiler一级支持。

我们看看enum类型被javac转换成什么了?
//Color.java
public enum Color {
    RED,
    GREEN,
    BLUE
};

上面是一个很简单的enum声明,下面是反编译器输出的代码:
public final class Color extends Enum
{

    public static final Color[] values()
    {
        return (Color[])$VALUES.clone();
    }

    public static Color valueOf(String s)
    {
        Color acolor[] = $VALUES;
        int i = acolor.length;
        for(int j = 0; j < i; j++)
        {
            Color color = acolor[j];
            if(color.name().equals(s))
                return color;
        }

        throw new IllegalArgumentException(s);
    }

    private Color(String s, int i)
    {
        super(s, i);
    }

    public static final Color RED;
    public static final Color GREEN;
    public static final Color BLUE;
    private static final Color $VALUES[];

    static
    {
        RED = new Color("RED", 0);
        GREEN = new Color("GREEN", 1);
        BLUE = new Color("BLUE", 2);
        $VALUES = (new Color[] {
            RED, GREEN, BLUE
        });
    }
}

在sun公司的一份培训材料中写到:
Problem:
—-Variable needs to hold limited set of values e.g. card suit can only be spade, diamond, club, heart
Solution:
—New type of class declaration Enum type has public, self-typed members for each enum constant
—New keyword, enum Works with switch statement

下面我们根据上面的叙述来使用一下enum:
public class TestEnum{
    public enum Color {
            RED,
            GREEN,
            BLUE
        };
    public static void main(String[] args) {
        for (Color clr : Color.values() ){
            System.out.println(clr);
            /*output:
                RED
                GREEN
                BLUE
            */
        }        
    }
}

反编译后我们会看到如下的代码:
public static void main(String args[])
{
        Color acolor[] = Color.values();
        int i = acolor.length;
        for(int j = 0; j < i; j++)
        {
            Color color = acolor[j];
            System.out.println(color);
        }
}

通过这两个例子也可以看出enum不过是从Enum继承下来的类罢了,只是javac将相关的变换细节隐藏了。不过却给我们带来了极大的便利。

5、Varargs
Problem:
— To have a method that takes a variable number of parameters
— Can be done with an array, but not nice
— Look at java.text.MessageFormat

Solution: Let the compiler do it for you
— New syntax:
— public static String format (String fmt , Object… args);
— Java. gets printf !

例子:
public static void myPrintf(Object… args){
        for(Object obj : args){
            System.out.println(obj);
        }
}

public static void main(String[] args) {
    int i = 6;
    myPrintf("Hello" , "Tiger" , "Java 5.0");
    myPrintf("Harbin" ,"Beijing","Shenyang" ,"Changchun");
    myPrintf("The number is :" , i);
}

我们看一下反编译器输出的代码:

public static transient void myPrintf(Object aobj[])
{
    Object aobj1[] = aobj;
    int i = aobj1.length;
    for(int j = 0; j < i; j++)
    {
        Object obj = aobj1[j];
        System.out.println(obj);
    }
}

byte byte0 = 6;
myPrintf(new Object[] {
    "Hello", "Tiger", "Java 5.0"
});
myPrintf(new Object[] {
    "Harbin", "Beijing", "Shenyang", "Changchun"
});
myPrintf(new Object[] {
    "The number is :", Integer.valueOf(byte0)
});

从反编译的代码可以看出javac内部使用了数组来完成对变参数的支持。

6、Static imports
Problem:
—Having to fully qualify every static referenced from external classes

Solution: New import syntax
—import static TypeName.Identifier;
—import static Typename.*;
—Also works for static methods and enums e.g Math.sin(x) becomes sin(x)

上面是引用sun那个ppt中的一些东东,这个我就不想详细写了,今天较累,看看电影轻松一下吧!

Java5.0第一部分就写到这。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats