这篇是大一的时候看ThinkInJava的时候随后记录的笔记,感觉还是那么熟悉!
局部变量存放在内存的栈里面,
内存分为四块:code segment 存放代码;data segment 存放静态变量 和字符串常量;stack 存放局部变量;heap 存放new出来的东西;
面向对象: 合适的方法应该出现在合适的类里!
1.遇到问题时,先抽象出来各个对象,以及各对象之间的关系!
2.对于一个类,是有静态属性和动态属性的!静态属性即为成员变量,动态属性即为方法!深刻理解!
3.类(对象)之间的关系之关联关系:往往是一个方法里的参数是另一个类的对象!
4.继承关系:XX是一种XX;
5.聚合关系:XX是XX的一部分!
聚合又分为聚集和组合,聚集:关系不是很紧密;组合:关系非常紧密!
7.实现关系:子类通过实现接口来实现自己的动作!
6.面向对象考虑问题过程:首先,在这个问题中有多少个类多少对象;然后,考虑这些类这些对象应该有哪些属性哪些方法:最后,考虑类与类之间有什么关系!
8.必须先定义类再定义对象!
9.对象是JAVA语言的核心!可以看做是静态属性(成员变量)和动态属性(方法)的封装体;
10.所谓静态属性,就是类中各个对象都应该具备但是又应该以此作为区别各个对象的标准的属性!深刻理解!
11.JAVA里面,除了基本类型以外,所有类型都是引用类型!
基本类型只占一块内存,引用类型占两块内存,栈和堆,栈中存放引用的地址,地址指向堆,堆中存放真正的new出来的东西!堆是动态分配内存的,类是静态概念,位于代码区!类的每个成员变量在不同的对象中都有不同的值(除了静态变量)而方法只有一个,执行的时候才占用内存!
12.对象的创建与引用!
对象(引用)有属于自己的成员变量。对象共享该类的方法!
13.stack是栈,用来存放引用!heap是堆,用来存放new出来的东西!可以理解为对象的实体!该实体含有类的属性,包括方法和成员变量!
14.构建一个新对象的时候用构造方法!使用new+构造方法 创建一个新的对象!
15.方法中的变量也存放在栈中,当方法调用完毕时,编译器自动释放栈空间!当调用方法时,传递进来的参数先在栈中存放,再由栈中的引用把值传给堆并最终保存起来!任何局部变量都会存放在栈里面!
16.当构造方法没有人工指定时,编译器自动生成一个空的构造方法!
17.分析程序时,从main方法的第一句来开始!
18.原来,基础变量只占一块内存,存放在栈里!不是堆里!
19.垃圾回收机的原理:检测一个对象,当没有任何一个引用指向这个对象时,垃圾回收机就释放这块内存!
20.不同的对象调用方法时,方法的作用域是不同的!因为各个对象在堆中的属性地址是不一样的!所以方法以地址为导向!
21.方法的返回值也是暂时存储在栈空间里,当方法调用完毕时,有垃圾回收机释放!
22.方法重载,当方法名相同但是返回类型不一致时,会发生方法重名,这现象在编译时就会报错!
23.是否构成重载关键看编译器在调用这两个方法时是否能够根据参数列表来区分调用哪个方法!
24.切记,构造方法也可以重载!
25.同一个类的对象共享该类的方法!非静态方法针对每个变量进行调用!
26.方法只是一段代码,所以应该保存在code segment中!当对象调用时,系统才为该方法及其参数分配各个内存中的存储空间,堆,栈都有可能!
27.打印语句中如果包含方法返回值时,在打印语句输出完毕以后方法返回值在栈中的存储空间被释放!
28.字符串常量存储在data segment区域!
29.当涉及一个方法的创建时,考虑三个问题:方法的名字,方法的参数,方法的返回值!
30.this 关键字,出现在类的方法定义中! this表示调用当前方法的对象的引用!注意,是引用!
31.用this 来处理方法中成员变量和参数重名的现象!
32.关于初始化:
1.假设有个名为dog的类。
2.当首次创建类型为dog的对象时(构造器可以看做是静态方法),或者dog类的静态方法/静态字段首次被访问时,java解释器以定位dog。class文件。
3.然后载入Dog.class文件(这里将创建一个Class对象,貌似与getClass方法有关!),有关静态初始化的所有动作都会执行,因此,静态初始化只在Class对象首次加载的时候进行一次。
4.当用new Dog()创建对象的时候,首先将在堆上位为Dog对象分配足够的存储空间,
5.这块存储空间会被清零,这就自动地将dog对象中的所有基本类型数据都设置成了缺省值,(对数字来说就是0,对布尔和字符也相同)对于引用则被设置成null。
6.执行所有出现于字段定义处的初始化动作。
7.执行构造器,正如将在第六章所看到的,这可能这可能会涉及到很多动作,尤其涉及到继承的时候。
33.对于static 变量,对对象来说只有一份,每个对象共享。
存放在data segment区域中!
34.可以把static变量放在构造方法里用作计数器!
35.成员变量伴随着对象的产生才产生于内存的堆中!
36.main方法是静态方法,对于非静态的成员变量,必须借助对象的调用才能在main方法里访问!这就是常说的“不能再静态方法里访问非静态变量!”同样也不能在main方法里直接访问非静态方法,对于非静态方法和变量,必须借助对象的引用才能访问出来!
37.静态方法不再是针对某个对象的引用,所以不能访问非静态成员变量!
38.注意,静态方法和变量均可以被类名和对象调用!
39.包名的命名,把公司的域名倒过来!
40.继承的内存关系:每一个子类对象中包含一个父类对象,(在堆中)
41.子类继承父类的时候,继承父类的所有成员变量和方法,包括private变量,但是仅仅是拥有该类型变量的拥有权,却无使用权!
42.方法重写:在子类中可以根据需要对从基类中继承来的方法进行重写;重写方法必须和原方法有相同的方法名,返回类型,参数列表;重写方法不能使用比被重写方法更严格的访问控制!
43.方法的重写是一种方法的拓展!
44.注意重写方法时,尽量去复制父类中的方法声明,因为一旦重写时写成了错的方法,调用时只会调用父类中的方法,不会编译错误!切记切记!
45.在new对象的时候,this指向对象本身,super指向这个对象所包含的父类对象的引用!
46.继承中的构造方法:子类的构造方法的过程中必须调用其基类的构造方法。
47.子类可以在自己的构造方法中使用super(argument list)调用基类的构造方法:使用this+参数列表 调用本类的另外的构造方法。
48.如果调用super,必须写子类构造方法的第一行。
49.如果子类的构造方法中没有显示地调用基类构造方法,则系统默认调用基类无参数的构造方法。
50.如果子类构造方法中既没有显式地调用基类构造方法,则编译器自动加载父类的无参构造函数,如果父类没有构造函数,则编译器自动生成一个,从而保证编译的通过,若父类有一个有参的构造方法,则编译器不再提供无参构造函数,此时编译出错!
51.如果在类的声明中未使用extends关键字指明基类,则默认基类为object类。
52.toString方法是object类中的!返回类型为字符串,当进行String与其他类型数据的链接操作时,将自动调用toString方法。可以根据需要在用户自定义类型中重写toString方法!
53.Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:
getClass().getName() + '@' + Integer.toHexString(hashCode())
54.toString方法在想直接输出对象信息时调用,默认的实现形式是输出类名+@+对象的哈希码。所以要想输出有价值的能读懂的信息,必须在子类中重写此方法!
55.Object类之equals方法,该方法是继承自object类,所以实现时需要重写!通常有必要重写hascCode方法!以维护哈希规范,该协议声明相等对象必须具有相等的哈希码!
56.equals方法在object类下的实现方法就是比较两个引用是否指向同一个对象,即A==B时,即当把B的引用赋值给A时才返回true.
57.对象转型:1 一个基类的引用类型变量可以“指向”子类对象。2 一个基类的引用不可以访问其子类对象新增加的成员。3 可以使用instanceof 类名来判断该引用型变量所指向的对象是否属于该类或该类的子类。4 子类的对象可以当做基类的对象来使用称作向上转型(upcasting) 反之称为向下转型(downcasting)
58.注意,instanceof关键字是判断当前引用是否指向该类或该类的子类,只要满足其中一个则返回true
59.对象转型的第二个应用:把父类对象作为参数传递进方法,同样可以把该父类的子类对象也传进去,然后用instanceof来检索进来的这个对象具体是指向那个类的。然后把该对象强制转换成该类对象,然后再用if语句来具体执行属于该具体类的相关方法!
60.在父类引用指向子类对象的时候,如果该父类引用调用了一个方法,且这个方法在各个子类中都有重写,则具体调用哪个类的方法则由该父类对象最终实际指向的对象的类决定,也称为:动态绑定!多态,迟绑定!
61.利用这种动态绑定机制使程序的可拓展性发展到最好!
62.所谓动态绑定是指在“执行期间”非编译期间,判断所引用对象的实际类型,根据其实际类型调用相应的方法!
63多态存在的3个条件:要有继承,要有重写,要有父类引用指向子类对象!
64.当一个类包含抽象方法时,这个类必须被声明为抽象类!
65.当继承该类时,必须要实现该方法!
66.抽象类必须被继承,抽象方法必须被重写!
67.注意,抽象方法声明时要加分号!
68.final的变量不能被改变。final的方法不能被重写,final的类不能被继承!final起到一个锁定的作用!
69.接口interface是抽象方法和常量值的定义的集合!从本质上讲,接口是一种特殊的抽象类,这种抽象类只包含常量和方法的定义,而没有变量和方法的实现!
70.接口支持多继承,接口中的属性默认为public static final 的,也只能是public static final的!接口可以继承,添加新的属性和抽象方法!而且方法只能是public的!
71.多个无关的类可以实现同一个接口!一个类可以试想多个无关的接口!与继承关系类似,接口与实现之间存在多态性!
72.访问权限的控制常被称为隐藏具体实现,把数据和方法包装进类中,以及具体实现的隐藏,常共同被称作是“封装”,其结果是一个同时带有特征和行为的数据类型!
73.类的权限只有包权限和public,要想该类的对象不能在其他类中被创建,则只需把该类的构造定义为private,这种情况内部类除外!
74.当想要为把构造方法设置为private的类创建对象时有如下方法:1.创建一个static方法 返回类型为该类的对象,然后实际返回new 类名+构造;2 用private static 创建一个对象,然后创建一个static方法 返回该对象的一个引用!需要对象时就直接用该方法调用引用来实现!
75.奇妙问题,当一个类实现了两个接口,这两个接口中有同样方法名的两个方法,则在类中具体实现这两个方法时是不会出错的!
Eclipse除外!貌似Eclipse不允许同名的方法出现!
76.private 和final的类不能被继承!但是只有内部类能被private修饰!
77.异常处理,观察错误的名字和行号最重要!程序是调出来的
!
78.当捕获异常后,通常的处理方式是e.printStackTrace();这是打印出错误的堆栈信息,堆栈信息对调试程序很有帮助!
79.java的程序执行过程中如出现异常事件,可以生成一个异常类对象,该异常类对象封装了异常事件的信息并将被提交给java运行时系统,这个过程成为抛出(throw)。
80.当java运行时系统接收到异常对象时,会寻找能处理这一异常的代码,并把该对象交给其处理,这一过程称为捕获(catch)。
81.对于异常,分为error和exception,error不可处理,属于系统错误,exception可以被处理,又分为runtimeexception与必须捕获的异常,对于runtimeexception可以不捕获,但是另外一种必须捕获!
82.注意一个try可以抛出多个异常,对应的,多个catch与一个try配套使用!
83.try语句,指定了一段代码,该代码就是一次捕获并处理例外的范围,在执行的过程中,该代码可能会产生并抛出一种或几种异常的对象,try后面的catch负责分别处理这些异常,如果没有例外产生,所以得catch代码都被跳过!
84.catch就是对异常进行处理的代码,在catch中声明的对象,封装了异常事件发生的信息,在catch语句块中可以使用这些信息!如getMessage(),用来得到有关异常事件的信息,printStaceTrace()方法用来跟踪异常事件发生时执行堆栈的内容!
85.finall语句,为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分以前,能够对程序的状态作统一的管理。
86.无论try指定的程序块中是否有抛出例外,finally所指定的代码都要被执行。
87.通常在finally语句中可以进行资源的清除工作,如:关闭打开的文件,删除临时的文件!
88.捕获异常以后一定要作出处理,比如getMessage,printStackTrace等!
89.当捕获的异常不想处理时,可以在main方法里抛出去,交给java运行时系统,但是这是很不好的编程习惯,杜绝!
文明的处理方式就是写try---catch方法!
90.throws关键字的用途就是抛出异常,以等待一个try---catch组合来捕获并处理!由catch内的资料来处理。
91.捕获异常的时候先捕获小的,再捕获大的!
92.自定义异常,通过继承java.lang.Exception类声明自己的异常类;在方法的适当的位置生成自定义异常的实例,并用throw语句抛出;在方法的声明部分用throws语句声明该方法可能抛出的异常!
93.注意throw在方法内部使用来抛出,throws在方法声明时使用来抛出!
94.继承中的异常问题,重写方法需要抛出与原方法所抛出异常类型一致异常或不抛出异常。
95.数组:c\c++中的数组允许分配在栈上,而java是引用类型!
96.数组里装的都是引用!java里声明数组时不能指定数组的长度:int a [] 是错误的!
97.当仅仅声明数组时,内存中只是在栈上创建一个数组里面放着null的初始引用!当用new关键字来初始化数组时,内存中堆上划分出一个与数组长度一致的区域!里面的数据已经被初始化!初始化规则与成员变量的规则一致!然后栈中的引用根据数组下标分别指向这些在堆中的具体数组值!
98.数组初始化分为静态初始化和动态初始化。动态初始化就是数组定义与为数组分配空间和赋值操作分开进行!
99.当程序涉及到输入输出时,判断一下,以防出现错误,这样的程序设计友好!当然要先把程序的主体流程涉及好!
100.当必须亲自处理垃圾时,就要多加小心了,因为一旦涉及垃圾回收,能够信赖的事就不多了!垃圾回收器可能永远不会被调用,即使被调用,它可能以任何它想要的顺序回收对象,最好的方法,是除了内存外,不要依赖垃圾回收器做任何事,如果需要进行清理,最好是编写好你自己的清理方法,但不要依赖finalized().
101.对象型的成员变量,可以被该类的对象调用,在由这个被调用类调用属于它自己的方法!很另类!
102.(is-a)用来表示继承关系,(has-a)用来表示组合关系!
103.如果将项目视作一种有机的,进化着的生命体去培养,而不是像打算盖摩天大楼一样快速见效,就会获得更多的成功和更迅速的回馈!
104.final型数据并不是在编译时就知道数值,若把它定义为随机数就不可知了,final static型量在编译器首次装在它时就已确定,不可再变。
105.带有初始值的final static基本类型全用大写字母命名,而且字与字间用下划线隔开。
106.final对基本数据类型仅仅是使值不变。final对引用的作用为一旦引用被初始化指向一个对象,就无法再改变这个引用指向的对象,但是可以改变实际对象的值!
107.空白final java允许使用final定义空成员变量,和引用,但该类变量必须在构造中北初始化。
108.参数列表,在参数列表中把类型设为final可以锁定该参数的引用不变。即不能更改,即只能被一个对象调用一个!这是一种安全策略。
109.final方法,把方法定义为final型目的:1.锁定方法,以防任何继承类修改它的定义,处于设计的考虑,来确保在继承中使方法行为保持不变且不会被覆盖。2.效率:统一编译器对该方法的所有调用都转为内嵌调用!
110.方法的返回值可以是数组!因为数组是引用类型,对象类型也是引用类型!
111.理解数组中的引用:数组名是一个变量,存在栈里,然后该引用指向堆中的空间,该空间被分为好多小格,长度为数组长度,然后该空间中的每个小格又指向堆中具体的对象!如是而已!
112.
110.private 与final:类内所有的private方法都隐式地被指定为final,由于无法去用private方法,所以就无法覆盖它!
111.覆盖只有在方法是基类的接口的一部分时才会实现,即必须能将一个对象向上转型为它的基本类型,并调用相同的方法,如果某方法为private它就不是基本接口的一部分,它仅仅是一些隐藏于类中的程序代码,只不过是具有相同名称而已,但若在导出类中以相同名称生成一个public,protected或包访问权限的话,该方法就不会与基类方法形成覆盖,仅是到处类的一个方法而已,由于private方法无法触及而且能有效隐藏,所以除了把它看成是因为它所归属的类的组织饥饿结构的原因而存在外,其他任何事物都不要考虑它。
112.final类:final类不允许别人这样做,换句话说出于某种考虑,该类不需要任何变动,出于安全考虑,你不希望它有子类,final类中所有方法都隐式地指定为是final的,因为无法覆盖它们!
113.面向对象思想中,问题域里的名词一般为类,动词为方法,宾语为参数列表!
114.注意,搜索往往是建立在排序的基础上!
115.排序算法:选择排序法!利用两层for循环遍历数组!注意,第一层I 次二层J=I+1;定义一个temp,当发现I>J时,先把I赋值给temp,再把J赋值给I,再把temp赋值给J如是而已!
116.冒泡排序法:仍然是两层for循环,注意,第一层中I定义为数组的最后一个值,然后I--,第二层中J从0开始++,当发现j>j+1时,就把j赋值给temp,把j+1赋值给j,把temp赋值给j+1;如是而已!
117.四维数组在3D的图形转换里是有用的!
118.java里数组的声明顺序是从左到右的(从高维到低维)
119.数组初始化分为静态和动态,静态初始化多数组时不能指定[]内的数字!java自动根据大括号后的内容予以初始化!
120.java里面的多维数组是数组中的数组! 比如:int a [] [] = new int [2] [3];里面的a.length 就是第一维的长度!
121.String型数组里存放的都是String的引用!初始都为null,随着new来在堆中创建对象!
122.数组在内存中的区域往往都是连续的!所以当需要把数组中的数据拷贝出来时!直接用方法System.arraycopy就行!有四个参数,第一个是开始数组名,第二个是数组的开始位置,第三个是目标数组名,第四个是目标数组的开始位置,最后一个是复制开始数组的长度,类似方法在C里叫memory copy。
123.当完成数组的复制以后!两个数组真正指向的是内存中的相同内容!因为复制操作时造作的引用! 当对一个数组的内容进行更改之后,另一个数组也同步更改!
124.当抽象方法在已经被覆盖的方法中调用时,由于抽象方法无方法体,所以会调用导出类中的被覆盖的方法。构造方法自动属于static型!
125.初始化顺序:1.在其他任何事发生前将分配给对象的存储空间初始化成二进制的0。
2.先调用积累的构造器,若该构造器中有抽象方法,则调用该构造方法的被覆盖方法,然后再调用导出类的构造方法。
126.编写构造器时有一条有效的准则,用尽可能简单的方法使对象进入正常状态,如果可以的话,避免调用其他方法,在构造器中唯一能够完全调用的方法使基类中的final方法(也适用于private)它们自动属于final型!
127.在不知道类与类具体的结合方式时,首选组合!因为继承是一个严谨的体系!
128.用继承表达行为间的差异,用字段表示状态上的变化。即通过继承得到不同的类,这样就有了被覆盖的不同的基类方法,即行为,用类(字段)或代码块来操纵引用来改变状态,如改变一个对象的引用!
129.基类引用指向导出类对象就是一种向上转型,这样,基类可以接收发送给导出类的任何信息,因为继承使它们拥有完全相同的接口(成员变量和方法),我们只要向上转型自然就会执行导出类的相关方法,这是多态的灵活之处。
130.向上转型会使对象丢失在导出类中拓展出来的方法,因此有向下转型,向上转型是安全的,但向下转型不安全。在c++中我们必须执行一个操作来获得安全的向下转型,但java中,所有的转型都会得到检查,这种检查叫做运行时检查(RTTI)若向下转型不正确,则返回一个ClassCastException。
131.这里的转型成功是指导出类的引用被正确地指向导出类对象,而该对象初始是指向基类的。
132.为了在自己的程序中有效地运用多态乃至面向对象技术,必须拓展自己的编程视野,使其不仅包括个别类的成员和消息,而且还要包括类与类之间的共同特征,及它们之间的关系,尽管这需要极大的努力,但是这样做是非常值得的,因为它可以带来很多成效:更快的程序开发过程,更好的代码组织,更好的拓展性!
133.接口:接口用来建立类与类之间的协议!interface中的方法隐式地维public,所以具体实现时也只能是public,否则会导致该方法的访问权限被降低,所以java不允许!
134.equals方法使object提供的,在java.lang中已经被重写,重写内容为比较两个字符串的实际值!所以在String中调用equals方法时,不必再手动重写!
135.String s1 = "java";
String s2 = "java";
String s3 = "sun";
System.out.println(s1 == s2);
如上所示,输出结果为true,因为s1 s2不是new出来的,只是字符串常量,存放在data segment区域中! 编译器对该区域中的变量有个优化,当生成s2时,由于已经存放了 与s2一样的值,所以编译器就直接把s2 的引用指向s1,所以就比较出同样的结果!
136.String s1 = "java";
String s2 = "java";
String s3 = new String("sun");
String s4 = new String("sun");
System.out.println(s1 == s2);
System.out.println(s3 == s4);
System.out.println(s3.equals(s4));
如上所示,输出结果为TRUE,false ,true。 因为s3,s4都是new出来的,所以编译器保存在heap中,分别分配内存!当比较引用时当然不一样,由于equals方法在java.lang中被覆盖,所以第三个结果为true。
136.s4.length()返回的是字符串的长度,单位为字符,不是字节!
137.
String s7 = "sun java";
String s8 = " Sun Java ";
System.out.println(s7.charAt(4));
System.out.println(s7.equals(s8));
System.out.println(s7.equalsIgnoreCase(s8));
System.out.println(s7.replace('s', 'A'));
System.out.println(s7.isEmpty());
System.out.println(s7.indexOf("java"));
System.out.println(s7.startsWith("sun"));
System.out.println(s7.endsWith("java"));
System.out.println(s7.toUpperCase());
System.out.println(s7.toLowerCase());
System.out.println(s8.trim());
String s9 = s7.substring(4,8);
System.out.println(s9);
注意substring方法是左开右闭的!
138.String.valueOf(...)可以把基本类型转换成字符串,也可以把对象转换成字符串,这里存在多态,因为它调用的对象的toString方法,而又存在对象转型!
139.多态是面向对象的最核心部分!
140.无论是将对象向上转型为普通类,抽象类,接口,都不会有问题,它们的行为是相同的,注意,可以向上转型为接口,并调用接口中的方法,不过实际调用的应该是该接口方法的具体实现方法!
141.使用接口的核心原因:为了能够向上转型为多个类型,然而使用接口的第二个原因却是与使用抽象基类相同:防止客户端程序员创建该类的对象,并确保这仅仅是建立的一个接口。
142.既然接口带来了抽象类的好处,并且还带来了使用接口的好处,所以如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类,事实上,如果知道某事物应该成为一个基类,那么首选它成为一个接口,只要强制你必须要有成员变量和方法定义时,才应该改而选择抽象类或者在必要时使其成为一个具体基类!
143.重载的方法可以通过参数列表,返回值来区分,但重写的方法必须完全一致!
144.通过继承可以很容易的在接口中添加新的方法声明,还可以通过继承在新接口中组合数个接口。
145.注意:extends 继承类时只能有一个, 但extends 继承接口时,可以是多个,仅需用逗号把接口名间隔开!
146.java.lang.StringBuffer 代表可变的字符序列!
147.StringBuffer和String类相似,但StringBuffer可以对其字符串进行改变!
148.StringBuffer类的常见构造方法:
1.StringBuffer():创建一个不包含字符序列的“空”的StringBuffer对象。
2.StringBuffer(String str):创建一个Stringbuffer对象,包含与String对象str相同的字符序列!
149.注意:StringBuffer中的reverse,append方法可以用在机器人中!
150.String不可变,Stringbuffer可变!区别在于内存中!比如:同样是合并字符!在String中必须开辟另外一块内存!来存放用于合并的几个字符串的和然后再把引用返回出去! 但是同样的工作在Stringbuffer中!只需直接在目标的内存中更改即可!这也就是可变与不可变的区别!注意!注意!
151.基础数据类型都是分配在栈上!若想把它们存储在堆上就需要基础类型的包装类来包装一下基础类型!
152.注意:包装类中的System.out.println(Integer.toBinaryString(123)+" B"); 用途可以用于机器人的加密解密! 先把用户输入的密码转换成二进制,再用于其它迷惑!
153.调试程序的时候打印一些消息对调试程序很有帮助!
154.注意二维数组的初始化!动态初始化时可以:double[][] d ;这样来声明,初始化第一维长度时:d = new double[3][] 注意要加两个中括号!初始化第二维长度时d[i] = new double[4];注意!
155.Math类:java.lang.Math提供了一系列静态方法用于科学计算;其方法的参数和返回值类型一般为double,也就是说,一般调用math方法时需要类型转换!
1.abs 绝对值。
2.acos,asin,atan,cos,sin,tan
3.sqrt 平方根
4.pow(double a,double b) a的b次幂
5.log 自然对数
6.exp e为底的指数
7.max(double a,double b)
8.min(double a,double b)
9.random()返回0.0到1.0的随机数
10.long round(double a)double型的数据a转换为long型(四舍五入)
11.toDegress(double angrad)弧度-》角度
12.toRadians(double angdeg)角度-》弧度
156.计算机文件系统记载文件修改时间都是以毫秒为单位的一个long型数值!该数值表示从上次文件被修改到现在经历的毫秒数!
157.反斜杠\在java里是一个转义字符,所以在java里用\\来表示 一个\。而在linux下都是以正斜杠/来划分文件目录的,windows也支持这种写法!所以/是windows和Linux下共同兼容的!
158.注意:用File类寻找文件的目录时,当该文件是位于一个包中,这时找出来的目录是包上一层的目录!
159.常用接口来创建常量组:public interface Math { int JANUARY = 1;} 调用时只需Math.JANUARY即可,注意:不可变的常量名全部大写,用_来间隔单词。
160.接口可以嵌套,接口内部的接口不能被定义为private,但被继承的接口允许。 实现一个private接口,只是一种方式,它可以强制接口中的方法定义不能添加任何类信息(不能向上转型)。
161.内部类:如果想在外部类的非静态方法之外的任何位置创建某个内部类的对象,那么必须像在main方法中那样具体的指明这个对象的类型:OutClassName.InnerClassName
162.可以把内部类向上转型为接口,来隐藏大量内部类中的具体实现。但private的InnerClass只能通过在它的包含类中,用一个能返回它的引用的方法,然后用该包含类的一个对象来调用这个方法的方式来把内部类的引用传递出来!
163.作用域可以理解为代码块,即{}之间的部分!
164.内部类不仅可以放在类作用域中,也可以放在方法作用域或任意的代码块中。这样做有两个理由:1.你实现了某类型的接口,于是可以创建并返回对其的引用。
2.你要解决一个复杂的问题,想要创建一个类来辅助你的解决方案, 但又不希望这个类是公共可用的。
165.内部类貌似是用来隐藏具体实现的!
166.内部类的几种用途:1.一个定义在方法中的类;2.一个定义在方法的作用域中的类;3.一个实现了接口的匿名类;4.一个匿名类,它扩展了有非缺省类型的构造器的类;5.一个匿名类,它执行字段初始化;6.一个匿名类,它通过实例初始化来实现构造器。
167.当内部类被创建在方法的作用域中时,只可以在该方法的作用域中创建它的对象。
168.也许大括号后跟分号的情况1.abstract方法后;2.匿名内部类后。
169.定义匿名内部类:public classic A {
public B cont() {
return new B () {
private interface id = 11;
public int value () { return id } 上面实际表示创建一个继承自B的类的对象,通过new 表达式返回的引用被自动转型为B。
170.如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用时final 的,如果忘记,将会得到一个编译时的错误消息。
171.如果想为匿名内部类添加构造动作,可以利用基类的构造器(基类为抽象类)(个人看法)
172.实力初始化内部类貌似字段的初始化,没感觉!内部类拥有其外部类所有元素的访问权。
173.内部类对外围类的访问权限如何做到:当某个外围类对象创建某个内部类对象时,此内部类对象必须保存一个指向那个外围类对象的引用,然后在你访问外围类成员时就是用那个隐藏的引用!
174.内部类声明为static时不会生产指向外围类的隐藏引用,这种内部类叫做嵌套类。
175.嵌套类表示:1.要创建嵌套类的对象并不需要其外围类的对象;2.不能从嵌套类中访问非静态的外围类对象;3.普通内部类的字段与方法只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类,但嵌套类可以。
176.在一个普通的非static内部类中,通过一个特殊的this引用,可以连接到其外围类对象,嵌套类就没有这个引用,因此它更像一个static方法!
177.正常情况下,不能在接口内部放置任何代码,但嵌套类可以所谓接口的一部分,因为类是static的,只是将嵌套类置于接口的命名空间内,并不违反接口机制。
178.可以用嵌套类来放置测试代码!从而不必写出main方法!
179.在外围类中创建内部类对象时必须先创建外围类对象,然后用该对象调用相关方法来创建内部类对象,因为创建内部类对象时会悄悄地连接到创建它的外围类的对象,然而若是嵌套类就不需要对其外围类的引用!
180.继承了内部类的类在创建构造器时,缺省的构造器不可用,因为导出类中不再有内部类可以默认连接到的外围类对象,因此,必须在构造器中传递内部类的外围类引用,然后再域中用该引用调用外围类的无参构造器。
181.内部类可以被继承,但必须有导出类明确地指出extends 外围类名.内部类名
内部类却不可以像方法一样被继承其外围类的导出类“覆盖”
182.使用局部内部类而不使用匿名内部类的唯一理由:需要不止一个该内部类的对象。
183.内部类最吸引人的原因:每个内部类都能独立地继承自一个(接口)的实现,所以无论外围类是否已经继承了某个接口的实现,对于内部类都没有影响。
184.内部类使得多重继承的解决方案变得完整:接口解决了部分问题,而内部类有效地实现了多重继承,也就是说:内部类允许继承多个非接口类型(实体类或抽象类)。
185.重要理解:内部类可以通过继承和操纵其他对象使类变得更健壮。符合客观的哲学思想:当一类个体发展到一定程度,会在内部产生或形成一个团体,这个团体对类有无限制的权限,可以对类产生影响,或者说是影响类的行为!比如:领导阶层!
186.如果解决面临实现多个接口的问题,则使用内部类与单一类无太大差别。若问题面临是实现多个抽象类或者是实体类,只有用内部类才能实现多重继承。
187.使用内部类获得的特性:1.内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立。
2.在单个外围类中,可以让多个内部类以不同的方法实现同一个接口,或继承同一个类。
3.创建内部类并没有令人迷惑的“is-a”关系,它就是一个独立的实体。
188.注意:内部类居然有权操纵外围类的private成员!
189.闭包:是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域,也就是说内部类是一种闭包!通过内部类提供闭包的功能是完美的解决方案,它比指针更灵活,更安全。closure:闭包!callback:回调!
190.内部类 = 闭包 = 创建它的作用域信息 + 指向该作用域信息的引用。这个引用向其他类提供了一种访问该内部类的外围类的各个成员(包括private)的途径;若此内部类再实现了某个接口,则这个引用可以被其他实现该接口的类的对象使用,这是一种复杂但更灵活的类类关系,多态贯穿其中,博大精深!
191.Framework(框架)是被设计用来解决某些特定问题额一个类或一组类,要运用某个应用程序框架,通常是集成一个或多个类,并覆盖某些方法,在覆盖后的方法中,编写代码定制应用程序框架,提供的通用解决方案,以解决特定问题(这是设计模式中的“模板方法”)
192.内部类与控制框架:1.内部类允许用单一的类完整地实现控制框架,从而将实现的细节封装起来,内部类用来表示解决问题所必须的各种不同的action()
2.内部类能够很容易地访问外围类的成员,所以可以避免这种实现变得笨拙。
193.当需要实现多个接口时,不妨添加一个总接口,然后由该接口继承其他接口,再用目标类实现该接口,当然,还是必须要实现所有接口中的方法!
194.注意:在返回接口引用时,别忘了new后的构造方法:return new类名();
195.在方法中创建匿名内部类时,若方法返回类型为一个类的名字,则该类必须存在,表示该匿名内部类匿名继承自此类!
196.定义内部类时,注意类名后不要加括号,注意类的声明格式与方法的格式,注意区分!
197.在外围类中调用内部类一般都是在外围类中创建一个能返回该内部类引用的方法,然后通过外围类对象调用该方法在调用内部类包含的一切动作!
198.创建一个包含内部类的类,再在另外一个类中创建该内部类的实例:
具体实现方式就是在另外一个类中,先创建它的外围类的对象,然后用外围类名.内部类名 标识符 = 外围类对象名.内部类名();
如:package InnerandInterface;
class Inner3 {
class Inner33 {
public Inner33() {
System.out.println("I am InnerClass33");
}
}
}
public class TestInnerClass8 {
public static void main(String args[]) {
Inner3 i3 = new Inner3();
Inner3.Inner33 i33 = i3.new Inner33();
}
}
191.枚举类型:只能取特定的值之一;使用enum关键字,是java.lang.Enum类!
192.注意,枚举类型是一种类型,并非成员变量!定义如下:public class TestEnum {
public enum MyLove {
yuer,shang,yaner,momo
}
public static void main(String args[]) {
MyLove ml = MyLove.shang;
switch(ml) {
case yuer: System.out.print("you love yuer");break;
case shang: System.out.print("you love shang");break;
case yaner: System.out.print("you love yaner");break;
case momo: System.out.print("you love momo");break;
}
}
}
注意:声明时不用 “=”,直接包含在大括号里,定义引用时不用构造!所以枚举类型的对象更像static型量!
193.容器类:Collection接口定义了存储一组对象的方法,其子接口Set和List分别定义了存储方式。Set中的数据对象无顺序不可重复,List中的数据对象有顺序可以重复,注意这里的重复指的是两个对象equals!
194.Map接口定义了存储键值对的方法!
195.注意,容器中存放的是对象,如果想存放基础类型,必须用相应的包装类将其包装成对象,因为基础类型存放在栈中,栈中的数据随时有可能被清空!
196.注意这种写法: Collection c = new ArrayList(); 父类引用指向子类对象,保证的将来代码的拓展性!
197.注意:调用remove方法时,比较的是对象的equals方法,如果对象是手动创建类的,那么如果类中没有重写Object类的equals方法,则永远不会移除此对象,因为引用永远不会一样!如果是用基本数据类型包装的基本类型!则会正常移除,因为所有包装类都已经重写了equals方法!
198.容器类对象在调用remove、contains 等方法时,需要比较对象是否相等,这会涉及到对象类型的equals方法和hashCode方法;对于自定义的类,需要重写equals和hashCode 方法以实现自定义的对象相等规则。注意:相等的对象应该具有相等的hash codes。
199.当对象用在Map接口中用作“键”,时比较方法会选择hashCode。重写equals方法必须重写hashCode方法!
200.所有标准异常类都有两个构造器,一个无参,一个接受字符串参数,以便能把相关信息放入构造器!
201.fillInStackTrace用来用来更新异常发生的地点信息!调用时如:e.fillInStackTrace()
202.fillInStackTrace返回的是对Throwable的引用,为了使所有异常都能捕获,自定义异常都继承自Throwable。
203.异常的基本概念是用名称代表发生的问题,并且异常的名称应该可以望文知义。
204.如果把try块放在循环里,就建立了一个“程序继续前必须要达到的”条件,还可以加入一个static类型的计数器,或别的装置,使循环再放弃以前能尝试一定的次数。
205.在构造方法里抛出异常:很有意思!
206.进行向下转型前,如果没有其他信息可以告诉你这个对象是什么类型,那么使用instanceof是必要的, 通常用提问的方式:if(x instanceof Dog)……
207.Iterator是用于各个集合的迭代器,也就是用来遍历各种容器的成员的一个接口,包含于java.util包中,使用的时候:Tierator i = c.iterator()这样这个I 就是一个接口对象,用于遍历各个容器,注意,他有三个方法:hasNext(), next(),remove() 返回类型依次是boolean,Object,void,其中remove方法是在容器中删除元素的唯一安全的方法!因为当用iterator接管容器进行操作时,iterator锁定当前对象,不允许外部操作,比如collection的remove方法等!注意:锁定!
208.把iterator看成一种游标,其中remove方法是删除游标左边的对象!
209.JDK1.5中提供了增强的for循环,语法:int[] dest = {4,3,6,2,8,5};
for(int h : dest) {
System.out.print(h+" ");
}
但是这种for循环只是用于简单的遍历数组元素,有两个缺陷:1.数值中:不能方便的访问下标值。
2.集合中:与使用Iterator相比,不能方便的删除集合中的内容,在增强的for循环内部也是调用Iterator。
总结:除了遍历并读出其中的内容外,不建议使用增强for。
210.Set接口时Collection的子接口,Set接口并没有提供新的子方法,Set接口的容器类中的元素是没有顺序的,但是不可用重复!Set容器可以与数学中“集合”的概念相对应!J2SDK API中,所提供的Ste容器类有HashSet,TreeSet等!
211.注意,在Set中可以添加相同的对象,因为其内存地址是不同的,但是不能打印出相同的元素!
212. Set s1 = new HashSet();
Set s2 = new HashSet();
s1.add("s"); s1.add("h"); s1.add("a"); s1.add("h");
s2.add("g"); s2.add("s"); s2.add("a"); s2.add("n");
Set sn = new HashSet(s1);
sn.retainAll(s2);
Set su = new HashSet(s2);
su.addAll(s2);
注意retainAll方法,用于求两集合的交集,addAll用于合并两集合!
213.数据结构的选择:Array读快改慢;Linked改快读慢;Hash两者之间!
214.map中添加对象时,可以直接添加基本类型,不必非得用包装类将其包装成对象再放进 map中,原来:m1.put("one",new Integer(3)); 现在:m1.put("one",1);即可!
215.注意:在map中放进去跟拿出来的value都是Object对象!注意出来使用前的类型强制转换!
216.泛型使用来规范放入集合中的对象的,为了使对象在取出来时仍然能保留自己的特殊类型,使用泛型!
217.for循环中,如果要省略第三个条件,必须在第二个条件后加分号!
218.容器这一章1136:一个图,一个类:Collections,三个知识点:增强的for,generic,auto-boxing/unboxing; 六个接口:collection set map list iterator compareable。
219.class有几个方法,可以在运行时获得类的相关信息,详情查看API。
220.对象数组保存的诗引用,基本类型数组保存的是数值!
221.布尔型自动被初始化成false。
222.在java中不需要担心为数组负责---只要你需要它,它就会一直存在,当你使用完后,垃圾回收期会清理掉它!
223.Arrays.fill(数组名,填充值)允许用一个固定值填充数组!System.arrayopy(数组1,开始位置,数组2,开始值,复制长度)允许把二中指定长度的值复制给一。
224.数组的equals:数组长度相同,相同位置上的元素相同!
225.程序设计的基本目标是“是不变的事物与会发生变化的事物分离”,通过回调技术可以将会发生变化的代码分离出来,然后由不会变化的代码回调会发生变化的代码!
226.Map中有内置的排序,若Map中的顺序对你很重要,应该使用LinkedHashSet或LInkedHashMap。
227.注意:Clooection及List,Set添加对象都用add,Map中用put方法!
228.注意:编译器隐式地支持String类型的转型,因为toString的存在,打印容器中的对象时都是调用对象的toString方法,因此若想打印出个性的内容建议在toString上做文章!
229.无形中产生的递归:public class Recursion {
public String toString() {
return “Recursion”+ this;
}
List v = new ArrayList();
for(int i=0;i<3; i++) {
v.add(new Recursion());
System.out.println(v);
}
}
}
这样会得到一个递归!应为打印V时会调用toStirng,当在toStirng中遇到this后,编译器会尝试把它转为toString 这样无形的形成了一个递归!
230.递归:允许一个方法在自己的内部调用自身!
231.接口的优美之处在于如果你决定改变当前的实现,只需要在创建的位置做些修改!
232.一个List可以生成ListIterator,使用它可以从两个方向遍历ArrayList,也可用于List中间插入和移除元素!ArrsyList查快改慢;LinkedList改快查慢!
233.LinkedList有addFirst,addLast,removeFirst,removeLast,getFirst,getLast这些方法(没有在任何接口或基类中定义过)使得LinkedList可以当做堆栈,队列,双向队列使用!
234.节点流就是直接插在文件上的流,相比,套在节点流或处理流上的流称作处理流!
235.良好的编程习惯,在关闭流之前,先调用flush方法!把缓冲的数据都提取到目的地!flush方法貌似只是在输出流中才有!
236.管道是线程与线程之间的通讯!
237.注意:用FileInputStream时,打印读取数据时要把in.read()赋值给一个int数,然后打印是把int数转换成char型!不知为何!直接打印in.read()有落差!
238.奇怪:用FileInputStream读取汉字然后再用FileOutputStream写出去!能获得完整的文件!但是打印的时候却得到乱码!
239.当用ByteOutputStream读取字节数组中的数据时注意“先写先读”队列顺序!
240.DataStream处理流,用来处理java的基本数据类型!
241.经典的输入流包裹:BufferedReader包裹InputStreamReader包裹System.in
242.Print流比较特殊!PrintWriter和PrintStream都属于输出流,分别针对与字符和字节!PrintWriter和PrintStream不用抛异常!此外PirntWriter和PrintStream都有自动的flush功能!
243.若想要把一个对象序列化!那该类必须实现serializable接口!
244.当需要用Object流来读取或写入一个对象时!务必要实现Serializable接口!否则对象不能被序列化!注意:transient用来修饰成员变量!用它修饰的变量在程序序列化时不予考虑!Externalizable接口继承自Serializable用来实现程序员控制的对象序列化过程!
245.UTF-8字符串省空间!因此在网络上传输时通常采用UTF-8;
246.注意sleep方法时静态方法调用方式:Thread.sleep(时间)!join方法也需要抛异常InterrputedException但是join方法感觉挺干净!简洁!
247.在单核cpu的机器上,线程的优先级表现的很好!
248.原子性的输出:最小单元的输出!不可再分!
249.注意:在方法前返回类型前加synchronizaed当该方法被调用时锁定调用该方法的对象的引用!并非锁定该方法!
250.没锁住的方法不能wait!否则报错!
251.Wait时别的线程可以访问锁定对象,调用wait方法的时候必须锁定该对象;Sleep时别的线程也不可以访问锁定对象!Wait属于Object类,Sleep属于Thread类!
252.网络编程时,记住,边写server边写client,起程序的时候先起server再起client!
253.聊天程序总结:首先,要得到socket的InputStream和OutputStream,注意在用InputStreamReader或者DataInputStream包裹时包裹的是getInputStream或OutputStream而非流的名字!第二:Wile循环中注意判断条件是“不等于某字符串时开始循环”注意加否定叹号!第三:由于进出顺序!当Client结束是字符串先在Client验证,所以Client先结束,同时Server端出现异常!最后我把异常给吞噬掉!无奈,目前没想到相关解决办法!
254.注意顺序:Server:读C,验C,写C,读S,写S,发S,再读C;Client:读C,验C,写C,读S,写S,再读C!
255.UDP根本无所谓客户端,服务端,所谓的Server就是用DatagramSocket new出来的对象裹一个端口,接收的时候用对象的receive方法接收一个DatagramPacket的对象,对象里裹得是一个字节数组!byte型的!长度自己定义!打印接收的数据的时候就new一个String然后调用那个复制的方法,注意,方法中的长度参数要用getLength!所谓的client也是一个DatagramSocket一个DatagramPacket,注意,Packet对象在裹字节数组的时候要在最后new 一个InetSocketAddress后边写上IP跟端口!用DatagramSocket对象的Send方法发出去就行了!注意new DatagramSocket的时候加上一个端口号!是用来发送的!
256.注意跟UDP通讯用的流最多的就是ByteArrayInput/OutputStream和DataInputStream/OutputStream
257.进入GUI编程!加油加油!
258.要想在JFrame里使用setBackground方法还得引入awt包!
259.Frame里的setLayout方法很重要,当显示不正常时可以检查此方法!切记切记!
260.注意:FlowLayout是Panel类默认的布局管理器!FlowLayout布局管理器的默认对齐方式时居中!
261.BorderLayout是Frame的默认布局管理器!
262.若不指定组件的加入部位,则默认加入到center区,每个区域只能加入一个组件,若加入多个,则先前加入的会被覆盖!
263.注意:f.add(null,BorderLayout.WEST);这种做法是不对滴!
264.监听器又叫钩子函数,回调函数!
265.注意:pack方法要写在Frame的add方法后!这样才能根据add进去的compont默认设置Frame的大小!
266.getSource方法获得的是发生事件的对象的引用!注意已经向上转型为ActionEvent类型!具体使用的时候需要再向下强制转型到具体的compont!
267.注意setEcohChar方法中间的参数是char型,用单引号包裹!而且JTextField里没有该方法!
268.注意import 包的时候有个类叫java.awt.Event不是监听器类,监听器类是java.awt.event切记切记!
269.持有对方引用!如果A类中在B类有许多需要访问成员变量,那么可以使用持有对方引用!用法:在B类中new一个A类的对象,然后在B类的构造里作为参数传给B的对象,这样在B中可以用这个引用随意访问A的成员变量!很优雅的访问方案!
270.Graphics类,在Java里控制画图,使用此类时只需在类中重写paint方法,里面自动生成一个Graphics 的对象,利用这个对象结合Graphics中的方法可以画出相关程序,注意Color c = g.getColor 最后 g.setColor = c 这样回复现场!把画笔颜色返还给画笔!
271.调用repaint方法,强制frame重画,这是一种双缓冲模式! 调用repaint时内部调用update方法,再调用paint得到画笔!
272.实现鼠标监听器的时候实现mouseAdapter类可以随意按需要重写的响应鼠标方法!如果实现的是MouseListener接口就要全部重写里面的 方法!
273.System.exit(0)表示正常退出,System.exit(-1)表示异常退出!
274.什么时候使用匿名类:放在匿名类中的逻辑简单,不需要经常变动!
275.LinkList具有能够直接实现栈的所有功能的方法,栈:LIFO 后进先出,最后压入栈的元素最先弹出栈。
276.LineInputStream(InputStream)可调用getLineNumber和setLineNumber方法。
277.可以用内部类启动线程,现在外围类里创建一个内部类的引用,然后再把内部类继承到Thread或实现Runnable方法,把start写在内部类的构造里,内部类里重写run方法,外围类里把先前内部类的引用new在一个方法里面,通过外部类对象调用方法再调用Start来实现线程的启动!
278.用匿名内部类更好:外围类提供一个thread对象,在外围类的构造里t = new Thread(name) {public viod run(){}};
279.设计Timer类的目的就是承担大量并发调度任务,所以它能成为很有用的工具。
280.setDaemon(true)将线程设为后台线程,isDaemon()检测线程是否后台,作用在实现了Thread的导出类中,必须声明在Start之前。
281.要控制对共享资源的访问,得先把它包装进一个对象,然后把所有要访问这个资源的方法标记为synchronized 也就是说:一旦某个线程处于一个标记为synchronized的方法中,那么在这个线程从该方法返回之前其他所有要调用类中任何标记为synchronized方法的线程都会被阻塞。
282.针对每个类也有一个锁,所以synchronized statci方法可以在类的范围内防止对static数据的访问。
283.最安全的同步方针:1.如果要对类中的某个方法进行同步控制,最好同步所有方法,如果忽略了其中那个一个通常很难确定这么做是否会有负面影响。2.只应在使用性能评价工具正式了条同步控制却是是性能瓶颈的时候才会解除同步。
284.Sleep方法不好释放锁, wait notify notifyAll方法会自动释放锁,所以上述方法必须使用在同步方法里。
285.在run中用一个flag布尔型来控制线程的返回在检查关闭条件符合后修改flag来实现线程结束!
286.对象设计的五个阶段:1.发现对象;2.对象的组合;3.系统的构建; 4.系统扩展; 5.对象重用!
287:
建议:设计阶段:: 1.优雅终将得到回报!2.先能运行,再求速度!3.谨记“分而治之”的原则!4.区分类的编写者和使用者!5.编写类的时候,类的名称要十分清晰,不需要注释也能理解!6.分析和设计必须使用系统中的类,它们的公共接口以及雷之间(尤其是与基类之间)的关系必须达到最少!7.尽量让所有东西自动化!8.在编写类之前先编写测试代码,以验证这个类是否设计完备!9.所有软件设计中的问题,都可以通过“引入额外的间接概念层次”得到简化!10.引入的间接概念层次要有意义!11.尽可能使类原子化:::a.复杂的switch语句---考虑使用多态;b.有许多发杂的方法,各自处理类型极为不同的操作---请考虑划分成不同的类;c.有许多成员变量,用来表示类型极为不同的属性---请考虑划分成不同的类。12.当心冗长的参数列表!13.不要一再重复!14.小心switch语句和if-else子句!15.从设计观点来看,要找出变动的因素,使它和不变的因素分开!16.不要依靠子类化来拓展基础功能!17.尽少意味着更多!18.大声朗读你的类,确保它们能够编译通过!19.在判断应该使用继承还是组合的时候,考虑一下是否需要向上转型成基类型!20.采用字段表示数值的变化,使用方法覆盖来变现动作的变化!21.小心重载! 22.使用异常体系!23.有时候仅仅使用聚合就能解决问题!24.从客户端程序员和程序维护者的角度进行思考!25.当心“巨型对象综合症”26.如果你只能采用某种别扭的方式才能实现某个功能,清将其抽象成服务,并局限在某个类内部!27.对象不应仅仅用来持有数据!28.在原有类的基础上编写基类时,首先应考虑组合!30.使用继承和方法覆盖来表达行为上的差异,使用字段来表示状态的变化!31.当心“变异性”! 32.注意继承期间的“限制”!33.使用设计模式来消除那些“纯粹的功能性代码”!34.当心“分析瘫痪”的情况!35.当认为自己已经获得了一个优秀的分析,设计或实现时,进行一次全面评审!
实现阶段::1.一般来说,清遵守Sun的程序编写习惯!2.无论使用何种编写风格,如果你的团队(或者公司)能够加以标准化,那么的确会带来显著效果!3.遵守标准的大小写规范! “包”是一个特列!4.不要为私有字段名称加上你自己的“修饰”符号!5.编写通用性的类时,清遵守标准形式。包括定义equals hashCode toString clone并实现Comparable和Serialiable接口!6对于那些“获得或改变私有字段值”的方法,清使用javaBeande "get" "set" "is" 等命名习惯!7.对于你编写的每一个类,清使用JUnit为他编写测试!8.有时需要通过继承才能访问基类的受保护成员!9.应避免纯粹为了提高执行速度而采用final方法!10.如果两个类在功能性上产生了惯量(比如容器和迭代器),那么请试着让一个类成为另一个类的内部类!11.在任何时候,都要警惕那些互相之间高度耦合的类!考虑一下使用内部类为程序编写维护带来的好处!12.不要跳入过早优化的陷阱!13.尽可能缩小对象的作用域,这样对象的可见范围和生存期也都尽可能地小!14.使用Java标准库提供的容器!15.对于一个健壮的程序而言,每一部分都必须健壮!16.宁可在编译期发生错误,也不要错误发生在执行期!17.当心冗长的方法定义!18.尽量使用private关键字!19.大量使用注释,并使用javadoc的“文档注释语法”来生成程序的文档!20.避免使 用“魔术数字”21.在编写构造器时,请考虑异常!22。在构造器中只做必要的动作!将对象设定为正确状态!23.客户端程序员用完对象之后,将对象设定能够为正确状态!24.客户端程序员用完对象之后,如果你的类需要任何清理动作,请将此动作放到一个精心定义的方法中!24.finalize方法的职责职能是为了调试的目的而检查对象的“终结条件”!25.如果对象在某个特定范围内必须被清理(而不是作为垃圾被回收)请先初始化对象如果成功的话吗,立刻进入一个带有finally子句的try块,在finally子句中进行清理动作!26.在继承的时候如果覆盖了finalize地方法,要记得调用super.finalize! 27.当你编写固定大小的对象容器时,它们要能够被传送给一个数组!28.优先选择接口而不是抽象类!29.为了避免十分令人泄气的经历,清检查类路径,确保所有为放进包里的类的名称互不相同!30.注意无心的重载错误! 31当心过早优化!32.记住:记住代码被阅读的时间多于它被编写的时间!
SWING SWING SWING
1.在顶层容器中也可以添加菜单组件,而菜单组件一般是放在顶层容器中,和内容面板是并列的!
2.在JFrame中添加面板可以用add(),但是JFrame类自有的方法时setContentPane()
3.关于菜单栏(JMenuBar)包括JMenu JMenuItem,JMenu构造器接收String为其指定名称,然后JMenuItem接受字符串为其命名,Bar包裹Menu,Menu包裹Item,Item对象有addSeparator为其添加间隔线!
4.添加组件的时候按照自下而上的顺序!编译器貌似很笨!
正则表达式
1.当匹配一个\时,必须用四个\来匹配,若用两个会报错!因为java中\\表示一个\
2.在匹配正则表达式时,如果字符串已经到结尾还调用find方法,编译不会报错!只会输出false结果!
3.matches方法永远匹配整个字符串!find方法从目标字符串中找字串!lookingAt方法只是从字符串的起始位置匹配,符合则返回true!
4.start,end方法返回的字符串下标都是左闭右开的!
5.注意:布尔型返回型的方法常用作循环判断条件!
6.正则表达式的分组:从表达式的左起,有几个左括号就是第几组!
7.表达式里的点号默认不匹配换行符!
数据结构
1.杂乱的数据不能表达和交流信息!
2.数据之间是有内在联系的!
3.数据之间是有联系的!
4.在某种数据结构上可定义一组运算!
5数据结构主要研究的内容:研究数据的各种逻辑结构,物理结构以及他们之间的相应联系;并对各种结构定义相应的各种运算;设计出相应的算法;分析算法的效率!
6.数据元素是数据的一个个体!数据对象是数据的一个子集!
7.数据项是数据具有意义的最小单位!
8.数据结构就是有结构的数据元素的集合!
9.数据结构就是数据元素及其相互关系的集合!
10.逻辑结构:数据元素之间的结构关系!
11.物理结构:数据结构在机内的表示!
12.算法:算法是一个有限的指令集,循环指令流可以完成特定的功能!
13.算法的基本特性:a.有穷性:算法经有限步后结束!b.确定性:下一步必须是明确的!c.可行性:每一部是可执行的!
14.算法与程序的区别:算法是解决问题的一种方法或一个过程,考虑如何将输入转换成输出,一个问题可以有多种算法!程序时用某种程序设计语言对算法的实现!
15.程序可以是无穷的,例如OS,算法是有穷的!程序可以是错误的,算法必须是正确的!程序是用程序设计语言描述,在机器上可以执行!算法还可以用框图,自然语言灯方式描述!
16.算法是给人看的,程序是给机器看的!
17.程序设计语言+自然语言描述的算法叫伪代码!
18.衡量算法的标准:A.运行所花费的时间(算法的时间特性)B.所占用的存储空间大小(算法的空间特性)C.其他(可读性,易调性,健壮性)!
19.算法的时间复杂度:T(n) = o(f(n)) 其中,n为算法的语句频度,即语句可执行的最大次数,也叫规模!o()为算法的同阶无穷大!如:x = x+1; 语句频度为 1 时间复杂度为O(1) 常数阶; for(int 1 = 1; i
21.算法与时间复杂度的关系:不必追求高效算法,低效算法可由高效计算机弥补的看法是错误的!当算法的时间复杂度大到一定程度,该算法在效率相差很大的机器上运行的时间是差不多的!
22.线性表是N个数据元素的有限序列,记为 L = (a1,a2,……an)
在线性表中,数据元素之间的关系是:ai-1 领先于ai ,ai领先于ai+1; 称ai-1是ai的直接前驱元素;ai+1是ai的直接后继元素;除a1外,每个元素有且仅有一个直接前驱元素,除an外,每个元素有且仅有一个直接后继元素,线性表中数据的个数n(n>=0)称线性表的长度,当n=0时,称为空表!
23.线性表的基本运算:1.INITIALTE(L)初始化操作;2.LENGTH(L)求长度函数;3.GET(L,i)取元素函数,类似的数组中一个游标i 叫做该线性表的位序;4.PRIOR(L,elm)求前驱函数;5.NEXT(L,elm)求后继函数;6.LOCATE(L,x)定位函数,返回X在表中第一次出现时的位序,若不存在返回0;7.前插操作INSERTE(L,i,b)表示把b插入到位序i前边!8.DELETE(L,i) 删除操作;9.判空表函数(L),若表L为空则返回真!10.CLEAR(L)表置空操作,将L置为空表!
24.注意:线性表的所有函数都需要程序员自己实现,因为线性表都是自己定义的!所以函数更需要自己定义了!
25.算法思想是指导编写算法的,算法是指导编写程序的!
26.数据在计算机中的存储结构包括:顺序存储结构和链式存储结构,所有的数据在计算机中都是这样实现存放的!顺序存储结构是一种物理结构!
27.线性表的顺序存储结构特点:a.逻辑上相邻的元素,其物理位置也相邻;b.可随机存取表中任一元素;c.必须按最大可能的长度预分存储空间存储空间利用率低,表的容量难以扩充,是一种静态存储结构!d.插入删除时,需移动大量元素,平均移动元素为n/2!
28.链式存储结构:由节点组成,每个节点包括数据域和指针域,指针域指向下一个节点的数据域!每个节点的指针域只保存自己的直接后继元素的指针域!最后一个节点的指针域为空!若将该空指针域指向第一个节点的数据域,则形成一个循环链表!
29.我们定义的单链表都是定义的指针,头指针,单链表中的任何一个数据都要通过头指针来找到!头指针能够唯一的标识一个单链表!
30.单链表的判空条件是头指针为空!
31.其实头节点的引入就是为了给链式存储结构的第一个数据元素DE中的数据域添加一个引用(指针)!
32.线性表链式存储结构的特点:a.逻辑上相邻的元素,其物理位置不一定相邻;元素之间的链接关系由指针域指示!b.链表是非随机存取存储结构;对链表的存取必须从头指针开始!c.链表是一种动态存储结构;链表的结点可以调用new()申请和dispose()释放!
d.插入删除运算非常方便;只需修改相应指针值!
33.循环链表的判空条件:H = H↑.next;
34.双向链表的判空条件:L↑.priou = L↑.next = NIL;
35.双向循环链表的判空条件:L↑.priou = L↑.next = L;
36.当接到实际问题编写算法时,首先应该选择数据结构,然后选择数据结构的逻辑结构,然后是物理结0:16 2010/3/4构,最后是算法的实现!
37.链表中的插入原则:从后往前接,如果从前往后接,当接到后面的时候后继元素的直接前驱元素的后继已经被赋值给了插入元素,而原来的后继已经丢失,从而造成断链!切记切记!
38.栈是插入和删除操作限定在表尾进行的线性表!
39.栈是操作受限制的线性表!
40.线性表的应用:一元多项式求值!
41.栈的应用:表达式求值,递归!
42.递归过程的特点:是程序设计的一个强有力的工具,它具有结构清晰,程序易编,易读,易调试,程序正确性容易证明!但是运行效率低!
43.递归原理:基本原理是重复地把问题转化为与原问题相似的新问题,知道问题可解决为止!
44.关键点:a.用较简单的新问题来表示较复杂的原问题,例如:n! = n(n-1)!,或n! = (n+1)!/(n+1) 前者(n-1)! 较原问题n! 简单,可行;而后者(n+1)! 较n! 更复杂,不可行!b.不能产生自己调用自己的无穷序列,即必须有一个递归调用序列的“出口”,来种植递归调用!
45.实现:递归过程都是通过栈来实现的,并且所有递归算法都可以通过栈改写为非递归算法!
46.队列(quene)是限定在一端插入,另一端删除的线性表。允许插入的一端叫队尾(rear),允许删除的一端叫对头(front),不含元素的空表成为可空队列,队列的运算特性是先进先出!
47.队列的基本运算:ENQUEUE(Q,x) 入队操作,队尾插入操作!DLQUEUE(Q)出队操作!GETHEAD(Q) 取队头元素且不删除!CURRENT-SIZE(Q) 求长度操作!
48.本来队列中元素没有满,却不能添加新元素的现象叫做“假溢出”!
49.队列的判空:q.front = q.rear
50.循环队列解决“假溢出”问题,循环队列的判空与判满一样!
51.循环队列顺时针旋转!
52.入队操作:append := rear"++"then append job; pop := remove job then front"++"注意“++”完成后要除以队列的maxsize取余!i = (i + 1)%max
53.解决循环队列的判空与判满条件一致的问题:1.在队列中预留一个空位;2.设定一个标志,没元素时为0.有元素时设为1!3.设置一个数字计数器!4.让front和rear等于一个不可能等于的值!
54.串的概念:n个字符的有限序列!求字串在串中的起始位置称为字串定位或模式匹配!
55.顺序存储结构时首先要确定数据的最大存储长度!
56.串的链式存储结构叫做块链结构!因为串可能将若干个元素封装成一个节点!不一定只是一个数据元素!、
57.数组和广义表是结构发生了变化的线性表!是线性表的一种拓展!
58.称非空表的第一个元素为表头,其余元素组成的表称为表尾!所以表头可以是单元素或表,但是表尾必须是一个表!
59.矩阵的压缩存储:给多个值相同的元素只分配一个空间,或者对值为零的元素不分配存储空间!
60.适用于压缩存储方式的特殊矩阵:对称矩阵,对角矩阵,稀疏矩阵!
61.广义表的两类存储结构:1,表头表尾链结构,有两类节点::表结点,单元素结点!2.同层结点链结构!
62.数据结构分为线性结构(线性表,栈,队列等)非线性结构:至少在一个数据元素有不止一个直接前驱或后继(树,图等)!
数据结构:
树和二叉树:
1.树的表示法:分支图表示法,嵌套集合表示法,广义表!分支图表示法最直接!
2.树的结点:包含一个DE和指向其子树的所有的分支!
3.结点的度:一个节点拥有的子树的个数,
我们称为结点的度,度为零的结点称为叶结点。
4.树的度:树中所有结点的度最大值(Max(D(I)).
含义:树中最大分支数为树的度!
5.注意:树的度不是树中所有结点的集合!而是最大值!
6.结点的层次及树的深度:根为第一层,根的孩子为第二层
,若某结点为第K层,则其孩子为K+1层,树中结点的最大层次称为树的深度或高度!
7.森林:是m(m>=0)棵互不相邻的树的集合,森林与树概念相近
,相互很容易转换!
8.树的度是指它孩子的分支!
9.二叉树是结点数为0或每个结点最多只有左右两棵子树的树,
二叉树是一种特殊的树
10.特点:每个结点最多只有两颗子树,即不存结点度大于2的结点;子树有左右
之分,不能颠倒!
11.二叉树和度为二的树的区别:结点孩子的个数,孩子的顺序!
12,二叉树的性质:1,在二叉树的第i层上只多有2^i-1个结(i>=1)
13.深度为k的二叉树之多有2的k次方减1个结点(k>=1) (深度一定,二叉树的最大结点数也确定)
14.二叉树中,终端结点数n0与度为2的结点数n2有如下关系:n0 = n2 +1
15.满二叉树:深度为K,且有2的k次方减1个结点的二叉树!特点:
a.每一层上结点数都达到最大;b.度为1的结点n1 = 0!
16.结点层序编号方法:从根结点起从上到下逐层(层内从左到右)对
二叉树的结点进行连续编号!
17.完全二叉树:深度为k,结点数为n的二叉树,当且仅当每个结点的标号
都与相同深度的满二叉树中从1到n的结点一一对应时,成为完全二叉树!
18.哈夫曼树是带权路径长度最短的二叉树!
19.图分为有向图(Directed graph),无向图(Undirected graph)
20.设n为定点数,e为边或弧的条数,对Undirected graph有:0<=e<=n(n-1)/2,
对于Drieced graph 有:0<=e<=n(n-1)!
21.完全图(Complete graph):边达到最大的图!
22.无向完全图:边数为n(n-1)/2的无向图;有向完全图:边数达到n(n-1)的图!
23.权:与图的边或弧相关的数;网:边或弧上带有权值的图!
24.定点的度TD(V):无向图:为依附于定点V的边数;有向图:等于以顶点V为
弧头的弧数(称为V的入度,记为ID(V))与以顶点V为弧尾的弧数(称为V的出度,记为OD(V))之和,即:TD(V)
= ID(V) + OD(V)
25.路径长度:路径上边或弧的数目!
26.简单路径:路径中不含相同顶点的路径!
27.回路或环:首尾顶点相同的路径,称为回路或环!
28.顶点连通:若顶点V到顶点V'有路径,则称顶点V与V'是连通的!
29.无向连通图:若无向图中任意两个顶点VI,VJ都是连通的,则称该图是连通图(vi<>vj)
30.有向连通图:若有向图中任意两个顶点vi ji都存在从vi到vj和从vj到vi
的路径,则称该图为强连通图(vi<>vj)
31.无向图连通分量:无向图中极大连通子图,称为连通分量!
32.有向图强连通分量:有向图中极大强连通图,称为强连通分量!
33.生成树:设无向图G是含有n个顶点的连通图,则图G的生成树是含有n个顶点,且只有n-1条边的连通子图!
34.图的存储结构:邻接矩阵!
35.图的遍历算法:深度优先搜索算法,广度优先搜索算法!
36.生成树的三大要素:n个顶点,n-1条边,连通!
37.生成树代价:对图中每条边赋予一个权值(代价),则构成一个网,网的生成树
G'=(V.{T})的代价是T中各边的权值之和,最小生成树就是网上所有可能的生成树中,代价最小的一类生成树!
最小生成树也不一定唯一,但是其代价肯定是相等的!
性质4:结点数为n的完全二叉树,其深度为log2n向下取整+1!
性质5:在按层序编号的n个结点的完全二叉树中,任意一结点i(1<=i<=n)有:
a.i = 1时,结点i是树的根;否则(i>1),结点i的双亲为结点i/2向下取整;
b.2i>n时,结点i无左孩子,为叶结点;否则,结点i的左孩子为结点2i;
c.2i+1>n时,结点i无右孩子;否则,结点i的右孩子为结点2i+1!
性质6:含有n个结点的二叉链表中,有n+1个空链域!
1.遍历二叉树:遍历二叉树是指按一定的规律对二叉树的每一个结点,访问且仅访问一次的处理过程!
2.访问时一种抽象的操作,是对结点的某种处理,例如:求结点的度,层次,打印结点的信息或做其他的工作!
3.遍历的次序:若设二叉树根为D,左子树为L,右子树为R,并限定先左后右,则有以下三种遍历次序:LDR 中序遍历; LRD 后序遍历; DLR 先序遍历!(是根据D的顺序而定的)!左子树始终先于右子树!
图:
1.设无向图中顶点数为n,边数为e,则它的邻接表需要n个头结点和2e个表结点!若为有向图,则它的邻接表需要n个头结点和e个表结点!
2.与无向图的邻接表结构一样,只是在第i条链表上的结点是以vi为弧尾的各个弧头顶点!第i条链表上的结点,为vi的出度!
3.为了方便求vi的入度,建立了有向图的逆邻接表,只是在第i条链表上的结点表示以vi为弧头的各个弧尾顶点!
4.邻接表计算出度容易,入度难,逆邻接表计算入度容易,出度难!
5.最小生成树的性质MST:设N=(V,{E})是一个连通网,U是顶点集V的一个非空子集,若(u,v)是一条具有最小权值的边,其中u属于U,v属于V-U即(u,v)= Min{cost(x,y)|x属于U,y属于V-U,则比存在一颗包含边(u,v)的最小生成树!
6.最小生成树的著名算法:普瑞姆算法!克鲁斯卡尔算法!共同利用MST特性! 7.AOV 网可以解决如下两个问题:1.判断工程的可行性,显然,有回路,整个工程就无法完成!2.确定各项活动在整个工程执行中的先后顺序!称这种先后顺序为拓扑有序序列!
8.拓扑排序的算法步骤:1.在AOV网中,选取一个没有前驱的顶点输出;2.删除该顶点和所有以它为弧尾的弧;3.重复以上两步,直到AOV网中全部顶点都已输出(得到拓扑有序序列)或者,图中再无没有前驱的顶点(AOV网中有环)
9.拓扑排序是一种对非线性结构的有向图进行线性化的重要手段!
10.关键路径的对象是AOE网!
11.AOE网:有向图中,顶点表示事件,弧表示活动,弧上的权表示完成该活动需要的时间,则称这类有向图为边表示活动的网(AOE网)
12.AOE网中仅有一个入度为0的事件,称为源点,表示工程的开始;也仅有一个出度为0的事件,称为汇点,表示工程的结束!每一事件V表示以它为弧头的所有活动已经完成,同时,也表示以它为弧尾的所有活动可以开始!
13.AOE网可解决的问题:1.估算工程的最短工期(从源点到汇点至少需要多少时间)2.找出哪些活动是影响整个工期进展的关键!
14.路径长度:路径上各活动持续时间的总和,即:路径上所有弧的权值之和)
15.关键路径:从源点到汇点直接按路径长度最长的路径(不一定是唯一的)
16.求AOE网的关键路径:a.先算各个事件(顶点)的最短发生时间,前结点时间+路径上的权值!取最大值!事件的最迟发生时间,从后往前算,取最小值!每个活动的最早发生时间就是它的弧尾时间!
17.查找表(table):由同类型的DE或记构成的集合!
18.静态查找表的第三个查找算法:索引表查找法!(分块查找法)
19.动态查找表的特点:表的结构在查找过程中试可以变化的!
20.二叉排序树:BST 或者是一棵空树,或者是具有如下性质的BT:A.若左子树非空,则左子树上所有结点的值均小于根结点的值;B.若右子树非空,则右子树上所有结点的值均大于根节点的值;C.左右子树也为BST!
21.不同关键字得到同一地址的现象,称为冲突!
22.几种哈希函数:直接哈希函数(选择关键字的一个线性函数作为哈希地址)数学分析法:取key中数字均匀分布的作为哈希地址!平方取中发:取关键字平方后的中间几位作为哈希地址!
23.折叠法:将关键字分割成位数相等的几部分,取这几部分的叠加和,舍去高位的进位,位数由存储地址的位数确定!相加时有两种方法:移位叠加法:将每部分的最后一位对齐,然后叠加;另一种是间界叠加法:即将关键字看做一纸条,从一端向另一端沿间界逐次折叠,然后对齐相加!
24.除留余数法:取关键字被某个不大于哈希表长m的数p除后的余数作为哈希地址!
25.随机数法:选择一个随机函数,取关键字的随机函数值作为它的哈希地址!
26.处理冲突的方法:开放定址法!再哈希法!链地址法!公共溢出区法!