Java的静态域和静态方法

static的定义

static是Java的静态修饰符,何为静态,一段程序中的变量或方法,是在编译时由系统自动分配内存来存储的,而所谓静态就是指在编译后所分配的内存会一直存在,直到程序退出才会释放这个空间.在Java程序里,万物皆对象,而对象的抽象就是类,一个Java类主要由数据和程序组成,数据也就是所谓的域(field),程序就是方法(method),当域或方法被static修饰时,则分别称它们为静态域和静态方法,也叫类变量类方法;

public Class User {
    public int id;//实例域
    public static final String name = "Acheron";//类变量
    public static String getName(){ return name; }//类方法
}

static的使用

对于一个类而言,如果要使用其中的成员,普通情况下必须先实例化对象后,通过对象的引用才能够访问这些成员,但是当该成员是用static声明的,则可以不用实例化对象就可以引用成员:

User.getName();

静态方法

静态方法是不能操作对象的方法,所以不能在静态方法中访问实例域,但可以访问静态域:

public static String getName(){ 
    return name; 
}

内存分配

根据是否有static修饰,则可以将一个类中的变量和方法分为四种情况: 1. 实例域(instance field) : 没有static修饰的field,随着每个instance各有一块内存 2. 实例方法(instance method) : 没有static修饰的method,共享一块内存 3. 类变量(class field) : 有static修饰的field,共享一块内存 4. 类方法(class method) : 有static修饰的method,共享一块内存

静态域的内存分配

当一个field是static修饰时,则这个field只占用一块内存,而且此内存空间是在此class被加载之后就立刻配置的,这个field和class本身有关,而不是与这个class的实例(instance)相关,此类的所有实例将会共享这个field.如果field没有static修饰,则此类的每一个实例对这个filed都有一个自己的拷贝.

对于上面的User类,每个User都有一个自己的id域,但这个类的所有实例将共享一个name域,如果new100个User类的对象,则有100个实例域id,但只有一个静态域name,就算没有一个User对象,静态域name也存在,它属于类,不属于对象.

实例方法的内存分配

实例方法为什么和静态方法一样共享一块内存,因为实例方法占用的内存是域的数百倍,如果和实例域一样随着每个instance各占一块内存,则太浪费空间了.

隐藏的this参数

既然一个类的所有实例共享相同的实例方法,那么下面两个实例调用相同method时,如何区分是instance1和instance2:

instance1.method();
instance2.method();

任何实例方法都有一个隐藏的参数,此参数的变量名是this,这个参数是由java编译器加上去的.当调用某个实例的方法时,必须在前面加上该实例的名称,当该实例和该方法所有在实例指的是同一个实例时,则该实例的名称就是this,这种情况,也可以省略this.

当方法中的参数或变量和实例域完全相同时,如果不在前面加上this,则表示指的是参数或局部变量,如果在前面加上this,那么指的才是实例域.

public void setName(String name) {
    this.name = name;
}

我是程序员,我不会修电脑

成为程序员之后,我才发现这个职业是如此适合我,它不需要太多的口才,不需要太多地与人接触,只需一台电脑,就可以安安静静玩耍一天了.没有成为程序员之前,我一直想成为一名图书馆管理员,做摆放,整理书籍的工作,以为这样就可以免费地看各种书籍了,12年毕业的那段时间,我对未来完全迷茫,当时还尝试着去浙江图书馆找工作,以为是那种门口贴个招聘广告就招人的,后来才知道需要考试,图书管理员是一门很专业的职业…..

我发现当我投入到一门新技术A的学习当中,学到中间,发现要学会技术A,必须先学会技术B,于是我就会暂时放下A,开始学习B,技术B学到一半,又发现不学会C,根本看不懂B,于是又搁下B转道学C,刚看了会C,发现C又是基于D,如此一步步掉入深渊,到最后我发现我看起了宇宙的起源……

个人经验来说,我是这样来提高个人生产力的:(1).用最优秀的IDE和文本编辑器,写Java我用Intellij,编辑文本我用Vim,写前端我用sublime;(2).努力使自己成为键盘流,熟悉各种快捷键,最大程度地抛弃鼠标,让手指敲代码的速度跟上思维的速度;(3).将任务拆分拆分再拆分,小到一个个具体的明确的任务点,番茄工作法,个个击破.

当我遇到一个技术难题时,我很少去问别人,我很不愿去打扰别人,就像我很不愿向人借钱一样,遇到问题就发问,只会越来越依赖别人,只会丧失自我解决问题的能力.网络,资料,看书能解决我遇到的大部分问题,有时比较有趣的是,忙了一天问题依然没解决,回去睡个觉,第二天思路会自然而来,三分钟就搞定了前一天困惑一天的问题.

互联网企业和传统企业最大的区别在哪里?答:加班,加班,加班!看过一个笑话说,一个工作2年的程序员去面试,面试官问:工作两年为什么简历上写工作四年.答:工作两年,加班两年……我对加班当然是持否定态度的,但也不会太抱怨,当重要bug的修复或项目上线的关键时刻,加班也情有可原,我讨厌的只是无所事事的加班,自我感动的加班,无偿的加班,SB领导要求的加班.

新技术发展实在太快了,尤其是前端,这几年的爆炸式发展,各种技术层出不穷,nodejs、angular、ember、vue、react、grunt、gulp、sass、coffee、less、typescript、browerify、webpack、ES6、babel,前一段时间,我对前端起了大兴趣,看了几天nodejs,最后又回到了java的怀抱,作为一个java程序员,自己碗里的饭还没吃干净,又何必觊觎别的.对新技术,我对它了解就够了,花大时间去学没有落地的技术,只会得不偿失.

说说程序员群体,他们工作努力,他们傲骄,他们一心想改变世界,他们自卑,他们容易受伤害,他们长得奇怪,他们穿着邋遢,他们可以一个月不洗头,他们玻璃心,他们不善言谈(才怪),他们爱女盆友(什么,他们有女盆友?),他们吃个饭都聊起技术,他们最’恨’的人是产品经理,他们讲个污笑话会流鼻血,他们都认为自己写的代码没bug,他们都确信自己的技术最牛逼……他们真的不会修电脑…..

一段代码的重构过程

原始代码

一个UserDb类中有一个populate方法,这是一个使用JDBC连接数据库,获取相关数据信息的方法,这段代码承担了太多的职责,而且重用性差,一个方法体中代码行数也太多,该如何对它进行重构.

 public void populate() throws Exception {
    Connection c = null;
    try {
        Class.forName(DRIVER_CLASS);
        c = DriverManager.getConnection(DB_URL, USER, PASSWORD);
        Statement stmt = c.createStatement();
        ResultSet rs = stmt.executeQuery(SQL);
        while (rs.next()) {
            User user = new User();
            user.setName(rs.getString("name"));
            user.setAge(rs.getInt("age"));
            userList.add(user);
        }
    } finally {
        c.close();
    }
}

重构一—拆分拆分再拆分

可以看出上述代码主要有四个步骤: 1.获得数据库连接 2.通过数据库连接获取结果集 3.遍历结果集,把每一项添加到User列表 4.关闭数据库连接

可以根据这四个步骤,将代码拆分,将其中相关代码抽取成私有方法,最后得到代码如下:

  public void populate() throws Exception {
        Connection c = null;
        try {
            c = getDatabaseConnection();
            ResultSet rs = createResultSet(c);
            while (rs.next())
                addUserToList(rs);               
        } finally {
            c.close();
        }
    }

提取出来的三个私有方法如下:

//获得数据库连接
private Connection getDatabaseConnection() throws SQLException, ClassNotFoundException {
    Connection c = null;
    Class.forName(DRIVER_CLASS);
    c = DriverManager.getConnection(DB_URL, USER, PASSWORD);
    return c;
}
//创建结果集    
private ResultSet createResultSet(Connection c) throws SQLException {
    return c.createStatement().executeQuery(SQL);
}
//将结果集中的数据封装成User对象    
private void addUserToList(ResultSet rs) throws SQLException {
    User user = new User();
    user.setName(rs.getString("name"));
    user.setAge(rs.getInt("age"));
    userList.add(user);
}

重构二 —模板方法模式

上面的方法是否还可以重构,观察可发现,getDatabaseConnection方法和createResultSet方法,前者只是用来取得数据库连接,和结果列表没有什么关系,后者只要传入SQL语句就可以成为通用方法,可以把这两个方法放到一个父类中去,createResultSet方法可以根据模板方法模式,将其设为抽象方法,让子类根据不同的SQL来实现.createResultSet方法被分解成两个方法:一个保留原来的名字,另一个是让子类提供SQL的新的抽象方法(getSql).最终得到AbstractDbBase类如下:

public abstract class AbstractDbBase {
    private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
    private static final String DB_URL = "jdbc://mysql://localhost/";
    private static final String USER = "test";
    private static final String PASSWORD = "123456";

    private Connection getDatabaseConnection() throws SQLException, ClassNotFoundException {
        Connection c = null;
        Class.forName(DRIVER_CLASS);
        c = DriverManager.getConnection(DB_URL, USER, PASSWORD);
        return c;
    }

    abstract protected String getSql(); 

     protected ResultSet createResultSet(Connection c) throws SQLException {
        return c.createStatement().executeQuery(getSql());
    }
}

重构三—抽象抽象再抽象

继续观察发现,populate方法只有在while循环里信赖于特定的实体类,从结果集中取出每一项再填充到实体列表,可以抽象出这部分,使用模板方法模式,将populate方法和addEntityToList也移到AbstractDbBase类中.

    abstract protected void addEntityToList(ResultSet rs) throws SQLException;

    public void populate() throws Exception {
        Connection c = null;
        try {
            c = getDatabaseConnection();
            ResultSet rs = createResultSet(c);
            while (rs.next())
                addEntityToList(rs);
        } finally {
            c.close();
        }
    }

重构之后

根据上述几个步骤重构后,UserDb类变成了如下结构:

public class UserDb extends AbstractDbBase{
    private static final String SQL = "select name,age from user";
    private ArrayList userList;

    public UserDb() {
        userList = new ArrayList();
    }

    @Override
    protected void addEntityToList(ResultSet rs) throws SQLException {
        User user = new User();
        user.setName(rs.getString("name"));
        user.setAge(rs.getInt("age"));
        userList.add(user);
    }

    @Override
    protected String getSql() {
     
   return SQL;
    }
}

可见重构之后,UserDb类中最后留下的都是跟User实体相关的方法,变量等,其它可以公用的方法都被抽取到了AbstractDbBase类中,可以被其它实体共用.

总结

  • 1.可复用的代码隐藏在代码的任何地方
  • 2.把代码分解成一步步后,可复用的代码就会暴露出来
  • 3.上述一步步的重构是一种测试驱动开发模式(TDD)
  • 4.尽量做到一个方法代码行数不超过15行
  • 5.每个方法中所有的代码应该处于同一抽象层次
  • 6.抽象,抽象,再抽象,再再抽象……

Java的链式调用

当实例化一个Java对象时,常常会看到如下结构的代码:

User user = new User();
user.setName("Acheron");
user.setAge(25);
user.setSex("男");
user.setAddress("some where");

怎样去除上面代码中Java API风格中令人反感的冗余,用链式调用法,让所有的属性设置方法返回this而不是void,User类就该是这样的:

public class User {
    private String name;
    private Integer age;
    private String sex;
    private String address;

    public static User instance(){
        return new User();
    }
    public User name(String name) {
        this.name = name;
        return this;
    }
    ......
}

现在用链式调用法就可以用如下方式:

User user = User.instance().name("Acheron").age(20).sex("男").address("some where");

2015年所读书

15年是我有读书记录以来,读书最少的一年,共26本,原因种种,今年是个人的旅游元年,周末假期大大小小玩过的地方十来个,二来今年所读书多数偏向技术类,技术书都是砖块书,读起来费时间,当然挤压了我的大部分业余时间的,主要还是工作的繁忙,尤其是10月份以来,加班偏多,读书时间就更少了,不过欣慰的一点是,我已经连续七年,每月至少会扫荡掉一本书.

15年的读书方向开始转变,大学时期我的读基本都是社科文艺类,小说居多,毕业后一两年文艺类一半,技术类一半,直到今年,90%都是计算机技术类,2月的时候列过一个读书计划,基本上都是按计划走的,但中途我可能兴趣会有转移,或对一门技术特别感兴趣,就会改道读相关书籍,计划只是列个大致方向,不强求焉,biu~

img

 

01.《The PH.D. Grind》 Philip J. Guo

02.《The Definitive Guide to Django》 Adrian Holovaty

03.《学习vi和vim编辑器》 Arnold Robbins、Elbert Hannah、Linda Lamb

04.《黑客:计算机革命的英雄》 Steven Levy

05.《代码大全》 迈克康奈尔

06.《重构:改善既有代码的设计》 Martin Fowler

07.《Ubuntu权威指南》

08.《亲吻的艺术》威廉•凯恩

09.《无器械健身 : 用自身体重锻练》 马克·劳伦、乔舒亚·克拉克

10.《交换机.路由器.防火墙》 刘晓辉

11.《1980年代的爱情》 野夫

12.《大型网站技术架构》 李智慧

13.《Web全栈工程师的自我修养》 余果

14.《构建高性能Web站点》 郭欣

15.《大型网站系统与Java中间件开发实践》 曾宪杰

16.《写给大家看的设计书(第3版)》 Robin Williams

17.《Java JDK 7学习笔记》 林信良

18.《专业日式美发技巧-基础篇》 JFA

19.《HTTP权威指南》 David Gourley、Brian Totty

20.《文学空间》 莫里斯.布朗肖

21.《Practical Vim : Edit Text at the Speed of Thought》 Drew Neil

22.《Pro Git》 Scott Chacon

23.《编码 : 隐匿在计算机软硬件背后的语言》 Charles Petzold

24.《软件随想录》 Joel Spolsky

25.《Facebook效应》 大卫·柯克帕特里克

26.《西西弗神话》 加缪