《Head First Java》读书笔记

2018-08-11  本文已影响0人  elesg

从大学课程设计、毕业设计到工作中的一些小功能调整,自己的Java水平一直是会点语法+面向搜索引擎编程级别。想要更加深入地学习Java的东西,但是Java圣经又太厚,自己也不是特别擅长看这些技术书籍的人,在别人的建议下选了《Head First Java》来看。
纵观全书,这本书的重点在Java的基础语法、对象、多态与继承等概念上的讲解(讲得挺好的),对于一些异常处理、线程、IO、网络方面更多是简单的介绍,并没有深入讲解。
原本想通过这本书学习线程方面的概念,为阅读其他更加深入讲解线程方面的文章打下基础,但是似乎无法达到目的。
尽管如此,我还是通过阅读这本书学习的到了一些新的东西。这篇笔记,就是为了整理记录这些新学到的知识,以巩固我对这些知识的掌握。


对象的声明、创建与赋值

当我们声明一个非基本数据类型的变量时,我们通常这样写:
Dog myDog = new Dog();
在这简单的一行代码中,其实包含了三个步骤:

// 1. 声明一个Dog类型的引用变量
Dog myDog
// 2. 创建Dog对象 
new Dog
// 3. 将创建的Dog对象,赋值给myDog这个引用变量
Dog myDog = new Dog(); 

所以,当我们声明对象数据的时候,实际上是声明了该对象的引用变量数据。


对象的生存空间

在Java虚拟机驱动的时候,会从底层操作系统获得一块内存来执行Java程序。在内存中,要关注这两块区域:对象的生存空间堆和方法调用及变量生存的空间栈。


赋值与引用的例子

Book a = new Book();
Book b = new Book();  //这里有两个引用变量,两个对象
Book c = a;  //此时有三个引用变量,两个引用变量,c与a指向同一个对象
b = a; // 此时b也与a指向同一个对象,b原本指向的对象失去了引用,处于可回收状态 

继承与多态

Animal[] animals = new Animal[5];
animals[0] = new Dog();
animals[1] = new Cat();

Class Vet{
    public void giveshot(Animal a){
    a.makeNoise();
}

Vet vet = new Vet();
v.giveshot(new Dog());
}
Object o = new Dog();
int i = o.hashCode();  // 可行,因为Object本身有hashCode()方法
o.makeNoise(); // 不可执行,因为此时o的引用类型是Object,Object没有makeNoise()方法,无法执行。
Animal a = (Dog) o;
a.makeNoise(); // 可行,当o赋值给a时进行了类型转换,Dog是Animal的子类,所以可以赋值成功。Animal有makeNoise()方法,所以可以执行
public Dog(String name){
//调用父类的构造函数
super();
}
Class Dog{
    String name;
    public Dog(){
        // 调用了有一个String参数的构造函数
        this("myDog");
    }
    public Dog(String name){
        //调用父类的构造函数
        super();
    }
}

接口与抽象类

静态方法

// 非静态方法
Dog d = new Dog();
d.makeNoise();
// 静态方法
Math.min(3,7);
public class Person {
    private String name;

    Person(String name){
        this.name = name;
    }
    
    public String getName() {
        return name;
    }

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

public class FinalTest {
    private final String final_01 = "chenssy";    //编译期常量,必须要进行初始化,且不可更改
    private final String final_02;                //构造器常量,在实例化一个对象时被初始化
    
    private static Random random = new Random();
    private final int final_03 = random.nextInt(50);    //使用随机数来进行初始化
    
    //引用
    public final Person final_04 = new Person("chen_ssy");    //final指向引用数据类型
    
    FinalTest(String final_02){
        this.final_02 = final_02;
    }
    
    public String toString(){
        return "final_01 = " + final_01 +"   final_02 = " + final_02 + "   final_03 = " + final_03 +
               "   final_04 = " + final_04.getName();
    }
    
    public static void main(String[] args) {
        System.out.println("------------第一次创建对象------------");
        FinalTest final1 = new FinalTest("cm");
        System.out.println(final1);
        System.out.println("------------第二次创建对象------------");
        FinalTest final2 = new FinalTest("zj");
        System.out.println(final2);
        System.out.println("------------修改引用对象--------------");
        final2.final_04.setName("chenssy");
        System.out.println(final2);
    }
}

------------------
Output:
------------第一次创建对象------------
final_01 = chenssy   final_02 = cm   final_03 = 34   final_04 = chen_ssy
------------第二次创建对象------------
final_01 = chenssy   final_02 = zj   final_03 = 46   final_04 = chen_ssy
------------修改引用对象--------------
final_01 = chenssy   final_02 = zj   final_03 = 46   final_04 = chenssy

异常处理

try{
 // do somethings
} catch (DogException de){
  //deal DogException
} catch (AnimalException ae){
  //deal AnimalException
}
// 如果AnimalException的catch块在DogException之前,那么DogException也会被AnimalException的catch块捕获,就不会落到后面的DogException的catch块了。

内部类


IO

IO这一章简单地讲了一下文件操作,着重讲了序列化的内容。
其实这章序列化说得不好,建议看这里Java 序列化的高级认识

会损害序列化的修改:

  • 删除实例变量
  • 改变实例变量的类型
  • 将非瞬时的实例变量改为瞬时的
  • 改变继承的继承层次
  • 将类从可序列化改为不可序列化
  • 将实例变量变成静态的

较为安全的修改:

  • 加入新的实例变量(还原时取默认值)
  • 在继承层次中加入新的类
  • 在继承层次中删除类
  • 将实例变量从瞬时改为非瞬时

网络通信与多线程


集合与排序

  • TreeSet:有序且防止重复的集合。
  • HashMap:Key-Value集合,Key不可重复
  • HashSet:防止重复的集合,可快速找到相符元素
  • LinkedList:针对经常插入或者删除中间元素所涉及的高效率集合(不如ArrayList实用)
  • LinkedHashMap:可记住元素插入顺序,可设定依照原宿上次存储先后来排序的HashMap。
// 实现Comparable接口
class Song inplements Comparable<Song>{
    public int compareTo(Song s){
       return title. compareTo(s.getTitle());
   }
}

// 实现Comparator
class Song{
class ArtistCompare implements Comparator<Song>{
    public int Compare (Song one, Song two){
          return one.getArtist().compareTo(two.getArtist());
    }


ArtistCompare artistCompare = new ArtistCompare();
    Collections.sort(songList, artistCompare);
}

}

泛型

//这里的list仅接受ArrayList<Animal>
public void takeThing(ArrayList<Animal> list) 

 //这里的list对象可以接受ArrayList<Dog>、ArrayList<Cat>等继承Animal的对象的ArrayList
// 泛型的extends等价于实体类的extends或者implements
public <T extends Animal> void takeThing(ArrayList<T> list)

//万用字符也可以让ArrayList接受Animal的子类
// 使用万用字符,能够调用list中任何元素的方法,但是不能增加元素。
public void takeAnimals(ArrayList<? extends Animal> animals){
    for(Animal a:animals){
        a.eat();  //合法
    }
    animals.add(new Dog());  //不合法的操作
}

// 第二、第三种写法执行起来是一样的,但是在一般用第二种,因为需要传入多个对象时,第二种方法不需要多次声明
public <T extends Animal> void takeThing(ArrayList<T> one, ArrayList<T> two)

远端过程调用

远端过程调用

远端过程调用的过程:

  1. 启动RMI registry
  2. 远程服务被初始化(生成stub和skeleton)
  3. 远程服务向RMI registry注册
  4. 客户端查询RMI registry
  5. 客户端从RMI registry获取stub
  6. 客户端调用stub上的方法
  7. stub将方法的调用送到服务器上
  • 启动服务前应先启动注册器
  • 远程服务的参数和返回都需要做成可序列化

碎片知识

integer --- 0
floating point --- 0.0
boolean --- false
reference --- null

int a = 3;
byte b =3;
if(a == b){ 
// true
}
Foo c = new Foo();
Foo d = new Foo();
Foo e = c;
if(c == d){
// false
}
if(c == e){
// true
}
if(c.equals(d)){
// true
}
  • 在&&表达式中,左右两边都为true这个表达式返回true,当左边返回false时,JVM不会执行右边的计算就直接返回false;
  • 在||表达式中,左右两边都为false这个表达式返回false,当左边返回true时,JVM不会执行右边的计算就直接返回true;
  • & 和 | 在boolean表达式会强制JVM执行两边的运算,但一般长表达是用在位运算中。

需要拓展的知识点

// 位非 ~
int x = 10;  //00001010
x = ~x;  //11110101

// 位与 & 、位或 |、位异或 ^
int x = 10;  //00001010
int x = 6;    //00000110
// 位与 &: 两位都是1返回1,否则返回0
int a =x&y;  //00000010
// 位或 |: 有一位为1就返回1,否则返回0
int a =x&y;  //00001110
// 位异或 ^: 位相同返回1,否则返回0
int a =x&y;  //11110010

// 移位运算 左移<<,右移>>,无符号右移>>>,需要结合数据类型来看。
int x = -11;  //11111011
// 左移 1位,等于值*2,向左边移动,并且在低位补0.
int a= x<<1; //11110110
// 右移1位,等于值/2,带符号右移,若左操作数是正数,则高位补“0”,若左操作数是负数,则高位补“1”.
int a= x>>1; //1111101
// 无符号右移,无论左操作数是正数还是负数,在高位都补“0”
int a= x>>>1; //0111101
public class Outer{
    static class Inner{
        void do(){
        // do somethings
        }
    }
   class Test{
        public static void main (String args[]){
          Outer.Inner a = new Outer.Inner();
          a.do();
        }
    }
}
button.addActionListen(new ActionListen{
    public void actionPerformed(ActionEvent e){
    //  do somethings
    }
})
上一篇下一篇

猜你喜欢

热点阅读