重学Java/Java小点整理(一)

写在前面

记得之前学习Java的时候完全是突击性的,因为要一个学期内掌握ssm框架,所以从下至下都学的不是很扎实,决定重新学习下Java。该博客是跟从JavaGuide学习的一些要点整理,并且对其讲得不太准确或容易产生误解的地方做些记录。本博文章节名与JavaGuide文章名对应。

Java基础知识

Java是编译与解释共存的语言。高级编程语言按照程序的执行方式分为编译型和解释型两种。简单来说,编译型语言是指编译器针对特定的操作系统将源代码一次性翻译成可被该平台执行的机器码;解释型语言是指解释器对源程序逐行解释成特定平台的机器码并立即执行。比如,你想阅读一本英文名著,你可以找一个英文翻译人员帮助你阅读, 有两种选择方式,你可以先等翻译人员将全本的英文名著(也就是源码)都翻译成汉语,再去阅读,也可以让翻译人员翻译一段,你在旁边阅读一段,慢慢把书读完。
Java 语言既具有编译型语言的特征,也具有解释型语言的特征,因为 Java 程序要经过先编译,后解释两个步骤,由 Java 编写的程序需要先经过编译步骤,生成字节码(*.class 文件),这种字节码必须由 Java 解释器来解释执行。因此,我们可以认为 Java 语言编译与解释并存。

Java中char类型占两个字节。

在 C 语言中,字符串或字符数组最后都会有一个额外的字符’\0’来表示结束。但是,Java 语言中没有结束符这一概念。原因解释

java的泛型擦除,自己之前写过一篇相关的博客指路

hashCode()和equals(),为了让自己设计的类能够正确地被hashset存储时,我们要重写hashCode()方法,同时hashCode()也能够让equals()提速不少。

java中的参数传递,一开始还以为教程上讲错了,还打算专门写篇博客,后来才发现自己对引用传递的概念忘干净了。同样没看懂的同学可以先复习下三种参数传递方式。为什么大家都说Java中只有值传递?这篇博客讲得挺细致的。

对于不想进行序列化的变量,使用 transient 关键字修饰。

使用try-with-resources来代替try-catch-finally,java7引入了try-with-resource,通过如下,我们就可以无需自己关闭资源了。

1
2
3
4
5
6
7
try (Scanner scanner = new Scanner(new File("test.txt"))) {
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}

Java基础知识疑难点

当我们需要使用精确小数时,应当使用BigDecimal。为了防止精度丢失,推荐使用它的BigDecimal(String)构造方法来创建对象。

Arrays.asList()会把数组转换为java.util.Arrays$ArrayList,注意和java.util.Arraylist做区分(JavaGuide并没有第一时间在文中指出)
翻阅java1.8源码我们可以看到java.util.Arrays$ArrayList是一个内部定义好的类,整体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;

ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}

@Override
public int size() {
return a.length;
}

@Override
public Object[] toArray() {
return a.clone();
}

@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size)
return Arrays.copyOf(this.a, size,
(Class<? extends T[]>) a.getClass());
System.arraycopy(this.a, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}

@Override
public E get(int index) {
return a[index];
}

@Override
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}

@Override
public int indexOf(Object o) {
E[] a = this.a;
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}

@Override
public boolean contains(Object o) {
return indexOf(o) != -1;
}

@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(a, Spliterator.ORDERED);
}

@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
for (E e : a) {
action.accept(e);
}
}

@Override
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
E[] a = this.a;
for (int i = 0; i < a.length; i++) {
a[i] = operator.apply(a[i]);
}
}

@Override
public void sort(Comparator<? super E> c) {
Arrays.sort(a, c);
}
}

我们可以看到a是被final关键字修饰了的,并且它的初始化是a = Objects.requireNonNull(array);,也就是说它本质是一个适配器。

不要在 foreach 循环里进行元素的 remove/add 操作