有时候我们需要一组相同数据类型的变量,这时候我们就要用数组来实现
数 组:用于存储同一类型数据的一个容器。好处:可以对该容器中的数据进行编号,从0开始。数组用于封装数据,就是一个具体的实体。
type[] 变量名 = new type[数组中元素的个数];
type 变量名[] = new type[数组中元素的个数];
type[] 变量名 = new type[]{逗号分隔的初始化值};
type[] 变量名 = {元素1,元素2…};
方式一
String[] strs = new String[2];
strs[0] = "0";
strs[1] = "1";
方式二
String[] strs = new String[]{"0", "1"};
方式三
String[] strs = {"0", "1"};
获取数组长度:数组名.length
int[] a = new int[10] ;
for(int i=0;i0;
}
for(int t:a){
System.out.println(t);
}
注:这里t就是数组元素的拷贝,不能通过t来修改数组元素的值
3.1.1 冒泡排序
public void bubbleSort(int a[]) {
for (int i = 0; i < a.length - 1; i++){
for (int j = 0; j < a.length - 1; j++){
if (a[j] > a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
3.1.2 选择排序
public void selectSort(int a[]) {
for (int n = a.length; n > 1; n--) {
int i = max(a,n);
int temp = a[i];
a[i] = a[n - 1];
a[n - 1] = temp;
}
}
3.1.3 插入排序
public void insertSort(int a[]) {
for (int i = 1; i < a.length; i++) {
int t = a[i];
int j;
for (j = i - 1; j >= 0 && t < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = t;
}
}
3.1.4 Arrays.sort()方法:
import java.util.Arrays; //导入包
public class Main {
public static void main(String[] args) {
int a[] = new int[10];
Arrays.sort(a);
}
}
3.2.1 二分查找法
public static int binarySearch(int[] arr,int key){
int min,max,mid;
min = 0;
max = arr.length-1;
mid = (max+min)>>1; //(max+min)/2;
while(arr[mid]!=key){
if(key>arr[mid]){
min = mid + 1;
}
else if(key1;
if(maxreturn -1;
mid = (max+min)>>1;
}
return mid;
}
3.2.2 用Arrays类进行二分查找
public static int binarySearch(Object[] a, Object key);
例如
Arrays.binarySearch(a, 10);
java.util.Arrays 类能方便地操作数组,它提供的所有方法都是静态的。
给数组赋值:public static void fill(int[] a, int val)。
对数组排序:public static void sort(Object[] a),按升序。
比较两个数组是否相等:public static boolean equals(long[] a, long[] a2)
二分查找数组元素:public static int binarySearch(Object[] a, Object key)
数组拷贝:Arrays.copyOf(original, newLength)
original – 这是要被复制的数组。
newLength – 这是要返回的副本长度。
System.arraycopy(src, srcPos, dest, destPos, length);
通过查看Arrays的源码可以发现实际上:Arrays.copyOf(original, newLength)内部是调用的System.arraycopy(src, srcPos, dest, destPos, length);
int[][] arr = new int[2][3];
int[][] arr = new int[2][];
int[][] arr = {{1,2,3},{4,5},{6,7,8,9}};
1.for循环遍历二维数组
public class Test {
public static void main(String[] args) {
int[][] arr = {{1,2,3},{4,5},{6,7,8,9}};
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
}
}
2.两层for-each循环
public class Test {
public static void main(String[] args) {
int[][] arr = {{1,2,3},{4,5},{6,7,8,9}};
for (int[] is : arr) {
for (int i : is) {
System.out.println(i);
}
}
}
}
1.二维数组的定义格式
int[][] arr = new int[2][]; 可以。
int[][] arr = new int[][3]; 不可以。一定要先给行,在考虑列。
2.int[] x,y[];请问x和y有区别吗?
有区别,x是一维数组,y是二维数组。
String str=”“;
string str=new String();
注:
a.实际运用中,我们要避免第二种方式,第二种方式创建了两个String对象。首先,通过双引号创建了String对象“abc”。然后,java虚拟机创建一个新的String对象,并把字符串“abc”传入构造函数。这是一次完全没有必要的构造,既影响了性能,也提高了代码阅读难度。
b.这两个对象创建的时期不同,一个是编译时,一个是运行时.
c.String str=”hello”;JVM先根据内容查找对象,如果没找到,则heap上面创建新对象,并将其赋予s1,否则使用已经存在的对象
d.string str=new String(“hello”); jvm直接在heap上创建新的对象,所以在heap中会出现内容相同而地址不同的String对象.
str=”hello”+”world”
aa.concat(str)
a.length();
回车 ‘\r’
换行 ‘\n’
Tab ‘\t’
换页 ‘\f’
退格 ‘\b’
单引号 ‘\’
换码符 ‘\’
双引号 ‘\”’
通过String类的源码的我们,value[]属性是final的。这代表一个String对象是不可改变的,String类的方法中我们也找不到任何能够改变字符串的值和长度的方法。这就是字符串的不可改变性
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
因为final是最终意思,final限定的类是最终类,没有其子类。所以不能够被继承。关于继承这个概念会在第八讲面向对象详细说明。
String类的equals()方法用来确定两个字符串是否相等
charAt()用以得到指定位置的字符
getChars()用以得到字符串的一部分字符串
subString()是提取字符串的另一种方法,它可以指定从何处开始提取字符串以及何处结束
replace()方法可以将字符串中的一个字符替换为另一个字符
toUpperCase()和toLowerCase()方法分别实现字符串大小写的转换
trim()方法可以将字符串中开头和结尾处的空格去掉.
String类提供静态方法valueOf(),它可以将任何类型的数据对象转换为一个字符串。
我们说String类是不可变字符序列,如果频繁的修改,将会产生很多的String对象,开销很大。有时候我们需要用到可变字符序列,jdk为我们提供了StringBuffer类与StringBuilder类。
StringBuffer对象的每次修改都会改变对象自身,这点是和String类最大的区别。StringBuffer是线程安全的(后续笔记中,将讲到多线程编程)。
StringBuffer sb = new StringBuffer();
StringBuffer sb = new StringBuffer(“xiaoqingchun”);
StringBuffer reverse();
int lastIndexOf(String str, int fromIndex);
int lastIndexOf(String str);
int indexOf(String str, int fromIndex);
int indexOf(String str);
StringBuffer insert(int offset, double d);
String substring(int start, int end);
CharSequence subSequence(int start, int end);
StringBuffer replace(int start, int end, String str);
StringBuffer deleteCharAt(int index);
StringBuffer delete(int start, int end)
append();
注:不能通过String常量来赋值,String不存与StringBuffer在继承关系,无法进行强转
StringBuilder sb= new StringBuilder(“xiaoqingchun!”);
方法 | 作用 |
---|---|
StringBuilder append(Object obj) | 将文本或对象的字符串表示形式添加到由当前 StringBuilder对象表示的字符串的结尾处 |
StringBuilder delete(int start, int end) | 删除指定start-end位置的字符串 |
StringBuilder deleteCharAt(int index) | 删除指定索引位置的字符 |
StringBuilder replace(int start, int end, String str) | 可以用另一个指定的字符来替换 StringBuilder对象内的字符 |
StringBuilder insert(int offset, Object obj) | 方法将字符串或对象添加到当前 StringBuilder中的指定位置 |
int indexOf(String str) | 求出第一次出现str字符串的位置 |
int lastIndexOf(String str) | 求出最后一次出现str字符串的位置 |
StringBuilder reverse() | 翻转字符串 |
void ensureCapacity(int minimumCapacity) | 设置长度 |
通常情况下 : 三者在执行速度方面的比较:StringBuilder > StringBuffer > String
但是一定是这样的嘛,接下来我们来看4个栗子
栗子1 :
(1)String str = “This is only a” + “simple”+ ” test”;
(2)StringBuffer buffer= new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
这里(1)的效率比(2)的效率高,这是因为jvm在编译的时候,已经直接进行了表达式合并优化,只开辟了一段内存。而编译StringBuffer还要进行append处理,花的时间要长一些
栗子2 :
(1) String str = “This is only a”;
str += “simple”;
str += “test”;
(2)StringBuffer buffer= new StringBuffer (“This is only a”).append(“ simple”).append(“ test”);
(1)的效率优于(2)的效率,因为String是不可变对象,,每次”+=”都会创造新的String对象
栗子3 :
(1)StringBuffer buffer= new StringBuffer ();
for(int i=0;i<50000;i++){
buffer.append(“hello”);
}
(2)StringBuffer buffer= new StringBuffer (250000);
for(int i=0;i<50000;i++){
buffer.append(“hello”);
}
第一周效率比第二种好,因为StringBuffer内部实现是char数组,默认初始化长度为16,每次字符串长度大于char数组长度的时候,JVM会构造新数组,并将原先的数组内容复制到新数组.方法二避免了复制数组的开销。
栗子4 :
(1)private static void test2(String s1,String s2) {
return s1+s2;
}
(2)private static void test2(String s1,String s2) {
return new StringBuffer().append(s1).append(s2);
}
1与2的效率相同,因为JVM会开辟一个内存段,再合并(扩展)内存,所以两者执行的过程是一致的
上述案例可以用一下测试来进行测定
public class Test {
public static void main(String[] args) {
test1();
test2();
}
private static void test1() {
Runtime run = Runtime.getRuntime();
long startTime, endTime;
long startMem, endMem;
System.out.println("方法1");
run.gc();//回收一下垃圾
// 记录开始时的内存及时间信息,并打印到屏幕上
startTime = System.currentTimeMillis();
startMem = run.totalMemory() - run.freeMemory();
System.out.println("开始时候使用的: " + startMem);
for (int i = 0; i < 10000; i++) {
// 执行需要测试的代码段
String str = "This is only a" + "simple"+ " test";
}
// 计算花费的内存及时间,然后打印到屏幕上
endTime = System.currentTimeMillis();
endMem = run.totalMemory() - run.freeMemory();
System.out.println("运行时间:" + (endTime - startTime));
System.out.println("结束时所用内存: " + endMem + ", 增加使用的内存:" + (endMem - startMem));
}
private static void test2() {
Runtime run = Runtime.getRuntime();
long startTime, endTime;
long startMem, endMem;
System.out.println("方法1");
//回收一下垃圾
run.gc();
// 记录开始时的内存及时间信息,并打印到屏幕上
startTime = System.currentTimeMillis();
startMem = run.totalMemory() - run.freeMemory();
System.out.println("开始时候使用的: " + startMem);
//微小放大法
for (int i = 0; i < 10000; i++) {
// 执行需要测试的代码段
StringBuffer sb = new StringBuffer("This is only a").append("simple").append(" test");
}
// 计算花费的内存及时间,然后打印到屏幕上
endTime = System.currentTimeMillis();
endMem = run.totalMemory() - run.freeMemory();
System.out.println("运行时间:" + (endTime - startTime));
System.out.println("结束时所用内存: " + endMem + ", 增加使用的内存:" + (endMem - startMem));
}
}
1.StringBuffer线程安全、效率相对低
2.StringBuilder线程不安全、效率相对高
(1)简单地认为.append()效率好于”+”是错误的。
(2)不要使用new创建String
(3)注意.intern()的使用
(4)在编译期能够确定字符串值的情况下,使用”+”效率最高
(5)避免使用”+=”来构造字符串
(6)在声明StringBuffer对象的时候,指定合适的capacity,不要使用默认值16
(7)注意下面两个的区别,后者开辟了两个内存段
1. String s=”a”+”b”;
2. String s= “a”;
s +=”b”;
1.请看下面的写法有没有区别? 假设s是一个字符串。
第一种写法:
if(s.equals("world")) {
}
第二种写法:
if("world".equals(s)) {
}
答案:有却别.如果s是外界传递的一个参数,可能别人传递一个null。这个时候,前者就会有空指针异常。后者没有问题。
推荐:在判断的时候把常量写在前面。