Thinking in Java 中闪耀的星星(一)

5 篇文章 0 订阅
5 篇文章 0 订阅

**”Thinking in java” 被誉为Java界的圣经,做为进阶是一个不错的选择,暑假在家闲着无聊,看着打发打发时间,把一些自己认为不错的点做了一些笔记。文字部分是我的见解,代码大部分取自原书。顺便我想给三个看Tij的建议:
1).看英文原著!中文版的翻译并不是原汁原味的翻译,而是意译,为了中文句式的流畅,有些意思会被篡改。
2).不要抱着想一次读完的心态!一本好书,是经得起时间的考验,必定要反复啃,温故而知新。
3).学习就像吃饭,书是香喷喷的米饭,视频是脍炙人口的菜,优酷上有一套斯坦福大学的《编程方法》公开课,刚好是选择以java为讲解语言的,可以跟看书同步:http://list.youku.com/albumlist/show/id_17643804.html?sf=10100&spm=0.0.0.0.bL8hk1**

下面我们开启Thinking之旅:

1.什么是面向对象编程?
1.)我们所处的世界是由对象构成的,java的设计的本质也是基于世界的!在理解什么是面向对象要先清楚“自顶而下”的设计思想,就是把大的方面细分为小的方面,直到原子性,比如,早上洗漱,细分为洗脸,刷牙,刷牙细分为挤牙膏,牙刷刷动牙齿…
2.)为什么是面向对象?举个例子:人类的上层是灵长类,灵长类的上层是哺乳动物,哺乳动物的上层是动物,那么人类、灵长类、哺乳动物、动物就称为类,我/你/他是人类的一个实例,称为对象,那么推广出去,java是面向对象的语言,不就反映出世界的物质性吗。
3.)对象的作用是接收发送过来的指令,做出回应。每个对象之间相互提供服务。对象向对象发送信息。好比生活中的例子:我把CD插入CD播放器,播放音乐。我、CD、CD播放器、音乐均是对象。
2面向对象特性?
抽象、继承、多态、封装。
本质是实现代码高内聚,低耦合,增强代码复用性。
3.String s = new String(“string s”);包含了什么?
里面的s代表一个引用,存在栈中,引用的名字 s 存在变量区,new 把 s 引用与String关联,String是一个类,存在堆。
4.Array 细节
1.)Array在创建时它的每个元素默认为null。
2.)如果:
List list=null;
list=…
会报空指针异常。
5.Java命名规则
类名的每个单词首字母大写
变量名和方法名的第一个单词的首字母小写,其余的首字母大写
6.注释
具体看下面的hello world 例子:

  //:object/HelloDate.java
import java.util.*;
/**The first Thinking in Java example program.
 *Displays a String and today's date
 *@author wayne
 *@version 4.0
 */
public class HelloDate{
    /**Entry point to class & application.
     *@param args array of string arguments 
     *@throws exceptions No exception thrown
     */
    public static void main(String[] args){
        System.out.println("Hello World,it's:");
        System.out.println(new Date());
    }
}/*Output:(55% match)
Hello World. it's:
Web July 14 17:42:36 MCT 2016
*///~

7.equals()方法陷阱
看例子:

public class EqualsMethod{
     public static void main(String[] args){
          Integer n1=new Integer(47);
          Integer n2=new Integer(47);
          System.out.println(n1.equals(n2));
          System.out.println("***********");
          Value v1=new Value();
          Value v2=new Value();
          v1.i=v2.i=100;
          System.out.println(v1.equals(v2));
     }
}
class Value{
   int i;
}/*Output
true
**********
false
*/  

很奇怪为什么一个是true,一个是false?
equals()是object的方法,用来比较对象的地址。所有类都是object的子类,Integer同样也是object的子类,也包含有equals()方法,但是Integer重写了equals()方法,用来比较两个Integer对象的数值。上面的例子中,Integer.equals()比较两个47的值相等而返回true,而Value类并没有重写equals()方法,比较的是new出来的对象的地址,两个对象的地址不同而返回false。
8.Java没有sizeof()函数
C语言中,经常用sizeof()在来定义数据类型的长度。操作系统是16/32/64…位的时候,不同数据类型的大小不一样。但是Java语言在设计时,不要sizeof(),所以在每个机器上各种数据类型的大小是固定的,使得java可以在各个平台来去自如,这就是Java的可移植性,所谓的跨平台。
9.Java的变量可以边用边定义
for(int i=0;i<10;i++)
而C不可以,i的作用域(生命周期)只在当前for循环中。
10goto做为Java的保留字,但是并不使用
在Java中,如果有嵌套的循环语句,当需要从某个循环跳出到指定的循环时,可以用label,定义一个label,然后再加在break或continue后面,看例子:

public class LabeledFor{
     public static void main(String[] args){
         int i=0;
         outer:
         for(;true;){
             inner:
             for(;i<10;i++){
                 System.out.println("i="+i);
                 if(i==2){
                     System.out.println("continue");
                     continue;
                 }
                 if(i==3){
                     System.out.println("break");
                     i++;
                     break;
                 }
                 if(i==7){
                     System.out.println("continue outer");
                     i++;
                     continue outer;
                 }
                 if(i==8){
                     System.out.println("break outer");
                     break outer;
                 }
                 for(int k=0;k<5;k++){
                     if(k==3){
                         System.out.println("continue inner");
                         continue inner;
                      }
                 }
             }
         }
     }
}/*Output
i=0
continue inner
i=1
continue inner
i=2
continue
i=3
break
i=4
continue inner
i=5
continue inner
i=6
continue inner
i=7
continue outer
i=8
break outer
*///~

11.overloading(重载)为什么要使用传入的参数区分?
在开发中我们定义对象名称和方法时, 一般采取语义法,但是为了拓展方法,会多出几个方法,又不想改动通俗易懂的方法名,于是采用不同参数区分开来。那位什么不通过返回值呢?因为当你只声明而不接收方法的返回值时,java编译器无法区分哪个方法被调用。
12.初始化一个对象的顺序
先初始化变量,再初始化方法。
13.方法的权限控制
public、package-access、private、protected
public:Everything naked to the world.所有对象都可以访问
package-access:顾名思义,同一个包内的可以访问(包:存放一堆类的namespace)
private:除了对象本身,其他对象均不能访问。主要用于解耦。
protected:住要用于修饰父类的方法。被修饰的方法可以被继承该对象的子类访问,其他对象不能访问
14.类的权限
类的权限之有两个:public、package-access。用法与方法一致。当public修饰一个类时,代表该类的所有内容都是public。另外,在一个java文件中,必须要有一个public的类。
15.is-a(继承/inheritance) vs has-a(合成/composition)
合成就是在一个类中整合进其他类构成一个新的类。它的灵活性,适应性比继承更好,但是每个类之间的变量和方法必须是public,封装性不如继承。
Bruce建议只有在确定能用继承是才用继承。实际编程中是继承和合成混用的。
16.final关键字修饰方法的作用
1.防止方法被重写
2.优化程序:一般的程序是通过压栈和出栈实现的,被final修饰的方法不会进栈,当程序运行到调用被final修饰方法的语句时,编译器直接把被final修饰的方法的代码拼接到语句后面,直接编译,提高速度。
17.构造器的调用顺序
1.从继承的根部开始调用构造方法
2.根据声明的顺序初始化变量
3.子类构造器的内部开始执行
看例子:

class Meal{
    Meal(){
        System.out.println("Meal()");
    }
}
class Bread{
    Bread(){
        System.out.println("Bread()");
    }
}
class Cheese{
    Cheese(){
        System.out.println("Cheese()");
    }
}
class Lettuce{
    Lettuce(){
         System.out.println("Lettuce()");
    }
}
class Lunch extends Meal{
    Lunch(){
        System.out.println("Lunch()");
    }
}
class PortableLunch extends Lunch{
    PortableLunch(){
        System.out.println("PortableLunch()");
    }
}
public class Sandwich extends PortableLunch{
    private Bread b=new Bread();
    private Cheese c=new Cheese();
    private Lettuce l=new Lettuce();
    public Sandwich(){
        System.out.println("Sandwich()");
    }
    public static void main(String[] args){
        new Sandwich();
    }
}/*Output
Meal()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()
*///~

18.继承和清除对象的顺序
从17的例子可以看出在继承关系中,方法的调用是从根部,最先的父类开始逐级调用。如果,想在对象被使用后回收该对象,释放内存空间。那么,调用回收函数的顺序是与继承相反的,为的是防止父类的方法被子类调用而回收父类的情况。
19.private 和 final
private默认是final。在使用多态时,如果想在构造器中调用方法,尽量把方法写在父类的构造器里。而且方法最好不要被重写,以免造成一些不必要的难以察觉的惊喜。
20.接口与抽象类的作用
在一般的继承关系中,父类的方法往往不会用到,而是使用子类重写的方法。父类的方法只是声明,所以接口和抽象类出现了。但是接口比抽象类更抽象。
抽象类不可被实例化,一般用来给子类继承;
接口最主要还是用来解耦合,接口允许被多个类实例化,增强代码的复用性,主要体现在适配器模式中。接口声明的方法默认为public,变量默认为static final
21.接口的“工厂”用法
直接看例子:

interface Game{
    boolean move();
}
interface GameFactory{
    Game getGame();
}
class Checkers implements Game{
    private int moves = 0;
    private static final int MOVES = 3;
    public boolean move(){
        System.out.println("Checkers move "+moves);
        return ++moves != MOVES;
    }
}
class CheckersFactory implements GameFactory{
    public Game getGame(){
        return new Checkers();
    }
}
class Chess implements Game{
    private int moves = 0;
    private static final int MOVES = 4;
    public boolean move(){
        System.out.println("Chess move "+moves);
        return ++moves!=MOVES;
    }
}
class ChessFactory implements GameFactory{
    public Game getGame(){
        return new Chess();
    }
}
public class Games{
    public static void playGame(GameFactory factory){
        Game s= factory.getGame();
        while(s.move()){
            ;
        }
    }
    public static void main(String[] args){
        playGame(new CheckersFactory());
        playGame(new ChessFactory());
    }
}/*Output
Checkers move 0
Checkers move 1
Checkers move 2
Chess move 0
Chess move 1
Chess move 2
Chess move 3
*///~

22.内部类的作用
内部类的设计初衷是解决接口的实现类的拓展缺陷。
内部类与外围类一起使用,外围类不管继承/实现什么接口,内部类也可以实现什么接口,独立于外围类。但是访问时要先访问外围类(除非内部类被static final修饰)。具体在程序中的作用可以参考 “Thinking in java” 原著第四版,P376~P380的例子。
内部类也称为闭包。
23.Local Inner Class vs anonymous Inner Class(匿名内部类)
先看一个例子:

interface Counter{
    int next();
}
public class LocalInnerClass{
    private int count =0;
    Counter getCounter(final String name){
        class LocalCounter implements Counter{
             public LocalCounter(){
                 System.out.println("LocalCounter()");
             }
             public int next(){
                 System.out.println(name);
                 return count++;
             }
        }
        return new LocalCounter();
    }
    Counter getCounter2(final String name){
        return new Counter(){
            {
                System.out.println("Counter()");
            }
            public int next(){
                System.out.println(name);
                return count++;
            }
        };
    }
public static void main(String[] args){
        LocalInnerClass lic=new LocalInnerClass();
        Counter
          c1=lic.getCounter("Local inner"),
          c2=lic.getCounter2("Anonymous inner");
        for(int i=0;i<5;i++){
            System.out.println(c1.next());
        }
        for(int i=0;i<5;i++){
            System.out.println(c2.next());
        }
    }
}/*Output
LocalCounter()
Counter()
Local inner
0
Local inner
1
Local inner
2
Local inner
3
Local inner
4
Anonymous inner
5
Anonymous inner
6
Anonymous inner
7
Anonymous inner
8
…

1.如果需要自己定义内部类的构造器或重写内部类的构造器,还是用local inner class
2.如果想为一个内部类创建多个对象,也还是使用 local inner class
24.集合的关系
collection 和 map 是最上层的类,其中:List,Set,Queue继承collection。List又衍生出ArrayList 和 LinkedList,Set衍生出HashSet 和 TreeSet,HashSet又衍生出LinkedHashSet,Queue 衍生出 PriorityQueue。HashMap ,TreeMap 继承Map ,HashMap又衍生出LinkedHashMap。
1.Map的功能强于Collection
2.List中元素是有顺序的
3.ArrayList适用于大规模查找,LinkedList适用于大规模插入和删除元素
4.TreeMap的key值是经过排序的,所以速度不如HashMap快
5.Set的元素不能重复,LinkedHashSet的元素的顺序是跟插入顺序一样的
25.stack 和 queue
这两个集合用的比较少几乎没用了,但是原理跟数据结构是一样的。stack是先入后出,queue是先入先出:
Stack:

import java.util.*;
public class StackTest{
    public static void main(String[] args){
        Stack<String> stack=new Stack<String>();
        for(String s:"My dog has fleas".split(" ")){
             stack.push(s);
        }
        while(!stack.empty()){
             System.out.print(stack.pop()+" ");
        }
    }
}/*Output
fleas has dog My
*///~
Queue:
import java.util.*;
public class QueueDemo{
    public static void printQ(Queue queue){
        while(queue.peek()!=null){
             System.out.print(queue.remove()+" ");
        }
        System.out.println();
    }
    public static void main(String[] args){
        Queue<Integer> queue=new LinkedList<Integer>();
        Random rand=new Random(47);
        for(int i=0;i<10;i++){
            queue.offer(rand.nextInt(i+10));
        }
        printQ(queue);
        Queue<Character> qc=new LinkedList<Character>();
        for(char c: "Brontosaurus".toCharArray()){
            qc.offer(c);
        }
        printQ(qc);
    }
}/*Output
8 1 1 1 5 14 3 1 0 1 
B r o n t o s a u r u s 
*///~
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值