Java - 软件界的擎天柱

作者: 尤汐Yogy | 来源:发表于2015-08-29 17:03 被阅读5300次

    写在前面

    本文为那些年我们追过的语言之Java篇。Java是一门使用广泛的向对象开发语言,用于开发应用程序的技术,通用高效安全。由于Java并非我的专长,本文由@Moonbal 主笔,我仅做完善补充。

    学点Java

    Java开发分为三个方向:

    1. J2SE(标准版):桌面应用程序开发/网络管理/电信
    2. J2EE(企业版):Web开发/电子商务/安全网站
    3. J2ME(移动版):手机游戏

    Java资源推荐:

    • Thinking in Java
      经典教程1
    • Effective Java
      经典教程2
    • Java 8 in Action: Lambdas, streams, and functional-style programming
      Java从Java8也开始支持函数式编程了。对于函数式编程,它是一种编程思想,在Java中使用函数式编程是为了使代码更简洁,且更可读。
    • 深入理解Java虚拟机
      JVM是Java的核心与基础,有人说,没有学习过JVM却说自己“精通Java”的同学就是在耍流氓。
    • 尚硅谷
      网站视频包括《Java 基础》、《Web 开发》、《JavaEE 框架》以及《Android 开发》,并且都是可以免费下载的。如果要学习建服务器和做项目,这里的内容蛮齐全的。
    • ImportNew
      这里有很多关于 Java 的优秀文章,基本每天都会有更新。

    Mac中的Java开发

    下面是OS X 10.10系统环境下,Java Web开发的环境配置与实现。

    1. 下载 JDK for Mac OS X

    2. 下载 Eclipse IDE for Java EE Developers

    3. 下载 Apache Tomcat(点击 Binary Distributions 下面第一行的 zip

    4. 切换到解压后的Tomcat目录下,执行下列命令:

    # 当前在 apache-tomcat 目录下
    cd bin
    sudo chmod 755 *.sh
    ./startup.sh    # 打开服务。使用 ./shutdown.sh 可关闭服务
    
    1. 在 eclipse 中配置 apache-tomcat 服务(这一步是让 eclipse 知道有 apache-tomcat 服务,类似于创建类):快捷键 cmd + , -> 选择左边的 Server -> 选择 Runtime Environments -> 点击右上角 Add... -> 选择安装的 apache-tomcat 版本 -> 点击 next -> 点击 Browse... 选择 apache-tomcat 的根目录 -> 点击 Installed JREs... 选择正确的 JRE -> 点击 finish

    2. 参考eclipse中如何新建tomcat服务,在 eclipse 中新建 tomcat 服务(这一步是在 eclipse 中创建并打开服务,类似于创建实例)。如果服务没有开启(显示 Stopped),右键单击服务,选择 Start。如果在控制台中打开了 apache 服务,则 eclipse 会提示:8080 端口被占用。需先在控制台关闭 apache 服务,再回到 eclipse 打开服务。

    3. 选择 File -> New -> Dynamic Web Project -> 输入工程名,创建好工程后 -> 在工程目录的 WebContent 目录下新建一个 html 文件 -> 右键该文件,选择 Run As,点击 Run On Server -> 选择后点击 finish。这样,就能在 eclipse 自带的浏览器中看到新建的 html 网页了,网址的格式为:http://localhost:8080/工程名/文件名。所以说工程目录的 WebContent 目录就是网站的所有网页文件的保存目录了。

    4. 刚刚只是写了个静态 html 页面。接下来就要开始编写服务端,Servlet 客户端与服务端交互的中枢。客户端的请求要发给服务端的 Servlet,并在 Servlet 中处理后返回响应给客户端。打开工程目录下的 Java Resources,该目录下的 src 目录,它将保存工程的所有 Java 文件。双击 src -> 选择 New -> 选择 Class,输入 Name: MyServlet。复制下面代码到该文件中,然后按快捷键 cmd + shift + o 导入所需包。

    @WebServlet(urlPatterns = {"/yogy.cc"}) 
    // 它的作用是 HTTP 请求的 path 为 /yogy.cc 会把请求映射到这个 Servlet 做处理
    // 最前面的 / 代表工程目录
    public class MyServlet extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
        
        @Override
        protected void doGet(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException 
        {
            // 请求的相关信息都可在 request 里找到
            // 要对客户端做出的响应通过 response 实现
            response.setContentType("text/html;charset=UTF-8");
            PrintWriter out = response.getWriter();
            try {
                // 返回 JSON 数据直接返回 JSON 字符串
                out.println("<html><head>");
                out.println("<head>");
                out.println("<title>MyServlet</title>");
                out.println("</head>");
                out.println("<body>");
                out.println("<h1>Servlet MyFirstServlet at " + request.getContextPath() + "</h1>");
                out.println("</body></html>");
            } finally {
                out.close();
            }
        }
     
        @Override
        protected void doPost(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {
            //Do some other work
        }
    }
    

    双击该文件点 Run As,点击 Run On Server -> 选择后点击 finish。仔细观察浏览器中链接的路径,并修改上面类文件,尝试不同结果。如果你有其他网络编程的经验,你应该很轻松就明白了客户端和服务端是怎么交互的。如果想继续学习 Java 网络编程,请参考 尚硅谷视频链接

    黑魔法

    1. Hello World

    So Easy?那可不一定,请看下面代码。

    import java.util.Random;
    
    public class Yogy {
        public static void main(String[] args) {
            System.out.println(helloWorld());
        }    
        
        public static String randomString(int s) {
            Random ran = new Random(s);
            StringBuilder sb = new StringBuilder();
            for (int k; (k = ran.nextInt(27)) != 0; ) {
                sb.append((char)('`' + k));
            }
            return sb.toString();
        }
        
        public static String helloWorld() {
            return randomString(-229985452) + " " + randomString(-147909649);
        }
    }
    

    明明是在程序里使用了java.util.Random()函数产生随机数,为什么每次打出的结果都是Hello World?请看Stackflow上有趣的讨论

    2. Integer 与 int

    import java.lang.reflect.Method;
    import java.util.Date;
    
    public class Yogy {
        private static int MAXNUM = 1000000000;
        
        public static void main(String[] args) {
            getRunningTime("useAutoboxing"); // useAutoboxing 执行10.65s
            getRunningTime("notAutoboxing"); // notAutoboxing 执行 1.471s
        }
    
        public static void getRunningTime(String methodName) {
            try {
                Method method = Yogy.class.getMethod(methodName);
                long stTime = new Date().getTime();
                method.invoke(null);
                System.out.println(methodName + " 执行" + (new Date().getTime() - stTime) / 1000. + "s");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        
        public static void useAutoboxing() {
            Integer sum = 0;
            for (int i = 1000; i < MAXNUM; ++i) {
                sum += i;
            }
        }
        
        public static void notAutoboxing() {
            int sum = 0;
            for (int i = 0; i < MAXNUM; ++i) {
                sum += i;
            }
        }
    }
    

    我们发现使用Integer的确比int慢了很多,因为在useAutoboxing中,sum + = i;实际上执行的是 int result = sum.intValue() + i; sum = new Integer(result);,生成了很多临时Integer对象。不仅Integer要转换成int执行操作,还要增加GC垃圾回收的代价,所以在含有大量操作的时候,尽量使用基本数据类型代替包装类。

    3. hashCode()和equals()

    import java.util.HashSet;
    
    class Monkey { 
        private String nickName;
    
        private String language;
    
        public Monkey(String name, String lang) {
            this.nickName = name;
            this.language = lang;
        }
    
        public String getNickName() {
            return nickName;
        }
    
        public void setNickName(String nickName) {
            this.nickName = nickName;
        }
    
        public String getLanguage() {
            return language;
        }
    
        public void setLanguage(String language) {
            this.language = language;
        }
    
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result
                    + ((language == null) ? 0 : language.hashCode());
            result = prime * result
                    + ((nickName == null) ? 0 : nickName.hashCode());
            return result;
        }
    }
    
    public class Yogy {
        public static void main(String[] args) {
            HashSet<Monkey> myFriends = new HashSet<Monkey>();
            
            // 当我和Yogy成为朋友时,她使用的还是C++
            Monkey yogy = new Monkey("Yogy", "C++");
            myFriends.add(yogy);
            
            // 现在Python已成为她的最爱
            yogy.setLanguage("Python");
            
            // 但当我再次遇到Yogy时,我却不能从我的脑海中找到她,我发现我失忆了
            System.out.println(myFriends.contains(yogy)); // 输出false
        }
    }
    

    到底发什么什么呢?在Java中,对象都是引用类型的数据,myFriends中保存的是yogy对象的引用,所以当yogy改变时,myFriends中的对象也会改变,但我却为什么不能想起她?理由是Monkey中重写了hashCode()方法,并且字段language也参与了hashCode的生成。打印出yogy使用C++时的hashCode为4800998,而yogy使用Python时的hashCode为1563076845,在哈希表的实现中如果两元素hashCode不等,则直接认为两元素不等。

    在上例中,删除Monkey中对hashCode重载,我能想起yogy。但是如果重新new Monkey(“Yogy”, “Python”),我还是会失忆。因为默认的hashCode是对象在内存中地址,重新new的对象和以前对象的地址不同,hashCode也会不同。因此要重写hashCode方法,使得只有字段nickName参与hashCode的生成,代码如下。

        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result
                    + ((nickName == null) ? 0 : nickName.hashCode());
            return result;
        }
    

    按照开始的版本,我能想起yogy。但对于new Monkey(“Yogy”, “Python”)还是不行,还需要重写equals()方法,默认的equals()也是比较两个对象的地址是否相等。重写equals()使得只有nickName参与相等类型的比较。这样我就能通过看到Yogy想起我的朋友了。

    结束语

    JAVA都有对象,但是经常找不到对象。

    Java
    转载请注明出处

    相关文章

      网友评论

      • 撸猫摸鱼侠:果断收藏!
      • 8128f43d9ca8:Integer和int那个是有自动装箱和拆箱存在,有些地方特别是泛型不支持基本类型,因此从1.5
        (印象中是这个)开始增加了自动装箱和拆箱操作,这个不注意就会出现很大问题。這点上面Groovy处理地比较好,一般情况下都是基本类型,只有当必须用做封装类型的时候才会进行转换,减少不必要的生成。
      • 0024b09f4dae:Java忠实粉~ :heart_eyes:
      • 5d8e2a600f79:Java这篇要比其他两篇更细点,看来作者常用Java哦。
        尤汐Yogy:@Captain_曹 主笔人最常用的是Object-C,我个人最常用是Python
      • 62785f299fbe:看不懂~~
      • 最怕认真:如所料不错,应该是在校大学僧。。
        尤汐Yogy:@最怕认真 为纪念本科毕业写的《那些年我们追过的语言》系列,研究生在读。
      • cca909454157:分享给我弟看了
      • 星星丢下了月亮:好棒好棒,我是学java这个专业滴,嘿嘿,
      • fewerworld:已入行坑,本文只做温故知新……
        尤汐Yogy:@fewerworld 祝好
      • gardenher:我的一个程序员朋友告诉我,学习入门的话HML5+CCS3.的话成本会低好多,这话可以么?HTML5这东东在很多网站都可以看到啊
        尤汐Yogy:@gardenher 如果做前端,应该是html+css+javascript。其中,html和css可以理解为版式版面;而javascript负责网页的逻辑性功能,其学习成本并不低,但在Web 2.0时代,作用非常大。
        c264d6d35fca:@gardenher 前端相对而言简单一点
      • 60e1a90c0d4a:认同标题,相比PHP,C,OC,JAVA可以担任擎天柱之位。
        本人开发3年,以上纯粹个人感觉,党派之争休提。
        尤汐Yogy:@子周 @赤子之心 评论时,标题是”软件界的垄断者“,确实有所不妥。感谢。
      • 25c723810640:不认同标题
        尤汐Yogy:@赤子之心 感谢反馈!我的初衷是一个系列,记录本科4年学过的9门语言,相比于其它8门而言,Java确实在软件开发方面得天独厚。我会考虑修改标题,谢谢!

      本文标题:Java - 软件界的擎天柱

      本文链接:https://www.haomeiwen.com/subject/vtkeqttx.html