黑马程序员——面向对象最全总结:谁说程序员没有“对象”

来源:互联网 发布:海云数据 编辑:程序博客网 时间:2024/05/22 15:08

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

前言

本文将以我个人对于该部分内容的理解,重新对整个体系进行归纳和划分,以一种不太常见的方式把面向对象的基础内容全部涵盖在内。我把整个面向对象的知识分成两大部分:第一部分是“功能”,第二部分是“关系”。功能部分包括:类的定义、类的初始化、类的实例化、类的修饰、类的扩展几个部分。关系部分包括:实例与类的关系、子类与父类的关系、类与类的关系几个部分。具体内容将在下文详述。
“异常处理”这部分的内容也常常被一些国内外教科书划分在面向对象的章节中,不过由于我认为异常处理部分内容的体系比较有特点,基本上属于自成体系,也有不少内容,将单独再写一篇文章来进行总结和演练。

功能

类的定义:内部类

基本定义与格式

一句话概述:将一个类定义在另一个类里面。

格式1:通用格式

<pre name="code" class="java">class outerClassName{private class innerClassName{//body of inner class}}

格式2:静态内部类

class outerClassName{private static class innerClassName{//body of inner class}}

格式3:匿名内部类

new ClassOrInterface(){//class-body}

内部类与非内部类的比较

不使用内部类的普通调用
/* * notInner想要访问Outer中的field或method, * 需要在notInner类中创建一个Outer类的对象 */class generalClass{//fieldint num = 3;//methodpublic void printStar(){//非静态方法System.out.println("*");}public static void printComma(){//静态方法System.out.println(",");}}class notInner{//field//methodpublic static void main(String[] args) {generalClass.printComma();//静态方法可以直接用类名调用generalClass ot = new generalClass();//非静态方法需要先创建一个实例,在notInner类中创建一个Outer类的对象int getNum = ot.num;//notInner类要访问Outer中的field:num,需要在创建实例后才能进行ot.printStar();//notInner类要访问Outer中的method:printStar(),需要在创建实例后才能进行}

使用内部类时的调用情况
/*内部类的访问规则:1,内部类可以直接访问外部类中的成员,包括私有。之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式 外部类名.this2,外部类要访问内部类,必须建立内部类对象。*/class Outer//外部类{private String str = "Outer的私有变量";class Inner//内部类//Class Inner还可以被私有修饰 private class Inner,因为它也属于Outer类的成员{String str = "Inner中的变量";void function(){String str = "function中的变量";System.out.println("innner :"+str);//该语句将会输出:innner :function中的变量System.out.println("innner :"+this.str);//该语句将会输出:innner :Inner中的变量,与Inner.this.str输出结果一致System.out.println("innner :"+Outer.this.str);//Outer后不加this,想要访问Outer中的field会报错,该语句将会输出:innner :Outer的私有变量System.out.println("innner :"+Inner.this.str);//Inner后不加this,想要访问Inner中的field会报错,该语句将会输出:innner :Inner中的变量}}void method()//在innerInOuter中定义的method方法{Inner in = new Inner();//外部类要访问内部类,必须建立内部类对象。in.function();//外部类访问内部类中的function方法}}class  innerClass{public static void main(String[] args) {Outer iio = new Outer();iio.method();//直接访问内部类中的成员。Outer.Inner in = new Outer().new Inner();//如果使用Inner in = new Inner();会报错,当内部类被私有时,则不能被访问到in.function();}}

静态内部类和非静态内部类的区别

当内部类被static修饰后,只能直接访问外部类中的static成员。出现了访问局限。
class staticInnerClassDemo{//在外部其他类中,直接访问非static内部类的methods比较Outer.Inner in = new Outer().new Inner();in.function();//在外部其他类中,直接访问static内部类的非静态methodsnew Outer.Inner().function();//在外部其他类中,直接访问static内部类的静态methodsOuter.Inner.function();}
内部类必须是static的两种情况
1.当内部类中定义了静态成员
2.外部类中的静态方法需要访问内部类
当描述事物时,事物的内部还有事物,该事物用内部类来描述,因为内部事物在使用外部事物的内容。
内部类可以定义在成员位置上,也可以定义在方法内部。定义在成员位置上时,就可以被私有化,也可以被static所修饰。
如果内部类定义在内部,则不能被静态所修饰,也不能私有化。

定义在方法内部的内部类

内部类定义在局部时,
1,不可以被成员修饰符修饰
2,可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。

class Outer{int x = 3;void method(final int a){final int y = 4;//内部类定义在局部时,不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。//定义在该method内部的内部类class Inner{void function(){System.out.println(y);}}new Inner().function();//如果不new一个Inner的对象,没有这句语句,将不会运行。没对象,不运行}}class  InnerClassDemo{public static void main(String[] args) {Outer out = new Outer();out.method(7);//出栈后释放out.method(8);//又进栈后开辟新的a}}

匿名内部类

匿名内部类:
1,匿名内部类其实就是内部类的简写格式。
2,定义匿名内部类的前提:内部类必须是继承一个类或者实现接口。
3,匿名内部类的格式:  new 父类或者接口(){定义子类的内容}
4,其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。 可以理解为带内容的对象。
5,匿名内部类中定义的方法最好不要超过3个。

class Outer{int x = 3;//没有使用匿名内部类时的情况:以下/*class Inner extends AbsDemo{int num = 90;void show(){System.out.println("show :"+num);}}public void function(){new Inner.show();}*///使用匿名内部类时的情况:以下public void function(){//匿名内部类,直接用AbsDemo创建对象,后面还带着代码块{}new AbsDemo()//创建的是AbsDemo的匿名子对象{void show(){System.out.println("show :"+num);}}.show();//注意:分号在这里,整个代码块是一个整体,是AbsDemo的子类对象,最后是方法调用。匿名对象对方法只能调用一次}}

类的初始化

1.构造函数

对象一建立就会调用与之对应的构造函数。
构造函数的作用:可以用于给对象进行初始化。
构造函数的小细节:
1.当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数。
2.当在类中自定义了构造函数后,默认的构造函数就没有了
一个对象建立,构造函数只运行一次。
而一般方法可以被该对象调用多次。
什么时候定义构造函数呢?
当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容定义在构造函数中。

/* 程序输出结果: 学号:003姓名:张飞 学号:004姓名:关羽 学号:001姓名:刘备职务:班长 学号:002姓名:诸葛亮职务:学习委员  */public class constructorDem {public static void main(String[] args) {Students stu1 = new Students("003","张飞");//1号张飞,学号如果设置成int,则001将会输出1,所以要用String来存学号Students stu2 = new Students("004","关羽");//2号关羽StuLeader sl1 = new StuLeader("001","刘备","班长");//班长刘备StuLeader sl2 = new StuLeader("002","诸葛亮","学习委员");//学习委员诸葛亮//打印输出,否则控制台没有显示结果System.out.println(stu1);System.out.println(stu2);System.out.println(sl1);System.out.println(sl2);}}class Students{private String number;//学号private String name;//姓名//构造函数public Students(String number, String name){this.setNumber(number);this.setName(name);}//学号的getter和setterpublic String getNumber() {return number;}public void setNumber(String number) {this.number = number;}//姓名的getter和setterpublic String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString(){return "学号:" + number +  "\t"  + "姓名:" + name ;}}class StuLeader extends Students{//学生干部是一个特殊的学生的类,继承自学生,多一个职务的属性//Implicit super constructor Students() is undefined for default constructor. Must define an explicit constructor//因为在父类Students中没有定义默认的构造器,所以必须要在该类中定义一个显式的构造器。因为在子类隐式的构造器开头隐含一个super();private String duty;public StuLeader(String number, String name, String duty){super(number,name);//不能写成super(int number,String name);this.duty = duty;}@Overridepublic String toString(){return super.toString() + "\t" + "职务:" + duty;//如果学号不对齐,使用tab键并调用super的时候会发生一些问题}}

2.构造代码块

作用:给对象进行初始化
对象一建立就运行,并优先于构造函数运行
和构造函数的区别:
构造代码块是给所有对象进行统一初始化,
而构造函数是给对应的对象初始化。
构造代码快中定义的是不同对象共性的初始化内容。
/*运用构造代码块,小孩不管有名字没名字,生下来都会哭了小孩生下来哭了小孩:Bob小孩生下来哭了 */class Baby{private String name;{System.out.println("小孩生下来哭了");}Baby(){}Baby(String name){this.name =name;}@Override //重写的toString不能放在构造函数中间,还需要在主函数中打印输出对象public String toString(){return "小孩:" + name + "\n";}}class  ConDem2{public static void main(String[] args) {//有名字的小孩Baby b = new Baby("Bob");System.out.println(b);//没名字的小孩new Baby();}}

类的实例化

匿名对象

匿名对象使用方式一:当对对象的方法只调用一次时,可以用匿名对象来完成
匿名对象使用方式二:可以将匿名对象作为实际参数进行传递。
匿名对象调用field没意义
class Car{String name = "奥迪";String color = "红色的";void run(){System.out.println(color + name + "在欢乐地奔跑");} }class AnonymousInstance {public static void main(String[] args) {//正常创建对象的方法Car redAudi = new Car();redAudi.run();//匿名对象使用方式一:当对对象的方法只调用一次时,可以用匿名对象来完成new Car().name = "被黑客改了名字的奥迪";new Car().run();//即使改了名字,这句话输出的结果还是:红色的奥迪在欢乐地奔跑//因为new Car().run();在创建之前,new Car().name = "被黑客改了名字的小土车";在内存中就已经被销毁了,匿名对象调用field没意义changeCar(redAudi);//程序将会输出:黑色的奥迪在欢乐地奔跑}//匿名对象使用方式二:可以将匿名对象作为实际参数进行传递。public static void changeCar(Car c){c.color = "黑色的";c.run();}}

Person p = new Person("张飞",20);这句话都做了什么

1,因为new用到了Person.class.所以会先找到Person.class文件并加载到内存中。
2,执行该类中的static代码块,如果有的话,给Person.class类进行初始化。
3,在堆内存中开辟空间,分配内存地址。
4,在堆内存中建立对象的特有属性。并进行默认初始化。
5,对属性进行显示初始化。
6,对对象进行构造代码块初始化。
7,对对象进行对应的构造函数初始化。
8,将内存地址付给栈内存中的p变量。

单例设计模式

单例设计模式的作用:解决一个类在内存只存在一个对象。

保证对象唯一的目的:
1,为避免其他程序过多建立该类对象,先禁止其他程序建立该类对象
2,又必须u让其他程序可以访问到该类对象,只好在本类中,自定义一个对象
3,为方便其他程序对自定义对象的访问,可以对外提供一些访问方式。

创建单例设计模式的步骤:
1,将构造函数私有化
2,在类中创建一个本类对象
3,提供一个可以获取到该对象的方法

1.饿汉式(Eager)

这个是先初始化对象,称为:饿汉式。
class Singleton{//1,将构造函数私有化。private  Singleton(){}//2,在类中创建一个本类对象private static Singleton s = new Singleton();//静态方法只能访问静态变量,故此处只能是static。类和对象都可以属于field//3,提供一个可以获取到该对象的方法public static  Singleton getInstance()//需要通过该方法才能访问对象,但是方法被调用只能通过对象、类名两种方式//现在没有对象,故需要用类名调用,必须是static方法{return s;}}class SingleDemo {Singleton sgt = Singleton.getInstance();//不能再通过new来创建对象了,只能通过调用Singleton中的getInstance方法}

2.懒汉式(Lazy)

对象是方法被调用时,才初始化,也叫做对象的延时加载。称为:懒汉式。
Single类进内存,对象还没有存在,只有当调用了getInstance方法时,才建立对象。
class Singleton2{//1,将构造函数私有化。private Singleton2(){}//2,在类中创建一个本类对象private static Singleton2 s = null;//3,提供一个可以获取到该对象的方法public static Singleton2 getInstance(){if(s==null){synchronized(Singleton2.class)//多线程部分的内容{if(s==null)s = new Singleton2();}}return s;}}


类的修饰符

1.Static

Static一言以蔽之:是属于类自带的
用法:是一个修饰符,用于修饰成员(成员变量,成员函数).
当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,
还可以直接被类名调用。类名.静态成员。

static特点:
1,随着类的加载而加载,随着类的消失而消失。说明它的生命周期最长。
2,优先于的对象存在(静态先存在,对象后存在)
3,被所有对象所共享
4,可以直接被类名所调用

实例变量和类变量的区别:
1,存放位置。
类变量:随着类的加载而存在于方法区中
实例变量:随着对象的建立而存在于堆内存中
2,生命周期:
类变量:生命周期随着类的消失而消失
实例变量:生命周期随着对象的消失而消失

静态使用注意事项:
1,静态方法只能访问静态成员(非静态方法既可以访问静态也可以访问非静态)
2,静态方法中不可以定义this,super关键字。(因为静态优先于对象存在。所以静态方法中不可以出现this)
3,主函数是静态的。

静态的利弊
利处:对对象的共享数据进行单独空间的存储,节省空间。没有必要每一个对象中都存储一份。
可以直接被类名调用。
弊端:生命周期过长。
 访问出现局限性。(静态虽好,只能访问静态。)


class Bike{public static String color = "red";public static void run(){System.out.println("自行车跑啊跑");}}public class StaticDemo {public static void main(String[] args) {//普通调用方式调用Bike的field中的colorBike giant = new Bike();System.out.println(giant.color);//类变量的另一种调用方式System.out.println(Bike.color);//效果与第一种调用方式相同//调用类变量的方法Bike.run();}}

2.Static Initializer:静态代码块

静态代码块。
格式:
static
{
静态代码块中的执行语句。
}
特点:随着类的加载而执行,只执行一次,并优先于主函数。
用于给类进行初始化的。
即使构造代码块定义在静态代码块之前,还是先执行静态代码块的内容
class StaticCode{int num = 9;//构造函数StaticCode(){System.out.println("构造函数的内容被打印了");}//构造代码块{System.out.println("构造代码块的内容被打印了 " + this.num);}//静态代码块static{System.out.println("静态代码块的内容被打印了");}//构造函数超载StaticCode(int x){System.out.println("构造函数超载的内容被打印了");}//静态方法public static void show(){System.out.println("show run");}}class StaitcInitializer {static{//System.out.println("b");}public static void main(String[] args) {new StaticCode(4);//因为没有创建过StaticCode的对象,"构造函数的内容被打印了"这行不会被打印}}/* 程序输出结果 静态代码块的内容被打印了:即使构造代码块定义在静态代码块之前,还是先执行静态代码块的内容构造代码块的内容被打印了 9构造函数超载的内容被打印了*/

类的扩展

1.抽象类

抽象类的特点:
1,抽象方法一定在抽象类中。
2,抽象方法和抽象类都必须被abstract关键字修饰。
3,抽象类不可以用new创建对象。因为调用抽象方法没意义。
4,抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后(非抽象方法可以不用实现),建立子类对象调用。
5,如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。

abstract 关键字旁边,和哪些关键字不能共存?
final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。
private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写。而抽象方法出现的就是需要被复写。
static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。可是抽象方法运行没意义。

模版方法:
在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,
那么这时就将不确定的部分暴露出去。由该类的子类去完成。

abstract class GetTime//把GetTime的功能定义成抽象类,模板设计模式{public final void getTime()//之所以要使用final关键字,是为了不让getTime被复写{long start = System.currentTimeMillis();runcode();long end = System.currentTimeMillis();System.out.println("毫秒:"+(end-start));}public abstract void runcode();//要求子类复写该抽象方法,以得到不同代码相对应的运行时间}class SubTime extends GetTime{public void runcode()//开始复写父类方法{for(int x=0; x<4000; x++){System.out.print(x);}}}class  AbstractDemo{public static void main(String[] args) {SubTime gt = new SubTime();gt.getTime();}

2.接口

接口定义时,格式特点:
1,接口中常见定义:常量,抽象方法。
2,接口中的成员都有固定修饰符。
常量:public static final
方法:public abstract 

注意:
1,接口中的成员都是public的。
2,接口是不可以创建对象的,因为有抽象方法。
3,接口需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。否则子类是一个抽象类。
4,接口可以被类多实现,也是对多继承不支持的转换形式。java支持多实现。
abstract class Student{abstract void study();void sleep(){System.out.println("sleep");}}interface Smoking//抽烟不是学生都具有的行为,定义为接口{void smoke();}class ZhangSan extends Student implements Smoking{void study(){}public void smoke(){}}

关系

子父类关系特点

1.子父类中变量的特点

如果子类中出现非私有的同名成员变量时,
子类要访问本类中的变量,用this。this:代表的是本类对象的引用。
子类要访问父类中的同名变量,用super。super:代表的是父类对象的引用。
class Fu {public String str = "爹的成员";}class Zi extends Fu{String str = "儿的方法";//一般不会这么定义,因为子类可以从父类中获取void show(){System.out.println(str);//儿的成员System.out.println(this.str);//儿的成员System.out.println(super.str);//爹的成员}}class ExtendsDemo {public static void main(String[] args) {Zi z = new Zi();z.show();}}

2.子父类中方法的特点

当子类出现和父类一模一样的函数时,子类对象调用该函数,会运行子类函数的内容。如同父类的函数被覆盖一样。
这种情况是函数的另一个特性:Override(覆盖)
当子类继承父类,沿袭了父类的功能,到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,
这时,没有必要定义新功能,而是使用覆盖特性,保留父类的功能定义,并重写功能内容。
覆盖:
1,子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。
2,静态只能覆盖静态。
class Father{void methods(){System.out.println("爹的方法");}}class Son extends Father{void methods(){System.out.println("儿的方法");}}class ExtendsDemo2{public static void main(String[] args) {Son z = new Son();z.methods();//儿的方法}}

3.子父类中构造函数的特点

在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认第一行有一条隐式的语句 super();
super():会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super();
为什么子类一定要访问父类中的构造函数?
因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。所以子类在对象初始化时,要先访问一下父类中的构造函数。
如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。
注意:super语句一定定义在子类构造函数的第一行。

多态(Polymorphism)

1.多态的概念

多态:可以理解为事物存在的多种体现形态。

多态的体现
父类的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。
多态的前提
必须是类与类之间有关系。要么继承,要么实现。
通常还有一个前提:存在覆盖。
多态的利弊
利:多态的出现大大的提高程序的扩展性。
弊:只能使用父类的引用访问父类中的成员。
多态的应用

2.多态引入的目的

最原始版本:为了让Cat类中的不同实例调用eat方法,需要反复创建该类的实例
<pre name="code" class="java">abstract class Animal{abstract void eat();}class Cat extends Animal{public void eat(){System.out.println("吃鱼");}public void catchMouse(){System.out.println("抓老鼠");}}class Dog extends Animal{public void eat(){System.out.println("吃骨头");}public void watchHome(){System.out.println("看家");}}public class PolyDemo {public static void main(String[] args) {Cat heimao = new Cat();heimao.eat();Cat lanmao = new Cat();lanmao.eat();}}


改进版本:将cat类作为参数,传递给一个专门用来调用Cat类中的eat()方法的方法,提高代码复用性
public class PolyDemo {public static void main(String[] args) {Cat heimao = new Cat();//heimao.eat();getEatmethod(heimao);Cat lanmao = new Cat();//lanmao.eat();getEatmethod(lanmao);}public static void getEatmethod(Cat c){//将cat类作为参数,传递给一个专门用来调用Cat类中的eat()方法的方法c.eat();}}

改进版本2:将Dog类作为参数,传递给一个专门用来调用Dog类中的eat()方法的方法,运用方法的重载
public class PolyDemo {public static void main(String[] args) {Cat heimao = new Cat();getEatmethod(heimao);Dog xiaohuang = new Dog();getEatmethod(xiaohuang);//或者直接getEatmethod(new Dog());}public static void getEatmethod(Cat c){//将cat类作为参数,传递给一个专门用来调用Cat类中的eat()方法的方法c.eat();}public static void getEatmethod(Dog d){//将Dog类作为参数,传递给一个专门用来调用Dog类中的eat()方法的方法,运用方法的重载d.eat();}}

改进版本3:利用多态性,直接运用父类
public class PolyDemo {public static void main(String[] args) {getEatmethod(new Cat());getEatmethod(new Dog());}public static void getEatmethod(Animal a){//直接传入父类即可//Animal a = new Cat();//Animal a = new Dog();a.eat();}

3.多态的转型

向上转型:类型提升,引用数据类型的提升

Animal a = new Cat();//类型提升。 向上转型。猫的类型提升为Animal

向下转型:猫提升为Animal后,失去了猫的特有方法,如果此时想要再调用猫的特有方法时,如何操作?
Cat c = (Cat)a;//强制将父类的引用a。转成子类类型Cat。向下转型。此时就可以使用c.catchMouse()了

错误代码:把动物转成猫的类型

<pre name="code" class="java">Animal a = new Animal();//千万不要出现这样的操作,就是将父类对象转成子类类型。//我们能转换的是父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强制转换。//多态自始至终都是子类对象在做着变化。Cat c = (Cat)a;

4. instanceof

假如没有instanceof,出现类型转换异常时的情况:
public class PolyDemo2 {public static void main(String[] args) {method(new Cat());method(new Dog());//传入method后,等于是把狗强制转换成了猫,会报类型转换异常}public static void method(Animal a){a.eat();Cat c = (Cat)a;//向下转型,转型后就可以抓老鼠了c.catchMouse();}}/*吃鱼Exception in thread "main" java.lang.ClassCastException: Dog cannot be cast to Cat抓老鼠吃骨头at PolyDemo2.method(PolyDemo2.java:40)at PolyDemo2.main(PolyDemo2.java:35)*/

有instanceof 时的处理方法
public static void method(Animal a)//Animal a = new Cat();{a.eat();/*小细节:不要把父类写在上面if(a instanceof Animal){System.out.println("haha");}else */if(a instanceof Cat){Cat c = (Cat)a;c.catchMouse();}else if(a instanceof Dog){Dog c = (Dog)a;c.kanJia();}/*instanceof : 用于判断对象的类型。 对象 intanceof 类型(类类型 接口类型)  */}

5.多态中成员的特点

在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
在多态中,成员变量的特点:
无论编译和运行,都参考左边(引用型变量所属的类)。
在多态中,静态成员函数的特点:
无论编译和运行,都参考做左边。

Object类:所有类的父类

Object:是所有对象的直接后者间接父类。该类中定义的肯定是所有对象都具备的功能。
Object类中已经提供了对对象是否相同的比较方法。如果自定义类中也有比较相同的功能,没有必要重新定义。
只要沿袭父类中的功能,建立自己特有比较内容即可。这就是覆盖。

class Demo{ //extends Object}class Person{}class ObjectDemo {public static void main(String[] args) {Demo d1 = new Demo();Demo d2 = new Demo();Demo d3 = d1;System.out.println(d1.equals(d2));//输出:falseSystem.out.println(d3.equals(d1));//输出:trueSystem.out.println(d1.toString());//输出:Demo@659e0bfdSystem.out.println(d2.toString());//输出:Demo@2a139a55System.out.println(d1);//输出语句打印对象时,会自动调用对象的toString方法。打印对象的字符串表现形式。输出:Demo@659e0bfdClass c = d1.getClass();System.out.println(c.getName());//输出:DemoSystem.out.println(c.getName()+"@"+Integer.toHexString(d1.hashCode()));//输出:Demo@659e0bfd//比较Person对象Person p1 = new Person();Person p2 = new Person();System.out.println("Person: " + p1.equals(p2));//输出:Person: false}}


自己定义一个比较的方法,版本1:
class Demo{ //extends Objectprivate int num;Demo(int num){this.num = num;}public boolean compare(Demo d){return this.num == d.num;}}class ObjectDemo {public static void main(String[] args) {Demo d1 = new Demo(4);Demo d2 = new Demo(3);Demo d3 = new Demo(4);System.out.println(d1.compare(d2));//输出:falseSystem.out.println(d1.compare(d3));//输出:true}}

自己定义一个比较的方法,版本2:
父类Object中已经提供了比较的方法,不用再自己写compare方法
可以自行复写Object中的equals方法
class Demo{ //extends Objectprivate int num;Demo(int num){this.num = num;}public boolean equals(Object obj){//Object obj = new Demo();Demo d = (Demo)obj; return this.num == d.num;//直接访问obj.num将会报错,找不到Object类中的num,想使用子类的东西,需要向上转型,然后访问d.num}}class ObjectDemo {public static void main(String[] args) {Demo d1 = new Demo(4);Demo d2 = new Demo(3);Demo d3 = new Demo(4);System.out.println(d1.equals(d2));//输出:falseSystem.out.println(d1.equals(d3));//输出:true}}











0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果手机忘记四位数解锁密码怎么办 银行卡用支付宝支付限额了怎么办 用银行卡号找回微信被盗密码怎么办 微信钱包密码错误被锁定怎么办 本人没玩财付通结果被扣了钱怎么办 我的银行卡给支付宝充不了钱怎么办 支付宝话费充错了怎么办啊 已充值成功送朋友话费不能送怎么办 微信绑定银行卡被盗刷q币怎么办 微信红包过了24小时没退回怎么办 微信6.67版本红包发错了怎么办 苹果6s还原后激活出错怎么办 q币充给了不存在的账号怎么办 怎么办微信的钱换成淘宝币 学信网密码密保手机号都忘了怎么办 第五人格玩游戏时总是闪退怎么办 qq安全中心密保手机换了怎么办 微信冻结账号绑定了银行卡怎么办 扣扣红包密码是支付密码忘了怎么办 红包退回通知不小心删除了怎么办 QQ炫舞金币充错账号怎么办 晋江的小说用晋江币买不了是怎么办 中国银行储蓄不能充值支付宝怎么办 微信怎么改银行卡密码忘记了怎么办 微信号手机号码换了密码忘了怎么办 微信被盗密码被改绑定手机号怎么办 微信qq号登陆改密码忘记了怎么办 本人微信红包赌博输了50万怎么办 4g飞享套餐话费用完了怎么办 手机丢了查话费欠了几百块怎么办 注销电信手机卡里面的余额怎么办 联通手机卡注销后里面的余额怎么办 手机卡网上销户以后剩余话费怎么办 联通新号注册微信发不了短信怎么办 韩博士装机卡在驱动恢复怎么办 xp打印后程序服务没有运行怎么办 刚注册的微信显示异常怎么办 不小心删了照片怎么办不要钱 qq邀请好友辅助验证成功后怎么办 微信申诉怎么让好友发验证码怎么办 微信申诉好友都删除了怎么办