读书笔记_java编程思想
编程思想
2.一切都是对象
2.1用引用操作对象
在java中一切都被看做对象,但实际操作对象的是对象的引用,引用于对象的关系就像电视遥控与电视,声明一个引用而不指定对象,也是可以的,但是运行会报空指针,相当于买了有一个遥控器,却没有电视.
2.2对象的存储地
- 寄存器
寄存器位于cpu内部速度最快但容量很小,所以java中根据需求分配寄存器.无法显式指定操作寄存器或向寄存器中存储对象,我们甚至无法感受到寄存器存在的痕迹 - 栈
栈位于RAM中,速度仅次于寄存器,但创建程序时,编译器必须知道存储在栈中的所有项的确切生命周期,这一为了效率而产生的约束限制了栈中不能存放对象,只能存放对象的引用,[1] - 堆
堆也位于RAM中,存放了java中的所有对象,好处是编译器不需要所有项的确切生命周期,坏处是因为不知道确切的生命周期,堆中的存储和垃圾回收需要比栈中更多的时间.有利就有弊.java将这两种结构与对象的数据结合,打造出合适的jvm内存管理. - 常量池
存储不会改变的常量.
- 特例:基本类型
对于一些很小的,简单但是常用的变量,单独为他们在堆中创建一个对象,似乎效率不高.对于这些类型,java采用与c,c++同样的办法:创建一个不是引用的变量,这些变量直接存储值,并且置于栈中,而不是使用new来创建对象,因此更加高效.这些变量被称作基本类型变量. - 数组
创建一个数组对象时,实际上就是创建了一个引用数组,并且所有引用都被初始化为一个特定值:null
2.5方法
在java中,方法是二等公民,不能单独存在,每个方法都必须依赖于类.要声明方法,必须先声明一个类来承载这个方法[2].
普通方法依赖于对象,必须先创建对象才能使用方法.
静态方法依赖于类,使用类本身就可以调用方法,不必须创建对象.
javadoc
3操作符
暂略
4控制执行流程
暂略
5初始化与垃圾回收
5.4 this关键字
一个类可以实例化多个对象,每个对象都可以调用类中的方法,那方法如何知道调用自己的是类中的哪个类呢,实际上,对象调用方法时,会将自己隐式传入方法中,想在方法中使用这个对象的话,this就可以出场了.也就是说,this就代表调用方法的对象.
5.5 清理
5.6变量初始化
java的原则是:所有的变量在使用前(对象实例化)都应该得到恰当的初始化,所以所有变量在声明的时候就有一个默认值,基础类型变量默认值是0,false等.别的变量类型为null.
静态变量只会在类装载时被初始化一次,他是属于类的,只存在一份.假设static变量时一个随机值,多次创建类的对象不会获得不同的static变量.
5.7初始化顺序
成员变量将在方法之前被赋值完毕.(避免方法中使用变量时,变量未赋值完成,引起错误)
1.静态变量
2.静态代码块
2.普通成员变量
3.普通代码块
3.构造方法(隐式static)
4.普通方法
??静态方法啥时候加载,为什么用不了非静态成员变量
访问静态域或静态方法会导致类的加载,类的加载会加载所有static修饰的东西,包括域和方法.
初始化会引起上述顺序加载
5.8可变参数
5.9枚举
总结
在C++中,大量编程错误都源于不正确不完整的初始化,java中为了避免重蹈覆辙,使用了构造器这种保障结构.
实例化一个对象前,构造器中及构造器之前(变量赋值)来保证初始化完整.
7复用类
7.1组合
7.2继承
子类继承父类后,不只是将父类的属性和方法单纯复制到子类中.当创建一个子类对象时,该对象中包含了一个父类对象.这个父类对象和调用父类构造器获得的父类对象是一样的.区别仅仅是后者来自于外部,前者被包装在子类对象内部.
要达到上述效果,需要调用java提供给我们的保证对象初始化成功的结构---构造器.也就是说,子类构造器中会隐式调用父类构造器.如果父类没有空参构造器,需要在子类构造器第一行调用父类构造器,否则编译不会通过.
子类可以在自己的类中对父类方法进行重载,或者直接重写覆盖.
7.3代理
7.6protected
允许来自其他包的继承包内父类的子类访问父类的protected域,起到保护包的作用.不继承,不能访问.
7.7向上转型
子类在方法层面是父类的超集,子类中必定含有父类的所有方法,所以java允许隐式的向上转型.因为父类能调用的方法,子类肯定可以调用.
对于域来说,父类的private域或者friendly域,显式访问会报错,但子类向上转型后访问会编译通过并被初始化为null.
7.8final
static final修饰变量可以保证变量在类中只有一份且不变.
p147有加载顺序,很重要
- final基本类型变量
变量值不许改变 - final引用类型变量
引用不允许被重新指向其他对象,但对象本身可以改变,包括数组,数组也是对象 - 空白final变量
声明变量时不赋值,在构造方法中才对final变量赋值,通过对构造方法传参,这样更灵活.
也就是说,final变量的确定是在对象初始化时才确定.这种方式局限性也在这里,不能用于static final修饰的变量. - final参数
参数引用不允许被重新赋值 - final方法
所有private方法都隐式添加了final,因为他只对自己可见,也就不存在被子类重写的情况.
在子类中声明一个方法声明和父类private方法声明一样的方法,不属于方法重写,只是声明了一个普通的子类方法. - final类
不允许被继承,所有方法被隐式添加final
8多态
子类可以重写父类的方法,并且子类引用可以自动向上转型为父类引用的这一特征,叫做继承.
在运行期间,父类的引用可以自动绑定为子类引用,以自动的调用具体子类的方法的这一过程,叫做动态.注意,多态只是针对普通方法的,对象的域以及静态方法,都不具有多态性.
9接口
需结合设计模式
- 策略模式
- 适配器模式
12异常
12.2java中的异常
- 异常也是类
java中的异常也是一个类对象,他也有一个默认的构造器,并且标准异常类都有一个参数为String类型的带参构造器,用于存储异常信息. - 抛出异常与方法返回的相似之处
方法抛出异常与方法正常返回返回值有很多相似之处,比如:
1.他们都可以中断方法继续执行
2.正常返回会返回一个引用,抛出异常同样也会抛出一个异常的对象引用 - 不同之处:
处理返回对象的"目的地",方法返回值交给栈中的上一层调用方法,异常则交给适当的异常处理程序,具体要看谁有能力处理这个异常,一个异常可能会跨越许多方法调用栈才能找到他的处理程序.
12.3捕获异常
异常会被第一个可以处理他的catch语句捕获,并且捕获后就结束,也就是说,多个并列的catch语句并不会像swtich语句那样被捕获多次.但是一个异常被捕获后处理完也可以继续抛出
12.5声明你的异常
在方法声明上使用throws关键字来向上一层方法声明你的异常,如果上一层方法有能力处理,就会处理这些异常,没有的话,他们应该继续向上声明异常.
12.6栈轨迹
通过调用e.printStackTrace来打印异常信息,信息可以通过getStackTrace来直接访问,该方法将返回一个数组.
数组中元素是栈轨迹,每个元素表示栈中的一帧,索引为0的元素是栈顶元素,也就是最后一个方法调用(抛出异常之处),最后一个元素也就是栈底元素是调用的第一个方法.