Javaweb微专业第六讲-----数组与字符串

来源:互联网 发布:英文原著推荐 知乎 编辑:程序博客网 时间:2024/04/28 02:24

有时候我们需要一组相同数据类型的变量,这时候我们就要用数组来实现
数 组:用于存储同一类型数据的一个容器。好处:可以对该容器中的数据进行编号,从0开始。数组用于封装数据,就是一个具体的实体。

一、数组的相关操作

1.数组声明、初始化、属性

1.1数组声明的几种方式

type[] 变量名 = new type[数组中元素的个数];
type 变量名[] = new type[数组中元素的个数];
type[] 变量名 = new type[]{逗号分隔的初始化值};
type[] 变量名 = {元素1,元素2…};

2.数组的几种初始化方式

方式一

String[] strs = new String[2];strs[0] = "0";strs[1] = "1";

方式二

String[] strs = new String[]{"0", "1"};

方式三

String[] strs = {"0", "1"};

3.属性

获取数组长度:数组名.length

2.数组的几种遍历方法

2.1 for循环遍历(其他循环遍历也可以)

int[] a = new int[10] ;        for(int i=0;i<a.length;i++){            a[i]=0;        }

2.2 for-each循环

    for(int t:a){            System.out.println(t);        }

注:这里t就是数组元素的拷贝,不能通过t来修改数组元素的值

3.数组的排序、查找

3.1 数组的排序

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 数组的查找

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(key<arr[mid])                max = mid - 1;            if(max<min)                return -1;            mid = (max+min)>>1;         }        return mid;    }

3.2.2 用Arrays类进行二分查找
public static int binarySearch(Object[] a, Object key);
例如
Arrays.binarySearch(a, 10);

4.Arrays 类

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);

5.二维数组

5.1声明与初始化

int[][] arr = new int[2][3];int[][] arr = new int[2][];int[][] arr = {{1,2,3},{4,5},{6,7,8,9}};

5.2 二维数组的遍历

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

5.3二维数组 的几个问题

1.二维数组的定义格式
int[][] arr = new int[2][]; 可以。
int[][] arr = new int[][3]; 不可以。一定要先给行,在考虑列。
2.int[] x,y[];请问x和y有区别吗?
有区别,x是一维数组,y是二维数组。

二、字符串的相关操作

1.字符串创建

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对象.

2.字符串的拼接

str=”hello”+”world”
aa.concat(str)

3.字符串的属性与方法

3.1.获取字符串长度

a.length();

3.2 特殊字符

回车 ‘\r’
换行 ‘\n’
Tab ‘\t’
换页 ‘\f’
退格 ‘\b’
单引号 ‘\’
换码符 ‘\’
双引号 ‘\”’

4.String类

4.1 不可修改性

通过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[];

4.2不能被继承

因为final是最终意思,final限定的类是最终类,没有其子类。所以不能够被继承。关于继承这个概念会在第八讲面向对象详细说明。

4.3 String对象的方法

String类的equals()方法用来确定两个字符串是否相等
charAt()用以得到指定位置的字符
getChars()用以得到字符串的一部分字符串
subString()是提取字符串的另一种方法,它可以指定从何处开始提取字符串以及何处结束
replace()方法可以将字符串中的一个字符替换为另一个字符
toUpperCase()和toLowerCase()方法分别实现字符串大小写的转换
trim()方法可以将字符串中开头和结尾处的空格去掉.
String类提供静态方法valueOf(),它可以将任何类型的数据对象转换为一个字符串。

我们说String类是不可变字符序列,如果频繁的修改,将会产生很多的String对象,开销很大。有时候我们需要用到可变字符序列,jdk为我们提供了StringBuffer类与StringBuilder类。

4.4 String对象的intern()方法

5.StringBuffer类

StringBuffer对象的每次修改都会改变对象自身,这点是和String类最大的区别。StringBuffer是线程安全的(后续笔记中,将讲到多线程编程)。

5.1 StringBuffer创建

StringBuffer sb = new StringBuffer();
StringBuffer sb = new StringBuffer(“xiaoqingchun”);

5.2 StringBuffer的常用方法

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在继承关系,无法进行强转

6.StringBuilder类

6.1 创建

StringBuilder sb= new StringBuilder(“xiaoqingchun!”);

6.2 常用方法

方法 作用 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) 设置长度

7.String,StringBuffer与StringBuilder的区别

7.1 效率比较

通常情况下 : 三者在执行速度方面的比较: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));    }}

7.2 StringBuilder与 StringBuffer的比较

1.StringBuffer线程安全、效率相对低
2.StringBuilder线程不安全、效率相对高

7.3StringBuffer面试关键点:

(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”;

7.4 一些面试题

1.请看下面的写法有没有区别? 假设s是一个字符串。
第一种写法:

if(s.equals("world")) {    }

第二种写法:

    if("world".equals(s)) {    }

答案:有却别.如果s是外界传递的一个参数,可能别人传递一个null。这个时候,前者就会有空指针异常。后者没有问题。
推荐:在判断的时候把常量写在前面。

0 0
原创粉丝点击