java中默认提供——Object类
一、Object类
1.object类简介
class Person{}
class Student{}
public class ObjectTest{
public static void main(String[] agrs){
fun(new Person());//这个过程相当于是实现了向上转型
fun(new Student());
}
public static void fun(Object obj){
System.out.println(obj);//打印对应的调用这个函数的对象
}
}
从上面的代码我们可以看出Person、Student类都是默认继承Object的,我们没有明显的继承关键字:extends,但是在调用fun函数的时候还是可以进行,这个时候相当于默认的使用了向上转型,最后打印的结构就是对应对象的编码。
2.取得对象信息
在Object类里面已经定义了好多的方法,比如我们的构造方法,toString()方法,equals()方法,正是因为已经定义好了这些方法,所以我们在在编写程序的时候可以直接用equals()进行字符串的比较,而toString()方法,我们之前在学习数组的时候就已经认识到了,当我们直接返回一个数组名字的时候是一个奇怪的编码,对于我们的对象也是一样的,如果只是直接调用toString方法,那么返回的就是这个对象的地址编码。对于我们的toString函数就是获取对象信息的,只是这个函数它默认的返回值就是对象的编码,是一个地址。
直接调用toString方法:
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
}
class Student{}
public class ObjectTest{
public static void main(String[] args){
fun(new Person("余名",20));
fun("hello");//这直接传一个
}
public static void fun(Object obj){
System.out.println(obj.toString());
}
}
从这个运行结果我们可以看到String可以直接输出字符串的内容,但是我们的对象想要直接输出字符串,就必须得调用toString()方法。但是我们Object中的toString方法只能输出这个对象的地址编码,所以如果我们需要直接通过对象名字返回内容,那么我们就需要重新覆写这个方法。
经过覆写以后再调用toStirng()方法:
//覆写toString方法
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return "姓名:"+this.name+"年龄:"+this.age;
}
}
class Student{}
public class ObjectTest{
public static void main(String[] args){
fun(new Person("张三",20));
fun("hello");
}
public static void fun(Object obj){
System.out.println(obj.toString());
}
}
除了字符串可以直接进行调用意外,其他的所有对象想要输出字符串的内容就必须得进行覆写toString方法。String是引用数据类型,就是类,它之所以可以直接的返回内容,是因为String这个类也是继承了Object类的,它已经将Object类中的toString方法进行了覆写,所以可以直接返回字符串的内容。
3.对象比较
我们知道进行值的比较用的是==号,对于字符串内容的比较我们用了equals方法,而我们知道String就是一个类,我们如果写成String a=“越文”,它就表示创建了一个String的对象,进行内容的比较就是用的equals,实际上这个equals就是覆写了Object类里面的方法,所以我们在进行对象比较的时候就是需要用到equals方法。
//对象的比较
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return "姓名:"+this.name+"年龄:"+this.age;
}
//equals方法覆写(以下是equals方法的模板,需要记住)
//在进行比较的时候,我们先判断是否为同一个对象
//如果不是则再看是否为同一类型,如果经判断以后不是同一类型的话我们就返回false,是才进行比较
public boolean equals(Object obj){
if(this==obj){//这里的this表示当前对象,而obj表示用户创建的对象
return true;
}
if(!(obj instanceof Person)){
return false;
}else{
Person person=(Person)obj;//向下转型
//满足是同一类型以后再进行内容的比较
return this.name.equals(person.name)&&(this.age==person.age);
}
}
}
class Student{}
public class ObjectTest{
public static void main(String[] args){
Person per1=new Person("张三",20);
Person per2=new Person("李四",20);
Person per3=new Person("张三",20);
Student stu1=new Student();
Person per4=per1;
System.out.println(per1.equals(per2));//属于同一个类型,但是值不相等->false
System.out.println(per1.equals(per3));//属于同一类型并且内容相等->true
System.out.println(per1.equals(stu1));//不属于同一个类型->false
System.out.println(per1.equals(per4));//是同一个对象->true
}
}
进行对象的比较我们一共分为三种类型:
(1)不属于同一种类型,也就是这两个对象没有任何的关系,不是由同一个类创建的,这样的对象无法进行比较,直接就返回false了。
(2)是同一个对象,就是这两个对象指向的堆内存的地址都是相同的。
(3)属于同一种类型,然后对这两个对象进行内容的判断,如果这内容相同,返回的还是true,否则返回false。
4.Object类可以接受引用数据类型
public class ObjectTest{
public static void main(String[] args){
//接收数组类型
Object obj=new int[] {1,2,3,4,5};
int[] data=(int[]) obj;
//for循环的增强版,foreach循环
for(int i:data){
System.out.println(i+" ");
}
}
}
从上面这个例子我们可以看出Object可以接收数组,对于其他的接口、类它都是可以接收的。
//Object接收接口对象
interface IMessage{
public void getMessage();
}
class MessageImp implements IMessage{
public String toString(){
return "I am ";
}
public void getMessage(){
System.out.println("你好");
}
}
public class ObjectTest{
public static void main(String[] args){
IMessage msg=new MessageImp();//向上转型
Object obj=msg;//接口向Object转型
System.out.println(obj);
IMessage temp=(IMessage)obj;//强制类型转换
temp.getMessage();
}
}
Object也可以接收接口类型,但我们知道接口不继承任何的类,但是Object还是可以进行接收接口,这是强制要求的。
二、包装类
从上面得到的结论是Object可以接收所有的类型,但是在java中我们的数据类型分为基本数据类型和引用数据类型,对于引用数据类型它们本来就是类,但是对于基本数据类型,我们又应该怎么处理呢?
下面我们就讲解我们是如何进行基本数据类型的接收的——包装类。
1.包装类是如何让产生的:就是在我们Object进行数据接收的时候分为两类,一类是引用数据类型,一类是基本数据类型,对于基本数据类型,它们不是类,所以我们对它进行包装,就有了包装类。
自己定义一个包装类:
class IntDemo{
private int num;
public IntDemo(int num){
this.num=num;
}
public int intValue(){
return this.num;
}
}
public class ObjectTest{
public static void main(String[] args){
Object obj=new IntDemo(20);//实现向上转型
IntDemo tmp=(IntDemo)obj;//向下转型
System.out.println(tmp.intValue());//取出里面的基本数据类型操作
}
}
此时这个20就相当于是在堆内存中,相当于是对象的属性,是一个引用数据类型的属性。
在java中已经提供了包装类的使用:
(1)对象类型(Object的直接子类):Boolean,Character(char)
(2)数值类型(Number的直接子类):Byte,Integer(int),Double,Short,Long,Float
注意:Number类是Object的直接子类,所以我们的数据类型是Object的间接子类
2.装箱与拆箱
装箱:装箱就是将我们的基本数据类型转换为一个类的对象,而我们称这个类是包装类。这个包装类有构造方法,让这个对象可以指向基本数据类型。
拆箱:就是通过包装类的对象以及Number里的方法对包装类的属性的访问。
//装箱、拆箱
public class ObjectTest{
public static void main(String[] agrs){
Integer num=new Integer(23);//在Integer里面有这个构造方法存在->
//装箱:num对象是Integer包装类的对象,它指向堆内存中的一个int属性
//这个属性的值现在赋值为23.
int data = num.intValue();//拆箱:通过包装类的这个对象以及Number中的函数,访问访问堆内存中int
//这个属性值。并且将这个值赋给一个变量data。
System.out.println(data);
}
}
这是我们自己通过手动进行的装箱和拆箱,在JDK1.5以后就可以自动的进行装箱和拆箱了,并且我们可以通过这样的对象进行各种操作。
public class ObjectTest{
public static void main(String[] args){
Integer num=55;//自动装箱、拆箱
num++;//进行运算
System.out.println(num);
}
}
下面我们通过一个简单的例子来看==与equals
public class ObjectTest{
public static void main(String[] args){
Integer a=100;
Integer b=100;
Integer c=new Integer(100);
Integer d=new Integer(100);
Integer e=new Integer(400);
Integer f=new Integer(400);
Integer g=400;
Integer h=400;
System.out.println(a==b);//true
System.out.println(a.equals(b));//true
System.out.println(c==d);//false
System.out.println(c.equals(d));//true
System.out.println(e==f);//false
System.out.println(e.equals(f));//true
System.out.println(g==h);//false
System.out.println(g.equals(h));//true
}
}
包装类Integer直接跟内存有关,而Integer内部做了缓存与对象池没有关系。这个缓存就是Integer本来就创建了256个对象,它们都会在堆上产生空间。我们在只用new进行重新创建的时候并不会用缓存,只有在-128——127之间才会用到缓存,这个时候就可以用“” 进行比较 ,它就相当于是内容的比较。但是如果是超出了-128——127这个范围我们就算直接赋值也相当于是在用new开辟空间,这个时候用双等号进行比较的话就会出现false。
对于下面写法是等价与直接赋值的:
Integer a=Integer.valueOf(100);-----------》Integer a=100;
Integer b=Integer.valueOf(100);-----------》Integer b=100;
这样的写法也是用到了缓存的。ab//true
3.字符串与基本数据类型转换(一定要掌握)
(1)String与int转换:public static int parseInt(String s)throws NumberFormatException
(2)String与double转换:public static double parseDouble(String s)throws NumberFormatException
(3)String与Boolean转换:public static Boolean parseBoolean(String s)throws NumberFormatException
public class ObjectTest{
public static void main(String[] agrs){
//将字符转换为整型-》默认转换为10进制
String str1="123";
int num1=Integer.parseInt(str1);//int num1=Integer.parseInt(str1,16);-》转换为16进制
System.out.println(num1);
//将字符转换为浮点型
String str2="123.34";
double num2=Double.parseDouble(str2);
System.out.println(num2);
//将字符转换为布尔类型
String str3="abc";
String str4="True";
String str5="true";
String str6="TRue";
String str7="aldj";
Boolean num3=Boolean.parseBoolean(str3);
Boolean num4=Boolean.parseBoolean(str4);
Boolean num5=Boolean.parseBoolean(str5);
Boolean num6=Boolean.parseBoolean(str6);
Boolean num7=Boolean.parseBoolean(str7);
System.out.println(num3);
System.out.println(num4);
System.out.println(num5);
System.out.println(num6);
System.out.println(num7);
}
}
对于基本数据类型与字符串进行转换需要注意的是字符串和布尔类型的转换,只要字符串不是true,不管里面是大写还是小写,结果都是false,不管大小写,只要是true结果就是true。
(4)基本数据类型转化为字符串
(4.1)任何数据类型使用了"+"连接空白字符串就变为了字符串类型。
(4.2)使用String类中提供的valueOf()方法,该方法更好,不会产生垃圾。
public class ObjectTest{
public static void main(String[] agrs){
//(1)
String str1=100+"";
System.out.println(str1);
//(2)
String str =String.valueOf(100);
System.out.println(str);
}
}
补充内容:
java中两个数的交换:
在Java中参数传递只有值传递=》传的就是栈空间内容。Java和c语言不同,没有什么传地址,只有值传递。
基本数据类型–》栈空间–》值。
引用数据类型–》栈空间:放的是引用的对象所在的堆空间地址。
public class ObjectTest{
public static void main(String[] args){
int a=20;//值传递传的是栈里面的内容,它是基本数据类型,所以它是直接传递的20(复制一份)
char[] ch=new char[]{'a','b'};//数组,是引用数据类型,传递的是栈里面的内容,栈中是地址
//所以拷贝的是地址,可以改变内容。
swap(a,ch);
System.out.println(a);//20
System.out.println(java.util.Arrays.toString(ch));//A b->在数组中使用toString方法可以直接
//通过数组名字打印数组中的内容。
}
public static void swap(int a1,char[] a2){
a1=10;
a2[0]='A';
}
}