# 引用类型
# 数组
数组可以比较方便的使用线性结构来保存一组类型相同的变量,传统数组的最大缺陷是个数固定,而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);
}
}
}
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();
}
}
}
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();
}
}
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");
}
}
}
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
注意:
- 在字符串上比较上,使用==和equals是不一样的:==用于引用类型比较时,比较的是内存地址,不是内容,而equals比较的是字符串内容。
- 字符串常量可看成是String类的匿名对象,而String类对象赋值相当于给匿名对象设置一个名字引用。
- 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");
}
}
}
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");
}
}
}
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) | 截取部分字符串 |
它们的类继承关系如下:
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) + "纳秒");
}
}
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());
}
}
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连接字符串时每次操作都会返回一个新实例化对象,属于运行时常量。