1.1、认识StringBuffer类
首先我们知道String类的一个特性是String的内容一旦声明则不可改变,如果改变,则改变的的是String的引用地址,对于经常该百年的字符串使用String性能极差,此时我们可以使用StringBuffer类。
1.2、StringBuffer常用方法
StringBuffer支持的方法大部分与String类似。
因为StringBuffer在开发中可以提升代码性能,所以使用较多。
1.2.1、字符串连接操作 append()
1.2.2、在字符串指定位置添加字符 insert()
1.2.3、字符串反转操作 reverse()
1.2.4、替换字符串指定范围的内容 replace()
1.2.5、字符串截取 substring()
1.2.6、删除指定范围的字符串 delete()
1.2.7、查找指定的内容是否存在 indexOf()
测试代码:
/**
* stringBuffer常用方法
*
* @author guai
*
*/
public class StringBufferMethond {
// @Test
// 字符串连接操作 append()
public void methond1() {
StringBuffer buf = new StringBuffer();
buf.append("guai");
buf.append(" is ");
buf.append(18).append(" ages");
System.out.println("字符串连接方法测试:" + buf);
}
// @Test
// 在字符串指定位置添加字符 insert()
public void methond2() {
StringBuffer buf = new StringBuffer();
buf.append("guai");
buf.insert(0, "Hello");
System.out.println("在字符串指定位置添加字符测试:" + buf);
}
// @Test
// 字符串反转操作 reverse()
public void methond3() {
StringBuffer buf = new StringBuffer();
buf.append("guai");
buf.reverse();
System.out.println("字符串反转操作测试:" + buf);
}
// @Test
// 替换字符串指定范围的内容 replace()
public void methond4() {
StringBuffer buf = new StringBuffer();
buf.append("guai");
buf.replace(0, 1, "sh");
System.out.println("替换字符串指定范围的内容测试:" + buf);
}
// @Test
// 字符串截取 substring()
public void methond5() {
StringBuffer buf = new StringBuffer();
buf.append("guai");
String str = buf.substring(0, 3);
System.out.println("字符串截取测试:" + str);
}
// @Test
// 删除指定范围的字符串 delete()
public void methond6() {
StringBuffer buf = new StringBuffer();
buf.append("guai");
buf.delete(3, 4);
System.out.println("删除指定范围的字符串测试:" + buf);
}
// @Test
// 查找指定的内容是否存在 indexOf()
public void methond7() {
StringBuffer buf = new StringBuffer();
buf.append("guai");
// 结果为-1表示没有找到指定内容否则反之
System.out.println("查找指定的内容是否存在测试:" + buf.indexOf("ui"));
System.out.println("查找指定的内容是否存在测试:" + buf.indexOf("ai"));
}
}
1.1、认识Runtime类
在Java中Runtime类表示运行时操作类,是一个封装了JVM进程的类,每一个JVM都对应着一个Runtime类的实例,此实例由JVM运行时为其实例化。所以在JDK文档中没有Runtime类中构造方法的定义,这是因为Runtime类本身的构造方法是私有化的(单例设计),如果要创建一个Runtime实例,只能通过下面的方法:
Runtime run=Runtime.getRuntime();
也就是说在Runtime类中提供了一个gtetRuntime()静态方法,此类可以取得Runtime类的实例,那么获取Runtime的实例有啥用处呢?
既然Runtime表示每一个JVM实例,所以可以通过Runtime取得一些系统性信息。
1.2、Runtime常用方法:
1.2.1、观察JVM的内存
JCVM最大内存: maxMemory()
JVM当前空余内存:freeMemory()
垃圾回收: gc()
1.2.2、执行本机可执行程序
运行可执行程序:exec()
关闭运行程序:destory()
通过exec()可以启动一个系统可执行程序,查看exec方法的返回值可以发现,其返回值为Process,表示一个操作系统进程的类,我们可以使用该类对启动的程序进行管理。比如关闭比操作。
测试方法:
@Test
//执行本机可执行程序 运行可执行程序:exec() 关闭运行程序:destory(
public void methond2() {
Runtime runtime = Runtime.getRuntime();
Process pro = null;
try {
//打开程序
pro=runtime.exec("notepad.exe");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//关闭进程
pro.destroy();
}
国际化操作指一个程序可以适应多种语言。
3.1、实现思路
根据不同的国家配置不同的资源文件(属性文件.properties),所有资源文件以**“key-value”**的形式出现,在程序执行中只要根据key找到value就可以显示value中的内容,以后只要key不变,value中的内容可以任意更换。
若要实现Java程序的国际化操作,必须使用以下3个类完成。
1)java.util.Locale:用于表示一个国家语言类
2)java.util.ResourceBundle:用于访问资源文件。
3)java.text.MessageFormat:格式化资源文件的占位字符串。
操作流程:通过Local类所指定的区域码,然后ResourceBundle根据Local类所指定的区域码找到相应的资源文件,如果资源文件中存在动态文本,则使用MessageForamt进行格式化操作。
Locale类:
方法定义: public Locale(String language) 构造方法 作用: 根据语言代码构造一个语言环境
方法定义: public Locale(String language,String country) 构造方法 作用: 根据语言和国家构造一个语言环境
ResourceBundle类:
常用方法:
public static final ReaourceBundle getBundle(String baseName) 作用:取得ResourceBundle的实例,并指定要操作的资源文件名称;
public static final ReaourceBundle getBundle(String baseName,Local local) 作用:取得Resource Bundle的实例,并指定要操作的资源文件名称和区域码;
public final String getString(String key) 作用:根据key从资源文件中取出对应的value;
MessageFormat类:
用到的方法:
public static String format(String pattern,Object…arguments);
3.2、实现
3.2.1、创建静态文本
属性文件:
下面列出了一个中文的属性文件,中文在属性文件中显示的时Unicode编码
注意:属性文件的名称需要按照要求命名即:名称_国家代码格式 且多个语言属性文件的名称需要一样。例:language_zh_CN 其中 _zh_CN表示中文中国
测试代码:
@Test
//非动态文本
public void staticProcessing() {
//表示国家语言
Locale zhLoc = new Locale("zh", "CN");
Locale enLoc = new Locale("en", "US");
Locale frLoc = new Locale("fr", "FR");
//加载属性文件
ResourceBundle zhrb = ResourceBundle.getBundle("com.shuai.ChapterEleven.languageProcessing.Language", zhLoc);
ResourceBundle enrb = ResourceBundle.getBundle("com.shuai.ChapterEleven.languageProcessing.Language", enLoc);
ResourceBundle frrb = ResourceBundle.getBundle("com.shuai.ChapterEleven.languageProcessing.Language", frLoc);
//通过键值对读取数据
System.out.println("中文:" + zhrb.getString("info"));
System.out.println("英文:" + enrb.getString("info"));
System.out.println("法文:" + frrb.getString("info"));
}
结果:
3.2.2、动态文本
动态文本指在属性文件中加入占位符(可以加入多个{0}{1}…{n})再通过MessageFormat类的format方法将需要添加的内容填充到占位符的位置上。
属性文件:
测试代码:
@Test
// 动态文本
public void dynamicProcessing() {
// 表示国家语言
Locale zhLoc = new Locale("zh", "CN");
Locale enLoc = new Locale("en", "US");
Locale frLoc = new Locale("fr", "FR");
// 加载属性文件
ResourceBundle zhrb = ResourceBundle.getBundle("com.shuai.ChapterEleven.languageProcessing.Language", zhLoc);
ResourceBundle enrb = ResourceBundle.getBundle("com.shuai.ChapterEleven.languageProcessing.Language", enLoc);
ResourceBundle frrb = ResourceBundle.getBundle("com.shuai.ChapterEleven.languageProcessing.Language", frLoc);
// 通过简直对读取数据
String str1=zhrb.getString("info");
String str2=enrb.getString("info");
String str3=frrb.getString("info");
//拼接文本
System.out.println("中文:" + MessageFormat.format(str1,"乖"));
System.out.println("英文:" + MessageFormat.format(str2,"guai"));
System.out.println("法文:" + MessageFormat.format(str3,"guai"));
}
结果:
4.1、System类是一些与系统相关属性和方法的集合,而且在System类中所有方法都是静态的,要想引用这些属性和方法,直接使用System类调用即可。
4.2、常用方法:
void exit(int status) 作用 :系统退出,如果status为非0就表示退出
void gc() 运行垃圾回收机制,调用的就是Runtime类中的gc方法
long currentTimemillis() 返回以毫秒为单位的当前时间
void arraycopy(Object src,int srcPos,Object dest,int destPos,int length) 数组复制操作
Properties getProperties() 取得当前系统的全部属性
String getProperty(String key) 根据键值取的属性的具体内容
4.3、部分方法测试:
/**
* system类的常用方法
*
* @author guai
*
*/
public class SystemMethod {
// @Test
// long currentTimemillis() 返回以毫秒为单位的当前时间
public void currentTimeMillisTest() {
Long startTime = System.currentTimeMillis();
int sum = 0;
for (int i = 0; i < 1000000000; i++) {
sum += i;
}
Long endTime = System.currentTimeMillis();
System.out.println("消耗时间:" + (endTime - startTime) + "毫秒");
}
// @Test
// Properties getProperties() 取得当前系统的全部属性
public void getPropertiesTest() {
System.getProperties().list(System.out);
}
// @Test
// String getProperty(String key) 根据键值取的属性的具体内容
public void getPropertyTest() {
System.out.println("系统版本为:" + System.getProperty("os.name") + System.getProperty("os.version")
+ System.getProperty("os.arch") + System.getProperty("user.home"));
}
//垃圾对象的回收 例
class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//对象释放空间时默认调用此方法
public void finalize()throws Throwable{
System.out.println("对象释放"+this);
}
}
@Test
public void gcTest() {
Person per=new Person();
per.setName("guai");
//断开引用 释放空间
per=null;
//强制释放空间
System.gc();
}
}
Date类是一个较为简单的操作类,在使用中直接使用 java.util.Date类的构造方法并进行输出就可以得到一个完整的日期,构造方法定义如下:
public Date();
使用:
System.out.println(“当前日期”+new Date());
Calendar类可以取得的时间精确到毫秒。但是这个类本身是一个抽象类,若想使用一个抽象类,则必须依靠对象的多态性,通过子类进行父类的实例化操作,Calendar的子类时GregorianCalendar类。
6.1、Calendar类中的常量和方法
常量:fianl int YEAR ,MONTH, DAY_OF_MONTH,HOUR_OF_DAY,MINUTE,SECOND,MILLISECOND
方法:
public static Calendar getInstance() 根据默认时区实例化对象
boolean after(Object when)判断一个日期是否在指定日期之后
boolean before(Object when)判断一个日期是否在指定日期之前
int get(int field) 返回给日历字段的值
getTimeInMillis():返回从格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000到Calendar对象表示的时间之间的毫秒数。
格式化日期格式
7.1、常用方法
final DateFormat getDateInstace()获得默认对象
final DateFormat getDateInstance(int style,Locale aLocale)根据Locale得到对象
final DateFormat getDateTimeInstance()得到日期对象
final DateFormat getDateTimeInstance(int dateStyle,int timeStyle,Locale aLocale)根据Locale得到日期时间对象
7.2、测试:
1)
@Test
public void getDateMethod() {
DateFormat df1=DateFormat.getDateInstance();
DateFormat df2=DateFormat.getDateTimeInstance();
System.out.println("DATE: "+df1.format(new Date()));
System.out.println("DATETIME: "+df2.format(new Date()));
}
结果:
2)
@Test
public void getDateMethod1() {
DateFormat df1=DateFormat.getDateInstance(DateFormat.YEAR_FIELD,new Locale("zh","CN"));
DateFormat df2=DateFormat.getDateTimeInstance(DateFormat.YEAR_FIELD,DateFormat.ERA_FIELD,new Locale("zh","CN"));
System.out.println("DATE: "+df1.format(new Date()));
System.out.println("DATETIME: "+df2.format(new Date()));
}
结果:
在开发中,经常将一个日期格式转化为另一种日期格式,例将2020-02-02 02:02:02转化为2020/02/02 02:02:02或2020年02月02日 02时02分02秒。此时可以是使用SimpleDateFormat类完成。
常用方法:
SimpleDateFormat(Stringpattern) 构造 通过指定的模板构造对象
Date parse(String source)throws ParseException 将一个表示日期的字符串变为Date类型
final String format(Date date) 将一个Date类型,按照格式变为String类型
测试方法:
@Test
public void testMethod() {
try {
//将字符串中的日期提取出来
Date date=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2020-02-11 12:51:22");
System.out.println(date);
System.out.println("格式后:"+new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒").format(date));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
9.1、 获取当前日期并对年月日进行加减操作
// 对获取到的当前日期中的年月日进行加减操作
//@Test
public void testMethod() {
// 获取当前日期
Calendar calendar = Calendar.getInstance(new Locale("zh", "CN"));
// 格式化当前日期
System.out.println("原始日期:" + new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
// 当前日期的年份减一
calendar.add(Calendar.YEAR, -1);
// 当前日期的月份减一
calendar.add(Calendar.MONTH, -1);
// 当前日期的天数减一
calendar.add(Calendar.DAY_OF_MONTH, -1);
System.out.println("修改后的日期" + new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
// 当前日期的年份加一
calendar.add(Calendar.YEAR, 1);
// 当前日期的月份加一
calendar.add(Calendar.MONTH, 1);
// 当前日期的天数加一
calendar.add(Calendar.DAY_OF_MONTH, 1);
System.out.println("修改后的日期" + new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
}
结果:
9.2、获取两个时间之间的时间间隔
//获取两个时间之间的时间间隔
@Test
public void testMethod1() {
//获取两个时间之间间隔的小时
Calendar calendar=Calendar.getInstance();
Calendar calendar2=Calendar.getInstance();
calendar2.add(Calendar.HOUR_OF_DAY, -12);
System.out.println("calendar: "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar.getTime()));
System.out.println("calendar2: "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar2.getTime()));
//getTimeInMillis():返回从格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000到Calendar对象表示的时间之间的毫秒数
long startTime=calendar.getTimeInMillis();
long endTime=calendar2.getTimeInMillis();
System.out.println("calendar: "+startTime);
System.out.println("calendar2: "+endTime);
double hour=((startTime-endTime)/1000.0/60/60);
System.out.println("两个日期间隔的小时数:"+hour);
double day=((startTime-endTime)/1000.0/60/60/24.0);
System.out.println("两个日期间隔的天数: "+day);
}
结果:
Math类是数学操作类,提供了一系列的数学操作方法,包括绝对值、三角函数等,在Math类中提供的方法都是静态方法。
基本方法:
Math.sqrt(9.0) 9开根号
max(10,32)
min(10,30)
pow(2,3) 求2的3次方
round(33.6) 四舍五入
abs(-10) 求绝对值
boolean nextBoolean() 随机生成一个boolean值
double nextDouble() 随机生成一个double值
float nextFloat()随机生成一个float值
int nextInt()随机生成一个int值
int nextInt(int n) 随机生成一个给定的最大int值
long nextLong() 随机生成一个long值
NumberFormat用于对数字的格式化,根据不同的国家习惯进行格式化
常用方法:
static Locale[]getAvailableLocales() 返回所有语言环境的数组
static final NumberFormat getInstance() 返回当前默认语言环境的数字格式
static NumberFormat getInstance(Locale inLocale) 返回指定语言环境的数字格式
static final NumberFormat getCurrencyInstance() 返回当前默认环境的货币格式
static NumberFormat getCurrencyInstance(Locale inLocale) 返回指定语言环境的数字格式
格式化数字主要用于自定义格式的使用
测试:
/**
* 自定义格式化数字
* @author guai
*
*/
class FormatDemo{
public void format1(String pattern,double value) {
DecimalFormat df=null;
df=new DecimalFormat(pattern);
String str=df.format(value);
System.out.println("使用:"+pattern+" 格式化数字: "+value+": "+ str);
}
}
public class DecimalFormatMethod {
/**
* 0 表示数字,每一个0表示以为数字,如果该位不存在则显示0
* #表示数字,如果不存在则不显示
* .小数点分隔符或货币的小数分隔符
* ,分组分隔符
* %前缀或后缀数字乘以100并显示为百分数
*/
@Test
public void testMethod() {
FormatDemo fm=new FormatDemo();
fm.format1("###,###.###", 111222.34567);
fm.format1("000,000.000", 11222.34567);
fm.format1("###,###.###¥", 11222.34567);
fm.format1("000,000.000¥", 11222.34567);
fm.format1("##.###%", 0.123456);
fm.format1("00.##%", 0.0345678);
fm.format1("###.###\u2030", 0.345678);
}
}
结果:
当一个数字非常大时,则无法使用基本数据类型接受,所以,最早碰到大数字时往往使用String接收,然后采用拆分的方式进行计算,但较为麻烦,在Java中为了解决这样的难题提供了BigInteger类,BigInteger表示大整数类,定义在java.math包中。
14.1、BigInteger常用方法:
BigInteger(String val) 构造方法,将一个字符串变为BigInteger类型
BigInteger add(BigInteger val) 加法
BigInteger subtract(BigInteger val) 减法
BigInteger multiply(BigInteger val ) 乘法
BigInteger divide(BigInteger val) 除法
BigInteger max(BigInteger val) 返回连个数字中的最大值
BigInteger min(BigInteger val) 返回连个数字中的最小值
BigInteger [] divideAndRemainder(BigInteger val) 触发操作,数组的第一个元素为除法的商,第二个元素为除法的余数
对于不需要准去计算计算精度的数字可以直接使用float或double,但是如果需要精确计算的结果,则必须使用BigDeciaml类,而且使用BigDecimal类也可以进行大数的操作。
15.1、BigDecimal类常用方法
BigDecimal (double val) 将double类型转换为BigDecimal
BigDecimal(int val) …
BigDecimal(String val) …
BigDecimal add(BigDecimal augend) …
BigDecimal subtract(BigDecimal subtrahend) 减法
BigDecimal multiply(BigDecimal multiplicand) 乘法
BigDecimal divide(BigDecimal divisor) 除法
测试方法:
/**
* BigDecimal 高精度计算
* @author guai
*
*/
public class BigDecimalMethod {
@Test
public void testMethod() {
BigDecimal bd=new BigDecimal(12.256);
BigDecimal bd1=new BigDecimal(12.256);
BigDecimal result=bd.multiply(bd1);
System.out.println("double:"+12.256*12.256);
System.out.println("result:" +result);
//除一并保留3位小数的四舍五入
System.out.println("BigDecimal 四舍五入:"+ (result.divide(new BigDecimal(1),3,BigDecimal.ROUND_HALF_UP)));
System.out.println("BigDecimal保存可长的数 并运算"+new BigDecimal("211321321231541541541541541413121131241465465454").add(new BigDecimal(1)));
}
}
结果: 精度确实比double高
在java中支持对象克隆操作,直接使用Object类中的clone()方法即可,方法定义如下
protected Object clone() throws CloneNoSupportException
以上方法是受保护的类型,所以在子类中必须覆写此方法,而且覆写之后应该扩大访问群贤,才可以被外部调用,但是具体的克隆方法的实现还是在Object中,所以在覆写的方法中只需要调用Object类中的clone()方法即可完成操作,而且在对象所在的类中必须实现Cloneable接口才可以完成对象的克隆操作。
测试:
/**
* 对象克隆
* @author guai
*
*/
//实现Cloneable接口
class Person implements Cloneable{
private String name;
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//覆写clone方法
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
public class ObjectCloneMethod {
@Test
public void testMethod() throws CloneNotSupportedException {
Person p1=new Person("guai");
Person p2;
p2=(Person) p1.clone();
Person p3=p1;
System.out.println("对象克隆:p1:" +p1+" 克隆对象p2:"+p2);
System.out.println("克隆对象与直接赋值方法的区别");
System.out.println("直接赋值:" +p1.equals(p3));
System.out.println("对象克隆:" +p1.equals(p2));
}
}
结果:
直接赋值属于引用传递, p1,p3指向同一块内存区域
而对象克隆则开辟了新的内存空间,p1和p2指向的不是同一块内存区域。
Arrays 类是数组的操作类,定义在java.util包中,主要功能是实现数组元素的查找、数组内容的填充、排序等
常用方法:
static boolean equals(int[]a,int[]a2) 判断两个数组是否相等,此方法被重载多次,可以判断各种数组类型的数组
static void fill(int[]a,int cal) 将指定内容填充到数组中,此方法被重载多次、、、、
static void sort(int []a) 数组排序,此方法被重载多次、、、、
static int binarySearch(int[] a,int key) 对排序后的数组进行检索,此方法被重载多次、、、
static String toString(int[] a) 输出数组信息,此方法被重载多次、、、
例:
/**
* Arrays数组操作类
* @author guai
*
*/
public class ArraysMethod {
@Test
public void testMethod() {
int temp[]= {3,5,7,9,45,2};
Arrays.sort(temp);
System.out.println("排序后的数组: "+Arrays.toString(temp));
int point=Arrays.binarySearch(temp, 5);
System.out.println("3在数组中的位置: "+point);
Arrays.fill(temp, 3);
System.out.println("数组填充: "+Arrays.toString(temp));
}
}
结果:
在Arrays中可以使用sort()方法对数组进行排序操作,而且该方法被重载多次可以对任意类型的数组排序,排列时会根据数据的大小进行排序。同样此方法也可以对Object类数组进行排序,但是使用此方法排序需要对象所在的类必须实现Comprarble接口,此接口就是用于指定对象排序规则的。
18.1、Comparable接口的定义如下:
public interface Comparable<T>{
public int comparaTo(T o);
}
从定一中可以发现,在Comparable接口中使用了Java泛型技术。其中只有一个comparaTo()方法,此方法返回一个int类型的数据,当时此int的值只能是以下三种:
1:表示大于
-1:表示小于
0:表示相等
18.2、应用:
/**
* Comparable 接口的应用
*
* @author guai
*
*/
// 实现Cloneable接口
class Student implements Comparable<Student> {
private String name;
private float score;
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
public Student(String name, float score) {
super();
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [name=" + name + ", score=" + score + "]";
}
// 覆写comparaTor()方法,自定义排序规则 根据学生成绩对数组排序
@Override
public int compareTo(Student stu) {
// TODO Auto-generated method stub
if (this.score > stu.score) {
return 1;
} else if (this.score == stu.score) {
return 0;
} else {
return -1;
}
}
}
public class ComparableApply {
@Test
public void testMethod() {
Student st[] = { new Student("guai", 99), new Student("shuai", 100), new Student("cabbage", 99.9f) };
//排序
Arrays.sort(st);
System.out.println("排序后的数组: " + Arrays.toString(st));
}
}
结果:
18.3、分析比较器的排序原理
Arrays.sort()排序过程就是数据结构中的二叉树排序算法,通过二叉树进行排序,然后利用中序遍历的方式把内容依次读取出来。
二叉树排序的基本原理就是:将第一个内容作为根节点保存,如果后面的值比根节点的值小,则放在根节点的左子树,如果后面的值比根节点大,则放在根节点的右子树。
按照这样的思路根据中序遍历的原理(左子树->根节点->右子树)即可将数字排序读取出来。
下面按照以上思路编写一个简单的二叉树排序操作。
因为Integer类已经实现Comparable接口,为了简化代码可直接使用Integer类。
由下面代码可见,Comparable接口可直接通过Integer对象实例化,然后直接输出Comparable接口对象时,实际调用的时Integer的toString()方法,我们下面将使用Comparable接口完成二叉树。
二叉树:
/**
* 比较器排序原理分析之二叉树
*
* @author guai
*
*/
class BinaryTree{
// 定义内部类 二叉树节点
class Node {
private Comparable data;
private Node left;
private Node rigth;
// 添加节点
public void AddNode(Node newNode) {
// 通过Integer实例化comparable然后调用在Integer中实现好的comparaTo方法
if (newNode.data.compareTo(this.data) < 0) {
if (this.left == null) {
this.left = newNode;
} else {
this.left.AddNode(newNode);
}
} else if (newNode.data.compareTo(this.data) >= 0) {
if (this.rigth == null) {
this.rigth = newNode;
} else {
this.rigth.AddNode(newNode);
}
}
}
// 中序遍历二叉树
public void printNode() {
//遍历左子树
if (this.left != null) {
this.left.printNode();
}
//輸出根节点
System.out.print(this.data + "\t");
//遍历右子树
if(this.rigth!=null) {
this.rigth.printNode();
}
}
};
//根节点
private Node root;
public void add(Comparable data) {
//每传入一个元素就声明一个根节点
Node newNode=new Node();
newNode.data=data;
if(root==null) {
root=newNode;
}else {
root.AddNode(newNode);
}
}
//输出节点
public void print() {
this.root.printNode();
}
}
public class BinaryTreeDemo {
@Test
public void testMethod() {
BinaryTree bt=new BinaryTree();
bt.add(4);
bt.add(0);
bt.add(222);
bt.add(3);
bt.add(90);
bt.add(33);
bt.add(1);
bt.add(23);
bt.add(3);
System.out.println("排序后的结果: ");
bt.print();
}
}
测试结果:
如果一个类已完成开发,但是在此类建立初期没有实现Comparable接口,此时肯定是无法进行对象排序操作的,所以为了解决这样的问题,java定义了另一种比较器的操作接口——Comparator此接口定义在java.util包中。
19.1、ComparaTor接口的定义
public Interface Comparator<T>{
public int compara(T o1,T o2);
boolean equals(Object obj);
}
可以发现,在此接口中也存在一个compra()方法,但是与之前不同的是,此方法接收两个个对象,参数一是需要比较的对象数组,参数二是自定义比较方法,其返回值依然是0,-1,1.
此接口使用与之前不同的是,需要单独指定好一个比较器的比较规则类才可以完成数组排序。
19.2、实现:
/**
* Comparator比较器的使用
*
* @author guai
*
*/
// 实现Cloneable接口
class Student2 {
private String name;
private float score;
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
public Student2(String name, float score) {
super();
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student2 [name=" + name + ", score=" + score + "]";
}
}
//实现Comparator接口,自定义比较方法
class StudentComparator implements Comparator<Student2> {
@Override
public int compare(Student2 stu1, Student2 stu2) {
// TODO Auto-generated method stub
if (stu1.getScore() > stu2.getScore()) {
return 1;
} else if (stu1.getScore() == stu2.getScore()) {
return 0;
} else {
return -1;
}
}
}
public class ComparatorApply {
@Test
public void testMethod() {
Student2 st[] = { new Student2("guai", 99), new Student2("shuai", 100), new Student2("cabbage", 99.9f) };
//参数一需要比较的对象数组参数二自定义比较方法
Arrays.sort(st,new StudentComparator());
System.out.println(Arrays.toString(st));
}
}
结果:
什么是观察者模式?举一个简单的例子,现在跟多的购房者都在关注房子价格的变化,每当房子价格变化时,所有的购房者都可以观察到,实际上以上的购房者都是观察者。
在Java中可以直接依靠Onservable类和Onserver接口轻松实现以上功能。
20.1、在java.util包中提供了Observable类,和Observer接口,使用它们即可完成观察者模式。需要被观察者的类必须继承Observable类。
Observable类的常用方法如下:
void addOberver(Observer o) 添加一个观察者
void deleteObserver(Oberver o) 删除一个观察者
void setChanged() 被观察者状态改变
void notifyObservers(Object arg) 通知所有观察者状态改变 参数表示变化后的数据
同时需要观察者实现Obervable接口
Oberver接口定义如下:
public interface Observer{
//第一个参数表示被观察者实例,第二个参数表示修改的内容。
void update(Observable o, Object arg);
}
实现方法:
/**
* 观察者模式
* @author guai
*
*/
//被观察者类
class House extends Observable {
private float price;
public House(float price) {
super();
this.price = price;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
// 设置变化点
super.setChanged();
// 通知观察者价格变动
super.notifyObservers(price);
this.price = price;
}
@Override
public String toString() {
return "房子价格为" + this.price;
}
}
//观察者类
class HoursePriceObserver implements Observer {
private String name;
public HoursePriceObserver(String name) {
this.name = name;
}
public void update(Observable obj, Object arg) {
if (arg instanceof Float) {
System.out.print(this.name + "观察到价格更改为:");
System.out.println(((Float) arg).floatValue());
}
}
}
public class ObserverMethod {
@Test
public void testMethos() {
House house = new House(10000);
HoursePriceObserver hpo = new HoursePriceObserver("A");
HoursePriceObserver hpo1 = new HoursePriceObserver("B");
HoursePriceObserver hpo2 = new HoursePriceObserver("C");
//添加观察者
house.addObserver(hpo);
house.addObserver(hpo1);
house.addObserver(hpo2);
System.out.println(house);
house.setPrice(6666);
System.out.println(house);
}
}
测试结果:
19.3让我们瞅瞅源码
setChaged方法在Observable类中的定义:
notifyObservers方法在Observable类中的定义
可见当价格改变时设置chaged标识为true然后调用notifyObservers方法,通过notifyObservers调用观察者的update方法
使用正则表达式可以方便的对数据进行匹配,还可以执行更加复杂的字符串验证、拆分、替换功能。
21.1、例如:判断一个字符串是否有数字组成。
//判断一个字符串是否由数字组成方法1
//@Test
public void testMethod() {
String str="12345678";
boolean flag=true;
char c[]=str.toCharArray();
for(int i=0;i<c.length;i++) {
if(c[i]<'0'||c[i]>'9') {
flag=false;
break;
}
}
if(flag) {
System.out.println("是由数字组成");
}else {
System.out.println("不是由数字组成");
}
}
@Test
//判断一个字符串是否由数字组成方法2
public void testMethod1() {
String str="12345678";
//正则验证
if(Pattern.compile("[0-9]+").matcher(str).matches()) {
System.out.println("是由数字组成");
}else {
System.out.println("不是由数字组成");
}
}
显然使用了正则表达式的方法二更为简单
21.2、Pattern类和Matcher类
如果要在程序中应用正则表达式必须依靠Pattern类和Matcher类,这两个类都在java.util.regex包中定义。
Pattern类的主要作用是进行正则规范的编写,而Mathcer类则主要执行规范。
常用正则规范:
\ 表示反斜线(\)字符
\t 表示制表符
\n 表示换行
[abc] 表示字符a、b、c
[^abc] 表示处理字符a、b、c之外的任意字符
[a-zA-Z0-9] 表示由字符、数字组成
\d 表示数字
\D 表示非数字
\w 表示字母、数字、下划线
\W 表示非字母、数字、下划线
\s 表示所有空白字符(换行、空格等)
\S 表示都有非空白字符
^ 行的开头
$ 行的结尾
. 匹配处理换行符之外的任意字符
数量表示 (X表示一组规范)
X 必须出现一次
X? 可以出现0次或一次
X* 可以出现0次、1次或多次
X+ 可以出现1次或多次
X{n} 必须出现n次
X{n,} 必须出现n次以上
X{n,m} 必须出现n~m次
逻辑运算符(X、Y表示一组规范)
XY X规范后跟着Y规范
X|Y X规范或Y规范
(X) 作为一个捕获组规范
21.3、Pattern类的常用方法
static Pattern complie(String regex) 指定正则表达式规则返回Pattern类实例
Matcher matcher(CharSequence input) 指定需要验证的字符串并返回Mathcer类实例
String[] sqlit(CharSequence input) 字符串拆分
21.4、Matcher类的常用方法
boolean matcher() 执行验证
String replaceAll(String replacement) 字符串替换
21.5、测试方法
/**
* 正则表达式的使用
* @author guai
*
*/
public class RegexMethod {
//判断一个字符串是否由数字组成方法1
//@Test
public void testMethod() {
String str="12345678";
boolean flag=true;
char c[]=str.toCharArray();
for(int i=0;i<c.length;i++) {
if(c[i]<'0'||c[i]>'9') {
flag=false;
break;
}
}
if(flag) {
System.out.println("是由数字组成");
}else {
System.out.println("不是由数字组成");
}
}
//@Test
//判断一个字符串是否由数字组成方法2
public void testMethod1() {
String str="1456a";
//正则验证
if(Pattern.compile("[0-7]{2}+[a-z]").matcher(str).matches()) {
System.out.println("是由数字组成");
}else {
System.out.println("不是由数字组成");
}
}
//@Test
//验证一个字符串是否是合法的日期格式
public void testMethod2() {
String str="2020-02-02";
String pat="\\d{4}-\\d{2}-\\d{2}";
//指定正则表达式规则
Pattern pa=Pattern.compile(pat);
//创建matcher实例
Matcher matcher=pa.matcher(str);
//执行验证
if(matcher.matches()) {
System.out.println("日期格式合法");
}else {
System.out.println("日期格式不合法");
}
}
//@Test
//按照字符串的数字将字符串拆分
public void testMethod3() {
String str="A1B7877887C3";
String pat="\\d+";
//指定正则表达式规则
Pattern p=Pattern.compile(pat);
//进行字符串拆分
String s[]=p.split(str);
for(int i=0;i<s.length;i++) {
System.out.println(s[i]);
}
}
@Test
//使用Matcher类中的替换操作
public void testMethod4() {
String str="A123B23C32D32";
String regex="\\d";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(str);
String newstr= matcher.replaceAll("-");
System.out.println(newstr);
}
}
撒花撒花
手机扫一扫
移动阅读更方便
你可能感兴趣的文章