《JAVA编程思想》学习笔记

细碎点集锦

  1. 程序是对象的集合,它们通过发送消息来告知彼此所要做的。要想请求一个对象,就必须对该对象发送一条消息。更具体的说,可以把消息想象为对某个特定对象的方法的调用
  2. 文档注释可以加html中的标签,使文档有更好的显示
  3. 静态导入可以方便一些方法的调用
    例如:
Import static net.mindview.util.Print.*;
Print(“Hello,World”);

但使用不当很容易引起代码阅读性的降低和重名几率的提高,需要慎用。

  1. 如下代码可实现在一条语句对同一对象执行多次操作:a.method().method();
Public class a{
  Public a method{
    Return this;
      }
}
  1. 执行顺序:静态初始化块>初始化块。初始化块总在构造器执行前执行,实际上编译后初始化块的内容会还原入每一个构造器
  2. 组合继承
    当创建一个导出类(继承类)的对象时,该对象包含了一个基类的子对象。这个子对象与你用基类直接创建的对象是一样的。组合和继承都允许在新的类中放子对象,组合是显示的这样做,而继承则是隐式的这样做。
    Is a 适合继承表达,has a适合组合
    到底该用组合还是继承,一个最清晰的判断方法就是问一问自己是否需要从新类向基类进行向上转型
  3. 类的加载过程
    类的代码在初次使用时才加载。这通常是指加载发生于创建类的第一个对象之时,但是访问static域或static方法时,也会发生加载
    一个对象加载过程:
    寻找class文件并加载进入内存(此类所有基类class文件一起加载)——》static初始化——》创建对象,初始化成员变量——》调用构造器(从基类往下)
  4. String的+拼接会被编译器优化成StringBuilder的append()方法,但优化有限,大量拼接时会不断new StringBuilder,所有大量拼接的情况还是用StringBuilder好,编译后只会new 一个StringBuilder
    注意,图省事用StringBuilder.append(a+”:”+b)会让编译器另外创建StringBuilder对象来处理括号内字符串拼接,所有还是用append好
    (p284)

多态

class Super{
    public void f() {
        System.out.println("super.f()");
    }
}
public class Sub extends Super{
    @Override
    public void f() {
        System.out.println("sub.f()");
    }
    public static void main(String[] args) {
        Super s=new Sub();
        s.f();
    }
}/*output:
Sub.f()
*//

问:为什么s调用f方法会是继承类中的f()方法而不是父类中的?
——将一个方法调用同一个方法的主体关联起来称为绑定。
若在程序执行前进行绑定,叫做前期绑定。
若在程序运行时根据对象的类型进行绑定,则称为后期绑定,或者动态绑定
Java中除了static方法和final方法外,其余方法都是后期绑定。
F方法调用时,会动态和对象s进行绑定,根据s对象中的类型信息(可以输出s对象查看),判断其为sub,所以调用了sub.f()。

class Super{
    public int field=0;
    public int getField(){
        return field;
    }
}

class Sub extends Super{
    public int field=1;
    public int getField(){
        return field;
    }
    public int getSuperField(){
        return super.field;
    }
}

public class Test{
    public static void main(String[] args) {
        Super sup=new Sub();
        System.out.println("sup.field="+sup.field+",sup.getField()="+sup.getField());
        Sub sub=new Sub();
        System.out.println("sub.field="+sub.field+",sub.getField="+sub.getField()+",sub.getSuperField()="+sub.getSuperField());
    }
}/*Output:
sup.field=0,sup.getField()=1
sub.field=1,sub.getField=1,sub.getSuperField()=0
*/

只有普通的方法调用为多态,域和静态方法都不具有多态。
因为任何域访问操作都将由编译器解析。例如,如果你直接访问某个域,这个访问就将在编译期进行解析,直接返回原本对象的域

类型信息

  • RTTI(Run-Time Type Identification):即运行时类型鉴定。Java中的工作原理在于,运行时可根据对象的Class类来知道其真实类型。
    Java中主要有两种方式:普通的RTTI以及反射。区别在于,前者在编译时打开和检查.class文件获取Class,而反射是在运行时打开和检查.class文件
  • 新的转型语法,对于无法使用普通转型的情况特别有用
class Father{}
class Son extends Father{}

public class Test {
    public static void main(String[] args) {
        Father f=new Son();
        Class<Son> sonType=Son.class;
        Son s=sonType.cast(f);
        //等效于: Son s=(Son)f;
    }
}
  • 空对象思想 (p341)
    使用内置的null来表示缺少对象时,每次都需要测试其是否为null。而null除了在操作时产生NullPointerException之外,没有其他任何行为。
    通过引入空对象,执行所有方法时都返回表示“不存在”的信息。这样我们可以假设所有对象都是有效的,而不必浪费编程精力去检查null
interface Null{}

class Person{
    public String name;
    public String address;
    //Person的空对象,单例模式
    public static final Person NULL=new NullPerson();
    
    public Person(String name,String address) {
        this.name=name;
        this.address=address;
    }
    
    public String whoAmI() {
        return name+" "+address;
    }
    
    public static class NullPerson extends Person implements Null{
        private NullPerson(){super("None", "None");}
        public String whoAmI() {
            return "NullPerson";
        }
    }
}

补充:Java8新特性-Optional
转载自http://www.blogbus.com/dreamhead-logs/235329092.html

java.lang.NullPointerException,只要敢自称Java程序员,那对这个异常就再熟悉不过了。为了防止抛出这个异常,我们经常会写出这样的代码:
Person person = people.find("John Smith");if (person != null) { person.doSomething();}
遗憾的是,在绝大多数Java代码里,我们常常忘记了判断空引用,所以,NullPointerException便也随之而来了。

“Null Sucks.”,这就是Doug Lea对空的评价。作为一个Java程序员,如果你还不知道Doug Lea是谁,那赶紧补课,没有他的贡献,我们还只能用着Java最原始的装备处理多线程。

"I call it my billion-dollar mistake.",有资格说这话是空引用的发明者,Sir C. A. R. Hoare。你可以不知道Doug Lea,但你一定要知道这位老人家,否则,你便没资格使用快速排序。

在Java世界里,解决空引用问题常见的一种办法是,使用Null Object模式。这样的话,在“没有什么”的情况下,就返回Null Object,客户端代码就不用判断是否为空了。但是,这种做法也有一些问题。首先,我们肯定要为Null Object编写代码,而且,如果我们想大规模应用这个模式,我们要为几乎每个类编写Null Object。
幸好,我们还有另外一种选择:Optional。Optional是对可以为空的对象进行的封装,它实现起来并不复杂。在某些语言里,比如Scala,Optional实现成了语言的一部分。而对于Java程序员而言,Guava为我们提供了Optional的支持。闲言少叙,先来如何使用Optional,完成前面的那段代码。

Optional person = people.find("John Smith");if (person.isPresent()) { person.get().doSomething();}
这里如果isPresent()返回false,说明这是个空对象,否则,我们就可以把其中的内容取出来做自己想做的操作了。

如果你期待的是代码量的减少,恐怕这里要让你失望了。单从代码量上来说,Optional甚至比原来的代码还多。但好处在于,你绝对不会忘记判空,因为这里我们得到的不是Person类的对象,而是Optional。

看完了客户端代码,我们再来看看怎样创建一个Optional对象,基本的规则很简单:

  • 如果我们知道自己要封装的对象是一个空对象,可以用 Optional.absent();
  • 如果封装的对象是一个非空对象,则可以用 Optional.of(obj);
  • 如果不知道对象是否为空,就这样创建创建 Optional.fromNullable(obj);

有时候,当一个对象为null的时候,我们并不是简单的忽略,而是给出一个缺省值,比如找不到这个人,任务就交给经理来做。使用Optional可以很容易地做到这一点,以上面的代码为例:
Optional person = people.find("John Smith"); person.or(manager).doSomething()
说白了,Optinal是给了我们一个更有意义的“空”。

  • 反射突破private限制
    我们都知道,private的域和方法是只能在本类中访问的,但通过反射可以突破这一点
class HidenPerson{
    private String name="jack";
    private final String sex; 
    private String address="BeiJing";
    
    
    public HidenPerson(String name, String address,String sex) {
        this.name = name;
        this.address = address;
        this.sex=sex;
    }

    private void whoAmI() {
        System.out.println(name+" | "+sex+" | "+address); 
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        HidenPerson hidenPerson=new HidenPerson("jack","BeiJing","boy");
        Class hidenPersonType=HidenPerson.class;
        
        //私有域和方法都不能在别的类中访问
//      System.out.println(hidenPerson.name); compile error
//      System.out.println(hidenPerson.sex);  compile error
//      System.out.println(hidenPerson.whoAmI());  compile error
        
        //反射访问私有方法
        Method m=hidenPersonType.getDeclaredMethod("whoAmI");
        m.setAccessible(true); //设置该方法可访问
        m.invoke(hidenPerson);
        
        //反射访问并改变私有域
        Field name=hidenPersonType.getDeclaredField("name");
        name.setAccessible(true);
        name.set(hidenPerson, "you are not jack");
        m.invoke(hidenPerson);
        
        //反射可访问私有final域,在使用构造器初始化域的情况下可以更改它;如果在声明sex时就赋值,则无法更改
        Field sex=hidenPersonType.getDeclaredField("sex");
        sex.setAccessible(true);
        sex.set(hidenPerson, "gril");
        m.invoke(hidenPerson);
    }
}/*output:
jack | boy | BeiJing
you are not jack | boy | BeiJing
you are not jack | gril | BeiJing
*/

这段颠覆了我的三观,原来private的域和方法也不是安全的!而且,即使发布编译后的代码,也可以使用反编译命令javap -private 类名轻松显示所有成员出来。或者使用反编译工具jd-gui更方便。

另外书中说明的是final的域是安全的,反射也不能更改。但笔者发现在使用构造器初始化域的情况下可以更改。(如上代码)
而如果声明时赋值则更改无效。private final String sex="boy";。原因不明。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容