Java基础复习(五):常用类及其常用方法——Object类、Scanner类、String类
常用类及其常用方法
一、Object类
Object类是所有类的主类。
主要的方法:
1、public boolean equals(Object obj)
:指示一些其他对象是否等于此,用于比较2个对象的内存地址是否相等。
(1)自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
(2)对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)回报true 。
(3)传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true个y.equals(z)回报true ,然后x.equals(z)应该返回true 。
(4)一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,没有设置中使用的信息equals比较上的对象被修改。
(5)对于任何非空的参考值x , x.equals(null)应该返回false 。
注意: equals方法在非空对象上引用不会有报错可能。所以在使用时尽量保证变量不为空对象,否则会报空指针异常;如变量与字符串比较时,尽量是“字符串”.equals(变量)。通常会重写equals方法,来拥有更好的性能,比如String类对该方法进行了重写用户比较字符串的值是否相等。
==和equals的区别
“==”的作用:用来比较两个对象的地址值是否相等。
对于基本数据类型,则相当于比较数值;对于引用类型变量,则是在比较对象的地址值是否相同(即都是在比较JVM栈中的值),引用类型中存在基本数据类型的包装类这一特殊情况,由于常量池的不同,会出现不同的结果。
equals的作用:用来比较两个对象是否相等,但是不能用于比较基本数据类型的变量。
如果类没有重写equals()
方法,则equals()
方法的作用就相当于“ == ”的作用,equals()
方法默认的是Objectl类中的equals()
方法。如果该类重写了equals()
方法,就会采用该类中的equals()
方法,一般会重写为比较内容是否相等的作用,如String类中重写的equals()
方法。
public class Test_equals {
public static void main(String[] args) {
Boolean flag;
//基本数据类型
int i1=300;
int i2=300;
flag = i1==i2;
System.out.println("i1==i2:"+flag);
//i1.equals(i2)会报错;
//包装类,超过常量池的数据范围,会新建一个对象
Integer i3=300;
Integer i4=300;
flag = i3==i4;
System.out.println("i3==i4:"+flag);
flag = i3.equals(i4);
System.out.println("i3.equals(i4):"+flag);
//i5创建后放入常量池,i6会从常量池中寻找再调用,所以是同一个对象
String i5="nihao";
String i6="nihao";
flag = i5==i6;
System.out.println("i5==i6:"+flag);
flag = i5.equals(i6);
System.out.println("i5.equals(i6):"+flag);
//new String创建字符串时,一定会重新创建对象
String i7=new String("nihao");
String i8=new String("nihao");
flag = i7==i8;
System.out.println("i7==i8:"+flag);
flag = i7.equals(i8);
System.out.println("i7.equals(i8):"+flag);
}
}
结果:
i1 == i2:true
i3 == i4:false
i3.equals(i4):true
i5 == i6:true
i5.equals(i6):true
i7 == i8:false
i7.equals(i8):true
2、public int hashCode()
:返回对象的哈希码值,一个int型的整数,用来确定该对象在哈希表中的索引位置。 支持这种方法是为了散列表,如HashMap提供的那样 。
在不使用散列表(HashMap、HashSet、HashTable等数据结构上)时:其中的hasnCode()
方法与equals()
方法完全没有关系,hasnCode()
方法没有作用。
public class Test3_HashCode {
public static void main(String[] args) {
// 新建2个相同内容的Person对象,
// 再用equals比较它们是否相等
Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Person p3 = new Person("aaa", 200);
System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
System.out.printf("p1.equals(p3) : %s; p1(%d) p3(%d)\n", p1.equals(p3), p1.hashCode(), p3.hashCode());
}
/**
* @desc Person类。
*/
private static class Person {
int age;
String name;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + " - " +age;
}
/**
* @desc 覆盖equals方法
*/
public boolean equals(Object obj){
if(obj == null){
return false;
}
//如果是同一个对象返回true,反之返回false
if(this == obj){
return true;
}
//判断是否类型相同
if(this.getClass() != obj.getClass()){
return false;
}
Person person = (Person)obj;
return name.equals(person.name) && age==person.age;
}
}
}
结果:
p1.equals(p2) : true; p1(23050916) p2(32379559)
p1.equals(p3) : false; p1(23050916) p3(21282042)
在散列表(HashMap、HashSet、HashTable等数据结构上)中使用该类:如果两个对象相等,则其hasnCode()
值一定是相等的;但是如果两个对象的hasnCode()
值相等,他们也不一定相等。因此在覆盖equals方法时也一定要覆盖hashCode方法。
只重写了equals()
方法:
import java.util.*;
public class Test_HashCode {
public static void main(String[] args) {
// 新建Person对象,
Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Person p3 = new Person("aaa", 200);
// 新建HashSet对象
HashSet set = new HashSet();
set.add(p1);
set.add(p2);
set.add(p3);
// 比较p1 和 p2, 并打印它们的hashCode()
System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
// 打印set
System.out.printf("set:%s\n", set);
}
/**
* @desc Person类。
*/
private static class Person {
int age;
String name;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "("+name + ", " +age+")";
}
/**
* @desc 覆盖equals方法
*/
@Override
public boolean equals(Object obj){
if(obj == null){
return false;
}
//如果是同一个对象返回true,反之返回false
if(this == obj){
return true;
}
//判断是否类型相同
if(this.getClass() != obj.getClass()){
return false;
}
Person person = (Person)obj;
return name.equals(person.name) && age==person.age;
}
}
}
结果:
p1.equals(p2) : true; p1(23050916) p2(32379559)
set:[(eee, 100), (eee, 100), (aaa, 200)]
由于没有重写hasnCode()
方法,尽管内容相同,但是hasnCode()
的值不同,所以在set集合里面还是会有重复值,equals()
方法不起作用。
重写equals()
方法和hashCode()
方法:
import java.util.*;
public class Test2_HashCode {
public static void main(String[] args) {
// 新建Person对象,
Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Person p3 = new Person("aaa", 200);
Person p4 = new Person("EEE", 100);
// 新建HashSet对象
HashSet set = new HashSet();
set.add(p1);
set.add(p2);
set.add(p3);
// 比较p1 和 p2, 并打印它们的hashCode()
System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
// 比较p1 和 p4, 并打印它们的hashCode()
System.out.printf("p1.equals(p4) : %s; p1(%d) p4(%d)\n", p1.equals(p4), p1.hashCode(), p4.hashCode());
// 打印set
System.out.printf("set:%s\n", set);
}
/**
* @desc Person类。
*/
private static class Person {
int age;
String name;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + " - " +age;
}
/**
* @desc重写hashCode
*/
@Override
public int hashCode(){
int nameHash = name.toUpperCase().hashCode();
return nameHash ^ age;
}
/**
* @desc 覆盖equals方法
*/
@Override
public boolean equals(Object obj){
if(obj == null){
return false;
}
//如果是同一个对象返回true,反之返回false
if(this == obj){
return true;
}
//判断是否类型相同
if(this.getClass() != obj.getClass()){
return false;
}
Person person = (Person)obj;
return name.equals(person.name) && age==person.age;
}
}
}
结果:
p1.equals(p2) : true; p1(68545) p2(68545)
p1.equals(p4) : false; p1(68545) p4(68545)
set:[eee - 100, aaa - 200]
比较p1和p2,hashCode()相等,且通过equals()比较它们也返回true。所以,p1和p2被视为相等。比较p1和p4,hashCode()相等;但是,通过equals()比较它们返回false。所以,p1和p4被视为不相等。equals()生效了,HashSet中没有重复元素。
3、public final native Class<?> getClass()
:返回此Object的运行时的类。 返回的类对象是被表示类的static synchronized方法锁定的对象。 使用了final关键字修饰,故不允许子类重写。并且需要注意的是该方法只能由类的实例变量调用。
public class Test_getClass {
public static void main(String[] args) {
Dog ss = new Dog();
Class a = ss.getClass();
System.out.println(ss.getClass());//class Dog
System.out.println(a.getName());//Dog
}
}
4、protected native Object clone() throws CloneNotSupportedException
:用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式 x.clone() != x 为true,x.clone().getClass() == x.getClass() 为true。Object本身没有实现Cloneable接口,所以不重写clone方法并且进行调用的话会发生CloneNotSupportedException异常。
5、public String toString()
:返回类的名字@实例的哈希码的16进制的字符串。一般Object所有的子类都重写这个方法,可以自己定义输出的形式。
与多线程有关的方法:wait()、notify/notifyAll() 方法(在Java线程上再细说)
6、public final void notify()
:不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
7、public final void notifyAll()
:不能重写。唤醒正在等待对象监视器的所有线程。
8、public final void wait(long timeout) throws InterruptedException
:不能重写。导致当前线程等待,直到另一个线程调用此对象的notify()方法或notifyAll()方法,或指定的时间已过。当前的线程必须拥有该对象的显示器。
9、public final void wait(long timeout, int nanos) throws InterruptedException
:多了nanos参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上nanos毫秒。
10、public final void wait() throws InterruptedException
:导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。 换句话说,这个方法的行为就好像简单地执行呼叫wait(0) 。跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念。
二、Scanner类
一个简单的文本扫描器,可以使用正则表达式解析原始类型和字符串。可以调用方法来获取输入框的内容。
主要的方法:
1、主要用于读取内容
nextxxx()
方法表示只能读取xxx类型的数据。next()
方法:只读取输入直到空格。它不能读两个由空格或符号隔开的单词。此外,next()
在读取输入后将光标放在同一行中。(next()
只读空格之前的数据,并且光标指向本行)
nextLine()
方法:读取输入,包括单词之间的空格和除回车以外的所有符号(即。它读到行尾)。读取输入后,nextLine()
将光标定位在下一行。
import java.util.Scanner;
public class Test_Scanner {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入字符串,不能够识别空格的");
String a = scanner.next();
System.out.println("a:"+a);
/*
结果:请输入字符串,不能够识别空格的
hello world
a:hello
*/
System.out.println("请输入字符串,能够识别空格的");
String b = scanner.nextLine();
System.out.println("b:"+b);
/*
结果:请输入字符串,能够识别空格的
hello world
b:hello world
*/
//nextxxx()类似
System.out.println("请输入一个整数");
System.out.println("c:"+scanner.nextInt());
/*
结果:请输入一个整数
123
c:123
*/
}
}
2、主要用于判断内容的类型
import java.util.Scanner;
public class Test2_Scanner {
public static void main(String args[]) {
Scanner scan = new Scanner(System.in); //构造Scanner类的对象scan,接收从控制台输入的信息
System.out.println("请输入你的姓名");
String name = scan.nextLine();//接收一个字符串,可以加除Enter以外的所有符号,包括空格和Tab
System.out.println("请输入你的ID");
String ID ;
while(scan.hasNextLine()) {// hasNextLine()方法判断当前是否有输入,当键盘有输入后执行循环
if(scan.hasNextInt()) {// 判断输入的值是否为整数类型,当为整数类型时执行循环
ID = scan.nextLine();
System.out.println("你输入的姓名为:"+name);
System.out.println("你输入的ID为:"+ID);
break;
}else {
System.out.println("ID需要输入数字!");
ID = scan.nextLine();
continue;
}
}
}
}
三、String类
String类代表字符串,引用数据类型。
1、定义及初始化:
(1)String str1 = "hello world";
该方法定义字符串,会将字符串存入字符串常量池中,再使用该种方法定义,若存在一样的字符串,则会引用常量池中的字符串。
(2)char[] Array = {'a','b','c'}; String str3=new String(Array);
该方法,会建立新的对象存放到堆中,然后通过地址值引用。
public class Test_String {
public static void main(String[] args) {
String str1="abc";
String str2="abc";
char[] Array = {'a','b','c'};
String str3=new String(Array);
String str4=new String(Array);
System.out.println("str1="+str1);
System.out.println("str2="+str2);
System.out.println("str3="+str3);
System.out.println("str4="+str4);
System.out.println("str1==str2: "+(str1==str2));
System.out.println("str1==str3: "+(str1==str3));
System.out.println("str1.equals(str3): "+(str1.equals(str3)));
System.out.println("str3==str4: "+(str3==str4));
}
}
结果:
str1=abc
str2=abc
str3=abc
str4=abc
str1 == str2: true
str1 == str3: false
str1.equals(str3): true
str3 == str4: false
2、常用方法:
(1)public int length()
:获取字符串长度。
(2)public String concat(String str)
:将指定的字符串连接到该字符串的末尾。原来的字符串不会发生变化,产生一个新的字符串值。
(3)public char charAt(int index)
:获取指定索引位置的单个字符,返回值为char型。
(4)public int indexOf(String str)
:返回指定子字符串第一次出现的字符串内的索引。
public int intindexOf(String str, int fromIndex)
:返回指定子串的第一次出现的字符串中的索引,从指定的索引开始。
两个方法的区别:
public class Test2_String {
public static void main(String[] args) {
String str1 = "hello world";
System.out.println(str1.indexOf("l"));//2
System.out.println(str1.indexOf("l",5));//9,从索引为5的地方开始数
}
}
(5)public String substring(int index)
:返回一个字符串,该字符串是此字符串的子字符串。
public String substring(int beginIndex, int endIndex) ;
:返回一个字符序列,该序列是该序列的子序列。
public class Test2_String {
public static void main(String[] args) {
String str2="hello world";
System.out.println(str2.substring(2));//llo world
System.out.println(str2.substring(2,5));//llo
}
}
(6)public char[ ] toCharArray();
:将此字符串转换为新的字符数组。
public class Test2_String {
public static void main(String[] args) {
String str = "hello world";
char[] chars = str.toCharArray();
for(char s:chars){
System.out.print(s+"-");
}
//结果:h-e-l-l-o- -w-o-r-l-d-
}
}
public byte[ ]getBytes()
:使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中。
public class Test3_String {
public static void main(String[] args) {
String str = "hello world";
byte[] bytes = str.getBytes();
for(byte s:bytes){
System.out.print(s+"-");
}
//结果:104-101-108-108-111-32-119-111-114-108-100-
}
}
public String replace(char oldChar, char newChar)
:返回从替换所有出现的导致一个字符串 oldChar在此字符串 newChar 。
public class Test3_String {
public static void main(String[] args) {
String str = "hello world";
System.out.println("str = "+str);
String str_2=str.replace("l","*");
System.out.println("str_2 = "+str_2);
//结果:str = hello world
// str_2 = he**o wor*d
}
}
其余方法详见JavaAPI文档。