1. *.java源代码 ---> 使用javac编译 ---> 生成*.class字节码文件 ---> 使用java解释执行 ---> 特定平台的机器码
2.JRE包含了JVM,JVM是Java程序的核心虚拟机,但运行Java程序不仅需要核心虚拟机JVM,还需要其他的类加载器、字节码校验器以及大量的基础类库。总的来说,JRE除了包含JVM之外,还包含运行Java程序的其他环境支持。
3.JDK包含了JRE,如需开发Java程序,则必须安装JDK;如只是运行Java程序,可以只安装JRE而无须安装JDK。
4.安装JDK只需选择安装JDK的两个组件即可:1.Development Tools 2.Source Code
不用安装Public JRE(公共JRE)。公共JRE是一个独立的JRE系统,它会向IE浏览器和系统中注册Java运行时环境,这样可以使系统中任何应用程序都可以使用公共JRE。由于我们完全可以选择JDK下的JRE来运行Java程序,因此没有必要安装额外的公共JRE。
5.Windows中,环境变量Path和PATH没有区别;而Linux中是区分大小写的,在Linux中只需设置好PATH即可。
6.用户变量只对当前用户有效,而系统变量对所有用户有效。
7.当使用JDK1.5以上版本时,无须设置CLASSPATH环境变量。CLASSPATH用于指定JRE搜索Java类的路径,此外,编译和运行Java程序还需要JDK的lib路径下dt.jar和tools.jar文件中的Java类,因此也需要将这两个文件加到CLASSPATH环境变量当中。如果指定了CLASSPATH,一定不要忘记在CLASSPATH开头加一个点(.)代表当前路径,用以强制Java解释器在当前路径下搜索Java类。
8.一个Java源文件可以包含多个类定义,但只能有一个定义为Public,且该文件的文件名必须与这个Public类的类名相同。
9.Java8删除了HotSpot JVM中的永生代内存(PermGen,永生代内存主要用于存储一些需要常驻内存,通常不会被回收的信息),而是改为使用本地内存来存储类的元数据信息,并将之称为:元空间(Metaspace),这意味着以后不会再遇到Java.lang.OutOfMemoryError:PermGen错误(曾经令许多Java程序员头痛的错误)。
10.浮点类型默认是double类型,如需将一个浮点数当成float类型处理,应用f或者F。如:5.21f。
11.错例: float a = 5.6 ;
正例:float a = 5.6 f; 或者 float a = (float)5.6 ;
12.Java还提供了三个特殊的浮点数值:正无穷大、负无穷大、非数,用于表示溢出和出错。例如,用一个正浮点数除以0得到正无穷大,使用一个负浮点数除以0得到负无穷大,0.0除以0.0或者对一个负数开方将得到一个非数。正无穷大通过Double或者Float类的POSITIVE_INFINITY表示;负无穷大通过NEGATIVE_INFINITY表示;非数通过NAN表示。注意,只有浮点数除以0才可以得到正负无穷大,因为Java程序在进行浮点数运算时会自动将除数0当成浮点数0.0来处理,若用一个整数除以0,则会抛出异常:Arithmetic Exception:/by zero。
13. 3+4+"Hello" 输出:7Hello
"Hello"+3+4 输出:Hello34
思考一下?
14.表达式类型的自动提升规则:
1.所有的byte类型、short、char 将被提升到int类型。
2.整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型。操作数的等级排列如下所示:
byte --> char、short --> int --> long --> float --> double
15. "Hello" + 'a' + 7 输出:Helloa7
'a' + 7 + "Hello" 输出:104Hello
思考:表达式最左边的'a'自动提升到int类型,变成'a'对应的ASCII值:97。
16. String s0 = "hello";
String s1 = "hello";
String s2 = "he" + "llo";
s0 == s1 //true
s0 == s2 //true
思考一下?
17. Switch支持的数据类型只能是byte、short、char、int、枚举类型以及String类型,其中String类型从Java7开始才被支持。
18.数组初始化的两种写法:
1. int[] arry = new int[] {1,2,3};
2. int[] arry = {1,2,3};
19. 当一个方法执行时,每个方法都会建立自己的内存栈,所有在方法中定义的局部变量都将被放入栈内存;运行时数据区为堆内存,因为对象的创建成本比较大,因此将对象放入的时堆内存,以便反复利用。栈内存随着方法的结束被销毁,而堆内存不会。只有当堆内存中的对象不再被任何引用变量引用时,垃圾回收器才会在合适的时候回收它。
20.Java8增强的工具类:Arrays增加了并发支持,充分利用了CPU性能。
21.Static修饰的成员不能访问没有Static修饰的成员。
22.若程序员没有编写构造器,则系统提供一个默认的无参构造器;一旦程序员提供了构造器,则系统不再提供默认的无参构造器。
23.类的修饰符可以是public、default(不指定时默认)、final、abstract。
24.构造器的返回值类型总是当前类,因此无须定义返回值类型,不需在构造器中显示使用return来返回当前类的对象,因为构造器的返回值是隐式的。
25.JDK1.5之后,Java允许定义形参个数可变的参数。在最后一个形参的类型后增加三点(...)表明该形参可以接受多个参数值,多个参数值被当作数组传入。例如:public void test (int a, String ... books);注意:个数可变的形参只能处于形参列表的最后,且一个方法中最多只能有一个个数可变的形参。由于个数可变的形参本质上是一个数组,因此调用的时候,既可以传入多个参数,也可以传入一个数组。
26.递归方法定义时,必须确保在某个时刻(条件)下该方法返回的值是确定的。
27.不推荐重载形参个数可变的方法。
28.类变量尽量由类访问,而不是通过实例,以提高程序可读性与明确性。
29.高内聚,低耦合:尽可能把模块的内部数据、功能实现细节隐藏在模块内部独立完成,不允许外部直接干预,仅暴露少量的方法供外部使用。
30.JDK1.5以后增加了静态导入,用于导入指定类的静态成员变量和方法,如下:
import static java.lang.Math.*;
31.super 调用父类构造器,仅能出现在子类构造器执行体第一行。
32.子类可以继承父类的成员变量和方法,但受访问权限的限制可能不能直接访问。
(貌似除了父类的构造器不能继承外,其余都能继承)
33.初始化块的修饰符只能是static,使用static修饰的初始化块被称为静态初始化块。
34.初始化块只在创建Java对象时隐式执行,且在执行构造器之前执行。注意:尽量把多个初始化块合并为一个,让程序更简洁。
35.JDK1.5开始提供自动装箱、拆箱。
36.instanceOf,当前面对象是后面类的实例或其子类的实例时都返回true。
37.接口中的方法默认就是public abstract,接口中的成员变量默认就是public static final。
38.Java8允许在接口中定义默认方法,默认方法必须使用default修饰,该方法不能使用static修饰。
39.枚举类:enum定义的枚举类默认继承java.lang.Enum类,而不是Object类,因此枚举类不能显示继承其他父类。
40.非抽象的枚举类默认为final,因此也不能被继承。
41.枚举类的构造器只能是private。
42.枚举类的所有实例必须在枚举类的第一行显式列出,否则这个枚举类永远都不能产生实例。这些实例默认就是public static final,无须显示添加,通过枚举类默认提供的values()方法可以方便地遍历所有的枚举值。注意:当使用System.out.println()来打印枚举值时,实际上输出的是该枚举值的toString()方法,即该枚举值的名称。
43.强制系统进行垃圾回收有如下两种方式:
1.System.gc(); 2.Runtime.getRuntime().gc();
这种强制只是通知系统进行垃圾回收,但系统是否进行垃圾回收依然不确定,但大部分时候总会起到一点效果。
44.JAR文件的全称是 Java Archive File,即Java档案文件;
WAR文件的全称是 Web Archive File;
EAR文件的全称是 EnterPrise Archive File。
45.Scanner : .hasNext(); .next();
.hasNextLine(); .nextLine();
46.通过System.loadLibrary()或Runtime.loadLibrary()加载动态链接库文件(通常用于访问底层硬件设备,Java程序无法实现,借助如C语言实现的方法)。
47.System.CurrentTimeMillis(),毫秒.
48.System.setIn()、setOut()、setErr()来改变系统的标准输入、输出以及错误输出流。
49.当某个类的hashCode()方法被重写之后,该类实例的hashCode()方法就不能唯一地标识该对象;但通过System.identityHashCode(Object x)返回的hashCode值可以唯一标识该对象(这个值是根据对象的地址计算得到的)。
50.每个Java程序都有一个与之对应的Runtime实例,通过getRuntime()方法获取与之关联的Runtime对象。Runtime类除了可以访问JVM相关信息,还可以单独启动一个进程来运行操作系统的命令,如:
Runtime rt = Runtime.getRuntime();
rt.exec("notepad.exe");
51.实现"克隆"的步骤:
1.实现Cloneable接口(该接口是个标记性接口,该接口里并没有定义任何方法);
2.自定义类中实现自己的clone()方法;
3.在clone()方法中直接调用super.clone()即可。
52.Object的clone()方法虽然简单易用,但它只是浅克隆(只克隆对象的所有成员变量值,不会对引用类型的成员变量值所引用的对象进行克隆,如果需要进行深克隆,则需开发者自行递归克隆)。
53.Java7新增的Objects类提供的方法大多是"空指针"安全的。
54.JDK1.5新增StringBuilder,StringBuilder与StringBuffer基本相似,不同的是StringBuffer是线程安全的,而StringBuilder是非线程安全的,所以StringBuilder性能略高。因此,通常情况下应该优先考虑使用StringBuilder。
55.Random生成的是伪随机数,它有两个构造器:一个构造器使用默认的种子(以当前时间作为种子),另一个构造器需要显式传入一个long型整数的种子。
56.ThreadLocalRandom是Java7新增的一个类,它是Random的增强版,且线程安全,通过current()方法来获取ThreadLocalRandom对象,随后即可调用各种.nextXXX()方法来获取伪随机数(如浮点型的、整数型的,还可以指定随机数的范围)。
例子:.nextInt(26); //生成0~26之间的伪随机数整数
57.若两个Random对象种子相同时,它们会产生相同的数字序列,注意:当使用默认的种子构造Random对象时,它们属于同一个种子。
58.为避免两个Random对象产生相同的数字序列,通常推荐使用当前时间作为Random对象的种子,如下:
Random rand = new Random(System.CurrentTimeMillis());
59.应使用BigDecimal进行浮点运算,以防止精度丢失。
60.通常建议优先使用基于String的构造器,如下:
错例:new BigDecimal(0.1); //实际上只能等于一个近似0.1的数
正例:new BigDecimal("0.1"); //正好等于预期的0.1
61.如果必须使用浮点数作为BigDecimal构造器的参数时,不应直接使用该数字作为参数构建对象,而应通过BigDecimal.valueOf(double value)来创建BigDecimal对象,否则会造成精度丢失的问题。
62.除不尽时,精确到小数点后10位的四舍五入写法:
public static double div(double v1, double v2) {
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.divide(b2, DEF_DIV_SCALE,BigDecimal.ROUND_HALF_UP).doubleValue();
}
63.Java原本提供的Date.Calendar用于处理日期不太方便:
1.Date无法实现国际化;
2.Date对不同属性使用了前后矛盾的偏移量,比如月份与小时都从0开始,而月份中的天数则从1开始,而年又是从1900开始
3.用java.util.Calendar则又显得过于复杂。
64.Java8提供了一套全新的日期时间库,在java.time包下。
65.Date类中绝大部分构造器与方法都已过时,不推荐使用。
66.基础正则语义:
$ : 匹配一行的结尾。如要匹配$本身,则使用\$
^ : 匹配一行的开头。
* : 零次或多次。
+ :一次或多次(即最少一次)。
? : 零次或一次(即最多一次)。
. : 匹配除换行符\n之外的任意单个字符。
| : 指定两项之间任选一项(二选一)。
\d : 匹配所有0~9的数字。
\D : 匹配非数字。
\s : 匹配所有空白字符。
\S :匹配所有非空白字符。
\w : 匹配所有单词字符,包括0~9的所有数字、26个英文字母和下划线_。
\W : 匹配所有的非单词字符。
67.Java集合大致可分为Set、List、Queue、Map四种体系。其中Set代表无序、不可重复的集合;List代表有序、可重复的集合;Map代表具有映射关系的集合;Java5又新增Queue体系,代表一种队列集合的实现。
68.遍历集合删除元素时,只能通过迭代器iterator.remove()进行删除元素,而不能通过remove()来删除,否则会引发异常。用JDK1.5提供的foreach循环也不行。
69.如果试图将两个相同的元素加入同一个Set中,则添加操作add()方法会返回false,即添加失败。
70.HashSet是一个非线程安全的,通过对象的HashCode()方法获取HashCode值,根据该值决定其存储位置,若两个对象通过equals()方法相比较为true,但HashCode值不同,依然可以添加成功,因为存储位置不同。
71.hash算法的功能是,它能保证快速查找被检索的对象,hash算法的价值在于速度。
72.LinkedHashSet与HashSet的区别在于有序,次序与添加时的顺序相同,通过链表来维持内部顺序。
73.TreeSet与HashSet的区别:TreeSet中的元素处于排序状态,但是采用红黑树的数据结构来存储元素的。TreeSet支持两种排序方法:自然排序和定制排序。在默认情况下为自然排序,即TreeSet会调用元素的CompareTo方法来比较元素之间的大小,然后升序排序。如果CompareTo方法返回0,即相等,TreeSet则会判断两个对象相等,不予插入。
74.使用TreeSet注意:只能添加同一类型对象,并且实现Comparable接口。
75.HashSet比TreeSet性能好,只有当需要保持排序的Set时才使用TreeSet。EnumSet是所有Set实现类中性能最好的,HashSet、TreeSet、EnumSet都不是线程安全的。如需保证线程安全,有两种方法:
1.手动保证同步;
2.通过Collections工具类的SynchronizedSortedSet方法来"包装"该Set集合。
76.List还提供了一个listIterator()方法,该方法返回一个ListIterator对象。ListIterator接口继承了Iterator接口,在Iterator的基础上增加了如下方法:
1. boolean hasPrevious();
2. Object previous();
3. void add(Object o);
77.ArrayList和Vector都是基于数组实现的,他们的显著区别是:ArrayList是线程不安全的,Vector则是线程安全的。即使这样,也并不推荐用Vector,Vector是一个过时的类。
78.工具类Arrays提供的asList(Object ... a)方法,可以把一个数组或指定个数的对象换成一个List集合,得到的集合是Arrays的内部类ArrayList的实例,而Arrays.ArrayList是一个固定长度的List集合,只能遍历,不可增加、删除,任何试图增加、删除其中元素的操作都会引发UnSupportedOperationException异常。
79.Hashtable线程安全,不允许null作key和value,已过时;
HashMap非线程安全,允许null作key和value。
80.即使需要使用线程安全的Map实现类,也无须使用Hashtable,可以使用Collections工具类将HashMap包装为线程安全的。
81.Properties类是Hashtable类的子类,Properties类可以把Map对象和属性文件关联起来,从而可以把Map对象中的key-value对写入属性文件中,也可以把属性文件中的"属性名=属性值"加载到Map对象中来。
82.对于一般的场景,程序应该多考虑使用HashMap,因为HashMap正是为快速查询而设计的,如果程序需要一个总是排好序的Map时,则可以考虑使用TreeMap。
83.Java源码就是先实现了HashMap、TreeMap等集合,然后通过包装一个所有value都为null的Map集合从而实现了Set集合类。
84.Collections工具类提供的常用的排序方法:
1.void reverse(List list); //反转元素顺序
2.void shuffle(List list); //随机排序(模拟"洗牌")
3.void sort(List list); //升序排序
......
85.Collections工具类还提供了用于查找、替换集合元素的方法,例如:
1.int binarySearch(List list, Object key); //使用二分搜索法,前提是list中的元素已经处于有序状态。
......
86.Collections工具类还提供了多个SynchonizedXXX()方法用以将指定的集合包装成线程安全的集合。
87.Collections工具类还提供了三类方法来返回一个不可变的集合(只读版本):
1.emtyXXX();
2.singletonXXX();
3.unmodifiableXXX();
88.Enumeration接口是Iterator的"古老版本",之所以还保留了下来,是为了照顾以前的"古老程序",如Vector及其子类Stack、Hashtable、BitSet,这些古老的集合类,可以用Enumeration来遍历,对于ArrayList、HashMap等,已不再支持使用Enumeration。
89.JDK1.5增加泛型支持,在很大程度上都是为了让集合能记住其元素的数据类型。在没有泛型之前,一旦把一个对象丢进集合中,集合就会忘记对象的类型,把所有的对象当成Object类型处理。当程序从集合中取出对象后,就需要进行强制类型转换,这种强制类型转换不仅使代码变得臃肿,而且容易引起classCastException异常。增加了泛型支持后的集合,完全可以记住集合中元素的类型,并可以在编译时检查集合中元素的类型,如果试图向集合中添加不满足类型要求的对象,编译器就会提示错误。增加了泛型支持后的集合,可以让代码更加简洁,程序更加健壮。除此之外,Java泛型还增强了枚举类、反射等方面的功能。
90.Java7开始支持的简化写法:
List strList = new ArrayList<>();
Map map = new HashMap<>();
91.Map的key不允许重复,即同一个Map对象的任何两个key通过equals()方法比较总是返回false。
92.Java程序中测试两个变量是否相等有两种方法:== 和 equals()方法。当使用==来判断两个变量是否相等时,如果两个变量是基本类型,且都是数值类型(不一定要求数据类型严格相同),则只要两个变量的值相等就返回true,但对于两个引用类型的变量,只有它们指向同一个对象时,==判断才会返回true。注意:==不可用于比较类型上没有父子关系的两个对象。
例如: int it = 65;
fload f1 = 65.0f;
it == f1 //true
char ch = 'A';
it == ch //true
"hello" == new Test() //会编译报错
在很多时候,程序判断两个引用变量是否相等时,也希望有一种类似于"值相等"的判断规则,并不严格要求其指向同一个对象,此时就用equals()方法。equals()方法是Object类提供的一个实例方法,其实使用这个方法判断两个对象相等的标准与使用==没有区别,同样都是要求两个引用变量指向同一个对象才会返会true,因此如果希望采用自定义的相等标准,则需要重写equals()方法。例如,String类已经重写了equals()方法。
93.只有try块是必须的,但catch块和finally块至少出现其一。
94.除非在try块、catch块中调用了退出虚拟机的方法(System.exit(1);),否则不管在try块、catch块中执行怎样的代码,即使使用了return,finally块也总是会被执行。
95.当在try块、catch块中遇到了return或者throw语句,程序会去寻找流程中是否包含finally块,如无,则程序会立即执行return或者throw语句,方法终止;如有,则立即执行finally块,直到finally块执行完毕后,程序才会返回执行刚才遇到的return或者throw语句。如果在finally块中也使用了return或者throw等导致方法终止的语句,则finally块就会直接终止方法,不会返回去执行之前的任何代码了,所以,尽量避免在finally块中使用return或者throw等导致方法终止的语句,否则可能导致出现一些很奇怪的情况。
96.如果程序员不手动处理异常,交于JVM自行处理的话,JVM会打印异常的跟踪栈信息,并终止程序运行。
97.如需在程序中自行抛出异常,则应使用throw语句,throw抛出的是一个异常类的实例,且每次只能抛出一个异常实例。
98.异常处理机制的初衷是将不可预期异常的处理代码和正常的业务逻辑处理代码分离,因此绝不要使用异常处理来代替正常的业务逻辑判断。另外,异常机制的效率也比正常的流程控制效率要差。
99.不要使用过于庞大的try块,因为会导致分析异常原因变得非常困难。
100.不要忽略捕获到的异常。