# 引用类型

# 数组

数组可以比较方便的使用线性结构来保存一组类型相同的变量,传统数组的最大缺陷是个数固定,而Java的一些类框架实现动态数组的操作。

# 一维数组

public class Main {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int arrLength = 10;
        int intArr[] = new int[arrLength];
        int[] intArr2 = new int[arrLength];
        int intArr3[];
        intArr3 = new int[arrLength];
        for (int i = 0; i < intArr.length; i++) {
            intArr[i] = i;
            intArr2[i] = i * 2;
            intArr3[i] = i * 3;
            System.out.println(intArr[i] + ":" + intArr2[i] + ":" + intArr3[i]);
        }
        // 上面是动态初始化 下面是静态初始化
        int intArr4[] = new int[] { 1, 2, 3 };
        for (int i = 0; i < intArr4.length; i++) {
            System.out.println(intArr4[i]);
        }
        int intArr5[] = intArr4;
        intArr5[1] = 100;
        for (int i : intArr4) {
            System.out.println(i);
        }
    }
}
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

# 二维数组

二维数组需要行和列两个下标才能访问数组元素,其结构为一张表。来看下基本操作:


public class Main {
    public static void main(String[] args) {
        int width=3,length=4;
        int intArr[][]= new int[width][length];
        for(int i=0;i<width;i++) {
            for(int j=0;j<length;j++){
                intArr[i][j]=j;
                System.out.print(intArr[i][j]+" ");
            }
            System.out.println();
        }
        int intArr2[][] = new int[][] {
            {1,2,3},
            {4,5,6},
            {7,8,9}
        };
        for(int i=0;i<intArr2.length;i++) {
            for(int j=0;j<intArr[i].length;j++) {
                System.out.print(intArr[i][j]+" ");
            }
            System.out.println();
        }
        int [][] intArr3 = new int[][] {
            {10,2,3},
            {4,5,6},
            {7,8,9}
        };
        for(int row[]:intArr3) {
            for(int col : row) {
                System.out.print(col+" ");
            }
            System.out.println();
        }
    }
}
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

# 数组与方法

数组可以作为参数传入方法可以一次传入多个数据,方法的可变参数也与数组有关。

import java.util.Random;

public class Main {
    public static void main(String[] args) {
        int length=10;
        int sourceData[] = new int[length];
        changeArr(sourceData);
        printArr(sourceData);
        java.util.Arrays.sort(sourceData);
        printArr(sourceData);
        GetInfo("A Sentence","Green","Ground","Grow","Grass");

    }

    public static void GetInfo(String name,String...other) {
        System.out.println(name+":");
        for(String n: other) {
            System.out.print(n+" ");
        }
    }

    public static void changeArr(int targetArr[]) {
        Random r = new Random(System.currentTimeMillis());
        for(int i=0;i<targetArr.length;i++) {
            targetArr[i]=r.nextInt(10);
        }

    }

    public static void printArr(int targetArr[]) {
        for(int elem:targetArr) {
            System.out.print(elem+" ");
        }
        System.out.println();
    }
}
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

# 字符串

Java中字符串的实现是使用String类,在JDK1.8之前,String类内部实现是char数组,JDK1.9之后,类内部实现是byte数组。可理解为字符串就是对数组的一种特殊包装,长度固定的包装。该类可通过直接赋值来进行实例化操作,除了直接赋值外,也提供了构造方法进行实例化,这两种方式有一些细微区别,下面具体细讲:

public class Main {
    public static void main(String[] args) {
        String str1 = "苹果", str2 = "苹果";
        String str3 = "苹" + "果";
        if (str1 == str2) {
            System.out.println("str1 == str2");
        }
        if (str1 == str3) {
            System.out.println("str1 == str3");
        }

        if (str1.equals(str3)) {
            System.out.println("str1 euqals str3");
        }

        String str4 = new String("苹果");
        String str5 = new String("苹果");
        if (str4 == str5) {
            System.out.println("str4 == str5");
        }
        if (str4.equals(str5)) {
            System.out.println("str4 equals str5");
        }
        if (str1.equals(str5)) {
            System.out.println("str1 equals str5");
        }
    }
}
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

注意:

  1. 在字符串上比较上,使用==和equals是不一样的:==用于引用类型比较时,比较的是内存地址,不是内容,而equals比较的是字符串内容。
  2. 字符串常量可看成是String类的匿名对象,而String类对象赋值相当于给匿名对象设置一个名字引用。
  3. JVM底层存在一个对象池,String只是可在其中保存的一种类型,当使用直接赋值实例化字符串时,会检查字符串对象池有没有该字符串,如果有的话则直接让字符串变量指向该字符串,如果没有则会把字符串放入字符串对象池,然后用字符串变量指向该字符串。这样就可以理解为什么直接赋值时,相同内容的字符串内存地址相同。

如果在使用构造方法实例化时也想把字符串放入对象池,可以使用intern()函数:

public class Main {
    public static void main(String[] args) {
        String str1 = new String("苹果").intern();
        String str2 = "苹果";
        String str3 = new String("苹果");
        if(str1 == str2) {
            System.out.println("str1 == str2");
        }
        if(str1 == str3) {
            System.out.println("str1 == str3");
        }

    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

注意字符串常量池分为两种:

  • 静态常量池:程序(*.class)加载的时候自动将程序中的字符串,普通常量,类及其内部信息保存到里面。
  • 运行常量池:当程序加载后,一些字符串内容是通过String对象保存再进行字符串连接,由于String对象的内容可改变,所以称为运行时常量池。
public class Main {
    public static void main(String[] args) {
        String str1 = "苹果";
        String str2 = "苹";
        String str3 = str2+"果";
        String str4 = str2+"果";

        if(str1 == str3) {
            System.out.println("str1 == str3");
        }

        if(str3 == str4) {
            System.out.println("str3 == str4");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# CharSequence接口

CharSequence是从JDK 1.4之后提供的用于描述字符串标准的接口,常见的子类有String,StringBuffer,StringBuilder,该接口提供三个方法:

方法原型 作用
public char charAt(int index) 获取指定索引字符串
public int length() 获取字符串长度
public CharSequence subSequence(int start,int end) 截取部分字符串

它们的类继承关系如下:

charSequence

String类我们比较熟,StringBuffer和StringBuilder都有增删除功能,StringBuffer是JDK 1.0提供的,StringBuilder是JDK 1.5提供的,它们都是可修改的字符串类型,唯一的区别在于StringBuffer类中方法使用synchronized关键字,适合多线程下并发访问下的同步处理,而StringBuilder属于非线程安全方法,主要用于单线程下的使用场景,它一般比StringBuffer要快。

从字符串对象池的概念中可看出它原本是为了节省字符串开辟空间,让其更高效可用,可是当频繁有字符串拼接时,每次字符串拼接都要先检查下对象池,然后再开辟空间,这会降低字符串拼接的效率。这时可考虑使用StringBuilder,StringBuffer类:

public class Main {
    public static void main(String[] args) {
        String str1 = "苹果";
        long beginTime = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            str1 += i;
        }
        System.out.println("常量字符串拼接:" + (System.nanoTime() - beginTime) + "纳秒");

        String str2 = new String("苹果");
        beginTime = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            str2 += i;
        }
        System.out.println("String 字符串拼接:" + (System.nanoTime() - beginTime) + "纳秒");

        StringBuilder sb1 = new StringBuilder("苹果");
        beginTime = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            sb1.append(i);
        }
        System.out.println("StringBuilder 字符串拼接:" + (System.nanoTime() - beginTime) + "纳秒");

        StringBuffer strBuffer = new StringBuffer("苹果");
        beginTime = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            strBuffer.append(i);
        }
        System.out.println("StringBuilder 字符串拼接:" + (System.nanoTime() - beginTime) + "纳秒");

    }
}
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

# String常见操作

public class Main {
    public static void main(String[] args) {
        String str1 = "Hello World!";
        System.out.println("得到第二个字符:" + str1.charAt(1));

        // 转换为字符数组,并转换为小写
        char[] result = str1.toCharArray();
        for (int i = 0; i < result.length; i++) {
            if (result[i] < 'Z' & result[i] > 'A') {
                result[i] += 32;
            }
            System.out.print(result[i]);
        }
        System.out.println();
        // 转换为字节数组,并转换为小写
        byte[] byteArr = str1.getBytes();
        for (int i = 0; i < byteArr.length; i++) {
            if (byteArr[i] < 'Z' & byteArr[i] > 'A') {
                byteArr[i] += 32;
            }

        }
        System.out.print(new String(byteArr));
        System.out.println();

        //字符串比较大小
        System.out.println("hello world!".equalsIgnoreCase(str1));
        System.out.println("hello World!".compareTo(str1));

        //字符串查找
        System.out.println(str1.contains("or"));
        System.out.println(str1.indexOf("l"));
        System.out.println(str1.lastIndexOf("l"));
        System.out.println(str1.startsWith("Hell"));

        //字符串替换
        System.out.println(str1.replaceAll("l","li"));

        //字符串拆分
        String splitedStr[] = "192.168.1.1".split("\\.");
        for(String i :splitedStr) {
            System.out.println(i);
        }

        //字符串截取
        String str2 = "name:xie;age:20";
        System.out.println(str2.substring(str2.indexOf(":")+1,str2.indexOf(";")));
        System.out.println("  this is my work!   ".trim());

        //字符串格式化
        System.out.println(String.format("name:%s,age:%3d","xie",80));
        System.out.println(str1.toUpperCase());

        //字符串连接
        System.out.println("myName:".concat("xs"));

        //字符串获取大小
        System.out.println(str1.length());
        //字符串是否为null
        System.out.println(str1.isEmpty());

    }
}
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

注意concat连接字符串时每次操作都会返回一个新实例化对象,属于运行时常量。