- 浏览: 461467 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
syw19901001:
30多条mysql数据库优化方法,千万级数据库记录查询轻松解决 ...
MYSQL的全表扫描,主键索引(聚集索引、第一索引),非主键索引(非聚集索引、第二索引),覆盖索引四种不同查询的分析 -
gaoyuanyuan121:
直接改成root.war,根路径能访问,项目路径也能访问,赞 ...
jetty 中如何设置root app -
freezingsky:
翻出来,再看一次!
AOP 的简单入门 -
Shen.Yiyang:
inter12 写道Shen.Yiyang 写道我说的不是NI ...
ReentrantLock、sync、ReentrantReadWriteLock性能比较 -
inter12:
Shen.Yiyang 写道我说的不是NIO和BIO的区别,而 ...
ReentrantLock、sync、ReentrantReadWriteLock性能比较
2009年8月13日 星期四 14时11分
第二章——万物皆为对象:
一) 数据在计算机中的存放地址:
1.寄存器(register):是处在处理器中,所以它的处理速度是最快的,但是也是数量也是很有限的,由编译器分配。
2.栈(stack):位于常规内存区(general random-access memory area).处理器通过栈指针(stack point)来对他进行直接访问。通过指针的上下移动来分配或销毁内存。是在效率和速度上仅次于寄存器。因为他的生命周期和大小是已知的。所以有一定的局限性。故java中一般不会把对象存放在这个内存区域,更多是引用。references存放在这个区域。先进后出原则
3.堆(heap):是一块多用途内存区(general -purpose pool of memory).基本上所有的java对象都是存放在这个区域。优点是分配空间时,编译器不关心分配多大的空间,何时销毁。速度上要慢些。(RAM)
4.静态存储(static storage):静态存储的数据在整个运行期间都能访问到,你可以把某个对象的属性定义为静态,但是java对象不能存放到static storgae
5.固定存储(constant storage):常量存放的地址。在嵌入式开发中,就可以考虑是否把常量放在ROM内存中。
6.非内存的存储(NON-RAM menmory):对于一些可以保存在程序运行之外的。即程序失去了对数据的控制,但是这些数据还是存在。简单的说就是把对象进行持久化。根据持久化方式的不同,我们可以分为:
6.1:流对象(streamed object):即把对象转化为字节流,存放到另一台机子上。
6.2:持久化对象(persistent object):即将对象按照某种方式序列化到存储设备中,如磁盘,DB等。
二) primitive (原始类型):在java体系中存在两种类型。一就是原始类型(primitive)&&对象类型。原始类型就是基本数据类型int,long 等。对于这些简单的数据类型,因为是非引用类型,所以在java中把它们存放在栈中。以提高效率。所有的基本类型都是有符号,没有unsigned符号。
三) Java中的数组
在C,C++中,数组就是一块内存。在数据未被初始化,或访问数组之外的内存,那么就会引起很多麻烦。在java中,规定了数组一定需要被初始化来限制。这样在访问数组之外的内存已经是不可能了。并另加一些内存来进行数组的边界检查。
当你在创建数组的时候就是在创建一个引用reference.该引用会自己初始化为一个特殊的值:null.Java当看到这个null值的时候就知道这个reference没有指向任何对象。当你在对这个null进行操作的时候,就会抛出一个异常来进行处理。
四)其他:
默认值:只有变量作为对象的类的成员时,才会有默认的初始值。
传递的问题:其实和C++中一样,我们在方法的传递时,如果传递的是一个primitive变量,那么传递仅仅是一个值,在return 的时候不会返回变化后的值。在C++中,为了解决这个问题,才方法中定义传参时,一般定义为指针,或者是引用。这个通java一样,在Java中传递一个基本类型,也是不变化的。通过传递一个对象(也就是一个对象的引用)来实现值变化的返回。对象就是C++中的指针或者引用。不过是进行封装,安全的指针。
第三章——控制程序流程
一) Java运算符:基本上所有的运算符号都是作用与primitive的,但是有些是例外:如 = == += !=
1.1 赋值:对于primitive类型的赋值就是在内存地址上进行赋值。
int a = 1; 建立一个a的指向栈中代表“1”地址
int b ; 建立一个默认指向0地址的引用。
int b = a 拷贝一份a的内容到b引用指向的地址。修改b,不会影响a的值。
简单的说:primitive之间的赋值就是内容的拷贝,对象之间的赋值就是引用的拷贝。
二) 数据类型转化:
比int 小的数据类型会被提升到int,再进行运算,所以结果仍然是int.向下转化时,必须加类型转化,而且会丢失数据。
总之:运算过程中最大的类型,决定结果的类型。如 long && double result is double .
三) 其他:
在for循环中可以这样使用逗号运算符,也是唯一用到的地方
for (int i =0 , int j = 1; i< 10 && j < 20 ;i++,j++){
//todo
}
在一些多层的循环的时候,可以使用标签来实现break , continue
for ()
{
label 1:
for ()
{
break label1; //这样可以实现一定范围的跳转
}
}
虽然保留这goto 但是没有使用。
第四章:初始化及清理
一)构造函数的由来,为了初始化一些东西,但是又为了希望被调用,不被遗忘。C++ JAVA中都定义了这种方式。
二)方法的重载:有构造函数的重载以及方法的重载。overLoad的最大区别是参数的不同。因为只有这个才能区分。
例如返回参数的不同,在系统调用的时候,并不知道调的是哪个。所以返回类型不同不能成为overload的区分方式。
方法的范围范围不同,如设置为private public .亦不能成为overload的区别,在同一个类中,调用这个方法编译器也不能区分调用的是哪个方法。
三)每一个类都存在一个默认的构造函数。
四)常见关键字
4.1 this 关键字:对象本身的引用。
在我们定义了两个相同类的对象。使用 a.f1(1) b.f1(1).在底层为了区分到底是哪个调用了f1()方法,其实把该对象的引用也作为一个参数传递过去了。那两个方法的调用实际上是以 banana.f1(1,a) banana.f1(1,b).
用途: 1.明确使用类内部自身对象。它代表就是类本身reference
2.在一个构造函数中调用另一个构造函数。
3.在传入参数与类自身属性相同时,用来区分是实参还是形参。this.a = a
4.2 static关键字:简单的说static 修饰过的方法里面没有this,是一个类变量,类函数。在static 方法里面只能调用static 方法。因为是一个类函数或类变量,公用。故不能调用属于该类其他任何的非static函数或变量。非static 意味着可能被生成多个对象。
4.3 finalize:释放内存时调用的方法。简单的说:
4.3.1.对象不一定会被垃圾回收
4.3.2.垃圾回收不析构函数
4.3.3 垃圾回收只与内存有关。只有在内存耗尽的时候才会取调用。一般不会耗费资源去调用
调用方式:system.gc()
五)成员的初始化
对于类成员变量,会默认的初始值,但是对于局部变量则需要自己取初始化。
1. 指定初始化,在定义变量的时候就进行初始化
2. 在构造函数中进行初始化
初始化的顺序:
在一个函数的初始化函数中,包含new其他类,那么无论是在什么位置new这个类,都必先会先调用这个类的构造函数,然后才调用自己的构造函数。
例如如下:一个类在加载的时候会先加载属性,然后才加载构造函数
第五章 隐藏实现
一些常见的接口方法
第六章 类的复用
合成:在新的类里面使用旧的类,例如在A类中使用B类
继承:直接继承另一个类,来复用父类的代码
初始化一般有三种形式:
1.直接在定义的属性的时候初始化 int a = 9
2.在构造期里面开始构造
3.lazy initial 就是需要进行判断后再初始化
if (null == a ) a = 9;
基类的初始化:
子类在初始化的时候会先调用基类的初始化函数
子类在调用父类的初始化构造函数时,调用父类的构造函数必须在最前面。这样做是为了防止:在调用父类的过程中抛出异常,可以首先知道。而不必取构造子类。
合成还是继承:
面向对象最简单的使用就是把数据和方法封装成一个类,然后再使用这个类的对象。
是否用继承的时候,判断这个类是否能够上传,即子类是否可以当做父类来使用。少用继承,多用合成。
final 关键字:
可以修饰属性:使得这个属性不能指向另一个引用
方法:为使这个方法不能在子类中被覆盖
类 :为使这个类不能被继承。比如说JDK中的String类等
第七章:多态性
抽象类的出现。就是你不想实例化这个抽象类,但是提供一些公共的接口让子类来实现
有抽象方法的一定是抽象类。抽象类以一定有抽象方法.
比如说你想创建一个类,但是该类又不想被实例化,那么就可以采用这种方法。
第八章: 接口与内部类
接口:是进一步的强化了abstract的概念,接口中所有的方法都是abstract和static且final的。故需要进行初始化
接口中也可以嵌套接口
内部类:在一个类中嵌套另一个类。将逻辑上相互从属的类组织起来,并控制它的访问权限。
内部类的访问方式:
outer.inner c = new outer.inner()//这个是显示内部类的用法。
内部类的优点:每个内部类都可以独立的实现某个接口,因此内部类不会受“宿主类是否已经继承了别的实现”的约束。
简单的说接口是部分解决了多继承的问题,那么内部类完全解决了多继承的问题。
第九章:用异常来处理错误
9.1 Java的基本哲学:糟糕的代码根本就得不到执行
9.2 异常的优点:让错误代码处理显的更有条理。即集中在一个地方对异常进行处理。还是应该坚持自己的意见,对于程序流程的跳转。可以利用异常来控制。
9.3 对于异常有两种处理模式
1. 中止模式:temination.即抛出异常,中止程序继续执行
2. 继续模式:resumption.即跳过这个异常,继续执行。我们所用的操作系统一般采用的就是这种方式。
对于程序中,我们可以自己定义自己的异常。来控制程序的走向。
9.4 调试的时候我们可以采用 system.err来输出错误信息。采用system.out的话有可能会被重定向。就是在catch{}里面
catch(Exception e)
{
system.err.println("exception has happened");
}
9.5 异常链:即在捕捉到一个异常后,再抛出一个其他类型的异常。JDK1.4以后提供了一个cause的构造函数来处理这个事件。
initCause();具体使用的时候可以再仔细研究下。
9.7 标准的JAVA异常
throwable : 是error :编译时候错误或者是系统错误。对于这类错误我们一般是无能为力的。也不需要我们取扑捉。
exception :java标准的类库方法及自定义的异常方法,这类方法需要我们来处理。
finally块中的代码是一定会被程序执行的。所以在其中进行一些清理工作。对于一些内存以外的东西设置到原来状态的时候,如关闭一些输入流等
使用finally块的时候有可能造成异常的丢失。如下所表示:
public class ExceptionsTest
{
public void f() throws MyTestException
{
throw new MyTestException();
}
public void disPlay() throws MyTestException2
{
throw new MyTestException2();
}
public static void main(String[] args) throws MyTestException, MyTestException2
{
ExceptionsTest eTest = new ExceptionsTest();
try
{
eTest.f();
}finally
{
eTest.disPlay();
}
}
}
9.8 在构造函数中抛出异常
异常处理原则:
不知道如何处理的时候就不要捕捉它
1. 在何时的地方处理异常
2. 把问题解决了,然后重新调用那个引起问题的方法
3. 修正那个方法,然后绕过那个方法再继续下去
4. 把当前环节能做的事情全部做完,然后把异常抛到更高层
5 把当前环节能做的事情全部做完,然后抛另一个异常到更高层
6. 中止程序
7. 简化
8. 把类库和程序做的更安全
第十章:检测类型
RTTI:run-time type identification 运行时类别识别。
10.1在运行时候的类型信息是由class文件来确定的。JVM在创建一个对象的时候会检查是否加载了这个类的class对象,如果没有则取加载.class文件。
对象的产生: 一旦内存加载了这个CLASS对象,所有该类的对象都是由该对象来产生的。所以对于判断是否是一个对象的时候也可以采用这种方式来进行。
对象之间的检测:
1 利用对象类型的强转
2.利用 instanceof, isInstance() 两种方式 后者为动态判断是否为同一个类型,前者写法较丑陋。
CLASS提供了很多有用的方法:
类名.class.isInstance()
类名.class.isInstance()
SubEqual.class.isArray();
SubEqual.class.isInterface();
SubEqual.class.isPrimitive();
SubEqual.class.isLocalClass();
instanceof 与 class之间都可以用于比较对象之间的类型。但是有一个区别
class之间的比较只能是由通一个 类名.class文件产生的对象 才是true
instanceof如果是其本类或者是子类 返回的都是true
获得class的reference的两种方式 一种是class.forName() 这样就不需要取new一个这个类型的对象。
另一种是通过已经生成的对象 getClass()方法来获得class的引用。
总结:RTTI一般不常用,因为它只是多态的底层实现。只有在我们在多态的过程中,某个子类的反映特别的慢,可以考虑用RTTI来替代多态。这个属于程序的优化。
软件编程的习惯是:首先让程序跑起来,然后才考虑的是优化的问题。
第十一章:对象的集合
如果程序的对象数目是有限,且数目是可知的,那么这个程序是相当的简单
数组:
数组跟其他容器的最大区别在于:效率,类型识别,可以持有primitives.在随即存储和访问references的效率中是最高的。只是一个简单的序列。
但是缺点一样明显,在创建后,数目是固定的。后来JDK提供了一个ArrayList,但是在速度上慢了很多。
与C++中的数组相比较,效率上差点,因为JAVA中的数组还要一定的开销做数组的下表越界。C++就没,所以容易出错。
数组是第一流的对象
因为容器只能只能存放对象的reference。数组两者兼可,而且效率更高。
ARRAYS里面有几个有用的方法:
Equals:数目,每个元素都要相等
sort,fill,
binarySearch:一种效率很高的查询方式,对于未排序的数组使用这个方法没有什么意义。
system.arraycopy()方法能够更快的执行数组的拷贝。
三目运算符的双重用法:
public int compareTo(String arg0)
{
int j = Integer.valueOf(arg0);
return this.i < j ? -1 : ( this.i == j ? 0 : 1);//这里用的就是双重的三目,看起来很爽
}
为了使的数组或容器中能够进行排序,那么就需要实现comparator接口。
数组总结:arrays这个类主要是为数组服务的。collections主要是为容器服务的。
容器:对于list还有一个更技巧的迭代器:ListIterator 可以沿两边来查看集合。
容器的结构图:
主要部分已经用黑色框表示:
其中的abstratXX主要是用了适配器模式,如果我们要写自己的类话,那就不需要实现对应的接口,只需要继承抽象类就可以了。不要实现接口,并实现接口所有的类。
容器简介LIST
List:以一定顺序保存数据,,允许重复。可以制造ListIterator,对集合进行两边的访问。
ArrayList :用数组实现的LIST,能够进行快速的随即访问,但是在中间插入或删除数据比较慢。ListIterator只能用在反向遍历集合中,不要用来插入或删除数据,相比较LinkedList,在ArrayList中使用ListIterator的系统开销比LinkedLIST大。
LinkedList:对顺序访问进行了优化,插入删除数据的代价也不高,但是随即访问能力较慢能当做栈,队列,双向队列来使用,在一般情况下不推荐是这个。建议使用ArrayList。
SET :多态的完美实现。无序,不允许重复的。对于加入的object对象,需要覆盖equals方法。
HASHSET:为优化查询速度而设计的SET,放入的object必须实现hasshCode方法。底层就是hashMap来实现的。
TREESET:有血的SET,放入的对象必须实现compable接口,或者有一个比较器compartor
LINKEDHASHSET:内部是在链表实现的SET,即有HASHSET的速度,又能保存元素加入的顺序,用iterator遍历的时候是按照插入顺序来遍历的。
MAP:底层用hash算法实现,在容器中的查询速度比arrayList还快。
散列算法和hash算法。
HASHMAP的底层实现:
其实在底层就是一个数组,每个数组的位置叫做BUCKET,没一个bucket其实就是一个linkedList,插入的时候,首先根据KEY值算的hashcode,让后对数组的大小进行去模,如果得到的这个bucket位上没有任何数据,就new一个linkedList,并放入到其中,若是已经有,则比遍历真个list看是否存在相等,若是相等的就返回原来的值,并把新值存放在位置上,若是没有相等的,那么就把值加到linkedList的最后。
影响其性能的因素:
1.bucket数目,即数组的大小。
2.initial bucket数目:初始化大小,可以通过初始化构造函数来设定。默认情况是16个,
3.当前hash表的数目
4.load factor:加载因子,即在什么时候对这个数组进行扩展。如果你设定的比较大的话,可以考虑把load factor设定的大点,免得需要多次reflash。默认的加载因子是0.75.也就是75%。
hashcode的产生原则:就是一个对象放入和取出计算的hashcode值要求是一样的,不能因为对象某个值得改变而导致取出的值不一样。
LIST的选择:
上表是对于四种容器的性能测试:
GET:随即访问 ITERATOR:顺序访问 INSERT:插入 REMOVE:删除
从上表可以看出数组在随即访问速度是最快的,在数据的插入和删除最慢。但是奇怪的是ArrayList的顺序访问速度比数组要快。
ArrayList的优势在于性能的平衡性,随即访问和插入的速度都可以,可怕的是删除速度,毕竟底层实现还是数组。
LinkedList 的优势在于删除和插入,
Vector是线程安全的,可以不用考虑。
SET的选择:
总体来说:HashSet的性能要比treeSet好,尤其是在查询和插入时,TreeSet存在的意义在于维护一个有序序列。
LinkedHashSet的插入要比HashSet稍微慢点,那是因为它要维护链表和Hash容器的双重代价。也因为底层是链表的缘故,所以它的遍历是最快的。
在容量不是很大的情况下个人建议还是使用LinkedHashSet,比较好,在插入的时候代价并不是很高,但是遍历的速度确实很快。
MAP选择:
一般情况下使用hashmap就可以了.treeMap需要维护一个有序列表,所以要慢些。
总结:
第二章——万物皆为对象:
一) 数据在计算机中的存放地址:
1.寄存器(register):是处在处理器中,所以它的处理速度是最快的,但是也是数量也是很有限的,由编译器分配。
2.栈(stack):位于常规内存区(general random-access memory area).处理器通过栈指针(stack point)来对他进行直接访问。通过指针的上下移动来分配或销毁内存。是在效率和速度上仅次于寄存器。因为他的生命周期和大小是已知的。所以有一定的局限性。故java中一般不会把对象存放在这个内存区域,更多是引用。references存放在这个区域。先进后出原则
3.堆(heap):是一块多用途内存区(general -purpose pool of memory).基本上所有的java对象都是存放在这个区域。优点是分配空间时,编译器不关心分配多大的空间,何时销毁。速度上要慢些。(RAM)
4.静态存储(static storage):静态存储的数据在整个运行期间都能访问到,你可以把某个对象的属性定义为静态,但是java对象不能存放到static storgae
5.固定存储(constant storage):常量存放的地址。在嵌入式开发中,就可以考虑是否把常量放在ROM内存中。
6.非内存的存储(NON-RAM menmory):对于一些可以保存在程序运行之外的。即程序失去了对数据的控制,但是这些数据还是存在。简单的说就是把对象进行持久化。根据持久化方式的不同,我们可以分为:
6.1:流对象(streamed object):即把对象转化为字节流,存放到另一台机子上。
6.2:持久化对象(persistent object):即将对象按照某种方式序列化到存储设备中,如磁盘,DB等。
二) primitive (原始类型):在java体系中存在两种类型。一就是原始类型(primitive)&&对象类型。原始类型就是基本数据类型int,long 等。对于这些简单的数据类型,因为是非引用类型,所以在java中把它们存放在栈中。以提高效率。所有的基本类型都是有符号,没有unsigned符号。
三) Java中的数组
在C,C++中,数组就是一块内存。在数据未被初始化,或访问数组之外的内存,那么就会引起很多麻烦。在java中,规定了数组一定需要被初始化来限制。这样在访问数组之外的内存已经是不可能了。并另加一些内存来进行数组的边界检查。
当你在创建数组的时候就是在创建一个引用reference.该引用会自己初始化为一个特殊的值:null.Java当看到这个null值的时候就知道这个reference没有指向任何对象。当你在对这个null进行操作的时候,就会抛出一个异常来进行处理。
四)其他:
默认值:只有变量作为对象的类的成员时,才会有默认的初始值。
传递的问题:其实和C++中一样,我们在方法的传递时,如果传递的是一个primitive变量,那么传递仅仅是一个值,在return 的时候不会返回变化后的值。在C++中,为了解决这个问题,才方法中定义传参时,一般定义为指针,或者是引用。这个通java一样,在Java中传递一个基本类型,也是不变化的。通过传递一个对象(也就是一个对象的引用)来实现值变化的返回。对象就是C++中的指针或者引用。不过是进行封装,安全的指针。
第三章——控制程序流程
一) Java运算符:基本上所有的运算符号都是作用与primitive的,但是有些是例外:如 = == += !=
1.1 赋值:对于primitive类型的赋值就是在内存地址上进行赋值。
int a = 1; 建立一个a的指向栈中代表“1”地址
int b ; 建立一个默认指向0地址的引用。
int b = a 拷贝一份a的内容到b引用指向的地址。修改b,不会影响a的值。
简单的说:primitive之间的赋值就是内容的拷贝,对象之间的赋值就是引用的拷贝。
二) 数据类型转化:
比int 小的数据类型会被提升到int,再进行运算,所以结果仍然是int.向下转化时,必须加类型转化,而且会丢失数据。
总之:运算过程中最大的类型,决定结果的类型。如 long && double result is double .
三) 其他:
在for循环中可以这样使用逗号运算符,也是唯一用到的地方
for (int i =0 , int j = 1; i< 10 && j < 20 ;i++,j++){
//todo
}
在一些多层的循环的时候,可以使用标签来实现break , continue
for ()
{
label 1:
for ()
{
break label1; //这样可以实现一定范围的跳转
}
}
虽然保留这goto 但是没有使用。
第四章:初始化及清理
一)构造函数的由来,为了初始化一些东西,但是又为了希望被调用,不被遗忘。C++ JAVA中都定义了这种方式。
二)方法的重载:有构造函数的重载以及方法的重载。overLoad的最大区别是参数的不同。因为只有这个才能区分。
例如返回参数的不同,在系统调用的时候,并不知道调的是哪个。所以返回类型不同不能成为overload的区分方式。
方法的范围范围不同,如设置为private public .亦不能成为overload的区别,在同一个类中,调用这个方法编译器也不能区分调用的是哪个方法。
三)每一个类都存在一个默认的构造函数。
四)常见关键字
4.1 this 关键字:对象本身的引用。
在我们定义了两个相同类的对象。使用 a.f1(1) b.f1(1).在底层为了区分到底是哪个调用了f1()方法,其实把该对象的引用也作为一个参数传递过去了。那两个方法的调用实际上是以 banana.f1(1,a) banana.f1(1,b).
用途: 1.明确使用类内部自身对象。它代表就是类本身reference
2.在一个构造函数中调用另一个构造函数。
3.在传入参数与类自身属性相同时,用来区分是实参还是形参。this.a = a
4.2 static关键字:简单的说static 修饰过的方法里面没有this,是一个类变量,类函数。在static 方法里面只能调用static 方法。因为是一个类函数或类变量,公用。故不能调用属于该类其他任何的非static函数或变量。非static 意味着可能被生成多个对象。
4.3 finalize:释放内存时调用的方法。简单的说:
4.3.1.对象不一定会被垃圾回收
4.3.2.垃圾回收不析构函数
4.3.3 垃圾回收只与内存有关。只有在内存耗尽的时候才会取调用。一般不会耗费资源去调用
调用方式:system.gc()
五)成员的初始化
对于类成员变量,会默认的初始值,但是对于局部变量则需要自己取初始化。
1. 指定初始化,在定义变量的时候就进行初始化
2. 在构造函数中进行初始化
初始化的顺序:
在一个函数的初始化函数中,包含new其他类,那么无论是在什么位置new这个类,都必先会先调用这个类的构造函数,然后才调用自己的构造函数。
例如如下:一个类在加载的时候会先加载属性,然后才加载构造函数
第五章 隐藏实现
一些常见的接口方法
第六章 类的复用
合成:在新的类里面使用旧的类,例如在A类中使用B类
继承:直接继承另一个类,来复用父类的代码
初始化一般有三种形式:
1.直接在定义的属性的时候初始化 int a = 9
2.在构造期里面开始构造
3.lazy initial 就是需要进行判断后再初始化
if (null == a ) a = 9;
基类的初始化:
子类在初始化的时候会先调用基类的初始化函数
子类在调用父类的初始化构造函数时,调用父类的构造函数必须在最前面。这样做是为了防止:在调用父类的过程中抛出异常,可以首先知道。而不必取构造子类。
合成还是继承:
面向对象最简单的使用就是把数据和方法封装成一个类,然后再使用这个类的对象。
是否用继承的时候,判断这个类是否能够上传,即子类是否可以当做父类来使用。少用继承,多用合成。
final 关键字:
可以修饰属性:使得这个属性不能指向另一个引用
方法:为使这个方法不能在子类中被覆盖
类 :为使这个类不能被继承。比如说JDK中的String类等
第七章:多态性
抽象类的出现。就是你不想实例化这个抽象类,但是提供一些公共的接口让子类来实现
有抽象方法的一定是抽象类。抽象类以一定有抽象方法.
比如说你想创建一个类,但是该类又不想被实例化,那么就可以采用这种方法。
第八章: 接口与内部类
接口:是进一步的强化了abstract的概念,接口中所有的方法都是abstract和static且final的。故需要进行初始化
接口中也可以嵌套接口
内部类:在一个类中嵌套另一个类。将逻辑上相互从属的类组织起来,并控制它的访问权限。
内部类的访问方式:
outer.inner c = new outer.inner()//这个是显示内部类的用法。
内部类的优点:每个内部类都可以独立的实现某个接口,因此内部类不会受“宿主类是否已经继承了别的实现”的约束。
简单的说接口是部分解决了多继承的问题,那么内部类完全解决了多继承的问题。
第九章:用异常来处理错误
9.1 Java的基本哲学:糟糕的代码根本就得不到执行
9.2 异常的优点:让错误代码处理显的更有条理。即集中在一个地方对异常进行处理。还是应该坚持自己的意见,对于程序流程的跳转。可以利用异常来控制。
9.3 对于异常有两种处理模式
1. 中止模式:temination.即抛出异常,中止程序继续执行
2. 继续模式:resumption.即跳过这个异常,继续执行。我们所用的操作系统一般采用的就是这种方式。
对于程序中,我们可以自己定义自己的异常。来控制程序的走向。
9.4 调试的时候我们可以采用 system.err来输出错误信息。采用system.out的话有可能会被重定向。就是在catch{}里面
catch(Exception e)
{
system.err.println("exception has happened");
}
9.5 异常链:即在捕捉到一个异常后,再抛出一个其他类型的异常。JDK1.4以后提供了一个cause的构造函数来处理这个事件。
initCause();具体使用的时候可以再仔细研究下。
9.7 标准的JAVA异常
throwable : 是error :编译时候错误或者是系统错误。对于这类错误我们一般是无能为力的。也不需要我们取扑捉。
exception :java标准的类库方法及自定义的异常方法,这类方法需要我们来处理。
finally块中的代码是一定会被程序执行的。所以在其中进行一些清理工作。对于一些内存以外的东西设置到原来状态的时候,如关闭一些输入流等
使用finally块的时候有可能造成异常的丢失。如下所表示:
public class ExceptionsTest
{
public void f() throws MyTestException
{
throw new MyTestException();
}
public void disPlay() throws MyTestException2
{
throw new MyTestException2();
}
public static void main(String[] args) throws MyTestException, MyTestException2
{
ExceptionsTest eTest = new ExceptionsTest();
try
{
eTest.f();
}finally
{
eTest.disPlay();
}
}
}
9.8 在构造函数中抛出异常
异常处理原则:
不知道如何处理的时候就不要捕捉它
1. 在何时的地方处理异常
2. 把问题解决了,然后重新调用那个引起问题的方法
3. 修正那个方法,然后绕过那个方法再继续下去
4. 把当前环节能做的事情全部做完,然后把异常抛到更高层
5 把当前环节能做的事情全部做完,然后抛另一个异常到更高层
6. 中止程序
7. 简化
8. 把类库和程序做的更安全
第十章:检测类型
RTTI:run-time type identification 运行时类别识别。
10.1在运行时候的类型信息是由class文件来确定的。JVM在创建一个对象的时候会检查是否加载了这个类的class对象,如果没有则取加载.class文件。
对象的产生: 一旦内存加载了这个CLASS对象,所有该类的对象都是由该对象来产生的。所以对于判断是否是一个对象的时候也可以采用这种方式来进行。
对象之间的检测:
1 利用对象类型的强转
2.利用 instanceof, isInstance() 两种方式 后者为动态判断是否为同一个类型,前者写法较丑陋。
CLASS提供了很多有用的方法:
类名.class.isInstance()
类名.class.isInstance()
SubEqual.class.isArray();
SubEqual.class.isInterface();
SubEqual.class.isPrimitive();
SubEqual.class.isLocalClass();
instanceof 与 class之间都可以用于比较对象之间的类型。但是有一个区别
class之间的比较只能是由通一个 类名.class文件产生的对象 才是true
instanceof如果是其本类或者是子类 返回的都是true
获得class的reference的两种方式 一种是class.forName() 这样就不需要取new一个这个类型的对象。
另一种是通过已经生成的对象 getClass()方法来获得class的引用。
总结:RTTI一般不常用,因为它只是多态的底层实现。只有在我们在多态的过程中,某个子类的反映特别的慢,可以考虑用RTTI来替代多态。这个属于程序的优化。
软件编程的习惯是:首先让程序跑起来,然后才考虑的是优化的问题。
第十一章:对象的集合
如果程序的对象数目是有限,且数目是可知的,那么这个程序是相当的简单
数组:
数组跟其他容器的最大区别在于:效率,类型识别,可以持有primitives.在随即存储和访问references的效率中是最高的。只是一个简单的序列。
但是缺点一样明显,在创建后,数目是固定的。后来JDK提供了一个ArrayList,但是在速度上慢了很多。
与C++中的数组相比较,效率上差点,因为JAVA中的数组还要一定的开销做数组的下表越界。C++就没,所以容易出错。
数组是第一流的对象
因为容器只能只能存放对象的reference。数组两者兼可,而且效率更高。
ARRAYS里面有几个有用的方法:
Equals:数目,每个元素都要相等
sort,fill,
binarySearch:一种效率很高的查询方式,对于未排序的数组使用这个方法没有什么意义。
system.arraycopy()方法能够更快的执行数组的拷贝。
三目运算符的双重用法:
public int compareTo(String arg0)
{
int j = Integer.valueOf(arg0);
return this.i < j ? -1 : ( this.i == j ? 0 : 1);//这里用的就是双重的三目,看起来很爽
}
为了使的数组或容器中能够进行排序,那么就需要实现comparator接口。
数组总结:arrays这个类主要是为数组服务的。collections主要是为容器服务的。
容器:对于list还有一个更技巧的迭代器:ListIterator 可以沿两边来查看集合。
容器的结构图:
主要部分已经用黑色框表示:
其中的abstratXX主要是用了适配器模式,如果我们要写自己的类话,那就不需要实现对应的接口,只需要继承抽象类就可以了。不要实现接口,并实现接口所有的类。
容器简介LIST
List:以一定顺序保存数据,,允许重复。可以制造ListIterator,对集合进行两边的访问。
ArrayList :用数组实现的LIST,能够进行快速的随即访问,但是在中间插入或删除数据比较慢。ListIterator只能用在反向遍历集合中,不要用来插入或删除数据,相比较LinkedList,在ArrayList中使用ListIterator的系统开销比LinkedLIST大。
LinkedList:对顺序访问进行了优化,插入删除数据的代价也不高,但是随即访问能力较慢能当做栈,队列,双向队列来使用,在一般情况下不推荐是这个。建议使用ArrayList。
SET :多态的完美实现。无序,不允许重复的。对于加入的object对象,需要覆盖equals方法。
HASHSET:为优化查询速度而设计的SET,放入的object必须实现hasshCode方法。底层就是hashMap来实现的。
TREESET:有血的SET,放入的对象必须实现compable接口,或者有一个比较器compartor
LINKEDHASHSET:内部是在链表实现的SET,即有HASHSET的速度,又能保存元素加入的顺序,用iterator遍历的时候是按照插入顺序来遍历的。
MAP:底层用hash算法实现,在容器中的查询速度比arrayList还快。
散列算法和hash算法。
HASHMAP的底层实现:
其实在底层就是一个数组,每个数组的位置叫做BUCKET,没一个bucket其实就是一个linkedList,插入的时候,首先根据KEY值算的hashcode,让后对数组的大小进行去模,如果得到的这个bucket位上没有任何数据,就new一个linkedList,并放入到其中,若是已经有,则比遍历真个list看是否存在相等,若是相等的就返回原来的值,并把新值存放在位置上,若是没有相等的,那么就把值加到linkedList的最后。
影响其性能的因素:
1.bucket数目,即数组的大小。
2.initial bucket数目:初始化大小,可以通过初始化构造函数来设定。默认情况是16个,
3.当前hash表的数目
4.load factor:加载因子,即在什么时候对这个数组进行扩展。如果你设定的比较大的话,可以考虑把load factor设定的大点,免得需要多次reflash。默认的加载因子是0.75.也就是75%。
hashcode的产生原则:就是一个对象放入和取出计算的hashcode值要求是一样的,不能因为对象某个值得改变而导致取出的值不一样。
LIST的选择:
上表是对于四种容器的性能测试:
GET:随即访问 ITERATOR:顺序访问 INSERT:插入 REMOVE:删除
从上表可以看出数组在随即访问速度是最快的,在数据的插入和删除最慢。但是奇怪的是ArrayList的顺序访问速度比数组要快。
ArrayList的优势在于性能的平衡性,随即访问和插入的速度都可以,可怕的是删除速度,毕竟底层实现还是数组。
LinkedList 的优势在于删除和插入,
Vector是线程安全的,可以不用考虑。
SET的选择:
总体来说:HashSet的性能要比treeSet好,尤其是在查询和插入时,TreeSet存在的意义在于维护一个有序序列。
LinkedHashSet的插入要比HashSet稍微慢点,那是因为它要维护链表和Hash容器的双重代价。也因为底层是链表的缘故,所以它的遍历是最快的。
在容量不是很大的情况下个人建议还是使用LinkedHashSet,比较好,在插入的时候代价并不是很高,但是遍历的速度确实很快。
MAP选择:
一般情况下使用hashmap就可以了.treeMap需要维护一个有序列表,所以要慢些。
总结:
发表评论
-
开源搜索框架笔记
2012-02-03 17:14 1265首推的当然时lucene了,先介绍这个吧 lucene ... -
head first 学习笔记 JSP&Servlet--8
2010-07-28 22:27 12031. 会话的销毁 1.1 设置会话的超时时间 ... -
head first 学习笔记 JSP&Servlet--7
2010-07-28 22:27 11667. 不同获得dispatch的方式 Reques ... -
head first 学习笔记 JSP&Servlet--6
2010-07-28 22:26 13081. 不是所有的类都需要实现序列化接口,在同一个JVM中,且未 ... -
head first 学习笔记 JSP&Servlet--5
2010-07-28 22:25 13334. 初始化参数 servletConfig: 获取方式: ... -
head first 学习笔记 JSP&Servlet--4
2010-07-28 22:25 1127response的输出返回有两 ... -
head first 学习笔记 JSP&Servlet--3
2010-07-28 22:24 15897.servlet中的幂等请求 get,head,p ... -
head first 学习笔记 JSP&Servlet--2
2010-07-28 22:23 12866.servletConfig 和ServletContext ... -
head first 学习笔记 JSP&Servlet--1
2010-07-28 22:23 11471. get 和post请求的区别 1.1 get请求的 ... -
穷爸爸富爸爸--5
2010-07-28 22:19 996第十章 还有一些需要做 ... -
穷爸爸富爸爸--4
2010-07-28 22:19 11705.首先支付自己:自律的力量 如果你不能控制自 ... -
穷爸爸富爸爸--3
2010-07-28 22:18 10774. 习惯 把每个月的收入首先支付给自己,因为 ... -
穷爸爸富爸爸--2
2010-07-28 22:17 1024第五章 财商由四封面组成 1. 会计 财务知识 ... -
穷爸爸富爸爸--1
2010-07-28 22:15 1096第一章: 1. 富人得到资 ... -
敏捷学习笔记--2
2010-07-28 22:11 104511. 测试人员是软件健康程度信息的提供者,不是质量保证者的想 ... -
敏捷学习笔记--1
2010-07-28 22:10 10102010年3月25日 星期四 09 ... -
effective java学习笔记--4
2010-07-28 22:08 11638.3 方法实现的小建议 ... -
effective java学习笔记--3
2010-07-28 22:08 1136第七条:改写equals尽量遵守的约定 7.1 ... -
effective java学习笔记--2
2010-07-28 22:07 967第四条:避免创建重复 ... -
effective java学习笔记--1
2010-07-28 22:06 988总共657条建议,每次把 ...
相关推荐
### Thinking In Java 学习笔记知识点总结 #### 面向对象编程(OOP)的重要性及其影响 面向对象编程(OOP)在软件开发领域产生了深远的影响。它不仅提高了开发效率和降低了维护成本,还简化了设计流程,使得编程任务...
《Thinking in Java》是一本深度解析Java编程语言的经典著作,其深入浅出的讲解和丰富的实例使得读者能够全面理解Java的精髓。以下是对书中部分关键知识点的总结: 1. **Java 泛型**:泛型是Java SE 5.0引入的重要...
### Thinking in Java 自学笔记——第二章 一切皆对象 #### 重要概念解析 ##### 2.1 用引用操纵对象 在Java中,一切都被视为对象,这意味着无论是字符串、数字还是其他数据类型都可以被视为对象来进行操作。当...
### Thinking in Java 读书笔记知识点总结 #### 一、万事万物皆对象 1. **对象存储位置** - **寄存器**:程序无法直接控制。 - **栈(Stack)**:存储基本类型数据和对象引用,但对象本身不在此处。 - **堆(Heap)...
该标签表明本章节的主要内容是关于 Java 编程语言的学习笔记。 部分内容: 1.1 抽象过程 抽象是编程语言的基本机制,它允许开发者定义和使用抽象类型,隐藏实现细节,提高代码的可维护性和可重用性。 1.2 每个...
《王者归来之Thinking in Java读书笔记》是对Bruce Eckel的经典之作《Thinking in Java》第四版的深度学习与总结。这本书是Java程序员的必备参考书,它深入浅出地阐述了Java语言的核心概念和技术,旨在帮助读者理解...
JAVA学习日记---Thinking in Java学习笔记 第5章总结 第五章 初始化与清理 5.1 用构造器确保初始化 1.构造器命名必须与类名相同 2.构造器也是方法,满足方法的各种特征,无参数的构造器称为默认构造器,默认构造...
《Thinking in Java》是Bruce Eckel的经典之作,它深入浅出地讲解了Java语言的核心概念和技术,对于初学者和有经验的开发者来说都是极好的学习资源。这篇读书笔记主要聚焦在第五部分的内容,可能涵盖了类、对象、...
这些只是《Thinking in Java》中的一部分内容,全书还包括类、接口、多态性、异常处理、集合框架、并发编程等多个主题,是Java学习者的宝贵资源。理解和掌握这些基础知识是成为一名熟练Java程序员的关键步骤。
通过以上概述,《Thinking In Java》第一章深入浅出地讲解了Java的基础概念,涵盖了面向对象编程的核心原则、数据的存储与管理、基本类型与包装类的使用,以及高精度数字的处理技巧,为初学者和进阶学习者提供了宝贵...
我的学习笔记的书本课程来自于:《Thinking in Java》和《Head First Java》 视频课程主要来自于:廖雪峰老师《Java 基础课程》 如涉及版权侵犯请联系我更正。 初来乍到,文笔稚嫩,学识浅薄,请多指教。
在IT领域,特别是Java编程的学习过程中,"JAVA夜未眠,thinkingJAVA和学习笔记"这一主题涵盖了许多核心概念和实践技巧。以下是对这些资源的详细解释: 首先,"Java夜未眠"可能指的是一个深入探讨Java编程的书籍或...
《中文版Thinking in Java 4th编程思想》是学习Java编程的重要参考资料,它深入浅出地介绍了面向对象编程的核心概念。下面将详细解读其中的主要知识点。 1. **对象导论** - **万物皆对象**:Java编程的核心是对象...
总之,《Thinking in Java》的读书笔记结合了广泛的Java知识和实践应用,从基础知识到高级主题,从理论到实践,为学习和提升Java编程技能提供了全面的资源。无论是对初学者还是经验丰富的开发者,这都是一个宝贵的...
其次,"Thinking in Java"的资源可能包括了课后练习、习题解答、代码注释或者其他辅助学习材料。这些资源对于自学Java的人来说极其宝贵,它们可以帮助检验学习效果,解决遇到的问题,并提供额外的实践机会。通过完成...
**Java JDK 6.0 学习笔记** Java JDK(Java Development Kit)是Java编程语言的核心组件,包含Java运行环境、编译器、类库以及各种工具,是开发者进行Java程序开发的基础。Java JDK 6.0是Oracle公司发布的一个重要...
Java》学习笔记 [TOC] 阅读计划 章节列表 对象导论 一切都是对象 操作符 控制执行流程 初始化与清理 访问权限控制 复用类 多态 接口 内部类 持有对象 通过异常处理错误 字符串 类型信息 泛型 数组 容器深入研究 Java...
6. **Java学习笔记.doc**: 这可能是个人或教师的教学笔记,可能包含学习心得、重点难点解析,对学习者来说是宝贵的参考资料。 7. **2011最新整理Java练习题.doc**: 提供了最新的练习题目,反映了当时Java技术的发展...