StringBuffer、StringBuilder和String一样,也用来代表字符串。String类是不可变类,任何对String的改变都 会引发新的String对象的生成;StringBuffer则是可变类,任何对它所指代的字符串的改变都不会产生新的对象。既然可变和不可变都有了,为何还有一个StringBuilder呢?相信初期的你,在进行append时,一般都会选择StringBuffer吧!

先说一下集合的故事,HashTable是线程安全的,很多方法都是synchronized方法,而HashMap不是线程安全的,但其在单线程程序中的性能比HashTable要高。StringBuffer和StringBuilder类的区别也是如此,他们的原理和操作基本相同,区别在于StringBufferd支持并发操作,线性安全的,适 合多线程中使用。StringBuilder不支持并发操作,线性不安全的,不适合多线程中使用。新引入的StringBuilder类不是线程安全的,但其在单线程中的性能比StringBuffer高。

接下来,我直接贴上测试过程和结果的代码,一目了然:

[java] view plain copy

public class StringTest {

public static String BASEINFO = “Mr.Y”;

public static final int COUNT = 2000000;

/**

* 执行一项String赋值测试

*/

public static void doStringTest() {

String str =new String(BASEINFO);

long starttime = System.currentTimeMillis();

for (int i = 0; i < COUNT / 100; i++) {

str = str +”miss”;

​ }

long endtime = System.currentTimeMillis();

​ System.out.println((endtime - starttime)

+” millis has costed when used String.”);

}

/**

* 执行一项StringBuffer赋值测试

*/

public static void doStringBufferTest() {

StringBuffer sb =new StringBuffer(BASEINFO);

long starttime = System.currentTimeMillis();

for (int i = 0; i < COUNT; i++) {

sb = sb.append(“miss”);

​ }

long endtime = System.currentTimeMillis();

​ System.out.println((endtime - starttime)

+” millis has costed when used StringBuffer.”);

}

/**

* 执行一项StringBuilder赋值测试

*/

public static void doStringBuilderTest() {

StringBuilder sb =new StringBuilder(BASEINFO);

long starttime = System.currentTimeMillis();

for (int i = 0; i < COUNT; i++) {

sb = sb.append(“miss”);

​ }

long endtime = System.currentTimeMillis();

​ System.out.println((endtime - starttime)

+” millis has costed when used StringBuilder.”);

}

/**

* 测试StringBuffer遍历赋值结果

*

* @param mlist

*/

public static void doStringBufferListTest(List mlist) {

StringBuffer sb =new StringBuffer();

long starttime = System.currentTimeMillis();

for (String string : mlist) {

​ sb.append(string);

​ }

long endtime = System.currentTimeMillis();

System.out.println(sb.toString() +”buffer cost:”

+ (endtime - starttime) +” millis”);

}

/**

* 测试StringBuilder迭代赋值结果

*

* @param mlist

*/

public static void doStringBuilderListTest(List mlist) {

StringBuilder sb =new StringBuilder();

long starttime = System.currentTimeMillis();

for (Iterator iterator = mlist.iterator(); iterator.hasNext();) {

​ sb.append(iterator.next());

​ }

long endtime = System.currentTimeMillis();

System.out.println(sb.toString() +”builder cost:”

+ (endtime - starttime) +” millis”);

}

public static void main(String[] args) {

​ doStringTest();

​ doStringBufferTest();

​ doStringBuilderTest();

List list =new ArrayList();

list.add(“ I “);

list.add(“ like “);

list.add(“ BeiJing “);

list.add(“ tian “);

list.add(“ an “);

list.add(“ men “);

list.add(“ . “);

​ doStringBufferListTest(list);

​ doStringBuilderListTest(list);

}

}

看一下执行结果:

2711 millis has costed when used String.

211 millis has costed when used StringBuffer.

141 millis has costed when used StringBuilder.

I like BeiJing tian an men . buffer cost:1 millis

I like BeiJing tian an men . builder cost:0 millis

从上面的结果可以看出,不考虑多线程,采用String对象时(我把Count/100),执行时间比其他两个都要高,而采用StringBuffer对象和采用StringBuilder对象的差别也比较明显。由此可见,如果我们的程序是在单线程下运行,或者是不必考虑到线程同步问题,我们应该优先使用StringBuilder类;如果要保证线程安全,自然是StringBuffer。

从后面List的测试结果可以看出,除了对多线程的支持不一样外,这两个类的使用方式和结果几乎没有任何差别

设置焦点(需要同时设置以下3个属性): edit.setFocusable(true);
edit.setFocusableInTouchMode(true);
edit.requestFocus();

取消焦点:edit.setFocusable(false);

SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,比如Activity状态,Activity暂停时,将此activity的状态保存到SharedPereferences中;当Activity重载,系统回调方法onSaveInstanceState时,再从SharedPreferences中将值取出。
#####操作模式:
SharedPreferences数据的四种操作模式

  • Context.MODE_PRIVATE
  • Context.MODE_APPEND
  • Context.MODE_WORLD_READABLE
  • Context.MODE_WORLD_WRITEABLE
  • Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容
  • Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件.
  • Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件.
  • MODE_WORLD_READABLE:表示当前文件可以被其他应用读取.
  • MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入
    特别注意:出于安全性的考虑,MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE 在Android 4.2版本中已经被弃用

#####存储数据:

1
2
3
4
5
6
7

SharedPreferences sp = mContext.getSharedPreferences("name", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("username", username);
editor.putString("passwd", passwd);
editor.commit();
//更改数据方法一样,直接提交新的值给KEY就ok

#####读取数据:

1
2
3
SharedPreferences sp = mContext.getSharedPreferences("name", Context.MODE_PRIVATE);
string name=sp.getString("username", "默认值"));
string password=sp.getString("passwd", ""));

####清空指定数据:

1
2
3
4
SharedPreferences sp = mContext.getSharedPreferences("name", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove("username");//key名称
editor.commit();

####清空所有数据:

1
2
3
4
SharedPreferences sp = mContext.getSharedPreferences("name", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
editor.commit();
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
private void MorePopShow() {
View view = LayoutInflater.from(this).inflate(R.layout.layout_target_more, null, false);
TextView tv_note_delete = (TextView) view.findViewById(R.id.tv_note_delete);
//1.构造一个PopupWindow,参数依次是加载的View,宽高
PopupWindow popWindow = new PopupWindow(view,
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
popWindow.setAnimationStyle(R.anim.note_pop_anim);
//设置加载动画
//这些为了点击非PopupWindow区域,PopupWindow会消失的,如果没有下面的
//代码的话,你会发现,当你把PopupWindow显示出来了,无论你按多少次后退键
//PopupWindow并不会关闭,而且退不出程序,加上下述代码可以解决这个问题
popWindow.setTouchable(true);
//popWindow.setTouchInterceptor(new View.OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// return false;
// // 这里如果返回true的话,touch事件将被拦截
// // 拦截后 PopupWindow的onTouchEvent不被调用,这样点击外部区域无法dismiss
// }
//});
popWindow.setBackgroundDrawable(new ColorDrawable(0x00000000)); //要为popWindow设置一个背景才有效
//设置popupWindow显示的位置,参数依次是参照View,x轴的偏移量,y轴的偏移量
popWindow.showAsDropDown(iv_more, 50, 0);
tv_note_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

popWindow.dismiss();
}
});
}

Java多线程

Java中,可运行的程序都是有一个或多个进程组成。进程则是由多个线程组成的。

最简单的一个进程,会包括mian线程以及GC线程。

线程的状态

线程状态由以下一张网上图片来说明:

img

在图中,红框标识的部分方法,可以认为已过时,不再使用。

(1)wait、notify、notifyAll是线程中通信可以使用的方法。线程中调用了wait方法,则进入阻塞状态,只有等另一个线程调用与wait同一个对象的notify方法。这里有个特殊的地方,调用wait或者notify,前提是需要获取锁,也就是说,需要在同步块中做以上操作。

(2)join方法。该方法主要作用是在该线程中的run方法结束后,才往下执行。如以下代码:

package com.thread.simple;

public class ThreadJoin {

public static void main(String[] args) {

Threadthread= new Thread(new Runnable() {

​ @Override

​ public void run() {

​ System.err.println(“线程”+Thread.currentThread().getId()+” 打印信息”);

​ }

​ });

​ thread.start();

​ try {

​ thread.join();

​ } catch (InterruptedException e) {

​ // TODO Auto-generated catch block

​ e.printStackTrace();

​ }

​ System.err.println(“主线程打印信息”);

}

}

该方法显示的信息是:

线程8 打印信息

主线程打印信息

如果去掉其中的join方法,则显示如下:

主线程打印信息

线程8 打印信息

(3)yield方法。这个是线程本身的调度方法,使用时你可以在run方法执行完毕时,调用该方法,告知你已可以出让内存资源。

其他的线程方法,基本都会在日常中用到,如start、run、sleep,这里就不再介绍。

Synchronized(同步锁)

在Java中使用多线程,你就不能绕过同步锁这个概念。这在多线程中是十分重要的。

在Java多线程的使用中,你必然会遇到一个问题:多个线程共享一个或者一组资源,这资源包括内存、文件等。

很常见的一个例子是,张三在银行账户存有9999元,经过多次的取100,存100后,账户还有多少钱?

看代码:

以下表示账户信息:

package com.thread.simple;

import java.sql.Time;

import java.util.concurrent.TimeUnit;

public class Account {

private String name;

private float amt;

public Account(String name,float amt) {

this.name=name;

this.amt=amt;

}

public void increaseAmt(float increaseAmt){

​ try {

​ TimeUnit.SECONDS.sleep(1);

​ } catch (InterruptedException e) {

​ // TODO Auto-generated catch block

​ e.printStackTrace();

​ }

​ amt+=increaseAmt;

}

public void decreaseAmt(float decreaseAmt){

​ try {

​ TimeUnit.SECONDS.sleep(1);

​ } catch (InterruptedException e) {

​ // TODO Auto-generated catch block

​ e.printStackTrace();

​ }

amt-=decreaseAmt;

}

public void printMsg(){

​ System.out.println(name+”账户现有金额为:”+amt);

}

}

以下是我们操作账户的方法:

​ final int NUM=100;

Thread[]threads=new Thread[NUM];

for(inti=0;i

​ if(threads[i]==null){

​ threads[i]=new Thread(new Runnable() {

​ @Override

​ public void run() {

​ account.increaseAmt(100f);

​ account.decreaseAmt(100f);

​ }

​ });

​ threads[i].start();

​ }

​ }

for(inti=0;i

​ try {

​ threads[i].join();

​ } catch (InterruptedException e) {

​ // TODO Auto-generated catch block

​ e.printStackTrace();

​ }

​ }

​ account.printMsg();

你会发现,每次打印出来的账户余额都不一定是一样的。这就是同步锁的必要性。

java中,提供了多种使用同步锁的方式。

(1)对动态方法的修饰。

作用的是调用该方法的对象(或者说对象引用)。

public synchronized void doSomething(){}

( 2) 对代码块的修饰。

作用的是调用该方法的对象(或者说对象引用)。

public void increaseAmt(float increaseAmt){

​ try {

​ TimeUnit.SECONDS.sleep(1);

​ } catch (InterruptedException e) {

​ // TODO Auto-generated catch block

​ e.printStackTrace();

​ }

​ synchronized (this) {

​ System.out.println(this);

​ amt+=increaseAmt;

​ }

}

(3)对静态方法的修饰。

作用的是静态方法所在类的所有对象(或者说对象引用)。

public synchronized static void increaseAmt(float increaseAmt){

​ try {

​ TimeUnit.SECONDS.sleep(1);

​ } catch (InterruptedException e) {

​ // TODO Auto-generated catch block

​ e.printStackTrace();

​ }

​ amt+=increaseAmt;

}

(4)对类的修饰。

作用的是静态方法所在类的所有对象(或者说对象引用)。

synchronized (AccountSynchronizedClass.class) {

amt-=decreaseAmt;

}

以修饰代码块的方式为例,我们重新运行以上代码后,得到了正确的结果。代码如下:

package com.thread.simple;

import java.util.concurrent.TimeUnit;

/**

* Synchronized 代码块

* @author 战国

*

*/

public class AccountSynchronizedBlock {

private String name;

private float amt;

public AccountSynchronizedBlock(String name,float amt) {

this.name=name;

this.amt=amt;

}

public void increaseAmt(float increaseAmt){

​ try {

​ TimeUnit.SECONDS.sleep(1);

​ } catch (InterruptedException e) {

​ // TODO Auto-generated catch block

​ e.printStackTrace();

​ }

​ synchronized (this) {

​ System.out.println(this);

​ amt+=increaseAmt;

​ }

}

public void decreaseAmt(float decreaseAmt){

​ try {

​ TimeUnit.SECONDS.sleep(1);

​ } catch (InterruptedException e) {

​ // TODO Auto-generated catch block

​ e.printStackTrace();

​ }

​ synchronized (this) {

​ System.out.println(this);

amt-=decreaseAmt;

​ }

}

public void printMsg(){

​ System.out.println(name+”账户现有金额为:”+amt);

}

}

//多线程synchronized修饰代码块 ,每次计算的值都一样

final AccountSynchronizedBlockaccount=new AccountSynchronizedBlock(“张三”, 9999.0f);

final intNUM=50;

Thread[]threads=new Thread[NUM];

for(inti=0;i

​ if(threads[i]==null){

​ threads[i]=new Thread(new Runnable() {

​ @Override

​ public void run() {

​ account.increaseAmt(100f);

​ account.decreaseAmt(100f);

​ }

​ });

​ threads[i].start();

​ }

​ }

for(inti=0;i

​ try {

​ threads[i].join();

​ } catch (InterruptedException e) {

​ // TODO Auto-generated catch block

​ e.printStackTrace();

​ }

​ }

​ account.printMsg();

以上是同步锁的简单说明。

在JDK5中,Java又引入了一个相似的概念Lock,也就是锁。功能与synchronized是类似的。

Lock

Lock对比synchronized有高手总结的差异如下:

总结来说,Lock和synchronized有以下几点不同:

  1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;

  2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

  3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

  4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

  5)Lock可以提高多个线程进行读操作的效率。

  在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

(参考http://www.cnblogs.com/dolphin0520/p/3923167.html)。

Lock的操作与synchronized相比,灵活性更高,而且Lock提供多种方式获取锁,有Lock、ReadWriteLock接口,以及实现这两个接口的ReentrantLock类、ReentrantReadWriteLock类。

对Lock的简单操作代码如下:

package com.thread.simple;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReadWriteLock;

import java.util.concurrent.locks.ReentrantLock;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LockImp {

private Locklock=new ReentrantLock();

private ReadWriteLockrwLock=new ReentrantReadWriteLock();

private List list=new ArrayList();

public void doReentrantLock(Thread thread){

​ lock.lock();

​ System.out.println(thread.getName()+”获取锁”);

​ try {

for(inti=0;i<10;i++){

​ list.add(i);

​ }

​ } catch (Exception e) {

​ }finally{

​ lock.unlock();

​ System.out.println(thread.getName()+”释放锁”);

​ }

}

public void doReentrantReadLock(Thread thread){

​ rwLock.readLock().lock();

​ System.out.println(thread.getName()+”获取读锁”);

​ try {

for(inti=0;i<10;i++){

​ list.add(i);

​ }

​ } catch (Exception e) {

​ }finally{

​ rwLock.readLock().unlock();

​ System.out.println(thread.getName()+”释放读锁”);

​ }

}

public void doReentrantWriteLock(Thread thread){

​ rwLock.writeLock().lock();

​ System.out.println(thread.getName()+”获取写锁”);

​ try {

for(inti=0;i<10;i++){

​ list.add(i);

​ }

​ } catch (Exception e) {

​ }finally{

​ rwLock.writeLock().unlock();

​ System.out.println(thread.getName()+”释放写锁”);

​ }

}

/**

* @param args

*/

public static void main(String[] args) {

final LockImplockImp=new LockImp();

final Threadthread1=new Thread();

final Threadthread2=new Thread();

final Threadthread3=new Thread();

​ new Thread(new Runnable() {

​ @Override

​ public void run() {

​ lockImp.doReentrantLock(thread1);

​ }

​ }).start();

​ new Thread(new Runnable() {

​ @Override

​ public void run() {

​ lockImp.doReentrantLock(thread2);

​ }

​ }).start();

​ new Thread(new Runnable() {

​ @Override

​ public void run() {

​ lockImp.doReentrantLock(thread3);

​ }

​ }).start();

​ lockImp.doReentrantReadLock(thread1);

​ lockImp.doReentrantReadLock(thread2);

​ lockImp.doReentrantReadLock(thread3);

​ lockImp.doReentrantWriteLock(thread1);

​ lockImp.doReentrantWriteLock(thread2);

​ lockImp.doReentrantWriteLock(thread3);

}

}

Lock的使用中,务必需要lock、unlock同时使用,避免死锁。

1.1正则表达式的概念

正则表达式(英语:Regular Expression,在代码中常简写为regex)。

正则表达式是一个字符串,使用单个字符串来描述、用来定义匹配规则,匹配一系列符合某个句法规则的字符串。在开发中,正则表达式通常被用来检索、替换那些符合某个规则的文本。

1.2 正则表达式的匹配规则

参照帮助文档,在Pattern类中有正则表达式的的规则定义,正则表达式中明确区分大小写字母。我们来学习语法规则。

正则表达式的语法规则:

字符:x

含义:代表的是字符x

例如:匹配规则为**”a”**,那么需要匹配的字符串内容就是”a”

字符:****\

含义:代表的是反斜线字符’'

例如:匹配规则为**”\“,**那么需要匹配的字符串内容就是”\”

字符:****\t

含义:制表符

例如:匹配规则为**”\t**”,那么对应的效果就是产生一个制表符的空间

字符:****\n

含义:换行符

例如:匹配规则为**”\n”**,那么对应的效果就是换行,光标在原有位置的下一行

字符:****\r

含义:回车符

例如:匹配规则为**”\r”** ,那么对应的效果就是回车后的效果,光标来到下一行行首

字符类:[abc]

含义:代表的是字符a、b 或 c

例如:匹配规则为**”[abc]”** ,那么需要匹配的内容就是字符a,或者字符b,或字符c的一个

字符类:[^abc]

含义:代表的是除了a、b 或 c以外的任何字符

例如:匹配规则为**”[^abc]”**,那么需要匹配的内容就是不是字符a,或者不是字符b,或不是字符c的任意一个字符

字符类:[a-zA-Z]

含义:代表的是a到 z 或 A 到 Z,两头的字母包括在内

例如:匹配规则为**”[a-zA-Z]”**,那么需要匹配的是一个大写或者小写字母

字符类:[0-9]

含义:代表的是0到9数字,两头的数字包括在内

例如:匹配规则为**”[0-9]”**,那么需要匹配的是一个数字

字符类:[a-zA-Z_0-9]

含义:代表的字母或者数字或者下划线(即单词字符)

例如:匹配规则为**” [a-zA-Z_0-9] “**,那么需要匹配的是一个字母或者是一个数字或一个下滑线

预定义字符类:.

含义:代表的是任何字符

例如:匹配规则为**” . “**,那么需要匹配的是一个任意字符。如果,就想使用.的话,使用匹配规则”\.”来实现

预定义字符类:****\d

含义:代表的是0到9数字,两头的数字包括在内,相当于[0-9]

例如:匹配规则为**”\d “**,那么需要匹配的是一个数字

预定义字符类:****w

含义:代表的字母或者数字或者下划线(即单词字符),相当于**[a-zA-Z_0-9]**

例如:匹配规则为**”\w “**,,那么需要匹配的是一个字母或者是一个数字或一个下滑线

边界匹配器:****^

含义:代表的是行的开头

例如:匹配规则为^[abc][0-9]$ ,那么需要匹配的内容从[abc]这个位置开始, 相当于左双引号

边界匹配器:$

含义:代表的是行的结尾

例如:匹配规则为^[abc][0-9]$ ,那么需要匹配的内容以[0-9]这个结束, 相当于右双引号

边界匹配器:****\b

含义:代表的是单词边界

例如:匹配规则为**”\b[abc]\b”** ,那么代表的是字母a或b或c的左右两边需要的是非单词字符([a-zA-Z_0-9])

数量词:****X?

含义:代表的是X出现一次或一次也没有

例如:匹配规则为**”a?”**,那么需要匹配的内容是一个字符a,或者一个a都没有

数量词:****X*

含义:代表的是X出现零次或多次

例如:匹配规则为**”a*“** ,那么需要匹配的内容是多个字符a,或者一个a都没有

数量词:****X+

含义:代表的是X出现一次或多次

例如:匹配规则为**”a+”**,那么需要匹配的内容是多个字符a,或者一个a

数量词:****X{n}

含义:代表的是X出现恰好 n 次

例如:匹配规则为**”a{5}”**,那么需要匹配的内容是5个字符a

数量词:****X{n,}

含义:代表的是X出现至少 n 次

例如:匹配规则为**”a{5, }”**,那么需要匹配的内容是最少有5个字符a

数量词:****X{n,m}

含义:代表的是X出现至少 n 次,但是不超过 m 次

例如:匹配规则为**”a{5,8}”**,那么需要匹配的内容是有5个字符a 到 8个字符a之间

1.3 正则表达式规则匹配练习

请写出满足如下匹配规则的字符串:

规则:”[0-9]{6,12}”

该规则需要匹配的内容是:长度为****6位到12位的数字。

如:使用数据”123456789”进行匹配结果为true;

使用数据”12345”进行匹配结果为false。

规则:”1[34578][0-9]{9}”

该规则需要匹配的内容是:11位的手机号码,第1位为1,第2位为3、4、5、7、8中的一个,后面9位为0到9之间的任意数字

如:使用数据”12345678901”进行匹配结果为false;

使用数据”13312345678”进行匹配结果为true。

规则:”a*b”

该规则需要匹配的内容是:在多个a或零个a后面有个b;b必须为最后一个字符。

如:使用数据”aaaaab”进行匹配结果为true;

使用数据”abc”进行匹配结果为false。

1.4 字符串类中涉及正则表达式的常用方法

img

public boolean matches(String regex) //判断字符串是否匹配给定的规则

举例:校验qq号码.

举例:校验qq号码.

1: 要求必须是5-15位数字

2: 0不能开头

代码演示:

String qq = “604154942”;

String regex = “[1-9][0-9]{4,14}”;

boolean flag2 = qq.matches(regex);

举例:校验手机号码

1:要求为11位数字

2:第1位为1,第2位为3、4、5、7、8中的一个,后面9位为0到9之间的任意数字。

代码演示:

String phone = “18800022116”;

String regex = “1[34578][0-9]{9}”;

boolean flag = phone.matches(regex);

public String[] split(String regex) //根据给定正则表达式的匹配规则,拆分此字符串

举例:分割出字符串中的的数字

代码演示:

String s = “18-22-40-65”;

String regex = “-“;

String[] result = s.split(regex);

代码演示:

String s = “18 22 40 65”;

String regex = “ “;

String[] result = s.split(regex);

public String replaceAll(String regex,String replacement) //将符合规则的字符串内容,全部替换为新字符串

举例:把文字中的数字替换成*

代码演示:

String s = “Hello12345World6789012”;

String regex = “[0-9]”;

String result = s.replaceAll(regex, “*”);

1.5 正则表达式练习

匹配正确的数字

匹配规则:

匹配正整数:”\d+”

匹配正小数:”\d+\.\d+”

匹配负整数:”-\d+”

匹配负小数:”-\d+\.\d+”

匹配保留两位小数的正数:”\d+\.\d{2}”

匹配保留1-3位小数的正数:”\d+\.\d{1,3}”

匹配合法的邮箱

匹配规则:

”[a-zA-Z_0-9]+@[a-zA-Z_0-9]+(\.[a-zA-Z_0-9]+)+”

”\w+@\w+(\.\w+)+”

获取IP地址(192.168.1.100)中的每段数字

匹配规则:

”\.”

多线程之间的通信

线程通信概念:线程是操作系统中独立的个体,但这些个体如果不经过特殊处理就不能成为一个整体,线程间的通信就成为整体的必用方式之一。当线程存在通信指挥,系统间的交互性会更强大,在提高CPU利用率的同时还会使开发人员对线程任务在处理过程中进行有效的把控与监督。

使用wait/notify 方法实现线程间的通信。(注意这两个方法都是Object类的方法,换句话说Java为所有的对象都提供了这两个方法)

wait 和 notify 必须配合synchronized 关键字使用。

wait 方法释放锁,notify 方法不释放锁

使用轮询的方式通信

publicstaticvoidmain(String[] args){finalListAddTest1 list =newListAddTest1(); Thread thread_1 =newThread(newRunnable() {@Overridepublicvoidrun(){for(inti =0; i <10; i++) {try{ list.add(); System.out.println(“当前线程:”+ Thread.currentThread().getName() +” 添加一个元素!”); Thread.sleep(500); }catch(InterruptedException e) { e.printStackTrace(); } } } },”Thread-1”); Thread thread_2 =newThread(newRunnable() {@Overridepublicvoidrun(){while(true) {if(list.size() ==5) { System.out.println(“当前线程收到通知:”+ Thread.currentThread().getName() +” list size = 5 线程停止..”);thrownewRuntimeException(); } } } },”Thread-2”); thread_1.start(); thread_2.start();}

使用notify 和 wait 方法通信

如上述的代码,thread-2 线程一种处于一种轮询的方式,我们可以修改Java中多线程通信的方式来改造, 使用notify 和 wait.

注意必须配合 synchronized 关键字来使用,否则会报 java.lang.IllegalMonitorStateException 非法监控异常

必须先启动 wait 方法的线程,因为notify 方法不会释放锁,先启动notify 方法的线程,执行到 notify 方法的时候,并没有线程在 wait.

publicstaticvoidmain(String[] args){finalListAddUseNotifyAndWait list =newListAddUseNotifyAndWait();finalObject lock =newObject(); Thread thread_1 =newThread(newRunnable() {@Overridepublicvoidrun(){// synchronized (lock) {try{for(inti =0; i <10; i++) { list.add(); System.out.println(“当前线程:”+ Thread.currentThread().getName() +” 添加一个元素!”); Thread.sleep(500);if(list.size() ==5) { System.out.println(“已经发出通知!”); lock.notify();// notify 方法不会释放锁} } }catch(InterruptedException e) { e.printStackTrace(); }// }} },”Thread-1”); Thread thread_2 =newThread(newRunnable() {@Overridepublicvoidrun(){try{// synchronized (lock) {if(list.size() !=5) { System.out.println(“Thread-2进入…”); lock.wait();// wait 方法会释放锁} System.out.println(“当前线程收到通知:”+ Thread.currentThread().getName() +” list size = 5 线程停止..”);thrownewRuntimeException();// }}catch(InterruptedException e) { e.printStackTrace(); } } },”Thread-2”);// 需要先启动 thread_2 , 因为如果先启动 thread_1, 那么 notify 方法不会释放锁,// t1线程完全执行完才会释放锁, 当t1到notify 方法的时候,并没有 其他线程在 waitthread_2.start(); thread_1.start();}

使用CountDownLatch 闭锁来进行通信

在使用notify 和 wait 来进行通信的时候还有一个问题,在程序中我们必须等 thread-1 执行完成,才会释放锁来通知 thread-2,这会造成不实时的问题。如果需要程序在 list.size 为5 的时候,就立马执行 thread-2 中的线程的话,我们就可以使用 CountDownLatch 的方式来进行通信

finalCountDownLatch countDownLatch =newCountDownLatch(1);Thread thread_1 =newThread(newRunnable() {@Overridepublicvoidrun(){try{for(inti =0; i <10; i++) { list.add(); System.out.println(“当前线程:”+ Thread.currentThread().getName() +” 添加一个元素!”); Thread.sleep(500);if(list.size() ==5) { System.out.println(“已经发出通知!”); countDownLatch.countDown(); } } }catch(InterruptedException e) { e.printStackTrace(); } }},”Thread-1”);Thread thread_2 =newThread(newRunnable() {@Overridepublicvoidrun(){try{if(list.size() !=5) { System.out.println(“Thread-2进入…”); countDownLatch.await(); } System.out.println(“当前线程收到通知:”+ Thread.currentThread().getName() +” list size = 5 线程停止..”);thrownewRuntimeException(); }catch(InterruptedException e) { e.printStackTrace(); } }},”Thread-2”);thread_1.start();thread_2.start();

###1.Json概念以及与XML的比较

  1. Json是什么?

    答:JavaScript Object Natation, 一种轻量级的数据交换格式, 与XML一样, 广泛被采用的客户端和服务端交互的解决方案!具有良好的可读和便于快速编写的特性。

  2. Json与XML的比较:

  • JSON和XML的数据可读性基本相同;
  • JSON和XML同样拥有丰富的解析手段
  • JSON相对于XML来讲,数据的体积小
  • JSON与JavaScript的交互更加方便
  • JSON对数据的描述性比XML较差
  • JSON的速度要远远快于XML

    PS:上述来自于百度~简单点说Json的优点:体积小,节省流量,只是不如XML直观,可读性 稍微差一点而已!

  1. Json的格式规范:

    就像协议一样,肯定是有一套规范的,毕竟双方都是通过Json字符串来传递数据,语法规则如下: 数据在名称/值对中;数据由逗号分隔;花括号保存对象;方括号保存数组; 而Json数据的书写格式:名称/值对 比如: “person”:”coder-pig” 比如一个简单的Json字符串:

    1
    2
    3
    4
    5
    [
    { "id":"1","name":"基神","age":"18" },
    { "id":"2","name":"B神","age":"18" },
    { "id":"3","name":"曹神","age":"18" }
    ]

###2.Android给我们提供的Json解析类
##这些API都存在于org.json包下,而我们用到的类有下面这些:

  • JSONObject: Json对象,可以完成Json字符串与Java对象的相互转换
  • JSONArray: Json数组,可以完成Json字符串与Java集合或对象的相互转换
  • JSONStringer: Json文本构建类,这个类可以帮助快速和便捷的创建JSON text, 每个JSONStringer实体只能对应创建一个JSON text
  • JSONTokener:Json解析类
  • JSONException:Json异常

###3.代码示例:解析Json字符串:

  1. 简单的Json字符串解析示例:
    我们解析的是上面这个简单的Json,首先我们来写一个POJO类:
    Person.java:
    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
    public class Person {
    private String id;
    private String name;
    private String age;
    public void setId(String id){
    this.id = id;
    }
    public String getId(){
    return this.id;
    }
    public void setName(String name){
    this.name = name;
    }
    public String getName(){
    return this.name;
    }
    public void setAge(String age){
    this.age = age;
    }
    public String getAge(){
    return this.age;
    }
    @Override
    public String toString() {
    return this.name + "~年方:" + this.age;
    }
    }
    写一个解析上述Json字符串的方法:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    private void parseEasyJson(String json){
    persons = new ArrayList<Person>();
    try{
    JSONArray jsonArray = new JSONArray(json);
    for(int i = 0;i < jsonArray.length();i++){
    JSONObject jsonObject = (JSONObject) jsonArray.get(i);
    Person person = new Person();
    person.setId(i+"");
    person.setName(jsonObject.getString("name"));
    person.setAge(jsonObject.getString("age"));
    persons.add(person);
    }
    }catch (Exception e){e.printStackTrace();}
    }

##运行效果图:
image.png
2. 复杂的Json字符串解析示例:
如果是这样的Json字符串呢?
image.png

解析代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void parseDiffJson(String json) {
try {
JSONObject jsonObject1 = new JSONObject(json);
Log.e("Json", json);
JSONArray jsonArray = jsonObject1.getJSONArray("ch");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = (JSONObject) jsonArray.get(i);
//取出name
String sname = jsonObject.getString("names");
JSONArray jarray1 = jsonObject.getJSONArray("data");
JSONArray jarray2 = jsonObject.getJSONArray("times");
Log.e("Json", sname);
Log.e("Json", jarray1.toString());
Log.e("Json", jarray2.toString());
}
} catch (Exception e) {
e.printStackTrace();
}

}

看下打印的Log:
image.png

特点:

后台运行,不可见,没有界面;

优先级高于Activity;

用途:

播放音乐,记录地理信息位置的告白,监听某种动作…

注意:

运行在主线程,不能用它来做耗时的请求或者动作

可以在服务中开一个线程,在线程中作耗时操作

类型:

本地服务(Local Service):

应用程序内部:

startService stopService stopSelf stopSelfResult

bindService unbindService

远程服务:(Remote Service):

Android系统内部的应用程序之间(同设备)

定义IBinder接口

生命周期:

左边是start方式启动的生命周期,右边是bind方式启动的生命周期:

img

Start方式特点:

服务跟启动源没有任何联系;

无法得到服务对象;

Bind方式特点:

通过Ibinder接口实例,返回一个ServiceConnection对象给启动源

通过ServiceConnetion对象的相关方法可以得到Service对象

start方式启动:

img

start方式销毁:

img

自定义Service类:

img

bind方式启动:

img

img

bind方式销毁:

img

自定义Service类:

```

public class MyBindService extends Service {

@Override

public void onCreate() {

​ super.onCreate();

}

public IBinder onBind(Intent intent) {

// IBinder这里无法直接使用,需要自己重写一个类去继承Binder

​ return new MyBinder();

}

public class MyBinder extends Binder{

​ public MyBindService getService(){

​ return MyBindService.this;

​ }

}

@Override

public boolean onUnbind(Intent intent) {

​ return super.onUnbind(intent);

}

//定义4个方法模拟播放器

@Override

public void onDestroy() {

​ super.onDestroy();

}

public void play(){

​ Log.e(“tyl”,”播放”);

}

public void pause(){

​ Log.e(“tyl”,”暂停”);

}

public void next(){

​ Log.e(“tyl”,”下一首”);

}

public void pervious(){

​ Log.e(“tyl”,”上一首”);

}

}

```

注册(两种方式一样):

img