《Java编程思想》读书笔记

第一章:对象导论

1)万物皆为对象
2)程序是对象的集合,它们通过发生消息来告知彼此所要做的
3)每个对象都有自己的有其他对象所构成的存储
4)每个对象都有其类型
5)某一特定类型的所有对象都可以接收同样的消息–可替代性

第二章:一切都是对象

自动装箱:自动将基本类型转换为包装器类型
自动拆箱:自动将包装器类型转换为基本类型

成员变量会默认被初始化,局部变量不会。

方法签名:方法名和参数列表

static:
修饰变量时:一个类的所有实例共享同一个变量
修饰方法时:可由 类名(而不是实例).方法 直接调用
修饰import时:引入库中的static方法可直接调用(而不用前缀类名)

javadoc

类的命名规则:驼峰风格

第三章:操作符

别名(浅复制)

==和equals

短路

按位操作符: & | ^ ~
&:均1为1,否则得0
|:有1为1,没1得0
^:相同为1,不同为0
~:取反

移位操作符: << >> >>>
1.<<:低位补0
2.>> : 正:高位插0 负:高位插1
3.>>>:高位插0

? :

窄化转换与扩展转换

第四章:控制执行流程

逗号操作符:for循环

foreach

标签

第五章:初始化与清理

默认构造器(无参构造器)

垃圾回收器只知道释放那些经由new分配的内存。为了释放并非使用new获得的内存南区域,java允许在类中定义一个名为finalize()的方法。其工作原理为:一旦垃圾回收器准备释放对象占用的存储空间,将首先调用finalize()方法,并且在下一次垃圾回收动作发生时才会真正回收对象占用的内存。

只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。因为垃圾回收本身也有开销,要是不使用它,就不用支付这部分开销了。

本地方法是一种在Java中调用非Java代码的方式

垃圾回收策略:

引用计数器:为0时释放
停止-复制
标记-清除
自适应:碎片较少时标记清除,碎片较多时停止复制

可变参数

第六章:访问权限控制

public :包内包外均可访问
protected:包内及其子类均可访问
包访问权限:包内均可访问
private:只有本类可访问

冲突:引入的包有相同名称的类库时,使用该类时需要写全名(包名+类名)

第七章:复用类

组合(has-a):想在新类中使用现有类的功能而非它的接口
继承(is-a):使用现有类,并开发一个特殊版本
java会自动在子类的默认构造器中插入对父类默认构造器的使用,有参数时需使用super()
代理

第八章:多态

向上塑型
绑定、前期绑定、后期绑定
只有非private方法才可以被覆盖
只有普通的方法调用可以是多态的。而如果某个方法是静态的,它的行为就不具有多态性。
构造器的调用顺序:
1)调用父类构造器
2)按声明顺序调用成员的初始化方法
3)调用子类的构造器主体
构造器内尽量不要使用其他方法,唯一能安全使用的只有父类中的final方法。
协变返回类型:子类即重写父类方法时,返回的类型可以是父类方法返回类型的某种子类。
纯继承:子类可以完全替代基类

第九章:接口

接口也可通过继承扩展接口
什么时候用抽象类?什么时候用接口?
抽象类 --> 模板
接口 -->标准/功能
面向接口编程而不是实现

第十章:内部类

如果想从外部类的非静态方法之外的任意位置创建某内部类的对象,那么必须像在main()方法中那样,具体地指明这个对象的类型:OuterClassName.InnerClassName
内部类可以访问外围对象的所有成员、元素
内部类中,如果需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟.this
由于内部类对象会暗暗地连接到创建它的外部类对象上,所有在拥有外部类对象前是不可能创建内部类对象的。(嵌套类除外)
外部类,内部类 对象名称 = 外部类对象.new 内部类();
局部内部类只能在局部使用
匿名内部类(匿名类)不能同时继承和实现接口(只能实现一个接口)
嵌套类:(没有与外部类的隐藏引用)
1)要创建嵌套类的对象,并不需要其外围类的对象
2)不能从嵌套类的对象中访问非静态的外围类对象

每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

1)内部类可以有多个实例,每个实例都有自己的状态信息并且与其外围类对象相互独立。
2)在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类。
3)创建内部类对象的时刻并不依赖于外围类对象的创建。
4)内部类并没有令人迷惑的“is-a” 关系;它就是一个独立的实体。

第十一章:持有对象

在这里插入图片描述

类型参数
Collection:List, Set, Queue
Map:HashMap,TreeMap, LinkedHashMap
所有的Collection对象都可用foreach遍历,而Map对象可由keyset()获得所有key,进而由key遍历

第十二章:通过异常处理错误

当抛出异常后,有几件事会随之发生。首先,同java中其他对象的创建一样, 将使用new在堆上创建异常对象。然后,当前的执行路径(它不能继续下去了)被终止,并且从当前环境中弹出对异常对象的引用。此时,异常处理机制接管程序,并开始寻找异常处理程序来继续执行程序。

异常分类

在这里插入图片描述
RuntimeException为运行时异常,即unchecked Exception,其他Exception为编译时异常,即checked Exception

抛出异常与方法正常返回值的异同
异常处理程序

异常处理程序的任务是将程序从错误状态中恢复,以使程序能要么换一种方式运行, 要么继续运行下去。

异常处理程序必须紧跟在try块之后。当异常被抛出时时,异常处理机制将负责搜寻参数与异常类型相匹配的第一个处理程序。然后进入catch子句执
句结束,则处理程序的查找过程结束。

终止与恢复

异常处理理论,上有两种基本模型。Java支持终止模型
在这种模型中,将假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行。
异常被抛出,就表明错误已无法挽回,也不能回来继续执行。
另一种称为恢复模型。意思是异常处理程序的工作是修正错误,然后重新尝试调用出问题的方法,并认为第二次能成功。对于恢复模型,通常希望异常被处理之后能继续执行程序。
如果想要用Java实现类似恢复的行为,那么在遇见错误时就不能抛出异常,而是调用方法来修正该错误。或者,把try块放在while循环里,这样就不断地进人try块,直到得到满意的结果。

自定义异常

自定义异常需要从现有异常类继承

异常说明

强制使用,并作为方法声明的一部分

捕获所有异常

catch(Exception e){}可以捕获所以异常,因为Exception是所有异常的父类。即:子类的异常也可匹配上父类的处理程序。

异常链

常常会再捕获一个异常后跑出另外一个异常,并且希望把异常原始信息保存下来,这被称为异常链。

覆盖方法的时候,只能抛出父类方法的异常说明中列出的那些异常。

吞食则有害

第十三章 字符串

String为什么不可变?
不可变的目的

由于在程序编写的过程中,会大量地用到String常量,如果每次声明一个String引用都要新建一个String对象,那么会造成空间的极大浪费。于是,在java的堆中开辟了一块存储空间String pool,用于存储String常量对象。当有多个String引用指向同样的String字符串时,实际上是指向的是同一个Sting pool中的对象,而不需要额外的创建对象。

实现String pool就需要String定义为final,否则,当引用a、b都指向“abc”时,通过a将对象改变后,引用b所指向的对象被动地改变了。

其他好处:
  1、以String作为HashMap的key,String的不可变保证了hash值的不可变。
  2、String作为网络连接的参数,它的不可变性提供了安全性。
  3、String不可变,所以线程安全。

不可变的原理

1.String类被final修饰,不可被继承。
2.String的成员变量char数组value被final修饰,初始化后不可更改引用。
3.String的成员变量value访问修饰符为private,不对外界提供修改value数组值的方法。

StringBulider

预先制定大小可以避免多次重新分配缓冲

与StringBuffer的区别:后者线程安全,但性能稍逊

正则表达式
Scanner

可以接受File对象,InputStream,String或者像Readable对象

第十四章:类型信息

RTTI:运行时类型信息
因要素过多,列举两篇博客

class对象

相关知识可见该篇博客:
https://blog.csdn.net/mcryeasy/article/details/52344729

反射

相关知识可见该篇博客:
https://blog.csdn.net/qq_40896997/article/details/94483820

第十五章:泛型

泛型:参数化类型,适用于许多许多的类型
泛型的主要目的之一就是用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。从而将一些运行时产生的错误移入到编译期。
基本类型无法作为类型参数。不过自动打包和拆包功能可以很方便的在基本类型和其相应的包装器类型之间进行转换。
泛型方法可以使方法能够独立于类而产生变化,如果使用了泛型方法可以取代整个类泛型化,那么就应该只使用泛型方法。
类型参数推断:使用泛型类时,必须在创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不必指明参数类型。
通配符: ?
? extends
? super
通配符引用的是明确的类型,因此List<? extends Fruit>它并不意味着所有类型的Fruit,而意味着所有Fruit类型中的某(具体)一种。

擦除:

Java泛型是使用擦除来实现的,这意味着当你在使用泛型时,任何具体的类型信息都被擦除了。因此ListList在运行时事实上是相同的类型。这两种形式都被擦除成它们的原生类型,即LIst。
泛型类型参数擦除时将擦除到它的第一个边界(List被擦除为List,普通类型变量在未指定边界的情况下被擦除为Object。
擦除的核心动机是“迁移兼容性”,即为了使泛化的客户端可以使用非泛化的类库(泛型代码与非泛型代码共存),如果不这样有些构建了很久的类库可能就不能再使用了。
擦除带来的问题:泛型不能显式地引用运行时类型的操作,如:塑型,instanceof操作和new表达式。因为所有关于参数的类型信息都丢失了。
弥补:传递类型标签
如何创建泛型数组:创建一个被擦除类型的新数组,然后将其转型。

第十六章:数组

Java中,数组是一种效率最高的存储和随机访问对象引用序列的方式。但其大小在申请时被固定,并且在其生命周期中不可改变。一旦越界,将会产生一个表示程序员错误的RuntimeException异常。
对象数组和基本类型数组在使用上几乎是相同的,唯一的区别就是对象数组保存的是引用,基本类型数组直接保存基本类型的值。
通常,数组与泛型不能很好的结合。你不能实例化具有参数化类型的数组,因为擦除会移除参数类型信息,而数组必须知道它们所持有的确切类型,以强制保证类型安全。但编译器允许创建这种数组的引用,所以我们可以创建非泛型的数组,然后将其转型。但一般我们还是使用泛型容器比较好。
记住:优选容器而非数组

Arrays的几个静态方法

fill(x, a):以同一个值(引用)a填充数组x中各位置 。还可在参数中加开始填充位置与结束填充位置(左闭右开)。
equals();deepequals();比较两数组(多维数组)是否相等。相等条件:元素个数相等,对应位置元素也相等。
sort()用于对数组排序
binarySearch()用于在有序数组中查找元素
toString()产生数组的String表示
hashcode()产生数组的散列码
asList()接受任意的序列或数组作为参数,将其转变为List容器

System.arraycopy(i,0,j,0,length)复制数组

第十七章:容器深入研究

填充容器:类似于Arrays.fill()也有Collection.fill()
正确的equals()方法必须满足以下5个条件:
1)自反性:对任意x,x.equals(x)一定返回true
2)对称性:对任意xy,若y.equals(x)返回true,则x.equals(y)也返回true
3)传递性:对任意xyz,若x.equals(y)与y.equals(z)都为true,则x.equals(z)也为true
4)一致性:对任意xy,只要对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,结果都不变
5)对任何不是null的x,x.equals(null)一定返回false
String有个特点:如果程序中有多个String对象,都包含相同的字符串序列,那么这些String对象都映射都同一块内存区域。即:拥有相同的hashcode
HashMap的默认负载因子是0.75
快速报错:能够防止对个进程同时修改同一个容器的内容。这个机制会探查容器上的任何除了你的进程所进行的操作以外的所有变化,一旦它发现其他进程修改了容器,就会立刻抛出ConcurrentModificationException异常。这就是“快速报错”的意思,即——不是使用复杂的算法在事后来检查问题。
获取迭代器的时机应为添加完所有元素之后(即获取迭代器后不能再添加或删除元素)

引用

强引用(Strong Reference):即使进行了多次的GC回收,即使JVM真的已经不够用了,即使JVM最终不得已抛出了OOM错误,那么该引用继续抢占;
软引用(Soft Reference):当内存空间不足时,可以回收此内存空间。如果充足则不回收,可以用其完成缓存的一些处理操作开发。
缓存:保证数据更快的操作(读取)。是不重要的数据。可以作为牺牲来释放空间。
弱引用(Weak Reference):不管内存是否紧张,只要一出现GC处理,则立即回收。
虚引用(Phantom Reference):和没有引用是一样的。
比如HashMap根据key取得值,设置key值为null和不设置key值的效果是一样的。
更深入学习可见本链接
对象是可获得的,是指此对象可在程序中的某处找到。这就意味着你在栈中有一个普通的引用,而它正指向某个对象(也可能嵌套)。如果一个对象是可获得的,则垃圾回收器就不能释放它,因为它仍然为你的程序所用。如果一个对象不是可获得的,那么你的程序就无法使用到它,故将其回收就是安全的。
如果想继续持用某个对象的引用,希望以后还能访问到该对象,但是也希望能够允许垃圾回收器释放它,这时就应该使用Reference对象。你可以在继续使用该对象的同时,在内存消耗殆尽的时候又允许释放该对象。
按由强到弱排列:强引用>软引用>弱引用>虚引用
软引用是实现内存敏感的高速缓存
弱引用是为实现规范映射而设计的,它不妨碍GC回收映射的键或值。规范映射中的对象实例可以在程序的多处被同时调用,以节省存储空间。
虚引用用以调度回收前的清理工作
使用软引用弱引用时,可以选择是否将其放入ReferenceQueue(用作回收前清理工作的工具)中,而虚引用只能依赖于ReferenceQueue。

第二十章:注解

注解(又称元数据)为我们再代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。
基本注解:@Override,@Deprecated,@SuppressWarnings,@SafeVarargs,@FunctionalInterface
元注解:@Retention、@Documented、@Target、@Inherited、@Repeatable
自定义注解:程序员通过元注解定义的注解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值