-
u是转义序列,一定要当心注释中的 u。注释
// u000A is a newline
会产生一个语法错误, 因为读程序时 u000A会替换为一个换行符类似地,下面这个注释
// Look inside c:users
也会产生一个语法错误, 因为 u 后面应该跟着 4 个十六进制数 -
尽管 $ 是一个合法的 Java 字符, 但不要在你自己的代码中使用这个字符。它只用
在 Java 编译器或其他工具生成的名字中。 -
可以在一行中声明多个变量:
int i , j // both are integers
不过,不提倡使用这种风格。逐一声明每一个变量可以提高程序的可读性。 -
需要注意, 整数除0将会产生一个算术异常
(java.lang.ArithmeticException: / by zero)
而浮点数除0除将会得到无穷大(Infinity)
或NaN
结果。 -
在默认情况下, 虚拟机设计者允许对中间计算结果采用扩展的精度(double64,但寄存器80位)。
但是, 对于使用 strictfp 关键字标记的方法必须使用严格的浮点计算来生成可再生的结
例如,可以把 main 方法标记为
public static strictfp void main(String[] args)
于是,在 main 方法中的所有指令都将使用严格的浮点计算。如果将一个类标记为
strictfp, 这个类中的所有方法都要使用严格的浮点计算。 -
下列返回类型都是dobule
Math.sqrt(4) //2.0 Double Math.pow()
-
虚线表示转换时会损失精度,int转float会损失精度,精度和大小是不同的概念
-
位运算符
处理整型类型时,可以直接对组成整型数值的各个位完成操作。这意味着可以使用掩码
技术得到整数中的各个位。位运算符包括:
&("and") |("or") ^("xor") ~("not")
应用在布尔值上时, & 和丨运算符也会得到一个布尔值。不过 & 和丨运算符不采用“ 短路” 方式来求值, 而是两个操作数都需要计算。
>>
和<<
运算符将位模式左移或右移。需要建立位模式来完成位掩码时, 这两个运算符会很方便:
int fourthBitFromRight = (n & (1« 3)) » 3
;
最后>>>
运算符会用 0 填充高位,这与>>
不同,它会用符号位填充高位。不存在<<<
运算符。
警告: 移位运算符的右操作数要完成模 32 的运算(除非左操作数是 long 类型, 在这种情
况下需要对右操作數模 64 )。
例如,1 << 35
的值等同于1 << 3
或 8。 -
如果虚拟机始终将相同的字符串共享, 就可以使用=运算符检测是否相等。但实际上
只有字符串常量是共享的,而 + 或 substring 等操作产生的结果并不是共享的。String greeting = "Hello"; //initialize greeting to a string if (greeting == "Hello") . // true if (greeting.substring(0, 3) == "Hel") . . . // false String i = "H"; String j = "Hi"; System.out.println(i+"i" ==j);//false String i = "H"+"i"; String j = "Hi"; System.out.println(i ==j);//true
-
在 Java 中, 允许数组长度为 0。在编写一个结果为数组的方法时, 如果碰巧结果为空,则这种语法形式就显得非常有用。此时可以创建一个长度为 0 的数组:
new elementType[0]
注意, 数组长度为 0 与 null 不同。 -
类的成员变量中有对象类型,那么可能会破坏封装性:越过类中方法,直接调用对象方法改变对象状态。如果需要返回一个可变对象的引用, 应该首先对它进行克隆(clone )。对象 clone 是
指存放在另一个位置上的对象副本。 下面是修改后的代码:class Employee { public Date getHireDayO { return (Date) hireDay.cloneO; // Ok }
凭经验可知, 如果需要返回一个可变数据域的拷贝,就应该使用 clone。
-
final 修饰符大都应用于基本 (primitive ) 类型域,或不可变(immutable) 类的域(如果类
中的每个方法都不会改变其对象, 这种类就是不可变的类。例如,String类就是一个不可变
的类)。
对于可变的类, 使用 final 修饰符可能会对读者造成混乱。例如,
private final StringBuiIcier evaluations
;
在 Employee 构造器中会初始化为
evaluations = new StringBuilder()
;
final 关键字只是表示存储在 evaluations 变量中的对象引用不会再指示其他 StringBuilder
对象。不过这个对象可以更改:public void giveGoldStarO { evaluations.append(LocalDate.now() + ": Gold star! "); }
-
数组继承了 object 类的 toString 方法,数组类型将按照旧的格式打印。例如:
int[] luckyNumbers = { 2, 3, 5, 7 S llf 13 } ; String s = "" + luckyNumbers; 生成字符串“ [I@la46e30”
(前缀 [I 表明是一个整型数组)。修正的方式是调用静态方法
Arrays.toString
。代码:String s = Arrays.toString(luckyNumbers); 将生成字符串“ [2,3,5,7,11,13]”。
要想打印多维数组(即,数组的数组)则需要调用
Arrays.deepToString
方法。 -
分配数组列表:
new ArrayListo(100) // capacity is 100
它与为新数组分配空间有所不同:
new Employee[100] // size is 100
数组列表的容量与数组的大小有一个非常重要的区别。如果为数组分配 100 个元素的存储空间,数组就有 100 个空位置可以使用。 而容量为 100 个元素的数组列表只是拥有保存 100 个元素的潜力 ( 实际上, 重新分配空间的话,将会超过丨00 ), 但是在最初,
甚至完成初始化构造之后,数组列表根本就不含有任何元素。List list = new ArrayList<>(10); System.out.println(list.size());//0 int[] i = new int[10]; System.out.println(i.length);//10
-
@SuppressWarnings("unchecked")
标注来标记
这个变量能够接受类型转换/压制警告信息 -
== 运算符也可以应用于对象包装器对象, 只不过检测的是对象是否指向同一个存储区域, 因此,下面的比较通常不会成立:
Integer a = 1000; Integer b = 1000; if (a = b) . . .
然而,Java 实现却有可能( may) 让它成立。自动装箱规范要求 boolean、byte、char 127, 介于 -128 ~ 127 之间的 short 和
int 被包装到固定的对象中。 -
能够分析类能力的程序称为反射(reflective )。
有时候,变量的取值只在一个有限的集合内。对这种情况, 可以自定义枚举类型。
鉴于历史原因,getName 方法在应用于数组类型的时候会返回一个很奇怪的名字:
Double[ ] class.getName( )
返回[Ljava.lang.Double
,
int[ ].class.getName( )
返回[I
, -
在 Java 语言中, 给出了 3 种处理系统错误的机制:
• 抛出一个异常
• 日志
• 使用断言
什么时候应该选择使用断言呢? 请记住下面几点:
• 断言失败是致命的、 不可恢复的错误。
• 断言检查只用于开发和测阶段(这种做法有时候被戏称为“ 在靠近海岸时穿上救生衣,
但在海中央时就把救生衣抛掉吧”)。
因此,不应该使用断言向程序的其他部分通告发生了可恢复性的错误,或者,不应该作为程序向用户通告问题的手段。断言只应该用于在测试阶段确定程序内部的错误位置。 -
泛型相关在 Java 库中, 使用变量 E 表示集合的元素类型, K 和 V 分别表示表的关键字与值的类型。T ( 需要时还可以用临近的字母 U 和 S) 表示“ 任意类型”。
有时,类或方法需要对类型变量加以约束。怎么才能确信 T 所属的类有 compareTo 方法呢?
解决这个问题的方案是将 T 限制为实现了 Comparable 接口(只含一个方法 compareTo 的
标准接口)的类。可以通过对类型变量 T 设置限定(bound) 实现这一点:
public static <T extends Comparable> T min(T[] a) . . .
一个类型变量或通配符可以有多个限定, 例如:
T extends Comparable & Serializable
-
队列通常有两种实现方式: 一种是使用循环数组;另一种是使用链表
-
编译器简单地将“ foreach” 循环翻译为带有迭代器的循环。it.hasNext()
-
如果 a.equals(b) 为 true, a 与 b 必须具有相同的散列码。
-
双端队列java.util.Deque
: • void addFirst(E element ) • void addLast(E element ) • boolean offerFirst(E element ) • boolean offerLast(E element )
将给定的对象添加到双端队列的头部或尾部。如果队列满了,前面两个方法将拋出一个 IllegalStateException,而后面两个方法返回 false。
• E removeFirst( ) • E removeLast( ) • E pollFirstO • E pollLastO
如果队列不空,删除并返回队列头部的元素。如果队列为空,前面两个方法将拋出一
个 NoSuchElementException, 而后面两个方法返回 null。• E getFirstO • E getLastO • E peekFirstO • E peekLast( )
如果队列非空,返回队列头部的元素, 但不删除。如果队列空,前面两个方法将拋出
一个 NoSuchElementException, 而后面两个方法返回 null。 -
Arrays 类的静态方法 asList 将返回一个包装了普通 Java 数组的 List 包装器。这个方法可
以将数组传递给一个期望得到列表或集合参数的方法。例如:Card[] cardOeck = new Card [52]; List<Card> cardList = Arrays.asList(cardDeck):
返回的对象不是 ArrayList。它是一个视图对象, 带有访问底层数组的 get 和 set 方
法。改变数组大小的所有方法(例如,与迭代器相关的 add 和 remove 方法)都会抛出一个
Unsupported OperationException 异常。 -
守护线程的唯一用途是为其他线程提供服务。
-
accounts[to] += amount
;
于这不是原子操作。该指令可能被处理如下:
1 ) 将 accounts[to] 加载到寄存器。
2 ) 增 加 amount。
3 ) 将结果写回 accounts[to]。 -
假设对共享变量除了赋值之外并不完成其他操作,那么可以将这些共享变量声明为
volatileo -
使用ThreadLocal线程安全化SimpleDateFormat
public static final ThreadLocal<SimpleDateFormat> dateFormat = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
要访问具体的格式化方法,可以调用:
String dateStamp = dateFormat.get().format(new DateO)
; -
执行器(Executor) 类有许多静态工厂方法用来构建线程池,方法描述:
- newCachedThreadPool: 必要时创建新线程;空闲线程会被保留 60 秒
- newFixedThreadPool: 该池包含固定数量的线程;空闲线程会一直被保留
- newSingleThreadExecutor:只有一个线程的 “ 池”, 该线程顺序执行每一个提交的任务(类似于Swing 事件分配线程)
- newScheduledThreadPool: 用于预定执行而构建的固定线程池, 替代 java.util.Timer
- newSingleThreadScheduledExecutor: 用于预定执行而构建的单线程 “ 池”
-
类之间的关系,类图