Java基础的学习很重要

Java学习

一、面向对象

1.面向对象五大原则

1.单一自责原则(Single-Responsibility Principle)

  • 一个类,最好只做一件事,只有一个引起它的变化

2.开放封闭原则(Open-Close principle)

  • 软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的。

3.里氏替换原则(Liskov-Substitution Principle)

  • 子类必须能够替换其基类。这一思想体现为对继承机制的约束规范,只有子类能够替换基类时,才能保证系统在运行期内识别子类,这是保证继承复用的基础。

4.依赖倒置原则(Dependency-Inversion Principle)

  • 依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。

5.接口隔离原则(Interface-Segregation Principle)

  • 使用多个小的专门的接口,而不要使用一个大的总接口。

2. 多用组合,少用继承

  • 建议在同样可行的情况下,优先使用组合而不是继承。
  • 因为组合更安全,更简单,更灵活,更高效。

3.类变量,成员变量,局部变量

  • 类变量:存储在方法区中。private static int a;
  • 成员变量:存储在堆内存中
  • 局部变量:存储在栈内存中
  • 抽象类与接口的区别
  • 类关系示例图
  • POJO的分类

4.成员变量的方法作用域

  • public:表明该成员变量或者方法是对所有类或者对象都是可见的,所有类或者对象都可以直接访问
  • private:表明该成员变量或者方法是私有的,只有当前类对其具有访问权限,除此之外其他类或者对象都没有访问权限.子类也没有访问权限.
  • protected:表明成员变量或者方法对类自身,与同在一个包中的其他类可见,其他包下的类不可访问,除非是他的子类
  • default:表明该成员变量或者方法只有自己和其位于同一个包的内可见,其他包内的类不能访问,即便是它的子类

5.基本类型

  • 不能用浮点型表示金额
    • 由于计算机中保存的小数其实是十进制的小数的近似值,并不是准确值,所以,千万不要在代码中使用浮点数来表示金额等重要的指标
    • 建议使用BIgDecimal或者Long来表示金额

5.1自动拆装箱

1
2
3
4
5
6
7
8
9
10
//java代码    
boolean flag = true;
Integer i = 0;
int j = 1;
int k = flag ? i : j;
//反编译后
boolean flag = true;
Integer i = Integer.valueOf(0);
int j = 1;
int k = flag ? i.intValue() : j;
  • 此时如果i值为null,就会发生NPE(空指针异常)。
1
2
3
4
5
6
Integer test1 = 3;
Integer test2 = 3;
// test1 == test2
Integer test3 = 300;
Integer test4 = 300;
// test3 != test4
  • 其中的 Javadoc 详细的说明了缓存支持 -128 到 127 之间的自动装箱过程。最大值 127 可以通过 -XX:AutoBoxCacheMax=size 修改。

  • 实际上这个功能在 Java 5 中引入的时候,范围是固定的 -128 至 +127。后来在 Java 6 中,可以通过 java.lang.Integer.IntegerCache.high 设置最大值。

  • 在 Boxing Conversion 部分的 Java 语言规范(JLS)规定如下:

    如果一个变量 p 的值是:

    • -128 至 127 之间的整数 (§3.10.1)
    • true 和 false 的布尔值 (§3.10.3)
    • \u0000\u007f 之间的字符 (§3.10.4)
注意:如果一个 for 循环中有大量拆装箱操作,会浪费很多资源。

6.字符串的不可变性String

  • String类的所有方法都没有改变字符串本身的值,都是返回了一个新的对象。

    • 如果我们想要一个可修改的字符串,可以选择StringBuffer 或者 StringBuilder这两个代替String。
  • 如有可能,我愿意任何时候都使用不可变对象。
    I would use an immutable whenever I can.
    
    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

    + 缓存-字符串对象使用频率高,将其缓存起来,相同的指向一个地址空间,节省资源

    + 安全性-字符串存储敏感数据,不可变,可以让开发者足够信任它

    + 线程安全-多个线程访问它们时,它们不会被改变。

    + hashcode缓存-由于字符串对象被广泛地用作数据结构,它们也被广泛地用于哈希实现,如HashMap、HashTable、HashSet等。在对这些散列实现进行操作时,经常调用hashCode()方法。

    + 性能-因为字符串不可变,所以可以用字符串池缓存,可以大大节省堆内存。而且还可以提前对hashcode进行缓存,更加高效

    ### 7.String类中常见用法

    > 内存泄露:在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。 内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

    #### 1.JDK6与JDK7中substring的原理及区别

    Jdk6:substring指向原string字符串其中的一部分数据

    Jdk7:重新创建对象

    #### 2.replaceFirst、replaceAll、replace区别

    replace(CharSequence target, CharSequence replacement) ,用replacement替换所有的target,两个参数都是字符串。

    replaceAll(String regex, String replacement) ,用replacement替换所有的regex匹配项,regex很明显是个正则表达式,replacement是字符串。

    replaceFirst(String regex, String replacement) ,基本和replaceAll相同,区别是只替换第一个匹配项。

    ```java
    String string = "abc123adb23456aa";
    System.out.println(string);//abc123adb23456aa

    //使用replace将a替换成H
    System.out.println(string.replace("a","H"));//Hbc123Hdb23456HH
    //使用replaceFirst将第一个a替换成H
    System.out.println(string.replaceFirst("a","H"));//Hbc123adb23456aa
    //使用replace将a替换成H
    System.out.println(string.replaceAll("a","H"));//Hbc123Hdb23456HH

    //使用replaceFirst将第一个数字替换成H
    System.out.println(string.replaceFirst("\\d","H"));//abcH23adb23456aa
    //使用replaceAll将所有数字替换成H
    System.out.println(string.replaceAll("\\d","H"));//abcHHHadbHHHHHaa

3.string中的“+”

代码:

1
2
3
4
5
String hello = "Hello"

String world = "World";

String sout = hello + "," world;

反编译后:

1
2
3
String wechat = "Hollis";
String introduce = "\u6BCF\u65E5\u66F4\u65B0Java\u76F8\u5173\u6280\u672F\u6587\u7AE0";//每日更新Java相关技术文章
String hollis = (new StringBuilder()).append(wechat).append(",").append(introduce).toString();

通过StringBuilder.append实现的拼接

4.字符串拼接的几种方法和区别

StringBuffer是线程安全的

StringUtils.join的源码,其实也是通过StringBuilder实现的

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
public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
if (separator == null) {
separator = EMPTY;
}

// endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator))
// (Assuming that all Strings are roughly equally long)
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}

final StringBuilder buf = new StringBuilder(noOfItems * 16);

for (int i = startIndex; i < endIndex; i++) {
if (i > startIndex) {
buf.append(separator);
}
if (array[i] != null) {
buf.append(array[i]);
}
}
return buf.toString();
}

效率对比

1
2
3
4
5
6
7
8
long t1 = System.currentTimeMillis();
//这里是初始字符串定义
for (int i = 0; i < 50000; i++) {
//这里是字符串拼接代码
}
long t2 = System.currentTimeMillis();
System.out.println("cost:" + (t2 - t1));

测试结果:StringBuilder<StringBuffer<concat<+<StringUtils.join

1
2
3
4
5
+ cost:5119
StringBuilder cost:3
StringBuffer cost:4
concat cost:3623
StringUtils.join cost:25726

Collection和Collections区别

Collection是一个集合接口.它提供了对集合对象进行基本操作的通用接口方法.是list,set等等父接口

Collections是一个包装类.她包含有各种关于集合操作的静态多态方法.类无法实例化,像工具类,服务与Java的Colloection框架.

Set和List区别

List,Set都是继承自Collection接口。都是用来存储一组相同类型的元素的。

List特点:元素有放入顺序,元素可重复

先放入的元素排在前面

Set特点:元素无放入顺序,元素不可重复.

无顺序,即先放入的元素不一定排在前面。 不可重复,即相同元素在set中只会保留一份。所以,有些场景下,set可以用来去重。 不过需要注意的是,set在元素插入时是要有一定的方法来判断元素是否重复的。这个方法很重要,决定了set中可以保存哪些元素。

ArrayList和LinkedList和Vector的区别

三者都实现了List接口,区别在于实现方式不同,对不同的操作具有不同的效率.

ArrayList是一个可改变大小的数组,其大小会顺随着元素的加入而动态地增长.内部通过get,set方法进行访问.本质上是个数组.