1、Java:简单性、可移植性、面向对象、解释型、分布式、高性能、健壮性、多线程、安全性、动态性、体系结构中立。
2、从一开始,java就被设计成能够防范各种袭击,包括:1)禁止运行时堆栈溢出,例如,蠕虫病毒常用的袭击手段;2)禁止
在自己的处理空间之外破坏内存; 3)未经授权禁止读写文件。(自Java1.1问世以来,Java就有了数字签名类)
3、Java是一种强类型语言(strongly typed language),必须为每一个变量声明一种类型。共有8种基本类型(primitive type
),4个整型、2个浮点类型、1个用于表示Unicode编码的字符单元的字符类型char和一个表示真值的Boolean类型
4、Java中整型的范围与运行Java代码的机器无关
5、三个特殊的浮点数值:正无穷大(一个正整数除以0结果为正无穷大Double.POSITIVE_INFINITY)、负无穷大
(Double.NEGATIVE_INFINITY)、NaN(计算0/0或者负数的平方根的结果为NaN,Double.NaN)
6、可使用if(Double.isNaN(x))
7、for语句的3个部分应该对同一个计数器变量进行初始化、检测和更新
8、数组时一种数据结构,用来存储同一类型值的集合。通过一个整型下标可以访问数组中的每一个值。
9、for(variable: collection) statement 循环collection中的每一个元素
10、匿名数组 new int[] {1, 2, 3, 4}
11、数组拷贝:1)将一个数组变量拷贝给另一个数组变量,两个变量将引用同一个数组;2)将一个数组的所有值拷贝到另一个
数组中去,就要使用System类的arraycopy(from,formIndex,to,toIndex,count),数组to必须有足够的空间来存放拷
贝的元素;
12、封装encapsulation。实现封装的关键在于绝对不能让类中的方法直接访问其他类的实例域,但可以访问自己类的实例域,
程序仅通过对象的方法与对象数据进行交互。
13、封装给予对象“黑盒”特征。
14、对象的主要特征:行为(behavior)、状态(state)、标识(identity)
15、常见的类之间的关系:依赖(uses-a)、聚合(has-a)、继承(is-a)
16、应该尽可能的减少相互依赖的类
17、一个对象变量并没有实际包含一个对象,而仅仅是引用一个对象
18、若需要返回一个可变数据域的拷贝,应该使用clone();
19、使用静态方法:1)当一个方法不需要访问对象状态,其所需参数都是通过显式参数提供的;2)当一个方法只需要访问类的
静态域。
20、每一个类都可以有一个main方法,这是对类进行单元测试时一个常用的技巧
21、参数变量用同样的名字将实例域屏蔽起来,用this.var。this指示隐式参数,也就是被构造的对象。
22、如果没有System.exit(0),会出现异常
public class hello {
static {
System.out.println("Hello World!");
System.exit(0);
}
}
23、类设计技巧
1)一定将数据设计为私有
2)一定要对数据初始化
3)不要在类中使用过多的基本数据类型
4)不是所有域都需要独立的域访问器和域修改器
5)将职责过多的类进行分解
6)类名和方法名药能够体现它们的职责。
24、super不是一个对象的引用,不能将super赋给另一个对象变量,它只是一个指示编译器调用超类方法的特有关键字。
25、使用super调用构造器的语句必须是子类构造器的第一条语句。如果子类的构造器没有显式地调用超类的构造器,则将自动
地调用超类默认(无参)的构造器。如果超类没有无参的构造器,并且在子类的构造器中又没有显式地调用超类的其他构造器,
编译器报错。
26、this的两个用途:1)引用隐式参数;2)调用该类其他的构造器。super的两个用途:1)调用超类的方法;2)调用超类的
构造器
27、一个对象变量可以引用多种实际类型的现象被称为多态(polymorphism),在运行时能够自动地选择调用的适当方法的现
象称为动态绑定(dynamic binding)
28、is-a可以用来判断是否应该将数据设计为继承关系。is-a规则的另一种表述法是置换法则。它表明程序中出现超类对象的任
何地方都可以用子类对象置换
29、每次调用方法都要进行搜索,时间开销相当大,因此虚拟机预先为每个类创建了一个方法表(method table),其中列出
了所有方法的签名和实际调用的方法。
30、动态绑定的一个非常重要的特性:无需对现存的代码进行修改,就可以对程序进行扩展
31、在覆盖一个方法的时候,子类方法不能低于超类方法的可见性。
32、不允许扩展的类被称为final类
33、将一个类声明为final,只有其中的方法自动地称为final,而不包括域。
34、进行类型转换的唯一原因是:在暂时忽视对象的实际类型之后,使用对象的全部功能。
35、将一个子类的引用赋给一个超类变量编译器是允许的。但将一个超类的引用赋给一个子类变量,必须进行类型转换。
36、只能在集成层次内进行类型转换;在将超类转换成子类前,应使用instanceof进行检查(在一般情况下,尽量少用类型转换
和instanceof运算符)
37、抽象类不能被实例化,但可以定义一个抽象类的对象变量,并且只能引用非抽象子类的对象。
38、Object类中的equals方法判断两个对象是否具有相同的引用。
39、Java语言规范要求equals方法具有以下的特性:
1)自反性:对于任何非空引用x,x.equals(x) 应返回true;
2)对称性:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)返回true;
3)传递性:对于任何引用x, y, z,如果x.equals(y)为true、y.equals(z)为true,那么x.equals(z)也应该为true;
4)一致性:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)应该返回同样的结果;
5)对于任意非空引用x,x.equals(null)应该返回false。
40、如果子类能够拥有自己的相等概念,那么对称性需求将强制采用getClass进行检测;如果由超类决定相等的概念,那么就可
以使用instanceof进行检测,这样可以在不同子类对象之间进行相等的比较。
41、编写equals方法的建议:
1)显式参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量;
2)检测this与otherObject是否引用同一个对象:if(this==otherObject) return true;
3)检测otherObject是否为null,如果为null返回false,这项检查室必要的。if(otherObject==null) return false; 比
较this与otherObject是否属于同一个类。如果equals的语义在每个子类中有所改变,就是用getClass检测:if(getClass()!
=otherObject.getClass()) return false;如果所有的子类都拥有统一的语义,就是用instanceof检测:if(!(otherObject
instanceof ClassName)) return false;
4)将otherObject转换为相应的类型变量:ClassName other = (ClassName)otherObject;
5)现在开始对所有需要比较的域进行比较,使用==比较基本类型,使用equals比较对象域。如果所有域都匹配,就
返回true,否则false :return fielda1==fieldb1&&fielda2==fieldb2&&......。如果在子类中重新定义equals,就要在其中包
含调用super.equals(other)。
42、@Override是一个元数据(metadata)标记
43、散列码(hash code)是由对象导出的一个整型值,无规律。如果x和y是两个不同的对象,x.hashCode()与y.hashCode()基
本上不会相同。
44、由于hashCode方法定义在Object类中,因此每个对象都有一个默认的散列码,其值为对象的存储地址。
45、 String s = "OK";
StringBuffer sb = new StringBuffer(s);
String t = new String("OK");
StringBuffer tb = new StringBuffer(t);
由于字符串的散列码是由内容导出的,所以字符串s与t拥有相同的散列码;字符串缓冲sb与tb却有着不同的散列码,这是因为在
StringBuffer类中没有定义hashCode方法,它的散列码是由Object类的默认hashCode方法导出的对象存储地址。
46、如果重新定义equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中。equals与hashCode的
定义必须一致:如果x.equals(y)为true,那么x.hashCode()就必须与y.hashCode()具有相同的值。
47、toString方法返回表示对象值的字符串。绝大多数的toString方法的格式:类的名字,随后是一对方括号括起来的域值。类
的名字最好通过getClass().getName()得到
48、也应该定义子类的toString方法,将子类域的描述添加进去。如果超类使用getClass().getName(),那么子类仅调用
super.toString()就可以。
49、只要对象与一个字符串通过操作符“+”连接起来,Java编译就会自动调用toString方法,以便获得这个对象的字符串描述
。
50、在调用x.toString()的地方可以用""+x代替。这里德x就是x.toString(),与toString不同的是,如果x是基本类型,这条语句照
样能够执行。
51、Object类定义了toString方法,用来打印输出对象所属的类名和散列码
52、toString方法是一种非常有用的调试工具,可以让用户能够获得一些有关对象状态的必要信息。
53、ArrayList在添加和删除元素时,具有自动调节数组容量的功能,而不需要编写任何代码;ArrayList是一个采用类型参数
(type parameter)的泛型类(generic class)。
54、Java老版本中使用Vector类实现动态数组,不过ArrayList更有效
55、JDK5.0以前的版本没有泛型类,因此ArrayList里允许接受任意类型的对象,编译器不会给出警告,只有在检索对象并试图对
它进行类型转换时,才会发现问题
56、由于每个值都分别包装在对象中,所有ArrayList<Integer>的效率远远低于int[]数组。
57、自动打包规范要求boolean、byte、char<=127、介于-128~127之间的short和int被包装到固定的对象中。例如如果a和b
被初始化为100,那么对他们进行比较,其结果一定是成了的。
58、打包盒拆包时编译器认可的,而不是虚拟机。编译器在生成类的字节码时,拆入必要的方法调用。虚拟机只是执行这些字节
码。
59、反射库(reflection libary)提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵Java代码的程序,这项功能
被大量地应用在JavaBeans中,它是Java组件的体系结构。
60、能够分析类能力的程序被称为反射(reflective),可以使用反射:在运行时分析类的能力;在运行时查看对象;实现数组的
操作代码;利用Method对象。使用它的主要对象是工具构造者,而不是应用程序员。
61、程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识,这个信息保存着每个对象所属的类足
迹。虚拟机利用运行时信息选择相应的方法执行。保存这些信息的类被称为Class。Object类中的getClass()方法返回一个Class类
型的实例。
62、鉴于历史原因,getName方法在应用于数组类型的时候会返回一个很奇怪的名字:Double[].class.getName()返回
[Ljava.lang.Double。int[].class.getName()返回[I。
63、虚拟机为每个类型管理一个Class对象。因此可以利用==实现两个对象比较。
64、可以使用newInstance()快速创建一个类的实例。newInstance调用默认的无参构造器初始化新创建的对象。如果没有默认
的构造器,抛出异常
65、java.lang.reflect包中有三个类Field、Method和Constructor分别用于描述类的域、方法和构造器。
67、查看对象域的关键是Field类中的get方法。如果f是一个Field类型的对象(例如通过getDeclaredFields得到的对象),obj
是某个包含f域的类的对象,那么f.get(obj)将返回一个对象,其值为obj域的当前值。
68、如果f是一个obj是一个私有域,则get方法将抛出一个ILLegalAccessException。
69、反射机制的默认行为受限于Java的访问控制。如果一个Java程序没有受到安全管理器的控制,调用Field、Method或
Constructor的setAccessible方法就可以覆盖访问控制。
70、setAccessible方法是AccessibleObject类中的一个方法,它是Field、Method和Constructor类的公共超类。这个特性是为
调试、持久存储和相似机制提供的。
71、Java.lang.reflect包中的Array类允许动态地创建数组。
72、建议仅在必要的时候,才使用Method对象,而最好使用接口和内部类。特别建议Java开发者不要使用Method对象的回调
功能。
73、继承设计技巧
1)将公共操作和域名放置在超类中
2)不要使用受保护的域(子类集合是无限制的,任何一个人都能够由某个类派生一个子类,并编写代码以直接访问
protected的实例域,破坏封装性;Java中,同一个包中的所有类都可以访问protected域,而不管它是否为这个类的子类)
3)使用继承实现is-a关系
4)除非所有继承的方法都有意义,否则不要使用继承
5)在覆盖方法时不要改变预期的行为
6)使用多态,而非类型信息
7)不要过多的使用反射
74、接口不是类,而是一组对类的需求描述,这些类要遵从接口描述的统一格式进行定义
75、接口不能使用new实例化一个接口,却能声明接口变量,接口变量必须引用实现了该接口的类对象。可以使用instanceof检
测一个对象是否实现了某个特定的接口。也可扩展接口。
76、接口中可以使用常量,接口中的域和方法自动地设为public static final
77、Cloneable接口只是作为一个标记出现,表面类的设计者知道要进行克隆处理。如果一个对象需要克隆,而没实现
Cloneable接口,会产生一个已检验异常(checked exception)
78、clone的默认是实现是浅拷贝
79、内部类(inner class)是定义在另一个类中的类。1)内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数
据;2)内部类可以对同一个包中的其他类隐藏起来;3)当想要定义一个回调函数且不想写大量代码时,使用匿名
(anonymous)内部类比较便捷。
80、如果内部类没有构造器,编译器将会对它进行修改,并添加一个外围类应用的参数。
81、利用代理可以在运行时创建一个实现了一组给定接口的心累。这种功能只在编译时无法确定需要实现哪个接口时才有必要使
用。
82、如果出现RuntimeException异常,就一定是自己的问题。
83、应该通过检测数组下标是否越界来避免ArrayIndexOutOfBoundsException异常;应该通过在使用变量之前检测是否为空来
杜绝NullPointerException异常的发生。
84、Java语言规范将派生于RuntimeException类或Error类的所有异常称为“未检查(unchecked)异常”,其他为“checked
异常”。编译器将核查是否为所有已检查异常提供异常处理器。
85、会抛出异常的情况:1)调用一个抛出已检查异常的方法;2)在程序运行过程中发现错误,并且利用throw语句抛出一个已
检查异常;3)程序出现错误;4)Java虚拟机和运行时库出现的内部异常。
86、不需要声明Java的内部错误(从Error继承的那些异常),也不应该声明从RuntimeException继承的那些未检查异常。
87、子类方法中抛出的异常范围更小或不抛异常;如果超类方法没有抛出任何已检查异常,那么子类也不能抛出任何已检查异常
。
88、1)找到一个合适的异常类;2)创建这个类的一个对象;3)将对象抛出
89、习惯上,定义的类应该包含两个构造器,一个是默认的构造器,另一个是带有详细描述信息的构造器
90、捕获那些知道如何处理的异常,而将不知道如何处理的异常传递出去。
91、包装异常: try{
access the database;
} catch(SQLException e) {
Throwable se = new ServletException("database error");
se.setCause(e);
throw se;
}
当捕获到异常时,可以使用下面这条语句得到原始异常:Throwable e = se.getCause();它允许用户抛出子系统中的高级异常,
而不会丢失原始异常的细节。
92、使用异常机制的建议:1)异常处理不能代替简单的测试。2)不要过分的细化异常;3)利用异常层次结构;4)不要忽略异
常;5)检测到错误时,苛刻要比放任更好;6)不要羞于传递异常
93、日志API的优点:1)可以很容易地取消全部日志记录,或者仅仅取消某个级别的日志,而且开启和关闭操作也很容易;2)
可以很简单地禁止日志的输出;3)日志记录可以被定向到不同的处理器,用于在控制台中显示,拥有存储在文件中等;4)日志
记录器和处理器都可以对记录进行过滤,过滤器可以根据过滤器实现器制定的标准丢弃无用的记录项;5)日志记录可以采用不
同的方式格式化,例如出文本或xml;6)应用程序可以使用多个日志记录器,他们实用类似包名的这种具有层次结构的名字;7
)在默认情况下,日志系统的配置由配置文件控制,如果需要的话,应用程序可以替换这个配置。
94、日志系统管理着一个名为Logger.global的默认日志记录器,如Logger.global.info("logInfo");如果在恰当的地方调用
Logger.global.setLevel(Level.OFF)则将会取消所有的日志。
95、可以自定义一个日志记录器:Logger myLogger = Logger.getLogger("cn.com.per.log");如果后面使用同一个名字调用日
志记录器就会产生相同的日志记录器对象。
96、通常有7个日志记录器级别:SEVERE/WARNING/INFO/CONFIG/FINE/FINER/FINEST,默认只记录前三个级别,可以用
logger.setLevel(Level.FINE)设置其他级别。,还可使用Level.ALL开启所有级别的记录,Level.OFF关闭所有级别的记录。记录方
法logger.warning(message)、logger.fine(message)或者logger.log(Level.FINE, message)
97、默认情况下,日志记录器将记录发送到ConsoleHandler中,并由它输出到System.err流中。
98、在一个具有自我防御能力的程序中,断言是一个常用的习语。
99、处理系统错误的三种机制:抛出异常、日志、使用断言。
100、使用断言应记住:断言失败是致命的、不可恢复的错误;断言检查只用于开发和测试阶段
101、断言是一种测试和调试阶段所使用的战术性工具,而日志记录是一种在程序的整个生命周期都可以使用的策略性工具。