目录
第一章 Java的API
在以前的学习过程中,我们都在学习对象基本特征、对象的使用以及对象的关系。接下来我们开始使用对象做事情,那么在使用对象做事情之前,我们要学习一些API中提供的常用对象。
1.1 Java 的API
- Java 的API(API: Application(应用) Programming(程序) Interface(接口))
- Java API就是JDK中提供给我们使用的类,这些类将底层的代码实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可。
- 在JDK安装目录下有个src.zip文件,这个文件是所有Java类的源文件。
- 每次查看类中的方法时,要打开源代码,这种方式过于麻烦。其实,我们可以通过查帮助文档的方式,来了解Java提供的API如何使用。
第二章 Object类
2.1 Object类概述
Object类是Java语言中的根类,即所有类的父类。它中描述的所有方法子类都可以使用。所有类在创建对象的时候,最终找的父类就是Object。
在Object类众多方法中,我们先学习equals方法与toString方法。其他方法后续会学到。
2.2 equals方法
equals方法,用于比较两个对象是否相同,它其实就是使用两个对象的内存地址在比较。Object类中的equals方法内部使用的就是==比较运算符。
2.2.1 比较地址
注意:引用类型中==表示比较两个对象的内存地址
在开发中要比较两个对象是否相同,经常是将对象中的属性值进行比较,即需要子类重写equals方法根据对象的属性值进行比较。如下代码演示:
package day15.demo1;
public class Person extends Object{
private String name;
private int age;
public Person(){}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public boolean equals(Object obj){
return (this == obj);}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package day15.demo1;
public class TestEquals {
public static void main(String[] args) {
// TODO Auto-generated method stub
//Person类继承Object类,继承下来了父类的方法equals
Person p1 = new Person("李四",20);
Person p2 = new Person("李四",20);
boolean b =p1.equals(p2);
System.out.println(b);
}
}
运行结果:
调用图:
2.2.2 比较内容
比较对象的一个属性是否相等,需要对obj参数进行类型的向下转型(转为子类),obj转成Person类型。
因为多态不能调用子类特有属性。
package day15.demo1;
public class Person extends Object{
private String name;
private int age;
public Person(){}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public boolean equals(Object obj){
//自己和自己比
if(this == obj) {
return true;
}
//obj非空比较
if(obj==null) {
return false;
}
//类型判断,参数obj接受到是Person对象,才能转型
// 对obj参数进行类型的向下转型,obj转成Person类型
if(obj instanceof Person) {
Person p = (Person)obj;
return this.age ==p.age;
}
return false;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package day15.demo1;
import java.util.ArrayList;
public class TestEquals {
public static void main(String[] args) {
// TODO Auto-generated method stub
//Person类继承Object类,继承下来了父类的方法equals
Person p1 = new Person("李四",20);
Person p2 = new Person("李四",20);
ArrayList<String> array = new ArrayList<String>();
boolean b =p1.equals(array);
System.out.println(b);
boolean b1 =p1.equals(p2);
System.out.println(b1);
boolean b2 =p1.equals(null);
System.out.println(b2);
}
}
运行结果:
调用图:
2.3 toString方法
toString方法返回该对象的字符串表示,其实该字符串内容就是对象的类型+@+内存地址值。
由于toString方法返回的结果是内存地址,而在开发中,经常需要按照对象的属性得到相应的字符串表现形式,因此也需要重写它。
不能重写静态的成员变量,因为静态就不属于对象,但toString方法的调用者是对象。
如果不重写toString方法,则返回的就是内存地址。如果返回的不是内存地址,说明方法被重写。
/*
* 重写父类的方法toString()
* 没有必要让调用者看到内存地址
* 要求: 方法中,返回类中所有成员变量的值
*/
public String toString(){
return name + age;
}
第三章 String类
3.1 String类的概述
String 类代表字符串,是引用型变量,但是不用new。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。
字符串是常量;它们的值在创建之后不能更改,这是什么意思呢?其实就是说一旦这个字符串确定了,那么就会在内存区域中就生成了这个字符串。字符串本身不能改变,但str变量中记录的地址值是可以改变的。
演示0:
package day15.demo2;
/*
* String类特点:
* 一切都是对象,字符串事物 "" 也是对象
* 类是描述事物,String类,描述字符串对象的类
* 所有的 "" 都是String类的对象
*
* 字符串是一个常量,一旦创建,不能改变
*/
public class StringDemo {
public static void main(String[] args) {
//引用变量str执行内存变化
//定义好的字符串对象,不变
String str = "itcast";
System.out.println(str);
str = "itheima";
System.out.println(str);
}
}
运行结果:
结果分析:
str是引用类型的变量,“itcast”、“itheima”都是对象。
引用变量 str指向的内存发生变化,而定义好的字符串对象是不发生变化的。
演示1:
package day15.demo2;
public class StringDemo1 {
public static void main(String[] args) {
//字符串定义方式2个, 直接= 使用String类的构造方法
String str1 = new String("abc");
String str2 = "abc";
System.out.println(str1);
System.out.println(str2);
System.out.println(str1==str2);//引用数据类型,比较对象的地址 false
System.out.println(str1.equals(str2));//true
}
}
执行String str1 = new String("abc")时,这一句话在堆内存创建出了两个对象,第一个存储空间是new String(),第二个对象是括号里面的"abc"(是以char数组的形式存储的,源码中叫value[]),第一个存储空间中存的是value[]的地址。
运行String str2 = "abc"; 堆内存中有“abc”,因此str2直接指向堆内存中的“abc”
因此比较(str1==str2)结果为false,因为指向地址不同。
System.out.println(str1==str2);//引用数据类型,比较对象的地址 false
内存图解:
String类重写的equals方法源码:
//String类重写的equals方法源码
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
3.2 String类构造方法
构造方法是用来完成String对象的创建,下图中给出了一部分构造方法需要在API中找到,并能够使用下列构造方法创建对象。
String(byte[] bytes)
功能是传递字节数组,字节数组转成字符串,通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
- 平台 : 机器操作系统
- 默认字符集: 操作系统中的默认编码表, 默认编码表GBK
汉字的字节编码就是负数, 默认编码表 ,一个汉字采用2个字节表示。
正数查ASCII码表
负数查GBK,查找结果是中文(一对数字代表一个汉字)
byte[] bytes = {-97,-98,-99,-100};//煘潨,代表两个字节一个汉字。{-97,-98}代表煘
String s1 = new String(); //创建String对象,字符串中没有内容
byte[] bys = new byte[]{97,98,99,100};
String s2 = new String(bys); // 创建String对象,把数组元素作为字符串的内容
String s3 = new String(bys, 1, 3); //创建String对象,把一部分数组元素作为字符串的内容,参数offset为数组元素的起始索引位置,参数length为要几个元素
char[] chs = new char[]{’a’,’b’,’c’,’d’,’e’};
String s4 = new String(chs); //创建String对象,把数组元素作为字符串的内容
String s5 = new String(chs, 0, 3);//创建String对象,把一部分数组元素作为字符串的内容,参数offset为数组元素的起始索引位置,参数count为要几个元素
String s6 = new String(“abc”); //创建String对象,字符串内容为abc
package day15.demo2;
/*
* String类构造方法
* String类的构造方法,重载形式
*
*/
public class StringDemo2 {
public static void main(String[] args) {
function_1();
function();
}
/*
* String(char[] value) 传递字符数组
* 将字符数组,转成字符串, 字符数组的参数,不查询编码表
*
* String(char[] value, int offset, int count) 传递字符数组
* 将字符数组的一部分转成字符串
* offset 数组开始索引
* count 个数
*/
public static void function_1(){
char[] ch = {'a','b','c','d','e','f'};
//调用String构造方法,传递字符数组
String s = new String(ch);
System.out.println(s);
String s1 = new String(ch,1,4);//[1,4]
System.out.println(s1);
}
/*
* 定义方法,String类的构造方法
* String(byte[] bytes) 传递字节数组
* 字节数组转成字符串
* 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
* 平台 : 机器操作系统
* 默认字符集: 操作系统中的默认编码表, 默认编码表GBK
* 将字节数组中的每个字节,查询了编码表,得到的结果
* 字节是负数,汉字的字节编码就是负数, 默认编码表 ,一个汉字采用2个字节表示
*
* String(byte[] bytes, int offset, int length) 传递字节数组
* 字节数组的一部分转成字符串
* offset 数组的起始的索引
* length 个数,转几个 , 不是结束的索引
*/
public static void function(){
//byte[] bytes = {97,98,99,100};
byte[] bytes = {-97,-98,-99,-100};//煘潨,两个字节一个汉字
//调用String类的构造方法,传递字节数组
String s = new String(bytes);
System.out.println(s);
byte[] bytes1 ={65,66,67,68,69};
//调用String构造方法,传递数组,传递2个int值
String s1 = new String(bytes1,1,3);
System.out.println(s1);
}
}
运行结果:
3.3 String类的方法查找
字符串是一个对象,那么它的方法必然是围绕操作这个对象的数据而定义的。我们想想字符串中有哪些功能呢?
3.3.1 获取字符串中有多少个字符
String str = "abcde";
int len = str.length();
System.out.println("len="+len);
3.3.2 获取部分字符串
String str = "abcde";
String s1 = str.substring(1); //返回一个新字符串,内容为指定位置开始到字符串末尾的所有字符 bcde
String s2 = str.substring(2, 4);//返回一个新字符串,内容为指定位置开始到指定位置结束所有字符 cd
System.out.println("str="+str);
System.out.println("s1="+s1);
System.out.println("s2="+s2);
3.4String类中方法查找练习
3.4.1 字符串是否以指定字符串开头,结尾同理
String str = "StringDemo.java";
boolean b1 = str.startsWith("Demo");//判断是否以给定字符串开头
boolean b2 = str.startsWith("String");
boolean b3 = str.endsWith(".java");//判断是否以给定字符串结尾
3.4.2 字符串中是否包含另一个字符串
String str = "abcde";
int index = str.indexOf(“bcd”); //判断是否包含指定字符串,包含则返回第一次出现该字符串的索引,不包含则返回-1
boolean b2 = str.contains("bcd");//判断是否包含指定字符串,包含返回true,不包含返回false
3.4.3将字符串转成一个字符数组,或者字节数组
String str = "abcde";
char[] chs = str.toCharArray();
byte[] bytes = str.getBytes();
3.4.4 判断两个字符串中的内容是否相同
String str = "abcde";
String str2 = "abcde";
String str3 = "hello";
boolean b1 = str.equals(str2);
boolean b2 = str.equals(str3);
3.4.5 获取该字符串对象中的内容
String str = new String("hello");
System.out.println( str.toString() ); //hello
System.out.pintln( str ); //hello
以下需求所对应的方法,大家可以在API中查找。
- 判断该字符串的内容是否为空的字符串
- 获取给定的字符,在该字符串中第一次出现的位置
- 获取该字符串中指定位置上的字符
- 把该字符串转换成 小写字符串
- 把该字符串转换成 大写字符串
- 在该字符串中,将给定的旧字符,用新字符替换
- 在该字符串中, 将给定的旧字符串,用新字符串替换
- 去除字符串两端空格,中间的不会去除,返回一个新字符串
package day15.demo2;
/*
* String类的查找功能
*/
public class StringDemo4 {
public static void main(String[] args) {
function_9();
}
/*
* boolean equals(Object obj)
* 方法传递字符串,判断字符串中的字符是否完全相同,如果完全相同返回true
*
* boolean equalsIgnoreCase(String s)
* 传递字符串,判断字符串中的字符是否相同,忽略大小写
*/
public static void function_9(){
String str1 = "Abc";
String str2 = "abc";
//分别调用equals和equalsIgnoreCase
boolean b1 = str1.equals(str2);
boolean b2 = str1.equalsIgnoreCase(str2);
System.out.println(b1);
System.out.println(b2);
}
/*
* char[] toCharArray() 将字符串转成字符数组
* 功能和构造方法相反
*/
public static void function_8(){
String str = "itcast";
//调用String类的方法toCharArray()
char[] ch = str.toCharArray();
for(int i = 0 ; i < ch.length ; i++){
System.out.println(ch[i]);
}
}
/*
* byte[] getBytes() 将字符串转成字节数组
* 此功能和String构造方法相反
* byte数组相关的功能,查询编码表
*/
public static void function_7(){
String str = "abc";
//调用String类方法getBytes字符串转成字节数组
byte[] bytes = str.getBytes();
for(int i = 0 ; i < bytes.length ; i++){
System.out.println(bytes[i]);
}
}
/*
* int indexOf(char ch)
* 查找一个字符,在字符串中第一次出现的索引
* 被查找的字符不存在,返回-1
*/
public static void function_6(){
String str = "itcast.cn";
//调用String类的方法indexOf
int index = str.indexOf('x');
System.out.println(index);
}
/*
* boolean contains (String s)
* 判断一个字符串中,是否包含另一个字符串
*/
public static void function_5(){
String str = "itcast.cn";
//调用String类的方法contains
boolean b =str.contains("ac");
System.out.println(b);
}
/*
* boolean endsWith(String prefix)
* 判断一个字符串是不是另一个字符串的后缀,结尾
* Demo.java
* .java
*/
public static void function_4(){
String str = "Demo.java";
//调用String类方法endsWith
boolean b = str.endsWith(".java");
System.out.println(b);
}
/*
* boolean startsWith(String prefix)
* 判断一个字符串是不是另一个字符串的前缀,开头
* howareyou
* hOw
*/
public static void function_3(){
String str = "howareyou";
//调用String类的方法startsWith
boolean b = str.startsWith("hOw");
System.out.println(b);
}
/*
* String substring(int beginIndex,int endIndex) 获取字符串的一部分
* 返回新的字符串
* 包含头,不包含尾巴
*
* String substring(int beginIndex)获取字符串的一部分
* 包含头,后面的字符全要
*/
public static void function_2(){
String str = "howareyou";
//调用String类方法substring获取字符串一部分
str= str.substring(1, 5);
System.out.println(str);
String str2 = "HelloWorld";
str2 = str2.substring(1);
System.out.println(str2);
}
/*
* int length() 返回字符串的长度
* 包含多少个字符
*/
public static void function(){
String str = "cfxdf#$REFewfrt54GT";
//调用String类方法length,获取字符串长度
int length = str.length();
System.out.println(length);
}
}
3.5String类方法使用练习
练习1:统计大小写、数字各类个数
获取指定字符串中,大写字母、小写字母、数字的个数。
package day15.demo2;
/*
* 获取指定字符串中,大写字母、小写字母、数字的个数。
* 思想:
* 1. 计数器,就是int变量,满足一个条件 ++
* 2. 遍历字符串, 长度方法length() + charAt() 遍历
* 3. 字符判断是大写,是小写,还是数字
*/
public class StringTest {
public static void main(String[] args) {
getCount("A%A3eBr1FFy");
}
public static void getCount(String str){
//定义三个变量,计数
int upper = 0;
int lower = 0;
int digit = 0;
//对字符串遍历
for(int i=0;i<str.length();i++) {
char c = str.charAt(i);
//小写字母 97-122 大写65-90 数字48-57
// if(c<=90 && c>=65) {
// upper++;
// }
// else if (c<=122 && c>=97) {
// lower++;
// }
// else if(c<=57 && c>=48) {
// digit++;
// }
if(c<='Z' && c>='A') {
upper++;
}
else if (c<='z' && c>='a') {
lower++;
}
else if(c<='9' && c>='0') {
digit++;
}
}
System.out.println(upper);
System.out.println(lower);
System.out.println(digit);
}
}
运行结果:
练习2:字符串大小写转换
将字符串中,第一个字母转换成大写,其他字母转换成小写,并打印改变后的字符串。
package day15.demo2;
public class StringTest {
public static void main(String[] args) {
System.out.println(toConvert("aBc5%4dEF"));
}
/*
* 将字符串的首字母转成大写,其他内容转成小写
* 思想:
* 获取首字母, charAt(0) substring(0,1)
* 转成大写 toUpperCase()
*
* 获取剩余字符串, substring(1) toLowerCase()
*/
public static String toConvert(String str){
//定义变量,保存首字母,和剩余字符
String first = str.substring(0,1);
String after = str.substring(1);
first = first.toUpperCase();
after =after.toLowerCase();
return first+after;
}
}
运行结果:
练习3:查询指定小字符串的次数
查询大字符串中,出现指定小字符串的次数。如“hellojava,nihaojava,javazhenbang”中查询出现“java”的次数。
题目分析:
package day15.demo2;
public class StringTest {
public static void main(String[] args) {
System.out.println(getStringCount("hellojava,nijavahaojava,javazhenbang", "java"));
}
/*
* 获取一个字符串中,另一个字符串出现的次数
* 思想:
* 1. indexOf到字符串中到第一次出现的索引
* 2. 找到的索引+被找字符串长度,截取字符串
* 3. 计数器++
*/
public static int getStringCount(String str, String key){
//定义计数器
int count = 0;
//定义变量,保存indexOf查找后的索引的结果
int index = 0;
//开始循环找,条件,indexOf==-1 字符串没有了
while((index=str.indexOf(key))!=-1){
count++;
//获取到的索引,和字符串长度求和,截取字符串
str= str.substring(index+key.length());
}
return count;
}
}
运行结果:
第四章 字符串缓冲区
4.1 StringBuffer类
查阅StringBuffer的API,StringBuffer又称为可变字符序列,它是一个类似于 String 的字符串缓冲区,通过某些方法调用可以改变该序列的长度和内容。
原来StringBuffer是个字符串的缓冲区,即就是它是一个容器,容器中可以装很多字符串。并且能够对其中的字符串进行各种操作。
4.2 StringBuffer的方法使用
//创建一个字符串缓冲区对象。用于存储数据。
StringBuffer sb = new StringBuffer();
sb.append("haha"); //添加字符串
sb.insert(2, "it");//在指定位置插入
sb.delete(1, 4);//删除
sb.replace(1, 4, "cast");//替换指定范围内的内容
String str = sb.toString();
如果StringBuffer的方法的返回值还是StringBuffer类型,则可用一直调用(调用链)
buffer.append(6).append(false).append('a').append(1.5);//调用链
java中索引,一般都是开始索引包含,结尾索引不包含。前闭后开区间。
package day15.demo2;
public class StringBufferDemo {
public static void main(String[] args) {
function_5();
}
/*
* StringBuffer类的方法
* String toString() 继承Object,重写toString()
* 将缓冲区中的所有字符,变成字符串
*/
public static void function_5(){
StringBuffer buffer = new StringBuffer();
buffer.append("abcdef");
buffer.append(12345);
//将可变的字符串缓冲区对象,变成了不可变String对象
String s = buffer.toString();
System.out.println(s);
}
/*
* StringBuffer类的方法
* reverse() 将缓冲区中的字符反转
*/
public static void function_4(){
StringBuffer buffer = new StringBuffer();
buffer.append("abcdef");
buffer.reverse();
System.out.println(buffer);
}
/*
* StringBuffer类方法
* replace(int start,int end, String str)
* 将指定的索引范围内的所有字符,替换成新的字符串
*/
public static void function_3(){
StringBuffer buffer = new StringBuffer();
buffer.append("abcdef");
buffer.replace(1, 4, "Q");
System.out.println(buffer);
}
/*
* StringBuffer类方法 insert
* insert(int index, 任意类型)
* 将任意类型数据,插入到缓冲区的指定索引上
*/
public static void function_2(){
StringBuffer buffer = new StringBuffer();
buffer.append("abcdef");
buffer.insert(3, 9.5);
System.out.println(buffer);
}
/*
* StringBuffer类方法
* delete(int start,int end) 删除缓冲区中字符
* 开始索引包含,结尾索引不包含
*/
public static void function_1(){
StringBuffer buffer = new StringBuffer();
buffer.append("abcdef");
buffer.delete(1,5);
System.out.println(buffer);
}
/*
* StringBuffer类方法
* StringBuffer append, 将任意类型的数据,添加缓冲区
* append 返回值,写return this
* 调用者是谁,返回值就是谁
*/
public static void function(){
StringBuffer buffer = new StringBuffer();
//调用StringBuffer方法append向缓冲区追加内容
buffer.append(6).append(false).append('a').append(1.5);
System.out.println(buffer);
}
}
4.3 StringBuilder类
StringBuilder类,它也是字符串缓冲区,StringBuilder与它和StringBuffer的有什么不同呢?
阅读StringBuilder的API发现,它也是一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步(不安全)。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。
目前,我们还没有涉及到线程与同步,知道结论StringBuilder比StringBuffer快即可。为什么快,我们会在学习线程时讲解。
简单来说,StringBuffer线程安全,但是速度慢。
StringBuilder线程不安全,速度快。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。
举例:将一个int[]中元素转成字符串格式[2,4,66,2,1]
package day15.demo2;
public class StringBufferTest {
public static void main(String[] args) {
int[] arr = {4,1,4,56,7,8,76};
System.out.println(toString(arr));
}
/*
* int[] arr = {34,12,89,68};将一个int[]中元素转成字符串
* 格式 [34,12,89,68]
* String s = "["
* 数组遍历
* s+= arr[i];
* s+"]"
* StringBuffer实现,节约内存空间, String + 在缓冲区中,append方法
*/
public static String toString(int[] arr){
//创建字符串缓冲区
StringBuffer buffer = new StringBuffer();
buffer.append("[");
//数组遍历
for(int i = 0 ; i < arr.length;i++){
//判断是不是数组的最后一个元素
if(i == arr.length-1){
buffer.append(arr[i]).append("]");
}else{
buffer.append(arr[i]).append(",");
}
}
return buffer.toString();
}
}