Thinking In Java学习笔记

来源:互联网 发布:数字摄影测量软件 编辑:程序博客网 时间:2024/05/06 07:38

读一部分写一部分。

1、无限精度整数:BigInteger;无限精度小数:BigDecimal。

2、for-each循环:for(元素类型 元素名:容器名)。

3、输出二进制用包装类的(例:printBinaryInteger)方法。

4、参数类型相同,顺序不同也可触发重载,但不推荐使用。

5、标签标识符:标签名+:,仅用于跳出嵌套循环。continue 标签名 会到达标签位置并重新进入紧跟其后的循环;break 标签名 会到达标签位置,但不会进入紧跟其后的循环,实质上是跳出了所有循环(假设标签设置在最外层)。

6、涉及基本类型的重载:支持自动宽化(short-int),不支持自动窄化(int-short)(会报错)。

7、在构造器中可以用this(参数列表)调用另一个构造器,但必须将该语句放置在起始位置,且只能调用一个。

8、finalize()方法不等同于析构函数,它仅仅在调用了本地方法(C、C++等)的情况下才使用,用于人工恢复内存(同样要使用本地方法)。使用它的一个主要场合是用于验证对象终结条件。当对象可以被清理时,从逻辑上讲它必然会处于一种特定的状态(例如苹果被吃完),此时可在finalize()方法中进行判断,若非如此则可输出一行显示错误的代码(利用println、Log.i(android)等),这样就可以最终发现该种情况。

9、Java虚拟机只会在内存耗尽的情况下才会去执行垃圾回收以恢复内存。

10、局部变量未初始化编译器会报错;类成员未初始化会自动赋初值(false、0、null)。

11、Java中可以在定义类成员时赋初值,但是C++中不行。赋初值的方法有直接定值(基本类型)、使用new、调用方法等。

12、定义时赋初值发生在构造器之前,无论它们之间的相对位置如何。

13、成员初始化顺序:静态成员(首次使用时)——定义时赋初值——初始化块——构造器

14、可变参数列表使用:f(类名... 列表名),一般用for-each循环处理。可接受0个参数(多用于可变尾随参数,如果方法传入值需要用到可变参数,一般将其置于传入值列表最后)。可直接传入一个数组作为可变参数列表。

15、为避免歧义,一般只在重载方法的一个版本中使用可变参数列表。

16、protected同样提供包访问权限。

17、派生类初始化时会先调用基类的构造器,若基类没有默认构造器(无参构造器)则需要利用super关键词显式调用基类构造器,否则编译器会报错。

18、final修饰方法参数:只能读参数,不能改参数。

19、final修饰方法:禁止覆盖。

20、final修饰类:禁止继承。

21、final修饰基本数据类型:禁止修改值;修饰引用:禁止改变指向(指向的对象可以改变)。

22、若基类与导出类均有static成员变量,在第一次调用时是从基类的static成员变量开始初始化。

23、在导出类中,对于基类的private方法,最好采用不同的名字,因为这会对多态产生干扰(举例:基类A中private f()与导出类B中public f(),若调用语句A a = new B();a.f(),调用的是基类A中的f())。

24、静态方法不具有多态性。访问域同样无法多态(例如某个成员变量)。

25、若需设置清理方法,则应按照导出类——基类的顺序进行清理工作。

26、在构造器中应当尽可能地不要调用其他方法,特别是被覆盖的方法,这会导致难以预料的错误。

27、向下转型会产生ClassCastException。

28、接口中的方法只能是public的,实现接口时在接口内被定义的方法也只能是public的。

29、Adapter设计模式:接收传入接口,产生需要的接口

30、接口内的成员变量都是static final的,包括类。因此接口内的类只能是嵌套类。

31、若一个导出类同时继承了基类与接口,若基类与接口中含有相同(同名、同返回值,同参数)方法(注意基类不一定实现了该接口,且基类中该方法是public的),则可以视作导出类已经实现了该方法(不必显式说明)。

32、当生成一个内部类的对象时,此对象与制造它的外围对象就有了一种联系,因此它能够访问其外围对象的所有成员。内部类可通过 外部类名.this 获取外部类对象的引用。

33、利用内部类实现接口提供对操作外部类的方法给其他类使用,此时的内部类叫做闭包(closure)。这是实现回调的一种方法。

34、要想直接创建内部类的对象,必须使用(外部类的对象(非外部类名).new 内部类名()的方式。

35、内部类可以在方法以及作用域(if等)内定义。

36、若匿名内部类需要使用在其外部定义的对象,那么需要将这个对象设置成final的。

37、匿名类的初始化可以利用初始化块的方式实现。

38、接口内部不能直接放置代码,但可以放置内部类并实现一些方法,甚至实现接口本身。这可以用于创建一些公共代码。

39、若一个类继承自一个另一个类的内部类,那么这个类的构造函数必须传入那个外部类的一个对象引用,并在构造函数中调用其super()方法。

40、使用局部内部类而不是匿名内部类的一个理由:需要不只一个该内部类的对象。

41、利用泛型定义的容器中可放置对应类型的子类。

42、在容器内添加一组元素的方式:(1)利用Collection类的构造函数,接收用逗号分隔的一组元素或是一个List对象(2)利用Collection类的addall()方法(3)利用Collections类的addall(collection,element)静态方法。

43、Arrays.asList()方法返回的List对象底层为数组,在增删元素时可能产生问题,使用时应将其作为一个输入值传入一个collection中。

44、Iterator()通用方法:(1)next()获取下一个元素(第一次使用时返回的是首个元素)(2)hasNext()判断是否还有下一个元素(3)(可选)remove()删除最近由next()返回的一个元素,必须在使用过next()的情况下使用。

45、遍历Iterator通用方法:if(iterator.hasNext()) it.next();

46、实现Iterable<T> 接口允许类被用于foreach语句中(foreach语句接受任意实现了Iterable<T>的类的对象)。

47、若想实现自定义容器,可通过继承AbstractCollection类实现。

48、利用throw重新抛出异常,printStackTrace()方法的路径不变。要想更新这个信息,可以调用fillInStackTrace()方法,返回一个Throwable对象,并将其转型为Exception并抛出,或者是抛出一个新异常(利用new创建)。

49、异常链通过Throwable提供的initCause()方法实现。

50、只能在代码中忽略RuntimeException及其子类类型的异常,其他类型的异常处理由编译器强制实施。

51、无论异常是否抛出,finally语句总能得到执行。

52、即便是涉及到break、continue、甚至return语句,finally语句也会得到执行。因此可将清理工作至于其内。

53、当覆盖方法的时候,只能够抛出在基类方法的异常说明里面列出的那些异常。(void f() throws ...)。构造器不受这个限制,派生类构造器可以抛出任何异常,但必须包括基类构造器的所有异常。

54、创建需要清理的对象的通用方法:在创建需要清理的对象之后,立即进入一个try-finally语句块,并在finally中加入清理语句。典型应用:开闭输入输出流。

55、异常使用指南(在以下情况下使用异常):
    (1)在恰当的级别处理问题。
    (2)解决问题并且重新调用产生异常的方法。
    (3)进行少许修补,然后绕过异常发生的地方继续执行。
    (4)用别的数据进行计算,以代替方法预计会返回的值。
    (5)把当前运行环境下能做的事情尽量做完,然后将相同或不同的异常抛出到更高层。
    (6)终止程序。
    (7)简化异常模式。

56、Exception的构造函数有无参与单个字符串参数两种。自定义时可利用super()。

57、拼接较大的字符串使用StringBuilder类。

58、%后加-代表左对齐(不足右边补空格),不加默认右对齐(不足左边补空格)。

59、构建格式化字符串利用String类的静态方法format,用法与C类似。

60、利用正则表达式分割字符串(split()方法)时,与正则表达式匹配的部分在结果中都不存在了。

61、构建正则表达式思路:构建正则表达式内容(本质)——思考如何在Java中输出该字符串(表象)。思考时要明确地将两步分离开。

62、正则表达式中匹配单个\要用\\\\(四个),原理同上(正则表达式中需要用\\表达匹配一个\,输出成字符串每个\需要用\\来表示)。

63、正则表达式量词:
    X? 一个或零个X;
    X* 零个或多个X;
    X+ 一个或多个X;
    X{n} 恰好n个X;
    X{n,} 至少n个X;
    X{n,m} 至少n个,不超过m个X。
这里的X可以是单个字符,也可以是用()包裹的多个字符。
量词默认为贪婪型(尽可能多的匹配),后加?为勉强型(尽可能少的匹配)。
注意:贪婪或勉强都要建立在有多种匹配方式的条件下,即不存在贪婪性能够匹配,而勉强性不能够匹配的情况。例:Never give up!用"Neve.*?!"可以匹配。

64、字符类:
    [abc] a、b 或 c(简单类);
    [^abc] 任何字符,除了 a、b 或 c(否定);
    [a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围);
    [a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集);
    [a-z&&[def]] d、e 或 f(交集);
    [a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去);
    [a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去);
    . 任何字符(与行结束符可能匹配也可能不匹配);
    \d 数字:[0-9] ;
    \D 非数字: [^0-9];
    \s 空白字符:[ \t\n\x0B\f\r];
    \S 非空白字符:[^\s] ;
    \w 单词字符:[a-zA-Z_0-9](注意包括_);
    \W 非单词字符:[^\w] ;
    \p{Lower} 小写字母字符:[a-z];
    \p{Upper} 大写字母字符:[A-Z];
    \p{ASCII} 所有 ASCII:[\x00-\x7F];
    \p{Alpha} 字母字符:[\p{Lower}\p{Upper}];
    \p{Digit} 十进制数字:[0-9];
    \p{Alnum} 字母数字字符:[\p{Alpha}\p{Digit}];
    \p{Punct} 标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ;
    \p{Graph} 可见字符:[\p{Alnum}\p{Punct}];
    \p{Print} 可打印字符:[\p{Graph}\x20];
    \p{Blank} 空格或制表符:[ \t];
    \p{Cntrl} 控制字符:[\x00-\x1F\x7F];
    \p{XDigit} 十六进制数字:[0-9a-fA-F];
    \p{Space} 空白字符:[ \t\n\x0B\f\r];

65、反斜线字符 ('\') 用于引用转义构造,同时还用于引用其他将被解释为非转义构造的字符。因此,正则表达式 \\ 与单个反斜线匹配,而 \{ 与左括号匹配(正则表达式中有特殊含义)。在不表示转义构造的任何字母字符前使用反斜线都是错误的,它们是为将来扩展正则表达式语言保留的;可以在非字母字符前使用反斜线,不管该字符是否非转义构造的一部分。

66、正则表达式"\n"、"\\n"、"\\\n"都可与字符串"\n"匹配,原理如下:
    一个\:传递一个\n字符用于匹配;
    两个\:正则表达式中为"\n",表示换行符;
    三个\:正则表达式中为"\\n",见65条。
关键点:正则表达式中的"\n"与字符串中的"\n"都表示换行符。

67、匹配单词要用\b单词\b,避免部分重叠,例如hi history high。
边界匹配器
    ^ 行的开头;
    $ 行的结尾;
    \b 单词边界;
    \B 非单词边界;
    \A 输入的开头;
    \G 上一个匹配的结尾;
    \Z 输入的结尾,仅用于最后的结束符(如果有的话);
    \z 输入的结尾。
注意:边界匹配器匹配的都是“位置”而不是某个字符。
例:\bhi\b匹配的是单个hi单词,\shi\s匹配的是 hi 。

68、Pattern与Matcher构建方法:
    (1)利用Pattern类的静态方法compile()传入正则表达式,构建Pattern对象;
    (2)利用Pattern类的方法matcher()传入用于匹配字符串,构建Matcher对象;
    (3)利用matcher类的方法reset()改变用于匹配的字符串。
使用方法:
    (1)利用Matcher类的方法find()寻找下一个匹配的子序列,并用start()与end()方法获取子序列索引。
    (2)利用Matcher类的方法group()获取在上一次匹配操作中(例:find())由指定组捕获的子序列。注意:因为整个子序列默认为第0组,因此实际组数=括号对数+1,因此在循环时条件应为i<=matcher.groupCount()(小于等于)。
    (3)利用appendReplacement(StringBuffer sb,String replacement)一步步进行替换并保存。需要配合find()进行,每次将从开始位置到匹配替换结束位置的子序列添加入sb中。例:"a b c d e"利用appendReplacement(sb,"x")替换" "过程:ax-axbx-axbxcx-axbxcxdx,最后使用appendTail(sb)后结果为axbxcxdxe。
    (4)利用appendTail(StringBuffer sb)将未匹配的剩余部分添加进sb中。

69、正则表达式中的组(group):用括号划分的正则表达式。例:A(B(C))D ABCD为组0,BC为组1,C为组2。

70、Pattern标记:
    Pattern.CANON_EQ:
    当且仅当两个字符的"正规分解(canonical decomposition)"都完全相同的情况下,才认定匹配。比如用了这个标志之后,表达式"a/u030A"会匹配"?"。默认情况下,不考虑"规范相等性(canonical equivalence)"。
    Pattern.CASE_INSENSITIVE (?i)(?-i):
     默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。这个标志能让表达式忽略大小写进行匹配。要想对Unicode字符进行大小不明感的匹配,只要将UNICODE_CASE与这个标志合起来就行了。
    Pattern.COMMENTS (?x)(?-x):
     在这种模式下,匹配时会忽略(正则表达式里的)空格字符(注:不是指表达式里的"//s",而是指表达式里的空格,tab,回车之类)。注释从#开始,一直到这行结束。可以    通过嵌入式的标志来启用Unix行模式。
    Pattern.DOTALL (?s)(?-s):
     在这种模式下,表达式'.'可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式'.'不匹配行的结束符。
    Pattern.MULTILINE (?m)(?-m):
     在这种模式下,'^'和'$'分别匹配一行的开始和结束。此外,'^'仍然匹配字符串的开始,'$'也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
    Pattern.UNICODE_CASE (?u)(?-u):
     在这个模式下,如果你还启用了CASE_INSENSITIVE标志,那么它会对Unicode字符进行大小写不明感的匹配。默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。
    Pattern.UNIX_LINES (?d)(?-d):
     在这个模式下,只有'/n'才被认作一行的中止,并且与'.','^',以及'$'进行匹配。

71、    (?:pattern)
     匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
    (?=pattern)
     正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
    (?!pattern)
     负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始

72、可用String类的方法format()模拟C中sprintf()函数。

73、扫描复杂字符串(例如.txt)可利用Scanner类。支持正则表达式扫描。步骤:scanner.next(regex);-MatchResult match = scanner.match();

74、可以使用类名.class获取特定类的Class对象引用。如果已经有了一个特定类的实例,则可利用对象的getClass()方法。

75、使用Class类的方法newInstance()的前提条件是类拥有默认构造器。调用该方法会得到InstantiationException与IllegalAccessException两种异常。

76、a instanceof B 返回一个布尔值,代表a是否是B的实例(A是B的派生类也成立)。B只能是命名类型而不能是Class对象。实际使用时多用Class类的方法isInstance()。

77、若将泛型语法<?>用于Class对象,那么newInstance()将返回确切类型,而不是Object。

78、Class类方法a.isAssignableFrom(Class b):若a是b的父类或a与b属于同一个类则返回true。

79、利用File类方法list()或者listFiles()获取目录下所有文件的信息。注意:File对象需指向一个目录,若指向的是某个文件则需要调用getParentFile()方法。若需要提取具有特定扩展名的文件,可利用list(FilenameFilter)方法,提供FilenameFilter接口进行过滤。

80、在switch()语句中使用枚举类型时,case后不必使用enum.XXX,直接使用XXX即可。

81、编译器自动会为每个enum类添加一个静态方法values(),可用循环遍历enum类所有内容。

82、可利用Class类的方法getEnumConstants()方法获取enum类内容。

83、所有enum类都继承自Enum类,因此不能再继承其他类,但可以实现接口。

84、利用泛型实现方法返回多个对象:
public class TwoTuple<A,B>{
    public final A first;
    public final B Second;
    public TwoTuple(A a,B b) {first = a;second = b;}
}

85、定义泛型方法需要将泛型参数列表置于返回值之前。

86、使用泛型类时,必须在创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不必指明参数类型,因为编译器会为我们找出具体的类型。

87、可以显式指定泛型方法的类型,做法是在点操作符与方法名之间插入泛型参数列表。

88、在泛型代码内部,无法获得任何有关泛型参数类型的信息。

89、泛型类型参数将擦除到它的第一个边界,并将类型参数替换为它的擦除。例:List<T>将被擦除为List,普通变量被擦除为Object。

90、在泛型中创建数组推荐使用Array.newInstance()。

91、若泛型代码中需要知道确切类型信息,则必须传入类型的Class对象。若需创建示例对象,推荐使用工厂模式,传入支持泛型的工厂对象。

92、成功创建泛型数组的唯一方式是创建一个被擦除类型的新数组,然后将其转型为泛型数组。实际使用中一般利用List代替数组。

93、实现“枚举的枚举”的方法:在一个enum内部定义接口,接口内定义若干个实现了该接口的enum,外部enum的成员构造器传入接口内部enum对应的class对象。

原创粉丝点击