- 浏览: 461434 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
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 995第十章 还有一些需要做 ... -
穷爸爸富爸爸--4
2010-07-28 22:19 11685.首先支付自己:自律的力量 如果你不能控制自 ... -
穷爸爸富爸爸--3
2010-07-28 22:18 10774. 习惯 把每个月的收入首先支付给自己,因为 ... -
穷爸爸富爸爸--2
2010-07-28 22:17 1023第五章 财商由四封面组成 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 987总共657条建议,每次把 ...
相关推荐
白色大气风格的旅游酒店企业网站模板.zip
python实现用户注册
Matlab领域上传的视频均有对应的完整代码,皆可运行,亲测可用,适合小白; 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作
内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;
内容概要:文档名为《平方表,派表集合.docx》,主要内容是1至1000的平方值以及1至1000与π的乘积结果。每个数字从1开始,逐步增加至1000,对应地计算了平方值和乘以π后的值。所有计算均通过Python脚本完成,并在文档中列出了详细的计算结果。 适合人群:需要进行数学计算或程序验证的学生、教师和研究人员。 使用场景及目标:用于快速查找特定数字的平方值或其与π的乘积,适用于教学、科研及程序测试等场景。 阅读建议:可以直接查阅所需的具体数值,无需从头到尾逐行阅读。建议在使用时配合相应的计算工具,以验证和拓展数据的应用范围。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;
白色大气风格的健身私人教练模板下载.zip
白色简洁风的商务网站模板下载.zip
白色大气风格的前端设计案例展示模板.zip
内容概要:本文介绍了两个有趣的圣诞树项目方向:一是使用Arduino或Raspberry Pi开发可编程的圣诞树灯光控制系统;二是基于MATLAB开发一个圣诞树模拟器。前者通过硬件连接、编写Arduino/Raspberry Pi程序、MATLAB控制程序来实现LED灯带的闪烁;后者则通过创建圣诞树图形、添加动画效果、用户交互功能来实现虚拟的圣诞树效果。 适合人群:具备基本电子工程和编程基础的爱好者和学生。 使用场景及目标:①通过硬件和MATLAB的结合,实现实际的圣诞树灯光控制系统;②通过MATLAB模拟器,实现一个有趣的圣诞树动画展示。 阅读建议:读者可以根据自己的兴趣选择合适的项目方向,并按照步骤进行动手实践,加深对硬件编程和MATLAB编程的理解。
白色扁平风格的温室大棚公司企业网站源码下载.zip
Navicat.zip
内容概要:本文详细介绍了主成分分析(PCA)技术的原理及其在Scikit-learn库中的Python实现。首先讲解了PCA的基本概念和作用,接着通过具体示例展示了如何使用Scikit-learn进行PCA降维。内容涵盖了数据准备、模型训练、数据降维、逆转换数据等步骤,并通过可视化和实际应用案例展示了PCA的效果。最后讨论了PCA的局限性和参数调整方法。 适合人群:数据科学家、机器学习工程师、数据分析从业者及科研人员。 使用场景及目标:适用于高维数据处理,特别是在需要降维以简化数据结构、提高模型性能的场景中。具体目标包括减少计算复杂度、提高数据可视化效果和改进模型训练速度。 其他说明:本文不仅提供了详细的代码示例,还讨论了PCA在手写数字识别和机器学习模型中的应用。通过比较原始数据和降维后数据的模型性能,读者可以更好地理解PCA的影响。
VOC格式的数据集转COCO格式数据集 VOC格式的数据集转YOLO格式数据集。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
数字信号处理课程设计.doc
白色扁平化风格的灯饰灯具销售企业网站模板.zip
华豫佰佳组合促销视图.sql
白色大气风格的商务团队公司模板下载.zip
白色大气风格的VPS销售网站模板.zip