java核心技术第9版(读书笔记)

java的11个特性

  1. 简单性:a.java保留了一部分c++的特性,剔除了一部分易混淆,少 使用,难理解的特性;b.小。(支持在小型机器上独立运行)
  2. 面向对象:a.接口代替c++中的多继承; b.元类模型
  3. 网络技能:java应用程序能通过URL打开和访问网络上的对象,十分便捷
  4. 健壮性:java编译器强大,能检测出其他语言仅在运行时刻才能检测出的问题
  5. 安全性:拥有许多安全特性
  6. 体系结构中立:编译器生成的文件可在任何机器上解释执行,可迅速翻译成本机代码
  7. 可移植性:java数据类型固定大小,消除了代码移植的问题;二进制数据以固定的格式进行存储和传输,消除了字节顺序的困扰;
    字符串用标准的Unicode格式进行存储。
  8. 解释性:java链接是增量式且轻量级的过程,可及时编译
  9. 高性能:可即时编译,高效
  10. 多线程:多线程编译简单,将实现交给了底层的操作系统或线层库来完成
  11. 动态性:java库可以自由添加新方法和实例变量,而对客户端没任何影响(程序运行可以动态添加代码)

jvm(java虚拟机):
用于生成中间代码,可应用于所有已经正确安装解释器(命令行编辑器等)的机器上。

java语法details

访问修饰符:用于控制程序的其他部分对这段代码的访问级别。
1.public:能被所有的类(接口、成员)访问;
2.protected:只能被本类、同一个包中的类或子类访问;
3.private:只能被本类访问;
4.friendly(default):访问权限与protected类似,但修饰类成员时不同包中的子类不能访问。

其他修饰符:staitc、final

final:可用于修饰非抽象类、非抽象类成员方法和变量。

1.final类不能被继承,没有子类,方法默认是final的;
2.final方法不能被子类的方法覆盖,但可以被继承;
3.final成员变量表示常量,一经赋值不能修改。

用途:如果一个类不需要有子类,类的实现细节不允许改变,并且确保这个类不会再被扩展,则设计为final类。
如果一个类不允许其子类覆盖某个方法,则声明为final方法。

使用final方法原因有二:1.把方法锁定,防止任何继承类修改它的意义和实现;2.高效。编译器在遇到调用final方法时会转入内嵌机制,大大提高执行效率。

final变量定义的时候,可以先声明而不给初值,这种变量称为final空白,编译器确保空的final在使用之前必须被初始化。

static:用于修饰成员变量和成员方法,也可形成静态代码块。

1.static变量:在内存中只要一个拷贝,jvm只为静态分配一次内存。在加载类的过程中完成静态变量的内存分配,可用类名直接访问;
2.static方法:可用类名直接访问;
3.static代码块:jvm加载时会执行这些静态代码块,将按照先后顺序执行一次。

java8种数据类型

  1. 4种整型:byte(1字节)、short(2字节)、int(4字节)、long(4字节)
  2. 2种浮点类型:float(4字节)、double(8字节)
  3. 1种字符类型:char(2字节)
  4. 1种布尔类型:boolean(1个bit,1/8个字节)

三个特殊的浮点类型:1.正无穷大(Double.POSITIVE_INFINITY)2.负无穷大(Double.NEGATIVE_INFINITY) 3.NaN(表示不是一个数字,使用时直接调用Double.isNaN())。

整数被0除将会产生一个异常,而浮点数被0除将会得到无穷大或NaN结果。

java命名规范:

1.驼峰命名法;2.常量名习惯使用全大写

运算符:

1.&&和||是按照“短路”的方式求值的。如果第一个操作数已经能够确定表达式的值,第二个操作数就不必计算;
2.&和|用于布尔值,作用与&&和||类似,只是不按照“短路”方式计算;
3.+=是右结合运算符;
4.==运算符只能确定两个字符串是不是放置在同个位置;

       String gerrting="Hello";
       if(gerrting=="Hello")
           //probably true
       if(gerrting.substring(0,1)=="Hel")
           //probably false      

java各种字符串存放在公共的存储池中。字符串变量指向存储池中相应的位置。如果复制一个字符串变量,原始字符串与复制的字符串共享相同的字符。
如果虚拟机始终将相同的字符串共享,就可以使用==运算符检测是否相等。但实际上只有字符串常量是共享的,而+或substring等操作产生的结果并不是共享的。

switch

switch语句,case可以是:1.char、byte、short或int;2.枚举常量;3.字符串字面量;

break不带标签,用于跳出一层循环;带标签,用于跳出多层循环。

continue语句将控制转移到最内层循环的首部。

数组

数字数组元素初始化都为0,而boolean数组元素初始化为false,对象数组初始化为null。

OOP(面向对象)

OOP:对象状态的改变必须通过调用方法实现,如果不经过方法调用就可以改变对象状态,只能说明封装性遭到了破坏。

类之间的关系:依赖、聚合(关联)、继承
1.依赖:如果一个类的方法操纵另一个类的对象,则一个类依赖于另一个类;
2.聚合:类A的对象包含类B的对象;

方法参数:
前提:java对象引用进行的是值传递。

Java程序设计语言总是按值调用,也就是说,方法等到的是所有参数值的一个拷贝。

public static void swap(Employee x,Employee y) 
{
    Employee temp=x;
    x=y;
    y=temp;
}   

Employee a=new Employee("Alice",...);
Employee b=new Employee("Bob",...);

swap(a,b);

//结果
a:Alice b:Bob x:Bob y:Alice

java中方法参数的使用情况:1.一个方法不能修改一个基本数据类型的参数(即数值型和布尔型)2.一个方法可以改变一个对象参数的状态 3.一个方法不能让对象参数引用一个新的对象

使用包的主要原因是保证类的唯一性。

只能使用星号(*)导入一个包,而不能使用import java.* 或import java.*.* 导入以java为前缀的包

import语句不仅可以导入类,还增加了导入静态方法和静态域的功能。

注释

方法注释:

1.@param 变量描述
2.@return描述
3.@throws类描述

通用注释:

1.@author 姓名 产生一个作者条目
2.@version 文本 一个版本条目
3.@since 文本 始于条目。对引入特性的版本描述
4.@deprecated 对类、方法或变量添加一个不再使用的注释。
5.@see 引用 将在“see also”部分增加一个超级链接

类设计技巧

1.一定要保证数据私有(个人理解:按设计需要可为protected等)
2.一定要对数据初始化
3.不要在类中使用过多的基本类型
4.不是所有的域都需要独立的域访问器和域变更器
5.将职责过多的类进行分解
6.类名和方法名要能够体现它们的职责

数组

所有数组都要牢记创建它们的元素类型,并负责监督仅将类型兼容的引用存储到数组中。(不是多态)

equals

Object类中的equals方法用于检测一个对象是否等于另一个对象。在Object中,这个方法将判断两个对象是否具有相同的引用。

然而,经常需要判断两个对象状态的相等性,就需要对hascCode()和equals()重载。

@Override
public boolean equals(Object otherObject){

    if(this==otherObject) return true;

    if(otherObject==null) return false;

    if(getClass()!=otherObject.getClass()) reteurn false;

    return Object.equals(this.fields,otherObject.fields )//比较属性
} 

在子类中定义equals方法时,首先调用超类的equals。如果检测失败,对象就不可能相等。如果超类的域都相等,再比较子类中的域。

如果不属于同一个类,不建议使用instance of检测。
因为equals具有以下特性:
1.自反性
2.对称性
3.传递性
4.一致性
5.对于任何非空引用x,x.equals(null)都返回false

所有,若
子类A instance of 父类 B,但父类B 不 instance of 子类A。
子类A equals 父类B,则父类B equals 子类A。

某些作者不建议使用getClass(),不符合置换原则。

所有应根据要比较的值,equals方法中选择instance of或getClass比较。

hasCode

String s="OK";
StringBuilder sb=new StringBuilder(s);
String t=new String("OK");
StringBuilder  tb=new StringBuilder(t);

s.hasCode()==t.hasCode();       //true
s.hasCode()==sb.hasCode();   //false
sb.hasCode()==tb.hasCode();  //false

字符串的散列码是有内容导出的,StringBuilder类中没有hasCode方法,默认调用Object类中的hasCode方法导出的对象存储地址。

Object类定义了toString方法,用来打印输出对象所属的类名和散列码。

包装对象

==运算符也可以用于对象包装对象,只不过检测的是对象是否指向同一个存储区域。

Interger a=1000;
Interger b=1000;

if(a==b)  //false

Interger a=100;
Interger b=100;

if(a==b)  //true

自动装箱规范要求boolean、byte、char<=127,介于-128和127之间的short和int被封装到固定的对象中。

装箱和拆箱是编译器认可的,而不是虚拟机。

public static void triple(Interger x) //won't work
{}

Interger 对象是不可变的,包装在包装器中的内容不会改变。不能使用这包装器创建修改数值参数的方法。

如果要编写一个修改数值参数的方法,需要使用org.omg.CORBA包中的持有者(holder)类型,包括ItHolder,BooleanHolder等。

public static void triple(IntHolder x)
{
    x.value=3*x.value;
}

枚举类型

所有的枚举类型都是Enum类的之类,值就是类中的实例。

比较枚举类型的值,直接使用==运算符就可以。

可以在枚举类型中添加一些构造器,方法和域。

反射

反射:能够分析类能力的程序称为反射。

反射机制可以用来:
1.在运行时分析类的能力
2.在运行时查看对象
3.实现通用的数组操作代码
4.利用Method对象

Class类

一个Class对象表示一个特定类的属性。

getClass().newInstance()方法可以快速创建一个类的实例。

Class.forName().newInstance().

Class类中的getFields、getMethods和getConsrtuctor方法将分别返回类提供的public域、方法和构造器数组。getDeclareFields、getDeclareMethods和getDeclareConsrtuctor方法将返回类提供的所有域、方法和构造器数组。

Employee harry=new Employee("harry coach",2550,1);
Class c1=harry.getClass();

f.setAccessible(true);  //因为name为private域,必须加

Field f=c1.getDeclareField("name"); //获取域name

Object v=f.get(harry);//Object对象,值为name的值

异常处理

如果由于出现错误而使得某些操作没有完成,程序应该:
返回到一种安全状态,并能够让用户执行一些其他的命令;
或者允许用户保存所有操作的结果,并以适当的方式终止程序。

异常处理的任务就是将控制权从错误产生的地方转移给能够处理这种情况的错误处理器。

异常对象都是派生与Throwable类的一个实例。

Throwable

  1. Error
  2. Exception
    2.1 IOException
    2.2 RuntimeException

Error类层次结构描述了java运行时系统的内部错误和资源耗尽错误。

Exception层次两个分支:由程序错误导致的异常属于RuntimeException;而程序本身没问题,但由于像I/O错误这类问题导致的异常属于其他异常。

Java语言规范将派生于Error类或RuntimeException类的所有异常称为未检查异常,所有其他的异常称为已检查异常。编译器将检查是否为已检查异常提供了异常处理器。

带资源的try
try(Resource res=…){
}
try快退出后,会自动执行res.close();

当finally子句包含return时,假设利用return语句从try语句块中退出。在方法返回前,finally子句的内容将会执行。如果finally字句中也有一个return语句,这个返回值将会覆盖原始的返回值。
demo:

public static int f(int n){
    try(){
        int r=n*n;
        return r;
    }finally{
        if(n==2) return 0;
    }
}
f(2) 返回0

使用异常机制的技巧:
1.异常处理不能代替简单的的测试(效率低)
2.不要过分的细化异常
3.利用异常层次结构
4.不要压制异常
5.在检测错误时,“苛刻”要比放任好
6.不要羞于传递异常

java中3种处理系统错误的机制:
1.抛出一个异常
2.日志
3.使用断言

代理

可以在运行时创建一个实现了一组给定接口的新类。

InvocationHandler接口:

public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}

参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。

Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

参数说明:
ClassLoader loader:类加载器
Class

日志

7个日志记录器级别
1.sever
2.warning
3.info
4.config
5.fine
6.finer
7.finest
默认情况下,只记录前3个级别。

泛型

虚拟机中没有泛型类型对象–所有对象都属于普通类。

无论何时定义一个泛型类型,都自动提供了一个相应的原始类型原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定的变量替换为Object)。

Demo:
public class Pair{
    private Object first;
    private Object second;

    public Pair(Object first,Object second){
        this.first=first;
        this.second=second;
    }
}
因为T是一个无限定的变量,直接用Object替换。

当程序调用泛型方法时,如果擦除返回类型,编译器插入强制类型转换。例如,下面这个语句序列

 Pair<Employee> buddies=...;
 Employee buddy=buddies.getFirst();

插入getFirst()的返回类型将返回Object类型。编译器自动插入Employee的强制类型转换。也就是说,编译器把这个方法翻译为两条虚拟机指令:
1.对原始方法Pair.getFirst()的调用;
2.将返回的Object类型强制转换为Employee类型。

不能使用基本类型实例化参数类型。因此,没有Pair,只有Pair。原因是类型擦除,Pair类含有Object类型的域,而Object不能存储double的值。

不允许创建参数化类型的数组。

集合

集合类的基本接口是Collection接口。

java集合类库将接口与实现分离。

队列接口(interface):Queue
队列接口实现:1.ArrayDeque(循环数组队列) 2.LinkedList(链表队列)

Collection接口有两个基本方法:

public interface Collection<E>{
    boolean add(E element);
    Iterator<E> iterator()
}

迭代器
Iterator接口含有3个方法:
public interface Iterator{
E next();
boolean hasNext();
void remove();
}

这里写图片描述

Iterator接口的remove方法将删除上次调用next方法时返回的元素。

在Java中,散列表用链表数组实现。每个列表被称为桶。要想查找表中对象的位置,就要先计算它的散列码,然后与桶的总数取余,所得到的结果就是保存这个元素的桶的索引。(Set集合就是这个存储的)

这里写图片描述

这里写图片描述

线程

创建线程类的方法:
1.通过扩展Thread类来创建多线程
2.通过实现Runnable接口来创建多线程

线程方法:start()启动,run()运行 ,interrupt()中断 , wait()等待
sleep()睡眠
stop()//已过时,不要调用

线程可以有以下6种状态:
1.New(新创建)
2.Runnable(可运行)
3.Blocked(阻塞)
4.Waiting(等待)
5.Timed Waiting(计时等待)
6.Terminated(被终止)

当一个线程试图获取一个内部的对象锁,而该锁被其他线程持有,则该线程加入阻塞状态。当所有其他线程释放该锁,并且线程调度器允许本线程持有它时,该线程变成非阻塞状态。

当线程等待另一个线程通知调度器另一个条件时,它自己进入等待状态。

有几个方法有一个超时参数。调用它们导致线程进入计时等待状态。这个状态一直保持到超时期满或收到适当的通知。

这里写图片描述

线程优先级
MIN_PRIORITY(1)
MORM_PRIORITY(5)
MAX_PRIORITY(10)

默认情况下,一个线程继承它的父线程的优先级。

同步:在大多数实际的多线程应用中,两个或两个以上的线程需要共享对统一数据的存取。

用ReentrantLock保护代码块的基本结构如下:

myLock.lock(); //a ReentrantLock Object

try{
    critical section
}finally{
    myLock.unclock(); 
}

这一结构确保任何时刻只有一个线程进入临界区。一旦一个线程封锁了锁对象,其他任何线程都无法通过lock语句。当其他线程调用lock时,它们被阻塞,直到第一个线程释放锁对象。

这里写图片描述

通常线程进入临界区,却发现在某一条件满足之后它才执行。要使用一个条件对象来管理那些已经获得了一个锁但是却不能做有效工作的线程。

这里写图片描述
这里写图片描述

这里写图片描述

public sychronized  void method(){
    method body
}
等价于加锁

这里写图片描述

这里写图片描述

其他细节:

1.StringBuilder类允许采用多线程的方式执行添加或删除字符的操作。
不能在嵌套的俩个块中声明相同的变量。

2.检测两个浮点数是否相等需要格外小心。

        for(double x=0;x!=10;x+=0.1

可能永远不会结束,因为0.1无法精确地用二进制表示;

3.大数值BigInteger和BigDecimal没有算术运算符(+和*等),只要add、multiply等方法。

4.java类库将保存时间与给时间点命名分开:一个是用来表示时间点的Date类;另一个是用来表示大家熟悉的日历表示法GregorianCalendar(通用Calendar类)

5.是否将某个方法设置为内联方法是jvm的任务,即时编译器会监视调用那些简介、经常被调用的,没有被重载的以及可优化的方法。

6.不要编写返回引用可变对象的访问器方法(会破坏封装性,需要可返回可变对象的引用)

7.java允许重载任何方法

8.如果类中提供了至少一个构造器,但是没有提供无参数的构造器,则在构造对象时如果没有提供参数就会视为不合法。

9.finalize将在垃圾回收器清除对象前调用,回收资源(但调用时间不确定)

10.super不是一个对象的引用,不能将super赋给另一个对象变量

11.一个对象变量可以指示多种实际类型的现象被称为多态。在运行时能够自动地选择调用哪个方法的现象称为动态绑定。

12.String类是final类。

13.动态绑定有一个非常重要的特性:无需对现存的代码进行修改,就可以对程序进行扩展。

14.只能在继承层次内进行类型转换。

15.在将超类转换成子类之前,应该使用instance of进行检查。

16.getClass方法将返回一个对象所属的类

17.多继承会让语言变得复制,效率也降低,用接口解决。

18.可以对类型变量T设置限定:

19.java不支持泛型类型的数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值