目录
十七、 多态
17.1 多态
1、java面向对象的四大特性: 继承、封装、多态、(抽象);
2、多态 :
(1)同一个对象,体现出来的多种不同形态(身份),将一种行为表现出不同的效果;
(2)想要实现多态的效果,需要先有继承关系
(3)=左边编译类型,=右边运行类型
3、多态的向上转型:Person p = new Teacher() ;父类类型 引用名 = new 子类类型()
(1)父类类型的引用指向子类的对象
(2)该引用只能调用父类中定义的属性和方法
(3)执行结果:如果调用属性,执行父类的;如果调用方法,看子类是否重写
(4)如果子类中将父类的方法重写,那么调用方法后执行的结果是子类重写之后的那个结果
(5)属性值没有重写之 说,就看编译类型
(6)如果父类与子类有同名的属性,调用父类的属性
(7)如果父类与子类有同名的方法,执行子类重写之后的方法
(8)如果想要调用子类中独有的成员,将身份还原回去才可以,需要强制类型转化,引出向下转型(造型)
4、多态的向下转型:Teacher t = (Teacher)p;子类类型 引用名 = (子类类型)父类引用;
(1)只能强转父类的引用,不能强转父类的对象
(2)要求父类的引用必须指向的是当前目标类型的对象
(3)可以调用子类类型中的所有成员
(4)执行结果:如果调用属性,执行子类的;如果调用方法,看父类的
(5)若需要转换的类型与真实对象的类型不匹配,会产生一个运行时异常ClassCastException
(6)为了避免转型时产生的问题,可以利用instanceof进行判断比较,比较前面对象和后面类型是否匹配
package test;
public class Test {
public static void main(String[] args) {
/*
1.这个真实的老师,体现出来的身份是一个人的身份,当这个老师走出校园他就是个普通人,所以
这个人不能调用teach方法,出来校门就不能随便教育人。
2.编译类型看=左边,运行类型看=右边
3.调用的时候看编译类型(也就是引用只能调用父类中定义的属性和方法,也就是说父类引用p只
能点Person中的方法),执行的时候看运行类型(也就是说调用后执行的结果是子类重写之后的那个结果,
也就是说调用后的方法,要去执行时,如果Teacher有自己的eat方法就先执行Teacher中的,
没有才会去执行父类的)
*/
//该引用只能调用父类中定义的属性或方法
Person p = new Teacher();//这个人是一个老师
// p.teach();//Person中没有teach方法。方法调用看编译类型
p.eat();//输出:我是老师的eat方法。方法执行看运行类型
p.sleep();//我是老师的sleep方法
p.talk();//我是人的talk方法。Teacher没有talk方法,所以去继承父类的方法
System.out.println(p.name);//我是人的name
// System.out.println(p.hah);
//如果想调用子类独有的属性或方法
//需要将类型还原真实类型,强制类型转化
Teacher t = (Teacher)p;
System.out.println(p.name);//我是老师的name
t.eat();
t.sleep();
t.teach();
t.talk();
}
}
class Person {
public String name = "我是人的name";
public String age = "我是人的age";
public void eat() {
System.out.println("我是人的eat方法");
}
public void sleep() {
System.out.println("我是人的sleep方法");
}
public void talk() {
System.out.println("我是人的talk方法");
}
}
class Teacher extends Person{
public String name = "我是老师的name";
public String hah = "我是老师的hah";
public void eat() {
System.out.println("我是老师的eat方法");
}
public void sleep() {
System.out.println("我是老师的sleep方法");
}
public void teach() {
System.out.println("我是老师的teach方法");
}
}
5、注意:不是一个分支上的不行瞎造型
(1)不能将Student造成Teacher,不能将Teacher造成Pig,不能将Person造成Pig
(2)要满足对象属于(instanceof)这个类的子类,就可以
package test02;
public class Test02 {
public static void main(String[] args) {
//可以调用父类Object中的方法和属性,但是调用后执行要看子类Teacher有没有重写,重写就执行子类的,没有就继承父类的
//可以调用:Object
Object o = new Teacher_();
o.hashCode();o.getClass();o.toString();
System.out.println("==============================================");
//想要调用子类的就要强转,编译类型决定可以调用什么,也就是说animal往上都可以调用:
//可以调用:Object----Animal
Animal_ a = (Animal_) o;
System.out.println(a.name);//animal的name属性,如果子类没有name属性就继承父类的,如果有就就要子类的
a.hashCode();a.toString();a.eat();a.sleep();
System.out.println("==============================================");
//Person往上的都可以调用:
//可以调用:Object-----Animal-----Person
//这个运行类型是Teacher:o----Teacher
Person_ p = (Person_) o;
System.out.println(p.name);//Person的name属性
p.hashCode();p.toString();p.sleep();p.talk();
p.eat();//我是teacher的eat方法
System.out.println("==============================================");
//编写的时候没有问题,但是运行时出现异常ClassCastException
//不能将一个学生变为老师
if (o instanceof Student_) {//对象是否属于后面类型
Student_ s = (Student_)o;//运行异常
s.study();
System.out.println("类型匹配");
} else {
System.out.println("对不起 类型不匹配 不能帮您造型了");
}
}
}
class Animal_ {
public String name = "我是Animal的name属性";
public void eat(){System.out.println("我是Animal的eat方法");}
public void sleep(){System.out.println("我是Animal的sleep方法");}
}
class Person_ extends Animal_{
public String name = "我是人的name属性";
public void eat() {System.out.println("我是人的eat方法");}
public void sleep() {System.out.println("我是人的sleep方法");}
public void talk() {System.out.println("我是人的talk方法");}
}
class Pig_ extends Animal_ {
public String name = "我是猪的name属性";
public void sleep() {System.out.println("我是猪的sleep方法");}
}
class Teacher_ extends Person_ {
public String name = "我是老师的name属性";
public void eat() {System.out.println("我是老师的eat方法");}
public void teach() {System.out.println("我是老师的teach方法");}
}
class Student_ extends Person_ {
public String name = "我是老师的name属性";
public void eat() {System.out.println("我是老师的eat方法");}
public void study() {System.out.println("我是老师的study方法");}
}
十八、策略模式 + 内部类
18.1 模拟一个Bank银行
1、思路:
(1)老人:1. 进银行 叫一个号码 排队;2.去窗口办理;3.办理完毕离开了
(2)银行:1.银行开门,等待用户进来办理业务
(3)银行和老人是依赖关系
package bank;
public class OldMan {
private String name;
public OldMan(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//1. 进银行 叫一个号码 排队
public void CallNumber() {
System.out.println("老人不知道哪叫号,请求经理帮忙");
}
//2.去窗口办理
public void transact() {
System.out.println("到窗口,拿出存折取钱");
}
//3.办理完毕离开了
public void leave() {
System.out.println("办理完成,离开");
}
}
package bank;
public class Bank {
//1.银行开门,等待用户进来办理业务
public void profession(OldMan oldman) {
System.out.println(oldman.getName() + "客户进入银行");
oldman.CallNumber();
oldman.transact();
oldman.leave();
}
}
package bank;
public class Test {
public static void main(String[] args) {
Bank bank = new Bank();
OldMan oldMan = new OldMan("老人");
bank.profession(oldMan);//银行欢迎老人进来办理业务
}
}
(4)你会发现老人、年轻人、土豪每个人干的三件事差不多都是一样的,那么这三个人的方法名最好是一样的;
2、按照上面的设计,可能会出现问题:
(1)三个不同的人类方法名不一样,可能就会出现一系列的小问题,比如:年轻人不用找经理,土豪不用排队直接走vip窗口等待...
3、解决如上所诉的问题:可以在三个人类之上创建一个父类:
(1)解决三个人类中的相同代码,比如:name属性,get方法
(2)因为每个人整体流程都是固定的,但是执行的结果由于不同人群的需求不同,比如:每个人的叫号方法都不确定,有可能叫号,有可能不,所以我们就直接把这些方法进行抽象化,定义一个抽象类
(3)父类定义的三个方法可以是抽象的,解决了子类名命不一致的问题和子类执行也不一样的问题
(4)父类可以作为参数传入银行这个方法中,可以把这个人传入银行;
package bank;
public abstract class Person {
/*
private String name;
//父类可以不用写构造方法了,因为子类他们每一个都有自己的构造方法,用不到父类的
//属性是私有的不能直接继承的,但是子类可以间接继承这两个共有方法,子类通过这set、get方法可以间接操作自己父类对象
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//如果换成受保护的,就更方便了,受保护的只有子类可以用
*/
protected String name;
public String getName() {
return this.name;
}
//1. 进银行 叫一个号码 排队
public abstract void CallNumber() ;
//2.去窗口办理
public abstract void transact() ;
//3.办理完毕离开了
public abstract void leave() ;
}
package bank;
public class OldMan extends Person{
//属性就不用写了,可以通过继承父类的name属性,又因为父类name私有的,所以可以get、set方法获取和设置
//如果是受保护的就更方便了,有且仅有子类可以用
//构造方法
public OldMan() {}
public OldMan(String name) {
this.name = name;
}
//1. 进银行 叫一个号码 排队
public void CallNumber() {
System.out.println("老人不知道哪叫号,请求经理帮忙");
}
//2.去窗口办理
public void transact() {
System.out.println("经理送到到窗口,拿出存折取钱");
}
//3.办理完毕离开了
public void leave() {
System.out.println("办理完成,离开");
}
}
package bank;
public class YoungMan extends Person{
public YoungMan() {}
public YoungMan(String name) {
this.name = name;
}
//1. 进银行 叫一个号码 排队
public void CallNumber() {
System.out.println("年轻人直接叫号");
}
//2.去窗口办理
public void transact() {
System.out.println("到号窗口,拿出存折取钱");
}
//3.办理完毕离开了
public void leave() {
System.out.println("办理完成,离开");
}
}
package bank;
public class Bank {
//1.银行开门,等待用户进来办理业务
public void profession(Person person) {
System.out.println(person.getName() + "客户进入银行");
person.CallNumber();
person.transact();
person.leave();
}
}
package bank;
public class Test {
public static void main(String[] args) {
//创建Bank对象是为了调用欢迎人进来的方法,但是这个方法里面有个参数就是Person人
//要给这个人赋予名字
Bank bank = new Bank();
Person p = new ToffMan("土豪");
bank.profession(p);
Person p2 = new OldMan("老人");
bank.profession(p2);
Person p3 = new YoungMan("年轻人");
bank.profession(p3);
}
}
4、这就是策略模式
18.2 策略模式Strategy
1、策略模式Startegy-------行为型模式,比如上面的小案例;(银行的业务是固定的),用于解决,执行流程固定,执行的结果由于提供了不同的策略而不同;
package bank;
public abstract class Person {
/*
private String name;
//父类可以不用写构造方法了,因为子类他们每一个都有自己的构造方法,用不到父类的
//属性是私有的不能直接继承的,但是子类可以间接继承这两个共有方法,子类通过这set、get方法可以间接操作自己父类对象
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//如果换成受保护的,就更方便了,受保护的只有子类可以用
*/
protected String name;
public String getName() {
return this.name;
}
//1. 进银行 叫一个号码 排队
public abstract void CallNumber() ;
//2.去窗口办理
public abstract void transact() ;
//3.办理完毕离开了
public abstract void leave() ;
}
package bank;
public class OldMan extends Person{
//属性就不用写了,可以通过继承父类的name属性,又因为父类name私有的,所以可以get、set方法获取和设置
//如果是受保护的就更方便了,有且仅有子类可以用
//构造方法
public OldMan() {}
public OldMan(String name) {
this.name = name;
}
//1. 进银行 叫一个号码 排队
public void CallNumber() {
System.out.println("老人不知道哪叫号,请求经理帮忙");
}
//2.去窗口办理
public void transact() {
System.out.println("经理送到到窗口,拿出存折取钱");
}
//3.办理完毕离开了
public void leave() {
System.out.println("办理完成,离开");
}
}
package bank;
public class YoungMan extends Person{
public YoungMan() {}
public YoungMan(String name) {
this.name = name;
}
//1. 进银行 叫一个号码 排队
public void CallNumber() {
System.out.println("年轻人直接叫号");
}
//2.去窗口办理
public void transact() {
System.out.println("到号窗口,拿出存折取钱");
}
//3.办理完毕离开了
public void leave() {
System.out.println("办理完成,离开");
}
}
package bank;
public class Bank {
//1.银行开门,等待用户进来办理业务
public void profession(Person person) {
System.out.println(person.getName() + "客户进入银行");
person.CallNumber();
person.transact();
person.leave();
}
}
package bank;
public class Test {
public static void main(String[] args) {
//创建Bank对象是为了调用欢迎人进来的方法,但是这个方法里面有个参数就是Person人
//要给这个人赋予名字
Bank bank = new Bank();
Person p = new ToffMan("土豪");
bank.profession(p);
Person p2 = new OldMan("老人");
bank.profession(p2);
Person p3 = new YoungMan("年轻人");
bank.profession(p3);
}
}
18.3 内部类
1、内部类:
(1)指的是在Java中可以将一个类定义在另一个类的内部
(2)内部类可以定义在:类的内部(与类成员层次一致)
(3)内部类可以定义在:方法/块内部(与类成员相差一个层次,方法的局部变量一个层次)
2、内部类分为:
(1)成员内部类:
①将一个类直接定义在类的里面,作为成员,与属性或方法层次一致
②成员内部类可以与正常类一样,使用不同的权限修饰符来修饰
③好处:可以省略一个.java文件;
④在成员内部类中可以访问外部类的所以成员,包括私有的
⑤若想要在内部类中通过对象.调用外部类成员,外部类的名字.this.外部类成员
(2)局部内部类:(很少用啊)
①将一个类定义在方法/块里面,作为成员的内部结构,与临时的局部变量一个层次
②局部内部类象时一个局部的变量一样(属于临时变量),不能用public、protected、private、static修饰,只能用abstract或final修饰
③可以在不同的方法中定义重名的局部内部类
④局部内部类可以访问外部类成员,
⑤当局部内部类访问局部变量的时候,要求局部的变量必须是final
(3)匿名内部类(就是没有名字):
①分为两种定义:成员匿名内部类,局部匿名内部类
②将类直接定义在类中或者类成员中
③匿名内部类很特殊,只有类体,没有类的所有结构(包含修饰符、名字、继承、实现都无)
④通常会在抽象类或者接口创建的后面使用,当然具体的类也可以有匿名的子类
⑤不能用任何修饰符来修饰,匿名内部类也没有构造方法
//匿名内部类,通常接口或抽象类的具体子类这样写,开发
//中为了省略一个类文件,下面这个习法比较常见
public interface Test{
public void test();
}
Test t = new Test(){
public void test(){
}
}
(4)静态内部类:成员静态内部类
①只能在类中定义,作为成员
②静态内部类不需要外部类对象操作,可以直接创建对象
③静态内部类可以访问外部类的静态成员
④静态内部类不能访问非静态成员(无论内部类还是外部类)
十九、枚举 + Runtime
19.1 枚举类enum
1、枚举类:一个类中的对象,认为个数是有限且固定的,可以将每一个对象一一的列举出来,枚举顾名思义就是一一列举。 把可能的取值一一列举。
(1)比如我们现实生活中:一周的星期一到星期日是有限的7天,可以一一列举。性别有:男、女、保密,也可以一一列举。 月份有12个月,也可以一一列举
2、若没有枚举类型的时候,如何手动设计?
(1)用静态常量设计,类似单例模式,Day(类,当作描述星期,一共有7个对象)
(2)private构造方法 和 public static final 属性 = new Day()的形式写
package myenum;
public class Day {//描述星期 7个
//类似单例模式的想法,个数是有限的,不让别人创建对象
//构造方法私有
private Day(){}
/*
所有对象都是属性,static保证每个属性只创建一个,共有是为了方便,为了不让别人创建对象所以final
为了保证安全,不让别人去改动,
描述一一列举的过程,就是枚举,这七个过程是描述对象的,保证这个Day这个类下只能有这七个对象,别人不能创建
如果要用一般属性和一般方法随便设计不影响,下面这七个就是为了控制对象而已
*/
public static final Day monday = new Day();
public static final Day tuesday = new Day();
public static final Day wednesday = new Day();
public static final Day thursday = new Day();
public static final Day firday = new Day();
public static final Day saturday = new Day();
public static final Day sunday = new Day();
}
package myenum;
public class Test {
public static void main(String[] args) {
Day day = Day.monday;//day类中访问了其中的一个对象,一共7个
}
}
3、JDK1.5版本以后可以直接定义enum枚举类型
(1)我们自己定义的enum类型直接默认继承Enum(java.lang包),然后这个Eunm又默认继承Object,所有我们可以调用两个类下的方法
(2)我们自己定义的enum类型不能再写extends,但是实现了默认继承Object
(3)可以通过枚举类直接访问属性名(其实就是我们说的枚举对象)
(4)我们可以在枚举类中直接列举对象,如:public enum EnumDay{ monday,tuedsay; },monday和tuesday都是枚举对象。monday就是枚举对象的name属性名
4、Enum类型,有两个私有属性
(1)name属性是来存储枚举对象的名字的,name()表示获取枚举对象的名字
(2)ordinal枚举对象在类中罗列的顺序(在枚举类中的索引),类似index,也从0开始
(3)name和ordinal都是私有的,所以他提供了两个获取name和oredinal属性的方法,name()和ordinal()获取相关信息的方法
(4)name()获取枚举对象的名字,ordinal()获取枚举对象的索引号
5、Enum类型,有一些常用的方法:
(1)valueOf() 通过给定的name获取对应的枚举对象
如:EnumDay enum = EnumDay.valueOf("monday"),通过一个name属性,这个属性名叫monday名的找到这个monday枚举对象,然后返回枚举对象
(2)如果不知那个名字,还有第二方法values();它可以返回所有枚举对象,他的返回值是枚举类型的数组,
如:EnumDay[] days = EnumDay.values();然后通过遍历就可以了,values() 获取全部的枚举对象 ,可以返回一个数组,这个数组是枚举类型的
(3)因为枚举还实现了一个接口,所以有个方法compareTo() 可以比较两个枚举对象的顺序
如:monday.comparTo(tuesday);(返回一个负的),看谁前谁后;越靠近前面的数字越小,往后的越大。monday这个枚举对象比较靠前,所以小,compareTo() 是返回一个int
6、switch内部判断枚举的应用
7、我们也可以在enum中描述自己的一些属性或方法
(1)必须在enum类中第一行先描述一下枚举的样子,描述以后需要添加分号,之后就可以定义自己的一般属性和方法了
(2)因为类创建的过程中,jvm会帮我们创建枚举类型的对象,所以需要给枚举类型提供对应样子的构造方法(带参数),我们自己是不能调用构造方法的,只能private修饰,可以重载
8、自己定义的enum不能在继承别的类(单继承),但是可以实现多个接口,然后在里面去添加具体的方法
package myenum;
public enum EnumDay {
//虽然你就写了几个名字,但是它是描述了七个当前类的对象;
//这个enum帮我们做了一些事情,相当于跟我们Day类中写的没什么区别
monday("星期一",1), tuesday, wednesday, thursday, friday, sunday;
//描述一下枚举的样子
private String name;
private int index;
private EnumDay() {}
private EnumDay(String name, int index) {
this.name = name;
this.index = index;
}
public String getName() {
return this.name;
}
public void setName() {
this.name = name;
}
}
package myenum;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
/*
这个enumDay是个枚举类型的对象,默认继承了Object,除了继承Object类的方法外,
还有一些compareTo getDeCleaing name(),证明我们自己创建的enum类型还默
认继承Enum,我们自己定义的每一个enum类型,都会默认继承Enum,间接继承Object
ordinal枚举对象在类中罗列的顺序,类似index,也从0开始,ordinal()获取序号
*/
EnumDay enumDay = EnumDay.monday;
//获取所有的枚举对象
EnumDay[] days = EnumDay.values();
for (EnumDay d:days) {
System.out.println(d.name() + "----->" + d.ordinal());
}
System.out.println("==============================================================================");
//调用静态方法,通过name找到叫monday的对象,所以返回值就是一个枚举类型的对象
EnumDay d1 = EnumDay.valueOf("monday");
System.out.println(d1.name() + "----->" + d1.ordinal());
System.out.println("==============================================================================");
//输入一个字符串monday,输出对应的信息
Scanner input = new Scanner(System.in);
System.out.print("输入一个星期的英文单词:");
String key = input.nextLine();
EnumDay day1 = EnumDay.valueOf(key);//通过输入的英文单词找到了对应的枚举对象
switch (day1) {
case monday:
System.out.println("您输入的是星期一");
break;
case tuesday:
System.out.println("您输入的是星期二");
break;
//下面的一样一直到星期日
default:
System.out.println("输入错误");
}
System.out.println("==============================================================================");
}
}
19.2 Runtime 类 管理堆内存
1、Runtime类中提供了管理内存的方法:
(1)maxMenmory
(2)totalMenmory
(3)freeMenmory
2、object类中有一个finalize方法用于回收对象的,如果重写也能看见回收,finalize是Object类中的一个protected方法,只有子类可以调用
(1)如:有一个领导和一个环卫工人,环卫工人再扫第一条街,领导看见第三条街有垃圾,告诉环卫工人去扫,这时这个环卫工人不一定立即执行,有可能扫完第一条街再去,也有可能扫完前两条街再去,这根据环卫工人自己做的决定,所以这个finalize他有自己的算法
3、上面一系列回收都是通过GC系统提供的,有很多回收算法(GC是系统提供的一个线程)
4、Runtime r = new Runtime()报错?为什么new不了?不能new有几种可能?
(1)抽象类或者是接口
(2)没有无参的构造方法
(3)构造方法是私有的(如:单例模式)
(4)看到源代码后发现他是单例模式,所以需要通过类名字点的形式(类名.)
package gc;
public class Test {
public static void main(String[] args) {
//为什么new不了?有几种可能?
//1.抽象类或者接口 2.没有无参的构造方法 3.构造方法私有(单例)
Runtime runtime = Runtime.getRuntime();
long max = runtime.maxMemory();
long total = runtime.totalMemory();
long free = runtime.freeMemory();
System.out.println(max); //整个堆内存 1873805312
System.out.println(total); //堆内存中可用的和空闲的区域126877696
System.out.println(free); //空闲的区域123522096
}
}
二十、工具类之包装类相关
1、所有工具包都是Java开发者写好的类。学这些东西最后有一个专业的文档---API文档:Java 8 中文版 - 在线API手册 - 码工具
20.1 包装类
1、包装类(封装类):
(1)java.lang包:byte---Byte(Byte是对应的包装类)、short---Short、int---Interger、long---Long、float---Float、double---Double、char---Character、boolean---Boolean
2、类所在的包:
(1)上面八个包装类都在同一个包下-----java.lang包,它们八个不需要import导包,可以直接使用;
(2)八个包装类中有六个是与数字相关,都默认继承父类Number,Number继承Object
(3)八个包装类都实现了接口:Serializable,comparable
(4)八个包装类都有自己对应类型参数的构造器,如:Interger(10)
(5)八个包装类中有七个(除了character)还有一个构造方法重载,带string类型
如:七个都可以:new Integer(10) 或 new Integer("10"); 但是character没有这个String参数的类型
(6)创建对象 对象调用属性/方法
有六个与数字相关的类都继承Number这个类,xxxValue(); 将一个包装类类型转化对应的基本类型(拆包)
如:Interger value = 10;左边是引用的数据类型,实际上是不可以给它赋予基本类型的,但是底层是给咱们做了一个转化,所以可以这么写。这么写也可以:int value = new Interger(10); 还有:int value = Interger.parselnt("10");
(7)==和equals的区别
①== 可以比较基本数据类型,也可以比较引用类型(遍历中存储的内容)
②如果比较基本类型比较是变量存储的值
③如果比较引用类型比较是变量存储的地址引用
④equals()是Object类中继承过来的方法,每一个引用类型都可以调用,只能比较引用类型
⑤默认继承的equals()方法比较与==一致,如果想要改变比较规则,可以重写equals方法
⑥由于Integer类重写了equals方法,所以Integer比较的是数值
⑦考察Integer类就加载的时候,自己有一个静态空间
⑧空间内立即加载Integer类型的数组,内存储256个Integer对象 -128~+127
⑨如果我们用的对象范围在这之内Integer i1 = 10;直接取静态区中找到对应的对象
public class Test {
public static void main(String[] args) {
Integer i1 = 10; //将10自动包装成Integer类型对象
Integer i2 = 10;
Integer i3 = new Integer(10);
Integer i4 = new Integer(10);
System.out.println(i1 == i2);//true 因为i1和i2存的都是数值指向同一个静态元素
System.out.println(i1 == i3);//false i1和i3存的数值不一样
System.out.println(i3 == i4);//false i3和i4地址不一样
//equals默认比较引用类型,但是Integer重写了,所以比较基本类型
System.out.println( i1.equals(i2) );//true 比较的是i1和i2里面的值
System.out.println( i1.equals(i3) );//true 比较的是i1和i3里面的值
System.out.println( i3.equals(i4) );//true
}
}
20.2 与数学相关的类
(1)Math
(1)所属包java.lang
(2)Math构造方法是私有的,我们不能直接调用创建对象,因为由于Math中提供的属性及方法都是static,所以不需要创建对象
2、常用的方法
(1)abs()返回给定属性的绝对值,参数是其中的一个(int long float double )
(2)double = ceil()向上取整
(3)double = floor()向下取整
(4)rint()临近的整数,如果两边距离一样,则返回偶数
(5)int = round() 四舍五入
(6)max(a, b),min(a, b) ,参数是其中一个(int long float double ),a和b参数一致
(7)pow(a, b);a的b次方,参数double 返回值double
(8)sqrt(a);获取给定参数的平方根值
(9)double = random();随机产生一个0.0 ~ 1.0之间的值
3、Math.random()计算小数的时候精确程度可能有些损失,所以我们以后用Random类
(2)Random类
(1)在java.util包中的类,需要import导入
(2)没有任何继承关系,默认继承Object类
(3)查找构造方法---> 如何创建对象;如:Random r = new Random();
(4)类中提供的常用方法
①r.nextInt() ;随机产生 int取值范围的整数 有正有负
②r.nextInt(int bound)必须为正数,否则会出现如下的运行时异常IllegalArgumentException
③r.nextFloat()随机产生一个[0.0 ~ 1.0]
④r.nextBoolean()随机产生一个boolean值 true或false
(3)UUID类
(1)所属类在java.util需要import导入
(2)没有任何继承关系,默认继承Object类
(3)构造方法有,没有无参数的构造方法,产生一个32位的随机元素,每一个位置是一个16进制的数字
UUID uuid = UUID.randomUUID();
System.out.println(uuid.toString());//数据表格主键 primary key
(4)BigInteger 大整数
用于存比较大的数范围(-2的63次方 ~ 2的63次方-1)
(1)属于java.math包,需要import引入
(2)继承Number类
(3)如何创建对象,提供的构造方法全部都是带参数的,通常利用String参数的构造方法创建这个类对象,如:BigInteger bi = new BigInteger("123");
(4)类中的常用方法
做四则运算add()、subtract()、multiply()、divide();加减乘除
(5)小例子 设计一个方法,用来计算给定数字的阶乘
public class Test {
//设计方法 用来计算给定数字的阶乘
public BigInteger factorial(int num) {
BigInteger resu = new BigInteger("1");
for (int i = 1; i <= num; i++) {
resu = resu.multiply(new BigInteger(i + ""));//整型加字符串型转化为字符串
}
return resu;
}
public static void main(String[] args) {
//创建对象 调用计算阶乘的方法
Test test = new Test();
BigInteger resu = test.factorial(6);
System.out.println(resu);
}
}
(5)BigDecima类
(1)所属的包:java.math包
(2)继承Number类
(3)通常利用String参数的构造方法创建这个类对象,如:BigDecimal bigDecimal = new BigDecimal("123.456");
(4)类中的常用方法
①做四则运算add()、stbtract()、multiply()、divide();乘除加减,
②还有一个处理小数点之后的位数的方法:setScale(),两个参数前面是保留小数点之后的位数,后面参数是设置的模式
//小数点之后保留两位,按照向下取整的方式进行截取 BigDecimal.还有很多常量进行选择
BigDecimal bigDecimal = new BigDecimal("123.456");
bigDecimal.setScale(2, BigDecimal.ROUND_DOWN);
(6)DecimalFormat类
(1)所属包java.text
(2)import导入才能使用
(3)通过带Sting参数的构造方法创建一个格式化对象,通过0和#进行区分的
(4)调用format方法将一个小数格式化成一个字符串
DecimalFormat decimalFormat = new DecimalFormat("000.###");
String value = decimalFormat.format(12.45);
System.out.println(value);//012.45
(7)Scanner类
(1)所属包java.util包,需要import导入
(2)通过一个带输入流的构造方法创建对象
(3)常用方法:nextInt()、nextFloat()、next()、nextLine()
二十一、工具类之日期相关
21.1 日期相关的类
(1)System类
(1)所属于java.lang包,不需要导入
(2)不需要创建对象,通过类名就可以访问
(3)有三个属性及其若干方法
①三个属性:out输出流、in是个输入流、err操作一下错误信息
②方法:gc()、exit(int)有一个int类型的参数、currentTimeMillis()返回当前系统时间与计算机元年之间的毫秒差
//返回当前系统时间与计算机元年之间的毫秒差
long time = System.currentTimeMillis();
(2)Data类
(1)通常使用的是java.util包,需要导包使用
(2)通常使用无参数的构造方法,或者带long构造方法
(3)Date类中常用的方法
1. boolean = before(Date when); 测试此日期是否在指定日期之前。
2. boolean = after(Date when); 测试此日期是否在指定日期之后。
3. setTime(long time); 设置time的时间 毫秒值
4. long = getTime();
//默认是当前的系统时间构建的date对象
Date date1 = new Date();
Date date2 = new Date();
System.out.println(date1);
boolean x = date1.before(date2);//比较date1是否在date2之前
boolean s = date1.after(date2);//比较date1是否在date2之后
date1.setTime(12321);//设置date1的时间 毫秒值
date1.getTime();//获取date1的时间 毫秒值
System.out.println(date1.compareTo(date2));//按照字典索引顺序比较 返回的是int型 1表示调用(date1)再前,参数在后
(4)可以处理一个Date日期的格式
(3)DateFormat类
(1)包java.text 需要导包使用
(2)此类是一个抽象类,不能创建对象,通过子类来使用
(3)SimpleDateFormat类是DateFormat的子类
(4)SimpleDateFormat类
(1)包java.text 需要导入包
(2)这个类调用带String参数的构造方法创建format对象
//字母不是随便写的里面的-和:是我们定义的,想变为2023-10-23 19:20:43
Date date3 = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.format(date3);//通过sdf对象将date3格式化成你描述的样子
(5)Calendar类
1、java.util 需要导入包
2、有构造方法,用protected修饰的,子类才能new,通常访问不到,通常会调用默认的getInstance()
3、常用方法:after()、before()、setTime()、getTime()
(1)boolean = after(Object when); true如果此时Calendar是由下式表示的时间之后when ; false否则。
(2)boolean = before(Object when); true如果此时Calendar是由下式表示的时间之前when ; false否则。
(3)getInstance(); 使用默认时区和区域设置获取日历。
Calendar calendar = Calendar.getInstance();//系统当前时间的calendar对象
Date date2 = new Date();
calendar.after(date2);//calender里面包含一个date,date里面包含一个time 毫秒值
int year = calendar.get(Calendar.YEAR);//获取年份
calendar.set(Calendar.YEAR,2024);//就是把年份设置为了2024年
int month = calendar.get(Calendar.MARCH);//获取月份,这个month是从0开始的 0~11月
int day = calendar.get(Calendar.DAY_OF_MONTH);//获取天
(6)TimeZone类
(1)在java.util需要导包
(2)可以通过calendar对象.getTimeZone()获取 或 TimeZone.getDefault();
(3)常用方法:主要是为了操作时区,有时有的系统可能是挎着这个时区来完成的
TimeZone tz = calendar.getTimeZone();
System.out.println(tz);
System.out.println(tz.getID());//Asia/ShangHai
System.out.println(tz.getDisplayName());//中国标准时间
二十二、工具类String
22.1 String类
(1)所属包java.lang包,不要导入
(2)没有任何继承关系,但是实现了三个接口Serializable/sɪərɪəlaɪzəbl/、CharSequence/siːkwəns/、Comparable/kɒmpərəb(ə)l/
(3)找寻构造方法创建对象,String是个类,按理来说应该是创建对象的方式来使用,所以Sting是一个非常特殊的引用类型,可以像基本类型一样去创建和赋值(String是个包装类)
//String是个类,按理来说应该是创建对象的方式来使用,直接将字符串常量赋值给s1(字符串常量池)
String s1 = "abc";//无参数构造方法创建空的对象
String s2 = new String("abc");//带String参数的构造方法创建对象
String s3 = new String(byte[]);//将数组中的每一个元素转化成对应的char,然后组合成String
String 34 = new String(char[]);//将数组中的每一个char元素拼接成最终的String
(4)String不可变特性:
①在String类中包含一个数组:private final char value[];//存储String中的每一个字符
②final最终的不可改变的,其实就是地址不让改变,数组的长度本身不可变的,一直指向一个空间,并且长度不能变,但是数组中有自己的元素可以变
③private私有的,不能在当前类以外访问,当前类中数组中的内容也不能改变
④String的不可变,体现在两个地方,长度和内容;长度不能变是因为final,内容不可变是因为private,
(5)== 和 equals() 、hasCode()
①比较基本类型和引用类型,基本类型比较值,引用类型比较地址
②equals只能比较引用类型,比较地址,
③equals方法,String将其重写了,所以比较字符串内容
④通常重写equals方法时会伴随着重写hashCode方法
//String是个类,按理来说应该是创建对象的方式来使用
//String将Object的equals重写了,将原有比较==的方式改为比较字符值了
//==比较基本类类型变量存储的值,比较引用类型是地址
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s1==s2);//true
System.out.println(s1==s3);//false
System.out.println(s3==s4);//false
System.out.println(s1.equals(s2));//true
System.out.println(s1.equals(s3));//true
System.out.println(s3.equals(s4));//true
str.equals(null); //默认继承Object比较地址,String 重写了改为比较字符串内容
str.hashCode();//继承Object,String重写了,将当前字符串的每一个char元素拆开 乘31求和
(1)String类中常用的方法
1、int = compareTo(String s1); 实现自Comparable接口,实现了按照字典(Unicode编码)索引的顺序比较
2、boolean = equals()、int = hashCode()、int = compareTo()、String = toString()都被重写了
boolean = equals(Object obj); //继承Object,String重写啦,比较两个字符串中的字面值是否相当
int = hashCokde(); //继承Object,String重写了,将当前字符串的每一个char元素拆开,乘以31求和
int = compareTo(String str); //实现自Comparable接口,按照字典Unicode编码索引顺序比较
String = toString(); //继承Object,String重写了,不在输出,类名@hashCOde(16进制的形式),重写后输出的是字符串中的字面值
str.equals(null); //默认继承Object比较地址,String 重写了改为比较字符串内容
str.hashCode();//继承Object,String重写了,将当前字符串的每一个char元素拆开 乘31求和
//按照两个字符串长度较短的那个作为比较循环的次数
//挨个比较元素,s1[i] - s2[i] 循环内如果有结果就直接输出这个结果(返回code差值)
//,如果循环过后发现所有字符一样,就按照s1和s2的长度比较
//返回0表示字符串一样,1大 -1小
s1.compareTo(s2);
3、char = CharAt(int index); //返回给定index对应位置的那个char值,index索引从0开始
4、int = codePointAt(int index); //返回给定index对应位置的那个char值所对应的code码
5、int = length(); //返回字符串的长度-----value数组的长度
//数组是length属性、box是size()方法、String是length()方法
String s1 = "abc";
for (int i = 0; i < s1.length(); i++) {
char value01 = s1.charAt(i);//char字符
int value02 = s1.codePointAt(i);//code码
System.out.print(value01 + "\t"); //a b c
System.out.print(value02 + "\t"); //97 98 99
System.out.print((char)value02 + "\t"); //a b c
}
System.out.println();
System.out.println("=================================================================");
//模拟加密 将abcde变为12345
String ss = "abcde";
String res = "";
for (int i = 0; i < ss.length(); i++) {
int v = ss.codePointAt(i);
res += (char)(v - 48);//密钥
}
System.out.println(res);
6、String = concat(String str);将给定的str拼接在当前String对象的后面,注意:方法执行完毕需要接受返回值,String的不可变特性
(1)concat拼接字符,这个拼接过程不用创建对象,但是需要通过给变量赋值的方式改变结果
(2)"a" + "b";拼接字符,这个拼接过程需要创建对象来完成,但是需要创建数组
(3)concat要比"a" + "b"的性能高
(4)若以后,开发中若遇到频繁的拼接字符串--------通常使用 StringBuilder / StringBuffer
/*
String str = "abcdef";这行代码,他会在底层会自动创建一个String对象,这个String对象里面有个
value属性,这个属性是个char数组private final char value[];,他会把abcdef存到这个不可变
的char数组中,我们不能操作
*/
String str = "abcdef";
/*
str.concat("g");这行代码,会再次创建一个新的String对象,他也有一个value属性,会把刚才那个String
对象value[]依次取出来,一个7个字符,然后存入新对象的value属性中,把g放在最后
str.concat("g");
不能改变属性,但是可以改变变量
*/
//为什么不输出abcdefg,因为String的不可变特性,你第一行代码和第二行代码不是一个地址,需要将str接收
str = str.concat("g");
System.out.println(str);
7、String对象的存储
(1)"abc"-----在字符串常量池
(2)new String("abc")----------在堆内存
String s2 = "a" + "b" + "c" + "d";
1 2 3 4 5 6 7
System.out.println(s2);//在这个过程中产生了几个String对象?字符串常量池有7个
/*
将字符和+,都加起来 7个
1对象----value[] a "a"
2对象----value[] b "b"
3对象----value[] {a,b} "ab"
4对象----value[] c "c"
5对象----value[] {a,b,c} "abc"
6对象----value[] d "d"
7对象----value[] {a,b,c,d} "abcd"
*/
8、boolean = contains(CharSequence s);用来判断给定的s是否在字符串中存在
String st = "abcdefg";
boolean va = st.contains("z");//判断此字符串中是否有z
boolean va2 = st.contains("ab");//判断此字符串中是否有ab
boolean va3 = st.contains("ag");//判断此字符串中是否有ab
System.out.println(va);//false
System.out.println(va2);//true
System.out.println(va3);//false 必须是连着的ag
9、boolean = startsWith(String prefix); 测试此字符串是否以指定的前缀开头
boolean = startsWith(String prefix, int toffset); 测试在指定索引处开始的此字符串的子字符串是否以指定的前缀开头。
boolean = endsWith(String suffix);判断此字符串是否已xxxx开发/结尾
//电脑上扫描,所以.java后缀名的源文件
String sr = "TestString.java";
boolean vaa1 = sr.endsWith(".java");
System.out.println(vaa1);//true
boolean vaa2 = sr.startsWith("Test");
System.out.println(vaa2);//true
10、byte[] = getBytes();char[] = toCharArray();将当前的字符串转化成数组,注意getBytes()不能拆中文字
String s3 = "abcdefg";
String s4 = "中国";
byte[] b = s3.getBytes();
for(byte v:b) {
System.out.println((char)v);//byte a b c d e f g
}
char[] c = s3.toCharArray();
for (char v:c) {
System.out.println((int)v);//byte 97 98 99 100 101 102 103
}
//会出现负数,就不对了,汉字是1字符
byte[] d = s4.getBytes();
for (byte v:d) {
System.out.println(v);
}
11、int = indexOf(int/String str[,int fromIndex]);四个方法重载找寻给定的元素在字符串中第一次出现的索引位置,若字符串不存在则返回-1
(1)lastIndex(); 四个方法重载找寻给定的元素在字符串中最后一次出现的索引位置,若不存在则返回-1
(2)无论从哪开始找,返回的index都是相对于整个String的
String ss2 = "abcdefgc";
//无论从哪开始找,返回的index都是相对于整个String的
int index = ss2.indexOf("c");
System.out.println(index);//2 默认从0号索引开始找
int index2 = ss2.indexOf("c",4);//从4号索引开始找,从c开始找
System.out.println(index2);//7
//返回-1表示从你开始找的位置,之后没有你这个元素了
int index3 = ss2.indexOf("a",4);//从4号索引开始找,从c开始找
System.out.println(index3);//-1
int index4 = ss2.indexOf(102,2);
System.out.println(index4);//5
int index5 = ss2.lastIndexOf("c",4);
System.out.println(index5);//2
12、boolean = isEmpty(); 判断当前字符串是否为空字符串(就是length是否为0),注意与null之间的区别
String sda = "";//如果把空字符串"" 变为null就会报错空指针异常
boolean vs = sda.isEmpty();
System.out.println(vs);//true
13、String = replace();
String = replaceAll();用给定的替换与给定的匹配的此字符串的每个子字符串。
String = replaceFirst();换第一次出现的那个字符串
String sss = "你太好";
sss = sss.replace('好','坏');//只能换一个字
System.out.println(sss);//你太坏
String sss2 = "你太好";
sss2 = sss2.replace("你太好","真坏");//可以换多个字符串
System.out.println(sss2);//真坏
String sss3 = "你太好00好";
sss3 = sss3.replaceFirst("好","坏蛋");//换第一次出现的字符串
System.out.println(sss3);//你太坏蛋00好
14、String[] = split(String regex [,int limit限度界限]); [,int limit限度界限]表示可写可不写,其实就是重载,regx表示regular有规律的 expression表达式,其实就是正则表达式
(1)按照给定的表达式将原来的字符串拆分开的,将"a-b-c-d" "-"进行拆分变为"abcd"
String ss1 = "a-b-c-d";
String[] value = ss1.split("-");
for (String v:value){
System.out.print(v);//abcd
}
System.out.println();
String[] value2 = ss1.split("-",2);//限制2个,最后结果必须留下2个“-”
for (String v:value2) {
System.out.print(v);//ab-c-d
}
(12)boolean = matches(String regex);判断字符串是否匹配给定的字符串
15、String = subString(int beginIndex[ , int endIndex]); 将当前的字符串截取一部分,从beginIndex开始到endIndex结束,[begin, end)区间,如果不写endIndex就默认一直到末尾
String s5 = "abcdefgh";
String vv = s5.substring(3);//从3号索引开始一直到最后
System.out.println(vv);//defgh
String vv2 = s5.substring(3,5);//从3号索引开始一直到5号索引结束 5号不可取 [3, 5)
System.out.println(vv2);//de
16、String = toUpperCase();将字符串转换为大写,String = toLowerCase();将字符串转换为小写
String o = "sad";
o = o.toUpperCase();//SAD
System.out.println(o);
o = o.toLowerCase();//sad
System.out.println(o);
17、String = trim();去掉字符串前后多余的空格的,不能去掉中间的空格
22.2 StringBuilder
(1)所属包java.lang包
(2)继承AbstractStringBuilder,间接继承Object,实现接口Seriailizable,charSequence,Appendable
(3)StringBuffer/StringBuilder没有compareTo方法,StringBuffer/StringBuilder含有一个String没有的方法append();将给定的字符串追加到原来字符串的末尾类似concate();
(4)特性:可变字符串 char[] value;进行动态扩容
(5)对象的构建:通过无参数构造方法 和 有参数的构造方法
//无参数构造方法 构建一个默认长度16个空间的对象 char[]
StringBuilder stringbuilder = new StringBuilder();
//利用给定的参数 构建一个自定义长度空间的对象 char[]
StringBuilder stringbuilder1 = new StringBuilder(20);
//利用带String参数的构造方法,默认数组长度字符串长度+16个
StringBuilder abc = new StringBuilder("abc");
(1)StringBuilder中常用的方法
1、最主要的append();
//比较concat和+号的性能,concat性能高,但是还是不利于拼接,+号会一直创建String对象,concat在堆内存创建空间,String中
//的不可变特性很麻烦需要重新赋值,所以出现了StringBuilder它是个可变的字符串,返回值是个字符串String
//append > concat > + --------在频繁的拼接字符串
String str = "a";
long time1 = System.currentTimeMillis();
for (int i = 0; i < 2000; i++) {
//str += "a";
str = str.concat("a");
}
long time2 = System.currentTimeMillis();
System.out.println(time2 - time1);//time2 > time1
StringBuilder a = new StringBuilder("a");
for (int i = 0; i < 2000; i++) {
a = a.append("a");
}
long time3 = System.currentTimeMillis();
System.out.println(time3 - time2);//time3 > time2
2、int = capacity();返回当前的容量(有默认的16空间)
int = length(); 返回长度(字符数)。
void = setLength();设置字符串的有效元素个数
StringBuilder abcdefg = new StringBuilder("abcdefg");//7+16 capacity容量
System.out.println(abcdefg.capacity());//23---底层那个数组的容量
System.out.println(abcdefg.length());//7---长度 有效元素的个数
3、char = charAt(int index); 返回给定索引位置的字符
int = codePointAt(int index); 返回指定索引处的字符(Unicode代码点)。
vodi = setCharAt(int index , char value);将index位置的字符修改成给定的value
StringBuilder zxcv = new StringBuilder("zxcv");
zxcv.deleteCharAt(3);//删除指定索引字符
zxcv.setCharAt(2,'z');//修改掉指定索引字符
System.out.println(zxcv);//zxz
4、String = substring(); 注意需要接受返回值,看见截取出来的新字符串效果
StringBulider = delete(int start [, int end]);StringBuilder类中独有的方法String没有,将start到end之间的字符串删掉,不用接受返回值就看到效果啦。
StringBuilder = deleteCharAt( int index) ;String类中没有的方法,将删掉给定index位置的某一个字符啦
StringBuilder abcd = new StringBuilder("abcd");
//StringBuilder的写法,从1索引截取到3索引,返回值String,可变性,但是返回值String
String value = abcd.substring(1,3);
//String的写法,从1索引截取到3索引,返回值String,由于不可变性需要在接收一下,然后指向一个空间
//abcd = abcd.substring(1,3);
System.out.println(value);//bc区间[1,3)
//在StringBuilder中substring返回值String,delete返回值StringBulider
StringBuilder qwerty = new StringBuilder("qwerty");
qwerty.delete(1,3);//区间[1,3)
System.out.println(qwerty);//qrty
5、int = indexOf(String str [, int fromIndex]);和 int = lastIndexOf( String str [, int fromIndex] );找寻给定的str在字符串中第一次出现的索引位置,带重载,则从某一个位置开始找。
6、StringBuilder = insert( int index , value);将给定的value插入index位置上
StringBuilder qwerty1 = new StringBuilder("qwerty");
qwerty1.append("u");//如果往后追加尽量用append
System.out.println(qwerty1);//qwertyu
qwerty1.insert(1,"x");//往前追加用insert
System.out.println(qwerty1);//xwqertyu
7、replacStringBuilder = e( int strat , int end , String str);将start和end之间的部分替换成str
StringBuilder asdfg = new StringBuilder("asdfg");
asdfg.replace(2,5,"qwe");
System.out.println(asdfg);//asqwe
8、StringBuilder = reverse();反转字符串,StringBuilder独有的方法
9、String = toString();将一个StringBuilder构建成一个String对象,返回
10、void = trimTosize();将数组中无用的容量去掉,变成length长度的数组;不能去除空格
StringBuilder lkjhg = new StringBuilder("lkjhg");
System.out.println(lkjhg.length());//5
System.out.println(lkjhg.capacity());//21
lkjhg.trimToSize();
System.out.println(lkjhg.length());//5
System.out.println(lkjhg.capacity());//5知识总结
22.3 为什么会出现StringBuilder
1、StringBuilder类不一定需要,是为了避免String频繁拼接修改字符串信息的时候才用的,底层数组是可变的,为了提高性能
2、常用方法
(1)StringBuilder中独有的方法(String没有的方法)
StringBuilder = append();StringBuilder = insert();StringBuilder = delete();delete = deleteCharAt();StringBuilder = reverse();
(2)与String类相同的方法
charAt();codePointAt();indexOf();lastIndexOf();subString();replace()名字相同用法不一致
(3)不是很常用的方法
ebsureCapacity();capacity();setLength();trimTosize();setChatAt();
22.4 String家族笔试常考的知识点
1、String所属包、继承关系、实现接口
(1)java.lang包、继承Object、接口Serializable/sɪərɪəlaɪzəbl/、CharSequence/siːkwəns/、Comparable/kɒmpərəb(ə)l/
2、String构建方式:常量、构造方法
3、String对象内存结构:
(1)字符串常量区、new堆内存对象
(2)== 和equals()区别
(3)“a” + “b” + “c”
4、String不可变性,长度及内容
5、String中常用方法---与StringBuilder的区别
6、String 和 StringBuilder 区别 | String和StringBuffer区别
(1)String不可变字符串
-
在JDK1.0版本
-
有一个接口Comparable
-
不可变体现长度及内容
-
有一些方法StringBuilder没有的:concat();compareTo();toUpperCase()
(2)StringBuilder可变字符串
-
JDK1.5版本
-
有一个接口Appendable
-
有一些方法String没有:append();insert();delete();reverse()
7、StringBuffer 和 StringBuilder区别
(1)StringBuffer是早期版本JDK1.0、StringBuilder是后来版本JDK1.5版本(这里俩个方法使用几乎一致)
(2)通常早期版本都是线程(同步)安全的,安全性比较高,但是执行效率相对较低
(3)后期版本,线程(非同步)非安全的,安全性比较低,但是执行效率相对较高
22.5 正则表达式regex
1、Regular有规律的、Expression表达式
2、正则表达式regex
(1)一个带有一定规律的表达式,匹配字符串格式的
3、正则表达式通常作用如下
(1)字符串的格式校验,String类中提供的一个方法boolean = str.matches( "regex" );
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个字符串");
String str = scanner.nextLine();
//判断输入的str字符串内容是否满足什么样的格式
//只能两个字母,第一个必须是a,第二个必须是abc其中一个
boolean value01 = str.matches("a[abc]");
System.out.println(value01);//true 或 false
//只能两个字母,第一个必须是a,第二个是非abc任意的其他一个(可以数字等)
boolean value02 = str.matches("a[^abc]");
//只能两个字母,第一个必须是a,第二个是a~z或A~Z范围之内的一个字母
boolean value03 = str.matches("a[a-zA-Z]");
//只能一个字母,a~z都可以,但不能是b和c
boolean value04 = str.matches("a[a-z&&[^bc]]");
如下的所有都用来描述字符的信息
.表示任意一个字符
\d digit数字 [0-9]
\D 非数字 [^0-9]
\s 一个空格或回车或换行(留白)
\S 非留白
\w word单词 [0-9A-Za-z] 数字或字母都可以
\W 非单词 [^0-9A-Za-z]
如下的所有都用来描述字符出现的次数
? 0-1次 [0-9]?
* 0-n次
+ 1-n次
{n} 固定n次
{n,} 至少出现n次
{m,n} m-n次
(2)字符串的拆分和替换,String类中提供的方法replace、split
(3)字符串的查找,Pattern 模式、Matcher适配器
String s = "127389sdkjbvoiqwlmk1297ru";
//1.利用Pattern类创建一个模式,理解为是一个正则表达式对象
//compile给它一个格式,把这个格式编译成一个对象
Pattern pattern = Pattern.compile("\\d{6}");//邮编
//2.需要提供一个字符串
//3.利用pattern模式对象创建一个匹配器
Matcher matcher = pattern.matcher(s);
//4.找寻字符串中出现满足上述格式的字符串
while (matcher.find()) {
System.out.println(matcher.group());//返回找到满足字符串格式的那串文字
}
22.6小任务(以下任务要求设计成方法)
(1)设计将字符串反转
//将字符串反转 参数字符串,返回值字符串
public String reverse(String str) {
//将str变化为数组
char[] value = str.toCharArray();
//数组头尾互换
for (int i = 0; i < value.length / 2; i++) {
char temp = value[i];
value[i] = value[value.length - 1 - i];//与最后一个互换
value[value.length - 1 - i] = temp;
}
//数组组合成字符串 返回,将一个char类型的字符串数组组合成字符串可以通过String对象中的构造方法
return new String(value);
}
TestTask testTask = new TestTask();
String val = testTask.reverse("abs");
System.out.println(val);//sba
(2)设计将给定字符串的正序和反序进行连接
//设计将给定字符串的正序和反序进行连接 参数字符串,返回字符串
public String reverseAndConcat(String str) {
//将str反转
String value = this.reverse(str);
//将反转过来的字符串拼接
String res = str.concat(value);
//返回字符串
return res;
}
String val02 = testTask.reverseAndConcat("abx");
System.out.println(val02);//abxxba
(3)设计判断给定字符串是否是回文
//设计判断给定字符串是否是回文 参数字符串,返回值boolean
public boolean isPalindrome(String str) {
//传递进来的str先反转
/*
String value = this.reverse(str);
if (value.equals(str)) {
return true;
} else {
return false;
}
*/
//反转后的str与传递进来的字符串进行比较
//如果完全一致 证明是回文
if (this.reverse(str).equals(str)) {
return true;
}
return false;
}
boolean val03 = testTask.isPalindrome("abbcbba");
System.out.println(val03);//true
(4)设计将给点给的字符串右位移x位置
//设计将给点给的字符串右位移x位置 参数字符串、右移到位置多少,返回值字符串(abcdefg,2--->fgabcde)
public String moveToRight(String str, int count) {
//如果移动的长度超过你给定的数组,我就将他从前移动,就像<< >>一样他是循环移动的,我们发现你移动12位和你移动5位没区别
if (count > str.length()) {
count %= str.length();//余数
}
//先从传进来的位置进行截取
//得到点半部分
//从索引0开始截取总长度-右移的距离,但是不包含索引为str.length() - count的元素,然后拼接时要放在后面,
String begin = str.substring(0, str.length() - count);
//得到后半部分
//str.length() - count从这个位置开始截取截到最后,然后拼接的时候放在最前面
String end = str.substring(str.length() - count);
//最后拼接然后返回
return end.concat(begin);//将begin拼接在end后面
}
String val04 = testTask.moveToRight("abcdefg",2);
System.out.println(val04);//fgabcde
String val04_ = testTask.moveToRight("abcdefg",12);
System.out.println(val04_);//cdefgab
(5)设计寻找若干字符串中最长的那个
//设计寻找若干字符串中最长的那个,动态参数若干个字符串String... 返回值字符串String
public String findMaxLengthString(String... strs) {
String result = strs[0];//打擂台,假设第一个为最长的
int maxLength = strs[0].length();//第一个字符串长度
//然后比长度就行了
for (int i = 0; i < strs.length; i++) {
if (maxLength < strs[i].length()) {
maxLength = strs[i].length();
result = strs[i];
}
}
return result;
}
String val05 = testTask.findMaxLengthString("asd","sadadas","safaf","asfEGIOE");
System.out.println(val05);//asfEGIOE
(6)设计同级给定字母在字符串中出现的次数
//设计同级给定字母在字符串中出现的次数 参数给定的字母char和String数组,返回值int次数
public int letterExistCount(String str, char leeter) {
/*
int count = 0;//用来记录找到的个数
//通过循环找到字母
for (int i = 0; i < str.length(); i++) {
//返回给定位置的字符char = str.charAt(i)
if (str.charAt(i) == leeter) {
count++;
}
}
*/
//abcdefga---->_bcdef_将数组中给定的字符换为空,将a换为空
//然后将原来的数组长度与替换后的数组长度进行减法,替换了几个最后的差值就是多少
//String.valueOf(leeter)将给定的字符转换为字符串,replace不能将字符替换为字符串,replace只能是字符串之间的替换
return str.length() - str.replace(String.valueOf(leeter), "").length();//这里""不能写空格
}
int val06 = testTask.letterExistCount("abcdefga",'a');
System.out.println(val06);//2
(7)设计将给定的字符串每一个首字母大写
//设计将给定的字符串每一个首字母大写 参数字符串 ,返回值字符串
public String firstLetterToUpperCase(String str) {
String result = "";//用于最终拼接完整字符串
//将完整的字符串按照空格拆分成好多单词 split
String[] value = str.split(" ");
//循环处理每一个单词 截取首字符变大写 截取其余的字母
for (int i = 0; i < value.length; i++) {
String word = value[i];//获取每一个单词
String firstLetter = word.substring(0,1).toUpperCase();//截取第一个单词首字母,然后变大写
String otherLetter = word.substring(1).toLowerCase();//其余都是小写
result = result.concat(firstLetter.concat(otherLetter) + " ");//注意String的不可变特性
}
//将循环每一次的单词拼接成一个完整的字符返回
return result.trim();//去掉最后多余的空格
}
String vall = testTask.firstLetterToUpperCase("this is a test");
System.out.println(vall);//This Is A Test
(8)设计获取给定字符串中的全部数字
//设计获取给定字符串中的全部数字 参数字符串,返回值int
public int findNumber(String str) {
String result = "";
//循环找寻字符串中的每一个 字符
for (int i = 0; i < str.length(); i++) {
//判断当前找到的字符是否是 数字 '0'~'9' 48~57
int code = str.codePointAt(i);
if (code >= 48 && code <= 57) {
result += (char)code;
}
}
//将找到的数字返回
// return Integer.parseInt(result);
return new Integer(result);
}
int v = testTask.findNumber("7sfafho101rb37");
System.out.println(v);//710137